@sentry/junior 0.179.0 → 0.180.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.
- package/dist/{agent-hooks-32IDCLMW.js → agent-hooks-DKDDRKZA.js} +16 -18
- package/dist/api/schema.js +0 -1
- package/dist/api.js +199 -197
- package/dist/app.d.ts +4 -0
- package/dist/app.js +300 -1259
- package/dist/catalog-runtime-WXKGUF3W.js +14 -0
- package/dist/chat/agent/sandbox.d.ts +0 -2
- package/dist/chat/api-turns/routing.d.ts +4 -0
- package/dist/chat/api-turns/work.d.ts +5 -0
- package/dist/chat/config.d.ts +5 -2
- package/dist/chat/configuration/defaults.d.ts +1 -1
- package/dist/chat/conversations/projection.d.ts +6 -4
- package/dist/chat/ingress/message-router.d.ts +3 -0
- package/dist/chat/model-profile.d.ts +8 -10
- package/dist/chat/pi/conversation-events.d.ts +3 -2
- package/dist/chat/plugins/task-queue.d.ts +40 -3
- package/dist/chat/plugins/task-runner.d.ts +1 -1
- package/dist/chat/queue/callback.d.ts +26 -0
- package/dist/chat/queue/sign.d.ts +30 -0
- package/dist/chat/sandbox/sandbox.d.ts +0 -2
- package/dist/chat/sandbox/session.d.ts +0 -2
- package/dist/chat/sandbox/skill-sync.d.ts +1 -1
- package/dist/chat/sandbox/snapshot/events.d.ts +23 -0
- package/dist/chat/sandbox/snapshot/job-callback.d.ts +5 -0
- package/dist/chat/sandbox/snapshot/job-queue.d.ts +26 -0
- package/dist/chat/sandbox/snapshot/job-runner.d.ts +11 -0
- package/dist/chat/sandbox/snapshot/not-ready-error.d.ts +6 -0
- package/dist/chat/sandbox/snapshot/workspace.d.ts +9 -3
- package/dist/chat/services/turn-router.d.ts +4 -3
- package/dist/chat/task-execution/queue-signing.d.ts +10 -21
- package/dist/chat/task-execution/state.d.ts +48 -0
- package/dist/chat/task-execution/store.d.ts +28 -2
- package/dist/chat/task-execution/worker.d.ts +4 -1
- package/dist/chat/tools/handoff/tool.d.ts +1 -1
- package/dist/{chunk-B6ECUSVX.js → chunk-2AYEVN7K.js} +8 -8
- package/dist/{chunk-SLGGOASN.js → chunk-2YIRH4E3.js} +46 -46
- package/dist/{chunk-KJLHIHFF.js → chunk-3ILJBWP7.js} +35 -227
- package/dist/{chunk-RZRYOLCE.js → chunk-5PUMIMNQ.js} +2292 -1147
- package/dist/{chunk-CJLBLELR.js → chunk-5TUR4M3M.js} +8 -61
- package/dist/{chunk-6ZWRNC4D.js → chunk-6Y5B5PEX.js} +1 -1
- package/dist/{chunk-XSPSCWLH.js → chunk-6YCEWOLO.js} +4 -4
- package/dist/chunk-7H2VZTWN.js +103 -0
- package/dist/{chunk-FAS6AIMF.js → chunk-CCDXTDSY.js} +8 -8
- package/dist/{chunk-CGA4ERJ5.js → chunk-CEMMLV5L.js} +1 -1
- package/dist/{chunk-XZY6G5YZ.js → chunk-CK6EINVZ.js} +180 -87
- package/dist/{chunk-FIANEE7Z.js → chunk-CM5HNV2W.js} +6 -6
- package/dist/{chunk-JT4WMD3C.js → chunk-CP73FKME.js} +144 -218
- package/dist/{chunk-3I7XE3PA.js → chunk-DHLOGWYH.js} +36 -36
- package/dist/chunk-DKIJ2RP5.js +68 -0
- package/dist/{chunk-YFNAMRGE.js → chunk-DRHEGXTZ.js} +1 -1
- package/dist/{chunk-OOUNJNMR.js → chunk-DWPN6SCH.js} +1 -1
- package/dist/chunk-EWHP2IRG.js +209 -0
- package/dist/{chunk-R6U7N4FS.js → chunk-FGC3PHNH.js} +3 -3
- package/dist/{chunk-3TM3FYLQ.js → chunk-GA5NS74S.js} +1 -1
- package/dist/{chunk-FIDMHAO6.js → chunk-GPXAHUQH.js} +84 -274
- package/dist/chunk-GUKXEPMX.js +218 -0
- package/dist/{chunk-GENV6KF2.js → chunk-I6IFTAPF.js} +108 -76
- package/dist/{chunk-R5NWWYIS.js → chunk-IANUX7HX.js} +5 -5
- package/dist/{chunk-G2CAC4CV.js → chunk-KCL6AWYW.js} +74 -68
- package/dist/{chunk-5IRROPA5.js → chunk-L7LTGN4Z.js} +129 -31
- package/dist/{chunk-Q5B3WTGG.js → chunk-LGVQLNLS.js} +42 -41
- package/dist/chunk-M3QYTBQ6.js +55 -0
- package/dist/{chunk-FTGD2FBP.js → chunk-MXEUIGHO.js} +2 -2
- package/dist/{chunk-M63DETLL.js → chunk-N7TMSOZH.js} +6 -6
- package/dist/{chunk-2HIPYNQI.js → chunk-O4QYZTDK.js} +33 -32
- package/dist/chunk-PEQXYSSE.js +45 -0
- package/dist/{chunk-RTRBYSF3.js → chunk-QSO7B5JO.js} +1 -1
- package/dist/{chunk-HQNE5APD.js → chunk-RAZG3YHC.js} +100 -79
- package/dist/{chunk-VP4OVRDD.js → chunk-S7YRTOSQ.js} +69 -73
- package/dist/{chunk-U4TKB6F6.js → chunk-SDBKZ5LV.js} +108 -5
- package/dist/{chunk-GPLAT6H7.js → chunk-TC5DE5KJ.js} +22 -18
- package/dist/{chunk-H4HBKISO.js → chunk-TXKUKMVO.js} +1 -1
- package/dist/chunk-U5EUCUBH.js +164 -0
- package/dist/{chunk-3AFVR5UC.js → chunk-VG722ONZ.js} +18 -16
- package/dist/{chunk-ZQMG3CL5.js → chunk-VGPPWWHF.js} +16 -16
- package/dist/{chunk-JMJNFEDC.js → chunk-WVAMRKYG.js} +9 -54
- package/dist/chunk-X6GDDWQH.js +60 -0
- package/dist/{chunk-4GWXAILB.js → chunk-ZE2KOV3G.js} +1 -1
- package/dist/{chunk-TIEKUH4Q.js → chunk-ZM7ZURJS.js} +4 -3
- package/dist/cli/chat.js +47 -43
- package/dist/cli/check.js +13 -15
- package/dist/cli/env.js +0 -1
- package/dist/cli/init.js +0 -1
- package/dist/cli/main.js +2 -3
- package/dist/cli/plugins.js +18 -20
- package/dist/cli/run.js +0 -1
- package/dist/cli/snapshot-create.js +14 -16
- package/dist/cli/upgrade.js +16 -18
- package/dist/{conversation-work-KATFHLG3.js → conversation-work-VIOQ5ZF3.js} +0 -2
- package/dist/{db-EJAV7JL6.js → db-6SBHIAJK.js} +8 -10
- package/dist/deployment.d.ts +1 -0
- package/dist/{discovery-GUFTFBTL.js → discovery-DWVDM7UK.js} +1 -2
- package/dist/{experimental-XVDOSRBS.js → experimental-SIJSRDJD.js} +0 -1
- package/dist/instrumentation.js +7 -9
- package/dist/nitro.js +39 -13
- package/dist/{oauth-callback-server-GAVSUBTQ.js → oauth-callback-server-WSDQPZZS.js} +34 -32
- package/dist/{oauth-relay-3ZU72UGL.js → oauth-relay-5XPVRPYB.js} +0 -1
- package/dist/{plugins-HW4VWW6G.js → plugins-YTYJMMJF.js} +1 -2
- package/dist/{runner-34JL64JF.js → runner-GWTSWESR.js} +39 -33
- package/dist/{sandbox-egress-signals-DXOOBSBI.js → sandbox-egress-signals-FIL7EGPR.js} +5 -6
- package/dist/{sentry-JMWTS32N.js → sentry-MB3NL3IR.js} +1 -2
- package/dist/skills-F32BPFYW.js +27 -0
- package/dist/spawn-X5BPP5OE.js +37 -0
- package/dist/task-runner-2FPBV5PP.js +32 -0
- package/dist/validation-62WO524A.js +17 -0
- package/dist/vercel.js +0 -1
- package/dist/version.js +1 -2
- package/dist/work-3C3CMZ24.js +45 -0
- package/dist/worker-MFAI6ZEK.js +22 -0
- package/package.json +8 -7
- package/dist/catalog-runtime-FBVA6WAQ.js +0 -16
- package/dist/chat/plugins/task-callback.d.ts +0 -5
- package/dist/chat/plugins/task-message.d.ts +0 -23
- package/dist/chat/plugins/task-signing.d.ts +0 -31
- package/dist/chat/sandbox/snapshot/waiting-error.d.ts +0 -15
- package/dist/chat/services/workspace-snapshot-wait.d.ts +0 -27
- package/dist/chunk-5I6ORJUY.js +0 -127
- package/dist/chunk-6GWA276C.js +0 -72
- package/dist/chunk-MLKGABMK.js +0 -9
- package/dist/chunk-UT6X7XN7.js +0 -51
- package/dist/chunk-WR76IVA5.js +0 -130
- package/dist/skills-U545HALM.js +0 -29
- package/dist/spawn-I2S4IDUQ.js +0 -37
- package/dist/validation-EVXVGA44.js +0 -19
- package/dist/work-QOAUPDBU.js +0 -45
- package/dist/worker-5GX2IKLZ.js +0 -24
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import {
|
|
2
2
|
persistConversationMessages
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-GPXAHUQH.js";
|
|
4
4
|
import {
|
|
5
5
|
JUNIOR_THREAD_STATE_TTL_MS
|
|
6
6
|
} from "./chunk-3Y47VMHV.js";
|
|
7
7
|
import {
|
|
8
8
|
getDb
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-S7YRTOSQ.js";
|
|
10
10
|
import {
|
|
11
11
|
juniorLocationConfigurations
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-FGC3PHNH.js";
|
|
13
13
|
import {
|
|
14
14
|
getStateAdapter
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-GA5NS74S.js";
|
|
16
16
|
import {
|
|
17
17
|
juniorDestinations
|
|
18
18
|
} from "./chunk-VFUK3X5B.js";
|
|
@@ -20,59 +20,7 @@ import {
|
|
|
20
20
|
isRecord,
|
|
21
21
|
toOptionalNumber,
|
|
22
22
|
toOptionalString
|
|
23
|
-
} from "./chunk-
|
|
24
|
-
|
|
25
|
-
// src/chat/conversations/turn-lifecycle.ts
|
|
26
|
-
var ConversationTurnLifecycleService = class {
|
|
27
|
-
constructor(events) {
|
|
28
|
-
this.events = events;
|
|
29
|
-
}
|
|
30
|
-
events;
|
|
31
|
-
/** Record the turn start once after every input message is durable. */
|
|
32
|
-
async start(input) {
|
|
33
|
-
await this.events.append(input.conversationId, [
|
|
34
|
-
{
|
|
35
|
-
idempotencyKey: `turn:${input.turnId}:started`,
|
|
36
|
-
createdAtMs: input.createdAtMs,
|
|
37
|
-
data: {
|
|
38
|
-
type: "turn_started",
|
|
39
|
-
turnId: input.turnId,
|
|
40
|
-
inputMessageIds: input.inputMessageIds,
|
|
41
|
-
surface: input.surface
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
]);
|
|
45
|
-
}
|
|
46
|
-
/** Record successful or intentional-silence completion once. */
|
|
47
|
-
async complete(input) {
|
|
48
|
-
await this.events.append(input.conversationId, [
|
|
49
|
-
{
|
|
50
|
-
idempotencyKey: `turn:${input.turnId}:terminal`,
|
|
51
|
-
createdAtMs: input.createdAtMs,
|
|
52
|
-
data: {
|
|
53
|
-
type: "turn_completed",
|
|
54
|
-
turnId: input.turnId,
|
|
55
|
-
outcome: input.outcome
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
]);
|
|
59
|
-
}
|
|
60
|
-
/** Record a classified failure once without accepting raw error details. */
|
|
61
|
-
async fail(input) {
|
|
62
|
-
await this.events.append(input.conversationId, [
|
|
63
|
-
{
|
|
64
|
-
idempotencyKey: `turn:${input.turnId}:terminal`,
|
|
65
|
-
createdAtMs: input.createdAtMs,
|
|
66
|
-
data: {
|
|
67
|
-
type: "turn_failed",
|
|
68
|
-
turnId: input.turnId,
|
|
69
|
-
failureCode: input.failureCode,
|
|
70
|
-
...input.eventId ? { eventId: input.eventId } : {}
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
]);
|
|
74
|
-
}
|
|
75
|
-
};
|
|
23
|
+
} from "./chunk-RAZG3YHC.js";
|
|
76
24
|
|
|
77
25
|
// src/chat/state/conversation.ts
|
|
78
26
|
function defaultConversationState() {
|
|
@@ -103,7 +51,7 @@ function coercePendingAuthState(value) {
|
|
|
103
51
|
const base = {
|
|
104
52
|
provider,
|
|
105
53
|
actorId,
|
|
106
|
-
...scope ? { scope } :
|
|
54
|
+
...scope ? { scope } : void 0,
|
|
107
55
|
sessionId,
|
|
108
56
|
linkSentAtMs
|
|
109
57
|
};
|
|
@@ -496,8 +444,8 @@ function getPersistedSandboxState(state) {
|
|
|
496
444
|
const workspaceId = toOptionalString(state.app_sandbox_workspace_id);
|
|
497
445
|
return {
|
|
498
446
|
id,
|
|
499
|
-
...profileHash ? { profileHash } :
|
|
500
|
-
...workspaceId ? { workspaceId } :
|
|
447
|
+
...profileHash ? { profileHash } : void 0,
|
|
448
|
+
...workspaceId ? { workspaceId } : void 0
|
|
501
449
|
};
|
|
502
450
|
}
|
|
503
451
|
async function persistThreadState(thread, patch) {
|
|
@@ -557,7 +505,6 @@ function getLocationConfigurationService(destination) {
|
|
|
557
505
|
}
|
|
558
506
|
|
|
559
507
|
export {
|
|
560
|
-
ConversationTurnLifecycleService,
|
|
561
508
|
configValueSchema,
|
|
562
509
|
coerceThreadConversationState,
|
|
563
510
|
getPersistedSandboxState,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
logWarn
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-RAZG3YHC.js";
|
|
4
4
|
|
|
5
5
|
// src/chat/conversation-privacy.ts
|
|
6
6
|
import { AsyncLocalStorage } from "async_hooks";
|
|
@@ -49,7 +49,7 @@ function toGenAiPayloadMetadata(payload) {
|
|
|
49
49
|
const keys = payloadKeys(payload);
|
|
50
50
|
return {
|
|
51
51
|
...base,
|
|
52
|
-
...keys ? { keys } :
|
|
52
|
+
...keys ? { keys } : void 0
|
|
53
53
|
};
|
|
54
54
|
}
|
|
55
55
|
function toGenAiPayloadTraceAttributes(prefix, payload) {
|
|
@@ -180,8 +180,8 @@ function toGenAiMessagesTraceAttributes(prefix, messages) {
|
|
|
180
180
|
[`${prefix}.message_count`]: messages.length,
|
|
181
181
|
[`${prefix}.content_chars`]: contentChars,
|
|
182
182
|
[`${prefix}.messages.size`]: contentChars,
|
|
183
|
-
...roles.size > 0 ? { [`${prefix}.roles`]: [...roles] } :
|
|
184
|
-
...partTypes.size > 0 ? { [`${prefix}.part_types`]: [...partTypes] } :
|
|
183
|
+
...roles.size > 0 ? { [`${prefix}.roles`]: [...roles] } : void 0,
|
|
184
|
+
...partTypes.size > 0 ? { [`${prefix}.part_types`]: [...partTypes] } : void 0
|
|
185
185
|
};
|
|
186
186
|
}
|
|
187
187
|
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
// src/chat/vercel-queue-client.ts
|
|
2
|
+
import { QueueClient } from "@vercel/queue";
|
|
3
|
+
function defaultQueueClientOptions() {
|
|
4
|
+
if (process.env.VERCEL_DEPLOYMENT_ID?.trim()) {
|
|
5
|
+
return {};
|
|
6
|
+
}
|
|
7
|
+
return { deploymentId: null };
|
|
8
|
+
}
|
|
9
|
+
function createVercelQueueClient() {
|
|
10
|
+
return new QueueClient(defaultQueueClientOptions());
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// src/chat/queue/sign.ts
|
|
14
|
+
import { createHmac, timingSafeEqual } from "crypto";
|
|
15
|
+
import { z } from "zod";
|
|
16
|
+
var QUEUE_SIGNATURE_MAX_AGE_MS = 60 * 60 * 1e3;
|
|
17
|
+
function secret() {
|
|
18
|
+
return process.env.JUNIOR_SECRET?.trim() || void 0;
|
|
19
|
+
}
|
|
20
|
+
function digest(args) {
|
|
21
|
+
return createHmac("sha256", args.secret).update(
|
|
22
|
+
[args.context, args.signedAtMs, ...args.parts].join(args.separator)
|
|
23
|
+
).digest("hex");
|
|
24
|
+
}
|
|
25
|
+
function sameHex(expected, actual) {
|
|
26
|
+
const left = Buffer.from(expected);
|
|
27
|
+
const right = Buffer.from(actual);
|
|
28
|
+
return left.length === right.length && timingSafeEqual(left, right);
|
|
29
|
+
}
|
|
30
|
+
function body(value) {
|
|
31
|
+
const {
|
|
32
|
+
signature: _signature,
|
|
33
|
+
signatureVersion: _signatureVersion,
|
|
34
|
+
signedAtMs: _signedAtMs,
|
|
35
|
+
...message
|
|
36
|
+
} = value;
|
|
37
|
+
return message;
|
|
38
|
+
}
|
|
39
|
+
function signQueueMessage(config, message, nowMs = Date.now()) {
|
|
40
|
+
const key = secret();
|
|
41
|
+
if (!key) {
|
|
42
|
+
throw new Error("Cannot sign queue message without JUNIOR_SECRET");
|
|
43
|
+
}
|
|
44
|
+
if (!Number.isFinite(nowMs)) {
|
|
45
|
+
throw new Error("Cannot sign queue message with an invalid clock");
|
|
46
|
+
}
|
|
47
|
+
const separator = config.separator ?? "\0";
|
|
48
|
+
return {
|
|
49
|
+
...message,
|
|
50
|
+
signedAtMs: nowMs,
|
|
51
|
+
signatureVersion: config.signatureVersion,
|
|
52
|
+
signature: digest({
|
|
53
|
+
context: config.context,
|
|
54
|
+
parts: config.parts(message),
|
|
55
|
+
secret: key,
|
|
56
|
+
separator,
|
|
57
|
+
signedAtMs: nowMs
|
|
58
|
+
})
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
function verifyQueueMessage(config, value, nowMs = Date.now()) {
|
|
62
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
63
|
+
return { status: "rejected", reason: "malformed" };
|
|
64
|
+
}
|
|
65
|
+
const signed = z.object({
|
|
66
|
+
signature: z.string().trim().min(1),
|
|
67
|
+
signatureVersion: z.literal(config.signatureVersion),
|
|
68
|
+
signedAtMs: z.number().finite()
|
|
69
|
+
}).safeParse(value);
|
|
70
|
+
const message = config.schema.safeParse(body(value));
|
|
71
|
+
if (!signed.success || !message.success) {
|
|
72
|
+
return { status: "rejected", reason: "malformed" };
|
|
73
|
+
}
|
|
74
|
+
const key = secret();
|
|
75
|
+
if (!key) {
|
|
76
|
+
return { status: "unavailable", reason: "missing_secret" };
|
|
77
|
+
}
|
|
78
|
+
if (!Number.isFinite(nowMs)) {
|
|
79
|
+
return { status: "unavailable", reason: "invalid_clock" };
|
|
80
|
+
}
|
|
81
|
+
const maxAgeMs = config.maxAgeMs ?? QUEUE_SIGNATURE_MAX_AGE_MS;
|
|
82
|
+
if (Math.abs(nowMs - signed.data.signedAtMs) > maxAgeMs) {
|
|
83
|
+
return { status: "rejected", reason: "expired" };
|
|
84
|
+
}
|
|
85
|
+
const expected = digest({
|
|
86
|
+
context: config.context,
|
|
87
|
+
parts: config.parts(message.data),
|
|
88
|
+
secret: key,
|
|
89
|
+
separator: config.separator ?? "\0",
|
|
90
|
+
signedAtMs: signed.data.signedAtMs
|
|
91
|
+
});
|
|
92
|
+
if (!sameHex(expected, signed.data.signature)) {
|
|
93
|
+
return { status: "rejected", reason: "signature_mismatch" };
|
|
94
|
+
}
|
|
95
|
+
return { status: "verified", message: message.data };
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export {
|
|
99
|
+
createVercelQueueClient,
|
|
100
|
+
QUEUE_SIGNATURE_MAX_AGE_MS,
|
|
101
|
+
signQueueMessage,
|
|
102
|
+
verifyQueueMessage
|
|
103
|
+
};
|
|
@@ -2,10 +2,10 @@ import {
|
|
|
2
2
|
parseSlackChannelId,
|
|
3
3
|
parseSlackMessageTs,
|
|
4
4
|
parseSlackTeamId
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-N7TMSOZH.js";
|
|
6
6
|
import {
|
|
7
7
|
toOptionalString
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-RAZG3YHC.js";
|
|
9
9
|
|
|
10
10
|
// src/chat/slack/context.ts
|
|
11
11
|
import { z } from "zod";
|
|
@@ -45,12 +45,12 @@ function readSlackRawMessageContext(message) {
|
|
|
45
45
|
const teamId = parseSlackTeamId(raw.data.team_id) ?? parseSlackTeamId(raw.data.team);
|
|
46
46
|
const authorTeamId = parseSlackTeamId(raw.data.user_team);
|
|
47
47
|
return {
|
|
48
|
-
...channelId ? { channelId } :
|
|
49
|
-
...threadTs ? { threadTs } :
|
|
50
|
-
...messageTs ? { messageTs } :
|
|
51
|
-
...nestedMessageTs ? { nestedMessageTs } :
|
|
52
|
-
...teamId ? { teamId } :
|
|
53
|
-
...authorTeamId ? { authorTeamId } :
|
|
48
|
+
...channelId ? { channelId } : void 0,
|
|
49
|
+
...threadTs ? { threadTs } : void 0,
|
|
50
|
+
...messageTs ? { messageTs } : void 0,
|
|
51
|
+
...nestedMessageTs ? { nestedMessageTs } : void 0,
|
|
52
|
+
...teamId ? { teamId } : void 0,
|
|
53
|
+
...authorTeamId ? { authorTeamId } : void 0
|
|
54
54
|
};
|
|
55
55
|
}
|
|
56
56
|
function parseSlackThreadId(threadId) {
|