@tramvai/module-common 2.7.1 → 2.10.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,12 +1,12 @@
1
1
  import { __decorate } from 'tslib';
2
2
  import eachObj from '@tinkoff/utils/object/each';
3
- import { createBundle, Scope, Module, provide, commandLineListTokens, COMMAND_LINE_RUNNER_TOKEN, COMMAND_LINES_TOKEN, DI_TOKEN, ACTION_PARAMETERS, ACTIONS_LIST_TOKEN, IS_DI_CHILD_CONTAINER_TOKEN, BUNDLE_LIST_TOKEN } from '@tramvai/core';
3
+ import { createBundle, Scope, Module, provide, commandLineListTokens, COMMAND_LINE_RUNNER_TOKEN, COMMAND_LINES_TOKEN, DI_TOKEN, isTramvaiAction, ACTION_PARAMETERS, ACTIONS_LIST_TOKEN, IS_DI_CHILD_CONTAINER_TOKEN, BUNDLE_LIST_TOKEN } from '@tramvai/core';
4
4
  import { EnvironmentModule } from '@tramvai/module-environment';
5
5
  import { CookieModule } from '@tramvai/module-cookie';
6
6
  export { COOKIE_MANAGER_TOKEN } from '@tramvai/module-cookie';
7
7
  import { LogModule } from '@tramvai/module-log';
8
8
  import { Hooks } from '@tinkoff/hook-runner';
9
- import { REQUEST_MANAGER_TOKEN, REQUEST, COMBINE_REDUCERS, STORE_TOKEN, RESPONSE_MANAGER_TOKEN, RESPONSE, ACTION_EXECUTION_TOKEN, LOGGER_TOKEN, PUBSUB_FACTORY_TOKEN, PUBSUB_TOKEN, ROOT_PUBSUB_TOKEN, INITIAL_APP_STATE_TOKEN, ACTION_REGISTRY_TOKEN, ACTION_CONDITIONALS, CONTEXT_TOKEN, ACTION_PAGE_RUNNER_TOKEN, DISPATCHER_TOKEN, DISPATCHER_CONTEXT_TOKEN, STORE_MIDDLEWARE, CREATE_CACHE_TOKEN, CLEAR_CACHE_TOKEN, REGISTER_CLEAR_CACHE_TOKEN, HOOK_TOKEN, COMPONENT_REGISTRY_TOKEN, BUNDLE_MANAGER_TOKEN, ADDITIONAL_BUNDLE_TOKEN } from '@tramvai/tokens-common';
9
+ import { REQUEST_MANAGER_TOKEN, REQUEST, COMBINE_REDUCERS, STORE_TOKEN, RESPONSE_MANAGER_TOKEN, RESPONSE, ACTION_EXECUTION_TOKEN, ROOT_EXECUTION_CONTEXT_TOKEN, LOGGER_TOKEN, EXECUTION_CONTEXT_MANAGER_TOKEN, COMMAND_LINE_EXECUTION_CONTEXT_TOKEN, PUBSUB_FACTORY_TOKEN, PUBSUB_TOKEN, ROOT_PUBSUB_TOKEN, INITIAL_APP_STATE_TOKEN, ACTION_REGISTRY_TOKEN, ACTION_CONDITIONALS, CONTEXT_TOKEN, ACTION_PAGE_RUNNER_TOKEN, DISPATCHER_TOKEN, DISPATCHER_CONTEXT_TOKEN, STORE_MIDDLEWARE, CREATE_CACHE_TOKEN, CLEAR_CACHE_TOKEN, REGISTER_CLEAR_CACHE_TOKEN, HOOK_TOKEN, COMPONENT_REGISTRY_TOKEN, BUNDLE_MANAGER_TOKEN, ADDITIONAL_BUNDLE_TOKEN } from '@tramvai/tokens-common';
10
10
  export * from '@tramvai/tokens-common';
11
11
  import { __lazyErrorHandler } from '@tramvai/react';
12
12
  import { fileSystemPagesEnabled, getAllFileSystemPages, isFileSystemPageComponent } from '@tramvai/experiments';
@@ -18,9 +18,9 @@ import { format } from '@tinkoff/url';
18
18
  import isEmpty from '@tinkoff/utils/is/empty';
19
19
  import values from '@tinkoff/utils/object/values';
20
20
  import { METRICS_MODULE_TOKEN } from '@tramvai/tokens-metrics';
21
- import { createChildContainer, Scope as Scope$1, createToken } from '@tinkoff/dippy';
21
+ import { createChildContainer, provide as provide$1, Scope as Scope$1, createToken } from '@tinkoff/dippy';
22
22
  import noop from '@tinkoff/utils/function/noop';
23
- import { isSilentError } from '@tinkoff/errors';
23
+ import { isSilentError, ConditionFailError, ExecutionAbortError } from '@tinkoff/errors';
24
24
  import { PubSub } from '@tinkoff/pubsub';
25
25
  import identity from '@tinkoff/utils/function/identity';
26
26
  import objectMap from '@tinkoff/utils/object/map';
@@ -28,6 +28,7 @@ import uniq from '@tinkoff/utils/array/uniq';
28
28
  import difference from '@tinkoff/utils/array/difference';
29
29
  import toArray from '@tinkoff/utils/array/toArray';
30
30
  import LRU from '@tinkoff/lru-cache-nano';
31
+ import { AbortController } from 'node-abort-controller';
31
32
  import { jsx } from 'react/jsx-runtime';
32
33
  import { EXTEND_RENDER } from '@tramvai/tokens-render';
33
34
  import { CHILD_APP_COMMON_INITIAL_STATE_TOKEN, CHILD_APP_INTERNAL_CONFIG_TOKEN, CHILD_APP_INTERNAL_ROOT_DI_BORROW_TOKEN, commandLineListTokens as commandLineListTokens$1 } from '@tramvai/tokens-child-app';
@@ -378,14 +379,17 @@ const resolveDi = (type, status, diContainer, providers) => {
378
379
  return di;
379
380
  };
380
381
  class CommandLineRunner {
381
- constructor({ lines, rootDi, logger, metrics, }) {
382
+ constructor({ lines, rootDi, logger, metrics, executionContextManager, }) {
383
+ this.executionContextByDi = new WeakMap();
382
384
  this.lines = lines;
383
385
  this.rootDi = rootDi;
384
386
  this.log = logger('command:command-line-runner');
385
387
  this.metrics = metrics;
388
+ this.executionContextManager = executionContextManager;
386
389
  }
387
390
  run(type, status, providers, customDi) {
388
391
  const di = customDi !== null && customDi !== void 0 ? customDi : resolveDi(type, status, this.rootDi, providers);
392
+ const rootExecutionContext = di.get({ token: ROOT_EXECUTION_CONTEXT_TOKEN, optional: true });
389
393
  this.log.debug({
390
394
  event: 'command-run',
391
395
  type,
@@ -397,13 +401,25 @@ class CommandLineRunner {
397
401
  const doneMetric = this.createDurationMetric();
398
402
  // eslint-disable-next-line promise/no-nesting
399
403
  return Promise.resolve()
400
- .then(() => this.createLineChain(di, line))
404
+ .then(() => {
405
+ return this.executionContextManager.withContext(rootExecutionContext, `command-line:${line.toString()}`, async (executionContext) => {
406
+ this.executionContextByDi.set(di, executionContext);
407
+ await this.createLineChain(di, line);
408
+ });
409
+ })
401
410
  .finally(() => doneMetric({ line: line.toString() }));
402
411
  });
403
412
  }, Promise.resolve())
404
413
  // После завершения цепочки отдаем context выполнения
414
+ .finally(() => {
415
+ this.executionContextByDi.delete(di);
416
+ })
405
417
  .then(() => di));
406
418
  }
419
+ resolveExecutionContextFromDi(di) {
420
+ var _a;
421
+ return (_a = this.executionContextByDi.get(di)) !== null && _a !== void 0 ? _a : null;
422
+ }
407
423
  createLineChain(di, line) {
408
424
  let lineInstance;
409
425
  try {
@@ -514,7 +530,7 @@ let CommandModule = class CommandModule {
514
530
  CommandModule = __decorate([
515
531
  Module({
516
532
  providers: [
517
- {
533
+ provide$1({
518
534
  // Раннер процессов
519
535
  provide: COMMAND_LINE_RUNNER_TOKEN,
520
536
  scope: Scope$1.SINGLETON,
@@ -527,14 +543,27 @@ CommandModule = __decorate([
527
543
  token: METRICS_MODULE_TOKEN,
528
544
  optional: true,
529
545
  },
546
+ executionContextManager: EXECUTION_CONTEXT_MANAGER_TOKEN,
530
547
  },
531
- },
532
- {
548
+ }),
549
+ provide$1({
550
+ provide: COMMAND_LINE_EXECUTION_CONTEXT_TOKEN,
551
+ useFactory: ({ di, commandLineRunner, }) => {
552
+ return () => {
553
+ return commandLineRunner.resolveExecutionContextFromDi(di);
554
+ };
555
+ },
556
+ deps: {
557
+ di: DI_TOKEN,
558
+ commandLineRunner: COMMAND_LINE_RUNNER_TOKEN,
559
+ },
560
+ }),
561
+ provide$1({
533
562
  // Дефолтный список команл
534
563
  provide: COMMAND_LINES_TOKEN,
535
564
  scope: Scope$1.SINGLETON,
536
565
  useValue: lines$1,
537
- },
566
+ }),
538
567
  ],
539
568
  })
540
569
  ], CommandModule);
@@ -602,14 +631,19 @@ const actionTramvaiReducer = createReducer('actionTramvai', initalState).on(acti
602
631
  serverState: payload,
603
632
  }));
604
633
 
634
+ /**
635
+ * @deprecated only for compatibility with legacy createAction
636
+ */
605
637
  const actionType = {
606
638
  global: 'global',
607
639
  local: 'local',
608
640
  };
609
641
 
642
+ const DEFAULT_CONDITIONS = {};
610
643
  class ActionChecker {
611
644
  // eslint-disable-next-line max-params
612
645
  constructor(globalConditionals, payload, parameters, executionState, type) {
646
+ var _a;
613
647
  this.globalConditionals = globalConditionals;
614
648
  this.payload = payload;
615
649
  this.parameters = parameters;
@@ -623,7 +657,7 @@ class ActionChecker {
623
657
  // если экшен был уже выполнен, то считаем, что его не нужно больше выполнять
624
658
  this.status = executionState.status !== 'success';
625
659
  }
626
- this.conditions = parameters.conditions;
660
+ this.conditions = (_a = parameters.conditions) !== null && _a !== void 0 ? _a : DEFAULT_CONDITIONS;
627
661
  }
628
662
  check() {
629
663
  this.globalConditionals.forEach((filter) => {
@@ -653,12 +687,16 @@ class ActionChecker {
653
687
  }
654
688
  }
655
689
 
690
+ const EMPTY_DEPS = {};
691
+ const DEFAULT_PAYLOAD = {};
656
692
  const getParameters = (action) => action[ACTION_PARAMETERS];
657
693
  class ActionExecution {
658
- constructor({ actionConditionals, store, context, di, transformAction, }) {
694
+ constructor({ store, context, di, executionContextManager, actionConditionals, transformAction, }) {
659
695
  this.actionConditionals = flatten(actionConditionals !== null && actionConditionals !== void 0 ? actionConditionals : []);
660
696
  this.context = context;
697
+ this.store = store;
661
698
  this.di = di;
699
+ this.executionContextManager = executionContextManager;
662
700
  this.execution = new Map();
663
701
  this.transformAction = transformAction || identity;
664
702
  const initialState = store.getState(actionTramvaiReducer);
@@ -668,32 +706,63 @@ class ActionExecution {
668
706
  }, initialState.serverState);
669
707
  }
670
708
  }
671
- run(action, payload, type = actionType.local) {
672
- // TODO выпилить после перевода всех экшенов к виду Action
673
- this.transformAction(action);
674
- const parameters = getParameters(action);
675
- const executionState = this.getExecutionState(parameters);
709
+ async runInContext(executionContext, action, ...params) {
710
+ var _a;
711
+ let parameters;
712
+ const payload = (_a = params[0]) !== null && _a !== void 0 ? _a : DEFAULT_PAYLOAD;
713
+ // TODO: replace type with pure context usage
714
+ const type = (executionContext === null || executionContext === void 0 ? void 0 : executionContext.values.pageActions) === true ? actionType.global : actionType.local;
715
+ // TODO: remove else branch after migration to new declareAction
716
+ if (isTramvaiAction(action)) {
717
+ parameters = action;
718
+ }
719
+ else {
720
+ this.transformAction(action);
721
+ parameters = getParameters(action);
722
+ }
723
+ const executionState = this.getExecutionState(parameters.name);
676
724
  if (!this.canExecuteAction(payload, parameters, executionState, type)) {
677
- return Promise.resolve();
725
+ switch (parameters.conditionsFailResult) {
726
+ case 'reject':
727
+ // TODO: pass condition that has failed
728
+ return Promise.reject(new ConditionFailError());
729
+ default:
730
+ return Promise.resolve();
731
+ }
678
732
  }
679
- const deps = parameters.deps ? this.di.getOfDeps(parameters.deps) : {};
680
733
  executionState.status = 'pending';
681
- return Promise.resolve()
682
- .then(() => action(this.context, payload, deps))
683
- .then((data) => {
684
- executionState.status = 'success';
685
- return data;
686
- })
687
- .catch((err) => {
688
- executionState.status = 'failed';
689
- throw err;
734
+ return this.executionContextManager.withContext(executionContext, {
735
+ name: parameters.name,
736
+ values: (executionContext === null || executionContext === void 0 ? void 0 : executionContext.values.pageActions) === true ? { pageActions: false } : undefined,
737
+ }, (executionActionContext) => {
738
+ const context = this.createActionContext(executionContext, executionActionContext, parameters);
739
+ return Promise.resolve()
740
+ .then(() => {
741
+ // TODO: do not execute action if context.abortSignal is aborted
742
+ if (isTramvaiAction(action)) {
743
+ return action.fn.apply(context, params);
744
+ }
745
+ return action(this.context, payload, context.deps);
746
+ })
747
+ .then((data) => {
748
+ executionState.status = 'success';
749
+ return data;
750
+ })
751
+ .catch((err) => {
752
+ executionState.status = 'failed';
753
+ throw err;
754
+ });
690
755
  });
691
756
  }
692
- getExecutionState(parameters) {
693
- let executionState = this.execution.get(parameters.name);
757
+ async run(action, ...params) {
758
+ return this.runInContext(null, action, ...params);
759
+ }
760
+ getExecutionState(name) {
761
+ let executionState = this.execution.get(name);
762
+ // TODO: probably do not need to create executionState on client as it is not used
694
763
  if (!executionState) {
695
764
  executionState = { status: 'pending', state: {} };
696
- this.execution.set(parameters.name, executionState);
765
+ this.execution.set(name, executionState);
697
766
  }
698
767
  return executionState;
699
768
  }
@@ -701,6 +770,16 @@ class ActionExecution {
701
770
  const actionChecker = new ActionChecker(this.actionConditionals, payload, parameters, executionState, type);
702
771
  return actionChecker.check();
703
772
  }
773
+ createActionContext(parentExecutionContext, actionExecutionContext, parameters) {
774
+ return {
775
+ abortSignal: actionExecutionContext === null || actionExecutionContext === void 0 ? void 0 : actionExecutionContext.abortSignal,
776
+ executeAction: this.runInContext.bind(this, actionExecutionContext),
777
+ deps: parameters.deps ? this.di.getOfDeps(parameters.deps) : EMPTY_DEPS,
778
+ actionType: (parentExecutionContext === null || parentExecutionContext === void 0 ? void 0 : parentExecutionContext.values.pageActions) ? 'page' : 'standalone',
779
+ dispatch: this.store.dispatch,
780
+ getState: this.store.getState,
781
+ };
782
+ }
704
783
  }
705
784
 
706
785
  const GLOBAL_PARAMETER = '@@global';
@@ -730,29 +809,32 @@ class ActionRegistry {
730
809
  }
731
810
  }
732
811
 
733
- const payload = {};
734
812
  class ActionPageRunner {
735
- constructor({ actionExecution, logger, }) {
736
- this.actionExecution = actionExecution;
737
- this.log = logger('action:action-page-runner');
813
+ constructor(deps) {
814
+ this.deps = deps;
815
+ this.log = deps.logger('action:action-page-runner');
738
816
  }
739
817
  runActions(actions, stopRunAtError = () => false) {
740
- const actionMapper = (action) => {
741
- return Promise.resolve()
742
- .then(() => this.actionExecution.run(action, payload, actionType.global))
743
- .catch((error) => {
744
- const parameters = action[ACTION_PARAMETERS];
745
- this.log.error({
746
- error,
747
- event: `action-execution-error`,
748
- message: `${parameters.name} execution error`,
818
+ return this.deps.executionContextManager.withContext(this.deps.commandLineExecutionContext(), { name: 'pageActions', values: { pageActions: true } }, async (executionContext) => {
819
+ const actionMapper = (action) => {
820
+ return Promise.resolve()
821
+ .then(() => this.deps.actionExecution.runInContext(executionContext, action))
822
+ .catch((error) => {
823
+ if (!isSilentError(error)) {
824
+ const parameters = isTramvaiAction(action) ? action : action[ACTION_PARAMETERS];
825
+ this.log.error({
826
+ error,
827
+ event: `action-execution-error`,
828
+ message: `${parameters.name} execution error`,
829
+ });
830
+ }
831
+ if (stopRunAtError(error)) {
832
+ throw error;
833
+ }
749
834
  });
750
- if (stopRunAtError(error)) {
751
- throw error;
752
- }
753
- });
754
- };
755
- return Promise.all(actions.map(actionMapper));
835
+ };
836
+ await Promise.all(actions.map(actionMapper));
837
+ });
756
838
  }
757
839
  }
758
840
 
@@ -830,23 +912,26 @@ ActionModule = __decorate([
830
912
  context: CONTEXT_TOKEN,
831
913
  store: STORE_TOKEN,
832
914
  di: DI_TOKEN,
915
+ executionContextManager: EXECUTION_CONTEXT_MANAGER_TOKEN,
833
916
  transformAction: {
834
917
  token: 'actionTransformAction',
835
918
  optional: true,
836
919
  },
837
920
  },
838
921
  }),
839
- {
922
+ provide({
840
923
  provide: ACTION_PAGE_RUNNER_TOKEN,
841
924
  scope: Scope.REQUEST,
842
925
  useClass: ActionPageRunner,
843
926
  deps: {
844
927
  actionExecution: ACTION_EXECUTION_TOKEN,
928
+ executionContextManager: EXECUTION_CONTEXT_MANAGER_TOKEN,
929
+ commandLineExecutionContext: COMMAND_LINE_EXECUTION_CONTEXT_TOKEN,
845
930
  store: STORE_TOKEN,
846
931
  limitTime: 'limitActionGlobalTimeRun',
847
932
  logger: LOGGER_TOKEN,
848
933
  },
849
- },
934
+ }),
850
935
  {
851
936
  provide: 'limitActionGlobalTimeRun',
852
937
  useValue: 500,
@@ -963,6 +1048,58 @@ CacheModule = __decorate([
963
1048
  })
964
1049
  ], CacheModule);
965
1050
 
1051
+ const EMPTY_VALUES = {};
1052
+ const normalizeOptions = (nameOrOptions) => {
1053
+ return typeof nameOrOptions === 'string' ? { name: nameOrOptions } : nameOrOptions;
1054
+ };
1055
+ class ExecutionContextManager {
1056
+ async withContext(parentContext, nameOrOptions, cb) {
1057
+ const options = normalizeOptions(nameOrOptions);
1058
+ const { name, values: selfValues = EMPTY_VALUES } = options;
1059
+ const contextName = parentContext ? `${parentContext.name}.${name}` : name;
1060
+ if (parentContext === null || parentContext === void 0 ? void 0 : parentContext.abortSignal.aborted) {
1061
+ throw new ExecutionAbortError({
1062
+ message: `Execution aborted in context "${contextName}"`,
1063
+ contextName,
1064
+ });
1065
+ }
1066
+ const abortController = new AbortController();
1067
+ let abortListener;
1068
+ let values = selfValues;
1069
+ if (parentContext) {
1070
+ values = {
1071
+ ...parentContext.values,
1072
+ ...selfValues,
1073
+ };
1074
+ abortListener = () => {
1075
+ abortController.abort();
1076
+ };
1077
+ // abort child context AbortController if parent AbortController was aborted
1078
+ parentContext.abortSignal.addEventListener('abort', abortListener);
1079
+ }
1080
+ const context = {
1081
+ name: contextName,
1082
+ abortSignal: abortController.signal,
1083
+ values,
1084
+ };
1085
+ try {
1086
+ const result = await cb(context, abortController);
1087
+ return result;
1088
+ }
1089
+ catch (error) {
1090
+ if (!error.executionContextName) {
1091
+ error.executionContextName = context.name;
1092
+ }
1093
+ throw error;
1094
+ }
1095
+ finally {
1096
+ if (abortListener) {
1097
+ parentContext.abortSignal.removeEventListener('abort', abortListener);
1098
+ }
1099
+ }
1100
+ }
1101
+ }
1102
+
966
1103
  let CommonModule = class CommonModule {
967
1104
  };
968
1105
  CommonModule = __decorate([
@@ -1033,6 +1170,10 @@ CommonModule = __decorate([
1033
1170
  store: STORE_TOKEN,
1034
1171
  },
1035
1172
  }),
1173
+ provide({
1174
+ provide: EXECUTION_CONTEXT_MANAGER_TOKEN,
1175
+ useClass: ExecutionContextManager,
1176
+ }),
1036
1177
  ...providers$2,
1037
1178
  ],
1038
1179
  })
@@ -1129,4 +1270,4 @@ CommonChildAppModule = __decorate([
1129
1270
  })
1130
1271
  ], CommonChildAppModule);
1131
1272
 
1132
- export { ActionExecution, CommandModule, CommonChildAppModule, CommonModule, alwaysCondition, createConsumerContext, onlyBrowser, onlyServer, pageBrowser, pageServer };
1273
+ export { ActionExecution, CommandModule, CommonChildAppModule, CommonModule, ExecutionContextManager, alwaysCondition, createConsumerContext, onlyBrowser, onlyServer, pageBrowser, pageServer };
package/lib/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  export { CommonModule } from './CommonModule';
2
2
  export { CommandModule } from './command/CommandModule';
3
3
  export { ActionExecution } from './actions/actionExecution';
4
+ export { ExecutionContextManager } from './executionContext/executionContextManager';
4
5
  export { alwaysCondition, onlyServer, onlyBrowser, pageServer, pageBrowser, } from './actions/ActionModule';
5
6
  export { createConsumerContext } from './createConsumerContext/createConsumerContext';
6
7
  export { CommonChildAppModule } from './child-app/ChildAppModule';