@tramvai/module-child-app 4.22.0 → 4.23.0

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,6 +1,6 @@
1
- import { Scope, DI_TOKEN } from '@tinkoff/dippy';
1
+ import { Scope, DI_TOKEN, optional } from '@tinkoff/dippy';
2
2
  import { provide, commandLineListTokens } from '@tramvai/core';
3
- import { CHILD_APP_LOADER_TOKEN, CHILD_APP_PRELOAD_MANAGER_TOKEN, CHILD_APP_COMMAND_LINE_RUNNER_TOKEN, CHILD_APP_RESOLUTION_CONFIG_MANAGER_TOKEN, CHILD_APP_RESOLVE_CONFIG_TOKEN, CHILD_APP_DI_MANAGER_TOKEN, CHILD_APP_COMMON_INITIAL_STATE_TOKEN, CHILD_APP_RENDER_MANAGER_TOKEN, CHILD_APP_CONTRACT_MANAGER, HOST_PROVIDED_CONTRACTS } from '@tramvai/tokens-child-app';
3
+ import { CHILD_APP_LOADER_TOKEN, CHILD_APP_PRELOAD_MANAGER_TOKEN, CHILD_APP_COMMAND_LINE_RUNNER_TOKEN, CHILD_APP_RESOLUTION_CONFIG_MANAGER_TOKEN, CHILD_APP_RESOLVE_CONFIG_TOKEN, CHILD_APP_DI_MANAGER_TOKEN, CHILD_APP_COMMON_INITIAL_STATE_TOKEN, CHILD_APP_RENDER_MANAGER_TOKEN, CHILD_APP_CONTRACT_MANAGER, HOST_PROVIDED_CONTRACTS, HOST_REQUIRED_CONTRACTS } from '@tramvai/tokens-child-app';
4
4
  import { LOGGER_TOKEN, STORE_TOKEN } from '@tramvai/tokens-common';
5
5
  import { ROUTER_TOKEN, PAGE_SERVICE_TOKEN } from '@tramvai/tokens-router';
6
6
  import { ChildAppContractManager } from '../contracts/contractManager.browser.browser.js';
@@ -136,7 +136,9 @@ const browserProviders = [
136
136
  useFactory: (deps) => new ChildAppContractManager(deps),
137
137
  deps: {
138
138
  appDi: DI_TOKEN,
139
- hostProvidedContracts: HOST_PROVIDED_CONTRACTS,
139
+ hostProvidedContracts: optional(HOST_PROVIDED_CONTRACTS),
140
+ hostRequiredContracts: optional(HOST_REQUIRED_CONTRACTS),
141
+ logger: LOGGER_TOKEN,
140
142
  },
141
143
  }),
142
144
  provide({
@@ -1,33 +1,140 @@
1
1
  import flatten from '@tinkoff/utils/array/flatten';
2
+ import isNil from '@tinkoff/utils/is/nil';
2
3
  import { optional } from '@tinkoff/dippy';
3
- import { CHILD_APP_INTERNAL_CONFIG_TOKEN, IS_CHILD_APP_CONTRACTS_COMPATIBLE_TOKEN, CHILD_REQUIRED_CONTRACTS } from '@tramvai/tokens-child-app';
4
+ import { CHILD_APP_INTERNAL_CONFIG_TOKEN, IS_CHILD_APP_CONTRACTS_COMPATIBLE_TOKEN, CHILD_REQUIRED_CONTRACTS, CHILD_CONTRACTS_FALLBACK, HOST_CONTRACTS_FALLBACK, CHILD_APP_PRELOAD_MANAGER_TOKEN, CHILD_APP_RESOLVE_CONFIG_TOKEN, CHILD_PROVIDED_CONTRACTS } from '@tramvai/tokens-child-app';
4
5
 
6
+ /* eslint-disable no-console */
5
7
  class BaseChildAppContractManager {
6
- constructor({ hostProvidedContracts }) {
7
- this.hostProvidedContracts = hostProvidedContracts;
8
+ constructor({ appDi, hostProvidedContracts, hostRequiredContracts, logger, }) {
9
+ this.appDi = appDi;
10
+ this.hostProvidedContracts = hostProvidedContracts !== null && hostProvidedContracts !== void 0 ? hostProvidedContracts : [];
11
+ this.hostRequiredContracts = hostRequiredContracts !== null && hostRequiredContracts !== void 0 ? hostRequiredContracts : [];
12
+ this.log = logger('child-app:contract-manager');
8
13
  }
9
14
  registerChildContracts(childDi) {
10
- var _a;
15
+ var _a, _b;
11
16
  const childAppConfig = childDi.get(CHILD_APP_INTERNAL_CONFIG_TOKEN);
12
17
  const childHasContractsSupport = childDi.get(optional(IS_CHILD_APP_CONTRACTS_COMPATIBLE_TOKEN));
13
18
  const childRequiredContracts = flatten((_a = childDi.get(optional(CHILD_REQUIRED_CONTRACTS))) !== null && _a !== void 0 ? _a : []);
14
- const childRequiredContractsKeys = childRequiredContracts.map((c) => c.toString());
15
19
  const hostProvidedContracts = this.getHostProvidedContracts(childAppConfig.name);
20
+ const hostProvidedContractsKeys = hostProvidedContracts.map((c) => c.toString());
16
21
  // if contracts unsupported, it is a legacy child app, and we need to register all possible contracts
17
- // otherwise register only required for child app contracts
18
- const hasContractsToRegistration = !childHasContractsSupport || childRequiredContracts.length > 0;
19
- if (hasContractsToRegistration) {
20
- for (const contract of hostProvidedContracts) {
22
+ if (!childHasContractsSupport) {
23
+ hostProvidedContracts.forEach((contract) => {
24
+ this.registerContract(childDi, contract);
25
+ });
26
+ // otherwise register only required for child app contracts
27
+ }
28
+ else if (childHasContractsSupport && childRequiredContracts.length > 0) {
29
+ const missedContracts = [];
30
+ childRequiredContracts.forEach((contract) => {
21
31
  const contractKey = contract.toString();
22
- // if contracts unsupported, it is a legacy child app, and we need to register all possible contracts
23
- // otherwise match required and provided contracts by key
24
- const isChildRequiredContract = !childHasContractsSupport || childRequiredContractsKeys.includes(contractKey);
25
- if (isChildRequiredContract) {
26
- this.registerContract(childDi, contract);
32
+ if (hostProvidedContractsKeys.includes(contractKey)) {
33
+ this.registerContract(childDi,
34
+ // we can't use `contract` here, because token from Child App chunk and from host bundle will not be equal by reference
35
+ hostProvidedContracts.find((c) => c.toString() === contractKey));
36
+ }
37
+ else {
38
+ this.log.warn(`Contract "${contract}" for "${childAppConfig.name}" Child App is not provided in the application`);
39
+ missedContracts.push(contract);
27
40
  }
41
+ });
42
+ if (missedContracts.length) {
43
+ this.log.warn({
44
+ message: `Missed contracts for "${childAppConfig.name}" Child App`,
45
+ missedContracts,
46
+ });
47
+ const fallbacks = (_b = childDi.get(optional(CHILD_CONTRACTS_FALLBACK))) !== null && _b !== void 0 ? _b : [];
48
+ fallbacks.forEach((fallback) => {
49
+ fallback({
50
+ childDi,
51
+ missedContracts,
52
+ });
53
+ });
54
+ }
55
+ }
56
+ }
57
+ validateChildProvidedContracts(childDi) {
58
+ var _a;
59
+ const childAppConfig = childDi.get(CHILD_APP_INTERNAL_CONFIG_TOKEN);
60
+ const hostDi = this.getRequestHostDi();
61
+ const childProvidedContracts = this.getChildProvidedContracts(childDi);
62
+ const childProvidedContractsKeys = childProvidedContracts.map((c) => c.toString());
63
+ const hostRequiredContracts = this.getHostRequiredContracts(childAppConfig.name);
64
+ const missedContracts = [];
65
+ hostRequiredContracts.forEach((required) => {
66
+ const requiredKey = required.toString();
67
+ if (!childProvidedContractsKeys.includes(requiredKey)) {
68
+ missedContracts.push(required);
28
69
  }
70
+ });
71
+ if (missedContracts.length) {
72
+ this.log.warn({
73
+ message: `Missed contracts for application, required from "${childAppConfig.name}" Child App`,
74
+ missedContracts,
75
+ });
76
+ const fallbacks = (_a = hostDi.get(optional(HOST_CONTRACTS_FALLBACK))) !== null && _a !== void 0 ? _a : [];
77
+ fallbacks.forEach((fallback) => {
78
+ fallback({
79
+ hostDi,
80
+ missedContracts,
81
+ });
82
+ });
29
83
  }
30
84
  }
85
+ async getChildProvidedContract(childAppName, contract) {
86
+ var _a, _b, _c, _d;
87
+ try {
88
+ // Resolve CHILD_APP_PRELOAD_MANAGER_TOKEN from DI to prevent circular dependency error
89
+ const childAppPreloadManager = this.appDi.get(CHILD_APP_PRELOAD_MANAGER_TOKEN);
90
+ // Wait for Child App loading before trying to resolve contract from Child App DI
91
+ await childAppPreloadManager.preload({ name: childAppName });
92
+ }
93
+ catch {
94
+ return null;
95
+ }
96
+ const childAppDi = this.getChildDi(childAppName);
97
+ const childProvidedContracts = this.getChildProvidedContracts(childAppName);
98
+ const childProvidedContractsKeys = childProvidedContracts.map((c) => c.toString());
99
+ const hostRequiredContracts = this.getHostRequiredContracts(childAppName);
100
+ const hostRequiredContractsKeys = hostRequiredContracts.map((c) => c.toString());
101
+ if (!hostRequiredContractsKeys.includes(contract.toString())) {
102
+ this.log.warn(`Contract "${contract}" is not required in the application`);
103
+ return null;
104
+ }
105
+ if (!childProvidedContractsKeys.includes(contract.toString())) {
106
+ this.log.warn(`Contract "${contract}" is not provided in the "${childAppName}" Child App`);
107
+ }
108
+ const result = ((_d = (_c = (_a = childAppDi === null || childAppDi === void 0 ? void 0 : childAppDi.get(optional(contract))) !== null && _a !== void 0 ? _a :
109
+ // contract can be registered in host DI in fallback
110
+ (_b = this.getRequestHostDi()) === null || _b === void 0 ? void 0 : _b.get(optional(contract))) !== null && _c !== void 0 ? _c : this.appDi.get(optional(contract))) !== null && _d !== void 0 ? _d : null);
111
+ if (isNil(result)) {
112
+ this.log.warn(`Contract "${contract}" is declared but not provided in the "${childAppName}" Child App or application contracts fallback`);
113
+ }
114
+ return result;
115
+ }
116
+ getChildDi(childAppName) {
117
+ var _a;
118
+ // Resolve CHILD_APP_RESOLVE_CONFIG_TOKEN from DI to prevent scope conflict warning
119
+ const resolveChildAppConfig = ((_a = this.getRequestHostDi()) !== null && _a !== void 0 ? _a : this.appDi).get(CHILD_APP_RESOLVE_CONFIG_TOKEN);
120
+ const childAppConfig = resolveChildAppConfig({ name: childAppName });
121
+ // ContractManager has Singleton scope, and we need to get Request scope Child App DI container.
122
+ // At server-side it will be resolved from Async Local Storage, at client-side everything is Singleton
123
+ const childAppDiManager = this.getRequestChildDiManager();
124
+ const childAppDi = childAppDiManager === null || childAppDiManager === void 0 ? void 0 : childAppDiManager.getChildDi(childAppConfig);
125
+ return childAppDi;
126
+ }
127
+ /**
128
+ * Pass DI here when we can't resolve it from Child DI manager without cycle
129
+ * - `Container` is used in case when `validateChildProvidedContracts` call this method
130
+ * - `string` is used in case when `getChildProvidedContract` call this method
131
+ */
132
+ getChildProvidedContracts(childAppNameOrDi) {
133
+ var _a;
134
+ const childAppDi = typeof childAppNameOrDi === 'string' ? this.getChildDi(childAppNameOrDi) : childAppNameOrDi;
135
+ const childProvidedContracts = flatten((_a = childAppDi === null || childAppDi === void 0 ? void 0 : childAppDi.get(optional(CHILD_PROVIDED_CONTRACTS))) !== null && _a !== void 0 ? _a : []);
136
+ return childProvidedContracts;
137
+ }
31
138
  getHostProvidedContracts(childAppName) {
32
139
  const contracts = [];
33
140
  // look over all provided by host contracts
@@ -41,6 +148,19 @@ class BaseChildAppContractManager {
41
148
  }
42
149
  return contracts;
43
150
  }
151
+ getHostRequiredContracts(childAppName) {
152
+ const contracts = [];
153
+ // look over all required by host contracts
154
+ for (const contract of this.hostRequiredContracts) {
155
+ // host require contract from specific Child APp
156
+ const contractFromChild = contract.childAppName === childAppName;
157
+ if (contractFromChild) {
158
+ contracts.push(...contract.requiredContracts);
159
+ }
160
+ }
161
+ return contracts;
162
+ }
44
163
  }
164
+ /* eslint-enable no-console */
45
165
 
46
166
  export { BaseChildAppContractManager };
@@ -1,16 +1,36 @@
1
- import type { ExtractDependencyType } from '@tinkoff/dippy';
1
+ import type { ExtractDependencyType, TokenInterface } from '@tinkoff/dippy';
2
2
  import { type Container } from '@tinkoff/dippy';
3
- import type { Contract, HOST_PROVIDED_CONTRACTS } from '@tramvai/tokens-child-app';
4
- import { type ChildAppContractManager as IChildAppContractManager } from '@tramvai/tokens-child-app';
5
- type HostProvidedContracts = ExtractDependencyType<typeof HOST_PROVIDED_CONTRACTS>;
3
+ import type { CHILD_APP_DI_MANAGER_TOKEN, Contract, HOST_PROVIDED_CONTRACTS, HOST_REQUIRED_CONTRACTS, ChildAppContractManager as IChildAppContractManager } from '@tramvai/tokens-child-app';
4
+ import type { LOGGER_TOKEN } from '@tramvai/tokens-common';
5
+ export type HostProvidedContracts = ExtractDependencyType<typeof HOST_PROVIDED_CONTRACTS>;
6
+ export type HostRequiredContracts = ExtractDependencyType<typeof HOST_REQUIRED_CONTRACTS>;
7
+ export type ChildAppDiManager = ExtractDependencyType<typeof CHILD_APP_DI_MANAGER_TOKEN>;
8
+ export type Logger = ExtractDependencyType<typeof LOGGER_TOKEN>;
6
9
  export declare abstract class BaseChildAppContractManager implements IChildAppContractManager {
7
- private hostProvidedContracts;
8
- constructor({ hostProvidedContracts }: {
9
- hostProvidedContracts: HostProvidedContracts;
10
+ protected appDi: Container;
11
+ protected hostProvidedContracts: HostProvidedContracts;
12
+ protected hostRequiredContracts: HostRequiredContracts;
13
+ protected log: ReturnType<Logger>;
14
+ constructor({ appDi, hostProvidedContracts, hostRequiredContracts, logger, }: {
15
+ appDi: Container;
16
+ hostProvidedContracts: HostProvidedContracts | null;
17
+ hostRequiredContracts: HostRequiredContracts | null;
18
+ logger: Logger;
10
19
  });
20
+ protected abstract registerContract(childDi: Container, contract: Contract): void;
21
+ protected abstract getRequestHostDi(): Container | null;
22
+ protected abstract getRequestChildDiManager(): ChildAppDiManager | null;
11
23
  registerChildContracts(childDi: Container): void;
12
- abstract registerContract(childDi: Container, contract: Contract): void;
24
+ validateChildProvidedContracts(childDi: Container): void;
25
+ getChildProvidedContract<T extends TokenInterface<any>>(childAppName: string, contract: T): Promise<ExtractDependencyType<T> | null>;
26
+ private getChildDi;
27
+ /**
28
+ * Pass DI here when we can't resolve it from Child DI manager without cycle
29
+ * - `Container` is used in case when `validateChildProvidedContracts` call this method
30
+ * - `string` is used in case when `getChildProvidedContract` call this method
31
+ */
32
+ private getChildProvidedContracts;
13
33
  private getHostProvidedContracts;
34
+ private getHostRequiredContracts;
14
35
  }
15
- export {};
16
36
  //# sourceMappingURL=contractManager.base.d.ts.map
@@ -1,33 +1,140 @@
1
1
  import flatten from '@tinkoff/utils/array/flatten';
2
+ import isNil from '@tinkoff/utils/is/nil';
2
3
  import { optional } from '@tinkoff/dippy';
3
- import { CHILD_APP_INTERNAL_CONFIG_TOKEN, IS_CHILD_APP_CONTRACTS_COMPATIBLE_TOKEN, CHILD_REQUIRED_CONTRACTS } from '@tramvai/tokens-child-app';
4
+ import { CHILD_APP_INTERNAL_CONFIG_TOKEN, IS_CHILD_APP_CONTRACTS_COMPATIBLE_TOKEN, CHILD_REQUIRED_CONTRACTS, CHILD_CONTRACTS_FALLBACK, HOST_CONTRACTS_FALLBACK, CHILD_APP_PRELOAD_MANAGER_TOKEN, CHILD_APP_RESOLVE_CONFIG_TOKEN, CHILD_PROVIDED_CONTRACTS } from '@tramvai/tokens-child-app';
4
5
 
6
+ /* eslint-disable no-console */
5
7
  class BaseChildAppContractManager {
6
- constructor({ hostProvidedContracts }) {
7
- this.hostProvidedContracts = hostProvidedContracts;
8
+ constructor({ appDi, hostProvidedContracts, hostRequiredContracts, logger, }) {
9
+ this.appDi = appDi;
10
+ this.hostProvidedContracts = hostProvidedContracts !== null && hostProvidedContracts !== void 0 ? hostProvidedContracts : [];
11
+ this.hostRequiredContracts = hostRequiredContracts !== null && hostRequiredContracts !== void 0 ? hostRequiredContracts : [];
12
+ this.log = logger('child-app:contract-manager');
8
13
  }
9
14
  registerChildContracts(childDi) {
10
- var _a;
15
+ var _a, _b;
11
16
  const childAppConfig = childDi.get(CHILD_APP_INTERNAL_CONFIG_TOKEN);
12
17
  const childHasContractsSupport = childDi.get(optional(IS_CHILD_APP_CONTRACTS_COMPATIBLE_TOKEN));
13
18
  const childRequiredContracts = flatten((_a = childDi.get(optional(CHILD_REQUIRED_CONTRACTS))) !== null && _a !== void 0 ? _a : []);
14
- const childRequiredContractsKeys = childRequiredContracts.map((c) => c.toString());
15
19
  const hostProvidedContracts = this.getHostProvidedContracts(childAppConfig.name);
20
+ const hostProvidedContractsKeys = hostProvidedContracts.map((c) => c.toString());
16
21
  // if contracts unsupported, it is a legacy child app, and we need to register all possible contracts
17
- // otherwise register only required for child app contracts
18
- const hasContractsToRegistration = !childHasContractsSupport || childRequiredContracts.length > 0;
19
- if (hasContractsToRegistration) {
20
- for (const contract of hostProvidedContracts) {
22
+ if (!childHasContractsSupport) {
23
+ hostProvidedContracts.forEach((contract) => {
24
+ this.registerContract(childDi, contract);
25
+ });
26
+ // otherwise register only required for child app contracts
27
+ }
28
+ else if (childHasContractsSupport && childRequiredContracts.length > 0) {
29
+ const missedContracts = [];
30
+ childRequiredContracts.forEach((contract) => {
21
31
  const contractKey = contract.toString();
22
- // if contracts unsupported, it is a legacy child app, and we need to register all possible contracts
23
- // otherwise match required and provided contracts by key
24
- const isChildRequiredContract = !childHasContractsSupport || childRequiredContractsKeys.includes(contractKey);
25
- if (isChildRequiredContract) {
26
- this.registerContract(childDi, contract);
32
+ if (hostProvidedContractsKeys.includes(contractKey)) {
33
+ this.registerContract(childDi,
34
+ // we can't use `contract` here, because token from Child App chunk and from host bundle will not be equal by reference
35
+ hostProvidedContracts.find((c) => c.toString() === contractKey));
36
+ }
37
+ else {
38
+ this.log.warn(`Contract "${contract}" for "${childAppConfig.name}" Child App is not provided in the application`);
39
+ missedContracts.push(contract);
27
40
  }
41
+ });
42
+ if (missedContracts.length) {
43
+ this.log.warn({
44
+ message: `Missed contracts for "${childAppConfig.name}" Child App`,
45
+ missedContracts,
46
+ });
47
+ const fallbacks = (_b = childDi.get(optional(CHILD_CONTRACTS_FALLBACK))) !== null && _b !== void 0 ? _b : [];
48
+ fallbacks.forEach((fallback) => {
49
+ fallback({
50
+ childDi,
51
+ missedContracts,
52
+ });
53
+ });
54
+ }
55
+ }
56
+ }
57
+ validateChildProvidedContracts(childDi) {
58
+ var _a;
59
+ const childAppConfig = childDi.get(CHILD_APP_INTERNAL_CONFIG_TOKEN);
60
+ const hostDi = this.getRequestHostDi();
61
+ const childProvidedContracts = this.getChildProvidedContracts(childDi);
62
+ const childProvidedContractsKeys = childProvidedContracts.map((c) => c.toString());
63
+ const hostRequiredContracts = this.getHostRequiredContracts(childAppConfig.name);
64
+ const missedContracts = [];
65
+ hostRequiredContracts.forEach((required) => {
66
+ const requiredKey = required.toString();
67
+ if (!childProvidedContractsKeys.includes(requiredKey)) {
68
+ missedContracts.push(required);
28
69
  }
70
+ });
71
+ if (missedContracts.length) {
72
+ this.log.warn({
73
+ message: `Missed contracts for application, required from "${childAppConfig.name}" Child App`,
74
+ missedContracts,
75
+ });
76
+ const fallbacks = (_a = hostDi.get(optional(HOST_CONTRACTS_FALLBACK))) !== null && _a !== void 0 ? _a : [];
77
+ fallbacks.forEach((fallback) => {
78
+ fallback({
79
+ hostDi,
80
+ missedContracts,
81
+ });
82
+ });
29
83
  }
30
84
  }
85
+ async getChildProvidedContract(childAppName, contract) {
86
+ var _a, _b, _c, _d;
87
+ try {
88
+ // Resolve CHILD_APP_PRELOAD_MANAGER_TOKEN from DI to prevent circular dependency error
89
+ const childAppPreloadManager = this.appDi.get(CHILD_APP_PRELOAD_MANAGER_TOKEN);
90
+ // Wait for Child App loading before trying to resolve contract from Child App DI
91
+ await childAppPreloadManager.preload({ name: childAppName });
92
+ }
93
+ catch {
94
+ return null;
95
+ }
96
+ const childAppDi = this.getChildDi(childAppName);
97
+ const childProvidedContracts = this.getChildProvidedContracts(childAppName);
98
+ const childProvidedContractsKeys = childProvidedContracts.map((c) => c.toString());
99
+ const hostRequiredContracts = this.getHostRequiredContracts(childAppName);
100
+ const hostRequiredContractsKeys = hostRequiredContracts.map((c) => c.toString());
101
+ if (!hostRequiredContractsKeys.includes(contract.toString())) {
102
+ this.log.warn(`Contract "${contract}" is not required in the application`);
103
+ return null;
104
+ }
105
+ if (!childProvidedContractsKeys.includes(contract.toString())) {
106
+ this.log.warn(`Contract "${contract}" is not provided in the "${childAppName}" Child App`);
107
+ }
108
+ const result = ((_d = (_c = (_a = childAppDi === null || childAppDi === void 0 ? void 0 : childAppDi.get(optional(contract))) !== null && _a !== void 0 ? _a :
109
+ // contract can be registered in host DI in fallback
110
+ (_b = this.getRequestHostDi()) === null || _b === void 0 ? void 0 : _b.get(optional(contract))) !== null && _c !== void 0 ? _c : this.appDi.get(optional(contract))) !== null && _d !== void 0 ? _d : null);
111
+ if (isNil(result)) {
112
+ this.log.warn(`Contract "${contract}" is declared but not provided in the "${childAppName}" Child App or application contracts fallback`);
113
+ }
114
+ return result;
115
+ }
116
+ getChildDi(childAppName) {
117
+ var _a;
118
+ // Resolve CHILD_APP_RESOLVE_CONFIG_TOKEN from DI to prevent scope conflict warning
119
+ const resolveChildAppConfig = ((_a = this.getRequestHostDi()) !== null && _a !== void 0 ? _a : this.appDi).get(CHILD_APP_RESOLVE_CONFIG_TOKEN);
120
+ const childAppConfig = resolveChildAppConfig({ name: childAppName });
121
+ // ContractManager has Singleton scope, and we need to get Request scope Child App DI container.
122
+ // At server-side it will be resolved from Async Local Storage, at client-side everything is Singleton
123
+ const childAppDiManager = this.getRequestChildDiManager();
124
+ const childAppDi = childAppDiManager === null || childAppDiManager === void 0 ? void 0 : childAppDiManager.getChildDi(childAppConfig);
125
+ return childAppDi;
126
+ }
127
+ /**
128
+ * Pass DI here when we can't resolve it from Child DI manager without cycle
129
+ * - `Container` is used in case when `validateChildProvidedContracts` call this method
130
+ * - `string` is used in case when `getChildProvidedContract` call this method
131
+ */
132
+ getChildProvidedContracts(childAppNameOrDi) {
133
+ var _a;
134
+ const childAppDi = typeof childAppNameOrDi === 'string' ? this.getChildDi(childAppNameOrDi) : childAppNameOrDi;
135
+ const childProvidedContracts = flatten((_a = childAppDi === null || childAppDi === void 0 ? void 0 : childAppDi.get(optional(CHILD_PROVIDED_CONTRACTS))) !== null && _a !== void 0 ? _a : []);
136
+ return childProvidedContracts;
137
+ }
31
138
  getHostProvidedContracts(childAppName) {
32
139
  const contracts = [];
33
140
  // look over all provided by host contracts
@@ -41,6 +148,19 @@ class BaseChildAppContractManager {
41
148
  }
42
149
  return contracts;
43
150
  }
151
+ getHostRequiredContracts(childAppName) {
152
+ const contracts = [];
153
+ // look over all required by host contracts
154
+ for (const contract of this.hostRequiredContracts) {
155
+ // host require contract from specific Child APp
156
+ const contractFromChild = contract.childAppName === childAppName;
157
+ if (contractFromChild) {
158
+ contracts.push(...contract.requiredContracts);
159
+ }
160
+ }
161
+ return contracts;
162
+ }
44
163
  }
164
+ /* eslint-enable no-console */
45
165
 
46
166
  export { BaseChildAppContractManager };
@@ -3,39 +3,147 @@
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var flatten = require('@tinkoff/utils/array/flatten');
6
+ var isNil = require('@tinkoff/utils/is/nil');
6
7
  var dippy = require('@tinkoff/dippy');
7
8
  var tokensChildApp = require('@tramvai/tokens-child-app');
8
9
 
9
10
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
10
11
 
11
12
  var flatten__default = /*#__PURE__*/_interopDefaultLegacy(flatten);
13
+ var isNil__default = /*#__PURE__*/_interopDefaultLegacy(isNil);
12
14
 
15
+ /* eslint-disable no-console */
13
16
  class BaseChildAppContractManager {
14
- constructor({ hostProvidedContracts }) {
15
- this.hostProvidedContracts = hostProvidedContracts;
17
+ constructor({ appDi, hostProvidedContracts, hostRequiredContracts, logger, }) {
18
+ this.appDi = appDi;
19
+ this.hostProvidedContracts = hostProvidedContracts !== null && hostProvidedContracts !== void 0 ? hostProvidedContracts : [];
20
+ this.hostRequiredContracts = hostRequiredContracts !== null && hostRequiredContracts !== void 0 ? hostRequiredContracts : [];
21
+ this.log = logger('child-app:contract-manager');
16
22
  }
17
23
  registerChildContracts(childDi) {
18
- var _a;
24
+ var _a, _b;
19
25
  const childAppConfig = childDi.get(tokensChildApp.CHILD_APP_INTERNAL_CONFIG_TOKEN);
20
26
  const childHasContractsSupport = childDi.get(dippy.optional(tokensChildApp.IS_CHILD_APP_CONTRACTS_COMPATIBLE_TOKEN));
21
27
  const childRequiredContracts = flatten__default["default"]((_a = childDi.get(dippy.optional(tokensChildApp.CHILD_REQUIRED_CONTRACTS))) !== null && _a !== void 0 ? _a : []);
22
- const childRequiredContractsKeys = childRequiredContracts.map((c) => c.toString());
23
28
  const hostProvidedContracts = this.getHostProvidedContracts(childAppConfig.name);
29
+ const hostProvidedContractsKeys = hostProvidedContracts.map((c) => c.toString());
24
30
  // if contracts unsupported, it is a legacy child app, and we need to register all possible contracts
25
- // otherwise register only required for child app contracts
26
- const hasContractsToRegistration = !childHasContractsSupport || childRequiredContracts.length > 0;
27
- if (hasContractsToRegistration) {
28
- for (const contract of hostProvidedContracts) {
31
+ if (!childHasContractsSupport) {
32
+ hostProvidedContracts.forEach((contract) => {
33
+ this.registerContract(childDi, contract);
34
+ });
35
+ // otherwise register only required for child app contracts
36
+ }
37
+ else if (childHasContractsSupport && childRequiredContracts.length > 0) {
38
+ const missedContracts = [];
39
+ childRequiredContracts.forEach((contract) => {
29
40
  const contractKey = contract.toString();
30
- // if contracts unsupported, it is a legacy child app, and we need to register all possible contracts
31
- // otherwise match required and provided contracts by key
32
- const isChildRequiredContract = !childHasContractsSupport || childRequiredContractsKeys.includes(contractKey);
33
- if (isChildRequiredContract) {
34
- this.registerContract(childDi, contract);
41
+ if (hostProvidedContractsKeys.includes(contractKey)) {
42
+ this.registerContract(childDi,
43
+ // we can't use `contract` here, because token from Child App chunk and from host bundle will not be equal by reference
44
+ hostProvidedContracts.find((c) => c.toString() === contractKey));
45
+ }
46
+ else {
47
+ this.log.warn(`Contract "${contract}" for "${childAppConfig.name}" Child App is not provided in the application`);
48
+ missedContracts.push(contract);
35
49
  }
50
+ });
51
+ if (missedContracts.length) {
52
+ this.log.warn({
53
+ message: `Missed contracts for "${childAppConfig.name}" Child App`,
54
+ missedContracts,
55
+ });
56
+ const fallbacks = (_b = childDi.get(dippy.optional(tokensChildApp.CHILD_CONTRACTS_FALLBACK))) !== null && _b !== void 0 ? _b : [];
57
+ fallbacks.forEach((fallback) => {
58
+ fallback({
59
+ childDi,
60
+ missedContracts,
61
+ });
62
+ });
63
+ }
64
+ }
65
+ }
66
+ validateChildProvidedContracts(childDi) {
67
+ var _a;
68
+ const childAppConfig = childDi.get(tokensChildApp.CHILD_APP_INTERNAL_CONFIG_TOKEN);
69
+ const hostDi = this.getRequestHostDi();
70
+ const childProvidedContracts = this.getChildProvidedContracts(childDi);
71
+ const childProvidedContractsKeys = childProvidedContracts.map((c) => c.toString());
72
+ const hostRequiredContracts = this.getHostRequiredContracts(childAppConfig.name);
73
+ const missedContracts = [];
74
+ hostRequiredContracts.forEach((required) => {
75
+ const requiredKey = required.toString();
76
+ if (!childProvidedContractsKeys.includes(requiredKey)) {
77
+ missedContracts.push(required);
36
78
  }
79
+ });
80
+ if (missedContracts.length) {
81
+ this.log.warn({
82
+ message: `Missed contracts for application, required from "${childAppConfig.name}" Child App`,
83
+ missedContracts,
84
+ });
85
+ const fallbacks = (_a = hostDi.get(dippy.optional(tokensChildApp.HOST_CONTRACTS_FALLBACK))) !== null && _a !== void 0 ? _a : [];
86
+ fallbacks.forEach((fallback) => {
87
+ fallback({
88
+ hostDi,
89
+ missedContracts,
90
+ });
91
+ });
37
92
  }
38
93
  }
94
+ async getChildProvidedContract(childAppName, contract) {
95
+ var _a, _b, _c, _d;
96
+ try {
97
+ // Resolve CHILD_APP_PRELOAD_MANAGER_TOKEN from DI to prevent circular dependency error
98
+ const childAppPreloadManager = this.appDi.get(tokensChildApp.CHILD_APP_PRELOAD_MANAGER_TOKEN);
99
+ // Wait for Child App loading before trying to resolve contract from Child App DI
100
+ await childAppPreloadManager.preload({ name: childAppName });
101
+ }
102
+ catch {
103
+ return null;
104
+ }
105
+ const childAppDi = this.getChildDi(childAppName);
106
+ const childProvidedContracts = this.getChildProvidedContracts(childAppName);
107
+ const childProvidedContractsKeys = childProvidedContracts.map((c) => c.toString());
108
+ const hostRequiredContracts = this.getHostRequiredContracts(childAppName);
109
+ const hostRequiredContractsKeys = hostRequiredContracts.map((c) => c.toString());
110
+ if (!hostRequiredContractsKeys.includes(contract.toString())) {
111
+ this.log.warn(`Contract "${contract}" is not required in the application`);
112
+ return null;
113
+ }
114
+ if (!childProvidedContractsKeys.includes(contract.toString())) {
115
+ this.log.warn(`Contract "${contract}" is not provided in the "${childAppName}" Child App`);
116
+ }
117
+ const result = ((_d = (_c = (_a = childAppDi === null || childAppDi === void 0 ? void 0 : childAppDi.get(dippy.optional(contract))) !== null && _a !== void 0 ? _a :
118
+ // contract can be registered in host DI in fallback
119
+ (_b = this.getRequestHostDi()) === null || _b === void 0 ? void 0 : _b.get(dippy.optional(contract))) !== null && _c !== void 0 ? _c : this.appDi.get(dippy.optional(contract))) !== null && _d !== void 0 ? _d : null);
120
+ if (isNil__default["default"](result)) {
121
+ this.log.warn(`Contract "${contract}" is declared but not provided in the "${childAppName}" Child App or application contracts fallback`);
122
+ }
123
+ return result;
124
+ }
125
+ getChildDi(childAppName) {
126
+ var _a;
127
+ // Resolve CHILD_APP_RESOLVE_CONFIG_TOKEN from DI to prevent scope conflict warning
128
+ const resolveChildAppConfig = ((_a = this.getRequestHostDi()) !== null && _a !== void 0 ? _a : this.appDi).get(tokensChildApp.CHILD_APP_RESOLVE_CONFIG_TOKEN);
129
+ const childAppConfig = resolveChildAppConfig({ name: childAppName });
130
+ // ContractManager has Singleton scope, and we need to get Request scope Child App DI container.
131
+ // At server-side it will be resolved from Async Local Storage, at client-side everything is Singleton
132
+ const childAppDiManager = this.getRequestChildDiManager();
133
+ const childAppDi = childAppDiManager === null || childAppDiManager === void 0 ? void 0 : childAppDiManager.getChildDi(childAppConfig);
134
+ return childAppDi;
135
+ }
136
+ /**
137
+ * Pass DI here when we can't resolve it from Child DI manager without cycle
138
+ * - `Container` is used in case when `validateChildProvidedContracts` call this method
139
+ * - `string` is used in case when `getChildProvidedContract` call this method
140
+ */
141
+ getChildProvidedContracts(childAppNameOrDi) {
142
+ var _a;
143
+ const childAppDi = typeof childAppNameOrDi === 'string' ? this.getChildDi(childAppNameOrDi) : childAppNameOrDi;
144
+ const childProvidedContracts = flatten__default["default"]((_a = childAppDi === null || childAppDi === void 0 ? void 0 : childAppDi.get(dippy.optional(tokensChildApp.CHILD_PROVIDED_CONTRACTS))) !== null && _a !== void 0 ? _a : []);
145
+ return childProvidedContracts;
146
+ }
39
147
  getHostProvidedContracts(childAppName) {
40
148
  const contracts = [];
41
149
  // look over all provided by host contracts
@@ -49,6 +157,19 @@ class BaseChildAppContractManager {
49
157
  }
50
158
  return contracts;
51
159
  }
160
+ getHostRequiredContracts(childAppName) {
161
+ const contracts = [];
162
+ // look over all required by host contracts
163
+ for (const contract of this.hostRequiredContracts) {
164
+ // host require contract from specific Child APp
165
+ const contractFromChild = contract.childAppName === childAppName;
166
+ if (contractFromChild) {
167
+ contracts.push(...contract.requiredContracts);
168
+ }
169
+ }
170
+ return contracts;
171
+ }
52
172
  }
173
+ /* eslint-enable no-console */
53
174
 
54
175
  exports.BaseChildAppContractManager = BaseChildAppContractManager;
@@ -1,22 +1,28 @@
1
1
  import isNil from '@tinkoff/utils/is/nil';
2
2
  import { provide, optional } from '@tinkoff/dippy';
3
+ import { CHILD_APP_INTERNAL_CONFIG_TOKEN, CHILD_APP_DI_MANAGER_TOKEN } from '@tramvai/tokens-child-app';
3
4
  import { BaseChildAppContractManager } from './contractManager.base.browser.js';
4
5
 
5
6
  class ChildAppContractManager extends BaseChildAppContractManager {
6
- constructor({ appDi, hostProvidedContracts, }) {
7
- super({ hostProvidedContracts });
8
- this.appDi = appDi;
9
- }
10
7
  registerContract(childDi, contract) {
11
8
  childDi.register(provide({
12
9
  provide: contract,
13
10
  useFactory: () => {
14
11
  const value = this.appDi.get(optional(contract));
15
- if (isNil(value)) ;
12
+ if (isNil(value)) {
13
+ const { name } = childDi.get(CHILD_APP_INTERNAL_CONFIG_TOKEN);
14
+ this.log.warn(`Contract "${contract}" for "${name}" Child App is declared but not provided in the application or contracts fallback`);
15
+ }
16
16
  return value;
17
17
  },
18
18
  }));
19
19
  }
20
+ getRequestHostDi() {
21
+ return this.appDi;
22
+ }
23
+ getRequestChildDiManager() {
24
+ return this.appDi.get(optional(CHILD_APP_DI_MANAGER_TOKEN));
25
+ }
20
26
  }
21
27
 
22
28
  export { ChildAppContractManager };
@@ -1,15 +1,10 @@
1
- import type { ExtractDependencyType } from '@tinkoff/dippy';
2
1
  import { type Container } from '@tinkoff/dippy';
3
- import type { Contract, HOST_PROVIDED_CONTRACTS } from '@tramvai/tokens-child-app';
2
+ import type { Contract } from '@tramvai/tokens-child-app';
3
+ import type { ChildAppDiManager } from './contractManager.base';
4
4
  import { BaseChildAppContractManager } from './contractManager.base';
5
- type HostProvidedContracts = ExtractDependencyType<typeof HOST_PROVIDED_CONTRACTS>;
6
5
  export declare class ChildAppContractManager extends BaseChildAppContractManager {
7
- private appDi;
8
- constructor({ appDi, hostProvidedContracts, }: {
9
- appDi: Container;
10
- hostProvidedContracts: HostProvidedContracts;
11
- });
12
6
  registerContract(childDi: Container, contract: Contract): void;
7
+ getRequestHostDi(): Container | null;
8
+ getRequestChildDiManager(): ChildAppDiManager | null;
13
9
  }
14
- export {};
15
10
  //# sourceMappingURL=contractManager.browser.d.ts.map
@@ -1,24 +1,27 @@
1
1
  import type { DI_TOKEN, ExtractDependencyType } from '@tinkoff/dippy';
2
2
  import { type Container } from '@tinkoff/dippy';
3
- import type { Contract, HOST_PROVIDED_CONTRACTS } from '@tramvai/tokens-child-app';
3
+ import type { Contract } from '@tramvai/tokens-child-app';
4
4
  import type { ASYNC_LOCAL_STORAGE_TOKEN } from '@tramvai/tokens-common';
5
+ import type { ChildAppDiManager, HostProvidedContracts, HostRequiredContracts, Logger } from './contractManager.base';
5
6
  import { BaseChildAppContractManager } from './contractManager.base';
6
7
  declare module '@tramvai/tokens-common' {
7
8
  interface AsyncLocalStorageState {
8
9
  tramvaiRequestDi?: ExtractDependencyType<typeof DI_TOKEN>;
9
10
  }
10
11
  }
11
- type HostProvidedContracts = ExtractDependencyType<typeof HOST_PROVIDED_CONTRACTS>;
12
12
  type AsyncLocalStorageType = ExtractDependencyType<typeof ASYNC_LOCAL_STORAGE_TOKEN>;
13
13
  export declare class ChildAppContractManager extends BaseChildAppContractManager {
14
- private appDi;
15
14
  private asyncLocalStorage;
16
- constructor({ appDi, asyncLocalStorage, hostProvidedContracts, }: {
15
+ constructor({ appDi, asyncLocalStorage, hostProvidedContracts, hostRequiredContracts, logger, }: {
17
16
  appDi: Container;
18
17
  asyncLocalStorage: AsyncLocalStorageType;
19
- hostProvidedContracts: HostProvidedContracts;
18
+ hostProvidedContracts: HostProvidedContracts | null;
19
+ hostRequiredContracts: HostRequiredContracts | null;
20
+ logger: Logger;
20
21
  });
21
22
  registerContract(childDi: Container, contract: Contract): void;
23
+ getRequestHostDi(): Container | null;
24
+ getRequestChildDiManager(): ChildAppDiManager | null;
22
25
  }
23
26
  export {};
24
27
  //# sourceMappingURL=contractManager.server.d.ts.map
@@ -1,11 +1,16 @@
1
1
  import isNil from '@tinkoff/utils/is/nil';
2
2
  import { provide, optional } from '@tinkoff/dippy';
3
+ import { CHILD_APP_INTERNAL_CONFIG_TOKEN, CHILD_APP_DI_MANAGER_TOKEN } from '@tramvai/tokens-child-app';
3
4
  import { BaseChildAppContractManager } from './contractManager.base.es.js';
4
5
 
5
6
  class ChildAppContractManager extends BaseChildAppContractManager {
6
- constructor({ appDi, asyncLocalStorage, hostProvidedContracts, }) {
7
- super({ hostProvidedContracts });
8
- this.appDi = appDi;
7
+ constructor({ appDi, asyncLocalStorage, hostProvidedContracts, hostRequiredContracts, logger, }) {
8
+ super({
9
+ appDi,
10
+ hostProvidedContracts,
11
+ hostRequiredContracts,
12
+ logger,
13
+ });
9
14
  this.asyncLocalStorage = asyncLocalStorage;
10
15
  }
11
16
  registerContract(childDi, contract) {
@@ -14,12 +19,24 @@ class ChildAppContractManager extends BaseChildAppContractManager {
14
19
  useFactory: () => {
15
20
  var _a, _b, _c;
16
21
  const value = (_c = (_b = (_a = this.asyncLocalStorage.getStore()) === null || _a === void 0 ? void 0 : _a.tramvaiRequestDi) === null || _b === void 0 ? void 0 : _b.get(optional(contract))) !== null && _c !== void 0 ? _c : this.appDi.get(optional(contract));
17
- if (isNil(value)) ;
22
+ if (isNil(value)) {
23
+ const { name } = childDi.get(CHILD_APP_INTERNAL_CONFIG_TOKEN);
24
+ this.log.warn(`Contract "${contract}" for "${name}" Child App is declared but not provided in the application or contracts fallback`);
25
+ }
18
26
  // TODO: Request scoped contrace is resolved in Singleton scope - what should we do?
19
27
  return value;
20
28
  },
21
29
  }));
22
30
  }
31
+ getRequestHostDi() {
32
+ var _a, _b;
33
+ return (_b = (_a = this.asyncLocalStorage.getStore()) === null || _a === void 0 ? void 0 : _a.tramvaiRequestDi) !== null && _b !== void 0 ? _b : null;
34
+ }
35
+ getRequestChildDiManager() {
36
+ var _a, _b, _c;
37
+ return ((_c = (_b = (_a = this.asyncLocalStorage
38
+ .getStore()) === null || _a === void 0 ? void 0 : _a.tramvaiRequestDi) === null || _b === void 0 ? void 0 : _b.get(optional(CHILD_APP_DI_MANAGER_TOKEN))) !== null && _c !== void 0 ? _c : null);
39
+ }
23
40
  }
24
41
 
25
42
  export { ChildAppContractManager };
@@ -4,6 +4,7 @@ Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var isNil = require('@tinkoff/utils/is/nil');
6
6
  var dippy = require('@tinkoff/dippy');
7
+ var tokensChildApp = require('@tramvai/tokens-child-app');
7
8
  var contractManager_base = require('./contractManager.base.js');
8
9
 
9
10
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
@@ -11,9 +12,13 @@ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'defau
11
12
  var isNil__default = /*#__PURE__*/_interopDefaultLegacy(isNil);
12
13
 
13
14
  class ChildAppContractManager extends contractManager_base.BaseChildAppContractManager {
14
- constructor({ appDi, asyncLocalStorage, hostProvidedContracts, }) {
15
- super({ hostProvidedContracts });
16
- this.appDi = appDi;
15
+ constructor({ appDi, asyncLocalStorage, hostProvidedContracts, hostRequiredContracts, logger, }) {
16
+ super({
17
+ appDi,
18
+ hostProvidedContracts,
19
+ hostRequiredContracts,
20
+ logger,
21
+ });
17
22
  this.asyncLocalStorage = asyncLocalStorage;
18
23
  }
19
24
  registerContract(childDi, contract) {
@@ -22,12 +27,24 @@ class ChildAppContractManager extends contractManager_base.BaseChildAppContractM
22
27
  useFactory: () => {
23
28
  var _a, _b, _c;
24
29
  const value = (_c = (_b = (_a = this.asyncLocalStorage.getStore()) === null || _a === void 0 ? void 0 : _a.tramvaiRequestDi) === null || _b === void 0 ? void 0 : _b.get(dippy.optional(contract))) !== null && _c !== void 0 ? _c : this.appDi.get(dippy.optional(contract));
25
- if (isNil__default["default"](value)) ;
30
+ if (isNil__default["default"](value)) {
31
+ const { name } = childDi.get(tokensChildApp.CHILD_APP_INTERNAL_CONFIG_TOKEN);
32
+ this.log.warn(`Contract "${contract}" for "${name}" Child App is declared but not provided in the application or contracts fallback`);
33
+ }
26
34
  // TODO: Request scoped contrace is resolved in Singleton scope - what should we do?
27
35
  return value;
28
36
  },
29
37
  }));
30
38
  }
39
+ getRequestHostDi() {
40
+ var _a, _b;
41
+ return (_b = (_a = this.asyncLocalStorage.getStore()) === null || _a === void 0 ? void 0 : _a.tramvaiRequestDi) !== null && _b !== void 0 ? _b : null;
42
+ }
43
+ getRequestChildDiManager() {
44
+ var _a, _b, _c;
45
+ return ((_c = (_b = (_a = this.asyncLocalStorage
46
+ .getStore()) === null || _a === void 0 ? void 0 : _a.tramvaiRequestDi) === null || _b === void 0 ? void 0 : _b.get(dippy.optional(tokensChildApp.CHILD_APP_DI_MANAGER_TOKEN))) !== null && _c !== void 0 ? _c : null);
47
+ }
31
48
  }
32
49
 
33
50
  exports.ChildAppContractManager = ChildAppContractManager;
@@ -3,7 +3,7 @@ import { Scope, optional, DI_TOKEN } from '@tinkoff/dippy';
3
3
  import { provide, commandLineListTokens } from '@tramvai/core';
4
4
  import { ENV_USED_TOKEN, LOGGER_TOKEN, CREATE_CACHE_TOKEN, ENV_MANAGER_TOKEN, STORE_TOKEN, ASYNC_LOCAL_STORAGE_TOKEN } from '@tramvai/tokens-common';
5
5
  import { RESOURCES_REGISTRY, RENDER_SLOTS, ResourceType, ResourceSlot, RENDER_FLOW_AFTER_TOKEN, REACT_SERVER_RENDER_MODE, EXTEND_RENDER } from '@tramvai/tokens-render';
6
- import { CHILD_APP_LOADER_TOKEN, CHILD_APP_STATE_MANAGER_TOKEN, CHILD_APP_DI_MANAGER_TOKEN, CHILD_APP_PRELOAD_MANAGER_TOKEN, CHILD_APP_COMMAND_LINE_RUNNER_TOKEN, CHILD_APP_RESOLUTION_CONFIG_MANAGER_TOKEN, CHILD_APP_RESOLVE_CONFIG_TOKEN, CHILD_APP_RENDER_MANAGER_TOKEN, CHILD_APP_CONTRACT_MANAGER, HOST_PROVIDED_CONTRACTS } from '@tramvai/tokens-child-app';
6
+ import { CHILD_APP_LOADER_TOKEN, CHILD_APP_STATE_MANAGER_TOKEN, CHILD_APP_DI_MANAGER_TOKEN, CHILD_APP_PRELOAD_MANAGER_TOKEN, CHILD_APP_COMMAND_LINE_RUNNER_TOKEN, CHILD_APP_RESOLUTION_CONFIG_MANAGER_TOKEN, CHILD_APP_RESOLVE_CONFIG_TOKEN, CHILD_APP_RENDER_MANAGER_TOKEN, CHILD_APP_CONTRACT_MANAGER, HOST_PROVIDED_CONTRACTS, HOST_REQUIRED_CONTRACTS } from '@tramvai/tokens-child-app';
7
7
  import { safeStringify } from '@tramvai/safe-strings';
8
8
  import { ServerLoader } from './loader.es.js';
9
9
  import { PreloadManager } from './preload.es.js';
@@ -146,7 +146,9 @@ const serverProviders = [
146
146
  deps: {
147
147
  appDi: DI_TOKEN,
148
148
  asyncLocalStorage: ASYNC_LOCAL_STORAGE_TOKEN,
149
- hostProvidedContracts: HOST_PROVIDED_CONTRACTS,
149
+ hostProvidedContracts: optional(HOST_PROVIDED_CONTRACTS),
150
+ hostRequiredContracts: optional(HOST_REQUIRED_CONTRACTS),
151
+ logger: LOGGER_TOKEN,
150
152
  },
151
153
  }),
152
154
  ];
@@ -150,7 +150,9 @@ const serverProviders = [
150
150
  deps: {
151
151
  appDi: dippy.DI_TOKEN,
152
152
  asyncLocalStorage: tokensCommon.ASYNC_LOCAL_STORAGE_TOKEN,
153
- hostProvidedContracts: tokensChildApp.HOST_PROVIDED_CONTRACTS,
153
+ hostProvidedContracts: dippy.optional(tokensChildApp.HOST_PROVIDED_CONTRACTS),
154
+ hostRequiredContracts: dippy.optional(tokensChildApp.HOST_REQUIRED_CONTRACTS),
155
+ logger: tokensCommon.LOGGER_TOKEN,
154
156
  },
155
157
  }),
156
158
  ];
@@ -100,6 +100,7 @@ class SingletonDiManager {
100
100
  });
101
101
  if (isolateDi) {
102
102
  this.contractManager.registerChildContracts(di);
103
+ this.contractManager.validateChildProvidedContracts(di);
103
104
  }
104
105
  const borrowTokens = di.get({ token: CHILD_APP_INTERNAL_ROOT_DI_BORROW_TOKEN, optional: true });
105
106
  if (borrowTokens) {
@@ -100,6 +100,7 @@ class SingletonDiManager {
100
100
  });
101
101
  if (isolateDi) {
102
102
  this.contractManager.registerChildContracts(di);
103
+ this.contractManager.validateChildProvidedContracts(di);
103
104
  }
104
105
  const borrowTokens = di.get({ token: CHILD_APP_INTERNAL_ROOT_DI_BORROW_TOKEN, optional: true });
105
106
  if (borrowTokens) {
@@ -108,6 +108,7 @@ class SingletonDiManager {
108
108
  });
109
109
  if (isolateDi) {
110
110
  this.contractManager.registerChildContracts(di);
111
+ this.contractManager.validateChildProvidedContracts(di);
111
112
  }
112
113
  const borrowTokens = di.get({ token: tokensChildApp.CHILD_APP_INTERNAL_ROOT_DI_BORROW_TOKEN, optional: true });
113
114
  if (borrowTokens) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tramvai/module-child-app",
3
- "version": "4.22.0",
3
+ "version": "4.23.0",
4
4
  "description": "Module for child apps",
5
5
  "browser": {
6
6
  "./lib/server.js": "./lib/browser.js",
@@ -33,23 +33,23 @@
33
33
  "@tinkoff/env-validators": "0.3.1",
34
34
  "@tinkoff/module-loader-client": "0.6.3",
35
35
  "@tinkoff/module-loader-server": "0.7.2",
36
- "@tramvai/module-common": "4.22.0",
36
+ "@tramvai/module-common": "4.23.0",
37
37
  "@tinkoff/url": "0.10.1",
38
- "@tramvai/child-app-core": "4.22.0",
38
+ "@tramvai/child-app-core": "4.23.0",
39
39
  "@tramvai/safe-strings": "0.7.2",
40
- "@tramvai/tokens-child-app": "4.22.0"
40
+ "@tramvai/tokens-child-app": "4.23.0"
41
41
  },
42
42
  "devDependencies": {},
43
43
  "peerDependencies": {
44
- "@tinkoff/dippy": "0.10.7",
45
- "@tinkoff/router": "0.4.75",
44
+ "@tinkoff/dippy": "0.10.8",
45
+ "@tinkoff/router": "0.4.76",
46
46
  "@tinkoff/utils": "^2.1.2",
47
- "@tramvai/core": "4.22.0",
48
- "@tramvai/state": "4.22.0",
49
- "@tramvai/react": "4.22.0",
50
- "@tramvai/tokens-common": "4.22.0",
51
- "@tramvai/tokens-render": "4.22.0",
52
- "@tramvai/tokens-router": "4.22.0",
47
+ "@tramvai/core": "4.23.0",
48
+ "@tramvai/state": "4.23.0",
49
+ "@tramvai/react": "4.23.0",
50
+ "@tramvai/tokens-common": "4.23.0",
51
+ "@tramvai/tokens-render": "4.23.0",
52
+ "@tramvai/tokens-router": "4.23.0",
53
53
  "react": ">=16.14.0",
54
54
  "react-dom": ">=16.14.0",
55
55
  "object-assign": "^4.1.1",