@foxford/den 3.0.0 → 3.1.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.
- package/README.mdx +215 -2
- package/chunk-6ZFVV3AV.cjs +214 -0
- package/chunk-7M5OAOQ4.js +214 -0
- package/chunk-CZVYVNLI.cjs +45 -0
- package/chunk-KJ6NDOOL.js +45 -0
- package/{chunk-5DJZZML5.cjs → chunk-P4QJCHMM.cjs} +12 -29
- package/{chunk-WRQC6BVJ.js → chunk-PZVUKTZG.js} +3 -20
- package/define.cjs +4 -4
- package/define.js +3 -3
- package/den-serve.js +146 -0
- package/descriptor-DZDNH7R5.d.ts +70 -0
- package/descriptor-h0JE9jFx.d.cts +70 -0
- package/index.cjs +16 -15
- package/index.d.cts +2 -1
- package/index.d.ts +2 -1
- package/index.js +11 -10
- package/island/index.cjs +10 -156
- package/island/index.d.cts +32 -29
- package/island/index.d.ts +32 -29
- package/island/index.js +17 -163
- package/package.json +27 -10
- package/routes-BqIoqbt1.d.cts +64 -0
- package/routes-CWpIqVAM.d.ts +64 -0
- package/serve/index.cjs +136 -0
- package/serve/index.d.cts +60 -0
- package/serve/index.d.ts +60 -0
- package/serve/index.js +136 -0
- package/{view-adapter-BvDC5O4y.d.cts → view-adapter-CPI8056c.d.ts} +4 -69
- package/{view-adapter-DtNgyjIf.d.ts → view-adapter-D2597RJZ.d.cts} +4 -69
- package/chunk-A6ZPAM6Z.cjs +0 -26
- package/chunk-TPBI6TOU.js +0 -26
package/index.d.cts
CHANGED
|
@@ -4,7 +4,8 @@ import { Container, Token } from '@foxford/ioc';
|
|
|
4
4
|
import { DefinitionResolver } from './adapter.cjs';
|
|
5
5
|
export { d as defineRepository, a as defineService, b as defineViewModel } from './define-repository-MDEWHqM7.cjs';
|
|
6
6
|
export { D as DefineSlotOptions, S as SlotDefinition, d as defineSlot } from './define-slot-BKvArA02.cjs';
|
|
7
|
-
export { V as ViewAdapter, a as ViewLayerDefinition, b as ViewLayerToken } from './view-adapter-
|
|
7
|
+
export { V as ViewAdapter, a as ViewLayerDefinition, b as ViewLayerToken } from './view-adapter-D2597RJZ.cjs';
|
|
8
|
+
import './descriptor-h0JE9jFx.cjs';
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* Опции для создания Core Runtime.
|
package/index.d.ts
CHANGED
|
@@ -4,7 +4,8 @@ import { Container, Token } from '@foxford/ioc';
|
|
|
4
4
|
import { DefinitionResolver } from './adapter.js';
|
|
5
5
|
export { d as defineRepository, a as defineService, b as defineViewModel } from './define-repository-Ca62_YCy.js';
|
|
6
6
|
export { D as DefineSlotOptions, S as SlotDefinition, d as defineSlot } from './define-slot-Dil8Kr1A.js';
|
|
7
|
-
export { V as ViewAdapter, a as ViewLayerDefinition, b as ViewLayerToken } from './view-adapter-
|
|
7
|
+
export { V as ViewAdapter, a as ViewLayerDefinition, b as ViewLayerToken } from './view-adapter-CPI8056c.js';
|
|
8
|
+
import './descriptor-DZDNH7R5.js';
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* Опции для создания Core Runtime.
|
package/index.js
CHANGED
|
@@ -1,23 +1,24 @@
|
|
|
1
1
|
import {
|
|
2
|
-
ActivatableToken,
|
|
3
|
-
ContainerManagerToken,
|
|
4
|
-
GuardRunnerToken,
|
|
5
|
-
NavigationManagerToken,
|
|
6
|
-
RequestContextToken,
|
|
7
2
|
SlotRegistry,
|
|
8
|
-
SlotRegistryToken,
|
|
9
|
-
StateRegistryToken,
|
|
10
|
-
StateSerializerToken,
|
|
11
3
|
defineRepository,
|
|
12
4
|
defineService,
|
|
13
5
|
defineSlot,
|
|
14
6
|
defineViewModel
|
|
15
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-PZVUKTZG.js";
|
|
16
8
|
import "./chunk-WBHHHICS.js";
|
|
17
9
|
import {
|
|
18
10
|
ViewLayerToken
|
|
19
11
|
} from "./chunk-E23E2VUC.js";
|
|
20
|
-
import
|
|
12
|
+
import {
|
|
13
|
+
ActivatableToken,
|
|
14
|
+
ContainerManagerToken,
|
|
15
|
+
GuardRunnerToken,
|
|
16
|
+
NavigationManagerToken,
|
|
17
|
+
RequestContextToken,
|
|
18
|
+
SlotRegistryToken,
|
|
19
|
+
StateRegistryToken,
|
|
20
|
+
StateSerializerToken
|
|
21
|
+
} from "./chunk-KJ6NDOOL.js";
|
|
21
22
|
import {
|
|
22
23
|
__async
|
|
23
24
|
} from "./chunk-HJO26HIQ.js";
|
package/island/index.cjs
CHANGED
|
@@ -2,168 +2,25 @@
|
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
|
|
5
|
-
var _chunkXOJ2VWX4cjs = require('../chunk-XOJ2VWX4.cjs');
|
|
6
5
|
|
|
7
6
|
|
|
8
7
|
|
|
9
8
|
|
|
10
|
-
var _chunkA6ZPAM6Zcjs = require('../chunk-A6ZPAM6Z.cjs');
|
|
11
9
|
|
|
12
10
|
|
|
13
11
|
|
|
14
|
-
var _chunkXHYR3SGGcjs = require('../chunk-XHYR3SGG.cjs');
|
|
15
12
|
|
|
16
|
-
// src/island/document.ts
|
|
17
|
-
function isDocumentSource(value) {
|
|
18
|
-
return typeof value === "object" && value !== null && typeof value.describeDocument === "function";
|
|
19
|
-
}
|
|
20
13
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
// src/island/runtime.ts
|
|
25
|
-
var _ioc = require('@foxford/ioc');
|
|
26
|
-
var appContainer = null;
|
|
27
|
-
function getAppContainer() {
|
|
28
|
-
var _a;
|
|
29
|
-
if (appContainer === null) {
|
|
30
|
-
appContainer = new (0, _ioc.Container)();
|
|
31
|
-
((_a = _chunkA6ZPAM6Zcjs.logger.getLogger("island:runtime")) != null ? _a : _chunkA6ZPAM6Zcjs.logger).debug("app-\u043A\u043E\u043D\u0442\u0435\u0439\u043D\u0435\u0440 \u0441\u043E\u0437\u0434\u0430\u043D");
|
|
32
|
-
}
|
|
33
|
-
return appContainer;
|
|
34
|
-
}
|
|
14
|
+
var _chunk6ZFVV3AVcjs = require('../chunk-6ZFVV3AV.cjs');
|
|
15
|
+
|
|
35
16
|
|
|
36
|
-
// src/island/lifecycle.ts
|
|
37
|
-
var EMPTY_ROUTE = { params: {}, pathname: "", search: "" };
|
|
38
|
-
var REDIRECT_FOUND = 302;
|
|
39
|
-
function createIslandContainer(descriptor, options = {}) {
|
|
40
|
-
var _a, _b, _c, _d, _e;
|
|
41
|
-
const { parent = getAppContainer() } = options;
|
|
42
|
-
const appLog = (_b = _logger.log.getLogger((_a = descriptor.name) != null ? _a : "app")) != null ? _b : _chunkA6ZPAM6Zcjs.logger;
|
|
43
|
-
const islandLog = (_c = appLog.getLogger("client")) != null ? _c : appLog;
|
|
44
|
-
try {
|
|
45
|
-
const container = parent.createChild();
|
|
46
|
-
container.bind(_chunkA6ZPAM6Zcjs.LoggerToken).toValue(islandLog);
|
|
47
|
-
descriptor.viewLayer.register(container);
|
|
48
|
-
const viewModels = (_d = descriptor.viewModels) != null ? _d : [];
|
|
49
|
-
const slots = Object.entries((_e = descriptor.slots) != null ? _e : {});
|
|
50
|
-
islandLog.info(
|
|
51
|
-
`\u043E\u0441\u0442\u0440\u043E\u0432: \u043A\u043E\u043D\u0442\u0435\u0439\u043D\u0435\u0440 \u0441\u043E\u0437\u0434\u0430\u043D (units=${descriptor.units.length}, vms=${viewModels.length}, slots=${slots.length})`
|
|
52
|
-
);
|
|
53
|
-
for (const unit of descriptor.units) {
|
|
54
|
-
unit.register(container);
|
|
55
|
-
}
|
|
56
|
-
for (const vm of viewModels) {
|
|
57
|
-
vm.register(container);
|
|
58
|
-
}
|
|
59
|
-
for (const [name, slot] of slots) {
|
|
60
|
-
slot.register(container, name);
|
|
61
|
-
}
|
|
62
|
-
return container;
|
|
63
|
-
} catch (error) {
|
|
64
|
-
islandLog.error("\u043E\u0441\u0442\u0440\u043E\u0432: \u0441\u0431\u043E\u0440\u043A\u0430 \u043A\u043E\u043D\u0442\u0435\u0439\u043D\u0435\u0440\u0430 \u0443\u043F\u0430\u043B\u0430", error);
|
|
65
|
-
return null;
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
function hydrateIslandState(container, descriptor, denState) {
|
|
69
|
-
var _a, _b;
|
|
70
|
-
for (const vm of (_a = descriptor.viewModels) != null ? _a : []) {
|
|
71
|
-
const instance = container.resolve(vm.token);
|
|
72
|
-
const saved = denState[vm.token.description];
|
|
73
|
-
if (saved !== void 0 && typeof ((_b = instance.state) == null ? void 0 : _b.set) === "function") {
|
|
74
|
-
_chunkA6ZPAM6Zcjs.unitLogger.call(void 0, container, vm.token.description).debug("\u0433\u0438\u0434\u0440\u0430\u0446\u0438\u044F VM \u0438\u0437 denState");
|
|
75
|
-
instance.state.set(saved);
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
function activateIslandViewModels(_0, _1) {
|
|
80
|
-
return _chunkXHYR3SGGcjs.__async.call(void 0, this, arguments, function* (container, descriptor, route = EMPTY_ROUTE) {
|
|
81
|
-
var _a;
|
|
82
|
-
yield Promise.all(
|
|
83
|
-
((_a = descriptor.viewModels) != null ? _a : []).map((vm) => _chunkXHYR3SGGcjs.__async.call(void 0, null, null, function* () {
|
|
84
|
-
var _a2;
|
|
85
|
-
const instance = container.resolve(vm.token);
|
|
86
|
-
_chunkA6ZPAM6Zcjs.unitLogger.call(void 0, container, vm.token.description).debug(`\u0430\u043A\u0442\u0438\u0432\u0430\u0446\u0438\u044F VM (${route.pathname || "\u2014"})`);
|
|
87
|
-
yield (_a2 = instance.activate) == null ? void 0 : _a2.call(instance, route);
|
|
88
|
-
}))
|
|
89
|
-
);
|
|
90
|
-
});
|
|
91
|
-
}
|
|
92
|
-
function collectIslandState(container, descriptor) {
|
|
93
|
-
var _a, _b;
|
|
94
|
-
const state = {};
|
|
95
|
-
for (const vm of (_a = descriptor.viewModels) != null ? _a : []) {
|
|
96
|
-
const instance = container.resolve(vm.token);
|
|
97
|
-
if (typeof ((_b = instance.state) == null ? void 0 : _b.get) === "function") {
|
|
98
|
-
state[vm.token.description] = instance.state.get();
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
return state;
|
|
102
|
-
}
|
|
103
|
-
function collectDocumentContribution(container, descriptor) {
|
|
104
|
-
var _a, _b;
|
|
105
|
-
const contribution = {};
|
|
106
|
-
for (const vm of (_a = descriptor.viewModels) != null ? _a : []) {
|
|
107
|
-
const instance = container.resolve(vm.token);
|
|
108
|
-
if (!isDocumentSource(instance)) {
|
|
109
|
-
continue;
|
|
110
|
-
}
|
|
111
|
-
const part = instance.describeDocument();
|
|
112
|
-
if (part.head) {
|
|
113
|
-
contribution.head = _chunkXHYR3SGGcjs.__spreadValues.call(void 0, _chunkXHYR3SGGcjs.__spreadValues.call(void 0, {}, contribution.head), part.head);
|
|
114
|
-
}
|
|
115
|
-
const declared = part.status !== void 0 || part.redirect !== void 0;
|
|
116
|
-
if (declared && contribution.status === void 0) {
|
|
117
|
-
contribution.status = (_b = part.status) != null ? _b : REDIRECT_FOUND;
|
|
118
|
-
contribution.redirect = part.redirect;
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
return contribution;
|
|
122
|
-
}
|
|
123
|
-
function resolveEagerUnits(container, descriptor) {
|
|
124
|
-
var _a;
|
|
125
|
-
for (const token of (_a = descriptor.eager) != null ? _a : []) {
|
|
126
|
-
const instance = container.resolve(token);
|
|
127
|
-
_chunkA6ZPAM6Zcjs.unitLogger.call(void 0, container, token.description).debug("eager: \u0435\u0434\u0438\u043D\u0438\u0446\u0430 \u043F\u043E\u0434\u043D\u044F\u0442\u0430 \u043F\u0440\u0438 \u043C\u043E\u043D\u0442\u0438\u0440\u043E\u0432\u0430\u043D\u0438\u0438");
|
|
128
|
-
if (instance instanceof Promise) {
|
|
129
|
-
instance.catch(
|
|
130
|
-
(error) => _chunkA6ZPAM6Zcjs.unitLogger.call(void 0, container, token.description).error("eager: \u0435\u0434\u0438\u043D\u0438\u0446\u0430 \u043D\u0435 \u043F\u043E\u0434\u043D\u044F\u043B\u0430\u0441\u044C", error)
|
|
131
|
-
);
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
17
|
|
|
136
|
-
|
|
137
|
-
var
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
params: (_a = request.params) != null ? _a : {},
|
|
143
|
-
pathname: request.pathname,
|
|
144
|
-
search: (_b = request.search) != null ? _b : ""
|
|
145
|
-
};
|
|
146
|
-
const container = createIslandContainer(descriptor, { parent: request.parent });
|
|
147
|
-
if (container === null) {
|
|
148
|
-
throw new Error(`den/island: \u043F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u0435 \xAB${descriptor.name}\xBB \u043D\u0435 \u0441\u043E\u0431\u0440\u0430\u043B\u043E\u0441\u044C \u2014 \u0440\u0435\u043D\u0434\u0435\u0440 \u043D\u0435\u0432\u043E\u0437\u043C\u043E\u0436\u0435\u043D`);
|
|
149
|
-
}
|
|
150
|
-
try {
|
|
151
|
-
yield activateIslandViewModels(container, descriptor, route);
|
|
152
|
-
const { head, redirect, status = STATUS_OK } = collectDocumentContribution(container, descriptor);
|
|
153
|
-
if (status !== STATUS_OK) {
|
|
154
|
-
return { head, html: "", redirect, state: {}, status };
|
|
155
|
-
}
|
|
156
|
-
const state = collectIslandState(container, descriptor);
|
|
157
|
-
const rendered = _chunkXOJ2VWX4cjs.resolveViewAdapter.call(void 0, container).renderIsland(descriptor, {
|
|
158
|
-
container,
|
|
159
|
-
slots: request.slots
|
|
160
|
-
});
|
|
161
|
-
return { head, headHtml: rendered.head, html: rendered.html, state, status };
|
|
162
|
-
} finally {
|
|
163
|
-
yield container.dispose();
|
|
164
|
-
}
|
|
165
|
-
});
|
|
166
|
-
}
|
|
18
|
+
|
|
19
|
+
var _chunkXOJ2VWX4cjs = require('../chunk-XOJ2VWX4.cjs');
|
|
20
|
+
require('../chunk-CZVYVNLI.cjs');
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
var _chunkXHYR3SGGcjs = require('../chunk-XHYR3SGG.cjs');
|
|
167
24
|
|
|
168
25
|
// src/island/slot-address.ts
|
|
169
26
|
function slotAddress(app, slot) {
|
|
@@ -210,10 +67,6 @@ function describeIsland(descriptor, denState) {
|
|
|
210
67
|
};
|
|
211
68
|
}
|
|
212
69
|
|
|
213
|
-
// src/island/routes.ts
|
|
214
|
-
function normalizeRoutes(routes = []) {
|
|
215
|
-
return routes.map((route) => typeof route === "string" ? { source: route } : route);
|
|
216
|
-
}
|
|
217
70
|
|
|
218
71
|
|
|
219
72
|
|
|
@@ -233,4 +86,5 @@ function normalizeRoutes(routes = []) {
|
|
|
233
86
|
|
|
234
87
|
|
|
235
88
|
|
|
236
|
-
|
|
89
|
+
|
|
90
|
+
exports.ViewLayerToken = _chunkXOJ2VWX4cjs.ViewLayerToken; exports.activateIslandViewModels = _chunk6ZFVV3AVcjs.activateIslandViewModels; exports.collectDocumentContribution = _chunk6ZFVV3AVcjs.collectDocumentContribution; exports.collectIslandState = _chunk6ZFVV3AVcjs.collectIslandState; exports.createIslandContainer = _chunk6ZFVV3AVcjs.createIslandContainer; exports.describeIsland = describeIsland; exports.getAppContainer = _chunk6ZFVV3AVcjs.getAppContainer; exports.getIslandsSnapshot = getIslandsSnapshot; exports.hydrateIslandState = _chunk6ZFVV3AVcjs.hydrateIslandState; exports.isDocumentSource = _chunk6ZFVV3AVcjs.isDocumentSource; exports.matchRoute = _chunk6ZFVV3AVcjs.matchRoute; exports.normalizeRoutes = _chunk6ZFVV3AVcjs.normalizeRoutes; exports.pathPattern = _chunk6ZFVV3AVcjs.pathPattern; exports.registerIsland = registerIsland; exports.renderApp = _chunk6ZFVV3AVcjs.renderApp; exports.resolveEagerUnits = _chunk6ZFVV3AVcjs.resolveEagerUnits; exports.resolveViewAdapter = _chunkXOJ2VWX4cjs.resolveViewAdapter; exports.slotAddress = slotAddress; exports.subscribeIslands = subscribeIslands; exports.viewAdapterOf = _chunkXOJ2VWX4cjs.viewAdapterOf;
|
package/island/index.d.cts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { I as IslandDescriptor } from '../
|
|
2
|
-
export { R as RenderIslandOptions, c as RenderTree, S as ServerRender, d as ServerRenderResult, V as ViewAdapter, a as ViewLayerDefinition, b as ViewLayerToken, r as resolveViewAdapter, v as viewAdapterOf } from '../view-adapter-BvDC5O4y.cjs';
|
|
1
|
+
import { I as IslandDescriptor } from '../descriptor-h0JE9jFx.cjs';
|
|
3
2
|
import { Container } from '@foxford/ioc';
|
|
4
|
-
import {
|
|
3
|
+
import { R as RequestContext } from '../types-COwVwgzE.cjs';
|
|
4
|
+
export { A as AppRoute, R as RouteDeclaration, a as RouteMatch, m as matchRoute, n as normalizeRoutes, p as pathPattern } from '../routes-BqIoqbt1.cjs';
|
|
5
|
+
export { R as RenderIslandOptions, c as RenderTree, S as ServerRender, d as ServerRenderResult, V as ViewAdapter, a as ViewLayerDefinition, b as ViewLayerToken, r as resolveViewAdapter, v as viewAdapterOf } from '../view-adapter-D2597RJZ.cjs';
|
|
5
6
|
import '../define-slot-BKvArA02.cjs';
|
|
6
7
|
|
|
7
8
|
/** Вклад приложения в `<head>` документа. */
|
|
@@ -32,7 +33,27 @@ interface DocumentContribution {
|
|
|
32
33
|
/** Адрес для 3xx. Объявлен без статуса — исход `302`. */
|
|
33
34
|
redirect?: string;
|
|
34
35
|
}
|
|
35
|
-
/**
|
|
36
|
+
/**
|
|
37
|
+
* VM, которой есть что сказать про документ.
|
|
38
|
+
*
|
|
39
|
+
* Метод СИНХРОННЫЙ, и это не ограничение, а разделение обязанностей: ходит в ручки активация,
|
|
40
|
+
* а здесь остаётся проекция уже посчитанного состояния. Приложению, которому «есть ли такая
|
|
41
|
+
* страница» известно только от бэкенда, второй поход не нужен — активация ждётся ДО сбора
|
|
42
|
+
* вклада, поэтому к моменту вызова ответ уже лежит в состоянии VM:
|
|
43
|
+
*
|
|
44
|
+
* ```ts
|
|
45
|
+
* async activate(route: IslandRoute) {
|
|
46
|
+
* this.state.set(await loadPage(this.service, route.pathname)) // сюда ходим
|
|
47
|
+
* }
|
|
48
|
+
*
|
|
49
|
+
* describeDocument(): DocumentContribution {
|
|
50
|
+
* return this.state.get().page === null ? { status: 404 } : { head: … } // здесь только решаем
|
|
51
|
+
* }
|
|
52
|
+
* ```
|
|
53
|
+
*
|
|
54
|
+
* Разреши мы здесь асинхронность — у рендера появилась бы вторая фаза походов в сеть, а логика
|
|
55
|
+
* загрузки разъехалась бы по двум местам. Ровно от этого избавлялись, убирая `load`.
|
|
56
|
+
*/
|
|
36
57
|
interface DocumentSource {
|
|
37
58
|
describeDocument(): DocumentContribution;
|
|
38
59
|
}
|
|
@@ -148,6 +169,12 @@ interface RenderAppRequest {
|
|
|
148
169
|
search?: string;
|
|
149
170
|
/** Параметры, выделенные маршрутом хоста. */
|
|
150
171
|
params?: Record<string, string>;
|
|
172
|
+
/**
|
|
173
|
+
* Реквизиты запроса браузера — заголовки и куки. Кладутся в контейнер под
|
|
174
|
+
* `RequestContextToken`, поэтому приложение читает их через `requires`, одинаково у обоих
|
|
175
|
+
* транспортов: в процессе хоста их даёт хост, за сетью — сетевой рантайм из `X-Forwarded-*`.
|
|
176
|
+
*/
|
|
177
|
+
context?: RequestContext;
|
|
151
178
|
/**
|
|
152
179
|
* Родитель контейнера приложения: через него приезжает всё, что настроил исполнитель, —
|
|
153
180
|
* логгер, конфиг HTTP, выданные возможности. По умолчанию — app-scope контейнер.
|
|
@@ -242,28 +269,4 @@ declare function getAppContainer(): Container;
|
|
|
242
269
|
*/
|
|
243
270
|
declare function slotAddress(app: string, slot: string): string;
|
|
244
271
|
|
|
245
|
-
|
|
246
|
-
interface RouteDeclaration {
|
|
247
|
-
/** Regex-источник адреса (`'^/cabinet/billing'`, `'.*'`). */
|
|
248
|
-
source: string;
|
|
249
|
-
/**
|
|
250
|
-
* Guard-ы этого маршрута — поверх guard-ов приложения и хоста. Пусто — маршрут открыт
|
|
251
|
-
* настолько, насколько открыто само приложение.
|
|
252
|
-
*/
|
|
253
|
-
guards?: ReadonlyArray<GuardDefinition>;
|
|
254
|
-
}
|
|
255
|
-
/**
|
|
256
|
-
* Заявка на адрес: голая строка — публичный маршрут, объект — маршрут со своей политикой.
|
|
257
|
-
* Обе формы лежат в одном массиве, и порядок значим так же, как раньше: хост раздаёт путь
|
|
258
|
-
* первому заявившему, поэтому частные записи ставятся выше общих.
|
|
259
|
-
*/
|
|
260
|
-
type AppRoute = string | RouteDeclaration;
|
|
261
|
-
/**
|
|
262
|
-
* Приводит заявки к одной форме — чтобы хост и dev-инструменты не разбирали union каждый сам.
|
|
263
|
-
*
|
|
264
|
-
* @param routes - Заявки приложения (строки и/или записи)
|
|
265
|
-
* @returns Записи маршрутов в порядке объявления
|
|
266
|
-
*/
|
|
267
|
-
declare function normalizeRoutes(routes?: ReadonlyArray<AppRoute>): RouteDeclaration[];
|
|
268
|
-
|
|
269
|
-
export { type AppRoute, type CreateIslandContainerOptions, type DocumentContribution, type DocumentHead, type DocumentSource, IslandDescriptor, type IslandRecord, type IslandRoute, type RenderAppRequest, type RenderAppResult, type RouteDeclaration, activateIslandViewModels, collectDocumentContribution, collectIslandState, createIslandContainer, describeIsland, getAppContainer, getIslandsSnapshot, hydrateIslandState, isDocumentSource, normalizeRoutes, registerIsland, renderApp, resolveEagerUnits, slotAddress, subscribeIslands };
|
|
272
|
+
export { type CreateIslandContainerOptions, type DocumentContribution, type DocumentHead, type DocumentSource, IslandDescriptor, type IslandRecord, type IslandRoute, type RenderAppRequest, type RenderAppResult, activateIslandViewModels, collectDocumentContribution, collectIslandState, createIslandContainer, describeIsland, getAppContainer, getIslandsSnapshot, hydrateIslandState, isDocumentSource, registerIsland, renderApp, resolveEagerUnits, slotAddress, subscribeIslands };
|
package/island/index.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { I as IslandDescriptor } from '../
|
|
2
|
-
export { R as RenderIslandOptions, c as RenderTree, S as ServerRender, d as ServerRenderResult, V as ViewAdapter, a as ViewLayerDefinition, b as ViewLayerToken, r as resolveViewAdapter, v as viewAdapterOf } from '../view-adapter-DtNgyjIf.js';
|
|
1
|
+
import { I as IslandDescriptor } from '../descriptor-DZDNH7R5.js';
|
|
3
2
|
import { Container } from '@foxford/ioc';
|
|
4
|
-
import {
|
|
3
|
+
import { R as RequestContext } from '../types-COwVwgzE.js';
|
|
4
|
+
export { A as AppRoute, R as RouteDeclaration, a as RouteMatch, m as matchRoute, n as normalizeRoutes, p as pathPattern } from '../routes-CWpIqVAM.js';
|
|
5
|
+
export { R as RenderIslandOptions, c as RenderTree, S as ServerRender, d as ServerRenderResult, V as ViewAdapter, a as ViewLayerDefinition, b as ViewLayerToken, r as resolveViewAdapter, v as viewAdapterOf } from '../view-adapter-CPI8056c.js';
|
|
5
6
|
import '../define-slot-Dil8Kr1A.js';
|
|
6
7
|
|
|
7
8
|
/** Вклад приложения в `<head>` документа. */
|
|
@@ -32,7 +33,27 @@ interface DocumentContribution {
|
|
|
32
33
|
/** Адрес для 3xx. Объявлен без статуса — исход `302`. */
|
|
33
34
|
redirect?: string;
|
|
34
35
|
}
|
|
35
|
-
/**
|
|
36
|
+
/**
|
|
37
|
+
* VM, которой есть что сказать про документ.
|
|
38
|
+
*
|
|
39
|
+
* Метод СИНХРОННЫЙ, и это не ограничение, а разделение обязанностей: ходит в ручки активация,
|
|
40
|
+
* а здесь остаётся проекция уже посчитанного состояния. Приложению, которому «есть ли такая
|
|
41
|
+
* страница» известно только от бэкенда, второй поход не нужен — активация ждётся ДО сбора
|
|
42
|
+
* вклада, поэтому к моменту вызова ответ уже лежит в состоянии VM:
|
|
43
|
+
*
|
|
44
|
+
* ```ts
|
|
45
|
+
* async activate(route: IslandRoute) {
|
|
46
|
+
* this.state.set(await loadPage(this.service, route.pathname)) // сюда ходим
|
|
47
|
+
* }
|
|
48
|
+
*
|
|
49
|
+
* describeDocument(): DocumentContribution {
|
|
50
|
+
* return this.state.get().page === null ? { status: 404 } : { head: … } // здесь только решаем
|
|
51
|
+
* }
|
|
52
|
+
* ```
|
|
53
|
+
*
|
|
54
|
+
* Разреши мы здесь асинхронность — у рендера появилась бы вторая фаза походов в сеть, а логика
|
|
55
|
+
* загрузки разъехалась бы по двум местам. Ровно от этого избавлялись, убирая `load`.
|
|
56
|
+
*/
|
|
36
57
|
interface DocumentSource {
|
|
37
58
|
describeDocument(): DocumentContribution;
|
|
38
59
|
}
|
|
@@ -148,6 +169,12 @@ interface RenderAppRequest {
|
|
|
148
169
|
search?: string;
|
|
149
170
|
/** Параметры, выделенные маршрутом хоста. */
|
|
150
171
|
params?: Record<string, string>;
|
|
172
|
+
/**
|
|
173
|
+
* Реквизиты запроса браузера — заголовки и куки. Кладутся в контейнер под
|
|
174
|
+
* `RequestContextToken`, поэтому приложение читает их через `requires`, одинаково у обоих
|
|
175
|
+
* транспортов: в процессе хоста их даёт хост, за сетью — сетевой рантайм из `X-Forwarded-*`.
|
|
176
|
+
*/
|
|
177
|
+
context?: RequestContext;
|
|
151
178
|
/**
|
|
152
179
|
* Родитель контейнера приложения: через него приезжает всё, что настроил исполнитель, —
|
|
153
180
|
* логгер, конфиг HTTP, выданные возможности. По умолчанию — app-scope контейнер.
|
|
@@ -242,28 +269,4 @@ declare function getAppContainer(): Container;
|
|
|
242
269
|
*/
|
|
243
270
|
declare function slotAddress(app: string, slot: string): string;
|
|
244
271
|
|
|
245
|
-
|
|
246
|
-
interface RouteDeclaration {
|
|
247
|
-
/** Regex-источник адреса (`'^/cabinet/billing'`, `'.*'`). */
|
|
248
|
-
source: string;
|
|
249
|
-
/**
|
|
250
|
-
* Guard-ы этого маршрута — поверх guard-ов приложения и хоста. Пусто — маршрут открыт
|
|
251
|
-
* настолько, насколько открыто само приложение.
|
|
252
|
-
*/
|
|
253
|
-
guards?: ReadonlyArray<GuardDefinition>;
|
|
254
|
-
}
|
|
255
|
-
/**
|
|
256
|
-
* Заявка на адрес: голая строка — публичный маршрут, объект — маршрут со своей политикой.
|
|
257
|
-
* Обе формы лежат в одном массиве, и порядок значим так же, как раньше: хост раздаёт путь
|
|
258
|
-
* первому заявившему, поэтому частные записи ставятся выше общих.
|
|
259
|
-
*/
|
|
260
|
-
type AppRoute = string | RouteDeclaration;
|
|
261
|
-
/**
|
|
262
|
-
* Приводит заявки к одной форме — чтобы хост и dev-инструменты не разбирали union каждый сам.
|
|
263
|
-
*
|
|
264
|
-
* @param routes - Заявки приложения (строки и/или записи)
|
|
265
|
-
* @returns Записи маршрутов в порядке объявления
|
|
266
|
-
*/
|
|
267
|
-
declare function normalizeRoutes(routes?: ReadonlyArray<AppRoute>): RouteDeclaration[];
|
|
268
|
-
|
|
269
|
-
export { type AppRoute, type CreateIslandContainerOptions, type DocumentContribution, type DocumentHead, type DocumentSource, IslandDescriptor, type IslandRecord, type IslandRoute, type RenderAppRequest, type RenderAppResult, type RouteDeclaration, activateIslandViewModels, collectDocumentContribution, collectIslandState, createIslandContainer, describeIsland, getAppContainer, getIslandsSnapshot, hydrateIslandState, isDocumentSource, normalizeRoutes, registerIsland, renderApp, resolveEagerUnits, slotAddress, subscribeIslands };
|
|
272
|
+
export { type CreateIslandContainerOptions, type DocumentContribution, type DocumentHead, type DocumentSource, IslandDescriptor, type IslandRecord, type IslandRoute, type RenderAppRequest, type RenderAppResult, activateIslandViewModels, collectDocumentContribution, collectIslandState, createIslandContainer, describeIsland, getAppContainer, getIslandsSnapshot, hydrateIslandState, isDocumentSource, registerIsland, renderApp, resolveEagerUnits, slotAddress, subscribeIslands };
|
package/island/index.js
CHANGED
|
@@ -1,170 +1,27 @@
|
|
|
1
|
+
import {
|
|
2
|
+
activateIslandViewModels,
|
|
3
|
+
collectDocumentContribution,
|
|
4
|
+
collectIslandState,
|
|
5
|
+
createIslandContainer,
|
|
6
|
+
getAppContainer,
|
|
7
|
+
hydrateIslandState,
|
|
8
|
+
isDocumentSource,
|
|
9
|
+
matchRoute,
|
|
10
|
+
normalizeRoutes,
|
|
11
|
+
pathPattern,
|
|
12
|
+
renderApp,
|
|
13
|
+
resolveEagerUnits
|
|
14
|
+
} from "../chunk-7M5OAOQ4.js";
|
|
1
15
|
import {
|
|
2
16
|
ViewLayerToken,
|
|
3
17
|
resolveViewAdapter,
|
|
4
18
|
viewAdapterOf
|
|
5
19
|
} from "../chunk-E23E2VUC.js";
|
|
20
|
+
import "../chunk-KJ6NDOOL.js";
|
|
6
21
|
import {
|
|
7
|
-
LoggerToken,
|
|
8
|
-
logger,
|
|
9
|
-
unitLogger
|
|
10
|
-
} from "../chunk-TPBI6TOU.js";
|
|
11
|
-
import {
|
|
12
|
-
__async,
|
|
13
22
|
__spreadValues
|
|
14
23
|
} from "../chunk-HJO26HIQ.js";
|
|
15
24
|
|
|
16
|
-
// src/island/document.ts
|
|
17
|
-
function isDocumentSource(value) {
|
|
18
|
-
return typeof value === "object" && value !== null && typeof value.describeDocument === "function";
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
// src/island/lifecycle.ts
|
|
22
|
-
import { log } from "@foxford/logger";
|
|
23
|
-
|
|
24
|
-
// src/island/runtime.ts
|
|
25
|
-
import { Container } from "@foxford/ioc";
|
|
26
|
-
var appContainer = null;
|
|
27
|
-
function getAppContainer() {
|
|
28
|
-
var _a;
|
|
29
|
-
if (appContainer === null) {
|
|
30
|
-
appContainer = new Container();
|
|
31
|
-
((_a = logger.getLogger("island:runtime")) != null ? _a : logger).debug("app-\u043A\u043E\u043D\u0442\u0435\u0439\u043D\u0435\u0440 \u0441\u043E\u0437\u0434\u0430\u043D");
|
|
32
|
-
}
|
|
33
|
-
return appContainer;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// src/island/lifecycle.ts
|
|
37
|
-
var EMPTY_ROUTE = { params: {}, pathname: "", search: "" };
|
|
38
|
-
var REDIRECT_FOUND = 302;
|
|
39
|
-
function createIslandContainer(descriptor, options = {}) {
|
|
40
|
-
var _a, _b, _c, _d, _e;
|
|
41
|
-
const { parent = getAppContainer() } = options;
|
|
42
|
-
const appLog = (_b = log.getLogger((_a = descriptor.name) != null ? _a : "app")) != null ? _b : logger;
|
|
43
|
-
const islandLog = (_c = appLog.getLogger("client")) != null ? _c : appLog;
|
|
44
|
-
try {
|
|
45
|
-
const container = parent.createChild();
|
|
46
|
-
container.bind(LoggerToken).toValue(islandLog);
|
|
47
|
-
descriptor.viewLayer.register(container);
|
|
48
|
-
const viewModels = (_d = descriptor.viewModels) != null ? _d : [];
|
|
49
|
-
const slots = Object.entries((_e = descriptor.slots) != null ? _e : {});
|
|
50
|
-
islandLog.info(
|
|
51
|
-
`\u043E\u0441\u0442\u0440\u043E\u0432: \u043A\u043E\u043D\u0442\u0435\u0439\u043D\u0435\u0440 \u0441\u043E\u0437\u0434\u0430\u043D (units=${descriptor.units.length}, vms=${viewModels.length}, slots=${slots.length})`
|
|
52
|
-
);
|
|
53
|
-
for (const unit of descriptor.units) {
|
|
54
|
-
unit.register(container);
|
|
55
|
-
}
|
|
56
|
-
for (const vm of viewModels) {
|
|
57
|
-
vm.register(container);
|
|
58
|
-
}
|
|
59
|
-
for (const [name, slot] of slots) {
|
|
60
|
-
slot.register(container, name);
|
|
61
|
-
}
|
|
62
|
-
return container;
|
|
63
|
-
} catch (error) {
|
|
64
|
-
islandLog.error("\u043E\u0441\u0442\u0440\u043E\u0432: \u0441\u0431\u043E\u0440\u043A\u0430 \u043A\u043E\u043D\u0442\u0435\u0439\u043D\u0435\u0440\u0430 \u0443\u043F\u0430\u043B\u0430", error);
|
|
65
|
-
return null;
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
function hydrateIslandState(container, descriptor, denState) {
|
|
69
|
-
var _a, _b;
|
|
70
|
-
for (const vm of (_a = descriptor.viewModels) != null ? _a : []) {
|
|
71
|
-
const instance = container.resolve(vm.token);
|
|
72
|
-
const saved = denState[vm.token.description];
|
|
73
|
-
if (saved !== void 0 && typeof ((_b = instance.state) == null ? void 0 : _b.set) === "function") {
|
|
74
|
-
unitLogger(container, vm.token.description).debug("\u0433\u0438\u0434\u0440\u0430\u0446\u0438\u044F VM \u0438\u0437 denState");
|
|
75
|
-
instance.state.set(saved);
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
function activateIslandViewModels(_0, _1) {
|
|
80
|
-
return __async(this, arguments, function* (container, descriptor, route = EMPTY_ROUTE) {
|
|
81
|
-
var _a;
|
|
82
|
-
yield Promise.all(
|
|
83
|
-
((_a = descriptor.viewModels) != null ? _a : []).map((vm) => __async(null, null, function* () {
|
|
84
|
-
var _a2;
|
|
85
|
-
const instance = container.resolve(vm.token);
|
|
86
|
-
unitLogger(container, vm.token.description).debug(`\u0430\u043A\u0442\u0438\u0432\u0430\u0446\u0438\u044F VM (${route.pathname || "\u2014"})`);
|
|
87
|
-
yield (_a2 = instance.activate) == null ? void 0 : _a2.call(instance, route);
|
|
88
|
-
}))
|
|
89
|
-
);
|
|
90
|
-
});
|
|
91
|
-
}
|
|
92
|
-
function collectIslandState(container, descriptor) {
|
|
93
|
-
var _a, _b;
|
|
94
|
-
const state = {};
|
|
95
|
-
for (const vm of (_a = descriptor.viewModels) != null ? _a : []) {
|
|
96
|
-
const instance = container.resolve(vm.token);
|
|
97
|
-
if (typeof ((_b = instance.state) == null ? void 0 : _b.get) === "function") {
|
|
98
|
-
state[vm.token.description] = instance.state.get();
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
return state;
|
|
102
|
-
}
|
|
103
|
-
function collectDocumentContribution(container, descriptor) {
|
|
104
|
-
var _a, _b;
|
|
105
|
-
const contribution = {};
|
|
106
|
-
for (const vm of (_a = descriptor.viewModels) != null ? _a : []) {
|
|
107
|
-
const instance = container.resolve(vm.token);
|
|
108
|
-
if (!isDocumentSource(instance)) {
|
|
109
|
-
continue;
|
|
110
|
-
}
|
|
111
|
-
const part = instance.describeDocument();
|
|
112
|
-
if (part.head) {
|
|
113
|
-
contribution.head = __spreadValues(__spreadValues({}, contribution.head), part.head);
|
|
114
|
-
}
|
|
115
|
-
const declared = part.status !== void 0 || part.redirect !== void 0;
|
|
116
|
-
if (declared && contribution.status === void 0) {
|
|
117
|
-
contribution.status = (_b = part.status) != null ? _b : REDIRECT_FOUND;
|
|
118
|
-
contribution.redirect = part.redirect;
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
return contribution;
|
|
122
|
-
}
|
|
123
|
-
function resolveEagerUnits(container, descriptor) {
|
|
124
|
-
var _a;
|
|
125
|
-
for (const token of (_a = descriptor.eager) != null ? _a : []) {
|
|
126
|
-
const instance = container.resolve(token);
|
|
127
|
-
unitLogger(container, token.description).debug("eager: \u0435\u0434\u0438\u043D\u0438\u0446\u0430 \u043F\u043E\u0434\u043D\u044F\u0442\u0430 \u043F\u0440\u0438 \u043C\u043E\u043D\u0442\u0438\u0440\u043E\u0432\u0430\u043D\u0438\u0438");
|
|
128
|
-
if (instance instanceof Promise) {
|
|
129
|
-
instance.catch(
|
|
130
|
-
(error) => unitLogger(container, token.description).error("eager: \u0435\u0434\u0438\u043D\u0438\u0446\u0430 \u043D\u0435 \u043F\u043E\u0434\u043D\u044F\u043B\u0430\u0441\u044C", error)
|
|
131
|
-
);
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
// src/island/render.ts
|
|
137
|
-
var STATUS_OK = 200;
|
|
138
|
-
function renderApp(descriptor, request) {
|
|
139
|
-
return __async(this, null, function* () {
|
|
140
|
-
var _a, _b;
|
|
141
|
-
const route = {
|
|
142
|
-
params: (_a = request.params) != null ? _a : {},
|
|
143
|
-
pathname: request.pathname,
|
|
144
|
-
search: (_b = request.search) != null ? _b : ""
|
|
145
|
-
};
|
|
146
|
-
const container = createIslandContainer(descriptor, { parent: request.parent });
|
|
147
|
-
if (container === null) {
|
|
148
|
-
throw new Error(`den/island: \u043F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u0435 \xAB${descriptor.name}\xBB \u043D\u0435 \u0441\u043E\u0431\u0440\u0430\u043B\u043E\u0441\u044C \u2014 \u0440\u0435\u043D\u0434\u0435\u0440 \u043D\u0435\u0432\u043E\u0437\u043C\u043E\u0436\u0435\u043D`);
|
|
149
|
-
}
|
|
150
|
-
try {
|
|
151
|
-
yield activateIslandViewModels(container, descriptor, route);
|
|
152
|
-
const { head, redirect, status = STATUS_OK } = collectDocumentContribution(container, descriptor);
|
|
153
|
-
if (status !== STATUS_OK) {
|
|
154
|
-
return { head, html: "", redirect, state: {}, status };
|
|
155
|
-
}
|
|
156
|
-
const state = collectIslandState(container, descriptor);
|
|
157
|
-
const rendered = resolveViewAdapter(container).renderIsland(descriptor, {
|
|
158
|
-
container,
|
|
159
|
-
slots: request.slots
|
|
160
|
-
});
|
|
161
|
-
return { head, headHtml: rendered.head, html: rendered.html, state, status };
|
|
162
|
-
} finally {
|
|
163
|
-
yield container.dispose();
|
|
164
|
-
}
|
|
165
|
-
});
|
|
166
|
-
}
|
|
167
|
-
|
|
168
25
|
// src/island/slot-address.ts
|
|
169
26
|
function slotAddress(app, slot) {
|
|
170
27
|
return `${app}:${slot}`;
|
|
@@ -209,11 +66,6 @@ function describeIsland(descriptor, denState) {
|
|
|
209
66
|
viewModels: ((_b = descriptor.viewModels) != null ? _b : []).map((vm) => vm.token.description)
|
|
210
67
|
};
|
|
211
68
|
}
|
|
212
|
-
|
|
213
|
-
// src/island/routes.ts
|
|
214
|
-
function normalizeRoutes(routes = []) {
|
|
215
|
-
return routes.map((route) => typeof route === "string" ? { source: route } : route);
|
|
216
|
-
}
|
|
217
69
|
export {
|
|
218
70
|
ViewLayerToken,
|
|
219
71
|
activateIslandViewModels,
|
|
@@ -225,7 +77,9 @@ export {
|
|
|
225
77
|
getIslandsSnapshot,
|
|
226
78
|
hydrateIslandState,
|
|
227
79
|
isDocumentSource,
|
|
80
|
+
matchRoute,
|
|
228
81
|
normalizeRoutes,
|
|
82
|
+
pathPattern,
|
|
229
83
|
registerIsland,
|
|
230
84
|
renderApp,
|
|
231
85
|
resolveEagerUnits,
|