@trigger.dev/sdk 0.0.0-prerelease-20260909071038 → 0.0.0-prerelease-streamfix-20260909094302
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/commonjs/imports/ai-runtime-cjs.cjs.map +1 -1
- package/dist/commonjs/imports/ai-runtime.js +0 -2
- package/dist/commonjs/v3/ai-shared.d.ts +0 -15
- package/dist/commonjs/v3/ai-shared.js +1 -35
- package/dist/commonjs/v3/ai-shared.js.map +1 -1
- package/dist/commonjs/v3/ai.d.ts +25 -275
- package/dist/commonjs/v3/ai.js +308 -1283
- package/dist/commonjs/v3/ai.js.map +1 -1
- package/dist/commonjs/v3/chat-client.d.ts +2 -11
- package/dist/commonjs/v3/chat-client.js +111 -227
- package/dist/commonjs/v3/chat-client.js.map +1 -1
- package/dist/commonjs/v3/chat-react.d.ts +0 -88
- package/dist/commonjs/v3/chat-react.js +1 -130
- package/dist/commonjs/v3/chat-react.js.map +1 -1
- package/dist/commonjs/v3/chat-server.d.ts +6 -42
- package/dist/commonjs/v3/chat-server.js +7 -52
- package/dist/commonjs/v3/chat-server.js.map +1 -1
- package/dist/commonjs/v3/chat.d.ts +10 -92
- package/dist/commonjs/v3/chat.js +73 -328
- package/dist/commonjs/v3/chat.js.map +1 -1
- package/dist/commonjs/v3/sessions.d.ts +2 -15
- package/dist/commonjs/v3/sessions.js +1 -12
- package/dist/commonjs/v3/sessions.js.map +1 -1
- package/dist/commonjs/v3/shared.js +36 -30
- package/dist/commonjs/v3/shared.js.map +1 -1
- package/dist/commonjs/v3/test/index.d.ts +0 -1
- package/dist/commonjs/v3/test/index.js +1 -3
- package/dist/commonjs/v3/test/index.js.map +1 -1
- package/dist/commonjs/v3/test/mock-chat-agent.d.ts +4 -47
- package/dist/commonjs/v3/test/mock-chat-agent.js +4 -115
- package/dist/commonjs/v3/test/mock-chat-agent.js.map +1 -1
- package/dist/commonjs/v3/test/test-session-handle.js +0 -6
- package/dist/commonjs/v3/test/test-session-handle.js.map +1 -1
- package/dist/commonjs/version.js +1 -1
- package/dist/esm/imports/ai-runtime.d.ts +2 -2
- package/dist/esm/imports/ai-runtime.js +2 -2
- package/dist/esm/imports/ai-runtime.js.map +1 -1
- package/dist/esm/v3/ai-shared.d.ts +0 -15
- package/dist/esm/v3/ai-shared.js +0 -33
- package/dist/esm/v3/ai-shared.js.map +1 -1
- package/dist/esm/v3/ai.d.ts +25 -275
- package/dist/esm/v3/ai.js +305 -1275
- package/dist/esm/v3/ai.js.map +1 -1
- package/dist/esm/v3/chat-client.d.ts +2 -11
- package/dist/esm/v3/chat-client.js +112 -228
- package/dist/esm/v3/chat-client.js.map +1 -1
- package/dist/esm/v3/chat-react.d.ts +0 -88
- package/dist/esm/v3/chat-react.js +1 -127
- package/dist/esm/v3/chat-react.js.map +1 -1
- package/dist/esm/v3/chat-server.d.ts +6 -42
- package/dist/esm/v3/chat-server.js +8 -53
- package/dist/esm/v3/chat-server.js.map +1 -1
- package/dist/esm/v3/chat.d.ts +10 -92
- package/dist/esm/v3/chat.js +74 -329
- package/dist/esm/v3/chat.js.map +1 -1
- package/dist/esm/v3/sessions.d.ts +2 -15
- package/dist/esm/v3/sessions.js +1 -11
- package/dist/esm/v3/sessions.js.map +1 -1
- package/dist/esm/v3/shared.js +23 -17
- package/dist/esm/v3/shared.js.map +1 -1
- package/dist/esm/v3/test/index.d.ts +0 -1
- package/dist/esm/v3/test/index.js +0 -1
- package/dist/esm/v3/test/index.js.map +1 -1
- package/dist/esm/v3/test/mock-chat-agent.d.ts +4 -47
- package/dist/esm/v3/test/mock-chat-agent.js +6 -117
- package/dist/esm/v3/test/mock-chat-agent.js.map +1 -1
- package/dist/esm/v3/test/test-session-handle.js +0 -6
- package/dist/esm/v3/test/test-session-handle.js.map +1 -1
- package/dist/esm/version.js +1 -1
- package/docs/ai-chat/actions.mdx +23 -55
- package/docs/ai-chat/anatomy.mdx +3 -3
- package/docs/ai-chat/backend.mdx +48 -125
- package/docs/ai-chat/background-injection.mdx +19 -69
- package/docs/ai-chat/client-protocol.mdx +4 -5
- package/docs/ai-chat/compaction.mdx +7 -13
- package/docs/ai-chat/custom-agents.mdx +0 -23
- package/docs/ai-chat/fast-starts.mdx +20 -27
- package/docs/ai-chat/frontend.mdx +14 -19
- package/docs/ai-chat/lifecycle-hooks.mdx +2 -6
- package/docs/ai-chat/migrating-from-a-route-handler.mdx +14 -16
- package/docs/ai-chat/patterns/database-persistence.mdx +2 -6
- package/docs/ai-chat/patterns/persistence-and-replay.mdx +23 -34
- package/docs/ai-chat/patterns/skills.mdx +10 -7
- package/docs/ai-chat/patterns/version-upgrades.mdx +6 -79
- package/docs/ai-chat/pending-messages.mdx +3 -3
- package/docs/ai-chat/prompt-caching.mdx +25 -23
- package/docs/ai-chat/quick-start.mdx +11 -11
- package/docs/ai-chat/reference.mdx +9 -67
- package/docs/ai-chat/sessions.mdx +1 -6
- package/docs/ai-chat/testing.mdx +1 -2
- package/docs/ai-chat/tools.mdx +13 -18
- package/docs/ai-chat/upgrade-guide.mdx +2 -2
- package/docs/apikeys.mdx +45 -27
- package/docs/config/extensions/syncEnvVars.mdx +0 -6
- package/docs/deploy-environment-variables.mdx +2 -23
- package/docs/deployment/overview.mdx +8 -4
- package/docs/deployment/preview-branches.mdx +4 -4
- package/docs/deployment/version-skew-protection.mdx +0 -62
- package/docs/manual-setup.mdx +7 -7
- package/docs/mcp-tools.mdx +0 -9
- package/docs/quick-start.mdx +3 -3
- package/docs/realtime/auth.mdx +1 -1
- package/docs/self-hosting/security.mdx +0 -5
- package/docs/tasks/scheduled.mdx +0 -24
- package/docs/triggering.mdx +1 -1
- package/package.json +4 -4
- package/skills/trigger-authoring-chat-agent/SKILL.md +29 -41
- package/skills/trigger-chat-agent-advanced/SKILL.md +12 -31
- package/dist/commonjs/v3/chatSnapshotIo.d.ts +0 -2
- package/dist/commonjs/v3/chatSnapshotIo.js +0 -174
- package/dist/commonjs/v3/chatSnapshotIo.js.map +0 -1
- package/dist/commonjs/v3/chatVersionSkew.d.ts +0 -12
- package/dist/commonjs/v3/chatVersionSkew.js +0 -30
- package/dist/commonjs/v3/chatVersionSkew.js.map +0 -1
- package/dist/commonjs/v3/externalDeploymentId.d.ts +0 -23
- package/dist/commonjs/v3/externalDeploymentId.js +0 -43
- package/dist/commonjs/v3/externalDeploymentId.js.map +0 -1
- package/dist/commonjs/v3/test/transcript-storage-tests.d.ts +0 -40
- package/dist/commonjs/v3/test/transcript-storage-tests.js +0 -258
- package/dist/commonjs/v3/test/transcript-storage-tests.js.map +0 -1
- package/dist/commonjs/v3/transcriptStorage.d.ts +0 -229
- package/dist/commonjs/v3/transcriptStorage.js +0 -321
- package/dist/commonjs/v3/transcriptStorage.js.map +0 -1
- package/dist/esm/v3/chatSnapshotIo.d.ts +0 -2
- package/dist/esm/v3/chatSnapshotIo.js +0 -166
- package/dist/esm/v3/chatSnapshotIo.js.map +0 -1
- package/dist/esm/v3/chatVersionSkew.d.ts +0 -12
- package/dist/esm/v3/chatVersionSkew.js +0 -27
- package/dist/esm/v3/chatVersionSkew.js.map +0 -1
- package/dist/esm/v3/externalDeploymentId.d.ts +0 -23
- package/dist/esm/v3/externalDeploymentId.js +0 -38
- package/dist/esm/v3/externalDeploymentId.js.map +0 -1
- package/dist/esm/v3/test/transcript-storage-tests.d.ts +0 -40
- package/dist/esm/v3/test/transcript-storage-tests.js +0 -255
- package/dist/esm/v3/test/transcript-storage-tests.js.map +0 -1
- package/dist/esm/v3/transcriptStorage.d.ts +0 -229
- package/dist/esm/v3/transcriptStorage.js +0 -309
- package/dist/esm/v3/transcriptStorage.js.map +0 -1
- package/docs/ai-chat/patterns/native-compaction.mdx +0 -310
- package/docs/ai-chat/transcript-storage.mdx +0 -233
- package/docs/reports.mdx +0 -157
- package/docs/troubleshooting-zod.mdx +0 -158
package/dist/esm/v3/chat.js
CHANGED
|
@@ -22,12 +22,12 @@
|
|
|
22
22
|
* }
|
|
23
23
|
* ```
|
|
24
24
|
*/
|
|
25
|
-
import { controlSubtype, headerValue,
|
|
25
|
+
import { controlSubtype, headerValue, PUBLIC_ACCESS_TOKEN_HEADER, SESSION_IN_EVENT_ID_HEADER, SSEStreamSubscription, TRIGGER_CONTROL_SUBTYPE, } from "@trigger.dev/core/v3";
|
|
26
26
|
function byteLength(body) {
|
|
27
27
|
return new TextEncoder().encode(body).byteLength;
|
|
28
28
|
}
|
|
29
29
|
import { ChatTabCoordinator } from "./chat-tab-coordinator.js";
|
|
30
|
-
import {
|
|
30
|
+
import { slimSubmitMessageForWire } from "./ai-shared.js";
|
|
31
31
|
const DEFAULT_BASE_URL = "https://api.trigger.dev";
|
|
32
32
|
const DEFAULT_STREAM_TIMEOUT_SECONDS = 120;
|
|
33
33
|
/**
|
|
@@ -40,32 +40,6 @@ function isAuthError(error) {
|
|
|
40
40
|
const e = error;
|
|
41
41
|
return e.name === "TriggerApiError" && (e.status === 401 || e.status === 403);
|
|
42
42
|
}
|
|
43
|
-
/**
|
|
44
|
-
* Detect the closed-session refusal from `.in/append`: HTTP 409 with the
|
|
45
|
-
* stable `session_closed` code. Terminal — never retried.
|
|
46
|
-
*/
|
|
47
|
-
function isSessionClosedError(error) {
|
|
48
|
-
if (error === null || typeof error !== "object")
|
|
49
|
-
return false;
|
|
50
|
-
const e = error;
|
|
51
|
-
return e.name === "TriggerApiError" && e.status === 409 && e.code === "session_closed";
|
|
52
|
-
}
|
|
53
|
-
function sessionClosedReasonOf(error) {
|
|
54
|
-
if (error === null || typeof error !== "object")
|
|
55
|
-
return undefined;
|
|
56
|
-
const reason = error.closedReason;
|
|
57
|
-
return typeof reason === "string" ? reason : undefined;
|
|
58
|
-
}
|
|
59
|
-
/** The local form of the refusal, for sends the transport rejects itself. */
|
|
60
|
-
function sessionClosedError(chatId, reason) {
|
|
61
|
-
const err = new Error(reason ? `Chat session ${chatId} is closed: ${reason}` : `Chat session ${chatId} is closed`);
|
|
62
|
-
err.name = "TriggerApiError";
|
|
63
|
-
err.status = 409;
|
|
64
|
-
err.code = "session_closed";
|
|
65
|
-
if (reason)
|
|
66
|
-
err.closedReason = reason;
|
|
67
|
-
return err;
|
|
68
|
-
}
|
|
69
43
|
/**
|
|
70
44
|
* Detect a 404 from a session-PAT-authed call — i.e. the session doesn't
|
|
71
45
|
* exist in the current environment. Happens when hydrated session state
|
|
@@ -171,7 +145,6 @@ export class TriggerChatTransport {
|
|
|
171
145
|
_onSessionChange;
|
|
172
146
|
_onEvent;
|
|
173
147
|
sessions = new Map();
|
|
174
|
-
pendingResumeCursors = new Map();
|
|
175
148
|
activeStreams = new Map();
|
|
176
149
|
pendingStarts = new Map();
|
|
177
150
|
// Last turn-producing send per chat — attribution source for the
|
|
@@ -211,8 +184,6 @@ export class TriggerChatTransport {
|
|
|
211
184
|
lastEventId: session.lastEventId,
|
|
212
185
|
activeInputSeq: session.activeInputSeq,
|
|
213
186
|
isStreaming: session.isStreaming,
|
|
214
|
-
closed: session.closed,
|
|
215
|
-
closedReason: session.closedReason,
|
|
216
187
|
});
|
|
217
188
|
}
|
|
218
189
|
}
|
|
@@ -262,10 +233,6 @@ export class TriggerChatTransport {
|
|
|
262
233
|
*/
|
|
263
234
|
sendMessages = async (options) => {
|
|
264
235
|
const { trigger, chatId, messageId, messages, abortSignal, body, metadata } = options;
|
|
265
|
-
const closedState = this.sessions.get(chatId);
|
|
266
|
-
if (closedState?.closed) {
|
|
267
|
-
throw sessionClosedError(chatId, closedState.closedReason);
|
|
268
|
-
}
|
|
269
236
|
if (this.coordinator) {
|
|
270
237
|
if (this.coordinator.isReadOnly(chatId)) {
|
|
271
238
|
throw new Error("This chat is active in another tab");
|
|
@@ -275,14 +242,6 @@ export class TriggerChatTransport {
|
|
|
275
242
|
const mergedMetadata = this.defaultMetadata || metadata
|
|
276
243
|
? { ...(this.defaultMetadata ?? {}), ...(metadata ?? {}) }
|
|
277
244
|
: undefined;
|
|
278
|
-
// An action sent through `useChat`. `useChatActions` (or any caller) puts
|
|
279
|
-
// it in `body.action`; sending it here rather than through
|
|
280
|
-
// `transport.sendAction` means `useChat` owns the response stream, so an
|
|
281
|
-
// action that becomes a turn renders the way a message turn does.
|
|
282
|
-
const actionInBody = body?.action;
|
|
283
|
-
if (actionInBody !== undefined) {
|
|
284
|
-
return this.sendAction(chatId, actionInBody, { abortSignal, metadata: mergedMetadata });
|
|
285
|
-
}
|
|
286
245
|
// First-turn handover routing — when `headStart` is set AND no
|
|
287
246
|
// session state exists yet for this chatId, POST the wire payload
|
|
288
247
|
// to the customer's `chat.handover` route handler. The handler
|
|
@@ -345,9 +304,11 @@ export class TriggerChatTransport {
|
|
|
345
304
|
activeStream.abort();
|
|
346
305
|
this.activeStreams.delete(chatId);
|
|
347
306
|
}
|
|
307
|
+
// A stop that never saw its TURN_COMPLETE leaves the flag set, and the new
|
|
308
|
+
// turn would be skipped record by record.
|
|
309
|
+
state.skipToTurnComplete = false;
|
|
348
310
|
state.activeInputSeq = inSeq;
|
|
349
311
|
state.isStreaming = true;
|
|
350
|
-
state.outstandingTurnAbandoned = false;
|
|
351
312
|
this.notifySessionChange(chatId, state);
|
|
352
313
|
// Owning turn: aborting this live send stops the turn the user drives.
|
|
353
314
|
return this.subscribeToSessionStream(state, abortSignal, chatId, {
|
|
@@ -419,16 +380,6 @@ export class TriggerChatTransport {
|
|
|
419
380
|
};
|
|
420
381
|
this.sessions.set(chatId, state);
|
|
421
382
|
this.notifySessionChange(chatId, state);
|
|
422
|
-
// Step 1 streams from the warm server either way; this says the agent run that owes step 2
|
|
423
|
-
// is parked on an undeployed external deployment id.
|
|
424
|
-
if (response.headers.get("X-Trigger-Chat-Pending-Version") === "1") {
|
|
425
|
-
this.emitEvent({
|
|
426
|
-
type: "run-pending-version",
|
|
427
|
-
chatId,
|
|
428
|
-
timestamp: Date.now(),
|
|
429
|
-
source: "head-start",
|
|
430
|
-
});
|
|
431
|
-
}
|
|
432
383
|
// Filter the parsed UIMessage stream:
|
|
433
384
|
// - Drop control chunks (`trigger:turn-complete`,
|
|
434
385
|
// `trigger:session-state`) before they reach AI SDK — they
|
|
@@ -595,9 +546,6 @@ export class TriggerChatTransport {
|
|
|
595
546
|
const state = this.sessions.get(options.chatId);
|
|
596
547
|
if (!state)
|
|
597
548
|
return null;
|
|
598
|
-
// A closed session has no further turns to resume.
|
|
599
|
-
if (state.closed)
|
|
600
|
-
return null;
|
|
601
549
|
// Watch is a standing subscription: a settled session is exactly the
|
|
602
550
|
// state it waits in, so a completed last turn must not block the resume.
|
|
603
551
|
if (state.isStreaming === false && !this.watchMode)
|
|
@@ -642,13 +590,7 @@ export class TriggerChatTransport {
|
|
|
642
590
|
catch {
|
|
643
591
|
return false;
|
|
644
592
|
}
|
|
645
|
-
|
|
646
|
-
// nothing to supersede, and gating it would swallow the next turn.
|
|
647
|
-
if (!state.outstandingTurnAbandoned &&
|
|
648
|
-
(state.isStreaming || state.activeInputSeq !== undefined)) {
|
|
649
|
-
state.skipToTurnComplete = true;
|
|
650
|
-
state.supersededInputSeq = state.activeInputSeq;
|
|
651
|
-
}
|
|
593
|
+
state.skipToTurnComplete = true;
|
|
652
594
|
const activeStream = this.activeStreams.get(chatId);
|
|
653
595
|
if (activeStream) {
|
|
654
596
|
activeStream.abort();
|
|
@@ -667,28 +609,15 @@ export class TriggerChatTransport {
|
|
|
667
609
|
this.notifySessionChange(chatId, state);
|
|
668
610
|
return true;
|
|
669
611
|
};
|
|
670
|
-
/**
|
|
671
|
-
* Clear the supersede gate armed by a stop. Call this when the stopped
|
|
672
|
-
* turn died without ever writing its `trigger:turn-complete` boundary,
|
|
673
|
-
* otherwise the next turn stays gated forever.
|
|
674
|
-
*/
|
|
675
|
-
clearSupersedeGate = (chatId) => {
|
|
676
|
-
const state = this.sessions.get(chatId);
|
|
677
|
-
if (!state)
|
|
678
|
-
return;
|
|
679
|
-
state.skipToTurnComplete = false;
|
|
680
|
-
state.supersededInputSeq = undefined;
|
|
681
|
-
state.outstandingTurnAbandoned = true;
|
|
682
|
-
};
|
|
683
612
|
/**
|
|
684
613
|
* Send a custom action chunk (for `chat.agent`'s `actionSchema` /
|
|
685
|
-
* `onAction` hook).
|
|
686
|
-
* `onAction` fire on the agent side
|
|
687
|
-
*
|
|
688
|
-
*
|
|
689
|
-
*
|
|
614
|
+
* `onAction` hook). Actions are not turns — only `hydrateMessages`
|
|
615
|
+
* and `onAction` fire on the agent side. The returned stream
|
|
616
|
+
* carries any model response `onAction` produced (when it returns a
|
|
617
|
+
* `StreamTextResult`); for `void`-returning side-effect-only actions
|
|
618
|
+
* the stream completes immediately with `trigger:turn-complete`.
|
|
690
619
|
*/
|
|
691
|
-
sendAction = async (chatId, action
|
|
620
|
+
sendAction = async (chatId, action) => {
|
|
692
621
|
if (this.coordinator) {
|
|
693
622
|
if (this.coordinator.isReadOnly(chatId)) {
|
|
694
623
|
throw new Error("This chat is active in another tab");
|
|
@@ -700,9 +629,7 @@ export class TriggerChatTransport {
|
|
|
700
629
|
chatId,
|
|
701
630
|
trigger: "action",
|
|
702
631
|
action,
|
|
703
|
-
metadata: this.defaultMetadata
|
|
704
|
-
? { ...(this.defaultMetadata ?? {}), ...(options?.metadata ?? {}) }
|
|
705
|
-
: undefined,
|
|
632
|
+
metadata: this.defaultMetadata ?? undefined,
|
|
706
633
|
};
|
|
707
634
|
const body = this.serializeInputChunk({ kind: "message", payload: wirePayload });
|
|
708
635
|
const partId = crypto.randomUUID();
|
|
@@ -717,14 +644,16 @@ export class TriggerChatTransport {
|
|
|
717
644
|
activeStream.abort();
|
|
718
645
|
this.activeStreams.delete(chatId);
|
|
719
646
|
}
|
|
647
|
+
// A stop that never saw its TURN_COMPLETE leaves the flag set, and the new
|
|
648
|
+
// turn would be skipped record by record.
|
|
649
|
+
state.skipToTurnComplete = false;
|
|
720
650
|
// Mark streaming + persist so a reload mid-action resumes (reconnectToStream
|
|
721
651
|
// no-ops when the persisted session says isStreaming: false).
|
|
722
652
|
state.activeInputSeq = inSeq;
|
|
723
653
|
state.isStreaming = true;
|
|
724
|
-
state.outstandingTurnAbandoned = false;
|
|
725
654
|
this.notifySessionChange(chatId, state);
|
|
726
655
|
// Owning action: aborting this send stops the turn the user drives.
|
|
727
|
-
return this.subscribeToSessionStream(state,
|
|
656
|
+
return this.subscribeToSessionStream(state, undefined, chatId, {
|
|
728
657
|
sinceInSeq: inSeq,
|
|
729
658
|
sendStopOnAbort: true,
|
|
730
659
|
});
|
|
@@ -739,42 +668,14 @@ export class TriggerChatTransport {
|
|
|
739
668
|
return this.toPersisted(state);
|
|
740
669
|
};
|
|
741
670
|
setSession(chatId, session) {
|
|
742
|
-
this.sessions.set(chatId,
|
|
671
|
+
this.sessions.set(chatId, {
|
|
743
672
|
publicAccessToken: session.publicAccessToken,
|
|
744
673
|
lastEventId: session.lastEventId,
|
|
745
674
|
activeInputSeq: session.activeInputSeq,
|
|
746
675
|
isStreaming: session.isStreaming,
|
|
747
|
-
})
|
|
676
|
+
});
|
|
748
677
|
this.notifySessionChange(chatId, this.toPersisted(this.sessions.get(chatId)));
|
|
749
678
|
}
|
|
750
|
-
/**
|
|
751
|
-
* Seed the `.out` resume cursor from a loaded transcript. Applied to the
|
|
752
|
-
* session now if it exists, otherwise held until the session is created so
|
|
753
|
-
* the first live subscription opens past the persisted history instead of
|
|
754
|
-
* replaying it. Never moves an existing cursor backward: the transcript load
|
|
755
|
-
* is async, so a live `.out` record can already have advanced the session
|
|
756
|
-
* past the snapshot, and overwriting it would replay those records.
|
|
757
|
-
*/
|
|
758
|
-
seedResumeCursor = (chatId, lastEventId) => {
|
|
759
|
-
const existing = this.sessions.get(chatId);
|
|
760
|
-
if (existing?.publicAccessToken) {
|
|
761
|
-
if (existing.lastEventId === undefined) {
|
|
762
|
-
existing.lastEventId = lastEventId;
|
|
763
|
-
this.notifySessionChange(chatId, this.toPersisted(existing));
|
|
764
|
-
}
|
|
765
|
-
this.pendingResumeCursors.delete(chatId);
|
|
766
|
-
return;
|
|
767
|
-
}
|
|
768
|
-
this.pendingResumeCursors.set(chatId, lastEventId);
|
|
769
|
-
};
|
|
770
|
-
applyPendingResumeCursor(chatId, state) {
|
|
771
|
-
const pending = this.pendingResumeCursors.get(chatId);
|
|
772
|
-
if (pending !== undefined && state.lastEventId === undefined) {
|
|
773
|
-
state.lastEventId = pending;
|
|
774
|
-
}
|
|
775
|
-
this.pendingResumeCursors.delete(chatId);
|
|
776
|
-
return state;
|
|
777
|
-
}
|
|
778
679
|
setOnSessionChange(callback) {
|
|
779
680
|
this._onSessionChange = callback;
|
|
780
681
|
}
|
|
@@ -845,22 +746,6 @@ export class TriggerChatTransport {
|
|
|
845
746
|
setClientData(clientData) {
|
|
846
747
|
this.defaultMetadata = clientData;
|
|
847
748
|
}
|
|
848
|
-
/**
|
|
849
|
-
* Update the request-time callbacks. Same reason as `setClientData`:
|
|
850
|
-
* a host that rebuilds these per render (a dashboard navigating between
|
|
851
|
-
* projects) would otherwise keep hitting the endpoint captured at
|
|
852
|
-
* construction. Every read goes through the live field, so the next
|
|
853
|
-
* request uses the latest callback.
|
|
854
|
-
*/
|
|
855
|
-
setAccessToken(accessToken) {
|
|
856
|
-
this.resolveAccessToken = accessToken;
|
|
857
|
-
}
|
|
858
|
-
setStartSession(startSession) {
|
|
859
|
-
this.resolveStartSession = startSession;
|
|
860
|
-
}
|
|
861
|
-
setFetch(fetchOverride) {
|
|
862
|
-
this.fetchOverride = fetchOverride;
|
|
863
|
-
}
|
|
864
749
|
// -------------------------------------------------------------------------
|
|
865
750
|
// Multi-tab coordination passthrough
|
|
866
751
|
// -------------------------------------------------------------------------
|
|
@@ -908,42 +793,7 @@ export class TriggerChatTransport {
|
|
|
908
793
|
lastEventId: state.lastEventId,
|
|
909
794
|
activeInputSeq: state.activeInputSeq,
|
|
910
795
|
isStreaming: state.isStreaming,
|
|
911
|
-
closed: state.closed,
|
|
912
|
-
closedReason: state.closedReason,
|
|
913
796
|
});
|
|
914
|
-
/**
|
|
915
|
-
* Flip a session to closed and tell listeners once. Terminal: sends and
|
|
916
|
-
* reconnects stop from here on, and there is no reopening.
|
|
917
|
-
*/
|
|
918
|
-
markSessionClosed(chatId, state, reason, source) {
|
|
919
|
-
if (state.closed)
|
|
920
|
-
return;
|
|
921
|
-
state.closed = true;
|
|
922
|
-
if (reason)
|
|
923
|
-
state.closedReason = reason;
|
|
924
|
-
state.isStreaming = false;
|
|
925
|
-
state.activeInputSeq = undefined;
|
|
926
|
-
state.skipToTurnComplete = false;
|
|
927
|
-
state.supersededInputSeq = undefined;
|
|
928
|
-
this.emitEvent({
|
|
929
|
-
type: "session-closed",
|
|
930
|
-
chatId,
|
|
931
|
-
timestamp: Date.now(),
|
|
932
|
-
...(reason ? { reason } : {}),
|
|
933
|
-
source,
|
|
934
|
-
});
|
|
935
|
-
this.notifySessionChange(chatId, state);
|
|
936
|
-
this.coordinator?.release(chatId);
|
|
937
|
-
}
|
|
938
|
-
/**
|
|
939
|
-
* Whether the conversation has been closed — by the agent via
|
|
940
|
-
* `chat.close()`, or from outside via `sessions.close()`. Closed is
|
|
941
|
-
* one-way: the transport refuses further sends and reconnects, and the
|
|
942
|
-
* transcript stays readable.
|
|
943
|
-
*/
|
|
944
|
-
sessionStatus = (chatId) => this.sessions.get(chatId)?.closed ? "closed" : "open";
|
|
945
|
-
/** The reason the session was closed, when one was given. */
|
|
946
|
-
sessionClosedReason = (chatId) => this.sessions.get(chatId)?.closedReason;
|
|
947
797
|
notifySessionChange(chatId, session) {
|
|
948
798
|
if (!this._onSessionChange)
|
|
949
799
|
return;
|
|
@@ -978,7 +828,7 @@ export class TriggerChatTransport {
|
|
|
978
828
|
// `sessions: { ... }` already, or the very first `accessToken` call
|
|
979
829
|
// returns a PAT for an out-of-band-created session.
|
|
980
830
|
const token = await this.resolveAccessToken({ chatId });
|
|
981
|
-
const state =
|
|
831
|
+
const state = { publicAccessToken: token };
|
|
982
832
|
this.sessions.set(chatId, state);
|
|
983
833
|
this.notifySessionChange(chatId, state);
|
|
984
834
|
return state;
|
|
@@ -987,23 +837,15 @@ export class TriggerChatTransport {
|
|
|
987
837
|
if (!this.resolveStartSession) {
|
|
988
838
|
throw new Error("TriggerChatTransport: `startSession` is required to call `start()` / `preload()`. Either provide it or pre-hydrate the session via `sessions: { ... }`.");
|
|
989
839
|
}
|
|
990
|
-
const { publicAccessToken
|
|
840
|
+
const { publicAccessToken } = await this.resolveStartSession({
|
|
991
841
|
taskId: this.taskId,
|
|
992
842
|
chatId,
|
|
993
843
|
clientData: (this.defaultMetadata ?? {}),
|
|
994
844
|
});
|
|
995
|
-
|
|
996
|
-
this.emitEvent({
|
|
997
|
-
type: "run-pending-version",
|
|
998
|
-
chatId,
|
|
999
|
-
timestamp: Date.now(),
|
|
1000
|
-
source: "start",
|
|
1001
|
-
});
|
|
1002
|
-
}
|
|
1003
|
-
const state = this.applyPendingResumeCursor(chatId, {
|
|
845
|
+
const state = {
|
|
1004
846
|
publicAccessToken,
|
|
1005
847
|
isStreaming: false,
|
|
1006
|
-
}
|
|
848
|
+
};
|
|
1007
849
|
this.sessions.set(chatId, state);
|
|
1008
850
|
this.notifySessionChange(chatId, state);
|
|
1009
851
|
return state;
|
|
@@ -1016,33 +858,6 @@ export class TriggerChatTransport {
|
|
|
1016
858
|
const raw = this.resolveBaseURLFn(ctx);
|
|
1017
859
|
return raw.replace(/\/$/, "");
|
|
1018
860
|
}
|
|
1019
|
-
/**
|
|
1020
|
-
* `fetchClient` for an `out` subscription. Reads `this.fetchOverride` on
|
|
1021
|
-
* every call, not once per subscription: a watch-mode subscription
|
|
1022
|
-
* reconnects for the lifetime of the page, and `setFetch` may have swapped
|
|
1023
|
-
* the override in between.
|
|
1024
|
-
*/
|
|
1025
|
-
sseFetchClient(ctx) {
|
|
1026
|
-
return ((input, init) => {
|
|
1027
|
-
const override = this.fetchOverride;
|
|
1028
|
-
if (!override)
|
|
1029
|
-
return fetch(input, init);
|
|
1030
|
-
if (typeof input === "string") {
|
|
1031
|
-
return override(input, init ?? {}, ctx);
|
|
1032
|
-
}
|
|
1033
|
-
if (input instanceof URL) {
|
|
1034
|
-
return override(input.toString(), init ?? {}, ctx);
|
|
1035
|
-
}
|
|
1036
|
-
// Request — preserve its url + intrinsic init, let any provided init
|
|
1037
|
-
// override on top (matches fetch(Request, init) semantics).
|
|
1038
|
-
return override(input.url, {
|
|
1039
|
-
method: input.method,
|
|
1040
|
-
headers: input.headers,
|
|
1041
|
-
signal: input.signal,
|
|
1042
|
-
...(init ?? {}),
|
|
1043
|
-
}, ctx);
|
|
1044
|
-
});
|
|
1045
|
-
}
|
|
1046
861
|
async doFetch(ctx, url, init) {
|
|
1047
862
|
return this.fetchOverride ? this.fetchOverride(url, init, ctx) : fetch(url, init);
|
|
1048
863
|
}
|
|
@@ -1064,65 +879,24 @@ export class TriggerChatTransport {
|
|
|
1064
879
|
const err = new Error(`appendToSessionStream failed: ${response.status} ${text}`);
|
|
1065
880
|
err.name = "TriggerApiError";
|
|
1066
881
|
err.status = response.status;
|
|
1067
|
-
let parsed;
|
|
1068
|
-
try {
|
|
1069
|
-
parsed = JSON.parse(text);
|
|
1070
|
-
}
|
|
1071
|
-
catch {
|
|
1072
|
-
parsed = undefined;
|
|
1073
|
-
}
|
|
1074
|
-
if (typeof parsed?.code === "string")
|
|
1075
|
-
err.code = parsed.code;
|
|
1076
|
-
if (typeof parsed?.closedReason === "string")
|
|
1077
|
-
err.closedReason = parsed.closedReason;
|
|
1078
882
|
throw err;
|
|
1079
883
|
}
|
|
1080
884
|
// The appended record's `.in` seq, for correlating the response stream to
|
|
1081
885
|
// this send. Omitted by older webapps / a lost idempotency claim.
|
|
1082
886
|
const data = (await response.json().catch(() => undefined));
|
|
1083
|
-
if (data?.pendingVersion === true) {
|
|
1084
|
-
this.emitEvent({
|
|
1085
|
-
type: "run-pending-version",
|
|
1086
|
-
chatId,
|
|
1087
|
-
timestamp: Date.now(),
|
|
1088
|
-
source: "send",
|
|
1089
|
-
});
|
|
1090
|
-
}
|
|
1091
887
|
return typeof data?.seq === "number" ? data.seq : undefined;
|
|
1092
888
|
}
|
|
1093
889
|
async callWithAuthRetry(chatId, state, op) {
|
|
1094
|
-
if (state.closed) {
|
|
1095
|
-
throw sessionClosedError(chatId, state.closedReason);
|
|
1096
|
-
}
|
|
1097
|
-
// Every attempt goes through here, so a closed-session refusal is terminal
|
|
1098
|
-
// on whichever one hits it. Reaching a 409 from a later attempt and not
|
|
1099
|
-
// marking it would leave local status open on a conversation the server
|
|
1100
|
-
// has already ended.
|
|
1101
|
-
const attempt = async (token) => {
|
|
1102
|
-
try {
|
|
1103
|
-
return await op(token);
|
|
1104
|
-
}
|
|
1105
|
-
catch (err) {
|
|
1106
|
-
if (isSessionClosedError(err)) {
|
|
1107
|
-
// Terminal. Retrying, refreshing the PAT, or recreating the session
|
|
1108
|
-
// would all be wrong: the conversation is over.
|
|
1109
|
-
this.markSessionClosed(chatId, state, sessionClosedReasonOf(err), "append");
|
|
1110
|
-
}
|
|
1111
|
-
throw err;
|
|
1112
|
-
}
|
|
1113
|
-
};
|
|
1114
890
|
// 1) Try with the current PAT.
|
|
1115
891
|
try {
|
|
1116
|
-
return await
|
|
892
|
+
return await op(state.publicAccessToken);
|
|
1117
893
|
}
|
|
1118
894
|
catch (err) {
|
|
1119
|
-
if (isSessionClosedError(err))
|
|
1120
|
-
throw err;
|
|
1121
895
|
if (isSessionNotFoundError(err)) {
|
|
1122
896
|
// The cached PAT authenticated but the session doesn't exist here —
|
|
1123
897
|
// recreate it and retry.
|
|
1124
898
|
await this.recreateSession(chatId, state);
|
|
1125
|
-
return await
|
|
899
|
+
return await op(state.publicAccessToken);
|
|
1126
900
|
}
|
|
1127
901
|
if (!isAuthError(err))
|
|
1128
902
|
throw err;
|
|
@@ -1133,7 +907,7 @@ export class TriggerChatTransport {
|
|
|
1133
907
|
state.publicAccessToken = fresh;
|
|
1134
908
|
this.notifySessionChange(chatId, state);
|
|
1135
909
|
try {
|
|
1136
|
-
return await
|
|
910
|
+
return await op(fresh);
|
|
1137
911
|
}
|
|
1138
912
|
catch (err) {
|
|
1139
913
|
if (!isSessionNotFoundError(err))
|
|
@@ -1143,7 +917,7 @@ export class TriggerChatTransport {
|
|
|
1143
917
|
// state is stale (created in a different environment, or before the
|
|
1144
918
|
// sessions upgrade). Recreate the session and retry once.
|
|
1145
919
|
await this.recreateSession(chatId, state);
|
|
1146
|
-
return await
|
|
920
|
+
return await op(state.publicAccessToken);
|
|
1147
921
|
}
|
|
1148
922
|
/**
|
|
1149
923
|
* Repair a stale/phantom hydrated session. The cached state pointed at a
|
|
@@ -1159,19 +933,11 @@ export class TriggerChatTransport {
|
|
|
1159
933
|
if (!this.resolveStartSession) {
|
|
1160
934
|
throw new Error("TriggerChatTransport: session not found and no `startSession` configured to recreate it. The stored session state for this chat may be stale (e.g. created in a different environment) — provide `startSession` or clear the stored session so a fresh one can be created.");
|
|
1161
935
|
}
|
|
1162
|
-
const { publicAccessToken
|
|
936
|
+
const { publicAccessToken } = await this.resolveStartSession({
|
|
1163
937
|
taskId: this.taskId,
|
|
1164
938
|
chatId,
|
|
1165
939
|
clientData: (this.defaultMetadata ?? {}),
|
|
1166
940
|
});
|
|
1167
|
-
if (pendingVersion) {
|
|
1168
|
-
this.emitEvent({
|
|
1169
|
-
type: "run-pending-version",
|
|
1170
|
-
chatId,
|
|
1171
|
-
timestamp: Date.now(),
|
|
1172
|
-
source: "start",
|
|
1173
|
-
});
|
|
1174
|
-
}
|
|
1175
941
|
state.publicAccessToken = publicAccessToken;
|
|
1176
942
|
state.lastEventId = undefined;
|
|
1177
943
|
state.isStreaming = false;
|
|
@@ -1195,13 +961,8 @@ export class TriggerChatTransport {
|
|
|
1195
961
|
: internalAbort.signal;
|
|
1196
962
|
if (abortSignal) {
|
|
1197
963
|
abortSignal.addEventListener("abort", () => {
|
|
1198
|
-
|
|
1199
|
-
// has no turn to stop: don't gate the next one, don't write a stop.
|
|
1200
|
-
const outstanding = !state.outstandingTurnAbandoned &&
|
|
1201
|
-
(state.isStreaming || state.activeInputSeq !== undefined);
|
|
1202
|
-
if (options?.sendStopOnAbort !== false && outstanding && !internalAbort.signal.aborted) {
|
|
964
|
+
if (options?.sendStopOnAbort !== false) {
|
|
1203
965
|
state.skipToTurnComplete = true;
|
|
1204
|
-
state.supersededInputSeq = state.activeInputSeq;
|
|
1205
966
|
this.appendInputChunk(chatId, state.publicAccessToken, this.serializeInputChunk({ kind: "stop" })).catch(() => { });
|
|
1206
967
|
}
|
|
1207
968
|
internalAbort.abort();
|
|
@@ -1261,7 +1022,26 @@ export class TriggerChatTransport {
|
|
|
1261
1022
|
})()
|
|
1262
1023
|
: () => { };
|
|
1263
1024
|
const sseCtx = { endpoint: "out", chatId };
|
|
1264
|
-
const
|
|
1025
|
+
const fetchOverride = this.fetchOverride;
|
|
1026
|
+
const sseFetchClient = fetchOverride
|
|
1027
|
+
? ((input, init) => {
|
|
1028
|
+
if (typeof input === "string") {
|
|
1029
|
+
return fetchOverride(input, init ?? {}, sseCtx);
|
|
1030
|
+
}
|
|
1031
|
+
if (input instanceof URL) {
|
|
1032
|
+
return fetchOverride(input.toString(), init ?? {}, sseCtx);
|
|
1033
|
+
}
|
|
1034
|
+
// Request — preserve its url + intrinsic init, let any
|
|
1035
|
+
// provided init override on top (matches fetch(Request, init)
|
|
1036
|
+
// semantics).
|
|
1037
|
+
return fetchOverride(input.url, {
|
|
1038
|
+
method: input.method,
|
|
1039
|
+
headers: input.headers,
|
|
1040
|
+
signal: input.signal,
|
|
1041
|
+
...(init ?? {}),
|
|
1042
|
+
}, sseCtx);
|
|
1043
|
+
})
|
|
1044
|
+
: undefined;
|
|
1265
1045
|
let sawFirstChunk = false;
|
|
1266
1046
|
let sinceInSeq = options?.sinceInSeq;
|
|
1267
1047
|
const connectSseOnce = async (token) => {
|
|
@@ -1309,6 +1089,12 @@ export class TriggerChatTransport {
|
|
|
1309
1089
|
return await connectSseOnce(fresh);
|
|
1310
1090
|
}
|
|
1311
1091
|
};
|
|
1092
|
+
// A body that ends without a turn-complete is only terminal when the
|
|
1093
|
+
// server says the session settled — otherwise the turn is still
|
|
1094
|
+
// running and we lost the connection (long-poll window closed, proxy
|
|
1095
|
+
// restarted). Resubscribe from `state.lastEventId`, bounded so a
|
|
1096
|
+
// permanently empty stream can't spin.
|
|
1097
|
+
const MAX_EOF_RESUBSCRIBES = 5;
|
|
1312
1098
|
let eofResubscribes = 0;
|
|
1313
1099
|
const resumeAfterEof = async () => {
|
|
1314
1100
|
// Watch mode is a standing subscription: it outlives turn-complete
|
|
@@ -1318,7 +1104,21 @@ export class TriggerChatTransport {
|
|
|
1318
1104
|
!currentSubscription?.sessionSettled &&
|
|
1319
1105
|
!combinedSignal.aborted) {
|
|
1320
1106
|
eofResubscribes++;
|
|
1321
|
-
|
|
1107
|
+
// Sleep, but wake immediately on abort — otherwise a stop lands
|
|
1108
|
+
// mid-backoff and the stream stays open for the rest of it.
|
|
1109
|
+
await new Promise((resolve) => {
|
|
1110
|
+
let timer;
|
|
1111
|
+
const done = () => {
|
|
1112
|
+
clearTimeout(timer);
|
|
1113
|
+
combinedSignal.removeEventListener("abort", done);
|
|
1114
|
+
resolve();
|
|
1115
|
+
};
|
|
1116
|
+
// Jitter the backoff so many clients reconnecting after the same
|
|
1117
|
+
// dropped window don't resubscribe in lockstep.
|
|
1118
|
+
const backoff = Math.min(100 * 2 ** (eofResubscribes - 1), 5_000);
|
|
1119
|
+
timer = setTimeout(done, backoff * (0.5 + Math.random() * 0.5));
|
|
1120
|
+
combinedSignal.addEventListener("abort", done);
|
|
1121
|
+
});
|
|
1322
1122
|
if (combinedSignal.aborted)
|
|
1323
1123
|
break;
|
|
1324
1124
|
const opened = await openWithAuthRetry();
|
|
@@ -1442,41 +1242,11 @@ export class TriggerChatTransport {
|
|
|
1442
1242
|
continue;
|
|
1443
1243
|
}
|
|
1444
1244
|
}
|
|
1445
|
-
if (state.skipToTurnComplete
|
|
1446
|
-
controlValue
|
|
1447
|
-
|
|
1448
|
-
// Fall through on a boundary so the `sinceInSeq` check and the
|
|
1449
|
-
// turn-completed emit below still run; content records are skipped.
|
|
1450
|
-
// A close is terminal and a pending version is the gated turn's own
|
|
1451
|
-
// handover status, so neither is ever gated away.
|
|
1452
|
-
if (controlValue !== TRIGGER_CONTROL_SUBTYPE.TURN_COMPLETE)
|
|
1453
|
-
continue;
|
|
1454
|
-
// A boundary older than the superseded turn is not its boundary —
|
|
1455
|
-
// keep gating. A header-less boundary (legacy wire) still clears.
|
|
1456
|
-
const gateCursorRaw = headerValue(value.headers, SESSION_IN_EVENT_ID_HEADER);
|
|
1457
|
-
const gateCursor = gateCursorRaw !== undefined ? Number.parseInt(gateCursorRaw, 10) : NaN;
|
|
1458
|
-
if (state.supersededInputSeq !== undefined &&
|
|
1459
|
-
!Number.isNaN(gateCursor) &&
|
|
1460
|
-
gateCursor < state.supersededInputSeq) {
|
|
1461
|
-
continue;
|
|
1462
|
-
}
|
|
1463
|
-
state.skipToTurnComplete = false;
|
|
1464
|
-
state.supersededInputSeq = undefined;
|
|
1465
|
-
// This boundary is the new turn's own, so the gate swallowed its
|
|
1466
|
-
// output: fail the turn instead of completing an empty answer, and
|
|
1467
|
-
// leave nothing armed for the retry.
|
|
1468
|
-
if (sinceInSeq !== undefined &&
|
|
1469
|
-
!Number.isNaN(gateCursor) &&
|
|
1470
|
-
gateCursor >= sinceInSeq) {
|
|
1471
|
-
// The lost boundary may also carry the session close.
|
|
1472
|
-
if (headerValue(value.headers, SESSION_CLOSED_HEADER) === "true") {
|
|
1473
|
-
this.markSessionClosed(chatId, state, headerValue(value.headers, SESSION_CLOSED_REASON_HEADER), "stream");
|
|
1474
|
-
}
|
|
1475
|
-
state.activeInputSeq = undefined;
|
|
1476
|
-
state.isStreaming = false;
|
|
1477
|
-
this.notifySessionChange(chatId, state);
|
|
1478
|
-
throw new Error("The previous turn's output was lost. Try again.");
|
|
1245
|
+
if (state.skipToTurnComplete) {
|
|
1246
|
+
if (controlValue === TRIGGER_CONTROL_SUBTYPE.TURN_COMPLETE) {
|
|
1247
|
+
state.skipToTurnComplete = false;
|
|
1479
1248
|
}
|
|
1249
|
+
continue;
|
|
1480
1250
|
}
|
|
1481
1251
|
if (controlValue === TRIGGER_CONTROL_SUBTYPE.UPGRADE_REQUIRED) {
|
|
1482
1252
|
// Server has already triggered the new run via
|
|
@@ -1485,26 +1255,6 @@ export class TriggerChatTransport {
|
|
|
1485
1255
|
// and keep reading.
|
|
1486
1256
|
continue;
|
|
1487
1257
|
}
|
|
1488
|
-
if (controlValue === TRIGGER_CONTROL_SUBTYPE.SESSION_CLOSED) {
|
|
1489
|
-
this.markSessionClosed(chatId, state, headerValue(value.headers, SESSION_CLOSED_REASON_HEADER), "stream");
|
|
1490
|
-
internalAbort.abort();
|
|
1491
|
-
try {
|
|
1492
|
-
controller.close();
|
|
1493
|
-
}
|
|
1494
|
-
catch {
|
|
1495
|
-
/* already closed */
|
|
1496
|
-
}
|
|
1497
|
-
return;
|
|
1498
|
-
}
|
|
1499
|
-
if (controlValue === TRIGGER_CONTROL_SUBTYPE.PENDING_VERSION) {
|
|
1500
|
-
this.emitEvent({
|
|
1501
|
-
type: "run-pending-version",
|
|
1502
|
-
chatId,
|
|
1503
|
-
timestamp: Date.now(),
|
|
1504
|
-
source: "upgrade",
|
|
1505
|
-
});
|
|
1506
|
-
continue;
|
|
1507
|
-
}
|
|
1508
1258
|
if (controlValue === TRIGGER_CONTROL_SUBTYPE.TURN_COMPLETE) {
|
|
1509
1259
|
// Skip a turn-complete from an earlier turn (committed `.in` cursor
|
|
1510
1260
|
// below this send's seq), e.g. an undo action that raced this send.
|
|
@@ -1515,11 +1265,6 @@ export class TriggerChatTransport {
|
|
|
1515
1265
|
continue;
|
|
1516
1266
|
}
|
|
1517
1267
|
}
|
|
1518
|
-
// A close decided during this turn rides out on turn-complete —
|
|
1519
|
-
// the last record a reader sees before it ends the stream.
|
|
1520
|
-
if (headerValue(value.headers, SESSION_CLOSED_HEADER) === "true") {
|
|
1521
|
-
this.markSessionClosed(chatId, state, headerValue(value.headers, SESSION_CLOSED_REASON_HEADER), "stream");
|
|
1522
|
-
}
|
|
1523
1268
|
const refreshedToken = headerValue(value.headers, PUBLIC_ACCESS_TOKEN_HEADER) ??
|
|
1524
1269
|
legacyChunk?.publicAccessToken;
|
|
1525
1270
|
if (refreshedToken) {
|