@foxford/den 3.7.0 → 4.0.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.
Files changed (40) hide show
  1. package/README.mdx +31 -6
  2. package/adapter.d.cts +1 -1
  3. package/adapter.d.ts +1 -1
  4. package/bin/den.cjs +3 -3
  5. package/bin/den.js +1 -1
  6. package/builder/index.cjs +2 -2
  7. package/builder/index.d.cts +4 -2
  8. package/builder/index.d.ts +4 -2
  9. package/builder/index.js +1 -1
  10. package/chunk-2P5TAWRW.cjs +227 -0
  11. package/chunk-DUU4MQ4B.js +227 -0
  12. package/{chunk-2GTQK2PZ.js → chunk-FMRORLLE.js} +6 -4
  13. package/{chunk-P4J4M2WZ.cjs → chunk-OC4LQ2CK.cjs} +6 -4
  14. package/{define-repository-AO7JI6Cb.d.ts → define-repository-Ck45La_2.d.ts} +1 -1
  15. package/{define-repository-C0MI-J32.d.cts → define-repository-DAyeXF48.d.cts} +1 -1
  16. package/{define-slot-CdWdFM16.d.ts → define-slot-BTlLQ__T.d.ts} +1 -1
  17. package/{define-slot-BEeHNEph.d.cts → define-slot-C6hrdJS3.d.cts} +1 -1
  18. package/define.d.cts +3 -3
  19. package/define.d.ts +3 -3
  20. package/{descriptor-BSaHM5B4.d.ts → descriptor-CNJFrEbS.d.ts} +2 -2
  21. package/{descriptor-C2j6Zz6c.d.cts → descriptor-DmfJP4jQ.d.cts} +2 -2
  22. package/index.d.cts +6 -6
  23. package/index.d.ts +6 -6
  24. package/island/index.d.cts +9 -6
  25. package/island/index.d.ts +9 -6
  26. package/ops/index.cjs +17 -0
  27. package/ops/index.d.cts +39 -0
  28. package/ops/index.d.ts +39 -0
  29. package/ops/index.js +17 -0
  30. package/package.json +25 -16
  31. package/{routes-BvV405k4.d.cts → routes-DQ4ud4bu.d.cts} +1 -1
  32. package/{routes-Di3K_0uQ.d.ts → routes-TkIxQ0Uc.d.ts} +1 -1
  33. package/serve/index.cjs +70 -16
  34. package/serve/index.d.cts +10 -5
  35. package/serve/index.d.ts +10 -5
  36. package/serve/index.js +71 -17
  37. package/{types-BxMQ-VOd.d.cts → types-Ccd5bmt1.d.cts} +23 -4
  38. package/{types-BxMQ-VOd.d.ts → types-Ccd5bmt1.d.ts} +23 -4
  39. package/{view-adapter-DMLlp3Iu.d.cts → view-adapter-CrHh7CjB.d.cts} +2 -2
  40. package/{view-adapter-DNLRSFka.d.ts → view-adapter-DPDvv09J.d.ts} +2 -2
@@ -66,7 +66,7 @@ function collectAssets(outDir, base) {
66
66
  }
67
67
 
68
68
  // src/serve/port.ts
69
- var DEFAULT_PORT = 3e3;
69
+ var DEFAULT_PORT = 8080;
70
70
  function resolvePort(declared) {
71
71
  var _a, _b;
72
72
  return Number((_b = (_a = process.env["PORT"]) != null ? _a : declared) != null ? _b : DEFAULT_PORT);
@@ -145,7 +145,8 @@ loadAppEnv(fileURLToPath(new URL('..', import.meta.url)))
145
145
  await serveApp(app, {
146
146
  ${assets} configure: config.server?.configure,
147
147
  host: process.env.HOST,
148
- port: Number(process.env.PORT ?? config.server?.port ?? ${String(DEFAULT_PORT)}),
148
+ ops: { host: process.env.OPS_HOST, port: Number(process.env.SERVICE_PORT ?? ${mode === "development" ? "config.server?.opsPort ?? 9090" : "9090"}) },
149
+ port: Number(process.env.PORT ?? ${mode === "development" ? "config.server?.port ?? " : ""}${String(DEFAULT_PORT)}),
149
150
  })
150
151
  `;
151
152
  }
@@ -201,7 +202,8 @@ function loadAppConfig(root) {
201
202
  configFile: false,
202
203
  logLevel: "silent",
203
204
  root,
204
- server: { middlewareMode: true }
205
+ // Этот сервер только загружает конфиг; пересборкой в dev управляет watchSources.
206
+ server: { middlewareMode: true, watch: null }
205
207
  });
206
208
  try {
207
209
  const loaded = yield server.ssrLoadModule(configPath);
@@ -324,7 +326,7 @@ var _url = require('url');
324
326
  var _os = require('os'); var _os2 = _interopRequireDefault(_os);
325
327
  var TOOL = "den";
326
328
  var PAD = 11;
327
- var ENDPOINTS = ["/_render?url=<\u043F\u0443\u0442\u044C>", "/_routes", "/_health"];
329
+ var ENDPOINTS = ["/_render?url=<\u043F\u0443\u0442\u044C>", "/_routes"];
328
330
  var OUTPUTS = ["build/client", "build/server", "build/server.mjs"];
329
331
  var SHORTCUTS = [
330
332
  { key: "r", title: "\u043F\u0435\u0440\u0435\u0441\u043E\u0431\u0440\u0430\u0442\u044C" },
@@ -1,4 +1,4 @@
1
- import { a as DefineServiceOptions, S as ServiceDefinition, b as DefineViewModelOptions, V as ViewModelDefinition, D as DefineRepositoryOptions, d as RepositoryDefinition } from './types-BxMQ-VOd.js';
1
+ import { a as DefineServiceOptions, S as ServiceDefinition, b as DefineViewModelOptions, V as ViewModelDefinition, D as DefineRepositoryOptions, d as RepositoryDefinition } from './types-Ccd5bmt1.js';
2
2
  import { Token } from '@foxford/ioc';
3
3
 
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { a as DefineServiceOptions, S as ServiceDefinition, b as DefineViewModelOptions, V as ViewModelDefinition, D as DefineRepositoryOptions, d as RepositoryDefinition } from './types-BxMQ-VOd.cjs';
1
+ import { a as DefineServiceOptions, S as ServiceDefinition, b as DefineViewModelOptions, V as ViewModelDefinition, D as DefineRepositoryOptions, d as RepositoryDefinition } from './types-Ccd5bmt1.cjs';
2
2
  import { Token } from '@foxford/ioc';
3
3
 
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { c as Definition, L as LayerDefinition } from './types-BxMQ-VOd.js';
1
+ import { c as Definition, L as LayerDefinition } from './types-Ccd5bmt1.js';
2
2
  import { Container } from '@foxford/ioc';
3
3
 
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { c as Definition, L as LayerDefinition } from './types-BxMQ-VOd.cjs';
1
+ import { c as Definition, L as LayerDefinition } from './types-Ccd5bmt1.cjs';
2
2
  import { Container } from '@foxford/ioc';
3
3
 
4
4
  /**
package/define.d.cts CHANGED
@@ -1,6 +1,6 @@
1
- export { d as defineRepository, a as defineService, b as defineViewModel } from './define-repository-C0MI-J32.cjs';
2
- export { D as DefineSlotOptions, S as SlotDefinition, d as defineSlot } from './define-slot-BEeHNEph.cjs';
3
- export { D as DefineRepositoryOptions, a as DefineServiceOptions, b as DefineViewModelOptions, c as Definition, d as RepositoryDefinition, S as ServiceDefinition, e as SlotEntry, f as SlotRegistry, g as SlotRegistryToken, V as ViewModelDefinition } from './types-BxMQ-VOd.cjs';
1
+ export { d as defineRepository, a as defineService, b as defineViewModel } from './define-repository-DAyeXF48.cjs';
2
+ export { D as DefineSlotOptions, S as SlotDefinition, d as defineSlot } from './define-slot-C6hrdJS3.cjs';
3
+ export { D as DefineRepositoryOptions, a as DefineServiceOptions, b as DefineViewModelOptions, c as Definition, d as RepositoryDefinition, S as ServiceDefinition, e as SlotEntry, f as SlotRegistry, g as SlotRegistryToken, V as ViewModelDefinition } from './types-Ccd5bmt1.cjs';
4
4
  import { Token, Container } from '@foxford/ioc';
5
5
  import { HierarchicalLogger } from '@foxford/logger';
6
6
 
package/define.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- export { d as defineRepository, a as defineService, b as defineViewModel } from './define-repository-AO7JI6Cb.js';
2
- export { D as DefineSlotOptions, S as SlotDefinition, d as defineSlot } from './define-slot-CdWdFM16.js';
3
- export { D as DefineRepositoryOptions, a as DefineServiceOptions, b as DefineViewModelOptions, c as Definition, d as RepositoryDefinition, S as ServiceDefinition, e as SlotEntry, f as SlotRegistry, g as SlotRegistryToken, V as ViewModelDefinition } from './types-BxMQ-VOd.js';
1
+ export { d as defineRepository, a as defineService, b as defineViewModel } from './define-repository-Ck45La_2.js';
2
+ export { D as DefineSlotOptions, S as SlotDefinition, d as defineSlot } from './define-slot-BTlLQ__T.js';
3
+ export { D as DefineRepositoryOptions, a as DefineServiceOptions, b as DefineViewModelOptions, c as Definition, d as RepositoryDefinition, S as ServiceDefinition, e as SlotEntry, f as SlotRegistry, g as SlotRegistryToken, V as ViewModelDefinition } from './types-Ccd5bmt1.js';
4
4
  import { Token, Container } from '@foxford/ioc';
5
5
  import { HierarchicalLogger } from '@foxford/logger';
6
6
 
@@ -1,5 +1,5 @@
1
- import { S as SlotDefinition } from './define-slot-CdWdFM16.js';
2
- import { L as LayerDefinition, c as Definition } from './types-BxMQ-VOd.js';
1
+ import { S as SlotDefinition } from './define-slot-BTlLQ__T.js';
2
+ import { L as LayerDefinition, c as Definition } from './types-Ccd5bmt1.js';
3
3
  import { Token } from '@foxford/ioc';
4
4
 
5
5
  /**
@@ -1,5 +1,5 @@
1
- import { S as SlotDefinition } from './define-slot-BEeHNEph.cjs';
2
- import { L as LayerDefinition, c as Definition } from './types-BxMQ-VOd.cjs';
1
+ import { S as SlotDefinition } from './define-slot-C6hrdJS3.cjs';
2
+ import { L as LayerDefinition, c as Definition } from './types-Ccd5bmt1.cjs';
3
3
  import { Token } from '@foxford/ioc';
4
4
 
5
5
  /**
package/index.d.cts CHANGED
@@ -1,11 +1,11 @@
1
- import { C as Core, j as ContainerManager, R as RequestContext, k as GuardRunner, l as Guard, m as GuardResult, N as NavigationManager, n as NavigationEntry, o as NavigationInterceptor, p as Disposable, q as LeaveGuardResult, r as StateSerializer, s as DefineGuardOptions, G as GuardDefinition, E as ExtensionConfig, t as DefineExtensionOptions, u as ExtensionDefinition, A as ActionGuard, v as DefineActionGuardOptions, w as ActionGuardDefinition, x as LayoutConfig, y as DefineLayoutOptions, z as LayoutDefinition, h as LayerConfig, B as DefineLayerOptions, L as LayerDefinition } from './types-BxMQ-VOd.cjs';
2
- export { F as Activatable, H as ActivatableToken, I as ContainerManagerToken, D as DefineRepositoryOptions, a as DefineServiceOptions, b as DefineViewModelOptions, c as Definition, J as GuardRunnerToken, K as NavigationManagerToken, d as RepositoryDefinition, i as RequestContextToken, S as ServiceDefinition, e as SlotEntry, f as SlotRegistry, g as SlotRegistryToken, M as StateCache, O as StateParticipant, P as StateRegistry, Q as StateRegistryToken, T as StateSerializerToken, V as ViewModelDefinition } from './types-BxMQ-VOd.cjs';
1
+ import { C as Core, j as ContainerManager, R as RequestContext, k as GuardRunner, l as Guard, m as GuardResult, N as NavigationManager, n as NavigationEntry, o as NavigationInterceptor, p as Disposable, q as LeaveGuardResult, r as StateSerializer, s as DefineGuardOptions, G as GuardDefinition, E as ExtensionConfig, t as DefineExtensionOptions, u as ExtensionDefinition, A as ActionGuard, v as DefineActionGuardOptions, w as ActionGuardDefinition, x as LayoutConfig, y as DefineLayoutOptions, z as LayoutDefinition, h as LayerConfig, B as DefineLayerOptions, L as LayerDefinition } from './types-Ccd5bmt1.cjs';
2
+ export { F as Activatable, H as ActivatableToken, I as ContainerManagerToken, D as DefineRepositoryOptions, a as DefineServiceOptions, b as DefineViewModelOptions, c as Definition, J as GuardRunnerToken, K as NavigationManagerToken, d as RepositoryDefinition, i as RequestContextToken, S as ServiceDefinition, e as SlotEntry, f as SlotRegistry, g as SlotRegistryToken, M as StateCache, O as StateParticipant, P as StateRegistry, Q as StateRegistryToken, T as StateSerializerToken, V as ViewModelDefinition } from './types-Ccd5bmt1.cjs';
3
3
  import { Container, Token } from '@foxford/ioc';
4
4
  import { DefinitionResolver } from './adapter.cjs';
5
- export { d as defineRepository, a as defineService, b as defineViewModel } from './define-repository-C0MI-J32.cjs';
6
- export { D as DefineSlotOptions, S as SlotDefinition, d as defineSlot } from './define-slot-BEeHNEph.cjs';
7
- export { V as ViewAdapter, a as ViewLayerDefinition, b as ViewLayerToken } from './view-adapter-DMLlp3Iu.cjs';
8
- import './descriptor-C2j6Zz6c.cjs';
5
+ export { d as defineRepository, a as defineService, b as defineViewModel } from './define-repository-DAyeXF48.cjs';
6
+ export { D as DefineSlotOptions, S as SlotDefinition, d as defineSlot } from './define-slot-C6hrdJS3.cjs';
7
+ export { V as ViewAdapter, a as ViewLayerDefinition, b as ViewLayerToken } from './view-adapter-CrHh7CjB.cjs';
8
+ import './descriptor-DmfJP4jQ.cjs';
9
9
  import './server-render-CocWXQKC.cjs';
10
10
 
11
11
  /**
package/index.d.ts CHANGED
@@ -1,11 +1,11 @@
1
- import { C as Core, j as ContainerManager, R as RequestContext, k as GuardRunner, l as Guard, m as GuardResult, N as NavigationManager, n as NavigationEntry, o as NavigationInterceptor, p as Disposable, q as LeaveGuardResult, r as StateSerializer, s as DefineGuardOptions, G as GuardDefinition, E as ExtensionConfig, t as DefineExtensionOptions, u as ExtensionDefinition, A as ActionGuard, v as DefineActionGuardOptions, w as ActionGuardDefinition, x as LayoutConfig, y as DefineLayoutOptions, z as LayoutDefinition, h as LayerConfig, B as DefineLayerOptions, L as LayerDefinition } from './types-BxMQ-VOd.js';
2
- export { F as Activatable, H as ActivatableToken, I as ContainerManagerToken, D as DefineRepositoryOptions, a as DefineServiceOptions, b as DefineViewModelOptions, c as Definition, J as GuardRunnerToken, K as NavigationManagerToken, d as RepositoryDefinition, i as RequestContextToken, S as ServiceDefinition, e as SlotEntry, f as SlotRegistry, g as SlotRegistryToken, M as StateCache, O as StateParticipant, P as StateRegistry, Q as StateRegistryToken, T as StateSerializerToken, V as ViewModelDefinition } from './types-BxMQ-VOd.js';
1
+ import { C as Core, j as ContainerManager, R as RequestContext, k as GuardRunner, l as Guard, m as GuardResult, N as NavigationManager, n as NavigationEntry, o as NavigationInterceptor, p as Disposable, q as LeaveGuardResult, r as StateSerializer, s as DefineGuardOptions, G as GuardDefinition, E as ExtensionConfig, t as DefineExtensionOptions, u as ExtensionDefinition, A as ActionGuard, v as DefineActionGuardOptions, w as ActionGuardDefinition, x as LayoutConfig, y as DefineLayoutOptions, z as LayoutDefinition, h as LayerConfig, B as DefineLayerOptions, L as LayerDefinition } from './types-Ccd5bmt1.js';
2
+ export { F as Activatable, H as ActivatableToken, I as ContainerManagerToken, D as DefineRepositoryOptions, a as DefineServiceOptions, b as DefineViewModelOptions, c as Definition, J as GuardRunnerToken, K as NavigationManagerToken, d as RepositoryDefinition, i as RequestContextToken, S as ServiceDefinition, e as SlotEntry, f as SlotRegistry, g as SlotRegistryToken, M as StateCache, O as StateParticipant, P as StateRegistry, Q as StateRegistryToken, T as StateSerializerToken, V as ViewModelDefinition } from './types-Ccd5bmt1.js';
3
3
  import { Container, Token } from '@foxford/ioc';
4
4
  import { DefinitionResolver } from './adapter.js';
5
- export { d as defineRepository, a as defineService, b as defineViewModel } from './define-repository-AO7JI6Cb.js';
6
- export { D as DefineSlotOptions, S as SlotDefinition, d as defineSlot } from './define-slot-CdWdFM16.js';
7
- export { V as ViewAdapter, a as ViewLayerDefinition, b as ViewLayerToken } from './view-adapter-DNLRSFka.js';
8
- import './descriptor-BSaHM5B4.js';
5
+ export { d as defineRepository, a as defineService, b as defineViewModel } from './define-repository-Ck45La_2.js';
6
+ export { D as DefineSlotOptions, S as SlotDefinition, d as defineSlot } from './define-slot-BTlLQ__T.js';
7
+ export { V as ViewAdapter, a as ViewLayerDefinition, b as ViewLayerToken } from './view-adapter-DPDvv09J.js';
8
+ import './descriptor-CNJFrEbS.js';
9
9
  import './server-render-CocWXQKC.js';
10
10
 
11
11
  /**
@@ -1,11 +1,11 @@
1
- import { A as AppAssets, I as IslandDescriptor } from '../descriptor-C2j6Zz6c.cjs';
2
- import { R as RequestContext, c as Definition } from '../types-BxMQ-VOd.cjs';
3
- export { i as RequestContextToken } from '../types-BxMQ-VOd.cjs';
1
+ import { A as AppAssets, I as IslandDescriptor } from '../descriptor-DmfJP4jQ.cjs';
2
+ import { R as RequestContext, c as Definition } from '../types-Ccd5bmt1.cjs';
3
+ export { i as RequestContextToken } from '../types-Ccd5bmt1.cjs';
4
4
  import { Container, Token } from '@foxford/ioc';
5
- export { A as AppRoute, R as RouteDeclaration, a as RouteMatch, m as matchRoute, n as normalizeRoutes, p as pathPattern } from '../routes-BvV405k4.cjs';
5
+ export { A as AppRoute, R as RouteDeclaration, a as RouteMatch, m as matchRoute, n as normalizeRoutes, p as pathPattern } from '../routes-DQ4ud4bu.cjs';
6
6
  export { R as RenderTree, a as ServerRender, S as ServerRenderResult } from '../server-render-CocWXQKC.cjs';
7
- export { R as RenderIslandOptions, V as ViewAdapter, a as ViewLayerDefinition, b as ViewLayerToken, r as resolveViewAdapter, v as viewAdapterOf } from '../view-adapter-DMLlp3Iu.cjs';
8
- import '../define-slot-BEeHNEph.cjs';
7
+ export { R as RenderIslandOptions, V as ViewAdapter, a as ViewLayerDefinition, b as ViewLayerToken, r as resolveViewAdapter, v as viewAdapterOf } from '../view-adapter-CrHh7CjB.cjs';
8
+ import '../define-slot-C6hrdJS3.cjs';
9
9
 
10
10
  /** Вклад приложения в `<head>` документа. */
11
11
  interface DocumentHead {
@@ -278,6 +278,9 @@ declare function parseCookieHeader(header: string | undefined): Record<string, s
278
278
  /**
279
279
  * Реквизиты запроса в браузере: куки документа, заголовков нет.
280
280
  *
281
+ * Реквизитов бэкенда тоже нет: в браузере их подставляет он сам — куку по своим правилам,
282
+ * остальное ему предъявлять нечем и незачем.
283
+ *
281
284
  * Биндится в контейнер острова при сборке, чтобы единица, требующая `RequestContextToken`,
282
285
  * резолвилась на обеих сторонах одинаково; иначе приложению пришлось бы держать две
283
286
  * реализации и переключать их по среде.
package/island/index.d.ts CHANGED
@@ -1,11 +1,11 @@
1
- import { A as AppAssets, I as IslandDescriptor } from '../descriptor-BSaHM5B4.js';
2
- import { R as RequestContext, c as Definition } from '../types-BxMQ-VOd.js';
3
- export { i as RequestContextToken } from '../types-BxMQ-VOd.js';
1
+ import { A as AppAssets, I as IslandDescriptor } from '../descriptor-CNJFrEbS.js';
2
+ import { R as RequestContext, c as Definition } from '../types-Ccd5bmt1.js';
3
+ export { i as RequestContextToken } from '../types-Ccd5bmt1.js';
4
4
  import { Container, Token } from '@foxford/ioc';
5
- export { A as AppRoute, R as RouteDeclaration, a as RouteMatch, m as matchRoute, n as normalizeRoutes, p as pathPattern } from '../routes-Di3K_0uQ.js';
5
+ export { A as AppRoute, R as RouteDeclaration, a as RouteMatch, m as matchRoute, n as normalizeRoutes, p as pathPattern } from '../routes-TkIxQ0Uc.js';
6
6
  export { R as RenderTree, a as ServerRender, S as ServerRenderResult } from '../server-render-CocWXQKC.js';
7
- export { R as RenderIslandOptions, V as ViewAdapter, a as ViewLayerDefinition, b as ViewLayerToken, r as resolveViewAdapter, v as viewAdapterOf } from '../view-adapter-DNLRSFka.js';
8
- import '../define-slot-CdWdFM16.js';
7
+ export { R as RenderIslandOptions, V as ViewAdapter, a as ViewLayerDefinition, b as ViewLayerToken, r as resolveViewAdapter, v as viewAdapterOf } from '../view-adapter-DPDvv09J.js';
8
+ import '../define-slot-BTlLQ__T.js';
9
9
 
10
10
  /** Вклад приложения в `<head>` документа. */
11
11
  interface DocumentHead {
@@ -278,6 +278,9 @@ declare function parseCookieHeader(header: string | undefined): Record<string, s
278
278
  /**
279
279
  * Реквизиты запроса в браузере: куки документа, заголовков нет.
280
280
  *
281
+ * Реквизитов бэкенда тоже нет: в браузере их подставляет он сам — куку по своим правилам,
282
+ * остальное ему предъявлять нечем и незачем.
283
+ *
281
284
  * Биндится в контейнер острова при сборке, чтобы единица, требующая `RequestContextToken`,
282
285
  * резолвилась на обеих сторонах одинаково; иначе приложению пришлось бы держать две
283
286
  * реализации и переключать их по среде.
package/ops/index.cjs ADDED
@@ -0,0 +1,17 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true});
2
+
3
+
4
+
5
+
6
+
7
+
8
+ var _chunk2P5TAWRWcjs = require('../chunk-2P5TAWRW.cjs');
9
+ require('../chunk-T5QVCXVB.cjs');
10
+
11
+
12
+
13
+
14
+
15
+
16
+
17
+ exports.ProcessMetrics = _chunk2P5TAWRWcjs.ProcessMetrics; exports.closeHttpServer = _chunk2P5TAWRWcjs.closeHttpServer; exports.clusterMetrics = _chunk2P5TAWRWcjs.clusterMetrics; exports.getProcessMetrics = _chunk2P5TAWRWcjs.getProcessMetrics; exports.isOpsPath = _chunk2P5TAWRWcjs.isOpsPath; exports.startOpsServer = _chunk2P5TAWRWcjs.startOpsServer;
@@ -0,0 +1,39 @@
1
+ import * as _prometheus_io_client from '@prometheus-io/client';
2
+ import { Registry, Counter, Histogram } from '@prometheus-io/client';
3
+ import { IncomingMessage, ServerResponse, Server } from 'node:http';
4
+
5
+ /** Реестр одного процесса; точкам измерений не нужен включённый Sentry. */
6
+ declare class ProcessMetrics {
7
+ readonly registry: Registry<_prometheus_io_client.RegistryContentType>;
8
+ private runtimeStarted;
9
+ counter(name: string, labelNames?: string[]): Counter<string>;
10
+ histogram(name: string, labelNames?: string[]): Histogram<string>;
11
+ /** Полный штатный набор Node/process-метрик клиента и дополнительные данные процесса. */
12
+ startRuntime(appName: string): void;
13
+ /** HTTP-измерения с ограниченными метками маршрута; вызывается один раз на запрос. */
14
+ trackHttp(req: IncomingMessage, res: ServerResponse, route: () => string): void;
15
+ }
16
+ declare function getProcessMetrics(): ProcessMetrics;
17
+
18
+ /** Служебный путь без query; работает и с относительным URL node:http. */
19
+ declare function isOpsPath(url?: string): boolean;
20
+ /** Подключает штатную межпроцессную агрегацию; вызывается и в primary, и в воркерах. */
21
+ declare function clusterMetrics(metrics?: ProcessMetrics): {
22
+ contentType: string;
23
+ collect: () => Promise<string>;
24
+ shutdown: () => Promise<void>;
25
+ };
26
+ interface OpsOptions {
27
+ port?: number;
28
+ host?: string;
29
+ metrics?: ProcessMetrics;
30
+ collect?: () => Promise<string>;
31
+ contentType?: string;
32
+ isLive?: () => boolean;
33
+ }
34
+ /** Второй HTTP-сервер в том же приложении. GET /healthz и /livez отвечают 200. */
35
+ declare function startOpsServer(options?: OpsOptions): Promise<Server>;
36
+ /** Ограниченное по времени закрытие обоих видов серверов node:http. */
37
+ declare function closeHttpServer(server: Server, timeoutMs?: number): Promise<void>;
38
+
39
+ export { type OpsOptions, ProcessMetrics, closeHttpServer, clusterMetrics, getProcessMetrics, isOpsPath, startOpsServer };
package/ops/index.d.ts ADDED
@@ -0,0 +1,39 @@
1
+ import * as _prometheus_io_client from '@prometheus-io/client';
2
+ import { Registry, Counter, Histogram } from '@prometheus-io/client';
3
+ import { IncomingMessage, ServerResponse, Server } from 'node:http';
4
+
5
+ /** Реестр одного процесса; точкам измерений не нужен включённый Sentry. */
6
+ declare class ProcessMetrics {
7
+ readonly registry: Registry<_prometheus_io_client.RegistryContentType>;
8
+ private runtimeStarted;
9
+ counter(name: string, labelNames?: string[]): Counter<string>;
10
+ histogram(name: string, labelNames?: string[]): Histogram<string>;
11
+ /** Полный штатный набор Node/process-метрик клиента и дополнительные данные процесса. */
12
+ startRuntime(appName: string): void;
13
+ /** HTTP-измерения с ограниченными метками маршрута; вызывается один раз на запрос. */
14
+ trackHttp(req: IncomingMessage, res: ServerResponse, route: () => string): void;
15
+ }
16
+ declare function getProcessMetrics(): ProcessMetrics;
17
+
18
+ /** Служебный путь без query; работает и с относительным URL node:http. */
19
+ declare function isOpsPath(url?: string): boolean;
20
+ /** Подключает штатную межпроцессную агрегацию; вызывается и в primary, и в воркерах. */
21
+ declare function clusterMetrics(metrics?: ProcessMetrics): {
22
+ contentType: string;
23
+ collect: () => Promise<string>;
24
+ shutdown: () => Promise<void>;
25
+ };
26
+ interface OpsOptions {
27
+ port?: number;
28
+ host?: string;
29
+ metrics?: ProcessMetrics;
30
+ collect?: () => Promise<string>;
31
+ contentType?: string;
32
+ isLive?: () => boolean;
33
+ }
34
+ /** Второй HTTP-сервер в том же приложении. GET /healthz и /livez отвечают 200. */
35
+ declare function startOpsServer(options?: OpsOptions): Promise<Server>;
36
+ /** Ограниченное по времени закрытие обоих видов серверов node:http. */
37
+ declare function closeHttpServer(server: Server, timeoutMs?: number): Promise<void>;
38
+
39
+ export { type OpsOptions, ProcessMetrics, closeHttpServer, clusterMetrics, getProcessMetrics, isOpsPath, startOpsServer };
package/ops/index.js ADDED
@@ -0,0 +1,17 @@
1
+ import {
2
+ ProcessMetrics,
3
+ closeHttpServer,
4
+ clusterMetrics,
5
+ getProcessMetrics,
6
+ isOpsPath,
7
+ startOpsServer
8
+ } from "../chunk-DUU4MQ4B.js";
9
+ import "../chunk-6FNC3XMI.js";
10
+ export {
11
+ ProcessMetrics,
12
+ closeHttpServer,
13
+ clusterMetrics,
14
+ getProcessMetrics,
15
+ isOpsPath,
16
+ startOpsServer
17
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@foxford/den",
3
- "version": "3.7.0",
3
+ "version": "4.0.0",
4
4
  "description": "Den — декларативный метафреймворк Foxford (core runtime)",
5
5
  "keywords": [
6
6
  "foxford",
@@ -30,6 +30,7 @@
30
30
  "den": "./den.js"
31
31
  },
32
32
  "dependencies": {
33
+ "@prometheus-io/client": "0.16.1",
33
34
  "fastify": "^5.12.1",
34
35
  "@foxford/ioc": "^1.1.2",
35
36
  "@foxford/logger": "^1.2.2"
@@ -75,6 +76,11 @@
75
76
  "require": "./island/index.cjs",
76
77
  "types": "./island/index.d.ts"
77
78
  },
79
+ "./ops": {
80
+ "import": "./ops/index.js",
81
+ "require": "./ops/index.cjs",
82
+ "types": "./ops/index.d.ts"
83
+ },
78
84
  "./serve": {
79
85
  "import": "./serve/index.js",
80
86
  "require": "./serve/index.cjs",
@@ -89,17 +95,19 @@
89
95
  "adapter.js",
90
96
  "bin",
91
97
  "builder",
92
- "chunk-2GTQK2PZ.js",
98
+ "chunk-2P5TAWRW.cjs",
93
99
  "chunk-3RX2OSUL.js",
94
100
  "chunk-6FNC3XMI.js",
95
101
  "chunk-6QV4L6R2.cjs",
96
102
  "chunk-A6ZPAM6Z.cjs",
97
103
  "chunk-C7BM4DGX.cjs",
104
+ "chunk-DUU4MQ4B.js",
98
105
  "chunk-E23E2VUC.js",
99
106
  "chunk-E56BKBQZ.js",
107
+ "chunk-FMRORLLE.js",
100
108
  "chunk-H5DKRHHQ.cjs",
101
109
  "chunk-KQAB6C6Q.cjs",
102
- "chunk-P4J4M2WZ.cjs",
110
+ "chunk-OC4LQ2CK.cjs",
103
111
  "chunk-QTWJTYZW.cjs",
104
112
  "chunk-RG7ZV5BD.js",
105
113
  "chunk-T5QVCXVB.cjs",
@@ -107,33 +115,34 @@
107
115
  "chunk-WBHHHICS.js",
108
116
  "chunk-XOJ2VWX4.cjs",
109
117
  "chunk-XQ7EHXHG.js",
110
- "define-repository-AO7JI6Cb.d.ts",
111
- "define-repository-C0MI-J32.d.cts",
112
- "define-slot-BEeHNEph.d.cts",
113
- "define-slot-CdWdFM16.d.ts",
118
+ "define-repository-Ck45La_2.d.ts",
119
+ "define-repository-DAyeXF48.d.cts",
120
+ "define-slot-BTlLQ__T.d.ts",
121
+ "define-slot-C6hrdJS3.d.cts",
114
122
  "define.cjs",
115
123
  "define.d.cts",
116
124
  "define.d.ts",
117
125
  "define.js",
118
126
  "den.js",
119
- "descriptor-BSaHM5B4.d.ts",
120
- "descriptor-C2j6Zz6c.d.cts",
127
+ "descriptor-CNJFrEbS.d.ts",
128
+ "descriptor-DmfJP4jQ.d.cts",
121
129
  "index.cjs",
122
130
  "index.d.cts",
123
131
  "index.d.ts",
124
132
  "index.js",
125
133
  "island",
134
+ "ops",
126
135
  "package.json",
127
- "routes-BvV405k4.d.cts",
128
- "routes-Di3K_0uQ.d.ts",
136
+ "routes-DQ4ud4bu.d.cts",
137
+ "routes-TkIxQ0Uc.d.ts",
129
138
  "serve",
130
139
  "server-render-CocWXQKC.d.cts",
131
140
  "server-render-CocWXQKC.d.ts",
132
- "types-BxMQ-VOd.d.cts",
133
- "types-BxMQ-VOd.d.ts",
134
- "view-adapter-DMLlp3Iu.d.cts",
135
- "view-adapter-DNLRSFka.d.ts"
141
+ "types-Ccd5bmt1.d.cts",
142
+ "types-Ccd5bmt1.d.ts",
143
+ "view-adapter-CrHh7CjB.d.cts",
144
+ "view-adapter-DPDvv09J.d.ts"
136
145
  ],
137
- "sha": "c642307",
146
+ "sha": "46c9d1a",
138
147
  "scripts": {}
139
148
  }
@@ -1,4 +1,4 @@
1
- import { G as GuardDefinition } from './types-BxMQ-VOd.cjs';
1
+ import { G as GuardDefinition } from './types-Ccd5bmt1.cjs';
2
2
 
3
3
  /** Маршрут с политикой доступа. */
4
4
  interface RouteDeclaration {
@@ -1,4 +1,4 @@
1
- import { G as GuardDefinition } from './types-BxMQ-VOd.js';
1
+ import { G as GuardDefinition } from './types-Ccd5bmt1.js';
2
2
 
3
3
  /** Маршрут с политикой доступа. */
4
4
  interface RouteDeclaration {
package/serve/index.cjs CHANGED
@@ -14,6 +14,13 @@ require('../chunk-6QV4L6R2.cjs');
14
14
  var _chunkA6ZPAM6Zcjs = require('../chunk-A6ZPAM6Z.cjs');
15
15
 
16
16
 
17
+
18
+
19
+
20
+ var _chunk2P5TAWRWcjs = require('../chunk-2P5TAWRW.cjs');
21
+
22
+
23
+
17
24
  var _chunkT5QVCXVBcjs = require('../chunk-T5QVCXVB.cjs');
18
25
 
19
26
  // src/serve/index.ts
@@ -79,7 +86,7 @@ function matchClaim(app, pathname) {
79
86
  }
80
87
  return (_b = (_a = _chunkQTWJTYZWcjs.matchRoute.call(void 0, app.routes, pathname)) == null ? void 0 : _a.params) != null ? _b : null;
81
88
  }
82
- function browserContext(req) {
89
+ function requestContextOf(req, fromBody) {
83
90
  const headers = {};
84
91
  const forwarded = {
85
92
  "accept-language": req.headers["x-forwarded-accept-language"],
@@ -91,22 +98,32 @@ function browserContext(req) {
91
98
  }
92
99
  }
93
100
  const cookie = req.headers.cookie;
94
- if (typeof cookie === "string" && cookie !== "") {
95
- headers.cookie = cookie;
101
+ const backendHeaders = _chunkT5QVCXVBcjs.__spreadValues.call(void 0, _chunkT5QVCXVBcjs.__spreadValues.call(void 0, {}, typeof cookie === "string" && cookie !== "" ? { cookie } : {}), fromBody);
102
+ return { backendHeaders, cookies: _chunkQTWJTYZWcjs.parseCookieHeader.call(void 0, cookie), headers };
103
+ }
104
+ function backendHeadersOf(value) {
105
+ if (value === void 0) {
106
+ return void 0;
107
+ }
108
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
109
+ return "invalid";
96
110
  }
97
- return { cookies: _chunkQTWJTYZWcjs.parseCookieHeader.call(void 0, cookie), headers };
111
+ const entries = Object.entries(value);
112
+ if (entries.some(([, single]) => typeof single !== "string")) {
113
+ return "invalid";
114
+ }
115
+ return Object.fromEntries(entries.map(([name, single]) => [name.toLowerCase(), single]));
98
116
  }
99
117
  var appPlugin = (instance, options) => {
100
118
  var _a, _b;
101
119
  const { app, slowRenderMs = DEFAULT_SLOW_RENDER_MS } = options;
102
120
  const appLog = (_a = _logger.log.getLogger(app.name)) != null ? _a : _chunkA6ZPAM6Zcjs.logger;
103
121
  const serveLog = (_b = appLog.getLogger("serve")) != null ? _b : appLog;
104
- instance.get("/_health", () => "ok");
105
122
  instance.get("/_routes", (_req, reply) => {
106
123
  void reply.header("cache-control", "no-store");
107
124
  return claim(app);
108
125
  });
109
- function handleRender(req, reply, target, inputs) {
126
+ function handleRender(req, reply, target, inputs, rawBackendHeaders) {
110
127
  return _chunkT5QVCXVBcjs.__async.call(void 0, this, null, function* () {
111
128
  if (typeof target !== "string" || !target.startsWith("/")) {
112
129
  return reply.code(400).send({ error: "\u043D\u0435 \u043F\u0435\u0440\u0435\u0434\u0430\u043D \u0438\u043B\u0438 \u043D\u0435\u0432\u0430\u043B\u0438\u0434\u0435\u043D \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440 url" });
@@ -114,6 +131,10 @@ var appPlugin = (instance, options) => {
114
131
  if (inputs !== void 0 && (typeof inputs !== "object" || inputs === null || Array.isArray(inputs))) {
115
132
  return reply.code(400).send({ error: "inputs \u0434\u043E\u043B\u0436\u043D\u044B \u0431\u044B\u0442\u044C \u043E\u0431\u044A\u0435\u043A\u0442\u043E\u043C \u043F\u043E \u043A\u043B\u044E\u0447\u0443 token.description" });
116
133
  }
134
+ const backendHeaders = backendHeadersOf(rawBackendHeaders);
135
+ if (backendHeaders === "invalid") {
136
+ return reply.code(400).send({ error: "backendHeaders \u0434\u043E\u043B\u0436\u043D\u044B \u0431\u044B\u0442\u044C \u043E\u0431\u044A\u0435\u043A\u0442\u043E\u043C \xAB\u0438\u043C\u044F \u0437\u0430\u0433\u043E\u043B\u043E\u0432\u043A\u0430 \u2192 \u0441\u0442\u0440\u043E\u043A\u0430\xBB" });
137
+ }
117
138
  const { pathname, search } = new URL(target, "http://localhost");
118
139
  const params = matchClaim(app, pathname);
119
140
  if (params === null) {
@@ -123,7 +144,7 @@ var appPlugin = (instance, options) => {
123
144
  const startedAt = Date.now();
124
145
  try {
125
146
  const result = yield _chunkQTWJTYZWcjs.renderApp.call(void 0, app, {
126
- context: browserContext(req),
147
+ context: requestContextOf(req, backendHeaders),
127
148
  inputs,
128
149
  params,
129
150
  pathname,
@@ -140,12 +161,15 @@ var appPlugin = (instance, options) => {
140
161
  }
141
162
  });
142
163
  }
143
- instance.get("/_render", (req, reply) => handleRender(req, reply, req.query.url, void 0));
164
+ instance.get(
165
+ "/_render",
166
+ (req, reply) => handleRender(req, reply, req.query.url, void 0, void 0)
167
+ );
144
168
  instance.route({
145
169
  handler: (req, reply) => {
146
170
  var _a2;
147
171
  const body = (_a2 = req.body) != null ? _a2 : {};
148
- return handleRender(req, reply, body.url, body.inputs);
172
+ return handleRender(req, reply, body.url, body.inputs, body.backendHeaders);
149
173
  },
150
174
  method: "QUERY",
151
175
  url: "/_render"
@@ -157,10 +181,35 @@ var appPlugin = (instance, options) => {
157
181
  var SHUTDOWN_SIGNALS = ["SIGTERM", "SIGINT"];
158
182
  function serveApp(_0) {
159
183
  return _chunkT5QVCXVBcjs.__async.call(void 0, this, arguments, function* (app, options = {}) {
160
- var _a, _b, _c, _d;
184
+ var _a, _b, _c, _d, _e;
161
185
  const appLog = (_a = _logger.log.getLogger(app.name)) != null ? _a : _chunkA6ZPAM6Zcjs.logger;
162
186
  const serveLog = (_b = appLog.getLogger("serve")) != null ? _b : appLog;
163
187
  const instance = _fastify2.default.call(void 0, { logger: false });
188
+ const metrics = _chunk2P5TAWRWcjs.getProcessMetrics.call(void 0, );
189
+ metrics.startRuntime(app.name);
190
+ let ops;
191
+ const shutdown = () => {
192
+ void instance.close();
193
+ };
194
+ instance.addHook("onRequest", (req, reply, done) => {
195
+ if (_chunk2P5TAWRWcjs.isOpsPath.call(void 0, req.url)) {
196
+ void reply.code(404).send();
197
+ return;
198
+ }
199
+ metrics.trackHttp(req.raw, reply.raw, () => {
200
+ var _a2;
201
+ return (_a2 = req.routeOptions.url) != null ? _a2 : "unmatched";
202
+ });
203
+ done();
204
+ });
205
+ instance.addHook("onClose", () => _chunkT5QVCXVBcjs.__async.call(void 0, null, null, function* () {
206
+ for (const signal of SHUTDOWN_SIGNALS) {
207
+ process.removeListener(signal, shutdown);
208
+ }
209
+ if (ops) {
210
+ yield _chunk2P5TAWRWcjs.closeHttpServer.call(void 0, ops);
211
+ }
212
+ }));
164
213
  yield instance.register(appPlugin, { app, slowRenderMs: options.slowRenderMs });
165
214
  if (options.assets) {
166
215
  registerAssets(instance, options.assets);
@@ -174,14 +223,19 @@ function serveApp(_0) {
174
223
  serveLog.info(`\u2190 ${String(reply.statusCode)} ${req.method} ${req.url} ${elapsed}\u043C\u0441`);
175
224
  done();
176
225
  });
177
- yield (_c = options.configure) == null ? void 0 : _c.call(options, instance);
178
- yield instance.listen({ host: options.host, port: (_d = options.port) != null ? _d : 0 });
226
+ try {
227
+ yield (_c = options.configure) == null ? void 0 : _c.call(options, instance);
228
+ if (options.ops !== false) {
229
+ ops = yield _chunk2P5TAWRWcjs.startOpsServer.call(void 0, options.ops);
230
+ }
231
+ yield instance.listen({ host: (_d = options.host) != null ? _d : "0.0.0.0", port: (_e = options.port) != null ? _e : 8080 });
232
+ } catch (error) {
233
+ yield instance.close();
234
+ throw error;
235
+ }
179
236
  if (options.gracefulShutdown !== false) {
180
237
  for (const signal of SHUTDOWN_SIGNALS) {
181
- process.once(signal, () => {
182
- serveLog.info(`${signal}: \u0437\u0430\u043A\u0440\u044B\u0432\u0430\u044E \u0438\u043D\u0441\u0442\u0430\u043D\u0441`);
183
- void instance.close();
184
- });
238
+ process.once(signal, shutdown);
185
239
  }
186
240
  }
187
241
  serveLog.info(
package/serve/index.d.cts CHANGED
@@ -1,9 +1,12 @@
1
1
  import { FastifyInstance, FastifyPluginAsync } from 'fastify';
2
- import { I as IslandDescriptor } from '../descriptor-C2j6Zz6c.cjs';
3
- import { A as AppRoute } from '../routes-BvV405k4.cjs';
4
- import '../define-slot-BEeHNEph.cjs';
5
- import '../types-BxMQ-VOd.cjs';
2
+ import { I as IslandDescriptor } from '../descriptor-DmfJP4jQ.cjs';
3
+ import { A as AppRoute } from '../routes-DQ4ud4bu.cjs';
4
+ import { OpsOptions } from '../ops/index.cjs';
5
+ import '../define-slot-C6hrdJS3.cjs';
6
+ import '../types-Ccd5bmt1.cjs';
6
7
  import '@foxford/ioc';
8
+ import '@prometheus-io/client';
9
+ import 'node:http';
7
10
 
8
11
  /** Что раздаётся и по какому префиксу. */
9
12
  interface AppAssetsSource {
@@ -31,7 +34,7 @@ interface AppPluginOptions {
31
34
  slowRenderMs?: number;
32
35
  }
33
36
  /**
34
- * Регистрирует ручки приложения на инстансе fastify: `/_render`, `/_routes`, `/_health`.
37
+ * Регистрирует ручки приложения на инстансе fastify: `/_render`, `/_routes`.
35
38
  *
36
39
  * Плагином, поэтому монтируется и в свой сервер, и в чужой — под префиксом, рядом с ручками
37
40
  * потребителя, вместе с его плагинами.
@@ -54,6 +57,8 @@ declare function loadAppEnv(root: string): void;
54
57
  interface ServeAppOptions {
55
58
  /** Порт; `0` — свободный, фактический смотри в `server.addresses()`. */
56
59
  port?: number;
60
+ /** Второй HTTP-сервер для probes и метрик; false — подключается потребителем. */
61
+ ops?: OpsOptions | false;
57
62
  /** Интерфейс прослушивания. */
58
63
  host?: string;
59
64
  /** Порог, выше которого рендер считается медленным и уходит в `warn`, мс. */