@agent-native/core 0.32.2 → 0.32.18

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 (241) hide show
  1. package/README.md +3 -1
  2. package/dist/agent/run-store.d.ts.map +1 -1
  3. package/dist/agent/run-store.js +48 -10
  4. package/dist/agent/run-store.js.map +1 -1
  5. package/dist/agent/thread-data-builder.d.ts +12 -0
  6. package/dist/agent/thread-data-builder.d.ts.map +1 -1
  7. package/dist/agent/thread-data-builder.js +104 -6
  8. package/dist/agent/thread-data-builder.js.map +1 -1
  9. package/dist/cli/app-skill.js +2 -2
  10. package/dist/cli/app-skill.js.map +1 -1
  11. package/dist/cli/code-agent-executor.d.ts.map +1 -1
  12. package/dist/cli/code-agent-executor.js +6 -1
  13. package/dist/cli/code-agent-executor.js.map +1 -1
  14. package/dist/cli/code-agent-output-smoother.d.ts +7 -0
  15. package/dist/cli/code-agent-output-smoother.d.ts.map +1 -0
  16. package/dist/cli/code-agent-output-smoother.js +111 -0
  17. package/dist/cli/code-agent-output-smoother.js.map +1 -0
  18. package/dist/cli/connect.d.ts.map +1 -1
  19. package/dist/cli/connect.js +5 -0
  20. package/dist/cli/connect.js.map +1 -1
  21. package/dist/cli/migrate.d.ts.map +1 -1
  22. package/dist/cli/migrate.js +17 -42
  23. package/dist/cli/migrate.js.map +1 -1
  24. package/dist/cli/skills.d.ts +23 -2
  25. package/dist/cli/skills.d.ts.map +1 -1
  26. package/dist/cli/skills.js +405 -41
  27. package/dist/cli/skills.js.map +1 -1
  28. package/dist/cli/templates-meta.d.ts.map +1 -1
  29. package/dist/cli/templates-meta.js +7 -105
  30. package/dist/cli/templates-meta.js.map +1 -1
  31. package/dist/client/AgentPanel.d.ts.map +1 -1
  32. package/dist/client/AgentPanel.js +41 -7
  33. package/dist/client/AgentPanel.js.map +1 -1
  34. package/dist/client/AgentTaskCard.d.ts.map +1 -1
  35. package/dist/client/AgentTaskCard.js +0 -28
  36. package/dist/client/AgentTaskCard.js.map +1 -1
  37. package/dist/client/AssistantChat.d.ts +8 -23
  38. package/dist/client/AssistantChat.d.ts.map +1 -1
  39. package/dist/client/AssistantChat.js +359 -205
  40. package/dist/client/AssistantChat.js.map +1 -1
  41. package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
  42. package/dist/client/MultiTabAssistantChat.js +254 -14
  43. package/dist/client/MultiTabAssistantChat.js.map +1 -1
  44. package/dist/client/agent-chat-adapter.d.ts.map +1 -1
  45. package/dist/client/agent-chat-adapter.js +14 -9
  46. package/dist/client/agent-chat-adapter.js.map +1 -1
  47. package/dist/client/agent-chat.d.ts +24 -0
  48. package/dist/client/agent-chat.d.ts.map +1 -1
  49. package/dist/client/agent-chat.js +73 -0
  50. package/dist/client/agent-chat.js.map +1 -1
  51. package/dist/client/assistant-ui-recovery.d.ts +34 -0
  52. package/dist/client/assistant-ui-recovery.d.ts.map +1 -0
  53. package/dist/client/assistant-ui-recovery.js +122 -0
  54. package/dist/client/assistant-ui-recovery.js.map +1 -0
  55. package/dist/client/composer/PromptComposer.d.ts.map +1 -1
  56. package/dist/client/composer/PromptComposer.js +7 -1
  57. package/dist/client/composer/PromptComposer.js.map +1 -1
  58. package/dist/client/composer/TiptapComposer.d.ts +7 -1
  59. package/dist/client/composer/TiptapComposer.d.ts.map +1 -1
  60. package/dist/client/composer/TiptapComposer.js +22 -2
  61. package/dist/client/composer/TiptapComposer.js.map +1 -1
  62. package/dist/client/frame-protocol.d.ts +6 -2
  63. package/dist/client/frame-protocol.d.ts.map +1 -1
  64. package/dist/client/frame-protocol.js.map +1 -1
  65. package/dist/client/index.d.ts +2 -1
  66. package/dist/client/index.d.ts.map +1 -1
  67. package/dist/client/index.js +2 -1
  68. package/dist/client/index.js.map +1 -1
  69. package/dist/client/org/OrgSwitcher.d.ts.map +1 -1
  70. package/dist/client/org/OrgSwitcher.js +2 -1
  71. package/dist/client/org/OrgSwitcher.js.map +1 -1
  72. package/dist/client/progress/RunsTray.d.ts +13 -3
  73. package/dist/client/progress/RunsTray.d.ts.map +1 -1
  74. package/dist/client/progress/RunsTray.js +105 -36
  75. package/dist/client/progress/RunsTray.js.map +1 -1
  76. package/dist/client/route-warmup.d.ts +61 -0
  77. package/dist/client/route-warmup.d.ts.map +1 -0
  78. package/dist/client/route-warmup.js +456 -0
  79. package/dist/client/route-warmup.js.map +1 -0
  80. package/dist/client/settings/SettingsPanel.d.ts.map +1 -1
  81. package/dist/client/settings/SettingsPanel.js +2 -1
  82. package/dist/client/settings/SettingsPanel.js.map +1 -1
  83. package/dist/client/settings/useBuilderStatus.d.ts +5 -0
  84. package/dist/client/settings/useBuilderStatus.d.ts.map +1 -1
  85. package/dist/client/settings/useBuilderStatus.js +10 -4
  86. package/dist/client/settings/useBuilderStatus.js.map +1 -1
  87. package/dist/client/use-action.d.ts +1 -0
  88. package/dist/client/use-action.d.ts.map +1 -1
  89. package/dist/client/use-action.js +22 -4
  90. package/dist/client/use-action.js.map +1 -1
  91. package/dist/code-agents/background-run.d.ts +2 -0
  92. package/dist/code-agents/background-run.d.ts.map +1 -1
  93. package/dist/code-agents/background-run.js.map +1 -1
  94. package/dist/db/client.d.ts +1 -1
  95. package/dist/db/client.d.ts.map +1 -1
  96. package/dist/db/client.js +25 -1
  97. package/dist/db/client.js.map +1 -1
  98. package/dist/deploy/build.d.ts +4 -0
  99. package/dist/deploy/build.d.ts.map +1 -1
  100. package/dist/deploy/build.js +171 -14
  101. package/dist/deploy/build.js.map +1 -1
  102. package/dist/deploy/immutable-assets.d.ts +1 -0
  103. package/dist/deploy/immutable-assets.d.ts.map +1 -1
  104. package/dist/deploy/immutable-assets.js +1 -0
  105. package/dist/deploy/immutable-assets.js.map +1 -1
  106. package/dist/index.browser.d.ts +1 -1
  107. package/dist/index.browser.d.ts.map +1 -1
  108. package/dist/index.browser.js +1 -1
  109. package/dist/index.browser.js.map +1 -1
  110. package/dist/index.d.ts +1 -1
  111. package/dist/index.d.ts.map +1 -1
  112. package/dist/index.js +1 -1
  113. package/dist/index.js.map +1 -1
  114. package/dist/mcp/connect-route.d.ts.map +1 -1
  115. package/dist/mcp/connect-route.js +118 -82
  116. package/dist/mcp/connect-route.js.map +1 -1
  117. package/dist/progress/routes.d.ts.map +1 -1
  118. package/dist/progress/routes.js +1 -0
  119. package/dist/progress/routes.js.map +1 -1
  120. package/dist/progress/store.d.ts +13 -0
  121. package/dist/progress/store.d.ts.map +1 -1
  122. package/dist/progress/store.js +18 -0
  123. package/dist/progress/store.js.map +1 -1
  124. package/dist/progress/types.d.ts +2 -0
  125. package/dist/progress/types.d.ts.map +1 -1
  126. package/dist/progress/types.js.map +1 -1
  127. package/dist/scripts/db/wipe-leaked-builder-keys.d.ts +2 -2
  128. package/dist/scripts/db/wipe-leaked-builder-keys.d.ts.map +1 -1
  129. package/dist/scripts/db/wipe-leaked-builder-keys.js +14 -3
  130. package/dist/scripts/db/wipe-leaked-builder-keys.js.map +1 -1
  131. package/dist/server/action-routes.d.ts +1 -0
  132. package/dist/server/action-routes.d.ts.map +1 -1
  133. package/dist/server/action-routes.js +36 -2
  134. package/dist/server/action-routes.js.map +1 -1
  135. package/dist/server/agent-chat-plugin.d.ts +5 -0
  136. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  137. package/dist/server/agent-chat-plugin.js +131 -26
  138. package/dist/server/agent-chat-plugin.js.map +1 -1
  139. package/dist/server/agent-discovery.d.ts.map +1 -1
  140. package/dist/server/agent-discovery.js +14 -1
  141. package/dist/server/agent-discovery.js.map +1 -1
  142. package/dist/server/agent-teams-run-queue.d.ts +80 -0
  143. package/dist/server/agent-teams-run-queue.d.ts.map +1 -0
  144. package/dist/server/agent-teams-run-queue.js +208 -0
  145. package/dist/server/agent-teams-run-queue.js.map +1 -0
  146. package/dist/server/agent-teams.d.ts +67 -0
  147. package/dist/server/agent-teams.d.ts.map +1 -1
  148. package/dist/server/agent-teams.js +607 -180
  149. package/dist/server/agent-teams.js.map +1 -1
  150. package/dist/server/auth-marketing.d.ts.map +1 -1
  151. package/dist/server/auth-marketing.js +0 -64
  152. package/dist/server/auth-marketing.js.map +1 -1
  153. package/dist/server/auth.d.ts.map +1 -1
  154. package/dist/server/auth.js +67 -14
  155. package/dist/server/auth.js.map +1 -1
  156. package/dist/server/builder-browser.d.ts +12 -2
  157. package/dist/server/builder-browser.d.ts.map +1 -1
  158. package/dist/server/builder-browser.js +24 -0
  159. package/dist/server/builder-browser.js.map +1 -1
  160. package/dist/server/core-routes-plugin.d.ts.map +1 -1
  161. package/dist/server/core-routes-plugin.js +66 -5
  162. package/dist/server/core-routes-plugin.js.map +1 -1
  163. package/dist/server/credential-provider.d.ts +10 -0
  164. package/dist/server/credential-provider.d.ts.map +1 -1
  165. package/dist/server/credential-provider.js +82 -3
  166. package/dist/server/credential-provider.js.map +1 -1
  167. package/dist/server/csrf.d.ts.map +1 -1
  168. package/dist/server/csrf.js +3 -0
  169. package/dist/server/csrf.js.map +1 -1
  170. package/dist/server/index.d.ts +1 -0
  171. package/dist/server/index.d.ts.map +1 -1
  172. package/dist/server/index.js +1 -0
  173. package/dist/server/index.js.map +1 -1
  174. package/dist/server/onboarding-html.d.ts +1 -0
  175. package/dist/server/onboarding-html.d.ts.map +1 -1
  176. package/dist/server/onboarding-html.js +14 -1
  177. package/dist/server/onboarding-html.js.map +1 -1
  178. package/dist/server/self-dispatch.d.ts +44 -0
  179. package/dist/server/self-dispatch.d.ts.map +1 -0
  180. package/dist/server/self-dispatch.js +113 -0
  181. package/dist/server/self-dispatch.js.map +1 -0
  182. package/dist/server/social-og-image.d.ts +14 -0
  183. package/dist/server/social-og-image.d.ts.map +1 -0
  184. package/dist/server/social-og-image.js +251 -0
  185. package/dist/server/social-og-image.js.map +1 -0
  186. package/dist/server/ssr-handler.d.ts +1 -1
  187. package/dist/server/ssr-handler.d.ts.map +1 -1
  188. package/dist/server/ssr-handler.js +27 -11
  189. package/dist/server/ssr-handler.js.map +1 -1
  190. package/dist/shared/cache-control.d.ts +7 -0
  191. package/dist/shared/cache-control.d.ts.map +1 -1
  192. package/dist/shared/cache-control.js +7 -0
  193. package/dist/shared/cache-control.js.map +1 -1
  194. package/dist/shared/index.d.ts +1 -1
  195. package/dist/shared/index.d.ts.map +1 -1
  196. package/dist/shared/index.js +1 -1
  197. package/dist/shared/index.js.map +1 -1
  198. package/dist/shared/route-warmup-config.d.ts +28 -0
  199. package/dist/shared/route-warmup-config.d.ts.map +1 -0
  200. package/dist/shared/route-warmup-config.js +58 -0
  201. package/dist/shared/route-warmup-config.js.map +1 -0
  202. package/dist/shared/social-meta.d.ts +5 -0
  203. package/dist/shared/social-meta.d.ts.map +1 -1
  204. package/dist/shared/social-meta.js +36 -2
  205. package/dist/shared/social-meta.js.map +1 -1
  206. package/dist/shared/streaming-text-smoothing.d.ts +12 -0
  207. package/dist/shared/streaming-text-smoothing.d.ts.map +1 -0
  208. package/dist/shared/streaming-text-smoothing.js +52 -0
  209. package/dist/shared/streaming-text-smoothing.js.map +1 -0
  210. package/dist/styles/agent-native.css +4 -4
  211. package/dist/templates/default/AGENTS.md +9 -4
  212. package/dist/templates/default/DEVELOPING.md +15 -1
  213. package/dist/templates/workspace-core/AGENTS.md +7 -3
  214. package/dist/templates/workspace-root/AGENTS.md +7 -3
  215. package/dist/vite/client.d.ts +13 -0
  216. package/dist/vite/client.d.ts.map +1 -1
  217. package/dist/vite/client.js +26 -0
  218. package/dist/vite/client.js.map +1 -1
  219. package/dist/vite/index.d.ts +1 -0
  220. package/dist/vite/index.d.ts.map +1 -1
  221. package/dist/vite/index.js.map +1 -1
  222. package/docs/content/client.md +62 -1
  223. package/docs/content/code-agents-ui.md +6 -13
  224. package/docs/content/context-awareness.md +186 -21
  225. package/docs/content/deployment.md +8 -11
  226. package/docs/content/dispatch.md +1 -1
  227. package/docs/content/external-agents.md +32 -2
  228. package/docs/content/migration-workbench.md +4 -21
  229. package/docs/content/multi-app-workspace.md +1 -1
  230. package/docs/content/recurring-jobs.md +1 -1
  231. package/docs/content/security.md +0 -1
  232. package/docs/content/sharing.md +1 -3
  233. package/docs/content/skills-guide.md +12 -10
  234. package/docs/content/template-assets.md +21 -1
  235. package/docs/content/template-design.md +23 -5
  236. package/docs/content/template-dispatch.md +1 -1
  237. package/package.json +2 -1
  238. package/src/templates/default/AGENTS.md +9 -4
  239. package/src/templates/default/DEVELOPING.md +15 -1
  240. package/src/templates/workspace-core/AGENTS.md +7 -3
  241. package/src/templates/workspace-root/AGENTS.md +7 -3
@@ -0,0 +1,113 @@
1
+ /**
2
+ * Shared self-dispatch helper for the framework's serverless background-work
3
+ * pattern: enqueue a unit of work to SQL, then fire a fresh HTTP POST back to
4
+ * this same deployment so the work runs in its own function invocation (with
5
+ * its own full timeout budget) instead of riding on the request that created
6
+ * it.
7
+ *
8
+ * This is the single mechanism that makes background work portable across every
9
+ * host Nitro deploys to:
10
+ * - Netlify Lambda / Vercel Functions / AWS Lambda — the dispatched request
11
+ * hits a fresh function with its own budget; no `waitUntil` needed.
12
+ * - Cloudflare Workers — same (and `waitUntil` still works as a belt-and-
13
+ * suspenders fallback where the in-process path is used).
14
+ * - Self-hosted / long-lived Node — the dispatch comes back as another
15
+ * request to the same process; each handler still runs to completion.
16
+ *
17
+ * Originally inlined in both `a2a/handlers.ts` (`resolveSelfBaseUrl` +
18
+ * `fireProcessTaskDispatch`) and `integrations/webhook-handler.ts`
19
+ * (`resolveBaseUrl` + the dispatch in `enqueueAndDispatch`). Extracted here so
20
+ * A2A, integration webhooks, and Agent Teams sub-agents share one tested
21
+ * implementation.
22
+ */
23
+ import { withConfiguredAppBasePath } from "./app-base-path.js";
24
+ import { isLocalDatabase } from "../db/client.js";
25
+ import { signInternalToken } from "../integrations/internal-token.js";
26
+ /**
27
+ * On serverless, returning from the dispatching handler before the outbound
28
+ * TCP handshake starts can freeze the function with the dispatch request stuck
29
+ * in the queue. Racing the fetch against a short timer gives the request a
30
+ * chance to leave the box at the cost of a little added latency on the
31
+ * dispatching call. Mirrors the 250ms used by the A2A/webhook paths.
32
+ */
33
+ export const DEFAULT_DISPATCH_SETTLE_MS = 250;
34
+ function readHeader(event, name) {
35
+ try {
36
+ const headers = event?.node?.req?.headers ?? event?.headers;
37
+ if (!headers)
38
+ return undefined;
39
+ if (typeof headers.get === "function") {
40
+ return headers.get(name) ?? undefined;
41
+ }
42
+ const map = headers;
43
+ return map[name] ?? map[String(name).toLowerCase()];
44
+ }
45
+ catch {
46
+ return undefined;
47
+ }
48
+ }
49
+ /**
50
+ * Resolve the base URL to fire a self-dispatch request at. Prefers explicit env
51
+ * vars (most reliable on serverless, where inbound host headers can be the
52
+ * platform's internal hostname), falling back to the inbound request headers
53
+ * and finally localhost in dev.
54
+ *
55
+ * Throws in production / shared deployments when no env var is set — a silent
56
+ * fallback to a bad host there would drop background work invisibly.
57
+ */
58
+ export function resolveSelfDispatchBaseUrl(event) {
59
+ const fromEnv = process.env.APP_URL ||
60
+ process.env.URL ||
61
+ process.env.DEPLOY_URL ||
62
+ process.env.BETTER_AUTH_URL;
63
+ if (fromEnv)
64
+ return withConfiguredAppBasePath(String(fromEnv));
65
+ if (process.env.NODE_ENV === "production" || !isLocalDatabase()) {
66
+ throw new Error("Self-dispatch requires APP_URL, URL, DEPLOY_URL, or BETTER_AUTH_URL in " +
67
+ "production/shared deployments so background work can reach this " +
68
+ "deployment's own URL.");
69
+ }
70
+ const proto = readHeader(event, "x-forwarded-proto") || "http";
71
+ const host = readHeader(event, "host") || `localhost:${process.env.PORT || 3000}`;
72
+ return withConfiguredAppBasePath(`${proto}://${host}`);
73
+ }
74
+ /**
75
+ * Fire a fresh, HMAC-signed POST to a processor route on this same deployment.
76
+ * Fire-and-forget: the dispatch is NOT awaited to completion (the processed run
77
+ * may take minutes); it is only raced against a short settle timer so the
78
+ * request reliably leaves a serverless box before it freezes.
79
+ *
80
+ * When `A2A_SECRET` is unset (local dev), the request is sent unsigned — the
81
+ * processor accepts unsigned dispatches in dev and relies on the SQL atomic
82
+ * claim for double-processing protection, mirroring the A2A/webhook flow.
83
+ */
84
+ export async function fireInternalDispatch(options) {
85
+ const baseUrl = options.baseUrl ?? resolveSelfDispatchBaseUrl(options.event);
86
+ const url = `${baseUrl}${options.path}`;
87
+ const headers = {
88
+ "Content-Type": "application/json",
89
+ };
90
+ try {
91
+ headers["Authorization"] = `Bearer ${signInternalToken(options.taskId)}`;
92
+ }
93
+ catch (err) {
94
+ // Distinguish the documented "no A2A_SECRET in dev" path from a real
95
+ // signing failure, so a malformed secret doesn't fail invisibly.
96
+ if (err instanceof Error && !/A2A_SECRET/i.test(err.message)) {
97
+ console.error(`[self-dispatch] signInternalToken failed unexpectedly for ${options.taskId}:`, err);
98
+ }
99
+ }
100
+ const dispatchPromise = fetch(url, {
101
+ method: "POST",
102
+ headers,
103
+ body: JSON.stringify({ taskId: options.taskId, ...(options.body ?? {}) }),
104
+ }).catch((err) => {
105
+ console.error(`[self-dispatch] dispatch to ${options.path} failed:`, err);
106
+ });
107
+ const settleMs = options.settleMs ?? DEFAULT_DISPATCH_SETTLE_MS;
108
+ await Promise.race([
109
+ dispatchPromise,
110
+ new Promise((resolve) => setTimeout(resolve, settleMs)),
111
+ ]);
112
+ }
113
+ //# sourceMappingURL=self-dispatch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"self-dispatch.js","sourceRoot":"","sources":["../../src/server/self-dispatch.ts"],"names":[],"mappings":"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","sourcesContent":["/**\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 { withConfiguredAppBasePath } from \"./app-base-path.js\";\nimport { isLocalDatabase } from \"../db/client.js\";\nimport { signInternalToken } from \"../integrations/internal-token.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\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 */\nexport async function fireInternalDispatch(\n options: FireInternalDispatchOptions,\n): Promise<void> {\n const baseUrl = options.baseUrl ?? resolveSelfDispatchBaseUrl(options.event);\n const url = `${baseUrl}${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 }).catch((err) => {\n console.error(`[self-dispatch] dispatch to ${options.path} failed:`, err);\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"]}
@@ -0,0 +1,14 @@
1
+ export interface AgentNativeOgImageInput {
2
+ appName?: string | null;
3
+ title?: string | null;
4
+ accentText?: string | null;
5
+ }
6
+ export declare const AGENT_NATIVE_OG_IMAGE_WIDTH = 1200;
7
+ export declare const AGENT_NATIVE_OG_IMAGE_HEIGHT = 630;
8
+ export declare const AGENT_NATIVE_OG_IMAGE_CACHE_CONTROL = "public, max-age=60, stale-while-revalidate=604800, stale-if-error=3600";
9
+ export declare const AGENT_NATIVE_OG_IMAGE_NETLIFY_CACHE_CONTROL = "public, durable, max-age=60, stale-while-revalidate=604800, stale-if-error=3600";
10
+ export declare function renderAgentNativeOgImageSvg(input?: AgentNativeOgImageInput): string;
11
+ export declare function renderAgentNativeOgImagePng(input?: AgentNativeOgImageInput): Promise<Uint8Array>;
12
+ export declare function agentNativeOgImageResponseHeaders(byteLength?: number): Record<string, string>;
13
+ export declare function createAgentNativeOgImageHandler(options?: AgentNativeOgImageInput): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<Response>>;
14
+ //# sourceMappingURL=social-og-image.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"social-og-image.d.ts","sourceRoot":"","sources":["../../src/server/social-og-image.ts"],"names":[],"mappings":"AAWA,MAAM,WAAW,uBAAuB;IACtC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED,eAAO,MAAM,2BAA2B,OAAO,CAAC;AAChD,eAAO,MAAM,4BAA4B,MAAM,CAAC;AAChD,eAAO,MAAM,mCAAmC,2EAC0B,CAAC;AAC3E,eAAO,MAAM,2CAA2C,oFAC2B,CAAC;AAmOpF,wBAAgB,2BAA2B,CACzC,KAAK,GAAE,uBAA4B,GAClC,MAAM,CAsCR;AAED,wBAAsB,2BAA2B,CAC/C,KAAK,GAAE,uBAA4B,GAClC,OAAO,CAAC,UAAU,CAAC,CAWrB;AAED,wBAAgB,iCAAiC,CAC/C,UAAU,CAAC,EAAE,MAAM,GAClB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAYxB;AAED,wBAAgB,+BAA+B,CAC7C,OAAO,GAAE,uBAA4B,2FAuBtC"}
@@ -0,0 +1,251 @@
1
+ import { defineEventHandler, getHeader, getMethod, getQuery, getRequestURL, } from "h3";
2
+ import { resolveBuiltInAuthMarketing } from "./auth-marketing.js";
3
+ import { getAppName } from "./app-name.js";
4
+ export const AGENT_NATIVE_OG_IMAGE_WIDTH = 1200;
5
+ export const AGENT_NATIVE_OG_IMAGE_HEIGHT = 630;
6
+ export const AGENT_NATIVE_OG_IMAGE_CACHE_CONTROL = "public, max-age=60, stale-while-revalidate=604800, stale-if-error=3600";
7
+ export const AGENT_NATIVE_OG_IMAGE_NETLIFY_CACHE_CONTROL = "public, durable, max-age=60, stale-while-revalidate=604800, stale-if-error=3600";
8
+ const WIDTH = AGENT_NATIVE_OG_IMAGE_WIDTH;
9
+ const HEIGHT = AGENT_NATIVE_OG_IMAGE_HEIGHT;
10
+ const BRAND_BLUE = "#00B5FF";
11
+ const BRAND_MINT = "#48FFE4";
12
+ const BG = "#000000";
13
+ const FG = "#f5f5f5";
14
+ const FONT_FAMILY = "Inter, Liberation Sans, Arial, Helvetica, system-ui, sans-serif";
15
+ const DEFAULT_ACCENT_TEXT = "100% free and open source";
16
+ const LOGO_MARK = `
17
+ <path d="M24.5537 65.7695H0L15.0859 39.4619L37.708 0L60.4912 39.4619H39.6396L24.5537 65.7695Z" fill="white"/>
18
+ <path d="M89.446 0H114L76.2921 65.7704H51.7383L89.446 0Z" fill="url(#brand)"/>
19
+ `;
20
+ function escapeSvg(value) {
21
+ return value
22
+ .replace(/&/g, "&amp;")
23
+ .replace(/</g, "&lt;")
24
+ .replace(/>/g, "&gt;")
25
+ .replace(/"/g, "&quot;");
26
+ }
27
+ function cleanText(value) {
28
+ return String(value ?? "")
29
+ .replace(/\s+/g, " ")
30
+ .trim();
31
+ }
32
+ function titleCase(value) {
33
+ return value
34
+ .split(/[\s._-]+/)
35
+ .filter(Boolean)
36
+ .map((part) => part.charAt(0).toUpperCase() + part.slice(1).toLowerCase())
37
+ .join(" ");
38
+ }
39
+ function titleFromAppName(appName) {
40
+ if (appName)
41
+ return appName;
42
+ const basePath = process.env.VITE_APP_BASE_PATH || process.env.APP_BASE_PATH || "";
43
+ const slug = basePath.split("/").filter(Boolean)[0] || "";
44
+ return titleCase(slug) || "Agent-Native";
45
+ }
46
+ function estimateTextWidth(value, fontSize) {
47
+ let units = 0;
48
+ for (const char of value) {
49
+ if (char === " ") {
50
+ units += 0.28;
51
+ }
52
+ else if (/[MW@#%&]/.test(char)) {
53
+ units += 0.86;
54
+ }
55
+ else if (/[A-Z]/.test(char)) {
56
+ units += 0.64;
57
+ }
58
+ else if (/[ilI.,:;|!']/u.test(char)) {
59
+ units += 0.26;
60
+ }
61
+ else if (/[0-9]/.test(char)) {
62
+ units += 0.56;
63
+ }
64
+ else {
65
+ units += 0.54;
66
+ }
67
+ }
68
+ return units * fontSize;
69
+ }
70
+ function trimTextToWidth(value, fontSize, maxWidth) {
71
+ const ellipsis = "...";
72
+ let trimmed = value.trim();
73
+ while (trimmed.length > 0 &&
74
+ estimateTextWidth(`${trimmed}${ellipsis}`, fontSize) > maxWidth) {
75
+ trimmed = trimmed.slice(0, -1).trimEnd();
76
+ }
77
+ return trimmed ? `${trimmed}${ellipsis}` : ellipsis;
78
+ }
79
+ function wrapTextToWidth(value, fontSize, maxWidth, maxLines) {
80
+ const words = value.split(/\s+/).filter(Boolean);
81
+ const lines = [];
82
+ let current = "";
83
+ let truncated = false;
84
+ for (const word of words) {
85
+ const next = current ? `${current} ${word}` : word;
86
+ if (estimateTextWidth(next, fontSize) <= maxWidth) {
87
+ current = next;
88
+ continue;
89
+ }
90
+ if (!current) {
91
+ lines.push(trimTextToWidth(word, fontSize, maxWidth));
92
+ truncated = true;
93
+ current = "";
94
+ }
95
+ else {
96
+ lines.push(current);
97
+ current = word;
98
+ }
99
+ if (lines.length === maxLines) {
100
+ truncated = true;
101
+ break;
102
+ }
103
+ }
104
+ if (current && lines.length < maxLines)
105
+ lines.push(current);
106
+ const usedWordCount = lines.join(" ").split(/\s+/).filter(Boolean).length;
107
+ if (usedWordCount < words.length && lines.length > 0) {
108
+ lines[lines.length - 1] = trimTextToWidth(lines[lines.length - 1], fontSize, maxWidth);
109
+ truncated = true;
110
+ }
111
+ return {
112
+ lines: lines.length ? lines : [trimTextToWidth(value, fontSize, maxWidth)],
113
+ truncated,
114
+ };
115
+ }
116
+ function getTitleLayout(title) {
117
+ const maxTitleWidth = 900;
118
+ if (estimateTextWidth(title, 88) <= maxTitleWidth) {
119
+ return {
120
+ lines: [title],
121
+ fontSize: 88,
122
+ lineHeight: 96,
123
+ };
124
+ }
125
+ for (const fontSize of [76, 70, 64, 58, 52]) {
126
+ const wrapped = wrapTextToWidth(title, fontSize, maxTitleWidth, 2);
127
+ if (!wrapped.truncated) {
128
+ const lineHeight = Math.round(fontSize * 1.1);
129
+ return {
130
+ lines: wrapped.lines,
131
+ fontSize,
132
+ lineHeight,
133
+ };
134
+ }
135
+ }
136
+ const fallbackFontSize = 52;
137
+ const wrapped = wrapTextToWidth(title, fallbackFontSize, maxTitleWidth, 2);
138
+ return {
139
+ lines: wrapped.lines,
140
+ fontSize: fallbackFontSize,
141
+ lineHeight: 60,
142
+ };
143
+ }
144
+ function textBlock({ lines, x, y, fontSize, lineHeight, weight, fill, anchor = "start", }) {
145
+ return `<text x="${x}" y="${y}" text-anchor="${anchor}" font-family="${FONT_FAMILY}" font-size="${fontSize}" font-weight="${weight}" fill="${fill}">${lines
146
+ .map((line, index) => `<tspan x="${x}" dy="${index === 0 ? 0 : lineHeight}">${escapeSvg(line)}</tspan>`)
147
+ .join("")}</text>`;
148
+ }
149
+ function resolveDefaultAppName(event) {
150
+ const requestHost = event
151
+ ? (getHeader(event, "x-forwarded-host") ?? getHeader(event, "host"))
152
+ : undefined;
153
+ const requestPath = event ? getRequestURL(event).pathname : undefined;
154
+ return (getAppName() ??
155
+ resolveBuiltInAuthMarketing({ requestHost, requestPath })?.appName ??
156
+ "Agent-Native");
157
+ }
158
+ function queryStringValue(value, maxLength) {
159
+ if (typeof value !== "string")
160
+ return undefined;
161
+ const clean = cleanText(value).slice(0, maxLength);
162
+ return clean || undefined;
163
+ }
164
+ function pngBody(bytes) {
165
+ const body = new ArrayBuffer(bytes.byteLength);
166
+ new Uint8Array(body).set(bytes);
167
+ return body;
168
+ }
169
+ export function renderAgentNativeOgImageSvg(input = {}) {
170
+ const appName = cleanText(input.appName) || resolveDefaultAppName();
171
+ const title = cleanText(input.title) || titleFromAppName(appName);
172
+ const accentText = cleanText(input.accentText) || DEFAULT_ACCENT_TEXT;
173
+ const titleLayout = getTitleLayout(title);
174
+ const titleY = titleLayout.lines.length > 1 ? 288 : 330;
175
+ const accentY = titleY + titleLayout.lineHeight * (titleLayout.lines.length - 1) + 70;
176
+ return `<svg xmlns="http://www.w3.org/2000/svg" width="${WIDTH}" height="${HEIGHT}" viewBox="0 0 ${WIDTH} ${HEIGHT}">
177
+ <title>${escapeSvg(title)} - Agent-Native preview</title>
178
+ <defs>
179
+ <linearGradient id="brand" x1="101.702" y1="67.4791" x2="113.672" y2="-37.4275" gradientUnits="userSpaceOnUse">
180
+ <stop stop-color="${BRAND_BLUE}"/>
181
+ <stop offset="1" stop-color="${BRAND_MINT}"/>
182
+ </linearGradient>
183
+ <pattern id="grid" width="48" height="48" patternUnits="userSpaceOnUse">
184
+ <path d="M 48 0 L 0 0 0 48" fill="none" stroke="#ffffff" stroke-opacity="0.07" stroke-width="1"/>
185
+ </pattern>
186
+ </defs>
187
+ <rect width="${WIDTH}" height="${HEIGHT}" fill="${BG}"/>
188
+ <rect width="${WIDTH}" height="${HEIGHT}" fill="url(#grid)"/>
189
+ <g transform="translate(80 116) scale(0.94)">
190
+ ${LOGO_MARK}
191
+ </g>
192
+ <g>
193
+ ${textBlock({
194
+ lines: titleLayout.lines,
195
+ x: 80,
196
+ y: titleY,
197
+ fontSize: titleLayout.fontSize,
198
+ lineHeight: titleLayout.lineHeight,
199
+ weight: 850,
200
+ fill: FG,
201
+ })}
202
+ <text x="84" y="${accentY}" font-family="${FONT_FAMILY}" font-size="34" font-weight="800" fill="${BRAND_BLUE}">${escapeSvg(accentText)}</text>
203
+ </g>
204
+ </svg>`;
205
+ }
206
+ export async function renderAgentNativeOgImagePng(input = {}) {
207
+ const { Resvg } = await import(/* @vite-ignore */ "@resvg/resvg-js");
208
+ const image = new Resvg(renderAgentNativeOgImageSvg(input), {
209
+ fitTo: { mode: "width", value: WIDTH },
210
+ font: {
211
+ loadSystemFonts: true,
212
+ defaultFontFamily: "Arial",
213
+ sansSerifFamily: "Arial",
214
+ },
215
+ }).render();
216
+ return image.asPng();
217
+ }
218
+ export function agentNativeOgImageResponseHeaders(byteLength) {
219
+ const headers = {
220
+ "Content-Type": "image/png",
221
+ "Cache-Control": AGENT_NATIVE_OG_IMAGE_CACHE_CONTROL,
222
+ "CDN-Cache-Control": AGENT_NATIVE_OG_IMAGE_CACHE_CONTROL,
223
+ "Netlify-CDN-Cache-Control": AGENT_NATIVE_OG_IMAGE_NETLIFY_CACHE_CONTROL,
224
+ "Cross-Origin-Resource-Policy": "cross-origin",
225
+ };
226
+ if (typeof byteLength === "number") {
227
+ headers["Content-Length"] = String(byteLength);
228
+ }
229
+ return headers;
230
+ }
231
+ export function createAgentNativeOgImageHandler(options = {}) {
232
+ return defineEventHandler(async (event) => {
233
+ if (getMethod(event) === "HEAD") {
234
+ return new Response(null, {
235
+ headers: agentNativeOgImageResponseHeaders(),
236
+ });
237
+ }
238
+ const query = getQuery(event);
239
+ const appName = cleanText(options.appName) || resolveDefaultAppName(event);
240
+ const png = await renderAgentNativeOgImagePng({
241
+ ...options,
242
+ appName,
243
+ title: cleanText(options.title) || queryStringValue(query.title, 140),
244
+ accentText: cleanText(options.accentText) || queryStringValue(query.accentText, 80),
245
+ });
246
+ return new Response(pngBody(png), {
247
+ headers: agentNativeOgImageResponseHeaders(png.byteLength),
248
+ });
249
+ });
250
+ }
251
+ //# sourceMappingURL=social-og-image.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"social-og-image.js","sourceRoot":"","sources":["../../src/server/social-og-image.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n defineEventHandler,\n getHeader,\n getMethod,\n getQuery,\n getRequestURL,\n type H3Event,\n} from \"h3\";\nimport { resolveBuiltInAuthMarketing } from \"./auth-marketing.js\";\nimport { getAppName } from \"./app-name.js\";\n\nexport interface AgentNativeOgImageInput {\n appName?: string | null;\n title?: string | null;\n accentText?: string | null;\n}\n\nexport const AGENT_NATIVE_OG_IMAGE_WIDTH = 1200;\nexport const AGENT_NATIVE_OG_IMAGE_HEIGHT = 630;\nexport const AGENT_NATIVE_OG_IMAGE_CACHE_CONTROL =\n \"public, max-age=60, stale-while-revalidate=604800, stale-if-error=3600\";\nexport const AGENT_NATIVE_OG_IMAGE_NETLIFY_CACHE_CONTROL =\n \"public, durable, max-age=60, stale-while-revalidate=604800, stale-if-error=3600\";\n\nconst WIDTH = AGENT_NATIVE_OG_IMAGE_WIDTH;\nconst HEIGHT = AGENT_NATIVE_OG_IMAGE_HEIGHT;\nconst BRAND_BLUE = \"#00B5FF\";\nconst BRAND_MINT = \"#48FFE4\";\nconst BG = \"#000000\";\nconst FG = \"#f5f5f5\";\nconst FONT_FAMILY =\n \"Inter, Liberation Sans, Arial, Helvetica, system-ui, sans-serif\";\nconst DEFAULT_ACCENT_TEXT = \"100% free and open source\";\n\nconst LOGO_MARK = `\n <path d=\"M24.5537 65.7695H0L15.0859 39.4619L37.708 0L60.4912 39.4619H39.6396L24.5537 65.7695Z\" fill=\"white\"/>\n <path d=\"M89.446 0H114L76.2921 65.7704H51.7383L89.446 0Z\" fill=\"url(#brand)\"/>\n`;\n\nfunction escapeSvg(value: string): string {\n return value\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\");\n}\n\nfunction cleanText(value: string | null | undefined): string {\n return String(value ?? \"\")\n .replace(/\\s+/g, \" \")\n .trim();\n}\n\nfunction titleCase(value: string): string {\n return value\n .split(/[\\s._-]+/)\n .filter(Boolean)\n .map((part) => part.charAt(0).toUpperCase() + part.slice(1).toLowerCase())\n .join(\" \");\n}\n\nfunction titleFromAppName(appName: string): string {\n if (appName) return appName;\n const basePath =\n process.env.VITE_APP_BASE_PATH || process.env.APP_BASE_PATH || \"\";\n const slug = basePath.split(\"/\").filter(Boolean)[0] || \"\";\n return titleCase(slug) || \"Agent-Native\";\n}\n\ninterface WrappedText {\n lines: string[];\n truncated: boolean;\n}\n\ninterface TitleLayout {\n lines: string[];\n fontSize: number;\n lineHeight: number;\n}\n\nfunction estimateTextWidth(value: string, fontSize: number): number {\n let units = 0;\n for (const char of value) {\n if (char === \" \") {\n units += 0.28;\n } else if (/[MW@#%&]/.test(char)) {\n units += 0.86;\n } else if (/[A-Z]/.test(char)) {\n units += 0.64;\n } else if (/[ilI.,:;|!']/u.test(char)) {\n units += 0.26;\n } else if (/[0-9]/.test(char)) {\n units += 0.56;\n } else {\n units += 0.54;\n }\n }\n return units * fontSize;\n}\n\nfunction trimTextToWidth(\n value: string,\n fontSize: number,\n maxWidth: number,\n): string {\n const ellipsis = \"...\";\n let trimmed = value.trim();\n while (\n trimmed.length > 0 &&\n estimateTextWidth(`${trimmed}${ellipsis}`, fontSize) > maxWidth\n ) {\n trimmed = trimmed.slice(0, -1).trimEnd();\n }\n return trimmed ? `${trimmed}${ellipsis}` : ellipsis;\n}\n\nfunction wrapTextToWidth(\n value: string,\n fontSize: number,\n maxWidth: number,\n maxLines: number,\n): WrappedText {\n const words = value.split(/\\s+/).filter(Boolean);\n const lines: string[] = [];\n let current = \"\";\n let truncated = false;\n\n for (const word of words) {\n const next = current ? `${current} ${word}` : word;\n if (estimateTextWidth(next, fontSize) <= maxWidth) {\n current = next;\n continue;\n }\n if (!current) {\n lines.push(trimTextToWidth(word, fontSize, maxWidth));\n truncated = true;\n current = \"\";\n } else {\n lines.push(current);\n current = word;\n }\n if (lines.length === maxLines) {\n truncated = true;\n break;\n }\n }\n if (current && lines.length < maxLines) lines.push(current);\n\n const usedWordCount = lines.join(\" \").split(/\\s+/).filter(Boolean).length;\n if (usedWordCount < words.length && lines.length > 0) {\n lines[lines.length - 1] = trimTextToWidth(\n lines[lines.length - 1],\n fontSize,\n maxWidth,\n );\n truncated = true;\n }\n\n return {\n lines: lines.length ? lines : [trimTextToWidth(value, fontSize, maxWidth)],\n truncated,\n };\n}\n\nfunction getTitleLayout(title: string): TitleLayout {\n const maxTitleWidth = 900;\n if (estimateTextWidth(title, 88) <= maxTitleWidth) {\n return {\n lines: [title],\n fontSize: 88,\n lineHeight: 96,\n };\n }\n\n for (const fontSize of [76, 70, 64, 58, 52]) {\n const wrapped = wrapTextToWidth(title, fontSize, maxTitleWidth, 2);\n if (!wrapped.truncated) {\n const lineHeight = Math.round(fontSize * 1.1);\n return {\n lines: wrapped.lines,\n fontSize,\n lineHeight,\n };\n }\n }\n\n const fallbackFontSize = 52;\n const wrapped = wrapTextToWidth(title, fallbackFontSize, maxTitleWidth, 2);\n return {\n lines: wrapped.lines,\n fontSize: fallbackFontSize,\n lineHeight: 60,\n };\n}\n\nfunction textBlock({\n lines,\n x,\n y,\n fontSize,\n lineHeight,\n weight,\n fill,\n anchor = \"start\",\n}: {\n lines: string[];\n x: number;\n y: number;\n fontSize: number;\n lineHeight: number;\n weight: number;\n fill: string;\n anchor?: \"start\" | \"middle\";\n}): string {\n return `<text x=\"${x}\" y=\"${y}\" text-anchor=\"${anchor}\" font-family=\"${FONT_FAMILY}\" font-size=\"${fontSize}\" font-weight=\"${weight}\" fill=\"${fill}\">${lines\n .map(\n (line, index) =>\n `<tspan x=\"${x}\" dy=\"${index === 0 ? 0 : lineHeight}\">${escapeSvg(line)}</tspan>`,\n )\n .join(\"\")}</text>`;\n}\n\nfunction resolveDefaultAppName(event?: H3Event): string {\n const requestHost = event\n ? (getHeader(event, \"x-forwarded-host\") ?? getHeader(event, \"host\"))\n : undefined;\n const requestPath = event ? getRequestURL(event).pathname : undefined;\n return (\n getAppName() ??\n resolveBuiltInAuthMarketing({ requestHost, requestPath })?.appName ??\n \"Agent-Native\"\n );\n}\n\nfunction queryStringValue(\n value: unknown,\n maxLength: number,\n): string | undefined {\n if (typeof value !== \"string\") return undefined;\n const clean = cleanText(value).slice(0, maxLength);\n return clean || undefined;\n}\n\nfunction pngBody(bytes: Uint8Array): ArrayBuffer {\n const body = new ArrayBuffer(bytes.byteLength);\n new Uint8Array(body).set(bytes);\n return body;\n}\n\nexport function renderAgentNativeOgImageSvg(\n input: AgentNativeOgImageInput = {},\n): string {\n const appName = cleanText(input.appName) || resolveDefaultAppName();\n const title = cleanText(input.title) || titleFromAppName(appName);\n const accentText = cleanText(input.accentText) || DEFAULT_ACCENT_TEXT;\n const titleLayout = getTitleLayout(title);\n const titleY = titleLayout.lines.length > 1 ? 288 : 330;\n const accentY =\n titleY + titleLayout.lineHeight * (titleLayout.lines.length - 1) + 70;\n\n return `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"${WIDTH}\" height=\"${HEIGHT}\" viewBox=\"0 0 ${WIDTH} ${HEIGHT}\">\n <title>${escapeSvg(title)} - Agent-Native preview</title>\n <defs>\n <linearGradient id=\"brand\" x1=\"101.702\" y1=\"67.4791\" x2=\"113.672\" y2=\"-37.4275\" gradientUnits=\"userSpaceOnUse\">\n <stop stop-color=\"${BRAND_BLUE}\"/>\n <stop offset=\"1\" stop-color=\"${BRAND_MINT}\"/>\n </linearGradient>\n <pattern id=\"grid\" width=\"48\" height=\"48\" patternUnits=\"userSpaceOnUse\">\n <path d=\"M 48 0 L 0 0 0 48\" fill=\"none\" stroke=\"#ffffff\" stroke-opacity=\"0.07\" stroke-width=\"1\"/>\n </pattern>\n </defs>\n <rect width=\"${WIDTH}\" height=\"${HEIGHT}\" fill=\"${BG}\"/>\n <rect width=\"${WIDTH}\" height=\"${HEIGHT}\" fill=\"url(#grid)\"/>\n <g transform=\"translate(80 116) scale(0.94)\">\n ${LOGO_MARK}\n </g>\n <g>\n ${textBlock({\n lines: titleLayout.lines,\n x: 80,\n y: titleY,\n fontSize: titleLayout.fontSize,\n lineHeight: titleLayout.lineHeight,\n weight: 850,\n fill: FG,\n })}\n <text x=\"84\" y=\"${accentY}\" font-family=\"${FONT_FAMILY}\" font-size=\"34\" font-weight=\"800\" fill=\"${BRAND_BLUE}\">${escapeSvg(accentText)}</text>\n </g>\n</svg>`;\n}\n\nexport async function renderAgentNativeOgImagePng(\n input: AgentNativeOgImageInput = {},\n): Promise<Uint8Array> {\n const { Resvg } = await import(/* @vite-ignore */ \"@resvg/resvg-js\");\n const image = new Resvg(renderAgentNativeOgImageSvg(input), {\n fitTo: { mode: \"width\", value: WIDTH },\n font: {\n loadSystemFonts: true,\n defaultFontFamily: \"Arial\",\n sansSerifFamily: \"Arial\",\n },\n }).render();\n return image.asPng();\n}\n\nexport function agentNativeOgImageResponseHeaders(\n byteLength?: number,\n): Record<string, string> {\n const headers: Record<string, string> = {\n \"Content-Type\": \"image/png\",\n \"Cache-Control\": AGENT_NATIVE_OG_IMAGE_CACHE_CONTROL,\n \"CDN-Cache-Control\": AGENT_NATIVE_OG_IMAGE_CACHE_CONTROL,\n \"Netlify-CDN-Cache-Control\": AGENT_NATIVE_OG_IMAGE_NETLIFY_CACHE_CONTROL,\n \"Cross-Origin-Resource-Policy\": \"cross-origin\",\n };\n if (typeof byteLength === \"number\") {\n headers[\"Content-Length\"] = String(byteLength);\n }\n return headers;\n}\n\nexport function createAgentNativeOgImageHandler(\n options: AgentNativeOgImageInput = {},\n) {\n return defineEventHandler(async (event) => {\n if (getMethod(event) === \"HEAD\") {\n return new Response(null, {\n headers: agentNativeOgImageResponseHeaders(),\n });\n }\n\n const query = getQuery(event);\n const appName = cleanText(options.appName) || resolveDefaultAppName(event);\n const png = await renderAgentNativeOgImagePng({\n ...options,\n appName,\n title: cleanText(options.title) || queryStringValue(query.title, 140),\n accentText:\n cleanText(options.accentText) || queryStringValue(query.accentText, 80),\n });\n\n return new Response(pngBody(png), {\n headers: agentNativeOgImageResponseHeaders(png.byteLength),\n });\n });\n}\n"]}
@@ -1,4 +1,4 @@
1
- export { DEFAULT_SPECULATION_RULES_HEADER, DEFAULT_SSR_CACHE_CONTROL, } from "../shared/cache-control.js";
1
+ export { DEFAULT_SSR_CACHE_HEADERS, DEFAULT_SPECULATION_RULES_HEADER, DEFAULT_SSR_CACHE_CONTROL, } from "../shared/cache-control.js";
2
2
  /**
3
3
  * Create an h3 catch-all that hands page routes to React Router and
4
4
  * returns 404 for framework / asset paths that React Router doesn't own.
@@ -1 +1 @@
1
- {"version":3,"file":"ssr-handler.d.ts","sourceRoot":"","sources":["../../src/server/ssr-handler.ts"],"names":[],"mappings":"AAqCA,OAAO,EACL,gCAAgC,EAChC,yBAAyB,GAC1B,MAAM,4BAA4B,CAAC;AA2UpC;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,2FAuE5E"}
1
+ {"version":3,"file":"ssr-handler.d.ts","sourceRoot":"","sources":["../../src/server/ssr-handler.ts"],"names":[],"mappings":"AA4CA,OAAO,EACL,yBAAyB,EACzB,gCAAgC,EAChC,yBAAyB,GAC1B,MAAM,4BAA4B,CAAC;AAyWpC;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,2FAyE5E"}
@@ -22,9 +22,9 @@ import { BETTER_AUTH_COOKIE_PREFIX, COOKIE_NAME, getSession } from "./auth.js";
22
22
  import { hasAuthContextAccess, runWithRequestContext, } from "./request-context.js";
23
23
  import { requestHasEmbedAuthMarker } from "./embed-session.js";
24
24
  import { EMBED_SESSION_COOKIE, EMBED_TOKEN_QUERY_PARAM, } from "../shared/embed-auth.js";
25
- import { AGENT_NATIVE_DEFAULT_SOCIAL_IMAGE } from "../shared/social-meta.js";
26
- import { DEFAULT_SPECULATION_RULES_PATH, DEFAULT_SSR_CACHE_CONTROL, } from "../shared/cache-control.js";
27
- export { DEFAULT_SPECULATION_RULES_HEADER, DEFAULT_SSR_CACHE_CONTROL, } from "../shared/cache-control.js";
25
+ import { AGENT_NATIVE_SOCIAL_IMAGE_ALT, AGENT_NATIVE_SOCIAL_IMAGE_HEIGHT, AGENT_NATIVE_SOCIAL_IMAGE_PATH, AGENT_NATIVE_SOCIAL_IMAGE_TYPE, AGENT_NATIVE_SOCIAL_IMAGE_WIDTH, } from "../shared/social-meta.js";
26
+ import { DEFAULT_SSR_CACHE_HEADERS, DEFAULT_SPECULATION_RULES_PATH, } from "../shared/cache-control.js";
27
+ export { DEFAULT_SSR_CACHE_HEADERS, DEFAULT_SPECULATION_RULES_HEADER, DEFAULT_SSR_CACHE_CONTROL, } from "../shared/cache-control.js";
28
28
  const ANONYMOUS_SESSION_COOKIE_NAMES = new Set(["an_docs_session"]);
29
29
  const BETTER_AUTH_SESSION_COOKIE_RE = /\.session_(?:token|data)$/;
30
30
  /**
@@ -132,20 +132,29 @@ function injectHeadScript(html, script) {
132
132
  const OG_IMAGE_META_RE = /<meta\b(?=[^>]*\bproperty=(["'])og:image\1)[^>]*>/i;
133
133
  const TWITTER_CARD_META_RE = /<meta\b(?=[^>]*\bname=(["'])twitter:card\1)[^>]*>/i;
134
134
  const TWITTER_IMAGE_META_RE = /<meta\b(?=[^>]*\bname=(["'])twitter:image\1)[^>]*>/i;
135
- function injectDefaultSocialImageMeta(html) {
135
+ function defaultSocialImageUrl(requestUrl, basePath) {
136
+ return new URL(prefixMountedPath(AGENT_NATIVE_SOCIAL_IMAGE_PATH, basePath), requestUrl).toString();
137
+ }
138
+ function injectDefaultSocialImageMeta(html, imageUrl) {
136
139
  const headCloseIdx = html.indexOf("</head>");
137
140
  if (headCloseIdx === -1)
138
141
  return html;
139
142
  const hasAnySocialImage = OG_IMAGE_META_RE.test(html) || TWITTER_IMAGE_META_RE.test(html);
140
143
  const tags = [];
141
144
  if (!hasAnySocialImage) {
142
- tags.push(`<meta property="og:image" content="${AGENT_NATIVE_DEFAULT_SOCIAL_IMAGE}">`);
145
+ tags.push(`<meta property="og:image" content="${imageUrl}">`);
146
+ tags.push(`<meta property="og:image:secure_url" content="${imageUrl}">`);
147
+ tags.push(`<meta property="og:image:type" content="${AGENT_NATIVE_SOCIAL_IMAGE_TYPE}">`);
148
+ tags.push(`<meta property="og:image:width" content="${AGENT_NATIVE_SOCIAL_IMAGE_WIDTH}">`);
149
+ tags.push(`<meta property="og:image:height" content="${AGENT_NATIVE_SOCIAL_IMAGE_HEIGHT}">`);
150
+ tags.push(`<meta property="og:image:alt" content="${AGENT_NATIVE_SOCIAL_IMAGE_ALT}">`);
143
151
  }
144
152
  if (!TWITTER_CARD_META_RE.test(html)) {
145
153
  tags.push(`<meta name="twitter:card" content="summary_large_image">`);
146
154
  }
147
155
  if (!hasAnySocialImage) {
148
- tags.push(`<meta name="twitter:image" content="${AGENT_NATIVE_DEFAULT_SOCIAL_IMAGE}">`);
156
+ tags.push(`<meta name="twitter:image" content="${imageUrl}">`);
157
+ tags.push(`<meta name="twitter:image:alt" content="${AGENT_NATIVE_SOCIAL_IMAGE_ALT}">`);
149
158
  }
150
159
  if (tags.length === 0)
151
160
  return html;
@@ -221,7 +230,14 @@ function applyDefaultSsrCacheHeader(headers, status, pathname, authContextAccess
221
230
  if (!shouldUseDefaultSsrCacheHeader(headers, status, pathname, authContextAccessed)) {
222
231
  return;
223
232
  }
224
- headers.set("cache-control", DEFAULT_SSR_CACHE_CONTROL);
233
+ // Netlify Functions/proxies are not cached by default, and production docs
234
+ // requests often carry stale auth/doc cookies. Keep all three cache headers:
235
+ // Cache-Control for browsers, CDN-Cache-Control for generic CDNs, and
236
+ // Netlify-CDN-Cache-Control (with durable) so Netlify's shared cache actually
237
+ // serves SSR HTML/.data instead of forwarding every request to origin.
238
+ for (const [name, value] of Object.entries(DEFAULT_SSR_CACHE_HEADERS)) {
239
+ headers.set(name, value);
240
+ }
225
241
  }
226
242
  function applyDefaultSpeculationRulesHeader(headers, status, basePath) {
227
243
  if (status < 200 || status >= 400)
@@ -256,7 +272,7 @@ function isFrameworkOrAssetPath(pathname) {
256
272
  pathname === "/favicon.png" ||
257
273
  (/\.\w+$/.test(pathname) && !pathname.endsWith(".data")));
258
274
  }
259
- async function rewriteMountedResponse(response, basePath, pathname, requestContext) {
275
+ async function rewriteMountedResponse(response, basePath, pathname, requestUrl, requestContext) {
260
276
  const sentryClientConfigScript = getSentryClientConfigScript();
261
277
  const headers = new Headers(response.headers);
262
278
  applyDefaultSsrCacheHeader(headers, response.status, pathname, hasAuthContextAccess(requestContext));
@@ -275,7 +291,7 @@ async function rewriteMountedResponse(response, basePath, pathname, requestConte
275
291
  }
276
292
  const html = await response.text();
277
293
  headers.delete("content-length");
278
- return new Response(injectHeadScript(injectDefaultSocialImageMeta(prefixMountedHtml(html, basePath)), sentryClientConfigScript), {
294
+ return new Response(injectHeadScript(injectDefaultSocialImageMeta(prefixMountedHtml(html, basePath), defaultSocialImageUrl(requestUrl, basePath)), sentryClientConfigScript), {
279
295
  status: response.status,
280
296
  statusText: response.statusText,
281
297
  headers,
@@ -326,9 +342,9 @@ export function createH3SSRHandler(getBuild) {
326
342
  status: response.status,
327
343
  statusText: response.statusText,
328
344
  headers: response.headers,
329
- }), basePath, p, ctx);
345
+ }), basePath, p, request.url, ctx);
330
346
  }
331
- return await rewriteMountedResponse(await runWithRequestContext(ctx, () => handler(request)), basePath, p, ctx);
347
+ return await rewriteMountedResponse(await runWithRequestContext(ctx, () => handler(request)), basePath, p, request.url, ctx);
332
348
  }
333
349
  catch (err) {
334
350
  // Log the full stack server-side, but never leak it to the client.