@agent-native/core 0.84.66 → 0.85.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.
Files changed (155) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +20 -0
  3. package/corpus/core/docs/content/locales/ar-SA/tracking.mdx +55 -0
  4. package/corpus/core/docs/content/locales/de-DE/tracking.mdx +55 -0
  5. package/corpus/core/docs/content/locales/es-ES/tracking.mdx +55 -0
  6. package/corpus/core/docs/content/locales/fr-FR/tracking.mdx +55 -0
  7. package/corpus/core/docs/content/locales/hi-IN/tracking.mdx +55 -0
  8. package/corpus/core/docs/content/locales/ja-JP/tracking.mdx +55 -0
  9. package/corpus/core/docs/content/locales/ko-KR/tracking.mdx +55 -0
  10. package/corpus/core/docs/content/locales/pt-BR/tracking.mdx +55 -0
  11. package/corpus/core/docs/content/locales/zh-CN/tracking.mdx +55 -0
  12. package/corpus/core/docs/content/locales/zh-TW/tracking.mdx +55 -0
  13. package/corpus/core/docs/content/tracking.mdx +2 -0
  14. package/corpus/core/package.json +1 -1
  15. package/corpus/core/src/agent/production-agent.ts +199 -38
  16. package/corpus/core/src/agent/run-manager.ts +79 -0
  17. package/corpus/core/src/agent/run-store.ts +117 -5
  18. package/corpus/core/src/agent/types.ts +13 -0
  19. package/corpus/core/src/client/RunStuckBanner.tsx +14 -0
  20. package/corpus/core/src/client/agent-chat-adapter.ts +475 -0
  21. package/corpus/core/src/client/analytics.ts +2 -0
  22. package/corpus/core/src/client/error-format.ts +4 -0
  23. package/corpus/core/src/client/extensions/ExtensionsSidebarSection.tsx +1 -1
  24. package/corpus/core/src/client/session-replay.ts +774 -2
  25. package/corpus/core/src/client/sse-event-processor.ts +65 -9
  26. package/corpus/core/src/client/use-run-stuck-detection.ts +31 -7
  27. package/corpus/core/src/db/runtime-diagnostics.ts +331 -0
  28. package/corpus/core/src/server/agent-chat-plugin.ts +115 -2
  29. package/corpus/core/src/server/analytics.ts +1 -34
  30. package/corpus/core/src/server/core-routes-plugin.ts +91 -4
  31. package/corpus/core/src/server/http-response-telemetry.ts +189 -0
  32. package/corpus/core/src/server/self-dispatch.ts +29 -0
  33. package/corpus/core/src/server/ssr-handler.ts +18 -377
  34. package/corpus/templates/analytics/.agents/skills/session-replay/SKILL.md +53 -1
  35. package/corpus/templates/analytics/AGENTS.md +13 -0
  36. package/corpus/templates/analytics/actions/view-screen.ts +25 -0
  37. package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +20 -0
  38. package/corpus/templates/analytics/app/global.css +55 -0
  39. package/corpus/templates/analytics/app/i18n/zh-TW.ts +100 -1
  40. package/corpus/templates/analytics/app/i18n-data.ts +1226 -0
  41. package/corpus/templates/analytics/app/pages/Settings.tsx +3 -0
  42. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/EmailReportDialog.tsx +182 -144
  43. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +11 -18
  44. package/corpus/templates/analytics/app/pages/analyses/AnalysisDetail.tsx +11 -18
  45. package/corpus/templates/analytics/app/pages/sessions/SessionDetailPage.tsx +49 -1
  46. package/corpus/templates/analytics/app/pages/sessions/SessionDevToolsPanel.tsx +557 -0
  47. package/corpus/templates/analytics/app/pages/sessions/session-replay-devtools.ts +274 -0
  48. package/corpus/templates/analytics/app/pages/settings/AlertRulesSettingsCard.tsx +974 -0
  49. package/corpus/templates/analytics/changelog/2026-07-02-alert-rules-can-now-be-viewed-and-managed-from-settings.md +6 -0
  50. package/corpus/templates/analytics/changelog/2026-07-02-recent-ask-chats-show-a-loading-placeholder-while-your-chat-.md +6 -0
  51. package/corpus/templates/analytics/changelog/2026-07-02-session-replays-now-capture-console-logs-and-network-request.md +6 -0
  52. package/corpus/templates/analytics/changelog/2026-07-02-sharing-status-labels-use-neutral-icons-instead-of-colored-d.md +6 -0
  53. package/corpus/templates/analytics/changelog/2026-07-02-the-session-replay-viewer-has-a-dev-tools-panel-with-console.md +6 -0
  54. package/corpus/templates/analytics/server/db/schema.ts +3 -0
  55. package/corpus/templates/analytics/server/jobs/analytics-alerts.ts +4 -0
  56. package/corpus/templates/analytics/server/lib/analytics-alerts.ts +142 -1
  57. package/corpus/templates/analytics/server/lib/session-replay-agent-context.ts +369 -8
  58. package/corpus/templates/analytics/server/lib/session-replay.ts +76 -2
  59. package/corpus/templates/analytics/server/routes/api/session-replay/agent-diagnostics.json.get.ts +101 -0
  60. package/corpus/templates/analytics/shared/session-replay-diagnostics.ts +78 -0
  61. package/corpus/templates/clips/server/routes/api/video/[recordingId].get.ts +0 -2
  62. package/corpus/templates/design/app/pages/DesignEditor.tsx +24 -12
  63. package/corpus/templates/design/changelog/2026-07-02-the-temporary-code-tab-is-hidden-from-the-design-editor-side.md +6 -0
  64. package/corpus/templates/forms/server/lib/public-form-ssr.ts +0 -1
  65. package/corpus/templates/plan/actions/create-visual-recap.ts +1 -1
  66. package/corpus/templates/plan/actions/update-local-plan-folder.ts +3 -1
  67. package/corpus/templates/plan/actions/update-visual-plan.ts +1 -1
  68. package/corpus/templates/plan/changelog/2026-07-02-trying-to-edit-a-recap-or-plan-you-can-only-view-now-explain.md +6 -0
  69. package/corpus/templates/plan/server/plans.ts +26 -9
  70. package/dist/agent/production-agent.d.ts.map +1 -1
  71. package/dist/agent/production-agent.js +155 -34
  72. package/dist/agent/production-agent.js.map +1 -1
  73. package/dist/agent/run-manager.d.ts +29 -0
  74. package/dist/agent/run-manager.d.ts.map +1 -1
  75. package/dist/agent/run-manager.js +73 -0
  76. package/dist/agent/run-manager.js.map +1 -1
  77. package/dist/agent/run-store.d.ts +41 -0
  78. package/dist/agent/run-store.d.ts.map +1 -1
  79. package/dist/agent/run-store.js +100 -4
  80. package/dist/agent/run-store.js.map +1 -1
  81. package/dist/agent/types.d.ts +13 -0
  82. package/dist/agent/types.d.ts.map +1 -1
  83. package/dist/agent/types.js.map +1 -1
  84. package/dist/client/RunStuckBanner.d.ts.map +1 -1
  85. package/dist/client/RunStuckBanner.js +13 -0
  86. package/dist/client/RunStuckBanner.js.map +1 -1
  87. package/dist/client/agent-chat-adapter.d.ts.map +1 -1
  88. package/dist/client/agent-chat-adapter.js +410 -0
  89. package/dist/client/agent-chat-adapter.js.map +1 -1
  90. package/dist/client/analytics.d.ts +1 -1
  91. package/dist/client/analytics.d.ts.map +1 -1
  92. package/dist/client/analytics.js.map +1 -1
  93. package/dist/client/error-format.d.ts.map +1 -1
  94. package/dist/client/error-format.js +2 -0
  95. package/dist/client/error-format.js.map +1 -1
  96. package/dist/client/extensions/ExtensionsSidebarSection.js +1 -1
  97. package/dist/client/extensions/ExtensionsSidebarSection.js.map +1 -1
  98. package/dist/client/session-replay.d.ts +36 -0
  99. package/dist/client/session-replay.d.ts.map +1 -1
  100. package/dist/client/session-replay.js +579 -1
  101. package/dist/client/session-replay.js.map +1 -1
  102. package/dist/client/sse-event-processor.d.ts +20 -1
  103. package/dist/client/sse-event-processor.d.ts.map +1 -1
  104. package/dist/client/sse-event-processor.js +42 -11
  105. package/dist/client/sse-event-processor.js.map +1 -1
  106. package/dist/client/use-run-stuck-detection.d.ts +14 -4
  107. package/dist/client/use-run-stuck-detection.d.ts.map +1 -1
  108. package/dist/client/use-run-stuck-detection.js +18 -4
  109. package/dist/client/use-run-stuck-detection.js.map +1 -1
  110. package/dist/collab/awareness.d.ts +2 -2
  111. package/dist/collab/awareness.d.ts.map +1 -1
  112. package/dist/collab/routes.d.ts +1 -1
  113. package/dist/db/runtime-diagnostics.d.ts +52 -0
  114. package/dist/db/runtime-diagnostics.d.ts.map +1 -0
  115. package/dist/db/runtime-diagnostics.js +250 -0
  116. package/dist/db/runtime-diagnostics.js.map +1 -0
  117. package/dist/observability/routes.d.ts +5 -5
  118. package/dist/provider-api/corpus-jobs.d.ts +2 -2
  119. package/dist/resources/handlers.d.ts +2 -2
  120. package/dist/secrets/routes.d.ts +3 -3
  121. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  122. package/dist/server/agent-chat-plugin.js +101 -2
  123. package/dist/server/agent-chat-plugin.js.map +1 -1
  124. package/dist/server/analytics.d.ts +1 -19
  125. package/dist/server/analytics.d.ts.map +1 -1
  126. package/dist/server/analytics.js +1 -31
  127. package/dist/server/analytics.js.map +1 -1
  128. package/dist/server/core-routes-plugin.d.ts +17 -0
  129. package/dist/server/core-routes-plugin.d.ts.map +1 -1
  130. package/dist/server/core-routes-plugin.js +65 -5
  131. package/dist/server/core-routes-plugin.js.map +1 -1
  132. package/dist/server/http-response-telemetry.d.ts +4 -0
  133. package/dist/server/http-response-telemetry.d.ts.map +1 -0
  134. package/dist/server/http-response-telemetry.js +174 -0
  135. package/dist/server/http-response-telemetry.js.map +1 -0
  136. package/dist/server/self-dispatch.d.ts +17 -0
  137. package/dist/server/self-dispatch.d.ts.map +1 -1
  138. package/dist/server/self-dispatch.js +11 -0
  139. package/dist/server/self-dispatch.js.map +1 -1
  140. package/dist/server/ssr-handler.d.ts.map +1 -1
  141. package/dist/server/ssr-handler.js +18 -271
  142. package/dist/server/ssr-handler.js.map +1 -1
  143. package/dist/server/transcribe-voice.d.ts +1 -1
  144. package/docs/content/locales/ar-SA/tracking.mdx +55 -0
  145. package/docs/content/locales/de-DE/tracking.mdx +55 -0
  146. package/docs/content/locales/es-ES/tracking.mdx +55 -0
  147. package/docs/content/locales/fr-FR/tracking.mdx +55 -0
  148. package/docs/content/locales/hi-IN/tracking.mdx +55 -0
  149. package/docs/content/locales/ja-JP/tracking.mdx +55 -0
  150. package/docs/content/locales/ko-KR/tracking.mdx +55 -0
  151. package/docs/content/locales/pt-BR/tracking.mdx +55 -0
  152. package/docs/content/locales/zh-CN/tracking.mdx +55 -0
  153. package/docs/content/locales/zh-TW/tracking.mdx +55 -0
  154. package/docs/content/tracking.mdx +2 -0
  155. package/package.json +1 -1
@@ -0,0 +1,4 @@
1
+ import type { EventHandler } from "h3";
2
+ export declare function normalizeHttpTelemetryPath(pathname: string): string;
3
+ export declare function createHttpResponseTelemetryMiddleware(): EventHandler;
4
+ //# sourceMappingURL=http-response-telemetry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http-response-telemetry.d.ts","sourceRoot":"","sources":["../../src/server/http-response-telemetry.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAW,MAAM,IAAI,CAAC;AA6DhD,wBAAgB,0BAA0B,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAMnE;AAgGD,wBAAgB,qCAAqC,IAAI,YAAY,CAwBpE"}
@@ -0,0 +1,174 @@
1
+ import { defineEventHandler, getHeader, getMethod } from "h3";
2
+ import { getDatabaseRuntimeFingerprint } from "../db/runtime-diagnostics.js";
3
+ import { track } from "../tracking/index.js";
4
+ import { getAppName } from "./app-name.js";
5
+ const TELEMETRY_EVENT_NAME = "http.response";
6
+ const TRACKING_INGEST_PATHS = new Set([
7
+ "/track",
8
+ "/api/analytics/track",
9
+ "/api/events/track",
10
+ "/_agent-native/track",
11
+ ]);
12
+ function envValue(key) {
13
+ const value = process.env[key]?.trim();
14
+ return value || undefined;
15
+ }
16
+ function boolEnv(key) {
17
+ return ["1", "true", "yes", "on"].includes((process.env[key] ?? "").trim().toLowerCase());
18
+ }
19
+ function sampleRate() {
20
+ const raw = envValue("AGENT_NATIVE_HTTP_TELEMETRY_SAMPLE_RATE");
21
+ if (!raw)
22
+ return 1;
23
+ const parsed = Number.parseFloat(raw);
24
+ if (!Number.isFinite(parsed))
25
+ return 1;
26
+ return Math.max(0, Math.min(1, parsed));
27
+ }
28
+ function shouldDisableTelemetry() {
29
+ return boolEnv("AGENT_NATIVE_HTTP_TELEMETRY_DISABLED");
30
+ }
31
+ function requestPath(event) {
32
+ const raw = event.url?.pathname ??
33
+ String(event.node?.req?.url ?? event.path ?? "/").split("?")[0] ??
34
+ "/";
35
+ return raw || "/";
36
+ }
37
+ function normalizeSegment(segment) {
38
+ if (!segment)
39
+ return segment;
40
+ if (/^[0-9]+$/.test(segment))
41
+ return ":id";
42
+ if (/^[0-9a-f]{8}-[0-9a-f-]{27}$/i.test(segment))
43
+ return ":id";
44
+ if (/^(run|turn|thread|design|screen|file|msg|key|tok)_[a-z0-9_-]+$/i.test(segment)) {
45
+ return ":id";
46
+ }
47
+ if (/^(run|turn)-[0-9]{10,}-[a-z0-9]+$/i.test(segment))
48
+ return ":id";
49
+ if (segment.length > 36 && /^[a-z0-9_-]+$/i.test(segment))
50
+ return ":id";
51
+ return segment;
52
+ }
53
+ export function normalizeHttpTelemetryPath(pathname) {
54
+ const normalized = pathname.startsWith("/") ? pathname : `/${pathname}`;
55
+ return normalized
56
+ .split("/")
57
+ .map((segment, index) => (index === 0 ? "" : normalizeSegment(segment)))
58
+ .join("/");
59
+ }
60
+ function statusClass(statusCode) {
61
+ if (!Number.isFinite(statusCode) || statusCode < 100)
62
+ return "unknown";
63
+ return `${Math.floor(statusCode / 100)}xx`;
64
+ }
65
+ function routeKind(pathname) {
66
+ if (pathname === "/_agent-native" || pathname.startsWith("/_agent-native/")) {
67
+ return "framework";
68
+ }
69
+ if (pathname === "/api" || pathname.startsWith("/api/"))
70
+ return "api";
71
+ if (pathname.startsWith("/.well-known/"))
72
+ return "well-known";
73
+ return "app";
74
+ }
75
+ function hostForEvent(event) {
76
+ return (getHeader(event, "x-forwarded-host") ??
77
+ getHeader(event, "host") ??
78
+ undefined);
79
+ }
80
+ function organizationForHost(host) {
81
+ const configured = envValue("AGENT_NATIVE_ANALYTICS_ORG_NAME") ??
82
+ envValue("AGENT_NATIVE_ORG_NAME");
83
+ if (configured)
84
+ return configured;
85
+ const normalized = host?.split(":")[0]?.toLowerCase();
86
+ return normalized?.endsWith(".agent-native.com") ||
87
+ normalized === "agent-native.com"
88
+ ? "Builder.io"
89
+ : undefined;
90
+ }
91
+ function shouldTrack(pathname, statusCode) {
92
+ if (shouldDisableTelemetry())
93
+ return false;
94
+ if (TRACKING_INGEST_PATHS.has(pathname))
95
+ return false;
96
+ if (pathname.startsWith("/api/analytics/replay"))
97
+ return false;
98
+ if (statusCode >= 500)
99
+ return true;
100
+ const rate = sampleRate();
101
+ if (rate <= 0)
102
+ return false;
103
+ if (rate >= 1)
104
+ return true;
105
+ return Math.random() < rate;
106
+ }
107
+ function responseStatusCode(event) {
108
+ const raw = event.node?.res?.statusCode ??
109
+ event.node?.res?.status ??
110
+ event.res?.status ??
111
+ 200;
112
+ const parsed = Number(raw);
113
+ return Number.isFinite(parsed) ? parsed : 200;
114
+ }
115
+ function emitTelemetry(event, startedAt) {
116
+ const statusCode = responseStatusCode(event);
117
+ const pathname = requestPath(event);
118
+ if (!shouldTrack(pathname, statusCode))
119
+ return;
120
+ try {
121
+ const host = hostForEvent(event);
122
+ const db = getDatabaseRuntimeFingerprint();
123
+ track(TELEMETRY_EVENT_NAME, {
124
+ source: "server",
125
+ app: getAppName(),
126
+ template: envValue("AGENT_NATIVE_TEMPLATE") ?? getAppName(),
127
+ organization: organizationForHost(host),
128
+ method: getMethod(event),
129
+ path: normalizeHttpTelemetryPath(pathname),
130
+ route_kind: routeKind(pathname),
131
+ status_code: statusCode,
132
+ status_class: statusClass(statusCode),
133
+ duration_ms: Math.max(0, Date.now() - startedAt),
134
+ host,
135
+ environment: envValue("NODE_ENV"),
136
+ deploy_context: envValue("CONTEXT") ?? envValue("VERCEL_ENV"),
137
+ deploy_id: envValue("DEPLOY_ID") ?? envValue("VERCEL_DEPLOYMENT_ID"),
138
+ commit_ref: envValue("COMMIT_REF") ??
139
+ envValue("NETLIFY_COMMIT_REF") ??
140
+ envValue("VERCEL_GIT_COMMIT_SHA") ??
141
+ envValue("GIT_COMMIT_SHA"),
142
+ db_source: db.source,
143
+ db_dialect: db.dialect,
144
+ db_url_hash: db.urlHash,
145
+ db_neon_endpoint: db.neon?.endpointId,
146
+ db_neon_pooled: db.neon?.pooled,
147
+ });
148
+ }
149
+ catch {
150
+ // Response telemetry is best-effort. Never perturb request handling.
151
+ }
152
+ }
153
+ export function createHttpResponseTelemetryMiddleware() {
154
+ return defineEventHandler((event) => {
155
+ const startedAt = Date.now();
156
+ const res = event.node?.res;
157
+ let emitted = false;
158
+ const emitOnce = () => {
159
+ if (emitted)
160
+ return;
161
+ emitted = true;
162
+ emitTelemetry(event, startedAt);
163
+ };
164
+ if (typeof res?.once === "function") {
165
+ res.once("finish", emitOnce);
166
+ res.once("close", emitOnce);
167
+ }
168
+ else if (typeof res?.on === "function") {
169
+ res.on("finish", emitOnce);
170
+ res.on("close", emitOnce);
171
+ }
172
+ });
173
+ }
174
+ //# sourceMappingURL=http-response-telemetry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http-response-telemetry.js","sourceRoot":"","sources":["../../src/server/http-response-telemetry.ts"],"names":[],"mappings":"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","sourcesContent":["import { defineEventHandler, getHeader, getMethod } from \"h3\";\nimport type { EventHandler, H3Event } from \"h3\";\n\nimport { getDatabaseRuntimeFingerprint } from \"../db/runtime-diagnostics.js\";\nimport { track } from \"../tracking/index.js\";\nimport { getAppName } from \"./app-name.js\";\n\nconst TELEMETRY_EVENT_NAME = \"http.response\";\nconst TRACKING_INGEST_PATHS = new Set([\n \"/track\",\n \"/api/analytics/track\",\n \"/api/events/track\",\n \"/_agent-native/track\",\n]);\n\nfunction envValue(key: string): string | undefined {\n const value = process.env[key]?.trim();\n return value || undefined;\n}\n\nfunction boolEnv(key: string): boolean {\n return [\"1\", \"true\", \"yes\", \"on\"].includes(\n (process.env[key] ?? \"\").trim().toLowerCase(),\n );\n}\n\nfunction sampleRate(): number {\n const raw = envValue(\"AGENT_NATIVE_HTTP_TELEMETRY_SAMPLE_RATE\");\n if (!raw) return 1;\n const parsed = Number.parseFloat(raw);\n if (!Number.isFinite(parsed)) return 1;\n return Math.max(0, Math.min(1, parsed));\n}\n\nfunction shouldDisableTelemetry(): boolean {\n return boolEnv(\"AGENT_NATIVE_HTTP_TELEMETRY_DISABLED\");\n}\n\nfunction requestPath(event: H3Event): string {\n const raw =\n event.url?.pathname ??\n String(event.node?.req?.url ?? event.path ?? \"/\").split(\"?\")[0] ??\n \"/\";\n return raw || \"/\";\n}\n\nfunction normalizeSegment(segment: string): string {\n if (!segment) return segment;\n if (/^[0-9]+$/.test(segment)) return \":id\";\n if (/^[0-9a-f]{8}-[0-9a-f-]{27}$/i.test(segment)) return \":id\";\n if (\n /^(run|turn|thread|design|screen|file|msg|key|tok)_[a-z0-9_-]+$/i.test(\n segment,\n )\n ) {\n return \":id\";\n }\n if (/^(run|turn)-[0-9]{10,}-[a-z0-9]+$/i.test(segment)) return \":id\";\n if (segment.length > 36 && /^[a-z0-9_-]+$/i.test(segment)) return \":id\";\n return segment;\n}\n\nexport function normalizeHttpTelemetryPath(pathname: string): string {\n const normalized = pathname.startsWith(\"/\") ? pathname : `/${pathname}`;\n return normalized\n .split(\"/\")\n .map((segment, index) => (index === 0 ? \"\" : normalizeSegment(segment)))\n .join(\"/\");\n}\n\nfunction statusClass(statusCode: number): string {\n if (!Number.isFinite(statusCode) || statusCode < 100) return \"unknown\";\n return `${Math.floor(statusCode / 100)}xx`;\n}\n\nfunction routeKind(pathname: string): string {\n if (pathname === \"/_agent-native\" || pathname.startsWith(\"/_agent-native/\")) {\n return \"framework\";\n }\n if (pathname === \"/api\" || pathname.startsWith(\"/api/\")) return \"api\";\n if (pathname.startsWith(\"/.well-known/\")) return \"well-known\";\n return \"app\";\n}\n\nfunction hostForEvent(event: H3Event): string | undefined {\n return (\n getHeader(event, \"x-forwarded-host\") ??\n getHeader(event, \"host\") ??\n undefined\n );\n}\n\nfunction organizationForHost(host: string | undefined): string | undefined {\n const configured =\n envValue(\"AGENT_NATIVE_ANALYTICS_ORG_NAME\") ??\n envValue(\"AGENT_NATIVE_ORG_NAME\");\n if (configured) return configured;\n const normalized = host?.split(\":\")[0]?.toLowerCase();\n return normalized?.endsWith(\".agent-native.com\") ||\n normalized === \"agent-native.com\"\n ? \"Builder.io\"\n : undefined;\n}\n\nfunction shouldTrack(pathname: string, statusCode: number): boolean {\n if (shouldDisableTelemetry()) return false;\n if (TRACKING_INGEST_PATHS.has(pathname)) return false;\n if (pathname.startsWith(\"/api/analytics/replay\")) return false;\n if (statusCode >= 500) return true;\n const rate = sampleRate();\n if (rate <= 0) return false;\n if (rate >= 1) return true;\n return Math.random() < rate;\n}\n\nfunction responseStatusCode(event: H3Event): number {\n const raw =\n (event.node?.res as any)?.statusCode ??\n (event.node?.res as any)?.status ??\n (event as any).res?.status ??\n 200;\n const parsed = Number(raw);\n return Number.isFinite(parsed) ? parsed : 200;\n}\n\nfunction emitTelemetry(event: H3Event, startedAt: number): void {\n const statusCode = responseStatusCode(event);\n const pathname = requestPath(event);\n if (!shouldTrack(pathname, statusCode)) return;\n\n try {\n const host = hostForEvent(event);\n const db = getDatabaseRuntimeFingerprint();\n track(TELEMETRY_EVENT_NAME, {\n source: \"server\",\n app: getAppName(),\n template: envValue(\"AGENT_NATIVE_TEMPLATE\") ?? getAppName(),\n organization: organizationForHost(host),\n method: getMethod(event),\n path: normalizeHttpTelemetryPath(pathname),\n route_kind: routeKind(pathname),\n status_code: statusCode,\n status_class: statusClass(statusCode),\n duration_ms: Math.max(0, Date.now() - startedAt),\n host,\n environment: envValue(\"NODE_ENV\"),\n deploy_context: envValue(\"CONTEXT\") ?? envValue(\"VERCEL_ENV\"),\n deploy_id: envValue(\"DEPLOY_ID\") ?? envValue(\"VERCEL_DEPLOYMENT_ID\"),\n commit_ref:\n envValue(\"COMMIT_REF\") ??\n envValue(\"NETLIFY_COMMIT_REF\") ??\n envValue(\"VERCEL_GIT_COMMIT_SHA\") ??\n envValue(\"GIT_COMMIT_SHA\"),\n db_source: db.source,\n db_dialect: db.dialect,\n db_url_hash: db.urlHash,\n db_neon_endpoint: db.neon?.endpointId,\n db_neon_pooled: db.neon?.pooled,\n });\n } catch {\n // Response telemetry is best-effort. Never perturb request handling.\n }\n}\n\nexport function createHttpResponseTelemetryMiddleware(): EventHandler {\n return defineEventHandler((event) => {\n const startedAt = Date.now();\n const res = event.node?.res as\n | {\n once?: (event: \"finish\" | \"close\", cb: () => void) => void;\n on?: (event: \"finish\" | \"close\", cb: () => void) => void;\n }\n | undefined;\n let emitted = false;\n const emitOnce = () => {\n if (emitted) return;\n emitted = true;\n emitTelemetry(event, startedAt);\n };\n\n if (typeof res?.once === \"function\") {\n res.once(\"finish\", emitOnce);\n res.once(\"close\", emitOnce);\n } else if (typeof res?.on === \"function\") {\n res.on(\"finish\", emitOnce);\n res.on(\"close\", emitOnce);\n }\n });\n}\n"]}
@@ -29,6 +29,23 @@ export interface FireInternalDispatchOptions {
29
29
  body?: Record<string, unknown>;
30
30
  /** Max ms to wait for the outbound request to leave the box. Default 250ms. */
31
31
  settleMs?: number;
32
+ /**
33
+ * Await the dispatch response fully instead of racing the settle timer.
34
+ *
35
+ * The 250ms settle race is correct for a synchronous handler that must
36
+ * respond to its own caller quickly — but it is WRONG for a handoff fired
37
+ * from a function that is about to finish (e.g. a background worker chaining
38
+ * its continuation chunk): once the handler's promise resolves, the Lambda
39
+ * freezes and a still-in-flight dispatch fetch is killed WITHOUT rejecting,
40
+ * so the handoff is lost silently — the error path never fires. With
41
+ * `awaitResponse: true` the call resolves only after the target confirmed
42
+ * receipt (Netlify background functions 202 on enqueue, normally well under
43
+ * a second) and throws on any network error or non-2xx, bounded by
44
+ * `responseTimeoutMs`.
45
+ */
46
+ awaitResponse?: boolean;
47
+ /** Max ms to await the dispatch response when `awaitResponse` is set. Default 15s. */
48
+ responseTimeoutMs?: number;
32
49
  }
33
50
  export declare function fireInternalDispatch(options: FireInternalDispatchOptions): Promise<void>;
34
51
  //# sourceMappingURL=self-dispatch.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"self-dispatch.d.ts","sourceRoot":"","sources":["../../src/server/self-dispatch.ts"],"names":[],"mappings":"AA6BA;;;;;;GAMG;AACH,eAAO,MAAM,0BAA0B,MAAM,CAAC;AAgB9C;;;;;;;;GAQG;AACH,wBAAgB,0BAA0B,CAAC,KAAK,CAAC,EAAE,GAAG,GAAG,MAAM,CAoB9D;AAED,MAAM,WAAW,2BAA2B;IAC1C,oFAAoF;IACpF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,2EAA2E;IAC3E,KAAK,CAAC,EAAE,GAAG,CAAC;IACZ,wFAAwF;IACxF,IAAI,EAAE,MAAM,CAAC;IACb,iGAAiG;IACjG,MAAM,EAAE,MAAM,CAAC;IACf,qEAAqE;IACrE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,+EAA+E;IAC/E,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AA8CD,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,2BAA2B,GACnC,OAAO,CAAC,IAAI,CAAC,CAkDf"}
1
+ {"version":3,"file":"self-dispatch.d.ts","sourceRoot":"","sources":["../../src/server/self-dispatch.ts"],"names":[],"mappings":"AA6BA;;;;;;GAMG;AACH,eAAO,MAAM,0BAA0B,MAAM,CAAC;AAgB9C;;;;;;;;GAQG;AACH,wBAAgB,0BAA0B,CAAC,KAAK,CAAC,EAAE,GAAG,GAAG,MAAM,CAoB9D;AAED,MAAM,WAAW,2BAA2B;IAC1C,oFAAoF;IACpF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,2EAA2E;IAC3E,KAAK,CAAC,EAAE,GAAG,CAAC;IACZ,wFAAwF;IACxF,IAAI,EAAE,MAAM,CAAC;IACb,iGAAiG;IACjG,MAAM,EAAE,MAAM,CAAC;IACf,qEAAqE;IACrE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,+EAA+E;IAC/E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;;;;;;;;;;OAaG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,sFAAsF;IACtF,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AA8CD,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,2BAA2B,GACnC,OAAO,CAAC,IAAI,CAAC,CA8Df"}
@@ -133,10 +133,14 @@ export async function fireInternalDispatch(options) {
133
133
  console.error(`[self-dispatch] signInternalToken failed unexpectedly for ${options.taskId}:`, err);
134
134
  }
135
135
  }
136
+ const awaitResponse = options.awaitResponse === true;
136
137
  const dispatchPromise = fetch(url, {
137
138
  method: "POST",
138
139
  headers,
139
140
  body: JSON.stringify({ taskId: options.taskId, ...(options.body ?? {}) }),
141
+ ...(awaitResponse
142
+ ? { signal: AbortSignal.timeout(options.responseTimeoutMs ?? 15_000) }
143
+ : {}),
140
144
  }).then(async (res) => {
141
145
  if (!res.ok) {
142
146
  throw await dispatchResponseError(options.path, res);
@@ -149,6 +153,13 @@ export async function fireInternalDispatch(options) {
149
153
  // logs diagnostic without changing the URL resolution order.
150
154
  console.error(`[self-dispatch] dispatch to ${options.path} (base ${baseUrl}) failed:`, err);
151
155
  });
156
+ if (awaitResponse) {
157
+ // Confirmed handoff: resolve only once the target acknowledged the
158
+ // dispatch (throws on network error / timeout / non-2xx). Used by callers
159
+ // whose own invocation is about to end — see the option doc above.
160
+ await dispatchPromise;
161
+ return;
162
+ }
152
163
  const settleMs = options.settleMs ?? DEFAULT_DISPATCH_SETTLE_MS;
153
164
  await Promise.race([
154
165
  dispatchPromise,
@@ -1 +1 @@
1
- {"version":3,"file":"self-dispatch.js","sourceRoot":"","sources":["../../src/server/self-dispatch.ts"],"names":[],"mappings":"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","sourcesContent":["import { isLocalDatabase } from \"../db/client.js\";\nimport { signInternalToken } from \"../integrations/internal-token.js\";\n/**\n * Shared self-dispatch helper for the framework's serverless background-work\n * pattern: enqueue a unit of work to SQL, then fire a fresh HTTP POST back to\n * this same deployment so the work runs in its own function invocation (with\n * its own full timeout budget) instead of riding on the request that created\n * it.\n *\n * This is the single mechanism that makes background work portable across every\n * host Nitro deploys to:\n * - Netlify Lambda / Vercel Functions / AWS Lambda — the dispatched request\n * hits a fresh function with its own budget; no `waitUntil` needed.\n * - Cloudflare Workers — same (and `waitUntil` still works as a belt-and-\n * suspenders fallback where the in-process path is used).\n * - Self-hosted / long-lived Node — the dispatch comes back as another\n * request to the same process; each handler still runs to completion.\n *\n * Originally inlined in both `a2a/handlers.ts` (`resolveSelfBaseUrl` +\n * `fireProcessTaskDispatch`) and `integrations/webhook-handler.ts`\n * (`resolveBaseUrl` + the dispatch in `enqueueAndDispatch`). Extracted here so\n * A2A, integration webhooks, and Agent Teams sub-agents share one tested\n * implementation.\n */\nimport {\n getConfiguredAppBasePath,\n withConfiguredAppBasePath,\n} from \"./app-base-path.js\";\n\n/**\n * On serverless, returning from the dispatching handler before the outbound\n * TCP handshake starts can freeze the function with the dispatch request stuck\n * in the queue. Racing the fetch against a short timer gives the request a\n * chance to leave the box at the cost of a little added latency on the\n * dispatching call. Mirrors the 250ms used by the A2A/webhook paths.\n */\nexport const DEFAULT_DISPATCH_SETTLE_MS = 250;\n\nfunction readHeader(event: any, name: string): string | undefined {\n try {\n const headers = event?.node?.req?.headers ?? event?.headers;\n if (!headers) return undefined;\n if (typeof headers.get === \"function\") {\n return headers.get(name) ?? undefined;\n }\n const map = headers as Record<string, string | undefined>;\n return map[name] ?? map[String(name).toLowerCase()];\n } catch {\n return undefined;\n }\n}\n\n/**\n * Resolve the base URL to fire a self-dispatch request at. Prefers explicit env\n * vars (most reliable on serverless, where inbound host headers can be the\n * platform's internal hostname), falling back to the inbound request headers\n * and finally localhost in dev.\n *\n * Throws in production / shared deployments when no env var is set — a silent\n * fallback to a bad host there would drop background work invisibly.\n */\nexport function resolveSelfDispatchBaseUrl(event?: any): string {\n const fromEnv =\n process.env.APP_URL ||\n process.env.URL ||\n process.env.DEPLOY_URL ||\n process.env.BETTER_AUTH_URL;\n if (fromEnv) return withConfiguredAppBasePath(String(fromEnv));\n\n if (process.env.NODE_ENV === \"production\" || !isLocalDatabase()) {\n throw new Error(\n \"Self-dispatch requires APP_URL, URL, DEPLOY_URL, or BETTER_AUTH_URL in \" +\n \"production/shared deployments so background work can reach this \" +\n \"deployment's own URL.\",\n );\n }\n\n const proto = readHeader(event, \"x-forwarded-proto\") || \"http\";\n const host =\n readHeader(event, \"host\") || `localhost:${process.env.PORT || 3000}`;\n return withConfiguredAppBasePath(`${proto}://${host}`);\n}\n\nexport interface FireInternalDispatchOptions {\n /** Base URL of this deployment. Defaults to `resolveSelfDispatchBaseUrl(event)`. */\n baseUrl?: string;\n /** Request event used to derive the base URL when `baseUrl` is omitted. */\n event?: any;\n /** Framework route path to POST to (e.g. \"/_agent-native/agent-teams/_process-run\"). */\n path: string;\n /** Task/run id the processor will claim. Used to sign the HMAC token and as the default body. */\n taskId: string;\n /** Extra fields merged into the JSON body alongside `{ taskId }`. */\n body?: Record<string, unknown>;\n /** Max ms to wait for the outbound request to leave the box. Default 250ms. */\n settleMs?: number;\n}\n\nasync function dispatchResponseError(\n path: string,\n res: Response,\n): Promise<Error> {\n let body = \"\";\n try {\n body = (await res.text()).trim();\n } catch {\n body = \"\";\n }\n const detail = body ? `: ${body.slice(0, 300)}` : \"\";\n return new Error(\n `Self-dispatch to ${path} returned HTTP ${res.status} ${res.statusText}${detail}`,\n );\n}\n\n/**\n * Fire a fresh, HMAC-signed POST to a processor route on this same deployment.\n * Fire-and-forget: the dispatch is NOT awaited to completion (the processed run\n * may take minutes); it is only raced against a short settle timer so the\n * request reliably leaves a serverless box before it freezes.\n *\n * When `A2A_SECRET` is unset (local dev), the request is sent unsigned — the\n * processor accepts unsigned dispatches in dev and relies on the SQL atomic\n * claim for double-processing protection, mirroring the A2A/webhook flow.\n */\n/**\n * For host-root dispatch targets (`/.netlify/functions/*`), strip the configured\n * app base path suffix from the resolved base url so the request reaches the\n * function at the host root rather than under the workspace app base path. For\n * every other (framework-route) path the base-path-prefixed base url is returned\n * unchanged, preserving the existing self-dispatch behavior.\n */\nfunction rootBaseUrlForPath(baseUrl: string, path: string): string {\n if (!path.startsWith(\"/.netlify/\")) return baseUrl;\n const basePath = getConfiguredAppBasePath();\n if (!basePath) return baseUrl;\n const trimmed = baseUrl.replace(/\\/$/, \"\");\n if (trimmed.endsWith(basePath)) {\n return trimmed.slice(0, trimmed.length - basePath.length);\n }\n return trimmed;\n}\n\nexport async function fireInternalDispatch(\n options: FireInternalDispatchOptions,\n): Promise<void> {\n const baseUrl = options.baseUrl ?? resolveSelfDispatchBaseUrl(options.event);\n // Netlify function default urls (`/.netlify/functions/<name>`) live at the\n // HOST ROOT, not under the workspace app base path. `resolveSelfDispatchBaseUrl`\n // appends the configured base path (e.g. `https://host/starter`) so framework\n // routes land on the right app; for a host-root function url we must dispatch\n // to `https://host/.netlify/functions/<name>` instead. Strip the base path\n // suffix from the resolved base url for `/.netlify/*` dispatch targets only.\n const url = `${rootBaseUrlForPath(baseUrl, options.path)}${options.path}`;\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n };\n try {\n headers[\"Authorization\"] = `Bearer ${signInternalToken(options.taskId)}`;\n } catch (err) {\n // Distinguish the documented \"no A2A_SECRET in dev\" path from a real\n // signing failure, so a malformed secret doesn't fail invisibly.\n if (err instanceof Error && !/A2A_SECRET/i.test(err.message)) {\n console.error(\n `[self-dispatch] signInternalToken failed unexpectedly for ${options.taskId}:`,\n err,\n );\n }\n }\n\n const dispatchPromise = fetch(url, {\n method: \"POST\",\n headers,\n body: JSON.stringify({ taskId: options.taskId, ...(options.body ?? {}) }),\n }).then(async (res) => {\n if (!res.ok) {\n throw await dispatchResponseError(options.path, res);\n }\n });\n dispatchPromise.catch((err) => {\n // Include the resolved base URL: a self-dispatch failure is almost always\n // about *which* host we POST to (custom domain behind an edge/auth wall vs\n // the deploy URL), and that is invisible from the error alone. Keeps prod\n // logs diagnostic without changing the URL resolution order.\n console.error(\n `[self-dispatch] dispatch to ${options.path} (base ${baseUrl}) failed:`,\n err,\n );\n });\n\n const settleMs = options.settleMs ?? DEFAULT_DISPATCH_SETTLE_MS;\n await Promise.race([\n dispatchPromise,\n new Promise<void>((resolve) => setTimeout(resolve, settleMs)),\n ]);\n}\n"]}
1
+ {"version":3,"file":"self-dispatch.js","sourceRoot":"","sources":["../../src/server/self-dispatch.ts"],"names":[],"mappings":"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","sourcesContent":["import { isLocalDatabase } from \"../db/client.js\";\nimport { signInternalToken } from \"../integrations/internal-token.js\";\n/**\n * Shared self-dispatch helper for the framework's serverless background-work\n * pattern: enqueue a unit of work to SQL, then fire a fresh HTTP POST back to\n * this same deployment so the work runs in its own function invocation (with\n * its own full timeout budget) instead of riding on the request that created\n * it.\n *\n * This is the single mechanism that makes background work portable across every\n * host Nitro deploys to:\n * - Netlify Lambda / Vercel Functions / AWS Lambda — the dispatched request\n * hits a fresh function with its own budget; no `waitUntil` needed.\n * - Cloudflare Workers — same (and `waitUntil` still works as a belt-and-\n * suspenders fallback where the in-process path is used).\n * - Self-hosted / long-lived Node — the dispatch comes back as another\n * request to the same process; each handler still runs to completion.\n *\n * Originally inlined in both `a2a/handlers.ts` (`resolveSelfBaseUrl` +\n * `fireProcessTaskDispatch`) and `integrations/webhook-handler.ts`\n * (`resolveBaseUrl` + the dispatch in `enqueueAndDispatch`). Extracted here so\n * A2A, integration webhooks, and Agent Teams sub-agents share one tested\n * implementation.\n */\nimport {\n getConfiguredAppBasePath,\n withConfiguredAppBasePath,\n} from \"./app-base-path.js\";\n\n/**\n * On serverless, returning from the dispatching handler before the outbound\n * TCP handshake starts can freeze the function with the dispatch request stuck\n * in the queue. Racing the fetch against a short timer gives the request a\n * chance to leave the box at the cost of a little added latency on the\n * dispatching call. Mirrors the 250ms used by the A2A/webhook paths.\n */\nexport const DEFAULT_DISPATCH_SETTLE_MS = 250;\n\nfunction readHeader(event: any, name: string): string | undefined {\n try {\n const headers = event?.node?.req?.headers ?? event?.headers;\n if (!headers) return undefined;\n if (typeof headers.get === \"function\") {\n return headers.get(name) ?? undefined;\n }\n const map = headers as Record<string, string | undefined>;\n return map[name] ?? map[String(name).toLowerCase()];\n } catch {\n return undefined;\n }\n}\n\n/**\n * Resolve the base URL to fire a self-dispatch request at. Prefers explicit env\n * vars (most reliable on serverless, where inbound host headers can be the\n * platform's internal hostname), falling back to the inbound request headers\n * and finally localhost in dev.\n *\n * Throws in production / shared deployments when no env var is set — a silent\n * fallback to a bad host there would drop background work invisibly.\n */\nexport function resolveSelfDispatchBaseUrl(event?: any): string {\n const fromEnv =\n process.env.APP_URL ||\n process.env.URL ||\n process.env.DEPLOY_URL ||\n process.env.BETTER_AUTH_URL;\n if (fromEnv) return withConfiguredAppBasePath(String(fromEnv));\n\n if (process.env.NODE_ENV === \"production\" || !isLocalDatabase()) {\n throw new Error(\n \"Self-dispatch requires APP_URL, URL, DEPLOY_URL, or BETTER_AUTH_URL in \" +\n \"production/shared deployments so background work can reach this \" +\n \"deployment's own URL.\",\n );\n }\n\n const proto = readHeader(event, \"x-forwarded-proto\") || \"http\";\n const host =\n readHeader(event, \"host\") || `localhost:${process.env.PORT || 3000}`;\n return withConfiguredAppBasePath(`${proto}://${host}`);\n}\n\nexport interface FireInternalDispatchOptions {\n /** Base URL of this deployment. Defaults to `resolveSelfDispatchBaseUrl(event)`. */\n baseUrl?: string;\n /** Request event used to derive the base URL when `baseUrl` is omitted. */\n event?: any;\n /** Framework route path to POST to (e.g. \"/_agent-native/agent-teams/_process-run\"). */\n path: string;\n /** Task/run id the processor will claim. Used to sign the HMAC token and as the default body. */\n taskId: string;\n /** Extra fields merged into the JSON body alongside `{ taskId }`. */\n body?: Record<string, unknown>;\n /** Max ms to wait for the outbound request to leave the box. Default 250ms. */\n settleMs?: number;\n /**\n * Await the dispatch response fully instead of racing the settle timer.\n *\n * The 250ms settle race is correct for a synchronous handler that must\n * respond to its own caller quickly — but it is WRONG for a handoff fired\n * from a function that is about to finish (e.g. a background worker chaining\n * its continuation chunk): once the handler's promise resolves, the Lambda\n * freezes and a still-in-flight dispatch fetch is killed WITHOUT rejecting,\n * so the handoff is lost silently — the error path never fires. With\n * `awaitResponse: true` the call resolves only after the target confirmed\n * receipt (Netlify background functions 202 on enqueue, normally well under\n * a second) and throws on any network error or non-2xx, bounded by\n * `responseTimeoutMs`.\n */\n awaitResponse?: boolean;\n /** Max ms to await the dispatch response when `awaitResponse` is set. Default 15s. */\n responseTimeoutMs?: number;\n}\n\nasync function dispatchResponseError(\n path: string,\n res: Response,\n): Promise<Error> {\n let body = \"\";\n try {\n body = (await res.text()).trim();\n } catch {\n body = \"\";\n }\n const detail = body ? `: ${body.slice(0, 300)}` : \"\";\n return new Error(\n `Self-dispatch to ${path} returned HTTP ${res.status} ${res.statusText}${detail}`,\n );\n}\n\n/**\n * Fire a fresh, HMAC-signed POST to a processor route on this same deployment.\n * Fire-and-forget: the dispatch is NOT awaited to completion (the processed run\n * may take minutes); it is only raced against a short settle timer so the\n * request reliably leaves a serverless box before it freezes.\n *\n * When `A2A_SECRET` is unset (local dev), the request is sent unsigned — the\n * processor accepts unsigned dispatches in dev and relies on the SQL atomic\n * claim for double-processing protection, mirroring the A2A/webhook flow.\n */\n/**\n * For host-root dispatch targets (`/.netlify/functions/*`), strip the configured\n * app base path suffix from the resolved base url so the request reaches the\n * function at the host root rather than under the workspace app base path. For\n * every other (framework-route) path the base-path-prefixed base url is returned\n * unchanged, preserving the existing self-dispatch behavior.\n */\nfunction rootBaseUrlForPath(baseUrl: string, path: string): string {\n if (!path.startsWith(\"/.netlify/\")) return baseUrl;\n const basePath = getConfiguredAppBasePath();\n if (!basePath) return baseUrl;\n const trimmed = baseUrl.replace(/\\/$/, \"\");\n if (trimmed.endsWith(basePath)) {\n return trimmed.slice(0, trimmed.length - basePath.length);\n }\n return trimmed;\n}\n\nexport async function fireInternalDispatch(\n options: FireInternalDispatchOptions,\n): Promise<void> {\n const baseUrl = options.baseUrl ?? resolveSelfDispatchBaseUrl(options.event);\n // Netlify function default urls (`/.netlify/functions/<name>`) live at the\n // HOST ROOT, not under the workspace app base path. `resolveSelfDispatchBaseUrl`\n // appends the configured base path (e.g. `https://host/starter`) so framework\n // routes land on the right app; for a host-root function url we must dispatch\n // to `https://host/.netlify/functions/<name>` instead. Strip the base path\n // suffix from the resolved base url for `/.netlify/*` dispatch targets only.\n const url = `${rootBaseUrlForPath(baseUrl, options.path)}${options.path}`;\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n };\n try {\n headers[\"Authorization\"] = `Bearer ${signInternalToken(options.taskId)}`;\n } catch (err) {\n // Distinguish the documented \"no A2A_SECRET in dev\" path from a real\n // signing failure, so a malformed secret doesn't fail invisibly.\n if (err instanceof Error && !/A2A_SECRET/i.test(err.message)) {\n console.error(\n `[self-dispatch] signInternalToken failed unexpectedly for ${options.taskId}:`,\n err,\n );\n }\n }\n\n const awaitResponse = options.awaitResponse === true;\n const dispatchPromise = fetch(url, {\n method: \"POST\",\n headers,\n body: JSON.stringify({ taskId: options.taskId, ...(options.body ?? {}) }),\n ...(awaitResponse\n ? { signal: AbortSignal.timeout(options.responseTimeoutMs ?? 15_000) }\n : {}),\n }).then(async (res) => {\n if (!res.ok) {\n throw await dispatchResponseError(options.path, res);\n }\n });\n dispatchPromise.catch((err) => {\n // Include the resolved base URL: a self-dispatch failure is almost always\n // about *which* host we POST to (custom domain behind an edge/auth wall vs\n // the deploy URL), and that is invisible from the error alone. Keeps prod\n // logs diagnostic without changing the URL resolution order.\n console.error(\n `[self-dispatch] dispatch to ${options.path} (base ${baseUrl}) failed:`,\n err,\n );\n });\n\n if (awaitResponse) {\n // Confirmed handoff: resolve only once the target acknowledged the\n // dispatch (throws on network error / timeout / non-2xx). Used by callers\n // whose own invocation is about to end — see the option doc above.\n await dispatchPromise;\n return;\n }\n\n const settleMs = options.settleMs ?? DEFAULT_DISPATCH_SETTLE_MS;\n await Promise.race([\n dispatchPromise,\n new Promise<void>((resolve) => setTimeout(resolve, settleMs)),\n ]);\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"ssr-handler.d.ts","sourceRoot":"","sources":["../../src/server/ssr-handler.ts"],"names":[],"mappings":"AA8CA,OAAO,EACL,yBAAyB,EACzB,gCAAgC,EAChC,yBAAyB,GAC1B,MAAM,4BAA4B,CAAC;AAooBpC;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,2FAgE5E"}
1
+ {"version":3,"file":"ssr-handler.d.ts","sourceRoot":"","sources":["../../src/server/ssr-handler.ts"],"names":[],"mappings":"AAuCA,OAAO,EACL,yBAAyB,EACzB,gCAAgC,EAChC,yBAAyB,GAC1B,MAAM,4BAA4B,CAAC;AAoSpC;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,2FAgE5E"}