@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/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-BvDC5O4y.cjs';
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-DtNgyjIf.js';
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-WRQC6BVJ.js";
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 "./chunk-TPBI6TOU.js";
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
- // src/island/lifecycle.ts
22
- var _logger = require('@foxford/logger');
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
- // src/island/render.ts
137
- var STATUS_OK = 200;
138
- function renderApp(descriptor, request) {
139
- return _chunkXHYR3SGGcjs.__async.call(void 0, 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 = _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
- exports.ViewLayerToken = _chunkXOJ2VWX4cjs.ViewLayerToken; exports.activateIslandViewModels = activateIslandViewModels; exports.collectDocumentContribution = collectDocumentContribution; exports.collectIslandState = collectIslandState; exports.createIslandContainer = createIslandContainer; exports.describeIsland = describeIsland; exports.getAppContainer = getAppContainer; exports.getIslandsSnapshot = getIslandsSnapshot; exports.hydrateIslandState = hydrateIslandState; exports.isDocumentSource = isDocumentSource; exports.normalizeRoutes = normalizeRoutes; exports.registerIsland = registerIsland; exports.renderApp = renderApp; exports.resolveEagerUnits = resolveEagerUnits; exports.resolveViewAdapter = _chunkXOJ2VWX4cjs.resolveViewAdapter; exports.slotAddress = slotAddress; exports.subscribeIslands = subscribeIslands; exports.viewAdapterOf = _chunkXOJ2VWX4cjs.viewAdapterOf;
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;
@@ -1,7 +1,8 @@
1
- import { I as IslandDescriptor } from '../view-adapter-BvDC5O4y.cjs';
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 { g as GuardDefinition } from '../types-COwVwgzE.cjs';
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
- /** VM, которой есть что сказать про документ. */
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 '../view-adapter-DtNgyjIf.js';
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 { g as GuardDefinition } from '../types-COwVwgzE.js';
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
- /** VM, которой есть что сказать про документ. */
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,