@boringnode/queue 0.5.0 → 0.5.2

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 (37) hide show
  1. package/README.md +80 -6
  2. package/build/{chunk-WOUYSNK2.js → chunk-KI47AJ6U.js} +2 -2
  3. package/build/chunk-PZ5AY32C.js +10 -0
  4. package/build/chunk-PZ5AY32C.js.map +1 -0
  5. package/build/{chunk-ZZFSQY36.js → chunk-QEFYHCL7.js} +4 -6
  6. package/build/{chunk-ZZFSQY36.js.map → chunk-QEFYHCL7.js.map} +1 -1
  7. package/build/{chunk-OVYXMSSU.js → chunk-VRXHCWNK.js} +113 -31
  8. package/build/chunk-VRXHCWNK.js.map +1 -0
  9. package/build/chunk-WVLSICD4.js +20 -0
  10. package/build/chunk-WVLSICD4.js.map +1 -0
  11. package/build/index.d.ts +61 -10
  12. package/build/index.js +64 -51
  13. package/build/index.js.map +1 -1
  14. package/build/{index-B1XdqWpN.d.ts → job-Z5fBSzRX.d.ts} +160 -6
  15. package/build/src/contracts/adapter.d.ts +1 -1
  16. package/build/src/drivers/fake_adapter.d.ts +6 -1
  17. package/build/src/drivers/fake_adapter.js +4 -2
  18. package/build/src/drivers/knex_adapter.d.ts +1 -1
  19. package/build/src/drivers/knex_adapter.js +2 -1
  20. package/build/src/drivers/knex_adapter.js.map +1 -1
  21. package/build/src/drivers/redis_adapter.d.ts +1 -1
  22. package/build/src/drivers/redis_adapter.js +92 -93
  23. package/build/src/drivers/redis_adapter.js.map +1 -1
  24. package/build/src/drivers/sync_adapter.d.ts +1 -1
  25. package/build/src/drivers/sync_adapter.js +38 -18
  26. package/build/src/drivers/sync_adapter.js.map +1 -1
  27. package/build/src/otel.d.ts +63 -0
  28. package/build/src/otel.js +245 -0
  29. package/build/src/otel.js.map +1 -0
  30. package/build/src/types/index.d.ts +6 -1
  31. package/build/src/types/main.d.ts +1 -1
  32. package/build/src/types/tracing_channels.d.ts +34 -0
  33. package/build/src/types/tracing_channels.js +1 -0
  34. package/build/src/types/tracing_channels.js.map +1 -0
  35. package/package.json +36 -14
  36. package/build/chunk-OVYXMSSU.js.map +0 -1
  37. /package/build/{chunk-WOUYSNK2.js.map → chunk-KI47AJ6U.js.map} +0 -0
@@ -1,13 +1,17 @@
1
1
  import {
2
2
  JobExecutionRuntime
3
- } from "../../chunk-WOUYSNK2.js";
3
+ } from "../../chunk-KI47AJ6U.js";
4
4
  import {
5
5
  Locator,
6
6
  QueueManager
7
- } from "../../chunk-OVYXMSSU.js";
7
+ } from "../../chunk-VRXHCWNK.js";
8
+ import {
9
+ executeChannel
10
+ } from "../../chunk-WVLSICD4.js";
8
11
  import {
9
12
  DEFAULT_PRIORITY
10
- } from "../../chunk-ZZFSQY36.js";
13
+ } from "../../chunk-QEFYHCL7.js";
14
+ import "../../chunk-PZ5AY32C.js";
11
15
 
12
16
  // src/drivers/sync_adapter.ts
13
17
  import { setTimeout as sleep } from "timers/promises";
@@ -113,33 +117,49 @@ var SyncAdapter = class {
113
117
  defaultTimeout: configResolver.getWorkerTimeout()
114
118
  });
115
119
  const jobFactory = QueueManager.getJobFactory();
120
+ const executionWrapper = QueueManager.getExecutionWrapper();
116
121
  let attempts = jobData.attempts;
117
122
  while (true) {
123
+ const now = Date.now();
124
+ const acquiredJob = { ...jobData, attempts, acquiredAt: now };
118
125
  const context = {
119
126
  jobId: jobData.id,
120
127
  name: jobData.name,
121
128
  attempt: attempts + 1,
122
129
  queue,
123
130
  priority: jobData.priority ?? DEFAULT_PRIORITY,
124
- acquiredAt: /* @__PURE__ */ new Date(),
131
+ acquiredAt: new Date(now),
125
132
  stalledCount: jobData.stalledCount ?? 0
126
133
  };
127
134
  const jobInstance = jobFactory ? await jobFactory(JobClass) : new JobClass();
128
- try {
129
- await runtime.execute(jobInstance, jobData.payload, context);
130
- return;
131
- } catch (error) {
132
- const outcome = runtime.resolveFailure(error, attempts);
133
- if (outcome.type === "failed") {
134
- await jobInstance.failed?.(outcome.hookError);
135
- return;
136
- }
137
- attempts++;
138
- if (outcome.type === "retry" && outcome.retryAt) {
139
- const delay = outcome.retryAt.getTime() - Date.now();
140
- if (delay > 0) {
141
- await sleep(delay);
135
+ const startTime = performance.now();
136
+ const executeMessage = { job: acquiredJob, queue };
137
+ const run = () => {
138
+ return executeChannel.tracePromise(async () => {
139
+ try {
140
+ await runtime.execute(jobInstance, jobData.payload, context);
141
+ executeMessage.status = "completed";
142
+ } catch (error) {
143
+ const outcome = runtime.resolveFailure(error, attempts);
144
+ executeMessage.error = error;
145
+ if (outcome.type === "failed") {
146
+ executeMessage.status = "failed";
147
+ await jobInstance.failed?.(outcome.hookError);
148
+ } else if (outcome.type === "retry") {
149
+ executeMessage.status = "retrying";
150
+ executeMessage.nextRetryAt = outcome.retryAt;
151
+ }
142
152
  }
153
+ executeMessage.duration = Number((performance.now() - startTime).toFixed(2));
154
+ }, executeMessage);
155
+ };
156
+ await executionWrapper(run, acquiredJob, queue);
157
+ if (executeMessage.status !== "retrying") return;
158
+ attempts++;
159
+ if (executeMessage.nextRetryAt) {
160
+ const delay = executeMessage.nextRetryAt.getTime() - Date.now();
161
+ if (delay > 0) {
162
+ await sleep(delay);
143
163
  }
144
164
  }
145
165
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/drivers/sync_adapter.ts"],"sourcesContent":["import { setTimeout as sleep } from 'node:timers/promises'\nimport { Locator } from '../locator.js'\nimport { QueueManager } from '../queue_manager.js'\nimport { JobExecutionRuntime } from '../job_runtime.js'\nimport type { Adapter, AcquiredJob } from '../contracts/adapter.js'\nimport type {\n JobContext,\n JobData,\n JobRetention,\n ScheduleConfig,\n ScheduleData,\n ScheduleListOptions,\n} from '../types/main.js'\nimport { DEFAULT_PRIORITY } from '../constants.js'\n\n/**\n * Create a sync adapter factory.\n */\nexport function sync() {\n return () => new SyncAdapter()\n}\n\n/**\n * Sync adapter executes jobs immediately when pushed.\n * Pop/complete/fail/retry are not supported as jobs are executed synchronously.\n */\nexport class SyncAdapter implements Adapter {\n setWorkerId(_workerId: string): void {}\n\n push(jobData: JobData): Promise<void> {\n return this.pushOn('default', jobData)\n }\n\n pushOn(queue: string, jobData: JobData): Promise<void> {\n return this.#execute(jobData, queue)\n }\n\n pushLater(jobData: JobData, delay: number): Promise<void> {\n return this.pushLaterOn('default', jobData, delay)\n }\n\n pushLaterOn(queue: string, jobData: JobData, delay: number): Promise<void> {\n setTimeout(() => {\n void this.#execute(jobData, queue).catch((error) => {\n QueueManager.getLogger().error(\n { err: error, jobId: jobData.id, jobName: jobData.name, queue },\n 'Failed to execute delayed sync job'\n )\n })\n }, delay)\n\n return Promise.resolve()\n }\n\n pushMany(jobs: JobData[]): Promise<void> {\n return this.pushManyOn('default', jobs)\n }\n\n async pushManyOn(queue: string, jobs: JobData[]): Promise<void> {\n for (const job of jobs) {\n await this.pushOn(queue, job)\n }\n }\n\n size(): Promise<number> {\n return this.sizeOf('default')\n }\n\n sizeOf(_queue: string): Promise<number> {\n return Promise.resolve(0)\n }\n\n pop(): Promise<AcquiredJob | null> {\n return this.popFrom('default')\n }\n\n popFrom(_queue: string): Promise<AcquiredJob | null> {\n throw new Error('SyncAdapter does not support pop - jobs are executed immediately on push')\n }\n\n completeJob(_jobId: string, _queue: string, _removeOnComplete?: JobRetention): Promise<void> {\n return Promise.resolve()\n }\n\n failJob(\n _jobId: string,\n _queue: string,\n _error?: Error,\n _removeOnFail?: JobRetention\n ): Promise<void> {\n return Promise.resolve()\n }\n\n retryJob(_jobId: string, _queue: string, _retryAt?: Date): Promise<void> {\n return Promise.resolve()\n }\n\n recoverStalledJobs(\n _queue: string,\n _stalledThreshold: number,\n _maxStalledCount: number\n ): Promise<number> {\n // SyncAdapter has no stalled jobs - jobs are executed immediately\n return Promise.resolve(0)\n }\n\n getJob(_jobId: string, _queue: string): Promise<null> {\n return Promise.resolve(null)\n }\n\n destroy(): Promise<void> {\n return Promise.resolve()\n }\n\n upsertSchedule(_config: ScheduleConfig): Promise<string> {\n // No-op: schedules don't make sense for sync adapter\n // Return a fake ID so code doesn't break in dev\n return Promise.resolve(`sync-schedule-${Date.now()}`)\n }\n\n /**\n * @deprecated Use `upsertSchedule` instead.\n */\n createSchedule(config: ScheduleConfig): Promise<string> {\n return this.upsertSchedule(config)\n }\n\n getSchedule(_id: string): Promise<ScheduleData | null> {\n return Promise.resolve(null)\n }\n\n listSchedules(_options?: ScheduleListOptions): Promise<ScheduleData[]> {\n return Promise.resolve([])\n }\n\n updateSchedule(\n _id: string,\n _updates: Partial<Pick<ScheduleData, 'status' | 'nextRunAt' | 'lastRunAt' | 'runCount'>>\n ): Promise<void> {\n return Promise.resolve()\n }\n\n deleteSchedule(_id: string): Promise<void> {\n return Promise.resolve()\n }\n\n claimDueSchedule(): Promise<ScheduleData | null> {\n // SyncAdapter doesn't support scheduling\n return Promise.resolve(null)\n }\n\n async #execute(jobData: JobData, queue: string = 'default'): Promise<void> {\n const JobClass = Locator.get(jobData.name)\n\n if (!JobClass) {\n throw new Error(`Job class ${jobData.name} not found.`)\n }\n\n const options = JobClass.options || {}\n const configResolver = QueueManager.getConfigResolver()\n const runtime = JobExecutionRuntime.from({\n jobName: jobData.name,\n options,\n retryConfig: configResolver.resolveRetryConfig(queue, options),\n defaultTimeout: configResolver.getWorkerTimeout(),\n })\n const jobFactory = QueueManager.getJobFactory()\n let attempts = jobData.attempts\n\n while (true) {\n const context: JobContext = {\n jobId: jobData.id,\n name: jobData.name,\n attempt: attempts + 1,\n queue,\n priority: jobData.priority ?? DEFAULT_PRIORITY,\n acquiredAt: new Date(),\n stalledCount: jobData.stalledCount ?? 0,\n }\n\n const jobInstance = jobFactory ? await jobFactory(JobClass) : new JobClass()\n\n try {\n await runtime.execute(jobInstance, jobData.payload, context)\n return\n } catch (error) {\n const outcome = runtime.resolveFailure(error as Error, attempts)\n\n if (outcome.type === 'failed') {\n await jobInstance.failed?.(outcome.hookError)\n return\n }\n\n attempts++\n\n if (outcome.type === 'retry' && outcome.retryAt) {\n const delay = outcome.retryAt.getTime() - Date.now()\n\n if (delay > 0) {\n await sleep(delay)\n }\n }\n }\n }\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/drivers/sync_adapter.ts"],"sourcesContent":["import { setTimeout as sleep } from 'node:timers/promises'\nimport { Locator } from '../locator.js'\nimport { QueueManager } from '../queue_manager.js'\nimport { JobExecutionRuntime } from '../job_runtime.js'\nimport { executeChannel } from '../tracing_channels.js'\nimport type { Adapter, AcquiredJob } from '../contracts/adapter.js'\nimport type {\n JobContext,\n JobData,\n JobRetention,\n ScheduleConfig,\n ScheduleData,\n ScheduleListOptions,\n} from '../types/main.js'\nimport type { JobExecuteMessage } from '../types/tracing_channels.js'\nimport { DEFAULT_PRIORITY } from '../constants.js'\n\n/**\n * Create a sync adapter factory.\n */\nexport function sync() {\n return () => new SyncAdapter()\n}\n\n/**\n * Sync adapter executes jobs immediately when pushed.\n * Pop/complete/fail/retry are not supported as jobs are executed synchronously.\n */\nexport class SyncAdapter implements Adapter {\n setWorkerId(_workerId: string): void {}\n\n push(jobData: JobData): Promise<void> {\n return this.pushOn('default', jobData)\n }\n\n pushOn(queue: string, jobData: JobData): Promise<void> {\n return this.#execute(jobData, queue)\n }\n\n pushLater(jobData: JobData, delay: number): Promise<void> {\n return this.pushLaterOn('default', jobData, delay)\n }\n\n pushLaterOn(queue: string, jobData: JobData, delay: number): Promise<void> {\n setTimeout(() => {\n void this.#execute(jobData, queue).catch((error) => {\n QueueManager.getLogger().error(\n { err: error, jobId: jobData.id, jobName: jobData.name, queue },\n 'Failed to execute delayed sync job'\n )\n })\n }, delay)\n\n return Promise.resolve()\n }\n\n pushMany(jobs: JobData[]): Promise<void> {\n return this.pushManyOn('default', jobs)\n }\n\n async pushManyOn(queue: string, jobs: JobData[]): Promise<void> {\n for (const job of jobs) {\n await this.pushOn(queue, job)\n }\n }\n\n size(): Promise<number> {\n return this.sizeOf('default')\n }\n\n sizeOf(_queue: string): Promise<number> {\n return Promise.resolve(0)\n }\n\n pop(): Promise<AcquiredJob | null> {\n return this.popFrom('default')\n }\n\n popFrom(_queue: string): Promise<AcquiredJob | null> {\n throw new Error('SyncAdapter does not support pop - jobs are executed immediately on push')\n }\n\n completeJob(_jobId: string, _queue: string, _removeOnComplete?: JobRetention): Promise<void> {\n return Promise.resolve()\n }\n\n failJob(\n _jobId: string,\n _queue: string,\n _error?: Error,\n _removeOnFail?: JobRetention\n ): Promise<void> {\n return Promise.resolve()\n }\n\n retryJob(_jobId: string, _queue: string, _retryAt?: Date): Promise<void> {\n return Promise.resolve()\n }\n\n recoverStalledJobs(\n _queue: string,\n _stalledThreshold: number,\n _maxStalledCount: number\n ): Promise<number> {\n // SyncAdapter has no stalled jobs - jobs are executed immediately\n return Promise.resolve(0)\n }\n\n getJob(_jobId: string, _queue: string): Promise<null> {\n return Promise.resolve(null)\n }\n\n destroy(): Promise<void> {\n return Promise.resolve()\n }\n\n upsertSchedule(_config: ScheduleConfig): Promise<string> {\n // No-op: schedules don't make sense for sync adapter\n // Return a fake ID so code doesn't break in dev\n return Promise.resolve(`sync-schedule-${Date.now()}`)\n }\n\n /**\n * @deprecated Use `upsertSchedule` instead.\n */\n createSchedule(config: ScheduleConfig): Promise<string> {\n return this.upsertSchedule(config)\n }\n\n getSchedule(_id: string): Promise<ScheduleData | null> {\n return Promise.resolve(null)\n }\n\n listSchedules(_options?: ScheduleListOptions): Promise<ScheduleData[]> {\n return Promise.resolve([])\n }\n\n updateSchedule(\n _id: string,\n _updates: Partial<Pick<ScheduleData, 'status' | 'nextRunAt' | 'lastRunAt' | 'runCount'>>\n ): Promise<void> {\n return Promise.resolve()\n }\n\n deleteSchedule(_id: string): Promise<void> {\n return Promise.resolve()\n }\n\n claimDueSchedule(): Promise<ScheduleData | null> {\n // SyncAdapter doesn't support scheduling\n return Promise.resolve(null)\n }\n\n async #execute(jobData: JobData, queue: string = 'default'): Promise<void> {\n const JobClass = Locator.get(jobData.name)\n\n if (!JobClass) {\n throw new Error(`Job class ${jobData.name} not found.`)\n }\n\n const options = JobClass.options || {}\n const configResolver = QueueManager.getConfigResolver()\n const runtime = JobExecutionRuntime.from({\n jobName: jobData.name,\n options,\n retryConfig: configResolver.resolveRetryConfig(queue, options),\n defaultTimeout: configResolver.getWorkerTimeout(),\n })\n const jobFactory = QueueManager.getJobFactory()\n const executionWrapper = QueueManager.getExecutionWrapper()\n let attempts = jobData.attempts\n\n while (true) {\n const now = Date.now()\n const acquiredJob: AcquiredJob = { ...jobData, attempts, acquiredAt: now }\n\n const context: JobContext = {\n jobId: jobData.id,\n name: jobData.name,\n attempt: attempts + 1,\n queue,\n priority: jobData.priority ?? DEFAULT_PRIORITY,\n acquiredAt: new Date(now),\n stalledCount: jobData.stalledCount ?? 0,\n }\n\n const jobInstance = jobFactory ? await jobFactory(JobClass) : new JobClass()\n\n const startTime = performance.now()\n const executeMessage: JobExecuteMessage = { job: acquiredJob, queue }\n\n const run = () => {\n return executeChannel.tracePromise(async () => {\n try {\n await runtime.execute(jobInstance, jobData.payload, context)\n executeMessage.status = 'completed'\n } catch (error) {\n const outcome = runtime.resolveFailure(error as Error, attempts)\n executeMessage.error = error as Error\n\n if (outcome.type === 'failed') {\n executeMessage.status = 'failed'\n await jobInstance.failed?.(outcome.hookError)\n } else if (outcome.type === 'retry') {\n executeMessage.status = 'retrying'\n executeMessage.nextRetryAt = outcome.retryAt\n }\n }\n\n executeMessage.duration = Number((performance.now() - startTime).toFixed(2))\n }, executeMessage)\n }\n\n await executionWrapper(run, acquiredJob, queue)\n\n if (executeMessage.status !== 'retrying') return\n\n attempts++\n\n if (executeMessage.nextRetryAt) {\n const delay = executeMessage.nextRetryAt.getTime() - Date.now()\n if (delay > 0) {\n await sleep(delay)\n }\n }\n }\n }\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,63 @@
1
+ import '../job-Z5fBSzRX.js';
2
+ import { JobDispatchMessage, JobExecuteMessage } from './types/tracing_channels.js';
3
+ import { Span } from '@opentelemetry/api';
4
+ import { TracingChannelSubscribers } from 'node:diagnostics_channel';
5
+ import { InstrumentationConfig, InstrumentationBase } from '@opentelemetry/instrumentation';
6
+
7
+ interface QueueInstrumentationConfig extends InstrumentationConfig {
8
+ /**
9
+ * How execution spans relate to the dispatch span.
10
+ *
11
+ * - `'link'` (default): Independent trace, linked to dispatch span
12
+ * - `'parent'`: Child of the dispatch span (same trace)
13
+ */
14
+ executionSpanLinkMode?: 'link' | 'parent';
15
+ /**
16
+ * The messaging system identifier.
17
+ *
18
+ * @default 'boringqueue'
19
+ */
20
+ messagingSystem?: string;
21
+ }
22
+ /**
23
+ * OpenTelemetry instrumentation for @boringnode/queue.
24
+ *
25
+ * Creates PRODUCER spans for job dispatch and CONSUMER spans for
26
+ * job execution, following OTel messaging semantic conventions.
27
+ *
28
+ * Uses `diagnostics_channel` for span lifecycle management and
29
+ * patches `QueueManager.init()` to inject wrappers automatically.
30
+ */
31
+ declare class QueueInstrumentation extends InstrumentationBase<QueueInstrumentationConfig> {
32
+ #private;
33
+ protected subscribed: boolean;
34
+ protected executeSpans: Map<string, Span>;
35
+ protected dispatchSpans: WeakMap<JobDispatchMessage, Span>;
36
+ protected executeHandlers?: TracingChannelSubscribers<JobExecuteMessage>;
37
+ protected dispatchHandlers?: TracingChannelSubscribers<JobDispatchMessage>;
38
+ constructor(config?: QueueInstrumentationConfig);
39
+ /**
40
+ * Required by InstrumentationBase. Returns undefined since we use
41
+ * diagnostics_channel instead of module patching.
42
+ */
43
+ protected init(): undefined;
44
+ /**
45
+ * Subscribes to diagnostics_channels for span lifecycle.
46
+ */
47
+ enable(): void;
48
+ /**
49
+ * Unsubscribes from diagnostics_channels and restores patched methods.
50
+ */
51
+ disable(): void;
52
+ /**
53
+ * Patches `QueueManager.init()` to auto-inject OTel wrappers
54
+ * and subscribes to diagnostics_channels.
55
+ */
56
+ manuallyRegister(queueModule: {
57
+ QueueManager: {
58
+ init: (...args: any[]) => any;
59
+ };
60
+ }): void;
61
+ }
62
+
63
+ export { QueueInstrumentation, type QueueInstrumentationConfig };
@@ -0,0 +1,245 @@
1
+ import {
2
+ dispatchChannel,
3
+ executeChannel
4
+ } from "../chunk-WVLSICD4.js";
5
+ import "../chunk-PZ5AY32C.js";
6
+
7
+ // src/otel.ts
8
+ import {
9
+ context,
10
+ propagation,
11
+ trace,
12
+ SpanKind,
13
+ SpanStatusCode,
14
+ ROOT_CONTEXT
15
+ } from "@opentelemetry/api";
16
+ import { suppressTracing } from "@opentelemetry/core";
17
+ import { InstrumentationBase } from "@opentelemetry/instrumentation";
18
+ var QueueInstrumentation = class extends InstrumentationBase {
19
+ subscribed = false;
20
+ executeSpans = /* @__PURE__ */ new Map();
21
+ dispatchSpans = /* @__PURE__ */ new WeakMap();
22
+ executeHandlers;
23
+ dispatchHandlers;
24
+ #originalInit;
25
+ #patchedManager;
26
+ constructor(config = {}) {
27
+ super("@boringnode/queue", "0.1.0", config);
28
+ }
29
+ get #messagingSystem() {
30
+ return this.getConfig().messagingSystem ?? "boringqueue";
31
+ }
32
+ get #executionSpanLinkMode() {
33
+ return this.getConfig().executionSpanLinkMode ?? "link";
34
+ }
35
+ /**
36
+ * Required by InstrumentationBase. Returns undefined since we use
37
+ * diagnostics_channel instead of module patching.
38
+ */
39
+ init() {
40
+ return void 0;
41
+ }
42
+ /**
43
+ * Subscribes to diagnostics_channels for span lifecycle.
44
+ */
45
+ enable() {
46
+ super.enable();
47
+ if (this.subscribed !== void 0) this.#subscribe();
48
+ }
49
+ /**
50
+ * Unsubscribes from diagnostics_channels and restores patched methods.
51
+ */
52
+ disable() {
53
+ if (this.subscribed !== void 0) {
54
+ this.#unsubscribe();
55
+ this.#unpatchInit();
56
+ }
57
+ super.disable();
58
+ }
59
+ /**
60
+ * Patches `QueueManager.init()` to auto-inject OTel wrappers
61
+ * and subscribes to diagnostics_channels.
62
+ */
63
+ manuallyRegister(queueModule) {
64
+ this.#patchInit(queueModule.QueueManager);
65
+ this.#subscribe();
66
+ }
67
+ #patchInit(manager) {
68
+ if (this.#originalInit) return;
69
+ this.#patchedManager = manager;
70
+ this.#originalInit = manager.init.bind(manager);
71
+ const instrumentation = this;
72
+ manager.init = async (config) => {
73
+ return this.#originalInit({
74
+ ...config,
75
+ internalOperationWrapper: (fn) => {
76
+ return context.with(suppressTracing(context.active()), fn);
77
+ },
78
+ executionWrapper: (fn, job, queue) => {
79
+ return instrumentation.#wrapExecution(fn, job, queue);
80
+ }
81
+ });
82
+ };
83
+ }
84
+ #unpatchInit() {
85
+ if (!this.#originalInit || !this.#patchedManager) return;
86
+ this.#patchedManager.init = this.#originalInit;
87
+ this.#originalInit = void 0;
88
+ this.#patchedManager = void 0;
89
+ }
90
+ #subscribe() {
91
+ if (this.subscribed) return;
92
+ if (!this.isEnabled()) return;
93
+ this.subscribed = true;
94
+ this.executeHandlers = {
95
+ start: () => {
96
+ },
97
+ end: () => {
98
+ },
99
+ asyncStart: () => {
100
+ },
101
+ asyncEnd: (msg) => this.#handleExecuteAsyncEnd(msg),
102
+ error: () => {
103
+ }
104
+ };
105
+ this.dispatchHandlers = {
106
+ start: (msg) => this.#handleDispatchStart(msg),
107
+ end: () => {
108
+ },
109
+ asyncStart: () => {
110
+ },
111
+ asyncEnd: (msg) => this.#handleDispatchAsyncEnd(msg),
112
+ error: () => {
113
+ }
114
+ };
115
+ executeChannel.subscribe(this.executeHandlers);
116
+ dispatchChannel.subscribe(this.dispatchHandlers);
117
+ }
118
+ #unsubscribe() {
119
+ if (!this.subscribed) return;
120
+ if (this.executeHandlers) executeChannel.unsubscribe(this.executeHandlers);
121
+ if (this.dispatchHandlers) dispatchChannel.unsubscribe(this.dispatchHandlers);
122
+ this.subscribed = false;
123
+ this.executeHandlers = void 0;
124
+ this.dispatchHandlers = void 0;
125
+ this.executeSpans.clear();
126
+ this.dispatchSpans = /* @__PURE__ */ new WeakMap();
127
+ }
128
+ /**
129
+ * Called on dispatchChannel `start` — injects trace context into jobData
130
+ * and creates/enriches a PRODUCER span.
131
+ */
132
+ #handleDispatchStart(message) {
133
+ const attributes = this.#buildDispatchAttributes(message);
134
+ const span = this.tracer.startSpan(`publish ${message.queue}`, {
135
+ kind: SpanKind.PRODUCER,
136
+ attributes
137
+ });
138
+ const dispatchContext = trace.setSpan(context.active(), span);
139
+ for (const job of message.jobs) {
140
+ if (!job.traceContext) job.traceContext = {};
141
+ propagation.inject(dispatchContext, job.traceContext);
142
+ }
143
+ this.dispatchSpans.set(message, span);
144
+ }
145
+ #handleDispatchAsyncEnd(message) {
146
+ const span = this.dispatchSpans.get(message);
147
+ if (!span) return;
148
+ if (message.error) {
149
+ span.recordException(message.error);
150
+ span.setStatus({ code: SpanStatusCode.ERROR, message: message.error.message });
151
+ }
152
+ span.end();
153
+ this.dispatchSpans.delete(message);
154
+ }
155
+ /**
156
+ * Called by `executionWrapper` config — creates CONSUMER span and wraps
157
+ * execution in OTel context for proper child span parenting.
158
+ */
159
+ #wrapExecution(fn, job, queue) {
160
+ const extractedContext = this.#extractParentContext(job.traceContext);
161
+ const parentSpanContext = trace.getSpanContext(extractedContext);
162
+ let baseContext;
163
+ let links;
164
+ if (this.#executionSpanLinkMode === "parent" && parentSpanContext) {
165
+ baseContext = extractedContext;
166
+ links = [];
167
+ } else {
168
+ links = parentSpanContext ? [{ context: parentSpanContext }] : [];
169
+ baseContext = ROOT_CONTEXT;
170
+ }
171
+ const span = this.tracer.startSpan(
172
+ `process ${queue}`,
173
+ {
174
+ kind: SpanKind.CONSUMER,
175
+ attributes: this.#buildExecuteAttributes(job, queue),
176
+ links
177
+ },
178
+ baseContext
179
+ );
180
+ if (job.createdAt) {
181
+ span.setAttribute("messaging.job.queue_time_ms", Date.now() - job.createdAt);
182
+ }
183
+ this.executeSpans.set(job.id, span);
184
+ const executionContext = trace.setSpan(baseContext, span);
185
+ return context.with(executionContext, fn);
186
+ }
187
+ #handleExecuteAsyncEnd(message) {
188
+ const span = this.executeSpans.get(message.job.id);
189
+ if (!span) return;
190
+ if (message.status) span.setAttribute("messaging.job.status", message.status);
191
+ if (message.error) span.recordException(message.error);
192
+ if (message.status === "retrying" && message.nextRetryAt) {
193
+ span.addEvent("messaging.retry", {
194
+ "messaging.message.retry.count": message.job.attempts + 1,
195
+ "messaging.job.retry_at": message.nextRetryAt.toISOString()
196
+ });
197
+ }
198
+ if (message.status === "failed") {
199
+ span.setStatus({ code: SpanStatusCode.ERROR, message: message.error?.message });
200
+ } else {
201
+ span.setStatus({ code: SpanStatusCode.OK });
202
+ }
203
+ span.end();
204
+ this.executeSpans.delete(message.job.id);
205
+ }
206
+ #extractParentContext(traceContext) {
207
+ if (!traceContext || Object.keys(traceContext).length === 0) return ROOT_CONTEXT;
208
+ return propagation.extract(ROOT_CONTEXT, traceContext);
209
+ }
210
+ #buildDispatchAttributes(message) {
211
+ const firstJob = message.jobs[0];
212
+ const attributes = {
213
+ "messaging.system": this.#messagingSystem,
214
+ "messaging.operation.name": "publish",
215
+ "messaging.operation.type": "send",
216
+ "messaging.destination.name": message.queue,
217
+ "messaging.job.name": firstJob.name
218
+ };
219
+ if (message.jobs.length === 1) attributes["messaging.message.id"] = firstJob.id;
220
+ if (message.jobs.length > 1) attributes["messaging.batch.message_count"] = message.jobs.length;
221
+ if (firstJob.groupId) attributes["messaging.job.group_id"] = firstJob.groupId;
222
+ if (firstJob.priority !== void 0) attributes["messaging.job.priority"] = firstJob.priority;
223
+ if (message.delay !== void 0) attributes["messaging.job.delay_ms"] = message.delay;
224
+ return attributes;
225
+ }
226
+ #buildExecuteAttributes(job, queue) {
227
+ const attributes = {
228
+ "entry_point.type": "job",
229
+ "messaging.system": this.#messagingSystem,
230
+ "messaging.operation.name": "process",
231
+ "messaging.operation.type": "process",
232
+ "messaging.destination.name": queue,
233
+ "messaging.message.id": job.id,
234
+ "messaging.message.retry.count": job.attempts,
235
+ "messaging.job.name": job.name
236
+ };
237
+ if (job.groupId) attributes["messaging.job.group_id"] = job.groupId;
238
+ if (job.priority !== void 0) attributes["messaging.job.priority"] = job.priority;
239
+ return attributes;
240
+ }
241
+ };
242
+ export {
243
+ QueueInstrumentation
244
+ };
245
+ //# sourceMappingURL=otel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/otel.ts"],"sourcesContent":["import {\n context,\n propagation,\n trace,\n SpanKind,\n SpanStatusCode,\n ROOT_CONTEXT,\n type Span,\n type Link,\n} from '@opentelemetry/api'\nimport type { TracingChannelSubscribers } from 'node:diagnostics_channel'\nimport { suppressTracing } from '@opentelemetry/core'\nimport { InstrumentationBase } from '@opentelemetry/instrumentation'\nimport type { InstrumentationConfig } from '@opentelemetry/instrumentation'\nimport { dispatchChannel, executeChannel } from './tracing_channels.js'\nimport type { AcquiredJob } from './contracts/adapter.js'\nimport type { JobDispatchMessage, JobExecuteMessage } from './types/tracing_channels.js'\n\nexport interface QueueInstrumentationConfig extends InstrumentationConfig {\n /**\n * How execution spans relate to the dispatch span.\n *\n * - `'link'` (default): Independent trace, linked to dispatch span\n * - `'parent'`: Child of the dispatch span (same trace)\n */\n executionSpanLinkMode?: 'link' | 'parent'\n\n /**\n * The messaging system identifier.\n *\n * @default 'boringqueue'\n */\n messagingSystem?: string\n}\n\n/**\n * OpenTelemetry instrumentation for @boringnode/queue.\n *\n * Creates PRODUCER spans for job dispatch and CONSUMER spans for\n * job execution, following OTel messaging semantic conventions.\n *\n * Uses `diagnostics_channel` for span lifecycle management and\n * patches `QueueManager.init()` to inject wrappers automatically.\n */\nexport class QueueInstrumentation extends InstrumentationBase<QueueInstrumentationConfig> {\n protected subscribed = false\n protected executeSpans = new Map<string, Span>()\n protected dispatchSpans = new WeakMap<JobDispatchMessage, Span>()\n protected executeHandlers?: TracingChannelSubscribers<JobExecuteMessage>\n protected dispatchHandlers?: TracingChannelSubscribers<JobDispatchMessage>\n\n #originalInit?: (...args: any[]) => any\n #patchedManager?: { init: (...args: any[]) => any }\n\n constructor(config: QueueInstrumentationConfig = {}) {\n super('@boringnode/queue', '0.1.0', config)\n }\n\n get #messagingSystem(): string {\n return this.getConfig().messagingSystem ?? 'boringqueue'\n }\n\n get #executionSpanLinkMode(): 'link' | 'parent' {\n return this.getConfig().executionSpanLinkMode ?? 'link'\n }\n\n /**\n * Required by InstrumentationBase. Returns undefined since we use\n * diagnostics_channel instead of module patching.\n */\n protected init() {\n return undefined\n }\n\n /**\n * Subscribes to diagnostics_channels for span lifecycle.\n */\n enable() {\n super.enable()\n if (this.subscribed !== undefined) this.#subscribe()\n }\n\n /**\n * Unsubscribes from diagnostics_channels and restores patched methods.\n */\n disable() {\n if (this.subscribed !== undefined) {\n this.#unsubscribe()\n this.#unpatchInit()\n }\n\n super.disable()\n }\n\n /**\n * Patches `QueueManager.init()` to auto-inject OTel wrappers\n * and subscribes to diagnostics_channels.\n */\n manuallyRegister(queueModule: { QueueManager: { init: (...args: any[]) => any } }) {\n this.#patchInit(queueModule.QueueManager)\n this.#subscribe()\n }\n\n #patchInit(manager: { init: (...args: any[]) => any }) {\n if (this.#originalInit) return\n\n this.#patchedManager = manager\n this.#originalInit = manager.init.bind(manager)\n const instrumentation = this\n\n manager.init = async (config: any) => {\n return this.#originalInit!({\n ...config,\n internalOperationWrapper: <T>(fn: () => Promise<T>) => {\n return context.with(suppressTracing(context.active()), fn)\n },\n executionWrapper: <T>(fn: () => Promise<T>, job: AcquiredJob, queue: string) => {\n return instrumentation.#wrapExecution(fn, job, queue)\n },\n })\n }\n }\n\n #unpatchInit() {\n if (!this.#originalInit || !this.#patchedManager) return\n\n this.#patchedManager.init = this.#originalInit\n this.#originalInit = undefined\n this.#patchedManager = undefined\n }\n\n #subscribe() {\n if (this.subscribed) return\n if (!this.isEnabled()) return\n\n this.subscribed = true\n\n this.executeHandlers = {\n start: () => {},\n end: () => {},\n asyncStart: () => {},\n asyncEnd: (msg) => this.#handleExecuteAsyncEnd(msg as unknown as JobExecuteMessage),\n error: () => {},\n }\n\n this.dispatchHandlers = {\n start: (msg) => this.#handleDispatchStart(msg as unknown as JobDispatchMessage),\n end: () => {},\n asyncStart: () => {},\n asyncEnd: (msg) => this.#handleDispatchAsyncEnd(msg as unknown as JobDispatchMessage),\n error: () => {},\n }\n\n executeChannel.subscribe(this.executeHandlers as any)\n dispatchChannel.subscribe(this.dispatchHandlers as any)\n }\n\n #unsubscribe() {\n if (!this.subscribed) return\n\n if (this.executeHandlers) executeChannel.unsubscribe(this.executeHandlers as any)\n if (this.dispatchHandlers) dispatchChannel.unsubscribe(this.dispatchHandlers as any)\n\n this.subscribed = false\n this.executeHandlers = undefined\n this.dispatchHandlers = undefined\n this.executeSpans.clear()\n this.dispatchSpans = new WeakMap()\n }\n\n /**\n * Called on dispatchChannel `start` — injects trace context into jobData\n * and creates/enriches a PRODUCER span.\n */\n #handleDispatchStart(message: JobDispatchMessage) {\n const attributes = this.#buildDispatchAttributes(message)\n const span = this.tracer.startSpan(`publish ${message.queue}`, {\n kind: SpanKind.PRODUCER,\n attributes,\n })\n\n const dispatchContext = trace.setSpan(context.active(), span)\n for (const job of message.jobs) {\n if (!job.traceContext) job.traceContext = {}\n propagation.inject(dispatchContext, job.traceContext)\n }\n\n this.dispatchSpans.set(message, span)\n }\n\n #handleDispatchAsyncEnd(message: JobDispatchMessage) {\n const span = this.dispatchSpans.get(message)\n if (!span) return\n\n if (message.error) {\n span.recordException(message.error)\n span.setStatus({ code: SpanStatusCode.ERROR, message: message.error.message })\n }\n\n span.end()\n this.dispatchSpans.delete(message)\n }\n\n /**\n * Called by `executionWrapper` config — creates CONSUMER span and wraps\n * execution in OTel context for proper child span parenting.\n */\n #wrapExecution<T>(fn: () => Promise<T>, job: AcquiredJob, queue: string): Promise<T> {\n const extractedContext = this.#extractParentContext(job.traceContext)\n const parentSpanContext = trace.getSpanContext(extractedContext)\n\n let baseContext: typeof extractedContext\n let links: Link[]\n\n if (this.#executionSpanLinkMode === 'parent' && parentSpanContext) {\n baseContext = extractedContext\n links = []\n } else {\n links = parentSpanContext ? [{ context: parentSpanContext }] : []\n baseContext = ROOT_CONTEXT\n }\n\n const span = this.tracer.startSpan(\n `process ${queue}`,\n {\n kind: SpanKind.CONSUMER,\n attributes: this.#buildExecuteAttributes(job, queue),\n links,\n },\n baseContext\n )\n\n if (job.createdAt) {\n span.setAttribute('messaging.job.queue_time_ms', Date.now() - job.createdAt)\n }\n\n this.executeSpans.set(job.id, span)\n const executionContext = trace.setSpan(baseContext, span)\n\n return context.with(executionContext, fn)\n }\n\n #handleExecuteAsyncEnd(message: JobExecuteMessage) {\n const span = this.executeSpans.get(message.job.id)\n if (!span) return\n\n if (message.status) span.setAttribute('messaging.job.status', message.status)\n if (message.error) span.recordException(message.error)\n\n if (message.status === 'retrying' && message.nextRetryAt) {\n span.addEvent('messaging.retry', {\n 'messaging.message.retry.count': message.job.attempts + 1,\n 'messaging.job.retry_at': message.nextRetryAt.toISOString(),\n })\n }\n\n if (message.status === 'failed') {\n span.setStatus({ code: SpanStatusCode.ERROR, message: message.error?.message })\n } else {\n span.setStatus({ code: SpanStatusCode.OK })\n }\n\n span.end()\n this.executeSpans.delete(message.job.id)\n }\n\n #extractParentContext(traceContext?: Record<string, string>) {\n if (!traceContext || Object.keys(traceContext).length === 0) return ROOT_CONTEXT\n return propagation.extract(ROOT_CONTEXT, traceContext)\n }\n\n #buildDispatchAttributes(message: JobDispatchMessage) {\n const firstJob = message.jobs[0]\n const attributes: Record<string, string | number | boolean> = {\n 'messaging.system': this.#messagingSystem,\n 'messaging.operation.name': 'publish',\n 'messaging.operation.type': 'send',\n 'messaging.destination.name': message.queue,\n 'messaging.job.name': firstJob.name,\n }\n\n if (message.jobs.length === 1) attributes['messaging.message.id'] = firstJob.id\n if (message.jobs.length > 1) attributes['messaging.batch.message_count'] = message.jobs.length\n if (firstJob.groupId) attributes['messaging.job.group_id'] = firstJob.groupId\n if (firstJob.priority !== undefined) attributes['messaging.job.priority'] = firstJob.priority\n if (message.delay !== undefined) attributes['messaging.job.delay_ms'] = message.delay\n\n return attributes\n }\n\n #buildExecuteAttributes(job: AcquiredJob, queue: string) {\n const attributes: Record<string, string | number | boolean> = {\n 'entry_point.type': 'job',\n 'messaging.system': this.#messagingSystem,\n 'messaging.operation.name': 'process',\n 'messaging.operation.type': 'process',\n 'messaging.destination.name': queue,\n 'messaging.message.id': job.id,\n 'messaging.message.retry.count': job.attempts,\n 'messaging.job.name': job.name,\n }\n\n if (job.groupId) attributes['messaging.job.group_id'] = job.groupId\n if (job.priority !== undefined) attributes['messaging.job.priority'] = job.priority\n\n return attributes\n }\n}\n"],"mappings":"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","names":[]}
@@ -1 +1,6 @@
1
- export { b as AcquiredJob, A as Adapter, x as AdapterFactory, v as BackoffConfig, B as BackoffStrategy, t as DispatchManyResult, s as DispatchResult, D as Duration, a as JobClass, u as JobContext, J as JobData, i as JobFactory, g as JobOptions, d as JobRecord, c as JobRetention, r as JobStatus, L as Logger, h as QueueConfig, Q as QueueManagerConfig, R as RetryConfig, S as ScheduleConfig, e as ScheduleData, f as ScheduleListOptions, y as ScheduleResult, k as ScheduleStatus, w as WorkerConfig, W as WorkerCycle } from '../../index-B1XdqWpN.js';
1
+ export { b as AcquiredJob, A as Adapter, r as AdapterFactory, B as BackoffConfig, s as BackoffStrategy, t as DispatchManyResult, u as DispatchResult, D as Duration, a as JobClass, v as JobContext, J as JobData, i as JobFactory, g as JobOptions, d as JobRecord, c as JobRetention, w as JobStatus, L as Logger, h as QueueConfig, Q as QueueManagerConfig, R as RetryConfig, S as ScheduleConfig, e as ScheduleData, f as ScheduleListOptions, x as ScheduleResult, k as ScheduleStatus, y as WorkerConfig, W as WorkerCycle } from '../../job-Z5fBSzRX.js';
2
+ export { JobDispatchMessage, JobExecuteMessage } from './tracing_channels.js';
3
+ export { QueueInstrumentationConfig } from '../otel.js';
4
+ import '@opentelemetry/api';
5
+ import 'node:diagnostics_channel';
6
+ import '@opentelemetry/instrumentation';
@@ -1 +1 @@
1
- export { x as AdapterFactory, v as BackoffConfig, B as BackoffStrategy, t as DispatchManyResult, s as DispatchResult, D as Duration, a as JobClass, u as JobContext, J as JobData, i as JobFactory, g as JobOptions, d as JobRecord, c as JobRetention, r as JobStatus, L as Logger, h as QueueConfig, Q as QueueManagerConfig, R as RetryConfig, S as ScheduleConfig, e as ScheduleData, f as ScheduleListOptions, y as ScheduleResult, k as ScheduleStatus, w as WorkerConfig, W as WorkerCycle } from '../../index-B1XdqWpN.js';
1
+ export { r as AdapterFactory, B as BackoffConfig, s as BackoffStrategy, t as DispatchManyResult, u as DispatchResult, D as Duration, a as JobClass, v as JobContext, J as JobData, i as JobFactory, g as JobOptions, d as JobRecord, c as JobRetention, w as JobStatus, L as Logger, h as QueueConfig, Q as QueueManagerConfig, R as RetryConfig, S as ScheduleConfig, e as ScheduleData, f as ScheduleListOptions, x as ScheduleResult, k as ScheduleStatus, y as WorkerConfig, W as WorkerCycle } from '../../job-Z5fBSzRX.js';
@@ -0,0 +1,34 @@
1
+ import { J as JobData, b as AcquiredJob } from '../../job-Z5fBSzRX.js';
2
+
3
+ /**
4
+ * Tracing data structure for job dispatch events.
5
+ */
6
+ type JobDispatchMessage = {
7
+ /** The jobs being dispatched (single dispatch = array of one) */
8
+ jobs: JobData[];
9
+ /** Target queue name */
10
+ queue: string;
11
+ /** Delay in milliseconds before the job becomes available */
12
+ delay?: number;
13
+ /** Error that caused the dispatch to fail */
14
+ error?: Error;
15
+ };
16
+ /**
17
+ * Tracing data structure for job execution events.
18
+ */
19
+ type JobExecuteMessage = {
20
+ /** The acquired job being executed */
21
+ job: AcquiredJob;
22
+ /** Queue the job was acquired from */
23
+ queue: string;
24
+ /** Execution outcome (set in asyncEnd) */
25
+ status?: 'completed' | 'failed' | 'retrying';
26
+ /** Execution duration in milliseconds (set in asyncEnd) */
27
+ duration?: number;
28
+ /** Error that caused the failure (set in asyncEnd) */
29
+ error?: Error;
30
+ /** When the next retry is scheduled (set in asyncEnd for retrying jobs) */
31
+ nextRetryAt?: Date;
32
+ };
33
+
34
+ export type { JobDispatchMessage, JobExecuteMessage };
@@ -0,0 +1 @@
1
+ //# sourceMappingURL=tracing_channels.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@boringnode/queue",
3
3
  "description": "A simple and efficient queue system for Node.js applications",
4
- "version": "0.5.0",
4
+ "version": "0.5.2",
5
5
  "main": "build/index.js",
6
6
  "type": "module",
7
7
  "files": [
@@ -9,6 +9,7 @@
9
9
  ],
10
10
  "exports": {
11
11
  ".": "./build/index.js",
12
+ "./otel": "./build/src/otel.js",
12
13
  "./drivers/*": "./build/src/drivers/*.js",
13
14
  "./contracts/*": "./build/src/contracts/*.js",
14
15
  "./types": "./build/src/types/index.js"
@@ -40,29 +41,46 @@
40
41
  "@japa/expect-type": "^2.0.4",
41
42
  "@japa/file-system": "^3.0.0",
42
43
  "@japa/runner": "^5.3.0",
44
+ "@opentelemetry/api": "^1.9.0",
45
+ "@opentelemetry/context-async-hooks": "^2.6.0",
46
+ "@opentelemetry/core": "^2.6.0",
47
+ "@opentelemetry/instrumentation": "^0.213.0",
48
+ "@opentelemetry/sdk-trace-base": "^2.6.0",
43
49
  "@poppinss/ts-exec": "^1.4.4",
44
50
  "@types/better-sqlite3": "^7.6.13",
45
- "@types/node": "^24.11.0",
46
- "@types/pg": "^8.18.0",
47
- "better-sqlite3": "^12.6.2",
48
- "bullmq": "^5.70.1",
51
+ "@types/node": "^25.5.0",
52
+ "@types/pg": "^8.20.0",
53
+ "better-sqlite3": "^12.8.0",
54
+ "bullmq": "^5.71.0",
49
55
  "c8": "^11.0.0",
50
56
  "del-cli": "^7.0.0",
51
- "ioredis": "^5.10.0",
52
- "knex": "^3.1.0",
53
- "oxfmt": "^0.36.0",
54
- "oxlint": "^1.51.0",
55
- "oxlint-tsgolint": "^0.15.0",
56
- "pg": "^8.19.0",
57
+ "ioredis": "^5.10.1",
58
+ "knex": "3.1.0",
59
+ "oxfmt": "^0.41.0",
60
+ "oxlint": "^1.56.0",
61
+ "oxlint-tsgolint": "^0.17.1",
62
+ "pg": "^8.20.0",
57
63
  "release-it": "^19.2.4",
58
64
  "tsup": "^8.5.1",
59
65
  "typescript": "^5.9.3"
60
66
  },
61
67
  "peerDependencies": {
68
+ "@opentelemetry/api": "^1.9.0",
69
+ "@opentelemetry/core": "^1.30.0 || ^2.0.0",
70
+ "@opentelemetry/instrumentation": "^0.200.0",
62
71
  "ioredis": "^5.0.0",
63
72
  "knex": "^3.0.0"
64
73
  },
65
74
  "peerDependenciesMeta": {
75
+ "@opentelemetry/api": {
76
+ "optional": true
77
+ },
78
+ "@opentelemetry/core": {
79
+ "optional": true
80
+ },
81
+ "@opentelemetry/instrumentation": {
82
+ "optional": true
83
+ },
66
84
  "ioredis": {
67
85
  "optional": true
68
86
  },
@@ -89,7 +107,8 @@
89
107
  ],
90
108
  "publishConfig": {
91
109
  "access": "public",
92
- "tag": "latest"
110
+ "tag": "latest",
111
+ "provenance": true
93
112
  },
94
113
  "release-it": {
95
114
  "git": {
@@ -99,8 +118,11 @@
99
118
  },
100
119
  "github": {
101
120
  "release": true,
102
- "releaseName": "v${version}",
103
- "web": true
121
+ "releaseName": "v${version}"
122
+ },
123
+ "npm": {
124
+ "publish": true,
125
+ "skipChecks": true
104
126
  }
105
127
  },
106
128
  "packageManager": "yarn@4.12.0",