@sentry/junior 0.9.3 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,678 +0,0 @@
1
- import {
2
- DeferredThreadMessageError,
3
- buildDeterministicTurnId,
4
- coerceThreadConversationState,
5
- createQueueCallbackHandler,
6
- downloadPrivateSlackFile,
7
- getThreadMessageTopic,
8
- removeReactionFromMessage,
9
- slackRuntime
10
- } from "./chunk-LWHXDHIN.js";
11
- import {
12
- getConnectedStateContext,
13
- getStateAdapter
14
- } from "./chunk-HRA2FXYH.js";
15
- import {
16
- createRequestContext,
17
- logError,
18
- logException,
19
- logInfo,
20
- logWarn,
21
- setSpanStatus,
22
- withContext,
23
- withSpan
24
- } from "./chunk-ZW4OVKF5.js";
25
-
26
- // src/chat/queue/process-thread-message.ts
27
- import { Message, ThreadImpl } from "chat";
28
-
29
- // src/chat/state/queue-processing-store.ts
30
- var QUEUE_MESSAGE_PROCESSING_PREFIX = "junior:queue_message";
31
- var QUEUE_MESSAGE_PROCESSING_TTL_MS = 30 * 60 * 1e3;
32
- var QUEUE_MESSAGE_COMPLETED_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
33
- var QUEUE_MESSAGE_FAILED_TTL_MS = 6 * 60 * 60 * 1e3;
34
- var CLAIM_OR_RECLAIM_PROCESSING_SCRIPT = `
35
- local key = KEYS[1]
36
- local nowMs = tonumber(ARGV[1])
37
- local ttlMs = tonumber(ARGV[2])
38
- local payload = ARGV[3]
39
- local current = redis.call("get", key)
40
-
41
- if not current then
42
- redis.call("set", key, payload, "PX", ttlMs)
43
- return 1
44
- end
45
-
46
- local ok, parsed = pcall(cjson.decode, current)
47
- if not ok or type(parsed) ~= "table" then
48
- return 0
49
- end
50
-
51
- local status = parsed["status"]
52
- if status == "failed" then
53
- redis.call("set", key, payload, "PX", ttlMs)
54
- return 3
55
- end
56
- if status ~= "processing" then
57
- return 0
58
- end
59
-
60
- local updatedAtMs = tonumber(parsed["updatedAtMs"])
61
- if not updatedAtMs then
62
- return 0
63
- end
64
-
65
- if updatedAtMs + ttlMs < nowMs then
66
- redis.call("set", key, payload, "PX", ttlMs)
67
- return 2
68
- end
69
-
70
- return 0
71
- `;
72
- var UPDATE_PROCESSING_STATE_IF_OWNER_SCRIPT = `
73
- local key = KEYS[1]
74
- local ownerToken = ARGV[1]
75
- local ttlMs = tonumber(ARGV[2])
76
- local payload = ARGV[3]
77
- local current = redis.call("get", key)
78
-
79
- if not current then
80
- return 0
81
- end
82
-
83
- local ok, parsed = pcall(cjson.decode, current)
84
- if not ok or type(parsed) ~= "table" then
85
- return 0
86
- end
87
-
88
- local currentOwner = parsed["ownerToken"]
89
- local status = parsed["status"]
90
- if currentOwner ~= ownerToken then
91
- return 0
92
- end
93
- if status ~= "processing" then
94
- return 0
95
- end
96
-
97
- redis.call("set", key, payload, "PX", ttlMs)
98
- return 1
99
- `;
100
- function queueMessageKey(rawKey) {
101
- return `${QUEUE_MESSAGE_PROCESSING_PREFIX}:${rawKey}`;
102
- }
103
- function buildQueueMessageProcessingPayload(args) {
104
- return JSON.stringify({
105
- status: args.status,
106
- updatedAtMs: args.updatedAtMs ?? Date.now(),
107
- ownerToken: args.ownerToken,
108
- ...args.errorMessage ? { errorMessage: args.errorMessage } : {},
109
- ...args.queueMessageId ? { queueMessageId: args.queueMessageId } : {}
110
- });
111
- }
112
- function parseQueueMessageState(value) {
113
- if (typeof value !== "string") {
114
- return void 0;
115
- }
116
- try {
117
- const parsed = JSON.parse(value);
118
- if (!parsed || parsed.status !== "processing" && parsed.status !== "completed" && parsed.status !== "failed" || typeof parsed.updatedAtMs !== "number") {
119
- return void 0;
120
- }
121
- return {
122
- status: parsed.status,
123
- updatedAtMs: parsed.updatedAtMs,
124
- ...typeof parsed.ownerToken === "string" ? { ownerToken: parsed.ownerToken } : {},
125
- ...typeof parsed.queueMessageId === "string" ? { queueMessageId: parsed.queueMessageId } : {},
126
- ...typeof parsed.errorMessage === "string" ? { errorMessage: parsed.errorMessage } : {}
127
- };
128
- } catch {
129
- return void 0;
130
- }
131
- }
132
- async function updateQueueMessageProcessingStateIfOwner(args) {
133
- const existingState = parseQueueMessageState(
134
- await args.stateAdapter.get(queueMessageKey(args.rawKey))
135
- );
136
- if (!existingState || existingState.status !== "processing" || existingState.ownerToken !== args.ownerToken) {
137
- return false;
138
- }
139
- await args.stateAdapter.set(
140
- queueMessageKey(args.rawKey),
141
- args.payload,
142
- args.ttlMs
143
- );
144
- return true;
145
- }
146
- async function getQueueMessageProcessingState(rawKey) {
147
- const adapter = getStateAdapter();
148
- await adapter.connect();
149
- const state = await adapter.get(queueMessageKey(rawKey));
150
- return parseQueueMessageState(state);
151
- }
152
- async function acquireQueueMessageProcessingOwnership(args) {
153
- const { stateAdapter, redisStateAdapter } = await getConnectedStateContext();
154
- const key = queueMessageKey(args.rawKey);
155
- const nowMs = Date.now();
156
- const payload = buildQueueMessageProcessingPayload({
157
- ownerToken: args.ownerToken,
158
- queueMessageId: args.queueMessageId,
159
- status: "processing",
160
- updatedAtMs: nowMs
161
- });
162
- if (redisStateAdapter) {
163
- const result = await redisStateAdapter.getClient().eval(CLAIM_OR_RECLAIM_PROCESSING_SCRIPT, {
164
- keys: [key],
165
- arguments: [
166
- String(nowMs),
167
- String(QUEUE_MESSAGE_PROCESSING_TTL_MS),
168
- payload
169
- ]
170
- });
171
- if (result === 1) {
172
- return "acquired";
173
- }
174
- if (result === 2) {
175
- return "reclaimed";
176
- }
177
- if (result === 3) {
178
- return "recovered";
179
- }
180
- return "blocked";
181
- }
182
- const existingState = parseQueueMessageState(await stateAdapter.get(key));
183
- if (!existingState) {
184
- const claimed = await stateAdapter.setIfNotExists(
185
- key,
186
- payload,
187
- QUEUE_MESSAGE_PROCESSING_TTL_MS
188
- );
189
- return claimed ? "acquired" : "blocked";
190
- }
191
- if (existingState.status === "failed") {
192
- await stateAdapter.set(key, payload, QUEUE_MESSAGE_PROCESSING_TTL_MS);
193
- return "recovered";
194
- }
195
- if (existingState.status === "processing" && existingState.updatedAtMs + QUEUE_MESSAGE_PROCESSING_TTL_MS < nowMs) {
196
- await stateAdapter.set(key, payload, QUEUE_MESSAGE_PROCESSING_TTL_MS);
197
- return "reclaimed";
198
- }
199
- return "blocked";
200
- }
201
- async function refreshQueueMessageProcessingOwnership(args) {
202
- const { stateAdapter, redisStateAdapter } = await getConnectedStateContext();
203
- const payload = buildQueueMessageProcessingPayload({
204
- ownerToken: args.ownerToken,
205
- queueMessageId: args.queueMessageId,
206
- status: "processing"
207
- });
208
- if (redisStateAdapter) {
209
- const result = await redisStateAdapter.getClient().eval(UPDATE_PROCESSING_STATE_IF_OWNER_SCRIPT, {
210
- keys: [queueMessageKey(args.rawKey)],
211
- arguments: [
212
- args.ownerToken,
213
- String(QUEUE_MESSAGE_PROCESSING_TTL_MS),
214
- payload
215
- ]
216
- });
217
- return result === 1;
218
- }
219
- return await updateQueueMessageProcessingStateIfOwner({
220
- rawKey: args.rawKey,
221
- ownerToken: args.ownerToken,
222
- payload,
223
- ttlMs: QUEUE_MESSAGE_PROCESSING_TTL_MS,
224
- stateAdapter
225
- });
226
- }
227
- async function completeQueueMessageProcessingOwnership(args) {
228
- const { stateAdapter, redisStateAdapter } = await getConnectedStateContext();
229
- const payload = buildQueueMessageProcessingPayload({
230
- ownerToken: args.ownerToken,
231
- queueMessageId: args.queueMessageId,
232
- status: "completed"
233
- });
234
- if (redisStateAdapter) {
235
- const result = await redisStateAdapter.getClient().eval(UPDATE_PROCESSING_STATE_IF_OWNER_SCRIPT, {
236
- keys: [queueMessageKey(args.rawKey)],
237
- arguments: [
238
- args.ownerToken,
239
- String(QUEUE_MESSAGE_COMPLETED_TTL_MS),
240
- payload
241
- ]
242
- });
243
- return result === 1;
244
- }
245
- return await updateQueueMessageProcessingStateIfOwner({
246
- rawKey: args.rawKey,
247
- ownerToken: args.ownerToken,
248
- payload,
249
- ttlMs: QUEUE_MESSAGE_COMPLETED_TTL_MS,
250
- stateAdapter
251
- });
252
- }
253
- async function failQueueMessageProcessingOwnership(args) {
254
- const { stateAdapter, redisStateAdapter } = await getConnectedStateContext();
255
- const payload = buildQueueMessageProcessingPayload({
256
- errorMessage: args.errorMessage,
257
- ownerToken: args.ownerToken,
258
- queueMessageId: args.queueMessageId,
259
- status: "failed"
260
- });
261
- if (redisStateAdapter) {
262
- const result = await redisStateAdapter.getClient().eval(UPDATE_PROCESSING_STATE_IF_OWNER_SCRIPT, {
263
- keys: [queueMessageKey(args.rawKey)],
264
- arguments: [
265
- args.ownerToken,
266
- String(QUEUE_MESSAGE_FAILED_TTL_MS),
267
- payload
268
- ]
269
- });
270
- return result === 1;
271
- }
272
- return await updateQueueMessageProcessingStateIfOwner({
273
- rawKey: args.rawKey,
274
- ownerToken: args.ownerToken,
275
- payload,
276
- ttlMs: QUEUE_MESSAGE_FAILED_TTL_MS,
277
- stateAdapter
278
- });
279
- }
280
-
281
- // src/chat/queue/process-thread-message.ts
282
- var THREAD_PROCESSING_LOCK_TTL_MS = 5 * 60 * 1e3;
283
- var THREAD_PROCESSING_LOCK_HEARTBEAT_MS = 60 * 1e3;
284
- function isSerializedThread(thread) {
285
- return typeof thread === "object" && thread !== null && thread._type === "chat:Thread";
286
- }
287
- function isSerializedMessage(message) {
288
- return typeof message === "object" && message !== null && message._type === "chat:Message";
289
- }
290
- function getPayloadChannelId(payload) {
291
- return payload.thread.channelId;
292
- }
293
- function getPayloadUserId(payload) {
294
- return payload.message.author?.userId;
295
- }
296
- function createMessageOwnerToken() {
297
- return `msg-${Date.now()}-${Math.random().toString(16).slice(2)}`;
298
- }
299
- var QueueMessageOwnershipError = class extends Error {
300
- constructor(stage, dedupKey) {
301
- super(
302
- `Queue message ownership lost during ${stage} for dedupKey=${dedupKey}`
303
- );
304
- this.name = "QueueMessageOwnershipError";
305
- }
306
- };
307
- var defaultProcessQueuedThreadMessageDeps = {
308
- clearProcessingReaction: async ({
309
- channelId,
310
- timestamp
311
- }) => {
312
- await removeReactionFromMessage({
313
- channelId,
314
- timestamp,
315
- emoji: "eyes"
316
- });
317
- },
318
- logInfo,
319
- logWarn
320
- };
321
- function resolveDeps(deps) {
322
- return {
323
- ...defaultProcessQueuedThreadMessageDeps,
324
- ...deps
325
- };
326
- }
327
- function deserializeThread(thread) {
328
- if (isSerializedThread(thread)) {
329
- return ThreadImpl.fromJSON(thread);
330
- }
331
- return thread;
332
- }
333
- function deserializeMessage(message) {
334
- if (isSerializedMessage(message)) {
335
- return Message.fromJSON(message);
336
- }
337
- return message;
338
- }
339
- async function logThreadMessageFailure(payload, errorMessage) {
340
- logError(
341
- "queue_message_failed",
342
- {
343
- slackThreadId: payload.normalizedThreadId,
344
- slackChannelId: getPayloadChannelId(payload),
345
- slackUserId: getPayloadUserId(payload)
346
- },
347
- {
348
- "messaging.message.id": payload.message.id,
349
- "app.queue.message_kind": payload.kind,
350
- "app.queue.message_id": payload.queueMessageId,
351
- "error.message": errorMessage
352
- },
353
- "Queue message processing failed"
354
- );
355
- }
356
- async function processQueuedThreadMessage(payload, deps) {
357
- const resolvedDeps = resolveDeps(deps);
358
- const existingMessageState = await getQueueMessageProcessingState(
359
- payload.dedupKey
360
- );
361
- if (existingMessageState?.status === "completed") {
362
- resolvedDeps.logInfo(
363
- "queue_message_skipped_completed",
364
- {
365
- slackThreadId: payload.normalizedThreadId,
366
- slackChannelId: getPayloadChannelId(payload),
367
- slackUserId: getPayloadUserId(payload)
368
- },
369
- {
370
- "messaging.message.id": payload.message.id,
371
- "app.queue.message_kind": payload.kind,
372
- "app.queue.message_id": payload.queueMessageId,
373
- "app.queue.processing_state": existingMessageState.status
374
- },
375
- "Skipping queue message because it is already completed"
376
- );
377
- return;
378
- }
379
- const state = getStateAdapter();
380
- await state.connect();
381
- const threadLock = await state.acquireLock(
382
- payload.normalizedThreadId,
383
- THREAD_PROCESSING_LOCK_TTL_MS
384
- );
385
- if (!threadLock) {
386
- resolvedDeps.logInfo(
387
- "queue_message_deferred_thread_locked",
388
- {
389
- slackThreadId: payload.normalizedThreadId,
390
- slackChannelId: getPayloadChannelId(payload),
391
- slackUserId: getPayloadUserId(payload)
392
- },
393
- {
394
- "messaging.message.id": payload.message.id,
395
- "app.queue.message_kind": payload.kind,
396
- "app.queue.message_id": payload.queueMessageId
397
- },
398
- "Deferring queue message because another turn already owns the thread lock"
399
- );
400
- throw new DeferredThreadMessageError(
401
- "thread_locked",
402
- payload.normalizedThreadId
403
- );
404
- }
405
- const threadLockHeartbeat = startThreadLockHeartbeat({
406
- lock: threadLock,
407
- state,
408
- payload,
409
- logWarn: resolvedDeps.logWarn
410
- });
411
- try {
412
- const runtimePayload = {
413
- ...payload,
414
- thread: deserializeThread(payload.thread),
415
- message: deserializeMessage(payload.message)
416
- };
417
- const currentTurnId = buildDeterministicTurnId(runtimePayload.message.id);
418
- const activeTurnId = coerceThreadConversationState(
419
- await runtimePayload.thread.state
420
- ).processing.activeTurnId;
421
- if (activeTurnId && activeTurnId !== currentTurnId) {
422
- resolvedDeps.logInfo(
423
- "queue_message_deferred_active_turn",
424
- {
425
- slackThreadId: payload.normalizedThreadId,
426
- slackChannelId: getPayloadChannelId(payload),
427
- slackUserId: getPayloadUserId(payload)
428
- },
429
- {
430
- "messaging.message.id": payload.message.id,
431
- "app.queue.message_kind": payload.kind,
432
- "app.queue.message_id": payload.queueMessageId,
433
- "app.thread.active_turn_id": activeTurnId,
434
- "app.thread.current_turn_id": currentTurnId
435
- },
436
- "Deferring queue message because another turn is still active for the thread"
437
- );
438
- throw new DeferredThreadMessageError(
439
- "active_turn",
440
- payload.normalizedThreadId,
441
- {
442
- activeTurnId,
443
- currentTurnId
444
- }
445
- );
446
- }
447
- const ownerToken = createMessageOwnerToken();
448
- const claimResult = await acquireQueueMessageProcessingOwnership({
449
- rawKey: payload.dedupKey,
450
- ownerToken,
451
- queueMessageId: payload.queueMessageId
452
- });
453
- if (claimResult === "blocked") {
454
- resolvedDeps.logInfo(
455
- "queue_message_skipped_blocked",
456
- {
457
- slackThreadId: payload.normalizedThreadId,
458
- slackChannelId: getPayloadChannelId(payload),
459
- slackUserId: getPayloadUserId(payload)
460
- },
461
- {
462
- "messaging.message.id": payload.message.id,
463
- "app.queue.message_kind": payload.kind,
464
- "app.queue.message_id": payload.queueMessageId,
465
- "app.queue.claim_result": claimResult,
466
- "app.queue.processing_state": "processing"
467
- },
468
- "Skipping queue message because another worker owns it"
469
- );
470
- return;
471
- }
472
- let reactionCleared = false;
473
- const clearProcessingReaction = async () => {
474
- if (reactionCleared) {
475
- return;
476
- }
477
- reactionCleared = true;
478
- try {
479
- await resolvedDeps.clearProcessingReaction({
480
- channelId: runtimePayload.thread.channelId,
481
- timestamp: runtimePayload.message.id
482
- });
483
- } catch (error) {
484
- const errorMessage = error instanceof Error ? error.message : String(error);
485
- resolvedDeps.logWarn(
486
- "queue_processing_reaction_clear_failed",
487
- {
488
- slackThreadId: payload.normalizedThreadId,
489
- slackChannelId: getPayloadChannelId(payload),
490
- slackUserId: getPayloadUserId(payload)
491
- },
492
- {
493
- "messaging.message.id": payload.message.id,
494
- "app.queue.message_kind": payload.kind,
495
- "app.queue.message_id": payload.queueMessageId,
496
- "error.message": errorMessage
497
- },
498
- "Failed to remove processing reaction after queue turn completion"
499
- );
500
- }
501
- };
502
- try {
503
- const refreshed = await refreshQueueMessageProcessingOwnership({
504
- rawKey: payload.dedupKey,
505
- ownerToken,
506
- queueMessageId: payload.queueMessageId
507
- });
508
- if (!refreshed) {
509
- throw new QueueMessageOwnershipError("refresh", payload.dedupKey);
510
- }
511
- await resolvedDeps.dispatch({
512
- kind: runtimePayload.kind,
513
- thread: runtimePayload.thread,
514
- message: runtimePayload.message
515
- });
516
- await clearProcessingReaction();
517
- const completed = await completeQueueMessageProcessingOwnership({
518
- rawKey: payload.dedupKey,
519
- ownerToken,
520
- queueMessageId: payload.queueMessageId
521
- });
522
- if (!completed) {
523
- throw new QueueMessageOwnershipError("complete", payload.dedupKey);
524
- }
525
- } catch (error) {
526
- const errorMessage = error instanceof Error ? error.message : String(error);
527
- await clearProcessingReaction();
528
- await logThreadMessageFailure(payload, errorMessage);
529
- const failed = await failQueueMessageProcessingOwnership({
530
- rawKey: payload.dedupKey,
531
- ownerToken,
532
- errorMessage,
533
- queueMessageId: payload.queueMessageId
534
- });
535
- if (!failed && !(error instanceof QueueMessageOwnershipError)) {
536
- throw new Error(
537
- `Failed to persist queue message failure state for dedupKey=${payload.dedupKey}: ${errorMessage}`
538
- );
539
- }
540
- throw error;
541
- }
542
- } finally {
543
- await threadLockHeartbeat.stop();
544
- }
545
- }
546
- function startThreadLockHeartbeat(args) {
547
- const interval = setInterval(() => {
548
- void args.state.extendLock(args.lock, THREAD_PROCESSING_LOCK_TTL_MS).catch((error) => {
549
- const errorMessage = error instanceof Error ? error.message : String(error);
550
- args.logWarn(
551
- "queue_thread_lock_extend_failed",
552
- {
553
- slackThreadId: args.payload.normalizedThreadId,
554
- slackChannelId: getPayloadChannelId(args.payload),
555
- slackUserId: getPayloadUserId(args.payload)
556
- },
557
- {
558
- "messaging.message.id": args.payload.message.id,
559
- "app.queue.message_kind": args.payload.kind,
560
- "app.queue.message_id": args.payload.queueMessageId,
561
- "error.message": errorMessage
562
- },
563
- "Failed to extend thread-processing lock during queue execution"
564
- );
565
- });
566
- }, THREAD_PROCESSING_LOCK_HEARTBEAT_MS);
567
- interval.unref?.();
568
- return {
569
- stop: async () => {
570
- clearInterval(interval);
571
- await args.state.releaseLock(args.lock);
572
- }
573
- };
574
- }
575
-
576
- // src/chat/queue/thread-message-dispatcher.ts
577
- function rehydrateAttachmentFetchers(message, downloadPrivateSlackFile2) {
578
- for (const attachment of message.attachments) {
579
- if (!attachment.fetchData && attachment.url) {
580
- attachment.fetchData = () => downloadPrivateSlackFile2(attachment.url);
581
- }
582
- }
583
- }
584
- function createThreadMessageDispatcher(options) {
585
- const downloadPrivateSlackFile2 = options.downloadPrivateSlackFile ?? downloadPrivateSlackFile;
586
- return async function dispatch2(args) {
587
- rehydrateAttachmentFetchers(args.message, downloadPrivateSlackFile2);
588
- if (args.kind === "new_mention") {
589
- await options.runtime.handleNewMention(args.thread, args.message, {
590
- beforeFirstResponsePost: args.beforeFirstResponsePost
591
- });
592
- return;
593
- }
594
- await options.runtime.handleSubscribedMessage(args.thread, args.message, {
595
- beforeFirstResponsePost: args.beforeFirstResponsePost
596
- });
597
- };
598
- }
599
-
600
- // src/handlers/queue-callback.ts
601
- var dispatch = createThreadMessageDispatcher({
602
- runtime: slackRuntime
603
- });
604
- var callbackHandler = createQueueCallbackHandler(
605
- async (message, metadata) => {
606
- if (metadata.topicName === getThreadMessageTopic()) {
607
- const payload = {
608
- ...message,
609
- queueMessageId: metadata.messageId
610
- };
611
- logInfo(
612
- "queue_callback_received",
613
- {
614
- slackThreadId: payload.normalizedThreadId,
615
- slackChannelId: payload.thread.channelId,
616
- slackUserId: payload.message.author?.userId
617
- },
618
- {
619
- "messaging.message.id": payload.message.id,
620
- "app.queue.message_kind": payload.kind,
621
- "app.queue.message_id": payload.queueMessageId,
622
- "app.queue.delivery_count": metadata.deliveryCount,
623
- "app.queue.topic": metadata.topicName
624
- },
625
- "Received queue callback payload"
626
- );
627
- await withSpan(
628
- "queue.process_message",
629
- "queue.process_message",
630
- {
631
- slackThreadId: payload.normalizedThreadId,
632
- slackChannelId: payload.thread.channelId,
633
- slackUserId: payload.message.author?.userId
634
- },
635
- async () => {
636
- await processQueuedThreadMessage(payload, {
637
- dispatch
638
- });
639
- },
640
- {
641
- "messaging.message.id": payload.message.id,
642
- "app.queue.message_kind": payload.kind,
643
- "app.queue.message_id": payload.queueMessageId,
644
- "app.queue.delivery_count": metadata.deliveryCount,
645
- "app.queue.topic": metadata.topicName
646
- }
647
- );
648
- return;
649
- }
650
- throw new Error(`Unexpected queue topic: ${metadata.topicName}`);
651
- }
652
- );
653
- async function POST(request) {
654
- const requestContext = createRequestContext(request, { platform: "queue" });
655
- return withContext(requestContext, async () => {
656
- try {
657
- const response = await callbackHandler(request);
658
- setSpanStatus(response.status >= 500 ? "error" : "ok");
659
- return response;
660
- } catch (error) {
661
- const message = error instanceof Error ? error.message : String(error);
662
- logError(
663
- "queue_callback_failed",
664
- {},
665
- {
666
- "error.message": message
667
- },
668
- "Queue callback processing failed"
669
- );
670
- logException(error, "queue_callback_failed");
671
- throw error;
672
- }
673
- });
674
- }
675
-
676
- export {
677
- POST
678
- };