@gobing-ai/ts-infra 0.3.5 → 0.3.6

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 (63) hide show
  1. package/README.md +95 -60
  2. package/dist/application/index.d.ts +16 -18
  3. package/dist/application/index.d.ts.map +1 -1
  4. package/dist/application/index.js +59 -96
  5. package/dist/application/plugins/builtins.d.ts +64 -0
  6. package/dist/application/plugins/builtins.d.ts.map +1 -0
  7. package/dist/application/plugins/builtins.js +146 -0
  8. package/dist/application/plugins/host.d.ts +61 -0
  9. package/dist/application/plugins/host.d.ts.map +1 -0
  10. package/dist/application/plugins/host.js +131 -0
  11. package/dist/application/plugins/index.d.ts +3 -0
  12. package/dist/application/plugins/index.d.ts.map +1 -0
  13. package/dist/application/plugins/index.js +2 -0
  14. package/dist/application/plugins/types.d.ts +69 -0
  15. package/dist/application/plugins/types.d.ts.map +1 -0
  16. package/dist/application/plugins/types.js +10 -0
  17. package/dist/application/types.d.ts +7 -0
  18. package/dist/application/types.d.ts.map +1 -1
  19. package/dist/application-node.d.ts.map +1 -1
  20. package/dist/application-node.js +40 -57
  21. package/dist/index.d.ts +1 -1
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +1 -1
  24. package/dist/scheduler/cloudflare.d.ts.map +1 -1
  25. package/dist/scheduler/cloudflare.js +9 -2
  26. package/dist/scheduler/factory.d.ts +4 -8
  27. package/dist/scheduler/factory.d.ts.map +1 -1
  28. package/dist/scheduler/factory.js +12 -22
  29. package/dist/scheduler/index.d.ts +1 -1
  30. package/dist/scheduler/index.d.ts.map +1 -1
  31. package/dist/scheduler/index.js +1 -1
  32. package/dist/scheduler/wrap-handler.d.ts +8 -4
  33. package/dist/scheduler/wrap-handler.d.ts.map +1 -1
  34. package/dist/scheduler/wrap-handler.js +8 -4
  35. package/dist/telemetry/index.d.ts +1 -2
  36. package/dist/telemetry/index.d.ts.map +1 -1
  37. package/dist/telemetry/index.js +1 -2
  38. package/dist/telemetry/metrics.d.ts +9 -1
  39. package/dist/telemetry/metrics.d.ts.map +1 -1
  40. package/dist/telemetry/metrics.js +22 -1
  41. package/dist/telemetry/sdk.d.ts +33 -1
  42. package/dist/telemetry/sdk.d.ts.map +1 -1
  43. package/dist/telemetry/sdk.js +14 -1
  44. package/package.json +5 -5
  45. package/src/application/index.ts +72 -102
  46. package/src/application/plugins/builtins.ts +178 -0
  47. package/src/application/plugins/host.ts +143 -0
  48. package/src/application/plugins/index.ts +3 -0
  49. package/src/application/plugins/types.ts +86 -0
  50. package/src/application/types.ts +7 -0
  51. package/src/application-node.ts +43 -61
  52. package/src/index.ts +0 -2
  53. package/src/scheduler/cloudflare.ts +16 -5
  54. package/src/scheduler/factory.ts +15 -26
  55. package/src/scheduler/index.ts +1 -1
  56. package/src/scheduler/wrap-handler.ts +8 -4
  57. package/src/telemetry/index.ts +9 -2
  58. package/src/telemetry/metrics.ts +22 -1
  59. package/src/telemetry/sdk.ts +51 -2
  60. package/dist/telemetry/config.d.ts +0 -41
  61. package/dist/telemetry/config.d.ts.map +0 -1
  62. package/dist/telemetry/config.js +0 -21
  63. package/src/telemetry/config.ts +0 -59
@@ -0,0 +1,146 @@
1
+ /**
2
+ * Built-in service plugins for the application bootstrap.
3
+ *
4
+ * Each factory returns a `Plugin` that maps an existing init/shutdown pair onto
5
+ * the PluginHost lifecycle: `onStart` = init, `onStop` = teardown. Absent
6
+ * hooks are omitted (no-op by absence, not by stub).
7
+ *
8
+ * @module application/plugins
9
+ */
10
+ import { initializeLogger } from '../../logger.js';
11
+ import { initMetrics, shutdownMetrics } from '../../telemetry/metrics.js';
12
+ import { initTelemetry, shutdownTelemetry } from '../../telemetry/sdk.js';
13
+ // ── Telemetry ──────────────────────────────────────────────────────────────
14
+ /**
15
+ * Built-in plugin for telemetry + metrics.
16
+ *
17
+ * `onStart`: `initTelemetry` + `initMetrics` (pre-warm instruments).
18
+ * `onStop`: `shutdownMetrics` + `shutdownTelemetry` (reverse of init).
19
+ * `failFast: true` — a failing telemetry init aborts the bootstrap.
20
+ */
21
+ export function telemetryPlugin(config) {
22
+ return {
23
+ name: 'builtin:telemetry',
24
+ version: '0.0.0',
25
+ failFast: true,
26
+ onLoad: async () => { },
27
+ onStart: async () => {
28
+ if (config.enabled) {
29
+ initTelemetry({
30
+ enabled: config.enabled,
31
+ serviceName: config.serviceName,
32
+ environment: config.environment,
33
+ dbStatementDebug: config.dbStatementDebug,
34
+ });
35
+ initMetrics();
36
+ }
37
+ },
38
+ onStop: async () => {
39
+ if (config.enabled) {
40
+ shutdownMetrics();
41
+ await shutdownTelemetry();
42
+ }
43
+ },
44
+ };
45
+ }
46
+ // ── Logger ─────────────────────────────────────────────────────────────────
47
+ /**
48
+ * Built-in plugin for the structured logger.
49
+ *
50
+ * `onStart`: `initializeLogger` (skipped when an injected logger is present).
51
+ * No `onStop` — the logger has no teardown.
52
+ * `failFast: true` — a failing logger init aborts the bootstrap.
53
+ */
54
+ export function loggerPlugin(config, injected) {
55
+ return {
56
+ name: 'builtin:logger',
57
+ version: '0.0.0',
58
+ failFast: true,
59
+ onLoad: async () => { },
60
+ onStart: async () => {
61
+ if (config.enabled && !injected) {
62
+ await initializeLogger({
63
+ level: config.level,
64
+ console: config.console,
65
+ json: config.json,
66
+ fileSink: config.fileSink,
67
+ });
68
+ }
69
+ },
70
+ };
71
+ }
72
+ /**
73
+ * Built-in plugin that wraps the user's `start`/`stop` callbacks.
74
+ *
75
+ * `onStart`: calls `options.start(app)`. `failFast: true`.
76
+ * `onStop`: calls `options.stop(app, reason)`. Registered after services,
77
+ * before scheduler, so stopAll/reverse-order places it after
78
+ * scheduler.stop and before service teardown.
79
+ */
80
+ export function userCallbackPlugin(start, stop, app) {
81
+ return {
82
+ name: 'builtin:user-callback',
83
+ version: '0.0.0',
84
+ failFast: true,
85
+ onLoad: async () => { },
86
+ onStart: async () => {
87
+ if (app)
88
+ await start(app);
89
+ },
90
+ onStop: stop && app
91
+ ? async (_host, reason) => {
92
+ await stop(app, reason ?? 'manual');
93
+ }
94
+ : undefined,
95
+ };
96
+ }
97
+ /**
98
+ * Built-in plugin for the scheduler.
99
+ *
100
+ * `onStart`: `adapter.start()` when `autoStart` is true.
101
+ * `onStop`: `adapter.stop()` — fail-soft.
102
+ *
103
+ * Registered LAST so autoStart always runs after the user callback.
104
+ */
105
+ export function schedulerPlugin(adapter, autoStart) {
106
+ return {
107
+ name: 'builtin:scheduler',
108
+ version: '0.0.0',
109
+ failFast: true,
110
+ onLoad: async () => { },
111
+ onStart: async () => {
112
+ if (autoStart) {
113
+ await adapter.start();
114
+ }
115
+ },
116
+ onStop: async () => {
117
+ // Fail-soft — the host always catches stop/unload errors
118
+ await adapter.stop();
119
+ },
120
+ };
121
+ }
122
+ // ── DB (reason-aware, for owned adapters only) ────────────────────────────
123
+ /**
124
+ * Built-in plugin for a DB adapter the bootstrap OWNS.
125
+ *
126
+ * `onStop(reason)`: `db.close()` — best-effort.
127
+ * Register ONLY when the bootstrap creates the adapter (Node subpath).
128
+ * Do NOT register for caller-injected `services.db` — those are caller-owned.
129
+ */
130
+ export function dbPlugin(db) {
131
+ return {
132
+ name: 'builtin:db',
133
+ version: '0.0.0',
134
+ failFast: false,
135
+ onLoad: async () => { },
136
+ onStart: async () => { },
137
+ onStop: async () => {
138
+ try {
139
+ db.close();
140
+ }
141
+ catch {
142
+ /* best-effort */
143
+ }
144
+ },
145
+ };
146
+ }
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Bare `PluginHost` — owns an insertion-ordered set of plugins and drives
3
+ * lifecycle fan-out (load → start → stop → unload) with fail-soft semantics
4
+ * for start/stop/unload and fail-fast for load.
5
+ *
6
+ * This is a runtime concern: it needs a logger and event bus, both provided
7
+ * by the application bootstrap. No capabilities, no trust ladder.
8
+ *
9
+ * @module application/plugins
10
+ */
11
+ import type { EventBus } from '../../event-bus/event-bus';
12
+ import type { EventMap } from '../../event-bus/types';
13
+ import { type Logger } from '../../logger';
14
+ import type { Plugin, PluginSummary } from './types';
15
+ /**
16
+ * Plugin host: registers plugins in insertion order and drives their lifecycle
17
+ * fan-out (load → start → stop → unload).
18
+ *
19
+ * The host stores `EventBus<EventMap>` (the base event contract) rather than
20
+ * a narrower `TEvents` subtype, because `EventBus` is invariant in its type
21
+ * parameter and plugins only need the base contract.
22
+ */
23
+ export declare class PluginHost {
24
+ readonly logger: Logger;
25
+ readonly events: EventBus<EventMap>;
26
+ private readonly _plugins;
27
+ constructor(events: EventBus<EventMap>, opts?: {
28
+ logger?: Logger;
29
+ });
30
+ /** Register a plugin. Throws on duplicate name. */
31
+ register(plugin: Plugin): void;
32
+ /** Remove a plugin by name. No-op if absent. */
33
+ unregister(name: string): void;
34
+ /** Check whether a plugin is registered. */
35
+ has(name: string): boolean;
36
+ /** List registered plugins in registration order. */
37
+ list(): readonly PluginSummary[];
38
+ /**
39
+ * Fail-fast: calls `onLoad` on every plugin in registration order.
40
+ * A throwing hook aborts the bootstrap.
41
+ */
42
+ loadAll(): Promise<void>;
43
+ /**
44
+ * Calls `onStart` on every plugin in registration order.
45
+ * Plugins with `failFast: true` rethrow (aborting boot); others log + skip.
46
+ */
47
+ startAll(): Promise<void>;
48
+ /**
49
+ * Fail-soft: calls `onStop` on every plugin in **reverse** registration order.
50
+ * A throwing hook is logged + skipped.
51
+ * `reason` is forwarded to each plugin's `onStop(host, reason?)`.
52
+ */
53
+ stopAll(reason?: string): Promise<void>;
54
+ /**
55
+ * Fail-soft: calls `onUnload` on every plugin in **reverse** registration order.
56
+ * A throwing hook is logged + skipped.
57
+ * `reason` is forwarded to each plugin's `onUnload(host, reason?)`.
58
+ */
59
+ unloadAll(reason?: string): Promise<void>;
60
+ }
61
+ //# sourceMappingURL=host.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"host.d.ts","sourceRoot":"","sources":["../../../src/application/plugins/host.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAa,KAAK,MAAM,EAAE,MAAM,cAAc,CAAC;AACtD,OAAO,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAIrD;;;;;;;GAOG;AACH,qBAAa,UAAU;IACnB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAEpC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA6B;gBAE1C,MAAM,EAAE,QAAQ,CAAC,QAAQ,CAAC,EAAE,IAAI,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE;IAOlE,mDAAmD;IACnD,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAO9B,gDAAgD;IAChD,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAI9B,4CAA4C;IAC5C,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAI1B,qDAAqD;IACrD,IAAI,IAAI,SAAS,aAAa,EAAE;IAUhC;;;OAGG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAO9B;;;OAGG;IACG,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAkB/B;;;;OAIG;IACG,OAAO,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAgB7C;;;;OAIG;IACG,SAAS,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAelD"}
@@ -0,0 +1,131 @@
1
+ /**
2
+ * Bare `PluginHost` — owns an insertion-ordered set of plugins and drives
3
+ * lifecycle fan-out (load → start → stop → unload) with fail-soft semantics
4
+ * for start/stop/unload and fail-fast for load.
5
+ *
6
+ * This is a runtime concern: it needs a logger and event bus, both provided
7
+ * by the application bootstrap. No capabilities, no trust ladder.
8
+ *
9
+ * @module application/plugins
10
+ */
11
+ import { getLogger } from '../../logger.js';
12
+ // ── PluginHost ─────────────────────────────────────────────────────────────
13
+ /**
14
+ * Plugin host: registers plugins in insertion order and drives their lifecycle
15
+ * fan-out (load → start → stop → unload).
16
+ *
17
+ * The host stores `EventBus<EventMap>` (the base event contract) rather than
18
+ * a narrower `TEvents` subtype, because `EventBus` is invariant in its type
19
+ * parameter and plugins only need the base contract.
20
+ */
21
+ export class PluginHost {
22
+ logger;
23
+ events;
24
+ _plugins = new Map();
25
+ constructor(events, opts) {
26
+ this.events = events;
27
+ this.logger = opts?.logger ?? getLogger('plugin-host');
28
+ }
29
+ // ── Registration ────────────────────────────────────────────────────
30
+ /** Register a plugin. Throws on duplicate name. */
31
+ register(plugin) {
32
+ if (this._plugins.has(plugin.name)) {
33
+ throw new Error(`Plugin already registered: ${plugin.name}`);
34
+ }
35
+ this._plugins.set(plugin.name, plugin);
36
+ }
37
+ /** Remove a plugin by name. No-op if absent. */
38
+ unregister(name) {
39
+ this._plugins.delete(name);
40
+ }
41
+ /** Check whether a plugin is registered. */
42
+ has(name) {
43
+ return this._plugins.has(name);
44
+ }
45
+ /** List registered plugins in registration order. */
46
+ list() {
47
+ const result = [];
48
+ for (const p of this._plugins.values()) {
49
+ result.push({ name: p.name, version: p.version });
50
+ }
51
+ return result;
52
+ }
53
+ // ── Lifecycle fan-out ───────────────────────────────────────────────
54
+ /**
55
+ * Fail-fast: calls `onLoad` on every plugin in registration order.
56
+ * A throwing hook aborts the bootstrap.
57
+ */
58
+ async loadAll() {
59
+ for (const plugin of this._plugins.values()) {
60
+ this.logger.debug(`Loading plugin: ${plugin.name}`, { name: plugin.name });
61
+ await plugin.onLoad(this);
62
+ }
63
+ }
64
+ /**
65
+ * Calls `onStart` on every plugin in registration order.
66
+ * Plugins with `failFast: true` rethrow (aborting boot); others log + skip.
67
+ */
68
+ async startAll() {
69
+ for (const plugin of this._plugins.values()) {
70
+ if (!plugin.onStart)
71
+ continue;
72
+ try {
73
+ this.logger.debug(`Starting plugin: ${plugin.name}`, { name: plugin.name });
74
+ await plugin.onStart(this);
75
+ }
76
+ catch (err) {
77
+ if (plugin.failFast) {
78
+ throw err;
79
+ }
80
+ this.logger.error(`Plugin start hook failed: ${plugin.name}`, {
81
+ name: plugin.name,
82
+ error: err.message,
83
+ });
84
+ }
85
+ }
86
+ }
87
+ /**
88
+ * Fail-soft: calls `onStop` on every plugin in **reverse** registration order.
89
+ * A throwing hook is logged + skipped.
90
+ * `reason` is forwarded to each plugin's `onStop(host, reason?)`.
91
+ */
92
+ async stopAll(reason) {
93
+ const reversed = [...this._plugins.values()].reverse();
94
+ for (const plugin of reversed) {
95
+ if (!plugin.onStop)
96
+ continue;
97
+ try {
98
+ this.logger.debug(`Stopping plugin: ${plugin.name}`, { name: plugin.name, reason });
99
+ await plugin.onStop(this, reason);
100
+ }
101
+ catch (err) {
102
+ this.logger.error(`Plugin stop hook failed: ${plugin.name}`, {
103
+ name: plugin.name,
104
+ error: err.message,
105
+ });
106
+ }
107
+ }
108
+ }
109
+ /**
110
+ * Fail-soft: calls `onUnload` on every plugin in **reverse** registration order.
111
+ * A throwing hook is logged + skipped.
112
+ * `reason` is forwarded to each plugin's `onUnload(host, reason?)`.
113
+ */
114
+ async unloadAll(reason) {
115
+ const reversed = [...this._plugins.values()].reverse();
116
+ for (const plugin of reversed) {
117
+ if (!plugin.onUnload)
118
+ continue;
119
+ try {
120
+ this.logger.debug(`Unloading plugin: ${plugin.name}`, { name: plugin.name, reason });
121
+ await plugin.onUnload(this, reason);
122
+ }
123
+ catch (err) {
124
+ this.logger.error(`Plugin unload hook failed: ${plugin.name}`, {
125
+ name: plugin.name,
126
+ error: err.message,
127
+ });
128
+ }
129
+ }
130
+ }
131
+ }
@@ -0,0 +1,3 @@
1
+ export { PluginHost } from './host';
2
+ export type { Plugin, PluginSummary } from './types';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/application/plugins/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AACpC,YAAY,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC"}
@@ -0,0 +1,2 @@
1
+ // PluginHost class doubles as the type (same contract)
2
+ export { PluginHost } from './host.js';
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Portable plugin lifecycle contract.
3
+ *
4
+ * The `Plugin` interface is a minimal runtime-neutral lifecycle contract:
5
+ * no capabilities, no trust ladder, no manifest schema — just `onLoad` / `onUnload`
6
+ * and `onStart` / `onStop` hooks. Names are deliberately runtime-neutral so
7
+ * CLI and long-lived server apps share the same semantics.
8
+ *
9
+ * @module application/plugins
10
+ */
11
+ import type { EventBus } from '../../event-bus/event-bus';
12
+ import type { EventMap } from '../../event-bus/types';
13
+ import type { Logger } from '../../logger';
14
+ /**
15
+ * Minimal plugin lifecycle contract.
16
+ *
17
+ * All hooks receive the host reference so a plugin can access the runtime
18
+ * logger, event bus, and other plugins.
19
+ */
20
+ export interface Plugin {
21
+ /** Unique name. Used for dedup and lookup in the host. */
22
+ readonly name: string;
23
+ /** Semver-compatible version string. Informational only in this cut. */
24
+ readonly version: string;
25
+ /**
26
+ * When `true`, a throwing `onStart` aborts the bootstrap (fail-fast).
27
+ * When absent/false, a throwing `onStart` is logged and skipped (fail-soft).
28
+ * Has no effect on `loadAll` (always fail-fast) or `stopAll`/`unloadAll`
29
+ * (always fail-soft — teardown is best-effort).
30
+ */
31
+ readonly failFast?: boolean;
32
+ /**
33
+ * Called during `PluginHost.loadAll()` — fail-fast.
34
+ * A throwing `onLoad` aborts the bootstrap.
35
+ */
36
+ onLoad(host: PluginHost): void | Promise<void>;
37
+ /** Called during `PluginHost.unloadAll()` — fail-soft. */
38
+ onUnload?(host: PluginHost, reason?: string): void | Promise<void>;
39
+ /** Called during `PluginHost.startAll()` — fail-soft. */
40
+ onStart?(host: PluginHost): void | Promise<void>;
41
+ /** Called during `PluginHost.stopAll()` — fail-soft. */
42
+ onStop?(host: PluginHost, reason?: string): void | Promise<void>;
43
+ }
44
+ /**
45
+ * Summary view of a registered plugin (no references, just metadata).
46
+ */
47
+ export interface PluginSummary {
48
+ readonly name: string;
49
+ readonly version: string;
50
+ }
51
+ /**
52
+ * Structural contract for the plugin host.
53
+ *
54
+ * This is the shape exposed on `ApplicationRuntime.pluginHost`. Consumers
55
+ * that need to register/unregister plugins at runtime use this interface.
56
+ */
57
+ export interface PluginHost {
58
+ readonly logger: Logger;
59
+ readonly events: EventBus<EventMap>;
60
+ register(plugin: Plugin): void;
61
+ unregister(name: string): void;
62
+ has(name: string): boolean;
63
+ list(): readonly PluginSummary[];
64
+ loadAll(): Promise<void>;
65
+ startAll(): Promise<void>;
66
+ stopAll(reason?: string): Promise<void>;
67
+ unloadAll(reason?: string): Promise<void>;
68
+ }
69
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/application/plugins/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAI3C;;;;;GAKG;AACH,MAAM,WAAW,MAAM;IACnB,0DAA0D;IAC1D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB,wEAAwE;IACxE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAEzB;;;;;OAKG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAE5B;;;OAGG;IACH,MAAM,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE/C,0DAA0D;IAC1D,QAAQ,CAAC,CAAC,IAAI,EAAE,UAAU,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEnE,yDAAyD;IACzD,OAAO,CAAC,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEjD,wDAAwD;IACxD,MAAM,CAAC,CAAC,IAAI,EAAE,UAAU,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACpE;AAID;;GAEG;AACH,MAAM,WAAW,aAAa;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC5B;AAID;;;;;GAKG;AACH,MAAM,WAAW,UAAU;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAEpC,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IAC3B,IAAI,IAAI,SAAS,aAAa,EAAE,CAAC;IAEjC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACzB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B,OAAO,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxC,SAAS,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC7C"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Portable plugin lifecycle contract.
3
+ *
4
+ * The `Plugin` interface is a minimal runtime-neutral lifecycle contract:
5
+ * no capabilities, no trust ladder, no manifest schema — just `onLoad` / `onUnload`
6
+ * and `onStart` / `onStop` hooks. Names are deliberately runtime-neutral so
7
+ * CLI and long-lived server apps share the same semantics.
8
+ *
9
+ * @module application/plugins
10
+ */
@@ -12,6 +12,8 @@ import type { BusLifecycleEvents, EventMap } from '../event-bus/types';
12
12
  import type { InfraEvents } from '../events';
13
13
  import type { Logger, LogLevel } from '../logger';
14
14
  import type { SchedulerAdapter } from '../scheduler/types';
15
+ import type { PluginHost } from './plugins/host';
16
+ import type { Plugin } from './plugins/types';
15
17
  /** Logging feature flags. */
16
18
  export interface LoggingOptions {
17
19
  /** Enable logging. Default `true`. */
@@ -92,6 +94,8 @@ export interface ApplicationServices<TEvents extends EventMap = InfraEvents> {
92
94
  lifecycleBus?: EventBus<BusLifecycleEvents>;
93
95
  db?: DbAdapterLike;
94
96
  scheduler?: SchedulerAdapter;
97
+ /** Pre-built plugin host (when injecting instead of constructing). */
98
+ pluginHost?: PluginHost;
95
99
  }
96
100
  /**
97
101
  * Minimal DB adapter shape the bootstrap cares about: `close()` for lifecycle.
@@ -122,6 +126,7 @@ export interface ApplicationRuntime<TAppConfig = unknown, TEvents extends EventM
122
126
  readonly db?: DbAdapterLike;
123
127
  /** Scheduler adapter (when enabled). */
124
128
  readonly scheduler?: SchedulerAdapter;
129
+ readonly pluginHost: PluginHost;
125
130
  /** Graceful shutdown. Idempotent — safe to call multiple times. */
126
131
  stop(reason?: ApplicationStopReason): Promise<void>;
127
132
  }
@@ -140,6 +145,8 @@ export interface ApplicationBootstrapOptions<TAppConfig = unknown, TEvents exten
140
145
  readonly appConfig?: TAppConfig;
141
146
  /** Pre-built services to inject instead of creating defaults. */
142
147
  readonly services?: Partial<ApplicationServices<TEvents>>;
148
+ /** Plugins to register and lifecycle-manage via PluginHost. */
149
+ readonly plugins?: Plugin[];
143
150
  /** User callback: application logic. Called after all services are ready. */
144
151
  readonly start: (app: ApplicationRuntime<TAppConfig, TEvents>) => Promise<void> | void;
145
152
  /** User callback: cleanup before services shut down. */
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/application/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/application/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,KAAK,EAAE,kBAAkB,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AACvE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAClD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAI9C,6BAA6B;AAC7B,MAAM,WAAW,cAAc;IAC3B,sCAAsC;IACtC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,2CAA2C;IAC3C,KAAK,CAAC,EAAE,QAAQ,CAAC;IACjB,6CAA6C;IAC7C,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;OAGG;IACH,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,yCAAyC;IACzC,IAAI,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,+BAA+B;AAC/B,MAAM,WAAW,aAAa,CAAC,OAAO,SAAS,QAAQ,GAAG,WAAW;IACjE,wCAAwC;IACxC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,yDAAyD;IACzD,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,kEAAkE;IAClE,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,0DAA0D;IAC1D,GAAG,CAAC,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC;CAC3B;AAED,+BAA+B;AAC/B,MAAM,WAAW,gBAAgB;IAC7B,wDAAwD;IACxD,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,mDAAmD;IACnD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,uDAAuD;IACvD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,0DAA0D;IAC1D,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED,+BAA+B;AAC/B,MAAM,WAAW,gBAAgB;IAC7B,yCAAyC;IACzC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,2DAA2D;IAC3D,OAAO,CAAC,EAAE,gBAAgB,CAAC;IAC3B,oDAAoD;IACpD,OAAO,CAAC,EAAE,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC/C,mFAAmF;IACnF,SAAS,CAAC,EAAE,OAAO,CAAC;CACvB;AAID;;;GAGG;AACH,MAAM,WAAW,0BAA0B;IACvC,QAAQ,CAAC,OAAO,EAAE,QAAQ,CACtB,QAAQ,CAAC,IAAI,CAAC,cAAc,EAAE,SAAS,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC,CAAC,GAAG;QAAE,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;KAAE,CACnH,CAAC;IACF,QAAQ,CAAC,MAAM,EAAE;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,SAAS,EAAE,OAAO,CAAC;QAAC,gBAAgB,EAAE,OAAO,CAAA;KAAE,CAAC;IACrF,QAAQ,CAAC,SAAS,EAAE;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,gBAAgB,EAAE,OAAO,CAAA;KAAE,CAAC;IAC9G,QAAQ,CAAC,SAAS,EAAE;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,SAAS,EAAE,OAAO,CAAA;KAAE,CAAC;CAChE;AAID,6EAA6E;AAC7E,MAAM,WAAW,mBAAmB,CAAC,OAAO,SAAS,QAAQ,GAAG,WAAW;IACvE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC;IAC3B,YAAY,CAAC,EAAE,QAAQ,CAAC,kBAAkB,CAAC,CAAC;IAC5C,EAAE,CAAC,EAAE,aAAa,CAAC;IACnB,SAAS,CAAC,EAAE,gBAAgB,CAAC;IAC7B,sEAAsE;IACtE,UAAU,CAAC,EAAE,UAAU,CAAC;CAC3B;AAED;;;GAGG;AACH,MAAM,WAAW,aAAa;IAC1B,KAAK,IAAI,IAAI,CAAC;CACjB;AAID,uCAAuC;AACvC,MAAM,MAAM,qBAAqB,GAAG,QAAQ,GAAG,QAAQ,GAAG,OAAO,GAAG,UAAU,CAAC;AAI/E;;;;GAIG;AACH,MAAM,WAAW,kBAAkB,CAAC,UAAU,GAAG,OAAO,EAAE,OAAO,SAAS,QAAQ,GAAG,WAAW;IAC5F,kEAAkE;IAClE,QAAQ,CAAC,MAAM,EAAE,0BAA0B,CAAC;IAC5C,0DAA0D;IAC1D,QAAQ,CAAC,SAAS,EAAE,UAAU,CAAC;IAC/B,yBAAyB;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,6BAA6B;IAC7B,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC;IACnC,oCAAoC;IACpC,QAAQ,CAAC,YAAY,CAAC,EAAE,QAAQ,CAAC,kBAAkB,CAAC,CAAC;IACrD,8CAA8C;IAC9C,QAAQ,CAAC,EAAE,CAAC,EAAE,aAAa,CAAC;IAC5B,wCAAwC;IACxC,QAAQ,CAAC,SAAS,CAAC,EAAE,gBAAgB,CAAC;IACtC,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;IAChC,mEAAmE;IACnE,IAAI,CAAC,MAAM,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACvD;AAID;;GAEG;AACH,MAAM,WAAW,2BAA2B,CAAC,UAAU,GAAG,OAAO,EAAE,OAAO,SAAS,QAAQ,GAAG,WAAW;IACrG,uEAAuE;IACvE,QAAQ,CAAC,MAAM,CAAC,EAAE;QACd,OAAO,CAAC,EAAE,cAAc,CAAC;QACzB,MAAM,CAAC,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC;QAChC,SAAS,CAAC,EAAE,gBAAgB,CAAC;QAC7B,SAAS,CAAC,EAAE,gBAAgB,CAAC;KAChC,CAAC;IACF,qEAAqE;IACrE,QAAQ,CAAC,SAAS,CAAC,EAAE,UAAU,CAAC;IAChC,iEAAiE;IACjE,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC,mBAAmB,CAAC,OAAO,CAAC,CAAC,CAAC;IAC1D,+DAA+D;IAC/D,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,6EAA6E;IAC7E,QAAQ,CAAC,KAAK,EAAE,CAAC,GAAG,EAAE,kBAAkB,CAAC,UAAU,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IACvF,wDAAwD;IACxD,QAAQ,CAAC,IAAI,CAAC,EAAE,CACZ,GAAG,EAAE,kBAAkB,CAAC,UAAU,EAAE,OAAO,CAAC,EAC5C,MAAM,EAAE,qBAAqB,KAC5B,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CAC7B;AAID;;;GAGG;AACH,MAAM,WAAW,sBAAsB,CAAC,CAAC;IACrC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAClB,QAAQ,CAAC,MAAM,CAAC,EAAE,aAAa,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACtE;AAED;;;GAGG;AACH,MAAM,MAAM,0BAA0B,CAAC,UAAU,IAC3C;IAAE,SAAS,CAAC,GAAG,EAAE,OAAO,GAAG,sBAAsB,CAAC,UAAU,CAAC,CAAA;CAAE,GAC/D,CAAC,CAAC,GAAG,EAAE,OAAO,KAAK,UAAU,CAAC,GAC9B;IAAE,QAAQ,CAAC,GAAG,EAAE,OAAO,GAAG,UAAU,CAAA;CAAE,GACtC;IAAE,KAAK,CAAC,GAAG,EAAE,OAAO,GAAG,UAAU,CAAA;CAAE,CAAC;AAE1C;;GAEG;AACH,MAAM,WAAW,uBAAuB,CAAC,UAAU,GAAG,OAAO;IACzD,oCAAoC;IACpC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,qEAAqE;IACrE,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IACnC,4EAA4E;IAC5E,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,4DAA4D;IAC5D,QAAQ,CAAC,SAAS,CAAC,EAAE,0BAA0B,CAAC,UAAU,CAAC,CAAC;IAC5D,4CAA4C;IAC5C,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChD;AAGD,YAAY,EAAE,kBAAkB,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AACvE,YAAY,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"application-node.d.ts","sourceRoot":"","sources":["../src/application-node.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AASH,OAAO,KAAK,EACR,2BAA2B,EAC3B,uBAAuB,EAEvB,kBAAkB,EAClB,qBAAqB,EAGrB,QAAQ,EACR,WAAW,EAId,MAAM,qBAAqB,CAAC;AAM7B,kGAAkG;AAClG,qBAAa,qBAAsB,SAAQ,KAAK;gBAChC,OAAO,EAAE,MAAM;CAI9B;AAgHD,uEAAuE;AACvE,MAAM,WAAW,sBAAsB,CAAC,UAAU,GAAG,OAAO,EAAE,OAAO,SAAS,QAAQ,GAAG,WAAW;IAChG,gEAAgE;IAChE,QAAQ,CAAC,YAAY,CAAC,EAAE,uBAAuB,CAAC,UAAU,CAAC,CAAC;IAC5D,8DAA8D;IAC9D,QAAQ,CAAC,MAAM,CAAC,EAAE,2BAA2B,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC;IAC7E,oCAAoC;IACpC,QAAQ,CAAC,QAAQ,CAAC,EAAE,2BAA2B,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC,UAAU,CAAC,CAAC;IACjF,wCAAwC;IACxC,QAAQ,CAAC,KAAK,EAAE,CAAC,GAAG,EAAE,kBAAkB,CAAC,UAAU,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IACvF,wDAAwD;IACxD,QAAQ,CAAC,IAAI,CAAC,EAAE,CACZ,GAAG,EAAE,kBAAkB,CAAC,UAAU,EAAE,OAAO,CAAC,EAC5C,MAAM,EAAE,qBAAqB,KAC5B,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CAC7B;AAID;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAsB,kBAAkB,CAAC,UAAU,GAAG,OAAO,EAAE,OAAO,SAAS,QAAQ,GAAG,WAAW,EACjG,OAAO,EAAE,sBAAsB,CAAC,UAAU,EAAE,OAAO,CAAC,GACrD,OAAO,CAAC,kBAAkB,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC,CAkHlD"}
1
+ {"version":3,"file":"application-node.d.ts","sourceRoot":"","sources":["../src/application-node.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAWH,OAAO,KAAK,EACR,2BAA2B,EAC3B,uBAAuB,EAEvB,kBAAkB,EAClB,qBAAqB,EAGrB,QAAQ,EACR,WAAW,EAId,MAAM,qBAAqB,CAAC;AAM7B,kGAAkG;AAClG,qBAAa,qBAAsB,SAAQ,KAAK;gBAChC,OAAO,EAAE,MAAM;CAI9B;AAgHD,uEAAuE;AACvE,MAAM,WAAW,sBAAsB,CAAC,UAAU,GAAG,OAAO,EAAE,OAAO,SAAS,QAAQ,GAAG,WAAW;IAChG,gEAAgE;IAChE,QAAQ,CAAC,YAAY,CAAC,EAAE,uBAAuB,CAAC,UAAU,CAAC,CAAC;IAC5D,8DAA8D;IAC9D,QAAQ,CAAC,MAAM,CAAC,EAAE,2BAA2B,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC;IAC7E,oCAAoC;IACpC,QAAQ,CAAC,QAAQ,CAAC,EAAE,2BAA2B,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC,UAAU,CAAC,CAAC;IACjF,wCAAwC;IACxC,QAAQ,CAAC,KAAK,EAAE,CAAC,GAAG,EAAE,kBAAkB,CAAC,UAAU,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IACvF,wDAAwD;IACxD,QAAQ,CAAC,IAAI,CAAC,EAAE,CACZ,GAAG,EAAE,kBAAkB,CAAC,UAAU,EAAE,OAAO,CAAC,EAC5C,MAAM,EAAE,qBAAqB,KAC5B,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CAC7B;AAID;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAsB,kBAAkB,CAAC,UAAU,GAAG,OAAO,EAAE,OAAO,SAAS,QAAQ,GAAG,WAAW,EACjG,OAAO,EAAE,sBAAsB,CAAC,UAAU,EAAE,OAAO,CAAC,GACrD,OAAO,CAAC,kBAAkB,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC,CA8FlD"}
@@ -19,6 +19,7 @@ import { dirname } from 'node:path';
19
19
  import { createDbAdapter } from '@gobing-ai/ts-db';
20
20
  import { interpolateTree, parseYamlObject } from '@gobing-ai/ts-runtime';
21
21
  import { runApplication } from './application/index.js';
22
+ import { dbPlugin } from './application/plugins/builtins.js';
22
23
  import { NodeSchedulerAdapter } from './scheduler-node.js';
23
24
  import { initNodeTelemetry, shutdownNodeTelemetry } from './telemetry/otel-node.js';
24
25
  // ── Errors ────────────────────────────────────────────────────────────────
@@ -141,7 +142,6 @@ function loadYamlConfig(loader, fileContent) {
141
142
  * ```
142
143
  */
143
144
  export async function runNodeApplication(options) {
144
- let nodeTelemetryInitialized = false;
145
145
  // ── Load config ─────────────────────────────────────────────────────
146
146
  let loadedAppConfig;
147
147
  let yamlBootstrap = {};
@@ -157,39 +157,47 @@ export async function runNodeApplication(options) {
157
157
  loadedAppConfig = loaded.appConfig;
158
158
  }
159
159
  // ── Resolve bootstrap config from YAML + inline options ────────────
160
- // YAML loads as Record<string, unknown>; bridge into typed options.
161
- // Inline options (options.config) take precedence over YAML sections.
162
160
  const yamlLog = yamlBootstrap.logging;
163
161
  const yamlTel = yamlBootstrap.telemetry;
164
162
  const yamlSched = yamlBootstrap.scheduler;
165
163
  const databaseOpts = (yamlBootstrap.database ?? {});
166
- const loggingOpts = {
167
- ...yamlLog,
168
- ...options.config?.logging,
169
- };
170
- const telemetryOpts = {
171
- ...yamlTel,
172
- ...options.config?.telemetry,
173
- };
174
- const schedulerOpts = {
175
- ...yamlSched,
176
- ...options.config?.scheduler,
177
- };
178
- // File sink from logging.filePath
164
+ const loggingOpts = { ...yamlLog, ...options.config?.logging };
165
+ const telemetryOpts = { ...yamlTel, ...options.config?.telemetry };
166
+ const schedulerOpts = { ...yamlSched, ...options.config?.scheduler };
179
167
  const logFilePath = yamlBootstrap.logging?.filePath;
180
168
  const loggingConfig = typeof logFilePath === 'string' ? { ...loggingOpts, fileSink: createFileSink(logFilePath) } : loggingOpts;
181
- // ── Node OTel telemetry ─────────────────────────────────────────────
169
+ // ── Scheduler adapter ───────────────────────────────────────────────
170
+ const schedulerConfig = {};
171
+ const rawSched = { ...schedulerOpts };
172
+ if (rawSched.enabled === true) {
173
+ schedulerConfig.enabled = true;
174
+ schedulerConfig.autoStart = schedulerOpts.autoStart;
175
+ schedulerConfig.adapter = new NodeSchedulerAdapter();
176
+ }
177
+ // ── Node-owned plugins ──────────────────────────────────────────────
178
+ const plugins = [];
179
+ let dbAdapter = options.services?.db;
182
180
  const rawTel = { ...telemetryOpts };
181
+ // Node OTel telemetry as a failFast plugin
183
182
  if (rawTel.enabled !== false && rawTel.endpoint) {
184
- initNodeTelemetry({
185
- serviceName: rawTel.serviceName ?? 'ts-libs',
186
- endpoint: rawTel.endpoint,
187
- headers: rawTel.headers,
183
+ plugins.push({
184
+ name: 'builtin:node-telemetry',
185
+ version: '0.0.0',
186
+ failFast: true,
187
+ onLoad: async () => { },
188
+ onStart: async () => {
189
+ initNodeTelemetry({
190
+ serviceName: rawTel.serviceName ?? 'ts-libs',
191
+ endpoint: rawTel.endpoint,
192
+ headers: rawTel.headers,
193
+ });
194
+ },
195
+ onStop: async () => {
196
+ await shutdownNodeTelemetry();
197
+ },
188
198
  });
189
- nodeTelemetryInitialized = true;
190
199
  }
191
- // ── DB adapter ──────────────────────────────────────────────────────
192
- let dbAdapter = options.services?.db;
200
+ // DB adapter (owned — registered as a plugin with fail-soft close)
193
201
  if (!dbAdapter && databaseOpts.enabled === true) {
194
202
  const driver = databaseOpts.driver;
195
203
  if (driver === 'bun-sqlite') {
@@ -198,48 +206,23 @@ export async function runNodeApplication(options) {
198
206
  url: databaseOpts.url,
199
207
  });
200
208
  dbAdapter = adapter;
209
+ plugins.push(dbPlugin(dbAdapter));
201
210
  }
202
211
  else {
203
212
  throw new ConfigValidationError(`database.enabled is true but driver ${driver ? `"${driver}"` : 'is missing'} is not supported ` +
204
213
  `(expected "bun-sqlite"). Provide a supported driver or inject a DbAdapter via services.db.`);
205
214
  }
206
215
  }
207
- // ── Scheduler adapter ───────────────────────────────────────────────
208
- const schedulerConfig = {};
209
- const rawSched = { ...schedulerOpts };
210
- if (rawSched.enabled === true) {
211
- schedulerConfig.enabled = true;
212
- schedulerConfig.autoStart = schedulerOpts.autoStart;
213
- // Use Node scheduler adapter by default in this subpath
214
- schedulerConfig.adapter = new NodeSchedulerAdapter();
215
- }
216
216
  // ── Delegate to portable runApplication ─────────────────────────────
217
- const app = await runApplication({
218
- config: {
219
- ...options.config,
220
- logging: loggingConfig,
221
- telemetry: telemetryOpts,
222
- scheduler: schedulerConfig,
223
- },
217
+ // Node-specific cleanup is handled by plugins in the service ring —
218
+ // node-telemetry onStop, owned-db onStop. No manual try/catch or stop
219
+ // override needed.
220
+ return await runApplication({
221
+ config: { ...options.config, logging: loggingConfig, telemetry: telemetryOpts, scheduler: schedulerConfig },
224
222
  appConfig: loadedAppConfig,
225
- services: {
226
- ...options.services,
227
- ...(dbAdapter ? { db: dbAdapter } : {}),
228
- },
223
+ services: { ...options.services, ...(dbAdapter ? { db: dbAdapter } : {}) },
229
224
  start: options.start,
230
225
  stop: options.stop,
226
+ plugins: plugins.length ? plugins : undefined,
231
227
  });
232
- // ── Compose a handle with Node-specific cleanup on stop ─────────────
233
- const originalStop = app.stop.bind(app);
234
- return {
235
- ...app,
236
- stop: async (reason) => {
237
- await originalStop(reason);
238
- // Node-specific cleanup (after portable shutdown):
239
- // 5. Shut down Node telemetry exporter
240
- if (nodeTelemetryInitialized) {
241
- await shutdownNodeTelemetry();
242
- }
243
- },
244
- };
245
228
  }