common
Tramvai tokens for integration and extension @tramvai/module-common.
Action tokens
import { createToken } from '@tinkoff/dippy';
import { Action, type SyncTapableHookInstance } 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');
export interface ActionStartHookData {
  action: Action | TramvaiAction<any, any, any>;
  deferred?: boolean;
  context: ExecutionContext | null;
  start: number;
}
export interface ActionEndHookData {
  action: Action | TramvaiAction<any, any, any>;
  deferred?: boolean;
  error?: Error & { originalMessage?: string };
  context: ExecutionContext | null;
  forbidden?: string;
  end: number;
}
/**
 * @description
 * Hooks for action execution
 */
export const ACTION_EXECUTION_HOOKS_TOKEN = createToken<{
  startExecution: SyncTapableHookInstance<ActionStartHookData>;
  endExecution: SyncTapableHookInstance<ActionEndHookData>;
}>('actionExecutionHooks');
/**
 * @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,
  }
);
/**
 * @description
 * Limit global and page actions execution time on server-side
 */
export const LIMIT_ACTION_GLOBAL_TIME_RUN = createToken<number>('limitActionGlobalTimeRun');
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 { Scope, createToken } from '@tinkoff/dippy';
export interface EnvironmentManager {
  get(name: string): string | undefined;
  getInt(name: string, def: number): number;
  getAll(): Record<string, string | undefined>;
  update(result: Record<string, string>): void;
  /**
   * @deprecated use CLIENT_ENV_MANAGER_TOKEN
   */
  clientUsed(): Record<string, string | undefined>;
  /**
   * @deprecated use CLIENT_ENV_MANAGER_TOKEN
   */
  updateClientUsed(result: Record<string, string>): void;
}
export interface ClientEnvironmentRepository {
  get(name: string): string | undefined;
  set(name: string, value: string): void;
  getAll(): Record<string, string | undefined>;
  update(result: Record<string, string>): void;
}
/**
 * @description
 * Instance that used for managing environment variables
 */
export const ENV_MANAGER_TOKEN = createToken<EnvironmentManager>('environmentManager', {
  scope: Scope.SINGLETON,
});
/**
 * @description
 * Instance that used for store and manage environment variables map, which are passed to the client.
 * Use only server-side for client env values modification depending on the specific request conditions.
 */
export const CLIENT_ENV_REPOSITORY_TOKEN = createToken<ClientEnvironmentRepository>(
  'clientEnvironmentManager',
  {
    scope: Scope.REQUEST,
  }
);
/**
 * @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 });
export type EnvTemplate = {
  key: string;
  fn: (...args: any[]) => string;
  validator?: (key: string, value: string) => void;
};
export const ENV_TEMPLATE_TOKEN = createToken<EnvTemplate>('env template token', {
  multi: true,
  scope: Scope.SINGLETON,
});
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 | undefined;
  getCookies(): Record<string, string | undefined>;
  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 { Scope, 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,
  scope: Scope.SINGLETON,
});
/**
 * @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'
);