@gobing-ai/ts-infra 0.3.4 → 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 (65) hide show
  1. package/README.md +196 -48
  2. package/dist/application/index.d.ts +55 -0
  3. package/dist/application/index.d.ts.map +1 -0
  4. package/dist/application/index.js +173 -0
  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 +195 -0
  18. package/dist/application/types.d.ts.map +1 -0
  19. package/dist/application/types.js +9 -0
  20. package/dist/application-node.d.ts +68 -0
  21. package/dist/application-node.d.ts.map +1 -0
  22. package/dist/application-node.js +228 -0
  23. package/dist/index.d.ts +1 -1
  24. package/dist/index.d.ts.map +1 -1
  25. package/dist/index.js +1 -1
  26. package/dist/scheduler/cloudflare.d.ts.map +1 -1
  27. package/dist/scheduler/cloudflare.js +9 -2
  28. package/dist/scheduler/factory.d.ts +4 -8
  29. package/dist/scheduler/factory.d.ts.map +1 -1
  30. package/dist/scheduler/factory.js +12 -22
  31. package/dist/scheduler/index.d.ts +1 -1
  32. package/dist/scheduler/index.d.ts.map +1 -1
  33. package/dist/scheduler/index.js +1 -1
  34. package/dist/scheduler/wrap-handler.d.ts +8 -4
  35. package/dist/scheduler/wrap-handler.d.ts.map +1 -1
  36. package/dist/scheduler/wrap-handler.js +8 -4
  37. package/dist/telemetry/index.d.ts +1 -2
  38. package/dist/telemetry/index.d.ts.map +1 -1
  39. package/dist/telemetry/index.js +1 -2
  40. package/dist/telemetry/metrics.d.ts +9 -1
  41. package/dist/telemetry/metrics.d.ts.map +1 -1
  42. package/dist/telemetry/metrics.js +22 -1
  43. package/dist/telemetry/sdk.d.ts +33 -1
  44. package/dist/telemetry/sdk.d.ts.map +1 -1
  45. package/dist/telemetry/sdk.js +14 -1
  46. package/package.json +16 -3
  47. package/src/application/index.ts +248 -0
  48. package/src/application/plugins/builtins.ts +178 -0
  49. package/src/application/plugins/host.ts +143 -0
  50. package/src/application/plugins/index.ts +3 -0
  51. package/src/application/plugins/types.ts +86 -0
  52. package/src/application/types.ts +210 -0
  53. package/src/application-node.ts +311 -0
  54. package/src/index.ts +0 -2
  55. package/src/scheduler/cloudflare.ts +16 -5
  56. package/src/scheduler/factory.ts +15 -26
  57. package/src/scheduler/index.ts +1 -1
  58. package/src/scheduler/wrap-handler.ts +8 -4
  59. package/src/telemetry/index.ts +9 -2
  60. package/src/telemetry/metrics.ts +22 -1
  61. package/src/telemetry/sdk.ts +51 -2
  62. package/dist/telemetry/config.d.ts +0 -41
  63. package/dist/telemetry/config.d.ts.map +0 -1
  64. package/dist/telemetry/config.js +0 -21
  65. package/src/telemetry/config.ts +0 -59
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Node/Bun convenience bootstrap for `@gobing-ai/ts-infra`.
3
+ *
4
+ * Composes the portable `runApplication` with runtime-specific wiring:
5
+ * - YAML config loading via `@gobing-ai/ts-runtime`
6
+ * - Application-specific config validation with caller-provided validator
7
+ * - File log sink via `node:fs`
8
+ * - Bun SQLite DB adapter creation from config
9
+ * - Optional Node OTel exporter initialization
10
+ * - Optional Node scheduler adapter
11
+ *
12
+ * This subpath may import runtime-specific adapters. The portable bootstrap
13
+ * subpath (`@gobing-ai/ts-infra/application`) must not.
14
+ *
15
+ * @module application-node
16
+ */
17
+ import type { ApplicationBootstrapOptions, ApplicationConfigLoader, ApplicationRuntime, ApplicationStopReason, EventMap, InfraEvents } from './application/types';
18
+ /** Error thrown when application config validation fails. Includes file path and section name. */
19
+ export declare class ConfigValidationError extends Error {
20
+ constructor(message: string);
21
+ }
22
+ /** Options for the Node/Bun convenience {@link runNodeApplication}. */
23
+ export interface NodeApplicationOptions<TAppConfig = unknown, TEvents extends EventMap = InfraEvents> {
24
+ /** YAML config loading options. When omitted, uses defaults. */
25
+ readonly configLoader?: ApplicationConfigLoader<TAppConfig>;
26
+ /** Inline bootstrap config (overrides YAML-loaded config). */
27
+ readonly config?: ApplicationBootstrapOptions<TAppConfig, TEvents>['config'];
28
+ /** Pre-built services to inject. */
29
+ readonly services?: ApplicationBootstrapOptions<TAppConfig, TEvents>['services'];
30
+ /** User callback: application logic. */
31
+ readonly start: (app: ApplicationRuntime<TAppConfig, TEvents>) => Promise<void> | void;
32
+ /** User callback: cleanup before services shut down. */
33
+ readonly stop?: (app: ApplicationRuntime<TAppConfig, TEvents>, reason: ApplicationStopReason) => Promise<void> | void;
34
+ }
35
+ /**
36
+ * Node/Bun convenience application bootstrap.
37
+ *
38
+ * Extends the portable `runApplication` with:
39
+ * - YAML config file loading with section splitting
40
+ * - Application-specific config validation
41
+ * - File log sink creation from `logging.filePath`
42
+ * - Bun SQLite DB adapter creation when `database.enabled` + `database.driver`
43
+ * - Optional Node OTel telemetry exporter
44
+ * - Optional Node scheduler adapter
45
+ *
46
+ * @example
47
+ * ```ts
48
+ * import { runNodeApplication } from '@gobing-ai/ts-infra/application-node';
49
+ *
50
+ * await runNodeApplication({
51
+ * configLoader: {
52
+ * configFile: 'config/app.yaml',
53
+ * bootstrapSection: 'bootstrap',
54
+ * appSection: 'billing',
55
+ * appConfig: {
56
+ * safeParse(raw) {
57
+ * return billingSchema.safeParse(raw);
58
+ * },
59
+ * },
60
+ * },
61
+ * async start(app) {
62
+ * app.logger.info('started');
63
+ * },
64
+ * });
65
+ * ```
66
+ */
67
+ export declare function runNodeApplication<TAppConfig = unknown, TEvents extends EventMap = InfraEvents>(options: NodeApplicationOptions<TAppConfig, TEvents>): Promise<ApplicationRuntime<TAppConfig, TEvents>>;
68
+ //# sourceMappingURL=application-node.d.ts.map
@@ -0,0 +1 @@
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"}
@@ -0,0 +1,228 @@
1
+ /**
2
+ * Node/Bun convenience bootstrap for `@gobing-ai/ts-infra`.
3
+ *
4
+ * Composes the portable `runApplication` with runtime-specific wiring:
5
+ * - YAML config loading via `@gobing-ai/ts-runtime`
6
+ * - Application-specific config validation with caller-provided validator
7
+ * - File log sink via `node:fs`
8
+ * - Bun SQLite DB adapter creation from config
9
+ * - Optional Node OTel exporter initialization
10
+ * - Optional Node scheduler adapter
11
+ *
12
+ * This subpath may import runtime-specific adapters. The portable bootstrap
13
+ * subpath (`@gobing-ai/ts-infra/application`) must not.
14
+ *
15
+ * @module application-node
16
+ */
17
+ import { appendFileSync, mkdirSync, readFileSync } from 'node:fs';
18
+ import { dirname } from 'node:path';
19
+ import { createDbAdapter } from '@gobing-ai/ts-db';
20
+ import { interpolateTree, parseYamlObject } from '@gobing-ai/ts-runtime';
21
+ import { runApplication } from './application/index.js';
22
+ import { dbPlugin } from './application/plugins/builtins.js';
23
+ import { NodeSchedulerAdapter } from './scheduler-node.js';
24
+ import { initNodeTelemetry, shutdownNodeTelemetry } from './telemetry/otel-node.js';
25
+ // ── Errors ────────────────────────────────────────────────────────────────
26
+ /** Error thrown when application config validation fails. Includes file path and section name. */
27
+ export class ConfigValidationError extends Error {
28
+ constructor(message) {
29
+ super(message);
30
+ this.name = 'ConfigValidationError';
31
+ }
32
+ }
33
+ // ── Config validation helper ──────────────────────────────────────────────
34
+ /**
35
+ * Validate a raw config section using the caller-provided validator.
36
+ * Supports structural `safeParse`, `validate()`, `parse()`, and bare function forms.
37
+ */
38
+ function validateAppConfig(validator, raw, section, filePath) {
39
+ if (typeof validator === 'object' && 'safeParse' in validator) {
40
+ const result = validator.safeParse(raw);
41
+ if (!result.success) {
42
+ const details = result.errors?.map((e) => `${e.path}: ${e.message}`).join('; ') ?? 'unknown error';
43
+ throw new ConfigValidationError(`Application config validation failed in section "${section}"` +
44
+ (filePath ? ` (file: ${filePath})` : '') +
45
+ `: ${details}`);
46
+ }
47
+ return result.data;
48
+ }
49
+ if (typeof validator === 'function') {
50
+ return validator(raw);
51
+ }
52
+ if (typeof validator === 'object' && 'validate' in validator) {
53
+ return validator.validate(raw);
54
+ }
55
+ if (typeof validator === 'object' && 'parse' in validator) {
56
+ return validator.parse(raw);
57
+ }
58
+ throw new ConfigValidationError(`Unsupported validator shape for section "${section}"`);
59
+ }
60
+ // ── File sink helper ──────────────────────────────────────────────────────
61
+ function createFileSink(filePath) {
62
+ return (line) => {
63
+ try {
64
+ mkdirSync(dirname(filePath), { recursive: true });
65
+ appendFileSync(filePath, line);
66
+ }
67
+ catch {
68
+ // Best-effort — don't crash on log write failure
69
+ }
70
+ };
71
+ }
72
+ function loadYamlConfig(loader, fileContent) {
73
+ const bootstrapSection = loader.bootstrapSection ?? 'bootstrap';
74
+ let raw;
75
+ if (fileContent !== undefined) {
76
+ raw = parseYamlObject(fileContent);
77
+ }
78
+ else if (loader.overrides) {
79
+ raw = { ...loader.overrides };
80
+ }
81
+ else {
82
+ raw = {};
83
+ }
84
+ // Interpolate environment variables (Node/Bun only)
85
+ raw = interpolateTree(raw);
86
+ // Extract bootstrap section
87
+ const bootstrapSection_ = raw[bootstrapSection];
88
+ const bootstrapConfig = typeof bootstrapSection_ === 'object' && bootstrapSection_ !== null
89
+ ? bootstrapSection_
90
+ : {};
91
+ // Extract app config section
92
+ let appConfig;
93
+ if (loader.appConfig) {
94
+ const appSection = loader.appSection;
95
+ const appRaw = appSection
96
+ ? raw[appSection]
97
+ : (() => {
98
+ // Default: full remaining object minus bootstrap section
99
+ const remaining = {};
100
+ for (const [key, value] of Object.entries(raw)) {
101
+ if (key !== bootstrapSection) {
102
+ remaining[key] = value;
103
+ }
104
+ }
105
+ return remaining;
106
+ })();
107
+ appConfig = validateAppConfig(loader.appConfig, appRaw, appSection ?? '*', loader.configFile);
108
+ }
109
+ return { bootstrapConfig, appConfig };
110
+ }
111
+ // ── Public API ────────────────────────────────────────────────────────────
112
+ /**
113
+ * Node/Bun convenience application bootstrap.
114
+ *
115
+ * Extends the portable `runApplication` with:
116
+ * - YAML config file loading with section splitting
117
+ * - Application-specific config validation
118
+ * - File log sink creation from `logging.filePath`
119
+ * - Bun SQLite DB adapter creation when `database.enabled` + `database.driver`
120
+ * - Optional Node OTel telemetry exporter
121
+ * - Optional Node scheduler adapter
122
+ *
123
+ * @example
124
+ * ```ts
125
+ * import { runNodeApplication } from '@gobing-ai/ts-infra/application-node';
126
+ *
127
+ * await runNodeApplication({
128
+ * configLoader: {
129
+ * configFile: 'config/app.yaml',
130
+ * bootstrapSection: 'bootstrap',
131
+ * appSection: 'billing',
132
+ * appConfig: {
133
+ * safeParse(raw) {
134
+ * return billingSchema.safeParse(raw);
135
+ * },
136
+ * },
137
+ * },
138
+ * async start(app) {
139
+ * app.logger.info('started');
140
+ * },
141
+ * });
142
+ * ```
143
+ */
144
+ export async function runNodeApplication(options) {
145
+ // ── Load config ─────────────────────────────────────────────────────
146
+ let loadedAppConfig;
147
+ let yamlBootstrap = {};
148
+ if (options.configLoader?.configFile) {
149
+ const fileContent = readFileSync(options.configLoader.configFile, 'utf-8');
150
+ const loaded = loadYamlConfig(options.configLoader, fileContent);
151
+ yamlBootstrap = loaded.bootstrapConfig;
152
+ loadedAppConfig = loaded.appConfig;
153
+ }
154
+ else if (options.configLoader) {
155
+ const loaded = loadYamlConfig(options.configLoader, undefined);
156
+ yamlBootstrap = loaded.bootstrapConfig;
157
+ loadedAppConfig = loaded.appConfig;
158
+ }
159
+ // ── Resolve bootstrap config from YAML + inline options ────────────
160
+ const yamlLog = yamlBootstrap.logging;
161
+ const yamlTel = yamlBootstrap.telemetry;
162
+ const yamlSched = yamlBootstrap.scheduler;
163
+ const databaseOpts = (yamlBootstrap.database ?? {});
164
+ const loggingOpts = { ...yamlLog, ...options.config?.logging };
165
+ const telemetryOpts = { ...yamlTel, ...options.config?.telemetry };
166
+ const schedulerOpts = { ...yamlSched, ...options.config?.scheduler };
167
+ const logFilePath = yamlBootstrap.logging?.filePath;
168
+ const loggingConfig = typeof logFilePath === 'string' ? { ...loggingOpts, fileSink: createFileSink(logFilePath) } : loggingOpts;
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;
180
+ const rawTel = { ...telemetryOpts };
181
+ // Node OTel telemetry as a failFast plugin
182
+ if (rawTel.enabled !== false && rawTel.endpoint) {
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
+ },
198
+ });
199
+ }
200
+ // DB adapter (owned — registered as a plugin with fail-soft close)
201
+ if (!dbAdapter && databaseOpts.enabled === true) {
202
+ const driver = databaseOpts.driver;
203
+ if (driver === 'bun-sqlite') {
204
+ const adapter = await createDbAdapter({
205
+ driver: 'bun-sqlite',
206
+ url: databaseOpts.url,
207
+ });
208
+ dbAdapter = adapter;
209
+ plugins.push(dbPlugin(dbAdapter));
210
+ }
211
+ else {
212
+ throw new ConfigValidationError(`database.enabled is true but driver ${driver ? `"${driver}"` : 'is missing'} is not supported ` +
213
+ `(expected "bun-sqlite"). Provide a supported driver or inject a DbAdapter via services.db.`);
214
+ }
215
+ }
216
+ // ── Delegate to portable runApplication ─────────────────────────────
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 },
222
+ appConfig: loadedAppConfig,
223
+ services: { ...options.services, ...(dbAdapter ? { db: dbAdapter } : {}) },
224
+ start: options.start,
225
+ stop: options.stop,
226
+ plugins: plugins.length ? plugins : undefined,
227
+ });
228
+ }
package/dist/index.d.ts CHANGED
@@ -3,6 +3,6 @@ export { attachDefaultObservers, attachFileObserver, attachLogObserver, attachTe
3
3
  export type { ApiClientEvents, ApiRequestErrorDetail, DbConnectionErrorDetail, DbEvents, InfraEvents, QueueEvents, QueueJobFailedDetail, QueueJobRetryingDetail, SchedulerEvents, SchedulerJobExecutedDetail, } from './events';
4
4
  export type { EnqueueOptions, Job, JobHandler, JobQueue, QueueConsumer, QueueConsumerConfig, QueueStats, } from './job-queue/index';
5
5
  export { getLogger, type InitLoggerOptions, initializeLogger, type Logger, type LogLevel, setLoggerMuted, } from './logger';
6
- export { ActionRegistry, type CreateDefaultRegistryOptions, createDefaultRegistry, getSchedulerAdapter, HealthPingAction, type HealthPingWriter, initScheduler, LogAction, NoopSchedulerAdapter, QueueStatsAction, type QueueStatsDaoProvider, type ScheduledAction, type SchedulerAction, type SchedulerAdapter, setSchedulerAdapter, toScheduledAction, wrapScheduledHandler, } from './scheduler/index';
6
+ export { ActionRegistry, type CreateDefaultRegistryOptions, createDefaultRegistry, HealthPingAction, type HealthPingWriter, initScheduler, LogAction, NoopSchedulerAdapter, QueueStatsAction, type QueueStatsDaoProvider, type ScheduledAction, type SchedulerAction, type SchedulerAdapter, toScheduledAction, wrapScheduledHandler, } from './scheduler/index';
7
7
  export { addSpanAttributes, addSpanEvent, extractSqlOperation, getActiveSpan, getEventbusEmitsTotal, getEventbusErrorsTotal, getHttpClientRequestDuration, getHttpClientRequestErrors, getHttpClientRequestTotal, getQueueJobCompletedTotal, getQueueJobEnqueuedTotal, getQueueJobFailedTotal, getQueueJobProcessingDuration, getSchedulerJobDuration, getSchedulerJobExecutedTotal, getSchedulerJobFailedTotal, getTelemetryConfig, getTracer, initMetrics, initTelemetry, isTelemetryEnabled, sanitizeSql, shutdownMetrics, shutdownTelemetry, type TelemetryConfig, type TelemetryConfigPartial, traceAsync, traceSync, withSpan, } from './telemetry/index';
8
8
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,KAAK,eAAe,EAAE,QAAQ,EAAE,KAAK,cAAc,EAAE,MAAM,cAAc,CAAC;AAG9F,OAAO,EACH,sBAAsB,EACtB,kBAAkB,EAClB,iBAAiB,EACjB,uBAAuB,EACvB,kBAAkB,EAClB,QAAQ,EACR,KAAK,QAAQ,EACb,KAAK,kBAAkB,EACvB,KAAK,gBAAgB,GACxB,MAAM,mBAAmB,CAAC;AAG3B,YAAY,EACR,eAAe,EACf,qBAAqB,EACrB,uBAAuB,EACvB,QAAQ,EACR,WAAW,EACX,WAAW,EACX,oBAAoB,EACpB,sBAAsB,EACtB,eAAe,EACf,0BAA0B,GAC7B,MAAM,UAAU,CAAC;AAElB,YAAY,EACR,cAAc,EACd,GAAG,EACH,UAAU,EACV,QAAQ,EACR,aAAa,EACb,mBAAmB,EACnB,UAAU,GACb,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACH,SAAS,EACT,KAAK,iBAAiB,EACtB,gBAAgB,EAChB,KAAK,MAAM,EACX,KAAK,QAAQ,EACb,cAAc,GACjB,MAAM,UAAU,CAAC;AAGlB,OAAO,EACH,cAAc,EACd,KAAK,4BAA4B,EACjC,qBAAqB,EACrB,mBAAmB,EACnB,gBAAgB,EAChB,KAAK,gBAAgB,EACrB,aAAa,EACb,SAAS,EACT,oBAAoB,EACpB,gBAAgB,EAChB,KAAK,qBAAqB,EAC1B,KAAK,eAAe,EACpB,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACrB,mBAAmB,EACnB,iBAAiB,EACjB,oBAAoB,GACvB,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EACH,iBAAiB,EACjB,YAAY,EACZ,mBAAmB,EACnB,aAAa,EACb,qBAAqB,EACrB,sBAAsB,EACtB,4BAA4B,EAC5B,0BAA0B,EAC1B,yBAAyB,EACzB,yBAAyB,EACzB,wBAAwB,EACxB,sBAAsB,EACtB,6BAA6B,EAC7B,uBAAuB,EACvB,4BAA4B,EAC5B,0BAA0B,EAC1B,kBAAkB,EAClB,SAAS,EACT,WAAW,EACX,aAAa,EACb,kBAAkB,EAClB,WAAW,EACX,eAAe,EACf,iBAAiB,EACjB,KAAK,eAAe,EACpB,KAAK,sBAAsB,EAC3B,UAAU,EACV,SAAS,EACT,QAAQ,GACX,MAAM,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,KAAK,eAAe,EAAE,QAAQ,EAAE,KAAK,cAAc,EAAE,MAAM,cAAc,CAAC;AAG9F,OAAO,EACH,sBAAsB,EACtB,kBAAkB,EAClB,iBAAiB,EACjB,uBAAuB,EACvB,kBAAkB,EAClB,QAAQ,EACR,KAAK,QAAQ,EACb,KAAK,kBAAkB,EACvB,KAAK,gBAAgB,GACxB,MAAM,mBAAmB,CAAC;AAG3B,YAAY,EACR,eAAe,EACf,qBAAqB,EACrB,uBAAuB,EACvB,QAAQ,EACR,WAAW,EACX,WAAW,EACX,oBAAoB,EACpB,sBAAsB,EACtB,eAAe,EACf,0BAA0B,GAC7B,MAAM,UAAU,CAAC;AAElB,YAAY,EACR,cAAc,EACd,GAAG,EACH,UAAU,EACV,QAAQ,EACR,aAAa,EACb,mBAAmB,EACnB,UAAU,GACb,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACH,SAAS,EACT,KAAK,iBAAiB,EACtB,gBAAgB,EAChB,KAAK,MAAM,EACX,KAAK,QAAQ,EACb,cAAc,GACjB,MAAM,UAAU,CAAC;AAGlB,OAAO,EACH,cAAc,EACd,KAAK,4BAA4B,EACjC,qBAAqB,EACrB,gBAAgB,EAChB,KAAK,gBAAgB,EACrB,aAAa,EACb,SAAS,EACT,oBAAoB,EACpB,gBAAgB,EAChB,KAAK,qBAAqB,EAC1B,KAAK,eAAe,EACpB,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACrB,iBAAiB,EACjB,oBAAoB,GACvB,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EACH,iBAAiB,EACjB,YAAY,EACZ,mBAAmB,EACnB,aAAa,EACb,qBAAqB,EACrB,sBAAsB,EACtB,4BAA4B,EAC5B,0BAA0B,EAC1B,yBAAyB,EACzB,yBAAyB,EACzB,wBAAwB,EACxB,sBAAsB,EACtB,6BAA6B,EAC7B,uBAAuB,EACvB,4BAA4B,EAC5B,0BAA0B,EAC1B,kBAAkB,EAClB,SAAS,EACT,WAAW,EACX,aAAa,EACb,kBAAkB,EAClB,WAAW,EACX,eAAe,EACf,iBAAiB,EACjB,KAAK,eAAe,EACpB,KAAK,sBAAsB,EAC3B,UAAU,EACV,SAAS,EACT,QAAQ,GACX,MAAM,mBAAmB,CAAC"}
package/dist/index.js CHANGED
@@ -5,6 +5,6 @@ export { attachDefaultObservers, attachFileObserver, attachLogObserver, attachTe
5
5
  // Logger
6
6
  export { getLogger, initializeLogger, setLoggerMuted, } from './logger.js';
7
7
  // Scheduler
8
- export { ActionRegistry, createDefaultRegistry, getSchedulerAdapter, HealthPingAction, initScheduler, LogAction, NoopSchedulerAdapter, QueueStatsAction, setSchedulerAdapter, toScheduledAction, wrapScheduledHandler, } from './scheduler/index.js';
8
+ export { ActionRegistry, createDefaultRegistry, HealthPingAction, initScheduler, LogAction, NoopSchedulerAdapter, QueueStatsAction, toScheduledAction, wrapScheduledHandler, } from './scheduler/index.js';
9
9
  // Telemetry
10
10
  export { addSpanAttributes, addSpanEvent, extractSqlOperation, getActiveSpan, getEventbusEmitsTotal, getEventbusErrorsTotal, getHttpClientRequestDuration, getHttpClientRequestErrors, getHttpClientRequestTotal, getQueueJobCompletedTotal, getQueueJobEnqueuedTotal, getQueueJobFailedTotal, getQueueJobProcessingDuration, getSchedulerJobDuration, getSchedulerJobExecutedTotal, getSchedulerJobFailedTotal, getTelemetryConfig, getTracer, initMetrics, initTelemetry, isTelemetryEnabled, sanitizeSql, shutdownMetrics, shutdownTelemetry, traceAsync, traceSync, withSpan, } from './telemetry/index.js';
@@ -1 +1 @@
1
- {"version":3,"file":"cloudflare.d.ts","sourceRoot":"","sources":["../../src/scheduler/cloudflare.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAEjE,UAAU,gBAAgB;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC;CAC9C;AAED,UAAU,cAAc;IACpB,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC;CAC9C;AAED;;;;;GAKG;AACH,qBAAa,0BAA2B,YAAW,gBAAgB;IAC/D,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAsC;;IAI9D,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe,GAAG,IAAI;IAI/C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAKtB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAI3B;;;OAGG;IACH,oBAAoB,CAAC,KAAK,EAAE,gBAAgB,EAAE,GAAG,EAAE,cAAc,GAAG,IAAI;CAY3E"}
1
+ {"version":3,"file":"cloudflare.d.ts","sourceRoot":"","sources":["../../src/scheduler/cloudflare.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAEjE,UAAU,gBAAgB;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC;CAC9C;AAED,UAAU,cAAc;IACpB,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC;CAC9C;AAED;;;;;GAKG;AACH,qBAAa,0BAA2B,YAAW,gBAAgB;IAC/D,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAsC;;IAI9D,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe,GAAG,IAAI;IAI/C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAKtB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAI3B;;;OAGG;IACH,oBAAoB,CAAC,KAAK,EAAE,gBAAgB,EAAE,GAAG,EAAE,cAAc,GAAG,IAAI;CAmB3E"}
@@ -2,7 +2,7 @@
2
2
  * Cloudflare Workers scheduler adapter using Cron Triggers.
3
3
  * Uses minimal local type declarations — no @cloudflare/workers-types dependency.
4
4
  */
5
- import { getSchedulerJobExecutedTotal, getSchedulerJobFailedTotal } from '../telemetry/metrics.js';
5
+ import { getSchedulerJobDuration, getSchedulerJobExecutedTotal, getSchedulerJobFailedTotal, } from '../telemetry/metrics.js';
6
6
  /**
7
7
  * Scheduler adapter for Cloudflare Workers Cron Triggers.
8
8
  *
@@ -29,10 +29,17 @@ export class CloudflareSchedulerAdapter {
29
29
  handleScheduledEvent(event, ctx) {
30
30
  const action = this.entries.get(event.cron);
31
31
  if (action) {
32
+ const startMs = performance.now();
32
33
  getSchedulerJobExecutedTotal().add(1, { cron: event.cron });
33
- ctx.waitUntil(action().catch((error) => {
34
+ ctx.waitUntil(action()
35
+ .catch((error) => {
34
36
  getSchedulerJobFailedTotal().add(1, { cron: event.cron });
35
37
  throw error;
38
+ })
39
+ .finally(() => {
40
+ // Duration parity with NodeSchedulerAdapter — record the job
41
+ // duration metric keyed by cron for both runtimes.
42
+ getSchedulerJobDuration().record(performance.now() - startMs, { cron: event.cron });
36
43
  }));
37
44
  }
38
45
  }
@@ -1,10 +1,4 @@
1
1
  import type { ScheduledAction, SchedulerAdapter } from './types';
2
- /** Set the runtime scheduler adapter. Call before {@link initScheduler}. */
3
- export declare function setSchedulerAdapter(adapter: SchedulerAdapter): void;
4
- /** Reset the scheduler adapter singleton. For testing. */
5
- export declare function resetSchedulerAdapter(): void;
6
- /** Get the currently configured scheduler adapter, or `undefined` if not set. */
7
- export declare function getSchedulerAdapter(): SchedulerAdapter | undefined;
8
2
  /**
9
3
  * Initialize the scheduler adapter and register cron entries.
10
4
  *
@@ -12,7 +6,9 @@ export declare function getSchedulerAdapter(): SchedulerAdapter | undefined;
12
6
  * running, newly registered entries will NOT be started until the next
13
7
  * `start()` call.
14
8
  *
15
- * Returns the configured adapter (defaults to noop if none set).
9
+ * @param adapter - Adapter to use. Defaults to a {@link NoopSchedulerAdapter}.
10
+ * @param cronEntries - `[cron, action]` pairs to register on the adapter.
11
+ * @returns The configured adapter.
16
12
  */
17
- export declare function initScheduler(cronEntries?: Array<[string, ScheduledAction]>): SchedulerAdapter;
13
+ export declare function initScheduler(adapter?: SchedulerAdapter, cronEntries?: Array<[string, ScheduledAction]>): SchedulerAdapter;
18
14
  //# sourceMappingURL=factory.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../src/scheduler/factory.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAIjE,4EAA4E;AAC5E,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,gBAAgB,GAAG,IAAI,CAEnE;AAED,0DAA0D;AAC1D,wBAAgB,qBAAqB,IAAI,IAAI,CAE5C;AAED,iFAAiF;AACjF,wBAAgB,mBAAmB,IAAI,gBAAgB,GAAG,SAAS,CAElE;AAED;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,WAAW,CAAC,EAAE,KAAK,CAAC,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC,GAAG,gBAAgB,CAa9F"}
1
+ {"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../src/scheduler/factory.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAEjE;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CACzB,OAAO,CAAC,EAAE,gBAAgB,EAC1B,WAAW,CAAC,EAAE,KAAK,CAAC,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC,GAC/C,gBAAgB,CAUlB"}
@@ -1,20 +1,11 @@
1
1
  /**
2
- * Scheduler factory — selects adapter based on runtime.
2
+ * Scheduler factory — initializes an adapter and registers cron entries.
3
+ *
4
+ * The adapter is passed in explicitly (dependency injection); there is no
5
+ * process-global adapter state. Callers that don't supply one get a
6
+ * {@link NoopSchedulerAdapter}.
3
7
  */
4
8
  import { NoopSchedulerAdapter } from './noop.js';
5
- let runtimeAdapter;
6
- /** Set the runtime scheduler adapter. Call before {@link initScheduler}. */
7
- export function setSchedulerAdapter(adapter) {
8
- runtimeAdapter = adapter;
9
- }
10
- /** Reset the scheduler adapter singleton. For testing. */
11
- export function resetSchedulerAdapter() {
12
- runtimeAdapter = undefined;
13
- }
14
- /** Get the currently configured scheduler adapter, or `undefined` if not set. */
15
- export function getSchedulerAdapter() {
16
- return runtimeAdapter;
17
- }
18
9
  /**
19
10
  * Initialize the scheduler adapter and register cron entries.
20
11
  *
@@ -22,17 +13,16 @@ export function getSchedulerAdapter() {
22
13
  * running, newly registered entries will NOT be started until the next
23
14
  * `start()` call.
24
15
  *
25
- * Returns the configured adapter (defaults to noop if none set).
16
+ * @param adapter - Adapter to use. Defaults to a {@link NoopSchedulerAdapter}.
17
+ * @param cronEntries - `[cron, action]` pairs to register on the adapter.
18
+ * @returns The configured adapter.
26
19
  */
27
- export function initScheduler(cronEntries) {
28
- // Default: create a noop adapter. Apps inject their own via setSchedulerAdapter.
29
- if (!runtimeAdapter) {
30
- runtimeAdapter = new NoopSchedulerAdapter();
31
- }
20
+ export function initScheduler(adapter, cronEntries) {
21
+ const resolved = adapter ?? new NoopSchedulerAdapter();
32
22
  if (cronEntries) {
33
23
  for (const [cron, action] of cronEntries) {
34
- runtimeAdapter.register(cron, action);
24
+ resolved.register(cron, action);
35
25
  }
36
26
  }
37
- return runtimeAdapter;
27
+ return resolved;
38
28
  }
@@ -1,5 +1,5 @@
1
1
  export { ActionRegistry, type CreateDefaultRegistryOptions, createDefaultRegistry, HealthPingAction, type HealthPingWriter, LogAction, QueueStatsAction, type QueueStatsDaoProvider, type SchedulerAction, toScheduledAction, } from './action';
2
- export { getSchedulerAdapter, initScheduler, resetSchedulerAdapter, setSchedulerAdapter } from './factory';
2
+ export { initScheduler } from './factory';
3
3
  export { NoopSchedulerAdapter } from './noop';
4
4
  export type { ScheduledAction, SchedulerAdapter } from './types';
5
5
  export { wrapScheduledHandler } from './wrap-handler';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/scheduler/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,cAAc,EACd,KAAK,4BAA4B,EACjC,qBAAqB,EACrB,gBAAgB,EAChB,KAAK,gBAAgB,EACrB,SAAS,EACT,gBAAgB,EAChB,KAAK,qBAAqB,EAC1B,KAAK,eAAe,EACpB,iBAAiB,GACpB,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,mBAAmB,EAAE,aAAa,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAC3G,OAAO,EAAE,oBAAoB,EAAE,MAAM,QAAQ,CAAC;AAC9C,YAAY,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AACjE,OAAO,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/scheduler/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,cAAc,EACd,KAAK,4BAA4B,EACjC,qBAAqB,EACrB,gBAAgB,EAChB,KAAK,gBAAgB,EACrB,SAAS,EACT,gBAAgB,EAChB,KAAK,qBAAqB,EAC1B,KAAK,eAAe,EACpB,iBAAiB,GACpB,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,oBAAoB,EAAE,MAAM,QAAQ,CAAC;AAC9C,YAAY,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AACjE,OAAO,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC"}
@@ -1,4 +1,4 @@
1
1
  export { ActionRegistry, createDefaultRegistry, HealthPingAction, LogAction, QueueStatsAction, toScheduledAction, } from './action.js';
2
- export { getSchedulerAdapter, initScheduler, resetSchedulerAdapter, setSchedulerAdapter } from './factory.js';
2
+ export { initScheduler } from './factory.js';
3
3
  export { NoopSchedulerAdapter } from './noop.js';
4
4
  export { wrapScheduledHandler } from './wrap-handler.js';
@@ -5,10 +5,14 @@ import type { ScheduledAction } from './types';
5
5
  * Wrap a scheduled action with OTel tracing, duration measurement, and
6
6
  * `scheduler.job.executed` event emission.
7
7
  *
8
- * Composes *on top of* the adapter's inline metrics (executed/failed/duration
9
- * counters live in the Node/Cloudflare adapters) — this wrapper adds the named
10
- * tracing span and the lifecycle event, neither of which the adapters provide.
11
- * Opt-in: wrap an action before registering it when you want that visibility.
8
+ * Observability is split by design across two axes, not duplicated:
9
+ * - The adapters (`NodeSchedulerAdapter`, `CloudflareSchedulerAdapter`) record
10
+ * executed/failed/duration **metrics keyed by `cron`** for aggregate dashboards.
11
+ * - This opt-in wrapper adds a named **tracing span + lifecycle event keyed by
12
+ * the human `name`**, for per-job diagnosis. Its timer measures the inner action
13
+ * scope; the adapter's measures the full tick — nested, not double-counted.
14
+ *
15
+ * Wrap an action before registering it when you want the named span/event.
12
16
  *
13
17
  * @param name - Job name, surfaced as `scheduler.job_name` on the span/event.
14
18
  * @param action - The action to wrap (new no-arg `ScheduledAction` signature).
@@ -1 +1 @@
1
- {"version":3,"file":"wrap-handler.d.ts","sourceRoot":"","sources":["../../src/scheduler/wrap-handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAEjD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE/C;;;;;;;;;;;;GAYG;AACH,wBAAgB,oBAAoB,CAChC,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,eAAe,EACvB,SAAS,CAAC,EAAE,QAAQ,CAAC,eAAe,CAAC,GAAG,IAAI,GAC7C,eAAe,CA2BjB"}
1
+ {"version":3,"file":"wrap-handler.d.ts","sourceRoot":"","sources":["../../src/scheduler/wrap-handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAEjD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE/C;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,oBAAoB,CAChC,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,eAAe,EACvB,SAAS,CAAC,EAAE,QAAQ,CAAC,eAAe,CAAC,GAAG,IAAI,GAC7C,eAAe,CA2BjB"}
@@ -3,10 +3,14 @@ import { addSpanAttributes, addSpanEvent, traceAsync } from '../telemetry/tracin
3
3
  * Wrap a scheduled action with OTel tracing, duration measurement, and
4
4
  * `scheduler.job.executed` event emission.
5
5
  *
6
- * Composes *on top of* the adapter's inline metrics (executed/failed/duration
7
- * counters live in the Node/Cloudflare adapters) — this wrapper adds the named
8
- * tracing span and the lifecycle event, neither of which the adapters provide.
9
- * Opt-in: wrap an action before registering it when you want that visibility.
6
+ * Observability is split by design across two axes, not duplicated:
7
+ * - The adapters (`NodeSchedulerAdapter`, `CloudflareSchedulerAdapter`) record
8
+ * executed/failed/duration **metrics keyed by `cron`** for aggregate dashboards.
9
+ * - This opt-in wrapper adds a named **tracing span + lifecycle event keyed by
10
+ * the human `name`**, for per-job diagnosis. Its timer measures the inner action
11
+ * scope; the adapter's measures the full tick — nested, not double-counted.
12
+ *
13
+ * Wrap an action before registering it when you want the named span/event.
10
14
  *
11
15
  * @param name - Job name, surfaced as `scheduler.job_name` on the span/event.
12
16
  * @param action - The action to wrap (new no-arg `ScheduledAction` signature).
@@ -1,7 +1,6 @@
1
- export { getTelemetryConfig, type TelemetryConfig, type TelemetryConfigPartial } from './config';
2
1
  export { extractSqlOperation, sanitizeSql } from './db-sanitize';
3
2
  export { type Counter, getEventbusEmitsTotal, getEventbusErrorsTotal, getHttpClientRequestDuration, getHttpClientRequestErrors, getHttpClientRequestTotal, getQueueJobCompletedTotal, getQueueJobEnqueuedTotal, getQueueJobFailedTotal, getQueueJobProcessingDuration, getSchedulerJobDuration, getSchedulerJobExecutedTotal, getSchedulerJobFailedTotal, type Histogram, initMetrics, shutdownMetrics, } from './metrics';
4
- export { getTracer, initTelemetry, isTelemetryEnabled, shutdownTelemetry } from './sdk';
3
+ export { getTelemetryConfig, getTracer, initTelemetry, isTelemetryEnabled, shutdownTelemetry, type TelemetryConfig, type TelemetryConfigPartial, } from './sdk';
5
4
  export type { Span, SpanOptions, Tracer } from './tracing';
6
5
  export { addSpanAttributes, addSpanEvent, getActiveSpan, traceAsync, traceSync, withSpan } from './tracing';
7
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/telemetry/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,KAAK,eAAe,EAAE,KAAK,sBAAsB,EAAE,MAAM,UAAU,CAAC;AACjG,OAAO,EAAE,mBAAmB,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjE,OAAO,EACH,KAAK,OAAO,EACZ,qBAAqB,EACrB,sBAAsB,EACtB,4BAA4B,EAC5B,0BAA0B,EAC1B,yBAAyB,EACzB,yBAAyB,EACzB,wBAAwB,EACxB,sBAAsB,EACtB,6BAA6B,EAC7B,uBAAuB,EACvB,4BAA4B,EAC5B,0BAA0B,EAC1B,KAAK,SAAS,EACd,WAAW,EACX,eAAe,GAClB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,OAAO,CAAC;AACxF,YAAY,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAC3D,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/telemetry/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjE,OAAO,EACH,KAAK,OAAO,EACZ,qBAAqB,EACrB,sBAAsB,EACtB,4BAA4B,EAC5B,0BAA0B,EAC1B,yBAAyB,EACzB,yBAAyB,EACzB,wBAAwB,EACxB,sBAAsB,EACtB,6BAA6B,EAC7B,uBAAuB,EACvB,4BAA4B,EAC5B,0BAA0B,EAC1B,KAAK,SAAS,EACd,WAAW,EACX,eAAe,GAClB,MAAM,WAAW,CAAC;AACnB,OAAO,EACH,kBAAkB,EAClB,SAAS,EACT,aAAa,EACb,kBAAkB,EAClB,iBAAiB,EACjB,KAAK,eAAe,EACpB,KAAK,sBAAsB,GAC9B,MAAM,OAAO,CAAC;AACf,YAAY,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAC3D,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC"}
@@ -1,5 +1,4 @@
1
- export { getTelemetryConfig } from './config.js';
2
1
  export { extractSqlOperation, sanitizeSql } from './db-sanitize.js';
3
2
  export { getEventbusEmitsTotal, getEventbusErrorsTotal, getHttpClientRequestDuration, getHttpClientRequestErrors, getHttpClientRequestTotal, getQueueJobCompletedTotal, getQueueJobEnqueuedTotal, getQueueJobFailedTotal, getQueueJobProcessingDuration, getSchedulerJobDuration, getSchedulerJobExecutedTotal, getSchedulerJobFailedTotal, initMetrics, shutdownMetrics, } from './metrics.js';
4
- export { getTracer, initTelemetry, isTelemetryEnabled, shutdownTelemetry } from './sdk.js';
3
+ export { getTelemetryConfig, getTracer, initTelemetry, isTelemetryEnabled, shutdownTelemetry, } from './sdk.js';
5
4
  export { addSpanAttributes, addSpanEvent, getActiveSpan, traceAsync, traceSync, withSpan } from './tracing.js';
@@ -30,7 +30,15 @@ export declare function getSchedulerJobExecutedTotal(): Counter;
30
30
  export declare function getSchedulerJobDuration(): Histogram;
31
31
  /** Counter for failed scheduled job executions. */
32
32
  export declare function getSchedulerJobFailedTotal(): Counter;
33
- /** Mark the metrics subsystem as initialized. Idempotent. */
33
+ /**
34
+ * Pre-warm every instrument against the currently-registered meter and mark the
35
+ * subsystem initialized. Idempotent.
36
+ *
37
+ * Instruments are otherwise created lazily on first getter call (so metrics keep
38
+ * working even if this is never called — see the module contract). Calling this
39
+ * during bootstrap eagerly materializes them, so `isMetricsInitialized()` reflects
40
+ * real wiring rather than being a flag that gates nothing.
41
+ */
34
42
  export declare function initMetrics(): void;
35
43
  /** Clear the instrument cache and mark metrics as uninitialized. */
36
44
  export declare function shutdownMetrics(): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"metrics.d.ts","sourceRoot":"","sources":["../../src/telemetry/metrics.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,KAAK,OAAO,EAAE,KAAK,SAAS,EAAW,MAAM,oBAAoB,CAAC;AAE3E,YAAY,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAI7D,kFAAkF;AAClF,wBAAgB,oBAAoB,IAAI,OAAO,CAE9C;AA8BD,kFAAkF;AAClF,wBAAgB,yBAAyB,IAAI,OAAO,CAEnD;AAED,oEAAoE;AACpE,wBAAgB,4BAA4B,IAAI,SAAS,CAExD;AAED,8DAA8D;AAC9D,wBAAgB,0BAA0B,IAAI,OAAO,CAEpD;AAID,yCAAyC;AACzC,wBAAgB,qBAAqB,IAAI,OAAO,CAE/C;AAED,4CAA4C;AAC5C,wBAAgB,sBAAsB,IAAI,OAAO,CAEhD;AAID,uCAAuC;AACvC,wBAAgB,wBAAwB,IAAI,OAAO,CAElD;AAED,qDAAqD;AACrD,wBAAgB,yBAAyB,IAAI,OAAO,CAEnD;AAED,8DAA8D;AAC9D,wBAAgB,sBAAsB,IAAI,OAAO,CAEhD;AAED,6DAA6D;AAC7D,wBAAgB,6BAA6B,IAAI,SAAS,CAEzD;AAID,kDAAkD;AAClD,wBAAgB,4BAA4B,IAAI,OAAO,CAEtD;AAED,sEAAsE;AACtE,wBAAgB,uBAAuB,IAAI,SAAS,CAEnD;AAED,mDAAmD;AACnD,wBAAgB,0BAA0B,IAAI,OAAO,CAEpD;AAID,6DAA6D;AAC7D,wBAAgB,WAAW,IAAI,IAAI,CAGlC;AAED,oEAAoE;AACpE,wBAAgB,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC,CAS/C;AAED;;;GAGG;AACH,wBAAgB,aAAa,IAAI,IAAI,CAMpC"}
1
+ {"version":3,"file":"metrics.d.ts","sourceRoot":"","sources":["../../src/telemetry/metrics.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,KAAK,OAAO,EAAE,KAAK,SAAS,EAAW,MAAM,oBAAoB,CAAC;AAE3E,YAAY,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAI7D,kFAAkF;AAClF,wBAAgB,oBAAoB,IAAI,OAAO,CAE9C;AA8BD,kFAAkF;AAClF,wBAAgB,yBAAyB,IAAI,OAAO,CAEnD;AAED,oEAAoE;AACpE,wBAAgB,4BAA4B,IAAI,SAAS,CAExD;AAED,8DAA8D;AAC9D,wBAAgB,0BAA0B,IAAI,OAAO,CAEpD;AAID,yCAAyC;AACzC,wBAAgB,qBAAqB,IAAI,OAAO,CAE/C;AAED,4CAA4C;AAC5C,wBAAgB,sBAAsB,IAAI,OAAO,CAEhD;AAID,uCAAuC;AACvC,wBAAgB,wBAAwB,IAAI,OAAO,CAElD;AAED,qDAAqD;AACrD,wBAAgB,yBAAyB,IAAI,OAAO,CAEnD;AAED,8DAA8D;AAC9D,wBAAgB,sBAAsB,IAAI,OAAO,CAEhD;AAED,6DAA6D;AAC7D,wBAAgB,6BAA6B,IAAI,SAAS,CAEzD;AAID,kDAAkD;AAClD,wBAAgB,4BAA4B,IAAI,OAAO,CAEtD;AAED,sEAAsE;AACtE,wBAAgB,uBAAuB,IAAI,SAAS,CAEnD;AAED,mDAAmD;AACnD,wBAAgB,0BAA0B,IAAI,OAAO,CAEpD;AAID;;;;;;;;GAQG;AACH,wBAAgB,WAAW,IAAI,IAAI,CAgBlC;AAED,oEAAoE;AACpE,wBAAgB,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC,CAS/C;AAED;;;GAGG;AACH,wBAAgB,aAAa,IAAI,IAAI,CAMpC"}
@@ -81,10 +81,31 @@ export function getSchedulerJobFailedTotal() {
81
81
  return getOrCreateCounter('schedFail', 'scheduler.jobs.failed', 'Failed scheduled jobs', '{failure}');
82
82
  }
83
83
  // ── Lifecycle ───────────────────────────────────────────────────────
84
- /** Mark the metrics subsystem as initialized. Idempotent. */
84
+ /**
85
+ * Pre-warm every instrument against the currently-registered meter and mark the
86
+ * subsystem initialized. Idempotent.
87
+ *
88
+ * Instruments are otherwise created lazily on first getter call (so metrics keep
89
+ * working even if this is never called — see the module contract). Calling this
90
+ * during bootstrap eagerly materializes them, so `isMetricsInitialized()` reflects
91
+ * real wiring rather than being a flag that gates nothing.
92
+ */
85
93
  export function initMetrics() {
86
94
  if (metricsInitialized)
87
95
  return;
96
+ // Eagerly materialize all instruments against the live meter.
97
+ getHttpClientRequestTotal();
98
+ getHttpClientRequestDuration();
99
+ getHttpClientRequestErrors();
100
+ getEventbusEmitsTotal();
101
+ getEventbusErrorsTotal();
102
+ getQueueJobEnqueuedTotal();
103
+ getQueueJobCompletedTotal();
104
+ getQueueJobFailedTotal();
105
+ getQueueJobProcessingDuration();
106
+ getSchedulerJobExecutedTotal();
107
+ getSchedulerJobDuration();
108
+ getSchedulerJobFailedTotal();
88
109
  metricsInitialized = true;
89
110
  }
90
111
  /** Clear the instrument cache and mark metrics as uninitialized. */