@agent-native/core 0.101.3 → 0.101.4
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/corpus/README.md +1 -1
- package/corpus/core/CHANGELOG.md +7 -0
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/client/RunStuckBanner.tsx +12 -5
- package/corpus/core/src/client/sse-event-processor.ts +36 -1
- package/corpus/core/src/client/use-run-stuck-detection.ts +162 -25
- package/corpus/core/src/deploy/build.ts +78 -25
- package/corpus/templates/chat/changelog/2026-07-14-chat-opens-reliably-on-hosted-deployments-instead-of-failing.md +6 -0
- package/corpus/templates/clips/app/components/player/media-duration.ts +24 -0
- package/corpus/templates/clips/app/components/player/video-player.tsx +9 -18
- package/corpus/templates/clips/changelog/2026-07-14-paused-time-no-longer-counts-toward-chrome-extension-recordi.md +6 -0
- package/corpus/templates/clips/chrome-extension/src/offscreen.ts +30 -4
- package/corpus/templates/clips/chrome-extension/src/recording-duration.ts +32 -0
- package/corpus/templates/slides/actions/_uploaded-files.ts +13 -2
- package/corpus/templates/slides/actions/import-docx.ts +3 -9
- package/corpus/templates/slides/actions/import-file.ts +11 -14
- package/corpus/templates/slides/actions/import-pptx.ts +3 -9
- package/corpus/templates/slides/changelog/2026-07-14-powerpoint-template-uploads-now-work-in-hosted-slides-deploy.md +6 -0
- package/corpus/templates/slides/server/handlers/uploads.ts +100 -50
- package/corpus/templates/slides/server/lib/tenant-files.ts +38 -11
- package/corpus/templates/slides/server/lib/uploaded-reference-storage.ts +108 -0
- package/dist/client/RunStuckBanner.d.ts.map +1 -1
- package/dist/client/RunStuckBanner.js +9 -5
- package/dist/client/RunStuckBanner.js.map +1 -1
- package/dist/client/sse-event-processor.d.ts.map +1 -1
- package/dist/client/sse-event-processor.js +33 -1
- package/dist/client/sse-event-processor.js.map +1 -1
- package/dist/client/use-run-stuck-detection.d.ts +4 -4
- package/dist/client/use-run-stuck-detection.d.ts.map +1 -1
- package/dist/client/use-run-stuck-detection.js +104 -19
- package/dist/client/use-run-stuck-detection.js.map +1 -1
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/awareness.d.ts.map +1 -1
- package/dist/deploy/build.d.ts +15 -14
- package/dist/deploy/build.d.ts.map +1 -1
- package/dist/deploy/build.js +64 -23
- package/dist/deploy/build.js.map +1 -1
- package/dist/notifications/routes.d.ts +3 -3
- package/dist/progress/routes.d.ts +1 -1
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/package.json +1 -1
|
@@ -28,6 +28,89 @@ export function useRunStuckDetection({ threadId, enabled = true, stuckThresholdM
|
|
|
28
28
|
const base = apiUrl ?? agentNativePath("/_agent-native/agent-chat");
|
|
29
29
|
let cancelled = false;
|
|
30
30
|
let timer = null;
|
|
31
|
+
let snapshotTransitionTimer = null;
|
|
32
|
+
let snapshotVersion = 0;
|
|
33
|
+
const effectiveThresholdFor = (dispatchMode, heartbeatSinceMs) => {
|
|
34
|
+
const liveBackgroundWorker = dispatchMode === "background-processing" &&
|
|
35
|
+
heartbeatSinceMs != null &&
|
|
36
|
+
heartbeatSinceMs >= 0 &&
|
|
37
|
+
heartbeatSinceMs < FRESH_BACKGROUND_HEARTBEAT_MS;
|
|
38
|
+
const serverContinued = dispatchMode === "foreground-self-chain" ||
|
|
39
|
+
dispatchMode?.startsWith("background") === true;
|
|
40
|
+
return liveBackgroundWorker
|
|
41
|
+
? Math.min(backgroundStuckThresholdMs, liveBackgroundStuckThresholdMs)
|
|
42
|
+
: serverContinued
|
|
43
|
+
? backgroundStuckThresholdMs
|
|
44
|
+
: stuckThresholdMs;
|
|
45
|
+
};
|
|
46
|
+
const scheduleSnapshotTransition = (snapshot, observedAtMs, version) => {
|
|
47
|
+
if (snapshotTransitionTimer)
|
|
48
|
+
clearTimeout(snapshotTransitionTimer);
|
|
49
|
+
snapshotTransitionTimer = null;
|
|
50
|
+
if (cancelled ||
|
|
51
|
+
version !== snapshotVersion ||
|
|
52
|
+
!snapshot.active ||
|
|
53
|
+
snapshot.status !== "running" ||
|
|
54
|
+
snapshot.runId == null) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
const currentElapsedMs = Math.max(0, Date.now() - observedAtMs);
|
|
58
|
+
const currentHeartbeatSinceMs = snapshot.heartbeatSinceMs == null
|
|
59
|
+
? null
|
|
60
|
+
: snapshot.heartbeatSinceMs + currentElapsedMs;
|
|
61
|
+
const currentStuckSinceMs = snapshot.stuckSinceMs == null
|
|
62
|
+
? null
|
|
63
|
+
: snapshot.stuckSinceMs + currentElapsedMs;
|
|
64
|
+
const effectiveThresholdMs = effectiveThresholdFor(snapshot.dispatchMode, currentHeartbeatSinceMs);
|
|
65
|
+
const currentlyStuck = Boolean(currentStuckSinceMs != null &&
|
|
66
|
+
currentStuckSinceMs > effectiveThresholdMs);
|
|
67
|
+
const transitionDelaysMs = [];
|
|
68
|
+
if (currentHeartbeatSinceMs != null &&
|
|
69
|
+
currentHeartbeatSinceMs >= 0 &&
|
|
70
|
+
currentHeartbeatSinceMs < FRESH_BACKGROUND_HEARTBEAT_MS) {
|
|
71
|
+
transitionDelaysMs.push(FRESH_BACKGROUND_HEARTBEAT_MS - currentHeartbeatSinceMs + 1);
|
|
72
|
+
}
|
|
73
|
+
if (currentStuckSinceMs != null && !currentlyStuck) {
|
|
74
|
+
transitionDelaysMs.push(Math.max(1, effectiveThresholdMs - currentStuckSinceMs + 1));
|
|
75
|
+
}
|
|
76
|
+
if (transitionDelaysMs.length === 0)
|
|
77
|
+
return;
|
|
78
|
+
// Both ages originate from the server clock. Advance those snapshots by
|
|
79
|
+
// only a local elapsed duration, which remains safe when client/server
|
|
80
|
+
// wall clocks differ. Wake at the earlier semantic boundary, then
|
|
81
|
+
// reschedule if the other boundary is still ahead.
|
|
82
|
+
const delayMs = Math.max(1, Math.min(...transitionDelaysMs));
|
|
83
|
+
snapshotTransitionTimer = setTimeout(() => {
|
|
84
|
+
snapshotTransitionTimer = null;
|
|
85
|
+
if (cancelled || version !== snapshotVersion)
|
|
86
|
+
return;
|
|
87
|
+
const elapsedSinceObservationMs = Math.max(0, Date.now() - observedAtMs);
|
|
88
|
+
const nextHeartbeatSinceMs = snapshot.heartbeatSinceMs == null
|
|
89
|
+
? null
|
|
90
|
+
: snapshot.heartbeatSinceMs + elapsedSinceObservationMs;
|
|
91
|
+
const nextStuckSinceMs = snapshot.stuckSinceMs == null
|
|
92
|
+
? null
|
|
93
|
+
: snapshot.stuckSinceMs + elapsedSinceObservationMs;
|
|
94
|
+
const nextEffectiveThresholdMs = effectiveThresholdFor(snapshot.dispatchMode, nextHeartbeatSinceMs);
|
|
95
|
+
const nextIsStuck = Boolean(nextStuckSinceMs != null &&
|
|
96
|
+
nextStuckSinceMs > nextEffectiveThresholdMs);
|
|
97
|
+
setState((current) => {
|
|
98
|
+
if (version !== snapshotVersion ||
|
|
99
|
+
current.runId !== snapshot.runId ||
|
|
100
|
+
current.lastProgressAt !== snapshot.lastProgressAt ||
|
|
101
|
+
current.heartbeatAt !== snapshot.heartbeatAt) {
|
|
102
|
+
return current;
|
|
103
|
+
}
|
|
104
|
+
return {
|
|
105
|
+
...current,
|
|
106
|
+
isStuck: nextIsStuck,
|
|
107
|
+
stuckSinceMs: nextStuckSinceMs,
|
|
108
|
+
heartbeatSinceMs: nextHeartbeatSinceMs,
|
|
109
|
+
};
|
|
110
|
+
});
|
|
111
|
+
scheduleSnapshotTransition(snapshot, observedAtMs, version);
|
|
112
|
+
}, delayMs);
|
|
113
|
+
};
|
|
31
114
|
const poll = async () => {
|
|
32
115
|
if (cancelled)
|
|
33
116
|
return;
|
|
@@ -49,30 +132,29 @@ export function useRunStuckDetection({ threadId, enabled = true, stuckThresholdM
|
|
|
49
132
|
const heartbeatAt = data.heartbeatAt ?? null;
|
|
50
133
|
const heartbeatSinceMs = heartbeatAt != null ? nowMs - heartbeatAt : null;
|
|
51
134
|
const dispatchMode = typeof data.dispatchMode === "string" ? data.dispatchMode : null;
|
|
52
|
-
// Server-continued runs get the wider threshold: the server's own
|
|
53
|
-
// recovery (150s no-progress backstop + chained continuations) must
|
|
54
|
-
// get its chance before the user sees a "stuck" affordance.
|
|
55
|
-
const serverContinued = dispatchMode === "foreground-self-chain" ||
|
|
56
|
-
dispatchMode?.startsWith("background") === true;
|
|
57
135
|
// A claimed durable worker with a fresh heartbeat can legitimately
|
|
58
|
-
// be waiting on a bounded long-running tool/sub-agent call.
|
|
59
|
-
//
|
|
60
|
-
//
|
|
61
|
-
//
|
|
62
|
-
//
|
|
63
|
-
const
|
|
64
|
-
heartbeatSinceMs != null &&
|
|
65
|
-
heartbeatSinceMs >= 0 &&
|
|
66
|
-
heartbeatSinceMs < FRESH_BACKGROUND_HEARTBEAT_MS;
|
|
67
|
-
const effectiveThresholdMs = liveBackgroundWorker
|
|
68
|
-
? liveBackgroundStuckThresholdMs
|
|
69
|
-
: serverContinued
|
|
70
|
-
? backgroundStuckThresholdMs
|
|
71
|
-
: stuckThresholdMs;
|
|
136
|
+
// be waiting on a bounded long-running tool/sub-agent call. Still
|
|
137
|
+
// surface informational status at the normal background threshold;
|
|
138
|
+
// RunStuckBanner uses the fresh heartbeat to withhold Retry while
|
|
139
|
+
// keeping an explicit Cancel available. The legacy live-worker
|
|
140
|
+
// threshold may make that notice earlier, but never later.
|
|
141
|
+
const effectiveThresholdMs = effectiveThresholdFor(dispatchMode, heartbeatSinceMs);
|
|
72
142
|
const isStuck = Boolean(data.active &&
|
|
73
143
|
data.status === "running" &&
|
|
74
144
|
stuckSinceMs != null &&
|
|
75
145
|
stuckSinceMs > effectiveThresholdMs);
|
|
146
|
+
const observedAtMs = Date.now();
|
|
147
|
+
const version = ++snapshotVersion;
|
|
148
|
+
scheduleSnapshotTransition({
|
|
149
|
+
active: data.active,
|
|
150
|
+
runId: data.runId ?? null,
|
|
151
|
+
status: data.status ?? null,
|
|
152
|
+
lastProgressAt,
|
|
153
|
+
stuckSinceMs,
|
|
154
|
+
heartbeatAt,
|
|
155
|
+
heartbeatSinceMs,
|
|
156
|
+
dispatchMode,
|
|
157
|
+
}, observedAtMs, version);
|
|
76
158
|
setState({
|
|
77
159
|
isStuck,
|
|
78
160
|
runId: data.runId ?? null,
|
|
@@ -107,8 +189,11 @@ export function useRunStuckDetection({ threadId, enabled = true, stuckThresholdM
|
|
|
107
189
|
timer = setTimeout(poll, 2_000);
|
|
108
190
|
return () => {
|
|
109
191
|
cancelled = true;
|
|
192
|
+
snapshotVersion += 1;
|
|
110
193
|
if (timer)
|
|
111
194
|
clearTimeout(timer);
|
|
195
|
+
if (snapshotTransitionTimer)
|
|
196
|
+
clearTimeout(snapshotTransitionTimer);
|
|
112
197
|
};
|
|
113
198
|
}, [
|
|
114
199
|
threadId,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-run-stuck-detection.js","sourceRoot":"","sources":["../../src/client/use-run-stuck-detection.ts"],"names":[],"mappings":"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","sourcesContent":["import { useEffect, useState, useCallback } from \"react\";\n\nimport { agentNativePath } from \"./api-path.js\";\n\n/**\n * Per-thread chat run health, derived from the durable `last_progress_at`\n * timestamp on the server. Drives the user-visible \"this chat looks stuck\"\n * affordance — distinct from the silent reconnect logic in\n * `agent-chat-adapter.ts`, which keeps trying in the background. When\n * automatic recovery isn't making progress (for whatever reason), this\n * hook surfaces a Retry / Cancel button to the user instead of leaving\n * them staring at a frozen spinner.\n */\nexport interface RunStuckState {\n /** True when an active run hasn't emitted an event for `stuckThresholdMs`. */\n isStuck: boolean;\n /** ID of the active run, or null when nothing is in flight. */\n runId: string | null;\n /** Server-side run status (\"running\" / \"completed\" / \"errored\" / etc.). */\n status: string | null;\n /** Server timestamp (ms) of the last emitted event, or null if none yet. */\n lastProgressAt: number | null;\n /** Milliseconds since `lastProgressAt`, or null. */\n stuckSinceMs: number | null;\n /** Server timestamp (ms) of the last process-alive heartbeat. */\n heartbeatAt: number | null;\n /** Milliseconds since `heartbeatAt`, computed against the server clock. */\n heartbeatSinceMs: number | null;\n /** How the run was dispatched/continued, e.g. foreground-self-chain or background-processing. */\n dispatchMode: string | null;\n /**\n * Server-authoritative: true when the run holds an open tool call or A2A\n * `agent_call` delegation (`in_flight_since` marker set). Preferred over the\n * client-side proxy for deciding whether Retry (which aborts the run) is\n * safe to offer. Null when the server bundle predates this field.\n */\n hasInFlightWork: boolean | null;\n}\n\nexport interface UseRunStuckDetectionOptions {\n /** The thread to monitor. Pass null/undefined to disable polling. */\n threadId: string | null | undefined;\n /**\n * Set false to skip scheduling the poll loop entirely — used to gate\n * polling to only the active chat tab when multiple tabs are mounted\n * (inactive tabs are kept alive via display:none, not unmounted).\n * Defaults to true.\n */\n enabled?: boolean;\n /**\n * Threshold above which an in-flight FOREGROUND run is considered stuck.\n * The default sits comfortably above the adapter's 75s no-progress\n * reconnect — by then automatic recovery has already had its chance.\n */\n stuckThresholdMs?: number;\n /**\n * Threshold for BACKGROUND-dispatched runs (dispatchMode starts with\n * \"background\"). The server owns recovery for these — its run-manager\n * no-progress backstop (150s) and unclaimed-run sweep act first — so the\n * user-facing \"stuck\" affordance is a late fallback, not a race against\n * them. Selected inside the hook because the dispatch mode is only known\n * from the same poll response that computes the elapsed time.\n */\n backgroundStuckThresholdMs?: number;\n /**\n * Threshold for a claimed durable background worker that is still sending\n * fresh process heartbeats. These workers can legitimately spend up to the\n * 12-minute tool/no-progress window on large Design, Plan, or Assets work.\n * Default 13 minutes, matching the durable chunk handoff boundary.\n */\n liveBackgroundStuckThresholdMs?: number;\n /** Poll interval. Default 5_000ms. */\n pollIntervalMs?: number;\n /** API base path. Default `/_agent-native/agent-chat`. */\n apiUrl?: string;\n}\n\nconst DEFAULT_STUCK_THRESHOLD_MS = 90_000;\nexport const DEFAULT_BACKGROUND_STUCK_THRESHOLD_MS = 180_000;\nexport const DEFAULT_LIVE_BACKGROUND_STUCK_THRESHOLD_MS = 13 * 60_000;\nconst DEFAULT_POLL_INTERVAL_MS = 5_000;\nconst IDLE_BACKOFF_INTERVAL_MS = 15_000;\nconst FRESH_BACKGROUND_HEARTBEAT_MS = 30_000;\n\ninterface ActiveRunResponse {\n active: boolean;\n runId?: string;\n status?: string;\n heartbeatAt: number | null;\n lastProgressAt?: number | null;\n dispatchMode?: string | null;\n /** Server clock at response time, used to compute elapsed server-relative. */\n serverNow?: number;\n /** True when the run holds an open tool/A2A call (in_flight_since marker). */\n hasInFlightWork?: boolean;\n}\n\nconst EMPTY_STATE: RunStuckState = {\n isStuck: false,\n runId: null,\n status: null,\n lastProgressAt: null,\n stuckSinceMs: null,\n heartbeatAt: null,\n heartbeatSinceMs: null,\n dispatchMode: null,\n hasInFlightWork: null,\n};\n\nexport function useRunStuckDetection({\n threadId,\n enabled = true,\n stuckThresholdMs = DEFAULT_STUCK_THRESHOLD_MS,\n backgroundStuckThresholdMs = DEFAULT_BACKGROUND_STUCK_THRESHOLD_MS,\n liveBackgroundStuckThresholdMs = DEFAULT_LIVE_BACKGROUND_STUCK_THRESHOLD_MS,\n pollIntervalMs = DEFAULT_POLL_INTERVAL_MS,\n apiUrl,\n}: UseRunStuckDetectionOptions): RunStuckState {\n const [state, setState] = useState<RunStuckState>(EMPTY_STATE);\n\n useEffect(() => {\n // Reset on every thread change so the previous thread's stuck banner\n // doesn't bleed onto the new one before the first poll completes.\n setState(EMPTY_STATE);\n if (!threadId || !enabled) return;\n\n const base = apiUrl ?? agentNativePath(\"/_agent-native/agent-chat\");\n let cancelled = false;\n let timer: ReturnType<typeof setTimeout> | null = null;\n\n const poll = async () => {\n if (cancelled) return;\n let nextDelay = pollIntervalMs;\n try {\n const res = await fetch(\n `${base}/runs/active?threadId=${encodeURIComponent(threadId)}`,\n { credentials: \"same-origin\" },\n );\n if (cancelled) return;\n if (res.ok) {\n const data = (await res.json()) as ActiveRunResponse;\n const lastProgressAt = data.lastProgressAt ?? null;\n // Measure elapsed against the SERVER clock (serverNow) rather than the\n // client's Date.now(). lastProgressAt is a server timestamp, so client\n // clock skew of more than stuckThresholdMs would otherwise mark every\n // run stuck (clock ahead) or never stuck (clock behind). Fall back to\n // the client clock for older bundles that don't send serverNow.\n const nowMs = data.serverNow ?? Date.now();\n const stuckSinceMs =\n lastProgressAt != null ? nowMs - lastProgressAt : null;\n const heartbeatAt = data.heartbeatAt ?? null;\n const heartbeatSinceMs =\n heartbeatAt != null ? nowMs - heartbeatAt : null;\n const dispatchMode =\n typeof data.dispatchMode === \"string\" ? data.dispatchMode : null;\n // Server-continued runs get the wider threshold: the server's own\n // recovery (150s no-progress backstop + chained continuations) must\n // get its chance before the user sees a \"stuck\" affordance.\n const serverContinued =\n dispatchMode === \"foreground-self-chain\" ||\n dispatchMode?.startsWith(\"background\") === true;\n // A claimed durable worker with a fresh heartbeat can legitimately\n // be waiting on a bounded long-running tool/sub-agent call. Showing\n // Retry at the generic 3-minute continuation threshold aborts healthy\n // work and starts the same call again. Let the worker's own 12-minute\n // watchdog act first; a dead/stale heartbeat still gets the earlier\n // background fallback below.\n const liveBackgroundWorker =\n dispatchMode === \"background-processing\" &&\n heartbeatSinceMs != null &&\n heartbeatSinceMs >= 0 &&\n heartbeatSinceMs < FRESH_BACKGROUND_HEARTBEAT_MS;\n const effectiveThresholdMs = liveBackgroundWorker\n ? liveBackgroundStuckThresholdMs\n : serverContinued\n ? backgroundStuckThresholdMs\n : stuckThresholdMs;\n const isStuck = Boolean(\n data.active &&\n data.status === \"running\" &&\n stuckSinceMs != null &&\n stuckSinceMs > effectiveThresholdMs,\n );\n setState({\n isStuck,\n runId: data.runId ?? null,\n status: data.status ?? null,\n lastProgressAt,\n stuckSinceMs,\n heartbeatAt,\n heartbeatSinceMs,\n dispatchMode,\n hasInFlightWork:\n typeof data.hasInFlightWork === \"boolean\"\n ? data.hasInFlightWork\n : null,\n });\n // Back off polling when nothing is in flight — there's no point\n // hammering the endpoint while the chat is idle. We still poll\n // occasionally so a fresh run started in another tab is picked up.\n if (!data.active || data.status !== \"running\") {\n nextDelay = IDLE_BACKOFF_INTERVAL_MS;\n }\n }\n } catch {\n // Network blip — leave previous state. Next tick will retry.\n }\n if (!cancelled) {\n timer = setTimeout(poll, nextDelay);\n }\n };\n\n // Stagger the first poll so a freshly-started run isn't immediately\n // classified as stuck before the server has had a chance to record\n // any progress events.\n timer = setTimeout(poll, 2_000);\n\n return () => {\n cancelled = true;\n if (timer) clearTimeout(timer);\n };\n }, [\n threadId,\n enabled,\n stuckThresholdMs,\n backgroundStuckThresholdMs,\n liveBackgroundStuckThresholdMs,\n pollIntervalMs,\n apiUrl,\n ]);\n\n return state;\n}\n\n/**\n * POST `/runs/:id/abort` so the server flips the run to \"aborted\" and the\n * adapter's reconnect loop exits cleanly. Returns the run id that was\n * aborted (or null on failure) so callers can correlate observability\n * events. Best-effort — failures are swallowed, since the user's intent\n * is already captured locally.\n */\nexport function useAbortRun(apiUrl?: string) {\n return useCallback(\n async (runId: string, reason: string = \"user\"): Promise<string | null> => {\n const base = apiUrl ?? agentNativePath(\"/_agent-native/agent-chat\");\n try {\n const res = await fetch(\n `${base}/runs/${encodeURIComponent(runId)}/abort`,\n {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n credentials: \"same-origin\",\n body: JSON.stringify({ reason }),\n },\n );\n if (!res.ok) return null;\n return runId;\n } catch {\n return null;\n }\n },\n [apiUrl],\n );\n}\n"]}
|
|
1
|
+
{"version":3,"file":"use-run-stuck-detection.js","sourceRoot":"","sources":["../../src/client/use-run-stuck-detection.ts"],"names":[],"mappings":"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","sourcesContent":["import { useEffect, useState, useCallback } from \"react\";\n\nimport { agentNativePath } from \"./api-path.js\";\n\n/**\n * Per-thread chat run health, derived from the durable `last_progress_at`\n * timestamp on the server. Drives the user-visible \"this chat looks stuck\"\n * affordance — distinct from the silent reconnect logic in\n * `agent-chat-adapter.ts`, which keeps trying in the background. When\n * automatic recovery isn't making progress (for whatever reason), this\n * hook surfaces a Retry / Cancel button to the user instead of leaving\n * them staring at a frozen spinner.\n */\nexport interface RunStuckState {\n /** True when an active run hasn't emitted an event for `stuckThresholdMs`. */\n isStuck: boolean;\n /** ID of the active run, or null when nothing is in flight. */\n runId: string | null;\n /** Server-side run status (\"running\" / \"completed\" / \"errored\" / etc.). */\n status: string | null;\n /** Server timestamp (ms) of the last emitted event, or null if none yet. */\n lastProgressAt: number | null;\n /** Milliseconds since `lastProgressAt`, or null. */\n stuckSinceMs: number | null;\n /** Server timestamp (ms) of the last process-alive heartbeat. */\n heartbeatAt: number | null;\n /** Milliseconds since `heartbeatAt`, computed against the server clock. */\n heartbeatSinceMs: number | null;\n /** How the run was dispatched/continued, e.g. foreground-self-chain or background-processing. */\n dispatchMode: string | null;\n /**\n * Server-authoritative: true when the run holds an open tool call or A2A\n * `agent_call` delegation (`in_flight_since` marker set). Preferred over the\n * client-side proxy for deciding whether Retry (which aborts the run) is\n * safe to offer. Null when the server bundle predates this field.\n */\n hasInFlightWork: boolean | null;\n}\n\nexport interface UseRunStuckDetectionOptions {\n /** The thread to monitor. Pass null/undefined to disable polling. */\n threadId: string | null | undefined;\n /**\n * Set false to skip scheduling the poll loop entirely — used to gate\n * polling to only the active chat tab when multiple tabs are mounted\n * (inactive tabs are kept alive via display:none, not unmounted).\n * Defaults to true.\n */\n enabled?: boolean;\n /**\n * Threshold above which an in-flight FOREGROUND run is considered stuck.\n * The default sits comfortably above the adapter's 75s no-progress\n * reconnect — by then automatic recovery has already had its chance.\n */\n stuckThresholdMs?: number;\n /**\n * Threshold for BACKGROUND-dispatched runs (dispatchMode starts with\n * \"background\"). The server owns recovery for these — its run-manager\n * no-progress backstop (150s) and unclaimed-run sweep act first — so the\n * user-facing \"stuck\" affordance is a late fallback, not a race against\n * them. Selected inside the hook because the dispatch mode is only known\n * from the same poll response that computes the elapsed time.\n */\n backgroundStuckThresholdMs?: number;\n /**\n * Legacy upper bound for a claimed durable background worker that is still\n * sending fresh process heartbeats. Informational quiet-run UI is never\n * delayed past `backgroundStuckThresholdMs`; this option can only request an\n * earlier notice for live workers. Default 13 minutes.\n */\n liveBackgroundStuckThresholdMs?: number;\n /** Poll interval. Default 5_000ms. */\n pollIntervalMs?: number;\n /** API base path. Default `/_agent-native/agent-chat`. */\n apiUrl?: string;\n}\n\nconst DEFAULT_STUCK_THRESHOLD_MS = 90_000;\nexport const DEFAULT_BACKGROUND_STUCK_THRESHOLD_MS = 180_000;\nexport const DEFAULT_LIVE_BACKGROUND_STUCK_THRESHOLD_MS = 13 * 60_000;\nconst DEFAULT_POLL_INTERVAL_MS = 5_000;\nconst IDLE_BACKOFF_INTERVAL_MS = 15_000;\nconst FRESH_BACKGROUND_HEARTBEAT_MS = 30_000;\n\ninterface ActiveRunResponse {\n active: boolean;\n runId?: string;\n status?: string;\n heartbeatAt: number | null;\n lastProgressAt?: number | null;\n dispatchMode?: string | null;\n /** Server clock at response time, used to compute elapsed server-relative. */\n serverNow?: number;\n /** True when the run holds an open tool/A2A call (in_flight_since marker). */\n hasInFlightWork?: boolean;\n}\n\nconst EMPTY_STATE: RunStuckState = {\n isStuck: false,\n runId: null,\n status: null,\n lastProgressAt: null,\n stuckSinceMs: null,\n heartbeatAt: null,\n heartbeatSinceMs: null,\n dispatchMode: null,\n hasInFlightWork: null,\n};\n\nexport function useRunStuckDetection({\n threadId,\n enabled = true,\n stuckThresholdMs = DEFAULT_STUCK_THRESHOLD_MS,\n backgroundStuckThresholdMs = DEFAULT_BACKGROUND_STUCK_THRESHOLD_MS,\n liveBackgroundStuckThresholdMs = DEFAULT_LIVE_BACKGROUND_STUCK_THRESHOLD_MS,\n pollIntervalMs = DEFAULT_POLL_INTERVAL_MS,\n apiUrl,\n}: UseRunStuckDetectionOptions): RunStuckState {\n const [state, setState] = useState<RunStuckState>(EMPTY_STATE);\n\n useEffect(() => {\n // Reset on every thread change so the previous thread's stuck banner\n // doesn't bleed onto the new one before the first poll completes.\n setState(EMPTY_STATE);\n if (!threadId || !enabled) return;\n\n const base = apiUrl ?? agentNativePath(\"/_agent-native/agent-chat\");\n let cancelled = false;\n let timer: ReturnType<typeof setTimeout> | null = null;\n let snapshotTransitionTimer: ReturnType<typeof setTimeout> | null = null;\n let snapshotVersion = 0;\n\n type RunHealthSnapshot = {\n active: boolean;\n runId: string | null;\n status: string | null;\n lastProgressAt: number | null;\n stuckSinceMs: number | null;\n heartbeatAt: number | null;\n heartbeatSinceMs: number | null;\n dispatchMode: string | null;\n };\n\n const effectiveThresholdFor = (\n dispatchMode: string | null,\n heartbeatSinceMs: number | null,\n ) => {\n const liveBackgroundWorker =\n dispatchMode === \"background-processing\" &&\n heartbeatSinceMs != null &&\n heartbeatSinceMs >= 0 &&\n heartbeatSinceMs < FRESH_BACKGROUND_HEARTBEAT_MS;\n const serverContinued =\n dispatchMode === \"foreground-self-chain\" ||\n dispatchMode?.startsWith(\"background\") === true;\n return liveBackgroundWorker\n ? Math.min(backgroundStuckThresholdMs, liveBackgroundStuckThresholdMs)\n : serverContinued\n ? backgroundStuckThresholdMs\n : stuckThresholdMs;\n };\n\n const scheduleSnapshotTransition = (\n snapshot: RunHealthSnapshot,\n observedAtMs: number,\n version: number,\n ) => {\n if (snapshotTransitionTimer) clearTimeout(snapshotTransitionTimer);\n snapshotTransitionTimer = null;\n if (\n cancelled ||\n version !== snapshotVersion ||\n !snapshot.active ||\n snapshot.status !== \"running\" ||\n snapshot.runId == null\n ) {\n return;\n }\n\n const currentElapsedMs = Math.max(0, Date.now() - observedAtMs);\n const currentHeartbeatSinceMs =\n snapshot.heartbeatSinceMs == null\n ? null\n : snapshot.heartbeatSinceMs + currentElapsedMs;\n const currentStuckSinceMs =\n snapshot.stuckSinceMs == null\n ? null\n : snapshot.stuckSinceMs + currentElapsedMs;\n const effectiveThresholdMs = effectiveThresholdFor(\n snapshot.dispatchMode,\n currentHeartbeatSinceMs,\n );\n const currentlyStuck = Boolean(\n currentStuckSinceMs != null &&\n currentStuckSinceMs > effectiveThresholdMs,\n );\n const transitionDelaysMs: number[] = [];\n if (\n currentHeartbeatSinceMs != null &&\n currentHeartbeatSinceMs >= 0 &&\n currentHeartbeatSinceMs < FRESH_BACKGROUND_HEARTBEAT_MS\n ) {\n transitionDelaysMs.push(\n FRESH_BACKGROUND_HEARTBEAT_MS - currentHeartbeatSinceMs + 1,\n );\n }\n if (currentStuckSinceMs != null && !currentlyStuck) {\n transitionDelaysMs.push(\n Math.max(1, effectiveThresholdMs - currentStuckSinceMs + 1),\n );\n }\n if (transitionDelaysMs.length === 0) return;\n\n // Both ages originate from the server clock. Advance those snapshots by\n // only a local elapsed duration, which remains safe when client/server\n // wall clocks differ. Wake at the earlier semantic boundary, then\n // reschedule if the other boundary is still ahead.\n const delayMs = Math.max(1, Math.min(...transitionDelaysMs));\n snapshotTransitionTimer = setTimeout(() => {\n snapshotTransitionTimer = null;\n if (cancelled || version !== snapshotVersion) return;\n const elapsedSinceObservationMs = Math.max(\n 0,\n Date.now() - observedAtMs,\n );\n const nextHeartbeatSinceMs =\n snapshot.heartbeatSinceMs == null\n ? null\n : snapshot.heartbeatSinceMs + elapsedSinceObservationMs;\n const nextStuckSinceMs =\n snapshot.stuckSinceMs == null\n ? null\n : snapshot.stuckSinceMs + elapsedSinceObservationMs;\n const nextEffectiveThresholdMs = effectiveThresholdFor(\n snapshot.dispatchMode,\n nextHeartbeatSinceMs,\n );\n const nextIsStuck = Boolean(\n nextStuckSinceMs != null &&\n nextStuckSinceMs > nextEffectiveThresholdMs,\n );\n setState((current) => {\n if (\n version !== snapshotVersion ||\n current.runId !== snapshot.runId ||\n current.lastProgressAt !== snapshot.lastProgressAt ||\n current.heartbeatAt !== snapshot.heartbeatAt\n ) {\n return current;\n }\n return {\n ...current,\n isStuck: nextIsStuck,\n stuckSinceMs: nextStuckSinceMs,\n heartbeatSinceMs: nextHeartbeatSinceMs,\n };\n });\n scheduleSnapshotTransition(snapshot, observedAtMs, version);\n }, delayMs);\n };\n\n const poll = async () => {\n if (cancelled) return;\n let nextDelay = pollIntervalMs;\n try {\n const res = await fetch(\n `${base}/runs/active?threadId=${encodeURIComponent(threadId)}`,\n { credentials: \"same-origin\" },\n );\n if (cancelled) return;\n if (res.ok) {\n const data = (await res.json()) as ActiveRunResponse;\n const lastProgressAt = data.lastProgressAt ?? null;\n // Measure elapsed against the SERVER clock (serverNow) rather than the\n // client's Date.now(). lastProgressAt is a server timestamp, so client\n // clock skew of more than stuckThresholdMs would otherwise mark every\n // run stuck (clock ahead) or never stuck (clock behind). Fall back to\n // the client clock for older bundles that don't send serverNow.\n const nowMs = data.serverNow ?? Date.now();\n const stuckSinceMs =\n lastProgressAt != null ? nowMs - lastProgressAt : null;\n const heartbeatAt = data.heartbeatAt ?? null;\n const heartbeatSinceMs =\n heartbeatAt != null ? nowMs - heartbeatAt : null;\n const dispatchMode =\n typeof data.dispatchMode === \"string\" ? data.dispatchMode : null;\n // A claimed durable worker with a fresh heartbeat can legitimately\n // be waiting on a bounded long-running tool/sub-agent call. Still\n // surface informational status at the normal background threshold;\n // RunStuckBanner uses the fresh heartbeat to withhold Retry while\n // keeping an explicit Cancel available. The legacy live-worker\n // threshold may make that notice earlier, but never later.\n const effectiveThresholdMs = effectiveThresholdFor(\n dispatchMode,\n heartbeatSinceMs,\n );\n const isStuck = Boolean(\n data.active &&\n data.status === \"running\" &&\n stuckSinceMs != null &&\n stuckSinceMs > effectiveThresholdMs,\n );\n const observedAtMs = Date.now();\n const version = ++snapshotVersion;\n scheduleSnapshotTransition(\n {\n active: data.active,\n runId: data.runId ?? null,\n status: data.status ?? null,\n lastProgressAt,\n stuckSinceMs,\n heartbeatAt,\n heartbeatSinceMs,\n dispatchMode,\n },\n observedAtMs,\n version,\n );\n setState({\n isStuck,\n runId: data.runId ?? null,\n status: data.status ?? null,\n lastProgressAt,\n stuckSinceMs,\n heartbeatAt,\n heartbeatSinceMs,\n dispatchMode,\n hasInFlightWork:\n typeof data.hasInFlightWork === \"boolean\"\n ? data.hasInFlightWork\n : null,\n });\n // Back off polling when nothing is in flight — there's no point\n // hammering the endpoint while the chat is idle. We still poll\n // occasionally so a fresh run started in another tab is picked up.\n if (!data.active || data.status !== \"running\") {\n nextDelay = IDLE_BACKOFF_INTERVAL_MS;\n }\n }\n } catch {\n // Network blip — leave previous state. Next tick will retry.\n }\n if (!cancelled) {\n timer = setTimeout(poll, nextDelay);\n }\n };\n\n // Stagger the first poll so a freshly-started run isn't immediately\n // classified as stuck before the server has had a chance to record\n // any progress events.\n timer = setTimeout(poll, 2_000);\n\n return () => {\n cancelled = true;\n snapshotVersion += 1;\n if (timer) clearTimeout(timer);\n if (snapshotTransitionTimer) clearTimeout(snapshotTransitionTimer);\n };\n }, [\n threadId,\n enabled,\n stuckThresholdMs,\n backgroundStuckThresholdMs,\n liveBackgroundStuckThresholdMs,\n pollIntervalMs,\n apiUrl,\n ]);\n\n return state;\n}\n\n/**\n * POST `/runs/:id/abort` so the server flips the run to \"aborted\" and the\n * adapter's reconnect loop exits cleanly. Returns the run id that was\n * aborted (or null on failure) so callers can correlate observability\n * events. Best-effort — failures are swallowed, since the user's intent\n * is already captured locally.\n */\nexport function useAbortRun(apiUrl?: string) {\n return useCallback(\n async (runId: string, reason: string = \"user\"): Promise<string | null> => {\n const base = apiUrl ?? agentNativePath(\"/_agent-native/agent-chat\");\n try {\n const res = await fetch(\n `${base}/runs/${encodeURIComponent(runId)}/abort`,\n {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n credentials: \"same-origin\",\n body: JSON.stringify({ reason }),\n },\n );\n if (!res.ok) return null;\n return runId;\n } catch {\n return null;\n }\n },\n [apiUrl],\n );\n}\n"]}
|
|
@@ -62,11 +62,11 @@ export declare const postAwareness: import("h3").EventHandlerWithFetch<import("h
|
|
|
62
62
|
error: string;
|
|
63
63
|
states?: undefined;
|
|
64
64
|
} | {
|
|
65
|
-
error?: undefined;
|
|
66
65
|
states: {
|
|
67
66
|
clientId: number;
|
|
68
67
|
state: string;
|
|
69
68
|
}[];
|
|
69
|
+
error?: undefined;
|
|
70
70
|
}>>;
|
|
71
71
|
/**
|
|
72
72
|
* GET /_agent-native/collab/:docId/users
|
|
@@ -77,10 +77,10 @@ export declare const getActiveUsers: import("h3").EventHandlerWithFetch<import("
|
|
|
77
77
|
error: string;
|
|
78
78
|
users?: undefined;
|
|
79
79
|
} | {
|
|
80
|
-
error?: undefined;
|
|
81
80
|
users: {
|
|
82
81
|
clientId: number;
|
|
83
82
|
lastSeen: number;
|
|
84
83
|
}[];
|
|
84
|
+
error?: undefined;
|
|
85
85
|
}>>;
|
|
86
86
|
//# sourceMappingURL=awareness.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"awareness.d.ts","sourceRoot":"","sources":["../../src/collab/awareness.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAgB3C,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB;AAOD,eAAO,MAAM,sBAAsB,EAAG,kBAA2B,CAAC;AAElE,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,WAAW,CAAC;IACpB,IAAI,EAAE,kBAAkB,CAAC;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,2EAA2E;IAC3E,MAAM,EAAE,KAAK,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACnD,gFAAgF;IAChF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,sCAAsC;IACtC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2EAA2E;IAC3E,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,yEAAyE;IACzE,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAOD,wBAAgB,mBAAmB,IAAI,YAAY,CAElD;AAED,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,cAAc,GAAG,SAAS,GAChC,IAAI,CAON;AAED,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,KAAK,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,EAClD,KAAK,CAAC,EAAE,cAAc,GACrB,IAAI,CAgBN;AAoBD,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAChB,SAAS,GAAE,MAAmB,GAC7B,IAAI,CAON;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAE1E;AAiBD,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,CAO1E;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,GAAG,IAAI,CAOnE;AAkCD;;;;;;;GAOG;AACH,eAAO,MAAM,aAAa
|
|
1
|
+
{"version":3,"file":"awareness.d.ts","sourceRoot":"","sources":["../../src/collab/awareness.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAgB3C,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB;AAOD,eAAO,MAAM,sBAAsB,EAAG,kBAA2B,CAAC;AAElE,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,WAAW,CAAC;IACpB,IAAI,EAAE,kBAAkB,CAAC;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,2EAA2E;IAC3E,MAAM,EAAE,KAAK,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACnD,gFAAgF;IAChF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,sCAAsC;IACtC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2EAA2E;IAC3E,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,yEAAyE;IACzE,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAOD,wBAAgB,mBAAmB,IAAI,YAAY,CAElD;AAED,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,cAAc,GAAG,SAAS,GAChC,IAAI,CAON;AAED,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,KAAK,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,EAClD,KAAK,CAAC,EAAE,cAAc,GACrB,IAAI,CAgBN;AAoBD,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAChB,SAAS,GAAE,MAAmB,GAC7B,IAAI,CAON;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAE1E;AAiBD,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,CAO1E;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,GAAG,IAAI,CAOnE;AAkCD;;;;;;;GAOG;AACH,eAAO,MAAM,aAAa;;;;;kBAwDa,MAAM;eAAS,MAAM;;;GAoB1D,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,cAAc;;;;;kBAYM,MAAM;kBAAY,MAAM;;;GAMvD,CAAC"}
|
package/dist/deploy/build.d.ts
CHANGED
|
@@ -151,12 +151,13 @@ export declare function isDurableBackgroundDeployEnabled(): boolean;
|
|
|
151
151
|
*/
|
|
152
152
|
export declare function emitSingleTemplateNetlifyBackgroundFunction(projectCwd: string): void;
|
|
153
153
|
/**
|
|
154
|
-
* Nitro
|
|
155
|
-
*
|
|
156
|
-
*
|
|
157
|
-
*
|
|
154
|
+
* Nitro receives the React Router SSR build as prebuilt chunks, so its normal
|
|
155
|
+
* dependency resolver cannot reliably fold the preserved bare `yjs` imports
|
|
156
|
+
* into the same module instance used by core's server collaboration code.
|
|
157
|
+
* Keep Yjs external through Nitro, bundle its complete public ESM surface once,
|
|
158
|
+
* then point every emitted server chunk at that one portable runtime module.
|
|
158
159
|
*/
|
|
159
|
-
export declare function
|
|
160
|
+
export declare function bundleYjsRuntimeForServerlessOutput(serverDir: string, projectCwd: string): string[];
|
|
160
161
|
export declare function assertSingleTemplateNetlifyBuildOutput(projectCwd: string): void;
|
|
161
162
|
/**
|
|
162
163
|
* Strip the harmful single-template catch-all rewrite that points at
|
|
@@ -204,17 +205,17 @@ export interface NitroBuildPipelineOptions {
|
|
|
204
205
|
*/
|
|
205
206
|
export declare function runNitroBuildPipeline(opts: NitroBuildPipelineOptions): Promise<void>;
|
|
206
207
|
/**
|
|
207
|
-
* Dependencies
|
|
208
|
-
*
|
|
209
|
-
*
|
|
210
|
-
* `yjs` is a direct core dependency, but it is deliberately externalized from
|
|
211
|
-
* the intermediate Vite SSR graph so that Vite and Nitro do not create two
|
|
212
|
-
* incompatible Yjs constructors. On file-traced serverless presets, leaving it
|
|
213
|
-
* external at Nitro's final build can emit `import "yjs"` into a function
|
|
214
|
-
* chunk without placing the package in that function's `node_modules`. Bundle
|
|
215
|
-
* it in Nitro's final output so every template receives the one portable copy.
|
|
208
|
+
* Dependencies Nitro itself must bundle outside the controlled serverless
|
|
209
|
+
* output pass. Netlify, Vercel, and Lambda keep Yjs external through Nitro;
|
|
210
|
+
* `bundleYjsRuntimeForServerlessOutput` then creates their one portable copy.
|
|
216
211
|
*/
|
|
217
212
|
export declare const NITRO_SERVER_RUNTIME_BUNDLED_DEPS: readonly ["yjs"];
|
|
213
|
+
/**
|
|
214
|
+
* Locate the core-owned ESM entry used by the controlled serverless bundling
|
|
215
|
+
* pass. Resolving from this module keeps the build independent of whether a
|
|
216
|
+
* template exposes core's transitive Yjs dependency at its own package root.
|
|
217
|
+
*/
|
|
218
|
+
export declare function resolveNitroBundledYjsEntry(): string;
|
|
218
219
|
/**
|
|
219
220
|
* Edge runtimes have no node_modules, while Node/serverless outputs only need
|
|
220
221
|
* the small set above bundled to keep their package manifests traceable.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/deploy/build.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/deploy/build.ts"],"names":[],"mappings":"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"}
|
package/dist/deploy/build.js
CHANGED
|
@@ -2101,15 +2101,15 @@ function walkServerJavaScriptFiles(dir, onFile) {
|
|
|
2101
2101
|
}
|
|
2102
2102
|
}
|
|
2103
2103
|
/**
|
|
2104
|
-
* Nitro
|
|
2105
|
-
*
|
|
2106
|
-
*
|
|
2107
|
-
*
|
|
2104
|
+
* Nitro receives the React Router SSR build as prebuilt chunks, so its normal
|
|
2105
|
+
* dependency resolver cannot reliably fold the preserved bare `yjs` imports
|
|
2106
|
+
* into the same module instance used by core's server collaboration code.
|
|
2107
|
+
* Keep Yjs external through Nitro, bundle its complete public ESM surface once,
|
|
2108
|
+
* then point every emitted server chunk at that one portable runtime module.
|
|
2108
2109
|
*/
|
|
2109
|
-
export function
|
|
2110
|
+
export function bundleYjsRuntimeForServerlessOutput(serverDir, projectCwd) {
|
|
2110
2111
|
const bareImports = [];
|
|
2111
2112
|
const unsupportedSubpathImports = [];
|
|
2112
|
-
const bundledYjsPath = path.join(serverDir, "_libs", "yjs.mjs");
|
|
2113
2113
|
walkServerJavaScriptFiles(serverDir, (filePath) => {
|
|
2114
2114
|
const source = fs.readFileSync(filePath, "utf-8");
|
|
2115
2115
|
if (!hasBareYjsRuntimeImport(source))
|
|
@@ -2125,9 +2125,17 @@ export function rewriteBareYjsImportsForServerlessOutput(serverDir) {
|
|
|
2125
2125
|
}
|
|
2126
2126
|
if (bareImports.length === 0)
|
|
2127
2127
|
return [];
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2128
|
+
const bundledYjsPath = path.join(serverDir, "_libs", "yjs-runtime.mjs");
|
|
2129
|
+
fs.mkdirSync(path.dirname(bundledYjsPath), { recursive: true });
|
|
2130
|
+
execFileSync(findEsbuild(), [
|
|
2131
|
+
resolveNitroBundledYjsEntry(),
|
|
2132
|
+
"--bundle",
|
|
2133
|
+
"--format=esm",
|
|
2134
|
+
"--platform=node",
|
|
2135
|
+
"--target=node22",
|
|
2136
|
+
"--minify",
|
|
2137
|
+
`--outfile=${bundledYjsPath}`,
|
|
2138
|
+
], { cwd: projectCwd, stdio: "pipe" });
|
|
2131
2139
|
for (const filePath of bareImports) {
|
|
2132
2140
|
const bundledImport = path
|
|
2133
2141
|
.relative(path.dirname(filePath), bundledYjsPath)
|
|
@@ -2217,6 +2225,19 @@ export function assertSingleTemplateNetlifyBuildOutput(projectCwd) {
|
|
|
2217
2225
|
if (bareYjsImports.length > 0) {
|
|
2218
2226
|
failures.push(`Netlify server bundle leaves yjs as a runtime import: ${bareYjsImports.join(", ")}`);
|
|
2219
2227
|
}
|
|
2228
|
+
// Nitro's `_libs/yjs.mjs` is a private tree-shaken chunk, not a package
|
|
2229
|
+
// facade. Repointing a prebuilt SSR chunk at it can request public exports
|
|
2230
|
+
// (notably `Text`) that the private chunk did not retain. The controlled
|
|
2231
|
+
// serverless pass must instead target the complete `yjs-runtime.mjs` bundle.
|
|
2232
|
+
const privateYjsImports = [];
|
|
2233
|
+
walkServerJavaScriptFiles(serverDir, (filePath) => {
|
|
2234
|
+
if (/\b(?:from\s*|import\s*\(\s*|import\s*)(["'])[^"']*_libs\/yjs\.mjs\1/.test(fs.readFileSync(filePath, "utf-8"))) {
|
|
2235
|
+
privateYjsImports.push(path.relative(projectCwd, filePath));
|
|
2236
|
+
}
|
|
2237
|
+
});
|
|
2238
|
+
if (privateYjsImports.length > 0) {
|
|
2239
|
+
failures.push(`Netlify server bundle imports Nitro's internal tree-shaken _libs/yjs.mjs: ${privateYjsImports.join(", ")}`);
|
|
2240
|
+
}
|
|
2220
2241
|
if (isDurableBackgroundDeployEnabled()) {
|
|
2221
2242
|
const backgroundDir = path.join(internalDir, AGENT_BACKGROUND_FUNCTION_NAME);
|
|
2222
2243
|
const backgroundEntryPath = path.join(backgroundDir, `${AGENT_BACKGROUND_FUNCTION_NAME}.mjs`);
|
|
@@ -2567,17 +2588,25 @@ const BROWSER_ONLY_SERVER_LIBS = [
|
|
|
2567
2588
|
"mermaid",
|
|
2568
2589
|
];
|
|
2569
2590
|
/**
|
|
2570
|
-
* Dependencies
|
|
2571
|
-
*
|
|
2572
|
-
*
|
|
2573
|
-
* `yjs` is a direct core dependency, but it is deliberately externalized from
|
|
2574
|
-
* the intermediate Vite SSR graph so that Vite and Nitro do not create two
|
|
2575
|
-
* incompatible Yjs constructors. On file-traced serverless presets, leaving it
|
|
2576
|
-
* external at Nitro's final build can emit `import "yjs"` into a function
|
|
2577
|
-
* chunk without placing the package in that function's `node_modules`. Bundle
|
|
2578
|
-
* it in Nitro's final output so every template receives the one portable copy.
|
|
2591
|
+
* Dependencies Nitro itself must bundle outside the controlled serverless
|
|
2592
|
+
* output pass. Netlify, Vercel, and Lambda keep Yjs external through Nitro;
|
|
2593
|
+
* `bundleYjsRuntimeForServerlessOutput` then creates their one portable copy.
|
|
2579
2594
|
*/
|
|
2580
2595
|
export const NITRO_SERVER_RUNTIME_BUNDLED_DEPS = ["yjs"];
|
|
2596
|
+
/**
|
|
2597
|
+
* Locate the core-owned ESM entry used by the controlled serverless bundling
|
|
2598
|
+
* pass. Resolving from this module keeps the build independent of whether a
|
|
2599
|
+
* template exposes core's transitive Yjs dependency at its own package root.
|
|
2600
|
+
*/
|
|
2601
|
+
export function resolveNitroBundledYjsEntry() {
|
|
2602
|
+
const requireFromCore = createRequire(import.meta.url);
|
|
2603
|
+
const packageDir = path.dirname(requireFromCore.resolve("yjs/package.json"));
|
|
2604
|
+
const entry = path.join(packageDir, "dist", "yjs.mjs");
|
|
2605
|
+
if (!fs.existsSync(entry)) {
|
|
2606
|
+
throw new Error(`[build] Could not resolve the Yjs ESM entry at ${entry}`);
|
|
2607
|
+
}
|
|
2608
|
+
return entry;
|
|
2609
|
+
}
|
|
2581
2610
|
/**
|
|
2582
2611
|
* Edge runtimes have no node_modules, while Node/serverless outputs only need
|
|
2583
2612
|
* the small set above bundled to keep their package manifests traceable.
|
|
@@ -2586,7 +2615,11 @@ export function nitroNoExternalsForPreset(targetPreset) {
|
|
|
2586
2615
|
return targetPreset.startsWith("cloudflare") ||
|
|
2587
2616
|
targetPreset.startsWith("deno")
|
|
2588
2617
|
? true
|
|
2589
|
-
:
|
|
2618
|
+
: targetPreset === "netlify" ||
|
|
2619
|
+
targetPreset === "vercel" ||
|
|
2620
|
+
targetPreset === "aws-lambda"
|
|
2621
|
+
? []
|
|
2622
|
+
: NITRO_SERVER_RUNTIME_BUNDLED_DEPS;
|
|
2590
2623
|
}
|
|
2591
2624
|
/**
|
|
2592
2625
|
* Rolldown plugin for the Nitro server bundle that replaces the browser-only
|
|
@@ -2722,6 +2755,14 @@ export default bundle;
|
|
|
2722
2755
|
// (ReferenceError: window is not defined → every request 502s). Mirrors the
|
|
2723
2756
|
// Vite `ssrStubPlugin`, which only covers the `build/server` step.
|
|
2724
2757
|
rollupConfig: {
|
|
2758
|
+
// Nitro treats the intermediate React Router SSR files as prebuilt
|
|
2759
|
+
// chunks, while core's server collaboration files participate in the
|
|
2760
|
+
// final Rolldown graph. Externalize Yjs consistently on serverless so
|
|
2761
|
+
// both graphs retain their public import shapes; the controlled
|
|
2762
|
+
// post-build pass below bundles and rewrites them to one module.
|
|
2763
|
+
...(preset === "netlify" || preset === "vercel" || preset === "aws-lambda"
|
|
2764
|
+
? { external: ["yjs"] }
|
|
2765
|
+
: {}),
|
|
2725
2766
|
plugins: [createBrowserOnlyServerStubPlugin()],
|
|
2726
2767
|
},
|
|
2727
2768
|
...(providedPluginsNitroPlugin
|
|
@@ -2729,9 +2770,9 @@ export default bundle;
|
|
|
2729
2770
|
: {}),
|
|
2730
2771
|
routeRules: mcpEmbedStaticAssetRouteRules(appBasePath),
|
|
2731
2772
|
// Edge presets (cloudflare, deno) bundle all deps because node_modules are
|
|
2732
|
-
// unavailable at runtime. Node
|
|
2733
|
-
//
|
|
2734
|
-
//
|
|
2773
|
+
// unavailable at runtime. Ordinary Node presets bundle Yjs through Nitro.
|
|
2774
|
+
// Controlled serverless presets externalize it above, then emit one full
|
|
2775
|
+
// runtime module after Nitro has preserved every consumer's public imports.
|
|
2735
2776
|
noExternals: nitroNoExternalsForPreset(preset),
|
|
2736
2777
|
});
|
|
2737
2778
|
await runNitroBuildPipeline({
|
|
@@ -2747,7 +2788,7 @@ export default bundle;
|
|
|
2747
2788
|
copyInstalledResvgPackages(nitro.options.output.serverDir);
|
|
2748
2789
|
copyInstalledFfmpegStaticPackage(nitro.options.output.serverDir);
|
|
2749
2790
|
sanitizeServerlessFunctionPackageManifest(nitro.options.output.serverDir);
|
|
2750
|
-
|
|
2791
|
+
bundleYjsRuntimeForServerlessOutput(nitro.options.output.serverDir, cwd);
|
|
2751
2792
|
}
|
|
2752
2793
|
// Durable background agent runs (default-OFF / opt-in; enable with a truthy
|
|
2753
2794
|
// AGENT_CHAT_DURABLE_BACKGROUND). Additive ONLY: emits a SECOND Netlify
|