Skip to main content

common

Tramvai tokens for integration and extension @tramvai/module-common.

Action tokens

import { createToken } from '@tinkoff/dippy';
import type { Action } from '@tramvai/tokens-core';
import type { TramvaiAction, PageAction } from '@tramvai/types-actions-state-context';
import type { ExecutionContext } from './execution';

/**
* @description
* Registry for storing actions based on their type
*/
export const ACTION_REGISTRY_TOKEN = createToken<ActionsRegistry>('actionRegistry');

/**
* @description
* Instance that executes actions
*/
export const ACTION_EXECUTION_TOKEN = createToken<ActionExecution>('actionExecution');

/**
* @description
* Instance that executes actions on navigations
*/
export const ACTION_PAGE_RUNNER_TOKEN = createToken<ActionPageRunner>('actionPageRunner');

/**
* @description
* Conditions that specify should action be executing or not
*/
export const ACTION_CONDITIONALS = createToken<ActionCondition | ActionCondition[]>(
'actionConditionals',
{
multi: true,
}
);

export interface ActionsRegistry {
add(type: string, actions: PageAction | PageAction[]): void;

get(type: string, addingActions?: PageAction[]): PageAction[];

getGlobal(): PageAction[] | undefined;

remove(type: string, actions?: PageAction[]): void;
}

export interface ActionPageRunner {
runActions(
actions: (Action | TramvaiAction<any, any, any>)[],
stopRunAtError?: (error: Error) => boolean
): Promise<any>;
}

export interface ActionExecution {
run<Params extends any[], Result, Deps>(
action: TramvaiAction<Params, Result, Deps>,
...params: Params
): Result extends Promise<any> ? Result : Promise<Result>;
run<Payload, Result, Deps>(
action: Action<Payload, Result, Deps>,
payload: Payload
): Result extends Promise<any> ? Result : Promise<Result>;

runInContext<Params extends any[], Result, Deps>(
context: ExecutionContext | null,
action: TramvaiAction<Params, Result, Deps>,
...params: Params
): Result extends Promise<any> ? Result : Promise<Result>;
runInContext<Payload, Result, Deps>(
context: ExecutionContext | null,
action: Action<Payload, Result, Deps>,
payload: Payload
): Result extends Promise<any> ? Result : Promise<Result>;

execution: Map<string, Record<string, any>>;

canExecute<Params extends any[], Result, Deps>(
action: TramvaiAction<Params, Result, Deps>
): boolean;
canExecute<Payload, Result, Deps>(action: Action<Payload, Result, Deps>): boolean;
}

export interface ActionConditionChecker<State = any> {
parameters: any;
conditions: Record<string, any>;
type: 'global' | 'local';
allow(): void;
setState(value: State): void;
getState(): State;
forbid(): void;
}

export type ActionCondition = {
key: string;
fn: (checker: ActionConditionChecker) => void;
};

export interface Deferred<Data = any> {
promise: Promise<Data>;
resolve: (data: Data) => void;
reject: (reason: Error) => void;
resolveData?: Data;
rejectReason?: Error;
isResolved: () => boolean;
isRejected: () => boolean;
reset: () => void;
}

export interface DeferredActionsMap {
get(key: string): Deferred | undefined;
set(key: string, value: Deferred): void;
has(key: string): boolean;
forEach(callback: (value: Deferred, key: string) => void): void;
}

export const DEFERRED_ACTIONS_MAP_TOKEN = createToken<DeferredActionsMap>(
'tramvai deferred actions map'
);

Bundle tokens

import { createToken } from '@tinkoff/dippy';
import type { Bundle } from '@tramvai/tokens-core';

/**
* @description
* Bundle Storage. When getting bundle additionally adds actions and components from bundle to according storages
*/
export const BUNDLE_MANAGER_TOKEN = createToken<BundleManager>('bundleManager');

/**
* @description
* Provides additional bundles to the app.
* Important! This token doesn't overrides already existing bundles.
*/
export const ADDITIONAL_BUNDLE_TOKEN = createToken<{ [key: string]: Bundle }>('additional bundle', {
multi: true,
});

export interface BundleManager {
bundles: Record<string, any>;

get(name: string, pageComponent: string): Promise<Bundle | undefined>;

has(name: string, pageComponent: string): boolean;
}

ComponentRegistry tokens

import { createToken } from '@tinkoff/dippy';
import type { TramvaiComponentDecl } from '@tramvai/react';
/**
* @description
* React components storage.
* Components in the repository are divided into groups, e.g. you can specify a bundle or a page component as a group key.
* The entity also allows you to get static component parameters through the `getComponentParam` method (will not work with `lazy` components)
*/
export const COMPONENT_REGISTRY_TOKEN = createToken<ComponentRegistry>('componentRegistry');

export interface ComponentRegistry {
components: Record<string, TramvaiComponentDecl>;

add(name: string, component: TramvaiComponentDecl, group?: string): void;

get(name: string, group?: string): TramvaiComponentDecl | undefined;

getComponentParam<T>(param: string, defaultValue: T, component: string, group?: string): T;
}

Env tokens

import { createToken } from '@tinkoff/dippy';

export interface EnvironmentManager {
get(name: string): string | undefined;
getInt(name: string, def: number): number;
getAll(): Record<string, string>;
update(result: Record<string, string>): void;
clientUsed(): Record<string, string>;
updateClientUsed(result: Record<string, string>): void;
}

/**
* @description
* Instance that used for managing env data on the server and on the client
*/
export const ENV_MANAGER_TOKEN = createToken<EnvironmentManager>('environmentManager');

/**
* @description
* List of envs that are used by the module or the app.
* All of the envs specified by that token will be accessible in the code through `environmentManager`
* ENV_USED_TOKEN format:
- `key` - id of the env. At that id the value of the env will be accessible through `environmentManager` and will be loaded from the external sources.
- `value` - default low-priority value for env `key`
- `optional` - is current env is optional. If `true` the app can work as usual event if the env value were not provided, if `false` - the app will fail to run without env value
- `validator` - validation function for passed env value. In case this function returns string it will be used as error message and validation will fail
- `dehydrate` - if `false` then env value will not be passed to client and this env can be used only on server
*
* @example
```tsx
interface EnvParameter {
key: string;
value?: string;
optional?: boolean;
validator?: (value: string) => boolean | string;
dehydrate?: boolean;
}
```
*/
export interface EnvParameter {
key: string;
value?: string;
optional?: boolean;
validator?: (value: string) => boolean | string;
dehydrate?: boolean;
}

export const ENV_USED_TOKEN = createToken<EnvParameter[]>('envUsed', { multi: true });

Context tokens

import type { Container } from '@tinkoff/dippy';
import { createToken } from '@tinkoff/dippy';
import type { ConsumerContext as BaseConsumerContext } from '@tramvai/types-actions-state-context';
import type { PUBSUB_TOKEN } from './pubsub';

export { PlatformAction } from '@tramvai/types-actions-state-context';

/**
* @description
* Context implementation
*/
export const CONTEXT_TOKEN = createToken<ConsumerContext>('context');

export interface ConsumerContext extends BaseConsumerContext {
readonly di: Container;
readonly pubsub: typeof PUBSUB_TOKEN;

dehydrate: () => {
dispatcher: {
stores: Record<string, any>;
};
};
}

Hook tokens

import { createToken } from '@tinkoff/dippy';

/**
* @description
* [Hooks documentation](https://tramvai.dev/docs/references/libs/hooks)
*/
export const HOOK_TOKEN = createToken<Hooks>('hooks');

type Hook<TPayload> = (context: any, payload?: TPayload, options?: any) => TPayload;

export interface Hooks {
/**
* Register hooks
*/
registerHooks<TPayload>(name: string, list: Hook<TPayload>[] | Hook<TPayload>): void;

/**
* Run sync hook
*/
runHooks<TPayload>(
name: string,
context: any,
payload?: TPayload,
options?: any
): TPayload | undefined;

/**
* Run async hooksЗапуск ассихронных хуков
*/
runAsyncHooks<TPayload>(name: string, context: any, payload: TPayload, options?: any): TPayload;

/**
* Run promise hooks
*/
runPromiseHooks(
name: string,
context: any,
options?: any
): <TPayload>(payload: TPayload) => Promise<TPayload> | Promise<never>;
}

Logger tokens

import type { Logger, Reporter } from '@tinkoff/logger';
import { createToken } from '@tinkoff/dippy';

/**
* @description
* Logger implementation
*/
export const LOGGER_TOKEN = createToken<LoggerFactory>('logger');

/**
* @description
* Hook to be able to modify logger on initialization
*/
export const LOGGER_INIT_HOOK = createToken<LoggerInitHook>('loggerHook', { multi: true });

/**
* @description
* Remote reporter for client logs
*/
export const LOGGER_REMOTE_REPORTER = createToken<Reporter>('remoteReporter');

/**
* @description
* Storage for dynamic log object properties
*/
export const LOGGER_SHARED_CONTEXT = createToken<LoggerSharedContext>(
'tramvai logger shared context'
);

type Config = {
name: string;
[key: string]: any;
};

export type LoggerFactory = Logger & ((configOrName: string | Config) => Logger);

type LoggerInitHook = (logger: LoggerFactory) => void;

export type { Logger, LogFn, LogArg } from '@tinkoff/logger';

export interface LoggerSharedContext {
get(key: string): any;
set(key: string, value: any): void;
}

Pubsub tokens

import { createToken } from '@tinkoff/dippy';

/**
* @description
* Factory for creating pubsub instances
*/
export const PUBSUB_FACTORY_TOKEN = createToken<() => PubSub>('pubsubFactory');

/**
* @description
* Singleton pubsub instance
*/
export const PUBSUB_TOKEN = createToken<PubSub>('pubsub');

/**
* @description
* Request pubsub instance that is created for every client
*/
export const ROOT_PUBSUB_TOKEN = createToken<PubSub>('rootPubsub');

export interface PubSub {
subscribe(event: string, fn: (payload?: any) => void): () => boolean;

publish(event: string, ...args: unknown[]): any;
}

RequestManager tokens

import { createToken } from '@tinkoff/dippy';
import type { Url } from '@tinkoff/url';

/**
* @description
* Instance for managing client requests (request headers, query-parameters, cookies etc).
* Mostly used on server, but has partial functional for browser for simplification build isomorphic app
*/
export const REQUEST_MANAGER_TOKEN = createToken<RequestManager>('requestManager');

export interface RequestManager {
getBody(): unknown;

getUrl(): string;

getParsedUrl(): Url;

getMethod(): string;

getCookie(key: string): string;

getCookies(): Record<string, string>;

getHeader(key: string): string | string[] | undefined;

getHeaders(): Record<string, string | string[] | undefined>;

getClientIp(): string;

getHost(): string;
}

ResponseManager tokens

import { createToken } from '@tinkoff/dippy';

/**
* @description
* Instance for managing client response (response headers, cookies, response body).
* Mostly used on server, but has partial functional for browser for simplification build isomorphic app
*/
export const RESPONSE_MANAGER_TOKEN = createToken<ResponseManager>('responseManager');

export interface ResponseManager {
getBody(): unknown;

setBody(value: unknown): void;

getHeader(key: string): string | string[];

getHeaders(): Record<string, string | string[]>;

setHeader(key: string, value: string): void;

getCookie(key: string): string;

getCookies(): Record<string, string>;

setCookie(key: string, value: string): void;

getStatus(): number;

setStatus(status: number): void;
}

State tokens

import { createToken } from '@tinkoff/dippy';
import type {
DispatcherContext,
Event,
Middleware,
Reducer,
} from '@tramvai/types-actions-state-context';

/**
* @description
* dispatcher implementation
* Реализация dispatcher
*/
export const DISPATCHER_TOKEN = createToken('dispatcher');

/**
* @description
* dispatcher context implementation
*/
export const DISPATCHER_CONTEXT_TOKEN = createToken<DispatcherContext<any>>('dispatcherContext');

/**
* @description
* Token for adding stores that were created with createReducer
*/
export const COMBINE_REDUCERS = createToken('combineReducers', { multi: true });

/**
* @description
* Common app store
*/
export const STORE_TOKEN = createToken<Store>('store');

/**
* @description
* Custom middlewares for working with store state
*/
export const STORE_MIDDLEWARE = createToken<Middleware>('storeMiddleware', { multi: true });

/**
* @description
* Начальное состояние для клиента
*/
export const INITIAL_APP_STATE_TOKEN = createToken<{ stores: Record<string, any> }>(
'initialAppState'
);

export interface Store<State = Record<string, any>> {
dispatch<Payload>(event: Event<Payload>): Payload;
dispatch<Payload>(actionOrNameEvent: string | Event<Payload>, payload?: Payload): Payload;

subscribe(callback: (state: Record<string, any>) => void): () => void;
subscribe<S>(reducer: Reducer<S>, callback: (state: S) => void): () => void;

getState(): State;
getState<S>(reducer: Reducer<S>): S;
}

Execution tokens

import { createToken } from '@tinkoff/dippy';

export interface ExecutionContextValues {
[key: string]: any | undefined;
}

export interface ExecutionContext {
name: string;
abortSignal: AbortSignal;
values: ExecutionContextValues;
}

export interface ExecutionContextOptions {
name: string;
values?: ExecutionContextValues;
}

export interface ExecutionContextManager {
withContext<T>(
parentContext: ExecutionContext | null,
nameOrOptions: string | ExecutionContextOptions,
cb: (context: ExecutionContext, abortController: AbortController) => Promise<T>
): Promise<T>;
}

export const EXECUTION_CONTEXT_MANAGER_TOKEN = createToken<ExecutionContextManager>(
'common ExecutionContextManager'
);

export const ROOT_EXECUTION_CONTEXT_TOKEN = createToken<ExecutionContext | null>(
'common rootExecutionContext'
);

export const COMMAND_LINE_EXECUTION_CONTEXT_TOKEN = createToken<() => ExecutionContext | null>(
'common commandLineExecutionContext'
);