@agent-native/core 0.22.4 → 0.22.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent/engine/builder-engine.d.ts.map +1 -1
- package/dist/agent/engine/builder-engine.js +10 -9
- package/dist/agent/engine/builder-engine.js.map +1 -1
- package/dist/agent/engine/builder-gateway-headers.d.ts +10 -0
- package/dist/agent/engine/builder-gateway-headers.d.ts.map +1 -0
- package/dist/agent/engine/builder-gateway-headers.js +44 -0
- package/dist/agent/engine/builder-gateway-headers.js.map +1 -0
- package/dist/agent/engine/index.d.ts +1 -1
- package/dist/agent/engine/index.d.ts.map +1 -1
- package/dist/agent/engine/index.js +1 -1
- package/dist/agent/engine/index.js.map +1 -1
- package/dist/agent/engine/registry.d.ts +1 -0
- package/dist/agent/engine/registry.d.ts.map +1 -1
- package/dist/agent/engine/registry.js +60 -1
- package/dist/agent/engine/registry.js.map +1 -1
- package/dist/agent/engine/translate-ai-sdk.d.ts.map +1 -1
- package/dist/agent/engine/translate-ai-sdk.js +3 -2
- package/dist/agent/engine/translate-ai-sdk.js.map +1 -1
- package/dist/agent/engine/translate-anthropic.d.ts +36 -2
- package/dist/agent/engine/translate-anthropic.d.ts.map +1 -1
- package/dist/agent/engine/translate-anthropic.js +159 -6
- package/dist/agent/engine/translate-anthropic.js.map +1 -1
- package/dist/agent/engine/types.d.ts +4 -2
- package/dist/agent/engine/types.d.ts.map +1 -1
- package/dist/agent/engine/types.js.map +1 -1
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +69 -9
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/agent/types.d.ts +2 -0
- package/dist/agent/types.d.ts.map +1 -1
- package/dist/agent/types.js.map +1 -1
- package/dist/cli/connect.d.ts +1 -1
- package/dist/cli/connect.d.ts.map +1 -1
- package/dist/cli/connect.js +5 -2
- package/dist/cli/connect.js.map +1 -1
- package/dist/cli/create.d.ts.map +1 -1
- package/dist/cli/create.js +48 -6
- package/dist/cli/create.js.map +1 -1
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +7 -1
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
- package/dist/client/MultiTabAssistantChat.js +4 -3
- package/dist/client/MultiTabAssistantChat.js.map +1 -1
- package/dist/client/NewWorkspaceAppFlow.d.ts.map +1 -1
- package/dist/client/NewWorkspaceAppFlow.js +1 -0
- package/dist/client/NewWorkspaceAppFlow.js.map +1 -1
- package/dist/client/agent-chat-adapter.d.ts.map +1 -1
- package/dist/client/agent-chat-adapter.js +11 -5
- package/dist/client/agent-chat-adapter.js.map +1 -1
- package/dist/client/api-path.d.ts.map +1 -1
- package/dist/client/api-path.js +2 -0
- package/dist/client/api-path.js.map +1 -1
- package/dist/client/embed-auth.d.ts +4 -0
- package/dist/client/embed-auth.d.ts.map +1 -0
- package/dist/client/embed-auth.js +102 -0
- package/dist/client/embed-auth.js.map +1 -0
- package/dist/client/index.d.ts +1 -0
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +1 -0
- package/dist/client/index.js.map +1 -1
- package/dist/client/settings/SettingsPanel.d.ts.map +1 -1
- package/dist/client/settings/SettingsPanel.js +7 -3
- package/dist/client/settings/SettingsPanel.js.map +1 -1
- package/dist/client/use-action.d.ts.map +1 -1
- package/dist/client/use-action.js +2 -0
- package/dist/client/use-action.js.map +1 -1
- package/dist/client/use-chat-models.d.ts.map +1 -1
- package/dist/client/use-chat-models.js +4 -3
- package/dist/client/use-chat-models.js.map +1 -1
- package/dist/client/use-chat-threads.d.ts.map +1 -1
- package/dist/client/use-chat-threads.js +7 -7
- package/dist/client/use-chat-threads.js.map +1 -1
- package/dist/client/use-chat-threads.spec.js +70 -0
- package/dist/client/use-chat-threads.spec.js.map +1 -1
- package/dist/client/use-db-sync.d.ts.map +1 -1
- package/dist/client/use-db-sync.js +4 -0
- package/dist/client/use-db-sync.js.map +1 -1
- package/dist/deploy/route-discovery.js +1 -1
- package/dist/deploy/route-discovery.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/mcp/build-server.d.ts.map +1 -1
- package/dist/mcp/build-server.js +49 -21
- package/dist/mcp/build-server.js.map +1 -1
- package/dist/mcp/builtin-tools.d.ts +1 -0
- package/dist/mcp/builtin-tools.d.ts.map +1 -1
- package/dist/mcp/builtin-tools.js +147 -8
- package/dist/mcp/builtin-tools.js.map +1 -1
- package/dist/mcp/connect-route.d.ts.map +1 -1
- package/dist/mcp/connect-route.js +79 -51
- package/dist/mcp/connect-route.js.map +1 -1
- package/dist/mcp/embed-app.d.ts +14 -0
- package/dist/mcp/embed-app.d.ts.map +1 -0
- package/dist/mcp/embed-app.js +191 -0
- package/dist/mcp/embed-app.js.map +1 -0
- package/dist/mcp/index.d.ts +1 -0
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js +1 -0
- package/dist/mcp/index.js.map +1 -1
- package/dist/scripts/agent-engines/list-agent-engines.d.ts.map +1 -1
- package/dist/scripts/agent-engines/list-agent-engines.js +2 -1
- package/dist/scripts/agent-engines/list-agent-engines.js.map +1 -1
- package/dist/scripts/agent-engines/manage-agent-engine.d.ts.map +1 -1
- package/dist/scripts/agent-engines/manage-agent-engine.js +4 -1
- package/dist/scripts/agent-engines/manage-agent-engine.js.map +1 -1
- package/dist/scripts/agent-engines/set-agent-engine.d.ts.map +1 -1
- package/dist/scripts/agent-engines/set-agent-engine.js +4 -1
- package/dist/scripts/agent-engines/set-agent-engine.js.map +1 -1
- package/dist/server/action-discovery.d.ts.map +1 -1
- package/dist/server/action-discovery.js +10 -1
- package/dist/server/action-discovery.js.map +1 -1
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +9 -1
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/auth.d.ts +7 -6
- package/dist/server/auth.d.ts.map +1 -1
- package/dist/server/auth.js +64 -15
- package/dist/server/auth.js.map +1 -1
- package/dist/server/core-routes-plugin.d.ts +2 -0
- package/dist/server/core-routes-plugin.d.ts.map +1 -1
- package/dist/server/core-routes-plugin.js +7 -0
- package/dist/server/core-routes-plugin.js.map +1 -1
- package/dist/server/credential-provider.d.ts +6 -4
- package/dist/server/credential-provider.d.ts.map +1 -1
- package/dist/server/credential-provider.js +91 -12
- package/dist/server/credential-provider.js.map +1 -1
- package/dist/server/embed-route.d.ts +8 -0
- package/dist/server/embed-route.d.ts.map +1 -0
- package/dist/server/embed-route.js +71 -0
- package/dist/server/embed-route.js.map +1 -0
- package/dist/server/embed-session.d.ts +65 -0
- package/dist/server/embed-session.d.ts.map +1 -0
- package/dist/server/embed-session.js +433 -0
- package/dist/server/embed-session.js.map +1 -0
- package/dist/server/index.d.ts +2 -0
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +2 -0
- package/dist/server/index.js.map +1 -1
- package/dist/server/open-route.d.ts.map +1 -1
- package/dist/server/open-route.js +10 -0
- package/dist/server/open-route.js.map +1 -1
- package/dist/server/security-headers.d.ts.map +1 -1
- package/dist/server/security-headers.js +4 -2
- package/dist/server/security-headers.js.map +1 -1
- package/dist/shared/embed-auth.d.ts +6 -0
- package/dist/shared/embed-auth.d.ts.map +1 -0
- package/dist/shared/embed-auth.js +6 -0
- package/dist/shared/embed-auth.js.map +1 -0
- package/dist/shared/index.d.ts +1 -0
- package/dist/shared/index.d.ts.map +1 -1
- package/dist/shared/index.js +1 -0
- package/dist/shared/index.js.map +1 -1
- package/dist/templates/workspace-core/AGENTS.md +14 -5
- package/dist/templates/workspace-root/AGENTS.md +5 -0
- package/dist/templates/workspace-root/README.md +3 -0
- package/dist/vite/action-types-plugin.d.ts.map +1 -1
- package/dist/vite/action-types-plugin.js +10 -1
- package/dist/vite/action-types-plugin.js.map +1 -1
- package/docs/content/a2a-protocol.md +5 -1
- package/docs/content/actions.md +19 -4
- package/docs/content/cli-adapters.md +5 -0
- package/docs/content/client.md +35 -1
- package/docs/content/database.md +29 -0
- package/docs/content/dispatch.md +7 -1
- package/docs/content/external-agents.md +37 -13
- package/docs/content/key-concepts.md +3 -3
- package/docs/content/messaging.md +1 -1
- package/docs/content/onboarding.md +26 -0
- package/docs/content/template-content.md +1 -1
- package/docs/content/template-dispatch.md +9 -0
- package/docs/content/template-starter.md +2 -2
- package/package.json +1 -1
- package/src/templates/workspace-core/AGENTS.md +14 -5
- package/src/templates/workspace-root/AGENTS.md +5 -0
- package/src/templates/workspace-root/README.md +3 -0
- /package/docs/content/{template-video.md → template-videos.md} +0 -0
|
@@ -2,12 +2,15 @@ import { defineEventHandler, getMethod } from "h3";
|
|
|
2
2
|
import { getSession, getConfiguredLoginHtml } from "./auth.js";
|
|
3
3
|
import { appStatePut, appStateGet } from "../application-state/store.js";
|
|
4
4
|
import { AGENT_SIDEBAR_QUERY_PARAM, withCollapsedAgentSidebarParam, } from "../shared/agent-sidebar-url.js";
|
|
5
|
+
import { EMBED_MODE_QUERY_PARAM, EMBED_TOKEN_QUERY_PARAM, } from "../shared/embed-auth.js";
|
|
5
6
|
/** Query keys that are route control, not navigation payload. */
|
|
6
7
|
const RESERVED = new Set([
|
|
7
8
|
"app",
|
|
8
9
|
"view",
|
|
9
10
|
"to",
|
|
10
11
|
"compose",
|
|
12
|
+
EMBED_MODE_QUERY_PARAM,
|
|
13
|
+
EMBED_TOKEN_QUERY_PARAM,
|
|
11
14
|
AGENT_SIDEBAR_QUERY_PARAM,
|
|
12
15
|
]);
|
|
13
16
|
// Control-char guard (NUL..US + DEL). Defined via codepoints so the source
|
|
@@ -171,6 +174,13 @@ export function createOpenRouteHandler(options = {}) {
|
|
|
171
174
|
filters.set(k, v);
|
|
172
175
|
}
|
|
173
176
|
target = appendSearchParams(target, filters);
|
|
177
|
+
const embedParams = new URLSearchParams();
|
|
178
|
+
for (const key of [EMBED_MODE_QUERY_PARAM, EMBED_TOKEN_QUERY_PARAM]) {
|
|
179
|
+
const value = search.get(key);
|
|
180
|
+
if (value)
|
|
181
|
+
embedParams.set(key, value);
|
|
182
|
+
}
|
|
183
|
+
target = appendSearchParams(target, embedParams);
|
|
174
184
|
target = withCollapsedAgentSidebarParam(target);
|
|
175
185
|
return redirect(target);
|
|
176
186
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"open-route.js","sourceRoot":"","sources":["../../src/server/open-route.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * `/_agent-native/open` — the stable deep-link route.\n *\n * An external coding agent (Claude Code / Cowork / Codex) surfaces an\n * \"Open in <app> →\" link (built by an action's `link` builder, see\n * `deep-link.ts`). When the user clicks it in any browser / inline webview,\n * this route:\n * 1. Resolves the *browser* session (NOT the agent token) — so the record\n * always lands where the human is logged in.\n * 2. When unauthenticated, serves the same sign-in form the auth guard\n * would, *at this same URL*. The login form's success handler reloads\n * `window.location.href`, so the now-authenticated request re-enters\n * this route and proceeds. No `?next=` plumbing needed.\n * 3. Writes the existing one-shot `navigate` application-state command (the\n * exact key the UI already drains every 2s — we don't invent a new\n * navigation mechanism, we bridge to it), plus an optional `compose-<id>`\n * draft.\n * 4. 302-redirects to the rendered SPA view so the page loads immediately;\n * the polled `navigate` command then applies record-level focus.\n *\n * The link itself is a pure pointer (view + record ids + filters) and carries\n * no privileged state.\n */\nimport type { H3Event } from \"h3\";\nimport { defineEventHandler, getMethod } from \"h3\";\nimport { getSession, getConfiguredLoginHtml } from \"./auth.js\";\nimport { appStatePut, appStateGet } from \"../application-state/store.js\";\nimport {\n AGENT_SIDEBAR_QUERY_PARAM,\n withCollapsedAgentSidebarParam,\n} from \"../shared/agent-sidebar-url.js\";\n\n/** Query keys that are route control, not navigation payload. */\nconst RESERVED = new Set([\n \"app\",\n \"view\",\n \"to\",\n \"compose\",\n AGENT_SIDEBAR_QUERY_PARAM,\n]);\n\n// Control-char guard (NUL..US + DEL). Defined via codepoints so the source\n// file stays plain ASCII.\nconst CONTROL_CHARS = new RegExp(\"[\\\\u0000-\\\\u001f\\\\u007f]\");\n\n// Compose-draft id charset. Mirrors `sanitizeDraftId` in\n// templates/mail/actions/manage-draft.ts so the id we concatenate into the\n// `compose-<id>` application-state key can't escape the key namespace\n// (path-traversal / key injection guard).\nconst COMPOSE_ID = /^[a-zA-Z0-9_-]{1,64}$/;\n\nexport interface OpenRouteOptions {\n /** Per-template override that turns the parsed deep-link params into the\n * client-side SPA path to redirect to. Return `null` to use the default\n * (`/<view>`). Filter params (`f_*`) are appended automatically. */\n resolveOpenPath?: (params: {\n app?: string;\n view?: string;\n params: Record<string, string>;\n }) => string | null | undefined;\n}\n\nfunction getRequestUrl(event: H3Event): string {\n return (event as any).node?.req?.url ?? (event as any).path ?? \"/\";\n}\n\n/** Decode a base64url string to UTF-8 (Node Buffer; this route is Node-only). */\nfunction decodeBase64Url(input: string): string {\n return Buffer.from(input, \"base64url\").toString(\"utf8\");\n}\n\n/**\n * Normalize a candidate redirect path to a safe, same-origin, leading-slash\n * relative path. Rejects absolute URLs, scheme-relative `//host`, and control\n * chars (open-redirect guard). Returns `null` when unsafe.\n */\nfunction safeRelativePath(raw: string | undefined | null): string | null {\n if (!raw) return null;\n if (CONTROL_CHARS.test(raw)) return null;\n if (!raw.startsWith(\"/\")) return null;\n if (raw.startsWith(\"//\") || raw.startsWith(\"/\\\\\")) return null;\n if (/^\\/[a-z][a-z0-9+.-]*:/i.test(raw)) return null;\n return raw;\n}\n\nfunction redirect(location: string): Response {\n // Native web Response (not h3 v2's reworked sendRedirect) — matches the\n // redirect pattern used elsewhere in auth.ts.\n return new Response(\"\", { status: 302, headers: { Location: location } });\n}\n\nfunction appendSearchParams(target: string, params: URLSearchParams): string {\n if (!params.toString()) return target;\n try {\n const url = new URL(target, \"http://an.invalid\");\n for (const [k, v] of params.entries()) url.searchParams.set(k, v);\n return `${url.pathname}${url.search}${url.hash}`;\n } catch {\n return target;\n }\n}\n\nexport function createOpenRouteHandler(options: OpenRouteOptions = {}) {\n return defineEventHandler(async (event: H3Event) => {\n const method = getMethod(event);\n if (method !== \"GET\" && method !== \"HEAD\") {\n return new Response(JSON.stringify({ error: \"Method not allowed\" }), {\n status: 405,\n headers: { \"Content-Type\": \"application/json\" },\n });\n }\n\n const rawUrl = getRequestUrl(event);\n let search: URLSearchParams;\n try {\n search = new URL(rawUrl, \"http://an.invalid\").searchParams;\n } catch {\n search = new URLSearchParams();\n }\n\n const app = search.get(\"app\") ?? undefined;\n const view = search.get(\"view\") ?? undefined;\n const toParam = search.get(\"to\") ?? undefined;\n const compose = search.get(\"compose\") ?? undefined;\n\n // Resolve the BROWSER session. When unauthenticated, serve the same login\n // form the guard would — at this URL — so the post-login reload returns\n // here authenticated.\n const session = await getSession(event);\n if (!session?.email) {\n const html = getConfiguredLoginHtml(event);\n if (html) {\n return new Response(html, {\n status: 200,\n headers: { \"Content-Type\": \"text/html; charset=utf-8\" },\n });\n }\n // No auth guard configured (fully open app) — best effort: still send\n // the user to the view; nothing to scope the navigate write to.\n }\n\n // Build the navigation payload from every non-reserved query param\n // (record ids + filters: threadId, eventId, dashboardId, f_*, ...).\n const navParams: Record<string, string> = {};\n for (const [k, v] of search.entries()) {\n if (RESERVED.has(k)) continue;\n navParams[k] = v;\n }\n const navPayload: Record<string, unknown> = { ...navParams };\n if (view) navPayload.view = view;\n\n if (session?.email) {\n try {\n await appStatePut(session.email, \"navigate\", navPayload, {\n requestSource: \"deep-link\",\n });\n if (compose) {\n try {\n const draft = JSON.parse(decodeBase64Url(compose));\n // Validate the id before using it as a key segment. An unsafe id\n // could escape the `compose-` namespace and clobber an unrelated\n // application-state key; skip the write (the view still opens),\n // mirroring the malformed-payload branch below.\n if (\n draft &&\n typeof draft === \"object\" &&\n typeof draft.id === \"string\" &&\n COMPOSE_ID.test(draft.id)\n ) {\n const composeKey = `compose-${draft.id}`;\n // A compact deep link may carry only `{ id, subject }` when the\n // full draft was too large to inline in the URL. The complete\n // draft is already persisted at `compose-<id>` by manage-draft\n // on create/update. Never let the truncated stub overwrite that\n // richer saved draft (would silently lose body / recipients /\n // reply metadata). Only write when the payload actually carries\n // content, or when nothing is saved yet (composer still opens).\n const hasContent =\n (typeof draft.body === \"string\" && draft.body.length > 0) ||\n !!draft.to ||\n !!draft.cc ||\n !!draft.bcc ||\n !!draft.html ||\n !!draft.replyToThreadId;\n const existing = hasContent\n ? null\n : await appStateGet(session.email, composeKey);\n if (hasContent || !existing) {\n await appStatePut(session.email, composeKey, draft, {\n requestSource: \"deep-link\",\n });\n }\n }\n } catch {\n // Malformed compose payload — skip; the view still opens.\n }\n }\n } catch {\n // App-state write failure shouldn't 500 the click; the redirect\n // below still lands the user on the right view.\n }\n }\n\n // Resolve the SPA path to redirect to.\n let target =\n safeRelativePath(toParam) ??\n safeRelativePath(\n options.resolveOpenPath?.({ app, view, params: navParams }) ??\n (view ? `/${view}` : null),\n ) ??\n \"/\";\n\n // Forward filter params (f_*) onto the redirect so dashboards/lists open\n // pre-filtered even before the navigate command is drained.\n const filters = new URLSearchParams();\n for (const [k, v] of search.entries()) {\n if (k.startsWith(\"f_\")) filters.set(k, v);\n }\n target = appendSearchParams(target, filters);\n target = withCollapsedAgentSidebarParam(target);\n\n return redirect(target);\n });\n}\n"]}
|
|
1
|
+
{"version":3,"file":"open-route.js","sourceRoot":"","sources":["../../src/server/open-route.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * `/_agent-native/open` — the stable deep-link route.\n *\n * An external coding agent (Claude Code / Cowork / Codex) surfaces an\n * \"Open in <app> →\" link (built by an action's `link` builder, see\n * `deep-link.ts`). When the user clicks it in any browser / inline webview,\n * this route:\n * 1. Resolves the *browser* session (NOT the agent token) — so the record\n * always lands where the human is logged in.\n * 2. When unauthenticated, serves the same sign-in form the auth guard\n * would, *at this same URL*. The login form's success handler reloads\n * `window.location.href`, so the now-authenticated request re-enters\n * this route and proceeds. No `?next=` plumbing needed.\n * 3. Writes the existing one-shot `navigate` application-state command (the\n * exact key the UI already drains every 2s — we don't invent a new\n * navigation mechanism, we bridge to it), plus an optional `compose-<id>`\n * draft.\n * 4. 302-redirects to the rendered SPA view so the page loads immediately;\n * the polled `navigate` command then applies record-level focus.\n *\n * The link itself is a pure pointer (view + record ids + filters) and carries\n * no privileged state.\n */\nimport type { H3Event } from \"h3\";\nimport { defineEventHandler, getMethod } from \"h3\";\nimport { getSession, getConfiguredLoginHtml } from \"./auth.js\";\nimport { appStatePut, appStateGet } from \"../application-state/store.js\";\nimport {\n AGENT_SIDEBAR_QUERY_PARAM,\n withCollapsedAgentSidebarParam,\n} from \"../shared/agent-sidebar-url.js\";\nimport {\n EMBED_MODE_QUERY_PARAM,\n EMBED_TOKEN_QUERY_PARAM,\n} from \"../shared/embed-auth.js\";\n\n/** Query keys that are route control, not navigation payload. */\nconst RESERVED = new Set([\n \"app\",\n \"view\",\n \"to\",\n \"compose\",\n EMBED_MODE_QUERY_PARAM,\n EMBED_TOKEN_QUERY_PARAM,\n AGENT_SIDEBAR_QUERY_PARAM,\n]);\n\n// Control-char guard (NUL..US + DEL). Defined via codepoints so the source\n// file stays plain ASCII.\nconst CONTROL_CHARS = new RegExp(\"[\\\\u0000-\\\\u001f\\\\u007f]\");\n\n// Compose-draft id charset. Mirrors `sanitizeDraftId` in\n// templates/mail/actions/manage-draft.ts so the id we concatenate into the\n// `compose-<id>` application-state key can't escape the key namespace\n// (path-traversal / key injection guard).\nconst COMPOSE_ID = /^[a-zA-Z0-9_-]{1,64}$/;\n\nexport interface OpenRouteOptions {\n /** Per-template override that turns the parsed deep-link params into the\n * client-side SPA path to redirect to. Return `null` to use the default\n * (`/<view>`). Filter params (`f_*`) are appended automatically. */\n resolveOpenPath?: (params: {\n app?: string;\n view?: string;\n params: Record<string, string>;\n }) => string | null | undefined;\n}\n\nfunction getRequestUrl(event: H3Event): string {\n return (event as any).node?.req?.url ?? (event as any).path ?? \"/\";\n}\n\n/** Decode a base64url string to UTF-8 (Node Buffer; this route is Node-only). */\nfunction decodeBase64Url(input: string): string {\n return Buffer.from(input, \"base64url\").toString(\"utf8\");\n}\n\n/**\n * Normalize a candidate redirect path to a safe, same-origin, leading-slash\n * relative path. Rejects absolute URLs, scheme-relative `//host`, and control\n * chars (open-redirect guard). Returns `null` when unsafe.\n */\nfunction safeRelativePath(raw: string | undefined | null): string | null {\n if (!raw) return null;\n if (CONTROL_CHARS.test(raw)) return null;\n if (!raw.startsWith(\"/\")) return null;\n if (raw.startsWith(\"//\") || raw.startsWith(\"/\\\\\")) return null;\n if (/^\\/[a-z][a-z0-9+.-]*:/i.test(raw)) return null;\n return raw;\n}\n\nfunction redirect(location: string): Response {\n // Native web Response (not h3 v2's reworked sendRedirect) — matches the\n // redirect pattern used elsewhere in auth.ts.\n return new Response(\"\", { status: 302, headers: { Location: location } });\n}\n\nfunction appendSearchParams(target: string, params: URLSearchParams): string {\n if (!params.toString()) return target;\n try {\n const url = new URL(target, \"http://an.invalid\");\n for (const [k, v] of params.entries()) url.searchParams.set(k, v);\n return `${url.pathname}${url.search}${url.hash}`;\n } catch {\n return target;\n }\n}\n\nexport function createOpenRouteHandler(options: OpenRouteOptions = {}) {\n return defineEventHandler(async (event: H3Event) => {\n const method = getMethod(event);\n if (method !== \"GET\" && method !== \"HEAD\") {\n return new Response(JSON.stringify({ error: \"Method not allowed\" }), {\n status: 405,\n headers: { \"Content-Type\": \"application/json\" },\n });\n }\n\n const rawUrl = getRequestUrl(event);\n let search: URLSearchParams;\n try {\n search = new URL(rawUrl, \"http://an.invalid\").searchParams;\n } catch {\n search = new URLSearchParams();\n }\n\n const app = search.get(\"app\") ?? undefined;\n const view = search.get(\"view\") ?? undefined;\n const toParam = search.get(\"to\") ?? undefined;\n const compose = search.get(\"compose\") ?? undefined;\n\n // Resolve the BROWSER session. When unauthenticated, serve the same login\n // form the guard would — at this URL — so the post-login reload returns\n // here authenticated.\n const session = await getSession(event);\n if (!session?.email) {\n const html = getConfiguredLoginHtml(event);\n if (html) {\n return new Response(html, {\n status: 200,\n headers: { \"Content-Type\": \"text/html; charset=utf-8\" },\n });\n }\n // No auth guard configured (fully open app) — best effort: still send\n // the user to the view; nothing to scope the navigate write to.\n }\n\n // Build the navigation payload from every non-reserved query param\n // (record ids + filters: threadId, eventId, dashboardId, f_*, ...).\n const navParams: Record<string, string> = {};\n for (const [k, v] of search.entries()) {\n if (RESERVED.has(k)) continue;\n navParams[k] = v;\n }\n const navPayload: Record<string, unknown> = { ...navParams };\n if (view) navPayload.view = view;\n\n if (session?.email) {\n try {\n await appStatePut(session.email, \"navigate\", navPayload, {\n requestSource: \"deep-link\",\n });\n if (compose) {\n try {\n const draft = JSON.parse(decodeBase64Url(compose));\n // Validate the id before using it as a key segment. An unsafe id\n // could escape the `compose-` namespace and clobber an unrelated\n // application-state key; skip the write (the view still opens),\n // mirroring the malformed-payload branch below.\n if (\n draft &&\n typeof draft === \"object\" &&\n typeof draft.id === \"string\" &&\n COMPOSE_ID.test(draft.id)\n ) {\n const composeKey = `compose-${draft.id}`;\n // A compact deep link may carry only `{ id, subject }` when the\n // full draft was too large to inline in the URL. The complete\n // draft is already persisted at `compose-<id>` by manage-draft\n // on create/update. Never let the truncated stub overwrite that\n // richer saved draft (would silently lose body / recipients /\n // reply metadata). Only write when the payload actually carries\n // content, or when nothing is saved yet (composer still opens).\n const hasContent =\n (typeof draft.body === \"string\" && draft.body.length > 0) ||\n !!draft.to ||\n !!draft.cc ||\n !!draft.bcc ||\n !!draft.html ||\n !!draft.replyToThreadId;\n const existing = hasContent\n ? null\n : await appStateGet(session.email, composeKey);\n if (hasContent || !existing) {\n await appStatePut(session.email, composeKey, draft, {\n requestSource: \"deep-link\",\n });\n }\n }\n } catch {\n // Malformed compose payload — skip; the view still opens.\n }\n }\n } catch {\n // App-state write failure shouldn't 500 the click; the redirect\n // below still lands the user on the right view.\n }\n }\n\n // Resolve the SPA path to redirect to.\n let target =\n safeRelativePath(toParam) ??\n safeRelativePath(\n options.resolveOpenPath?.({ app, view, params: navParams }) ??\n (view ? `/${view}` : null),\n ) ??\n \"/\";\n\n // Forward filter params (f_*) onto the redirect so dashboards/lists open\n // pre-filtered even before the navigate command is drained.\n const filters = new URLSearchParams();\n for (const [k, v] of search.entries()) {\n if (k.startsWith(\"f_\")) filters.set(k, v);\n }\n target = appendSearchParams(target, filters);\n const embedParams = new URLSearchParams();\n for (const key of [EMBED_MODE_QUERY_PARAM, EMBED_TOKEN_QUERY_PARAM]) {\n const value = search.get(key);\n if (value) embedParams.set(key, value);\n }\n target = appendSearchParams(target, embedParams);\n target = withCollapsedAgentSidebarParam(target);\n\n return redirect(target);\n });\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"security-headers.d.ts","sourceRoot":"","sources":["../../src/server/security-headers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;
|
|
1
|
+
{"version":3,"file":"security-headers.d.ts","sourceRoot":"","sources":["../../src/server/security-headers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AA8BH;;;;;;GAMG;AACH,wBAAgB,+BAA+B,8EAsB9C"}
|
|
@@ -45,6 +45,7 @@
|
|
|
45
45
|
* us most of the protection.
|
|
46
46
|
*/
|
|
47
47
|
import { defineEventHandler, setResponseHeader } from "h3";
|
|
48
|
+
import { requestHasEmbedAuthMarker } from "./embed-session.js";
|
|
48
49
|
const HSTS = "max-age=31536000; includeSubDomains; preload";
|
|
49
50
|
const PERMISSIONS_POLICY = "camera=(), microphone=(self), geolocation=(), screen-wake-lock=()";
|
|
50
51
|
/**
|
|
@@ -79,11 +80,12 @@ function isHttpsRequest(event) {
|
|
|
79
80
|
export function createSecurityHeadersMiddleware() {
|
|
80
81
|
const isProduction = process.env.NODE_ENV === "production";
|
|
81
82
|
return defineEventHandler((event) => {
|
|
83
|
+
const embedFrameRequest = requestHasEmbedAuthMarker(event);
|
|
82
84
|
setResponseHeader(event, "X-Content-Type-Options", "nosniff");
|
|
83
|
-
if (isProduction) {
|
|
85
|
+
if (isProduction && !embedFrameRequest) {
|
|
84
86
|
setResponseHeader(event, "X-Frame-Options", "DENY");
|
|
85
87
|
}
|
|
86
|
-
setResponseHeader(event, "Referrer-Policy", "strict-origin-when-cross-origin");
|
|
88
|
+
setResponseHeader(event, "Referrer-Policy", embedFrameRequest ? "no-referrer" : "strict-origin-when-cross-origin");
|
|
87
89
|
setResponseHeader(event, "Permissions-Policy", PERMISSIONS_POLICY);
|
|
88
90
|
setResponseHeader(event, "Cross-Origin-Opener-Policy", "same-origin");
|
|
89
91
|
setResponseHeader(event, "Cross-Origin-Resource-Policy", "same-site");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"security-headers.js","sourceRoot":"","sources":["../../src/server/security-headers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AAEH,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"security-headers.js","sourceRoot":"","sources":["../../src/server/security-headers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AAEH,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,IAAI,CAAC;AAC3D,OAAO,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAC;AAE/D,MAAM,IAAI,GAAG,8CAA8C,CAAC;AAC5D,MAAM,kBAAkB,GACtB,mEAAmE,CAAC;AAEtE;;;;;GAKG;AACH,SAAS,cAAc,CAAC,KAAU;IAChC,MAAM,GAAG,GACP,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC,mBAAmB,CAAC;QAChD,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,mBAAmB,CAAC,CAAC;IAC7C,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,OAAO;QACjE,OAAO,IAAI,CAAC;IACd,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,KAAK,OAAO;QAAE,OAAO,IAAI,CAAC;IAC1D,uDAAuD;IACvD,MAAM,KAAK,GAAG,KAAK,EAAE,GAAG,EAAE,QAAQ,CAAC;IACnC,IAAI,KAAK,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IACpC,2DAA2D;IAC3D,IAAI,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,UAAU,EAAE,SAAS;QAAE,OAAO,IAAI,CAAC;IACzD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,+BAA+B;IAC7C,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY,CAAC;IAC3D,OAAO,kBAAkB,CAAC,CAAC,KAAK,EAAE,EAAE;QAClC,MAAM,iBAAiB,GAAG,yBAAyB,CAAC,KAAK,CAAC,CAAC;QAC3D,iBAAiB,CAAC,KAAK,EAAE,wBAAwB,EAAE,SAAS,CAAC,CAAC;QAC9D,IAAI,YAAY,IAAI,CAAC,iBAAiB,EAAE,CAAC;YACvC,iBAAiB,CAAC,KAAK,EAAE,iBAAiB,EAAE,MAAM,CAAC,CAAC;QACtD,CAAC;QACD,iBAAiB,CACf,KAAK,EACL,iBAAiB,EACjB,iBAAiB,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,iCAAiC,CACtE,CAAC;QACF,iBAAiB,CAAC,KAAK,EAAE,oBAAoB,EAAE,kBAAkB,CAAC,CAAC;QACnE,iBAAiB,CAAC,KAAK,EAAE,4BAA4B,EAAE,aAAa,CAAC,CAAC;QACtE,iBAAiB,CAAC,KAAK,EAAE,8BAA8B,EAAE,WAAW,CAAC,CAAC;QACtE,IAAI,cAAc,CAAC,KAAK,CAAC,EAAE,CAAC;YAC1B,iBAAiB,CAAC,KAAK,EAAE,2BAA2B,EAAE,IAAI,CAAC,CAAC;QAC9D,CAAC;QACD,2EAA2E;QAC3E,OAAO,SAAS,CAAC;IACnB,CAAC,CAAC,CAAC;AACL,CAAC","sourcesContent":["/**\n * Security response headers middleware.\n *\n * Sets a baseline set of \"no-brainer\" security headers on every framework HTTP\n * response. These headers are layered defenses: each one mitigates a specific\n * class of attack, and together they harden the surface against clickjacking,\n * MIME-sniffing, referrer leakage, mixed-content downgrades, and cross-origin\n * window/embed access.\n *\n * The headers we emit:\n *\n * - `Strict-Transport-Security` — forces HTTPS for the browser's lifetime\n * of the cached value, preventing SSL-strip MITM. Only emitted when the\n * request scheme is `https` (we don't want to break local-dev HTTP, and\n * emitting HSTS over HTTP is a no-op per the spec but causes confusion).\n * - `X-Content-Type-Options: nosniff` — disables browser MIME sniffing so\n * a tool /render route serving user-authored HTML can't be misinterpreted\n * as some other content type by a clever Accept header.\n * - `X-Frame-Options: DENY` — prevents the entire app from being iframed by\n * other origins (clickjacking the agent chat, booking pages, etc.). The\n * tool /render endpoint and any other route that legitimately needs to be\n * embedded in the same-origin app shell can opt out by setting its own\n * header inside the route handler — h3's `setResponseHeader` overwrites,\n * so a route emitting `SAMEORIGIN` wins over our middleware default.\n * We skip this header entirely in dev (NODE_ENV !== \"production\") so the\n * desktop app's local dev frame (localhost:3334) can iframe templates\n * running on other localhost ports (e.g. mail at 8085).\n * - `Referrer-Policy: strict-origin-when-cross-origin` — strips path/query\n * from outbound Referer headers when the request crosses origin, so a\n * public-share viewer's outbound link clicks never leak the share token.\n * - `Permissions-Policy: camera=(), microphone=(self), geolocation=(),\n * screen-wake-lock=()` — allows the app shell to request microphone access\n * for composer dictation while keeping camera/location/wake-lock blocked\n * by default. Templates that need broader media capture for recording UI\n * override this on their own routes.\n * - `Cross-Origin-Opener-Policy: same-origin` — isolates window.opener so\n * a popup-window opener reference can't read or modify our document.\n * - `Cross-Origin-Resource-Policy: same-site` — prevents other origins from\n * embedding our endpoints as `<img>` / `<script>` / `<audio>`, blocking\n * the simplest data-leak chain when combined with auth cookies.\n *\n * NOTE: We don't set `Cross-Origin-Embedder-Policy` because it requires every\n * embedded subresource to opt in via CORP/CORS, which would break Builder's\n * iframe editor and template embed use cases. COOP + CORP without COEP gives\n * us most of the protection.\n */\n\nimport { defineEventHandler, setResponseHeader } from \"h3\";\nimport { requestHasEmbedAuthMarker } from \"./embed-session.js\";\n\nconst HSTS = \"max-age=31536000; includeSubDomains; preload\";\nconst PERMISSIONS_POLICY =\n \"camera=(), microphone=(self), geolocation=(), screen-wake-lock=()\";\n\n/**\n * Returns true when the request was received over HTTPS. We trust both the\n * underlying connection (when the server is terminating TLS itself) and the\n * `x-forwarded-proto` header (set by Netlify, Vercel, Cloudflare, and any\n * other reverse proxy that fronts the framework).\n */\nfunction isHttpsRequest(event: any): boolean {\n const xfp =\n event?.node?.req?.headers?.[\"x-forwarded-proto\"] ??\n event?.headers?.get?.(\"x-forwarded-proto\");\n if (typeof xfp === \"string\" && xfp.split(\",\")[0].trim() === \"https\")\n return true;\n if (Array.isArray(xfp) && xfp[0] === \"https\") return true;\n // h3 sets `event.url.protocol` to \"http:\" or \"https:\".\n const proto = event?.url?.protocol;\n if (proto === \"https:\") return true;\n // Direct Node `req.connection.encrypted` (older runtimes).\n if (event?.node?.req?.connection?.encrypted) return true;\n return false;\n}\n\n/**\n * Create the security-headers h3 middleware. Mount this BEFORE other route\n * handlers so the headers are present on every response (including 4xx/5xx\n * error pages). Route handlers that need to relax a specific header (e.g.\n * `X-Frame-Options: SAMEORIGIN` on the tool render route) can call\n * `setResponseHeader` after this runs — the latest write wins.\n */\nexport function createSecurityHeadersMiddleware() {\n const isProduction = process.env.NODE_ENV === \"production\";\n return defineEventHandler((event) => {\n const embedFrameRequest = requestHasEmbedAuthMarker(event);\n setResponseHeader(event, \"X-Content-Type-Options\", \"nosniff\");\n if (isProduction && !embedFrameRequest) {\n setResponseHeader(event, \"X-Frame-Options\", \"DENY\");\n }\n setResponseHeader(\n event,\n \"Referrer-Policy\",\n embedFrameRequest ? \"no-referrer\" : \"strict-origin-when-cross-origin\",\n );\n setResponseHeader(event, \"Permissions-Policy\", PERMISSIONS_POLICY);\n setResponseHeader(event, \"Cross-Origin-Opener-Policy\", \"same-origin\");\n setResponseHeader(event, \"Cross-Origin-Resource-Policy\", \"same-site\");\n if (isHttpsRequest(event)) {\n setResponseHeader(event, \"Strict-Transport-Security\", HSTS);\n }\n // Continue to the next handler — we only set headers, don't return a body.\n return undefined;\n });\n}\n"]}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export declare const EMBED_START_PATH = "/_agent-native/embed/start";
|
|
2
|
+
export declare const EMBED_TOKEN_QUERY_PARAM = "__an_embed_token";
|
|
3
|
+
export declare const EMBED_MODE_QUERY_PARAM = "embedded";
|
|
4
|
+
export declare const EMBED_SESSION_COOKIE = "an_embed_session";
|
|
5
|
+
export declare const EMBED_TARGET_HEADER = "x-agent-native-embed-target";
|
|
6
|
+
//# sourceMappingURL=embed-auth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"embed-auth.d.ts","sourceRoot":"","sources":["../../src/shared/embed-auth.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,gBAAgB,+BAA+B,CAAC;AAC7D,eAAO,MAAM,uBAAuB,qBAAqB,CAAC;AAC1D,eAAO,MAAM,sBAAsB,aAAa,CAAC;AACjD,eAAO,MAAM,oBAAoB,qBAAqB,CAAC;AACvD,eAAO,MAAM,mBAAmB,gCAAgC,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export const EMBED_START_PATH = "/_agent-native/embed/start";
|
|
2
|
+
export const EMBED_TOKEN_QUERY_PARAM = "__an_embed_token";
|
|
3
|
+
export const EMBED_MODE_QUERY_PARAM = "embedded";
|
|
4
|
+
export const EMBED_SESSION_COOKIE = "an_embed_session";
|
|
5
|
+
export const EMBED_TARGET_HEADER = "x-agent-native-embed-target";
|
|
6
|
+
//# sourceMappingURL=embed-auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"embed-auth.js","sourceRoot":"","sources":["../../src/shared/embed-auth.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,gBAAgB,GAAG,4BAA4B,CAAC;AAC7D,MAAM,CAAC,MAAM,uBAAuB,GAAG,kBAAkB,CAAC;AAC1D,MAAM,CAAC,MAAM,sBAAsB,GAAG,UAAU,CAAC;AACjD,MAAM,CAAC,MAAM,oBAAoB,GAAG,kBAAkB,CAAC;AACvD,MAAM,CAAC,MAAM,mBAAmB,GAAG,6BAA6B,CAAC","sourcesContent":["export const EMBED_START_PATH = \"/_agent-native/embed/start\";\nexport const EMBED_TOKEN_QUERY_PARAM = \"__an_embed_token\";\nexport const EMBED_MODE_QUERY_PARAM = \"embedded\";\nexport const EMBED_SESSION_COOKIE = \"an_embed_session\";\nexport const EMBED_TARGET_HEADER = \"x-agent-native-embed-target\";\n"]}
|
package/dist/shared/index.d.ts
CHANGED
|
@@ -6,4 +6,5 @@ export { llmConnectionTrackingProperties, normalizeLlmConnection, type LlmConnec
|
|
|
6
6
|
export { DISPATCH_WORKSPACE_ROOT_REDIRECTS, RESERVED_WORKSPACE_APP_IDS, assertValidWorkspaceAppId, getWorkspaceAppIdValidationError, isValidWorkspaceAppIdFormat, } from "./workspace-app-id.js";
|
|
7
7
|
export { DEFAULT_WORKSPACE_APP_AUDIENCE, WORKSPACE_APP_AUDIENCES, normalizeWorkspaceAppAudience, normalizeWorkspaceAppPathList, workspaceAppAudienceFromEnv, workspaceAppAudienceFromPackageJson, workspaceAppRouteAccessFromEnv, workspaceAppRouteAccessFromPackageJson, type WorkspaceAppRouteAccess, type WorkspaceAppRouteAccessFromConfig, type WorkspaceAppAudience, } from "./workspace-app-audience.js";
|
|
8
8
|
export { AGENT_NATIVE_OPEN_PATH, AGENT_SIDEBAR_QUERY_PARAM, AGENT_SIDEBAR_QUERY_VALUE_CLOSED, isAgentNativeOpenDeepLink, withCollapsedAgentSidebarParam, } from "./agent-sidebar-url.js";
|
|
9
|
+
export { EMBED_MODE_QUERY_PARAM, EMBED_SESSION_COOKIE, EMBED_START_PATH, EMBED_TOKEN_QUERY_PARAM, } from "./embed-auth.js";
|
|
9
10
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/shared/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,EACT,KAAK,gBAAgB,EACrB,KAAK,oBAAoB,EACzB,KAAK,iBAAiB,GACvB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,QAAQ,EAAE,KAAK,MAAM,EAAE,MAAM,gBAAgB,CAAC;AACvD,OAAO,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAC1D,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EACL,+BAA+B,EAC/B,sBAAsB,EACtB,KAAK,mBAAmB,GACzB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,iCAAiC,EACjC,0BAA0B,EAC1B,yBAAyB,EACzB,gCAAgC,EAChC,2BAA2B,GAC5B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,8BAA8B,EAC9B,uBAAuB,EACvB,6BAA6B,EAC7B,6BAA6B,EAC7B,2BAA2B,EAC3B,mCAAmC,EACnC,8BAA8B,EAC9B,sCAAsC,EACtC,KAAK,uBAAuB,EAC5B,KAAK,iCAAiC,EACtC,KAAK,oBAAoB,GAC1B,MAAM,6BAA6B,CAAC;AACrC,OAAO,EACL,sBAAsB,EACtB,yBAAyB,EACzB,gCAAgC,EAChC,yBAAyB,EACzB,8BAA8B,GAC/B,MAAM,wBAAwB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/shared/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,EACT,KAAK,gBAAgB,EACrB,KAAK,oBAAoB,EACzB,KAAK,iBAAiB,GACvB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,QAAQ,EAAE,KAAK,MAAM,EAAE,MAAM,gBAAgB,CAAC;AACvD,OAAO,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAC1D,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EACL,+BAA+B,EAC/B,sBAAsB,EACtB,KAAK,mBAAmB,GACzB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,iCAAiC,EACjC,0BAA0B,EAC1B,yBAAyB,EACzB,gCAAgC,EAChC,2BAA2B,GAC5B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,8BAA8B,EAC9B,uBAAuB,EACvB,6BAA6B,EAC7B,6BAA6B,EAC7B,2BAA2B,EAC3B,mCAAmC,EACnC,8BAA8B,EAC9B,sCAAsC,EACtC,KAAK,uBAAuB,EAC5B,KAAK,iCAAiC,EACtC,KAAK,oBAAoB,GAC1B,MAAM,6BAA6B,CAAC;AACrC,OAAO,EACL,sBAAsB,EACtB,yBAAyB,EACzB,gCAAgC,EAChC,yBAAyB,EACzB,8BAA8B,GAC/B,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,sBAAsB,EACtB,oBAAoB,EACpB,gBAAgB,EAChB,uBAAuB,GACxB,MAAM,iBAAiB,CAAC"}
|
package/dist/shared/index.js
CHANGED
|
@@ -6,4 +6,5 @@ export { llmConnectionTrackingProperties, normalizeLlmConnection, } from "./llm-
|
|
|
6
6
|
export { DISPATCH_WORKSPACE_ROOT_REDIRECTS, RESERVED_WORKSPACE_APP_IDS, assertValidWorkspaceAppId, getWorkspaceAppIdValidationError, isValidWorkspaceAppIdFormat, } from "./workspace-app-id.js";
|
|
7
7
|
export { DEFAULT_WORKSPACE_APP_AUDIENCE, WORKSPACE_APP_AUDIENCES, normalizeWorkspaceAppAudience, normalizeWorkspaceAppPathList, workspaceAppAudienceFromEnv, workspaceAppAudienceFromPackageJson, workspaceAppRouteAccessFromEnv, workspaceAppRouteAccessFromPackageJson, } from "./workspace-app-audience.js";
|
|
8
8
|
export { AGENT_NATIVE_OPEN_PATH, AGENT_SIDEBAR_QUERY_PARAM, AGENT_SIDEBAR_QUERY_VALUE_CLOSED, isAgentNativeOpenDeepLink, withCollapsedAgentSidebarParam, } from "./agent-sidebar-url.js";
|
|
9
|
+
export { EMBED_MODE_QUERY_PARAM, EMBED_SESSION_COOKIE, EMBED_START_PATH, EMBED_TOKEN_QUERY_PARAM, } from "./embed-auth.js";
|
|
9
10
|
//# sourceMappingURL=index.js.map
|
package/dist/shared/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/shared/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,GAIV,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,QAAQ,EAAe,MAAM,gBAAgB,CAAC;AACvD,OAAO,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAC1D,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EACL,+BAA+B,EAC/B,sBAAsB,GAEvB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,iCAAiC,EACjC,0BAA0B,EAC1B,yBAAyB,EACzB,gCAAgC,EAChC,2BAA2B,GAC5B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,8BAA8B,EAC9B,uBAAuB,EACvB,6BAA6B,EAC7B,6BAA6B,EAC7B,2BAA2B,EAC3B,mCAAmC,EACnC,8BAA8B,EAC9B,sCAAsC,GAIvC,MAAM,6BAA6B,CAAC;AACrC,OAAO,EACL,sBAAsB,EACtB,yBAAyB,EACzB,gCAAgC,EAChC,yBAAyB,EACzB,8BAA8B,GAC/B,MAAM,wBAAwB,CAAC","sourcesContent":["export {\n agentChat,\n type AgentChatMessage,\n type AgentChatCallOptions,\n type AgentChatResponse,\n} from \"./agent-chat.js\";\nexport { agentEnv, type EnvVar } from \"./agent-env.js\";\nexport { extractOAuthStateAppId } from \"./oauth-state.js\";\nexport { truncate } from \"./truncate.js\";\nexport {\n llmConnectionTrackingProperties,\n normalizeLlmConnection,\n type LlmConnectionStatus,\n} from \"./llm-connection.js\";\nexport {\n DISPATCH_WORKSPACE_ROOT_REDIRECTS,\n RESERVED_WORKSPACE_APP_IDS,\n assertValidWorkspaceAppId,\n getWorkspaceAppIdValidationError,\n isValidWorkspaceAppIdFormat,\n} from \"./workspace-app-id.js\";\nexport {\n DEFAULT_WORKSPACE_APP_AUDIENCE,\n WORKSPACE_APP_AUDIENCES,\n normalizeWorkspaceAppAudience,\n normalizeWorkspaceAppPathList,\n workspaceAppAudienceFromEnv,\n workspaceAppAudienceFromPackageJson,\n workspaceAppRouteAccessFromEnv,\n workspaceAppRouteAccessFromPackageJson,\n type WorkspaceAppRouteAccess,\n type WorkspaceAppRouteAccessFromConfig,\n type WorkspaceAppAudience,\n} from \"./workspace-app-audience.js\";\nexport {\n AGENT_NATIVE_OPEN_PATH,\n AGENT_SIDEBAR_QUERY_PARAM,\n AGENT_SIDEBAR_QUERY_VALUE_CLOSED,\n isAgentNativeOpenDeepLink,\n withCollapsedAgentSidebarParam,\n} from \"./agent-sidebar-url.js\";\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/shared/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,GAIV,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,QAAQ,EAAe,MAAM,gBAAgB,CAAC;AACvD,OAAO,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAC1D,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EACL,+BAA+B,EAC/B,sBAAsB,GAEvB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,iCAAiC,EACjC,0BAA0B,EAC1B,yBAAyB,EACzB,gCAAgC,EAChC,2BAA2B,GAC5B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,8BAA8B,EAC9B,uBAAuB,EACvB,6BAA6B,EAC7B,6BAA6B,EAC7B,2BAA2B,EAC3B,mCAAmC,EACnC,8BAA8B,EAC9B,sCAAsC,GAIvC,MAAM,6BAA6B,CAAC;AACrC,OAAO,EACL,sBAAsB,EACtB,yBAAyB,EACzB,gCAAgC,EAChC,yBAAyB,EACzB,8BAA8B,GAC/B,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,sBAAsB,EACtB,oBAAoB,EACpB,gBAAgB,EAChB,uBAAuB,GACxB,MAAM,iBAAiB,CAAC","sourcesContent":["export {\n agentChat,\n type AgentChatMessage,\n type AgentChatCallOptions,\n type AgentChatResponse,\n} from \"./agent-chat.js\";\nexport { agentEnv, type EnvVar } from \"./agent-env.js\";\nexport { extractOAuthStateAppId } from \"./oauth-state.js\";\nexport { truncate } from \"./truncate.js\";\nexport {\n llmConnectionTrackingProperties,\n normalizeLlmConnection,\n type LlmConnectionStatus,\n} from \"./llm-connection.js\";\nexport {\n DISPATCH_WORKSPACE_ROOT_REDIRECTS,\n RESERVED_WORKSPACE_APP_IDS,\n assertValidWorkspaceAppId,\n getWorkspaceAppIdValidationError,\n isValidWorkspaceAppIdFormat,\n} from \"./workspace-app-id.js\";\nexport {\n DEFAULT_WORKSPACE_APP_AUDIENCE,\n WORKSPACE_APP_AUDIENCES,\n normalizeWorkspaceAppAudience,\n normalizeWorkspaceAppPathList,\n workspaceAppAudienceFromEnv,\n workspaceAppAudienceFromPackageJson,\n workspaceAppRouteAccessFromEnv,\n workspaceAppRouteAccessFromPackageJson,\n type WorkspaceAppRouteAccess,\n type WorkspaceAppRouteAccessFromConfig,\n type WorkspaceAppAudience,\n} from \"./workspace-app-audience.js\";\nexport {\n AGENT_NATIVE_OPEN_PATH,\n AGENT_SIDEBAR_QUERY_PARAM,\n AGENT_SIDEBAR_QUERY_VALUE_CLOSED,\n isAgentNativeOpenDeepLink,\n withCollapsedAgentSidebarParam,\n} from \"./agent-sidebar-url.js\";\nexport {\n EMBED_MODE_QUERY_PARAM,\n EMBED_SESSION_COOKIE,\n EMBED_START_PATH,\n EMBED_TOKEN_QUERY_PARAM,\n} from \"./embed-auth.js\";\n"]}
|
|
@@ -55,11 +55,14 @@ available to every workspace app. Only create or request per-app vault grants
|
|
|
55
55
|
when Dispatch's vault access setting is switched to manual mode.
|
|
56
56
|
|
|
57
57
|
Workspace apps are discovered from `apps/<app-name>/package.json`. There is no
|
|
58
|
-
separate workspace app registry to edit for Dispatch to list the app.
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
58
|
+
separate workspace app registry to edit for Dispatch to list the app. Always
|
|
59
|
+
save a concise, human-readable `description` there; Dispatch lists and A2A
|
|
60
|
+
connected-agent context use the app name plus description so agents know what
|
|
61
|
+
the app does. Use relative workspace links like `/<app-name>` and never
|
|
62
|
+
hardcode `localhost`, `127.0.0.1`, `8080`, `8100`, or any dev port in app
|
|
63
|
+
cards, instructions, redirects, or navigation; the active workspace
|
|
64
|
+
gateway/browser origin owns the port. React Router apps must preserve
|
|
65
|
+
`APP_BASE_PATH` / `VITE_APP_BASE_PATH` in
|
|
63
66
|
`app/entry.client.tsx` via `appBasePath()` so the app hydrates correctly when
|
|
64
67
|
mounted at `/<app-name>`. Use the framework/template UI stack for standard UI:
|
|
65
68
|
shadcn/ui components and `@tabler/icons-react`. Do not add `lucide-react` or
|
|
@@ -80,3 +83,9 @@ workspace root. In production, Dispatch posts new-app requests to Builder
|
|
|
80
83
|
branch creation; Builder should still scaffold the separate workspace app. The
|
|
81
84
|
workspace dev gateway (`pnpm dev`) detects new `apps/<app-name>` directories
|
|
82
85
|
automatically.
|
|
86
|
+
|
|
87
|
+
When using the starter template, treat it as scaffolding only. The finished app
|
|
88
|
+
must be branded as the requested app, with its own home screen, navigation,
|
|
89
|
+
package metadata, manifest, and domain workflow. Do not leave visible
|
|
90
|
+
`Starter`, `Blank app`, `Start building`, or `New app` UI in a starter-derived
|
|
91
|
+
app.
|
|
@@ -108,6 +108,11 @@ coding agents can discover the same workspace-wide guidance from the root.
|
|
|
108
108
|
should still create the separate workspace app, not patch starter. The local
|
|
109
109
|
workspace gateway detects new app directories automatically and starts each
|
|
110
110
|
app server lazily on first visit.
|
|
111
|
+
- When using the starter template, treat it as scaffolding only. The finished
|
|
112
|
+
app must be branded as the requested app, with its own home screen,
|
|
113
|
+
navigation, package metadata, manifest, and domain workflow. Do not leave
|
|
114
|
+
visible `Starter`, `Blank app`, `Start building`, or `New app` UI in a
|
|
115
|
+
starter-derived app.
|
|
111
116
|
|
|
112
117
|
## Workspace Identity
|
|
113
118
|
|
|
@@ -106,6 +106,9 @@ pnpm exec agent-native create crm --template=starter
|
|
|
106
106
|
The CLI detects the workspace root and scaffolds a minimal app that already
|
|
107
107
|
depends on `@{{APP_NAME}}/shared`. Edit only the routes you care about;
|
|
108
108
|
auth, org switching, skills, and instructions come from the shared package.
|
|
109
|
+
Starter is only the source scaffold: the finished app should use its own name,
|
|
110
|
+
home screen, navigation, package metadata, and manifest rather than leaving
|
|
111
|
+
starter or new-app UI in place.
|
|
109
112
|
If the request starts from Dispatch in production, Dispatch sends it to Builder
|
|
110
113
|
branch creation; that branch should still add a new `apps/<app-id>` workspace
|
|
111
114
|
app rather than adding files to `apps/starter`.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"action-types-plugin.d.ts","sourceRoot":"","sources":["../../src/vite/action-types-plugin.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"action-types-plugin.d.ts","sourceRoot":"","sources":["../../src/vite/action-types-plugin.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAwSnC;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAuC1C;AAED;;;GAGG;AACH,wBAAgB,gCAAgC,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAG1E"}
|
|
@@ -55,6 +55,15 @@ const CORE_SHARING_ACTIONS = [
|
|
|
55
55
|
specifier: "@agent-native/core/file-upload/actions/upload-image",
|
|
56
56
|
},
|
|
57
57
|
];
|
|
58
|
+
function isRuntimeSourceFile(filename) {
|
|
59
|
+
if (!/\.(ts|js)$/.test(filename))
|
|
60
|
+
return false;
|
|
61
|
+
if (/\.d\.ts$/.test(filename))
|
|
62
|
+
return false;
|
|
63
|
+
if (/\.(test|spec)\.(ts|js)$/.test(filename))
|
|
64
|
+
return false;
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
58
67
|
function scanActionFiles(actionsDir) {
|
|
59
68
|
let files;
|
|
60
69
|
try {
|
|
@@ -64,7 +73,7 @@ function scanActionFiles(actionsDir) {
|
|
|
64
73
|
return [];
|
|
65
74
|
}
|
|
66
75
|
return files.filter((f) => {
|
|
67
|
-
if (!
|
|
76
|
+
if (!isRuntimeSourceFile(f))
|
|
68
77
|
return false;
|
|
69
78
|
const name = f.replace(/\.(ts|js)$/, "");
|
|
70
79
|
if (name.startsWith("_"))
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"action-types-plugin.js","sourceRoot":"","sources":["../../src/vite/action-types-plugin.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Vite plugin that generates end-to-end type-safe action types AND a runtime\n * registry of static imports so bundlers (Nitro on Netlify/Vercel/AWS-Lambda,\n * Rolldown, etc.) include every action file in the server bundle.\n *\n * Watches the `actions/` directory and emits:\n * - `.generated/action-types.d.ts` — type-only module that augments the\n * `ActionRegistry` interface in `@agent-native/core/client`, giving\n * `useActionQuery`/`useActionMutation` full inference.\n * - `.generated/actions-registry.ts` — runtime registry keyed by action\n * name, with static `import` statements for every action. Templates\n * import this file from their `server/plugins/agent-chat.ts` so Nitro\n * bundles the actions into the server function; without it the runtime\n * `fs.readdirSync` inside `autoDiscoverActions` finds nothing in a\n * bundled serverless function and every action route 404s.\n */\nimport path from \"path\";\nimport fs from \"fs\";\nimport type { Plugin } from \"vite\";\n\n/** Files to skip during discovery (matches action-discovery.ts). */\nconst SKIP_FILES = new Set([\n \"helpers\",\n \"run\",\n \"db-connect\",\n \"db-status\",\n \"registry\",\n]);\n\n/**\n * Framework-level sharing actions that must ALWAYS be in the generated\n * registry, even when the template's `actions/` directory doesn't contain\n * them. Each entry maps the action name to the bare-specifier import path so\n * bundlers see a static import and pull the module into the server bundle.\n *\n * Order matters: templates can override by defining a same-named file in\n * their own `actions/` directory — the merge below is skip-existing.\n */\nconst CORE_SHARING_ACTIONS: Array<{ name: string; specifier: string }> = [\n {\n name: \"share-resource\",\n specifier: \"@agent-native/core/sharing/actions/share-resource\",\n },\n {\n name: \"unshare-resource\",\n specifier: \"@agent-native/core/sharing/actions/unshare-resource\",\n },\n {\n name: \"list-resource-shares\",\n specifier: \"@agent-native/core/sharing/actions/list-resource-shares\",\n },\n {\n name: \"set-resource-visibility\",\n specifier: \"@agent-native/core/sharing/actions/set-resource-visibility\",\n },\n {\n name: \"upload-image\",\n specifier: \"@agent-native/core/file-upload/actions/upload-image\",\n },\n];\n\nfunction scanActionFiles(actionsDir: string): string[] {\n let files: string[];\n try {\n files = fs.readdirSync(actionsDir);\n } catch {\n return [];\n }\n return files.filter((f) => {\n if (!f.endsWith(\".ts\") && !f.endsWith(\".js\")) return false;\n const name = f.replace(/\\.(ts|js)$/, \"\");\n if (name.startsWith(\"_\")) return false;\n if (SKIP_FILES.has(name)) return false;\n // Only include files that actually call defineAction or explicitly\n // re-export a package action. CLI scripts or example templates that live\n // in actions/ but don't export an action would otherwise drag their own\n // (often app/, browser-only, or fs-only) imports into the serverless\n // bundle and fail to resolve.\n try {\n const content = fs.readFileSync(path.join(actionsDir, f), \"utf-8\");\n const reexportsDefaultAction =\n /export\\s*\\{\\s*default\\s*\\}\\s*from\\s*[\"'][^\"']+[\"']/.test(content);\n if (!content.includes(\"defineAction\") && !reexportsDefaultAction) {\n return false;\n }\n } catch {\n return false;\n }\n return true;\n });\n}\n\nfunction toIdent(name: string): string {\n return \"a_\" + name.replace(/[^a-zA-Z0-9_]/g, \"_\");\n}\n\nfunction writeIfChanged(outFile: string, content: string): void {\n const existing = fs.existsSync(outFile)\n ? fs.readFileSync(outFile, \"utf-8\")\n : \"\";\n if (existing !== content) {\n fs.mkdirSync(path.dirname(outFile), { recursive: true });\n fs.writeFileSync(outFile, content);\n }\n}\n\nfunction findWorkspaceCoreActionsDir(projectRoot: string): string | null {\n let dir = path.resolve(projectRoot);\n let workspaceRoot: string | null = null;\n let packageName: string | null = null;\n\n for (let i = 0; i < 20; i++) {\n const pkgPath = path.join(dir, \"package.json\");\n if (fs.existsSync(pkgPath)) {\n try {\n const pkg = JSON.parse(fs.readFileSync(pkgPath, \"utf-8\"));\n const declared = pkg?.[\"agent-native\"]?.workspaceCore;\n if (typeof declared === \"string\" && declared.length > 0) {\n workspaceRoot = dir;\n packageName = declared;\n break;\n }\n } catch {\n // Keep walking on malformed package.json.\n }\n }\n const parent = path.dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n\n if (!workspaceRoot || !packageName) return null;\n\n const nm = path.join(workspaceRoot, \"node_modules\", packageName);\n if (fs.existsSync(path.join(nm, \"package.json\"))) {\n const actionsDir = path.join(fs.realpathSync(nm), \"actions\");\n return fs.existsSync(actionsDir) ? actionsDir : null;\n }\n\n const packagesDir = path.join(workspaceRoot, \"packages\");\n const candidates: string[] = [];\n if (fs.existsSync(packagesDir)) {\n for (const entry of fs.readdirSync(packagesDir, { withFileTypes: true })) {\n if (!entry.isDirectory()) continue;\n candidates.push(path.join(packagesDir, entry.name));\n if (entry.name.startsWith(\"@\")) {\n const scopeDir = path.join(packagesDir, entry.name);\n for (const sub of fs.readdirSync(scopeDir, { withFileTypes: true })) {\n if (sub.isDirectory()) candidates.push(path.join(scopeDir, sub.name));\n }\n }\n }\n }\n\n for (const candidate of candidates) {\n const pkgPath = path.join(candidate, \"package.json\");\n if (!fs.existsSync(pkgPath)) continue;\n try {\n const pkg = JSON.parse(fs.readFileSync(pkgPath, \"utf-8\"));\n if (pkg?.name === packageName) {\n const actionsDir = path.join(candidate, \"actions\");\n return fs.existsSync(actionsDir) ? actionsDir : null;\n }\n } catch {\n // Ignore malformed package.json.\n }\n }\n\n return null;\n}\n\n/**\n * Scan the actions directory and emit the types + runtime registry files.\n * Only writes files whose content has changed, to avoid triggering rebuilds.\n */\nfunction generateActionArtifacts(\n actionsDir: string,\n projectRoot: string,\n): void {\n const outDir = path.resolve(projectRoot, \".generated\");\n const relActionsDir = path.relative(outDir, actionsDir).replace(/\\\\/g, \"/\");\n\n const actionFiles = scanActionFiles(actionsDir);\n const workspaceActionsDir = findWorkspaceCoreActionsDir(projectRoot);\n const workspaceActionFiles = workspaceActionsDir\n ? scanActionFiles(workspaceActionsDir)\n : [];\n\n // Pre-compute template action names — used for skip-existing logic in both\n // the type declarations and the runtime registry below.\n const templateActionNames = new Set<string>(\n actionFiles.map((f) => f.replace(/\\.(ts|js)$/, \"\")),\n );\n const registeredActionNames = new Set(templateActionNames);\n\n const actionSources = actionFiles.map((f) => {\n const name = f.replace(/\\.(ts|js)$/, \"\");\n return {\n name,\n relPath: `${relActionsDir}/${name}`,\n };\n });\n\n if (workspaceActionsDir) {\n for (const f of workspaceActionFiles) {\n const name = f.replace(/\\.(ts|js)$/, \"\");\n if (registeredActionNames.has(name)) continue;\n const relPath = path\n .relative(outDir, path.join(workspaceActionsDir, name))\n .replace(/\\\\/g, \"/\");\n actionSources.push({ name, relPath });\n registeredActionNames.add(name);\n }\n }\n\n // --- types file ---------------------------------------------------------\n const typeEntries = actionSources.map(({ name, relPath }) => {\n return ` \"${name}\": ActionEntry<typeof import(\"${relPath}\")>;`;\n });\n\n // Also declare types for framework-level sharing actions so callers don't\n // need `as any` casts (same skip-existing logic as the runtime registry).\n for (const entry of CORE_SHARING_ACTIONS) {\n if (registeredActionNames.has(entry.name)) continue;\n typeEntries.push(\n ` \"${entry.name}\": ActionEntry<typeof import(\"${entry.specifier}\")>;`,\n );\n registeredActionNames.add(entry.name);\n }\n\n const typesContent = `// AUTO-GENERATED by @agent-native/core — do not edit manually.\n// Regenerated when files in actions/ change.\n// This file augments the ActionRegistry interface so that useActionQuery and\n// useActionMutation infer the correct types from your action definitions.\n\n/** Extract the return type and parameter type from a defineAction module. */\ntype ActionEntry<T> = T extends { default: { run: (...args: infer A) => infer R } }\n ? {\n result: Awaited<R>;\n params: A extends [infer P, ...any[]] ? P : Record<string, any>;\n }\n : { result: any; params: Record<string, any> };\n\ndeclare module \"@agent-native/core/client\" {\n interface ActionRegistry {\n${typeEntries.join(\"\\n\")}\n }\n}\n\nexport {};\n`;\n\n writeIfChanged(path.join(outDir, \"action-types.d.ts\"), typesContent);\n\n // --- runtime registry ---------------------------------------------------\n // Static imports of each action's default export so bundlers see every\n // action and include it in the server bundle. Normalization matches\n // `loadActionsIntoRegistry` in server/action-discovery.ts.\n const imports: string[] = [];\n const entries: string[] = [];\n const runtimeActionNames = new Set<string>();\n for (const { name, relPath } of actionSources) {\n const ident = toIdent(name);\n imports.push(`import * as ${ident} from \"${relPath}\";`);\n entries.push(` ${JSON.stringify(name)}: ${ident},`);\n runtimeActionNames.add(name);\n }\n // Framework-level sharing actions — only added when the template hasn't\n // provided a same-named file (skip-existing merge). Static imports ensure\n // bundlers pull these modules into the server bundle so\n // `/_agent-native/actions/share-resource` (etc.) always resolve.\n for (const entry of CORE_SHARING_ACTIONS) {\n if (runtimeActionNames.has(entry.name)) continue;\n const ident = toIdent(entry.name);\n imports.push(`import * as ${ident} from \"${entry.specifier}\";`);\n entries.push(` ${JSON.stringify(entry.name)}: ${ident},`);\n runtimeActionNames.add(entry.name);\n }\n\n const registryContent = `// AUTO-GENERATED by @agent-native/core — do not edit manually.\n// Static-import registry of every action file. Bundlers (Nitro, Rolldown)\n// see these imports and include the action modules in the server bundle.\n// The agent-chat plugin normalizes each module into an ActionEntry shape.\n${imports.join(\"\\n\")}\n\nconst modules: Record<string, unknown> = {\n${entries.join(\"\\n\")}\n};\n\nexport default modules;\n`;\n\n // Always write the registry — even when the template has no actions/ files\n // we still emit imports for the framework-level sharing actions so they get\n // mounted on every template that consumes the registry.\n writeIfChanged(path.join(outDir, \"actions-registry.ts\"), registryContent);\n\n // Ensure .generated/ is in .gitignore\n const gitignorePath = path.join(projectRoot, \".gitignore\");\n if (fs.existsSync(gitignorePath)) {\n const gitignore = fs.readFileSync(gitignorePath, \"utf-8\");\n if (!gitignore.includes(\".generated\")) {\n fs.appendFileSync(gitignorePath, \"\\n.generated/\\n\");\n }\n }\n}\n\n/**\n * Vite plugin that watches `actions/` and generates type-safe action types.\n *\n * Add to your Vite config (auto-included by `defineConfig` from `@agent-native/core`):\n *\n * ```ts\n * import { actionTypesPlugin } from \"@agent-native/core/vite/action-types-plugin\";\n * plugins: [actionTypesPlugin()]\n * ```\n */\nexport function actionTypesPlugin(): Plugin {\n let projectRoot = \"\";\n let actionsDir = \"\";\n let workspaceActionsDir: string | null = null;\n\n return {\n name: \"agent-native-action-types\",\n configResolved(config) {\n projectRoot = config.root;\n actionsDir = path.resolve(projectRoot, \"actions\");\n workspaceActionsDir = findWorkspaceCoreActionsDir(projectRoot);\n },\n buildStart() {\n generateActionArtifacts(actionsDir, projectRoot);\n },\n configureServer(server) {\n // Generate on startup\n generateActionArtifacts(actionsDir, projectRoot);\n\n // Watch for changes in actions/\n const watcher = server.watcher;\n const handleChange = (file: string) => {\n const inAppActions = file.startsWith(actionsDir);\n const inWorkspaceActions = workspaceActionsDir\n ? file.startsWith(workspaceActionsDir)\n : false;\n if ((inAppActions || inWorkspaceActions) && /\\.(ts|js)$/.test(file)) {\n generateActionArtifacts(actionsDir, projectRoot);\n }\n };\n watcher.add(actionsDir);\n if (workspaceActionsDir) watcher.add(workspaceActionsDir);\n watcher.on(\"add\", handleChange);\n watcher.on(\"unlink\", handleChange);\n // Don't regenerate on content changes — only file additions/removals\n // affect the registry. Return type changes are picked up by TypeScript\n // from the source files via typeof import().\n },\n };\n}\n\n/**\n * Public helper to regenerate the types + registry from a non-Vite context\n * (e.g. the Nitro deploy build, where Vite plugins don't run).\n */\nexport function generateActionRegistryForProject(projectRoot: string): void {\n const actionsDir = path.resolve(projectRoot, \"actions\");\n generateActionArtifacts(actionsDir, projectRoot);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"action-types-plugin.js","sourceRoot":"","sources":["../../src/vite/action-types-plugin.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Vite plugin that generates end-to-end type-safe action types AND a runtime\n * registry of static imports so bundlers (Nitro on Netlify/Vercel/AWS-Lambda,\n * Rolldown, etc.) include every action file in the server bundle.\n *\n * Watches the `actions/` directory and emits:\n * - `.generated/action-types.d.ts` — type-only module that augments the\n * `ActionRegistry` interface in `@agent-native/core/client`, giving\n * `useActionQuery`/`useActionMutation` full inference.\n * - `.generated/actions-registry.ts` — runtime registry keyed by action\n * name, with static `import` statements for every action. Templates\n * import this file from their `server/plugins/agent-chat.ts` so Nitro\n * bundles the actions into the server function; without it the runtime\n * `fs.readdirSync` inside `autoDiscoverActions` finds nothing in a\n * bundled serverless function and every action route 404s.\n */\nimport path from \"path\";\nimport fs from \"fs\";\nimport type { Plugin } from \"vite\";\n\n/** Files to skip during discovery (matches action-discovery.ts). */\nconst SKIP_FILES = new Set([\n \"helpers\",\n \"run\",\n \"db-connect\",\n \"db-status\",\n \"registry\",\n]);\n\n/**\n * Framework-level sharing actions that must ALWAYS be in the generated\n * registry, even when the template's `actions/` directory doesn't contain\n * them. Each entry maps the action name to the bare-specifier import path so\n * bundlers see a static import and pull the module into the server bundle.\n *\n * Order matters: templates can override by defining a same-named file in\n * their own `actions/` directory — the merge below is skip-existing.\n */\nconst CORE_SHARING_ACTIONS: Array<{ name: string; specifier: string }> = [\n {\n name: \"share-resource\",\n specifier: \"@agent-native/core/sharing/actions/share-resource\",\n },\n {\n name: \"unshare-resource\",\n specifier: \"@agent-native/core/sharing/actions/unshare-resource\",\n },\n {\n name: \"list-resource-shares\",\n specifier: \"@agent-native/core/sharing/actions/list-resource-shares\",\n },\n {\n name: \"set-resource-visibility\",\n specifier: \"@agent-native/core/sharing/actions/set-resource-visibility\",\n },\n {\n name: \"upload-image\",\n specifier: \"@agent-native/core/file-upload/actions/upload-image\",\n },\n];\n\nfunction isRuntimeSourceFile(filename: string): boolean {\n if (!/\\.(ts|js)$/.test(filename)) return false;\n if (/\\.d\\.ts$/.test(filename)) return false;\n if (/\\.(test|spec)\\.(ts|js)$/.test(filename)) return false;\n return true;\n}\n\nfunction scanActionFiles(actionsDir: string): string[] {\n let files: string[];\n try {\n files = fs.readdirSync(actionsDir);\n } catch {\n return [];\n }\n return files.filter((f) => {\n if (!isRuntimeSourceFile(f)) return false;\n const name = f.replace(/\\.(ts|js)$/, \"\");\n if (name.startsWith(\"_\")) return false;\n if (SKIP_FILES.has(name)) return false;\n // Only include files that actually call defineAction or explicitly\n // re-export a package action. CLI scripts or example templates that live\n // in actions/ but don't export an action would otherwise drag their own\n // (often app/, browser-only, or fs-only) imports into the serverless\n // bundle and fail to resolve.\n try {\n const content = fs.readFileSync(path.join(actionsDir, f), \"utf-8\");\n const reexportsDefaultAction =\n /export\\s*\\{\\s*default\\s*\\}\\s*from\\s*[\"'][^\"']+[\"']/.test(content);\n if (!content.includes(\"defineAction\") && !reexportsDefaultAction) {\n return false;\n }\n } catch {\n return false;\n }\n return true;\n });\n}\n\nfunction toIdent(name: string): string {\n return \"a_\" + name.replace(/[^a-zA-Z0-9_]/g, \"_\");\n}\n\nfunction writeIfChanged(outFile: string, content: string): void {\n const existing = fs.existsSync(outFile)\n ? fs.readFileSync(outFile, \"utf-8\")\n : \"\";\n if (existing !== content) {\n fs.mkdirSync(path.dirname(outFile), { recursive: true });\n fs.writeFileSync(outFile, content);\n }\n}\n\nfunction findWorkspaceCoreActionsDir(projectRoot: string): string | null {\n let dir = path.resolve(projectRoot);\n let workspaceRoot: string | null = null;\n let packageName: string | null = null;\n\n for (let i = 0; i < 20; i++) {\n const pkgPath = path.join(dir, \"package.json\");\n if (fs.existsSync(pkgPath)) {\n try {\n const pkg = JSON.parse(fs.readFileSync(pkgPath, \"utf-8\"));\n const declared = pkg?.[\"agent-native\"]?.workspaceCore;\n if (typeof declared === \"string\" && declared.length > 0) {\n workspaceRoot = dir;\n packageName = declared;\n break;\n }\n } catch {\n // Keep walking on malformed package.json.\n }\n }\n const parent = path.dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n\n if (!workspaceRoot || !packageName) return null;\n\n const nm = path.join(workspaceRoot, \"node_modules\", packageName);\n if (fs.existsSync(path.join(nm, \"package.json\"))) {\n const actionsDir = path.join(fs.realpathSync(nm), \"actions\");\n return fs.existsSync(actionsDir) ? actionsDir : null;\n }\n\n const packagesDir = path.join(workspaceRoot, \"packages\");\n const candidates: string[] = [];\n if (fs.existsSync(packagesDir)) {\n for (const entry of fs.readdirSync(packagesDir, { withFileTypes: true })) {\n if (!entry.isDirectory()) continue;\n candidates.push(path.join(packagesDir, entry.name));\n if (entry.name.startsWith(\"@\")) {\n const scopeDir = path.join(packagesDir, entry.name);\n for (const sub of fs.readdirSync(scopeDir, { withFileTypes: true })) {\n if (sub.isDirectory()) candidates.push(path.join(scopeDir, sub.name));\n }\n }\n }\n }\n\n for (const candidate of candidates) {\n const pkgPath = path.join(candidate, \"package.json\");\n if (!fs.existsSync(pkgPath)) continue;\n try {\n const pkg = JSON.parse(fs.readFileSync(pkgPath, \"utf-8\"));\n if (pkg?.name === packageName) {\n const actionsDir = path.join(candidate, \"actions\");\n return fs.existsSync(actionsDir) ? actionsDir : null;\n }\n } catch {\n // Ignore malformed package.json.\n }\n }\n\n return null;\n}\n\n/**\n * Scan the actions directory and emit the types + runtime registry files.\n * Only writes files whose content has changed, to avoid triggering rebuilds.\n */\nfunction generateActionArtifacts(\n actionsDir: string,\n projectRoot: string,\n): void {\n const outDir = path.resolve(projectRoot, \".generated\");\n const relActionsDir = path.relative(outDir, actionsDir).replace(/\\\\/g, \"/\");\n\n const actionFiles = scanActionFiles(actionsDir);\n const workspaceActionsDir = findWorkspaceCoreActionsDir(projectRoot);\n const workspaceActionFiles = workspaceActionsDir\n ? scanActionFiles(workspaceActionsDir)\n : [];\n\n // Pre-compute template action names — used for skip-existing logic in both\n // the type declarations and the runtime registry below.\n const templateActionNames = new Set<string>(\n actionFiles.map((f) => f.replace(/\\.(ts|js)$/, \"\")),\n );\n const registeredActionNames = new Set(templateActionNames);\n\n const actionSources = actionFiles.map((f) => {\n const name = f.replace(/\\.(ts|js)$/, \"\");\n return {\n name,\n relPath: `${relActionsDir}/${name}`,\n };\n });\n\n if (workspaceActionsDir) {\n for (const f of workspaceActionFiles) {\n const name = f.replace(/\\.(ts|js)$/, \"\");\n if (registeredActionNames.has(name)) continue;\n const relPath = path\n .relative(outDir, path.join(workspaceActionsDir, name))\n .replace(/\\\\/g, \"/\");\n actionSources.push({ name, relPath });\n registeredActionNames.add(name);\n }\n }\n\n // --- types file ---------------------------------------------------------\n const typeEntries = actionSources.map(({ name, relPath }) => {\n return ` \"${name}\": ActionEntry<typeof import(\"${relPath}\")>;`;\n });\n\n // Also declare types for framework-level sharing actions so callers don't\n // need `as any` casts (same skip-existing logic as the runtime registry).\n for (const entry of CORE_SHARING_ACTIONS) {\n if (registeredActionNames.has(entry.name)) continue;\n typeEntries.push(\n ` \"${entry.name}\": ActionEntry<typeof import(\"${entry.specifier}\")>;`,\n );\n registeredActionNames.add(entry.name);\n }\n\n const typesContent = `// AUTO-GENERATED by @agent-native/core — do not edit manually.\n// Regenerated when files in actions/ change.\n// This file augments the ActionRegistry interface so that useActionQuery and\n// useActionMutation infer the correct types from your action definitions.\n\n/** Extract the return type and parameter type from a defineAction module. */\ntype ActionEntry<T> = T extends { default: { run: (...args: infer A) => infer R } }\n ? {\n result: Awaited<R>;\n params: A extends [infer P, ...any[]] ? P : Record<string, any>;\n }\n : { result: any; params: Record<string, any> };\n\ndeclare module \"@agent-native/core/client\" {\n interface ActionRegistry {\n${typeEntries.join(\"\\n\")}\n }\n}\n\nexport {};\n`;\n\n writeIfChanged(path.join(outDir, \"action-types.d.ts\"), typesContent);\n\n // --- runtime registry ---------------------------------------------------\n // Static imports of each action's default export so bundlers see every\n // action and include it in the server bundle. Normalization matches\n // `loadActionsIntoRegistry` in server/action-discovery.ts.\n const imports: string[] = [];\n const entries: string[] = [];\n const runtimeActionNames = new Set<string>();\n for (const { name, relPath } of actionSources) {\n const ident = toIdent(name);\n imports.push(`import * as ${ident} from \"${relPath}\";`);\n entries.push(` ${JSON.stringify(name)}: ${ident},`);\n runtimeActionNames.add(name);\n }\n // Framework-level sharing actions — only added when the template hasn't\n // provided a same-named file (skip-existing merge). Static imports ensure\n // bundlers pull these modules into the server bundle so\n // `/_agent-native/actions/share-resource` (etc.) always resolve.\n for (const entry of CORE_SHARING_ACTIONS) {\n if (runtimeActionNames.has(entry.name)) continue;\n const ident = toIdent(entry.name);\n imports.push(`import * as ${ident} from \"${entry.specifier}\";`);\n entries.push(` ${JSON.stringify(entry.name)}: ${ident},`);\n runtimeActionNames.add(entry.name);\n }\n\n const registryContent = `// AUTO-GENERATED by @agent-native/core — do not edit manually.\n// Static-import registry of every action file. Bundlers (Nitro, Rolldown)\n// see these imports and include the action modules in the server bundle.\n// The agent-chat plugin normalizes each module into an ActionEntry shape.\n${imports.join(\"\\n\")}\n\nconst modules: Record<string, unknown> = {\n${entries.join(\"\\n\")}\n};\n\nexport default modules;\n`;\n\n // Always write the registry — even when the template has no actions/ files\n // we still emit imports for the framework-level sharing actions so they get\n // mounted on every template that consumes the registry.\n writeIfChanged(path.join(outDir, \"actions-registry.ts\"), registryContent);\n\n // Ensure .generated/ is in .gitignore\n const gitignorePath = path.join(projectRoot, \".gitignore\");\n if (fs.existsSync(gitignorePath)) {\n const gitignore = fs.readFileSync(gitignorePath, \"utf-8\");\n if (!gitignore.includes(\".generated\")) {\n fs.appendFileSync(gitignorePath, \"\\n.generated/\\n\");\n }\n }\n}\n\n/**\n * Vite plugin that watches `actions/` and generates type-safe action types.\n *\n * Add to your Vite config (auto-included by `defineConfig` from `@agent-native/core`):\n *\n * ```ts\n * import { actionTypesPlugin } from \"@agent-native/core/vite/action-types-plugin\";\n * plugins: [actionTypesPlugin()]\n * ```\n */\nexport function actionTypesPlugin(): Plugin {\n let projectRoot = \"\";\n let actionsDir = \"\";\n let workspaceActionsDir: string | null = null;\n\n return {\n name: \"agent-native-action-types\",\n configResolved(config) {\n projectRoot = config.root;\n actionsDir = path.resolve(projectRoot, \"actions\");\n workspaceActionsDir = findWorkspaceCoreActionsDir(projectRoot);\n },\n buildStart() {\n generateActionArtifacts(actionsDir, projectRoot);\n },\n configureServer(server) {\n // Generate on startup\n generateActionArtifacts(actionsDir, projectRoot);\n\n // Watch for changes in actions/\n const watcher = server.watcher;\n const handleChange = (file: string) => {\n const inAppActions = file.startsWith(actionsDir);\n const inWorkspaceActions = workspaceActionsDir\n ? file.startsWith(workspaceActionsDir)\n : false;\n if ((inAppActions || inWorkspaceActions) && /\\.(ts|js)$/.test(file)) {\n generateActionArtifacts(actionsDir, projectRoot);\n }\n };\n watcher.add(actionsDir);\n if (workspaceActionsDir) watcher.add(workspaceActionsDir);\n watcher.on(\"add\", handleChange);\n watcher.on(\"unlink\", handleChange);\n // Don't regenerate on content changes — only file additions/removals\n // affect the registry. Return type changes are picked up by TypeScript\n // from the source files via typeof import().\n },\n };\n}\n\n/**\n * Public helper to regenerate the types + registry from a non-Vite context\n * (e.g. the Nitro deploy build, where Vite plugins don't run).\n */\nexport function generateActionRegistryForProject(projectRoot: string): void {\n const actionsDir = path.resolve(projectRoot, \"actions\");\n generateActionArtifacts(actionsDir, projectRoot);\n}\n"]}
|
|
@@ -29,7 +29,7 @@ Most templates get A2A through the framework agent chat plugin. If you are mount
|
|
|
29
29
|
import { mountA2A } from "@agent-native/core/a2a";
|
|
30
30
|
|
|
31
31
|
export default defineNitroPlugin((nitro) => {
|
|
32
|
-
mountA2A(nitro
|
|
32
|
+
mountA2A(nitro, {
|
|
33
33
|
name: "Analytics Agent",
|
|
34
34
|
description: "Runs analytics queries and returns chart data",
|
|
35
35
|
skills: [
|
|
@@ -106,6 +106,10 @@ All methods are called via `POST /_agent-native/a2a` with JSON-RPC 2.0 format:
|
|
|
106
106
|
|
|
107
107
|
When `message/send` is called with `async: true`, the JSON-RPC handler enqueues the task and self-fires a POST to an internal `/_agent-native/a2a/_process-task` route so the handler runs in a fresh function execution with its own full timeout. This route is authenticated with an HMAC token bound to the task ID (5-minute lifetime, signed with `A2A_SECRET`). It is mounted before the `/_agent-native/a2a` JSON-RPC route so h3's prefix matching does not swallow it.
|
|
108
108
|
|
|
109
|
+
> [!IMPORTANT]
|
|
110
|
+
> **Serverless Webhook & Gateway Timeouts:**
|
|
111
|
+
> Hosted environment gateways (such as Netlify, Vercel, or Cloudflare Pages) impose strict execution limits (often 10 to 30 seconds) on public-facing HTTP routes. Because agent loops can take significant time to run queries, fetch context, and execute tools, you **must use `async: true`** when calling A2A endpoints or handling external webhooks. This immediately returns a `working` status to the API gateway, keeping the connection open only for a few milliseconds, while the self-fired `/process-task` POST executes the agent loop in the background. Do not block the primary HTTP request waiting for the agent loop to finish.
|
|
112
|
+
|
|
109
113
|
Messages contain typed parts:
|
|
110
114
|
|
|
111
115
|
```json
|
package/docs/content/actions.md
CHANGED
|
@@ -112,7 +112,7 @@ For actions that change state:
|
|
|
112
112
|
```tsx
|
|
113
113
|
import { useActionMutation } from "@agent-native/core/client";
|
|
114
114
|
|
|
115
|
-
const { mutate, isPending } = useActionMutation("
|
|
115
|
+
const { mutate, isPending } = useActionMutation("reply-to-email");
|
|
116
116
|
|
|
117
117
|
<Button
|
|
118
118
|
disabled={isPending}
|
|
@@ -131,17 +131,17 @@ For read-only GET actions:
|
|
|
131
131
|
```ts
|
|
132
132
|
import { useActionQuery } from "@agent-native/core/client";
|
|
133
133
|
|
|
134
|
-
const { data, isLoading } = useActionQuery("
|
|
134
|
+
const { data, isLoading } = useActionQuery("get-lead", { leadId });
|
|
135
135
|
```
|
|
136
136
|
|
|
137
|
-
The query is cached under `["action", "
|
|
137
|
+
The query is cached under `["action", "get-lead", { leadId }]` and auto-invalidated on any mutating action that completes.
|
|
138
138
|
|
|
139
139
|
## Calling it from the CLI {#cli}
|
|
140
140
|
|
|
141
141
|
Every action is runnable via `pnpm action`:
|
|
142
142
|
|
|
143
143
|
```bash
|
|
144
|
-
pnpm action
|
|
144
|
+
pnpm action reply-to-email --emailId thread-123 --body "Thanks!"
|
|
145
145
|
```
|
|
146
146
|
|
|
147
147
|
Flags are parsed into the shape your schema expects. Useful for agent-dev loops, scripts, and cron.
|
|
@@ -177,6 +177,21 @@ export default defineAction({
|
|
|
177
177
|
|
|
178
178
|
This advertises the MCP Apps extension (`io.modelcontextprotocol/ui`), exposes the HTML via MCP resources, and includes both current and legacy UI resource metadata for compatible hosts. Keep `link` as the fallback for CLI and non-UI MCP clients; see [External Agents](/docs/external-agents#mcp-apps).
|
|
179
179
|
|
|
180
|
+
When the best inline UI is the existing app itself, use the framework helper instead of hand-writing a duplicate HTML surface:
|
|
181
|
+
|
|
182
|
+
```ts
|
|
183
|
+
import { embedApp } from "@agent-native/core/mcp";
|
|
184
|
+
|
|
185
|
+
export default defineAction({
|
|
186
|
+
// ...description, schema, run, link...
|
|
187
|
+
mcpApp: {
|
|
188
|
+
resource: embedApp({ title: "Open dashboard" }),
|
|
189
|
+
},
|
|
190
|
+
});
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
The helper launches the action's `link` target through `/_agent-native/embed/start` with a short-lived browser session, so routes such as dashboards, filtered inboxes, drafts, and extension pages can reuse the app's React components directly.
|
|
194
|
+
|
|
180
195
|
## Standard actions {#standard-actions}
|
|
181
196
|
|
|
182
197
|
Every template should include these two for [context awareness](/docs/context-awareness):
|
|
@@ -165,6 +165,11 @@ export class DockerAdapter implements CliAdapter {
|
|
|
165
165
|
}
|
|
166
166
|
```
|
|
167
167
|
|
|
168
|
+
> [!WARNING]
|
|
169
|
+
> **Edge and Serverless Compatibility:**
|
|
170
|
+
> CLI adapters (both `ShellCliAdapter` and custom adapters using `node:child_process`) rely on Node.js-specific system bindings (`child_process.execFile` or `child_process.spawn`).
|
|
171
|
+
> These APIs **do not exist** on edge/worker runtimes (e.g., Cloudflare Workers, Netlify Edge Functions). If you deploy your server routes to these edge presets, executing CLI adapters will throw runtime exceptions. Always ensure CLI adapter endpoints and tasks run in standard Node.js environments (like traditional server containers or serverless Node functions).
|
|
172
|
+
|
|
168
173
|
## Server route {#server-route}
|
|
169
174
|
|
|
170
175
|
Expose the registry to the UI via an API route so actions and components can discover and invoke CLIs:
|
package/docs/content/client.md
CHANGED
|
@@ -176,7 +176,41 @@ function App() {
|
|
|
176
176
|
| `ignoreSource` | `string?` | Per-tab request source to ignore so a tab does not refetch from its own writes |
|
|
177
177
|
| `onEvent` | `(data) => void` | Optional callback when SSE/polling receives a change event |
|
|
178
178
|
|
|
179
|
-
For normal CRUD, prefer `useActionQuery` and `useActionMutation`; mutating actions emit `source: "action"` and those hooks refetch automatically.
|
|
179
|
+
For normal CRUD, prefer `useActionQuery` and `useActionMutation`; mutating actions emit `source: "action"` and those hooks refetch automatically.
|
|
180
|
+
|
|
181
|
+
## useChangeVersion / useChangeVersions {#use-change-version}
|
|
182
|
+
|
|
183
|
+
The framework uses change versions to sync React Query caches with changes made by background agents, cron jobs, or other users.
|
|
184
|
+
|
|
185
|
+
When any server-side database mutation occurs, the server records a change event with a specific `source` key. The client's `useDbSync` listener receives these events and bumps the local change version counter for that source. By folding the version counter into your React Query keys, queries automatically refetch whenever the backend notifies the client of new activity.
|
|
186
|
+
|
|
187
|
+
- **`useChangeVersion(source: string): number`** — returns a counter that increments whenever the specified `source` is mutated.
|
|
188
|
+
- **`useChangeVersions(sources: readonly string[]): number`** — returns the sum of version counters for multiple sources.
|
|
189
|
+
|
|
190
|
+
### Example: Syncing a raw query with the database
|
|
191
|
+
|
|
192
|
+
```tsx
|
|
193
|
+
import { useQuery } from "@tanstack/react-query";
|
|
194
|
+
import { useChangeVersion } from "@agent-native/core/client";
|
|
195
|
+
|
|
196
|
+
function DashboardView({ id }) {
|
|
197
|
+
// Get version for dashboards domain source
|
|
198
|
+
const v = useChangeVersion("dashboards");
|
|
199
|
+
|
|
200
|
+
const { data } = useQuery({
|
|
201
|
+
queryKey: ["dashboard", id, v], // Invalidate automatically when version bumps
|
|
202
|
+
queryFn: () => fetchDashboard(id),
|
|
203
|
+
placeholderData: (prev) => prev, // Prevent layout flicker during refetch
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
return <div>{data?.title}</div>;
|
|
207
|
+
}
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### Latency Models & Invalidation Behavior
|
|
211
|
+
|
|
212
|
+
- **UI-Initiated mutations:** When you execute an action from the UI using `useActionMutation`, the mutation immediately fires a local event with `source: "action"` on success. This triggers an **instant, optimistic refetch** of all query keys depending on that action, avoiding visual delay.
|
|
213
|
+
- **Background or Agent Mutations:** When the AI agent, a webhook, or a background worker mutates data, the update is broadcast to the client. The client's `useDbSync` captures this either instantly over SSE (Server-Sent Events) or falls back to the **2-second polling tick**. The query key version then bumps, triggering a background refetch.
|
|
180
214
|
|
|
181
215
|
## cn(...inputs) {#cn}
|
|
182
216
|
|