@agent-native/core 0.11.1 → 0.11.2
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/thread-data-builder.d.ts +1 -0
- package/dist/agent/thread-data-builder.d.ts.map +1 -1
- package/dist/agent/thread-data-builder.js +1 -0
- package/dist/agent/thread-data-builder.js.map +1 -1
- package/dist/client/AgentPanel.js +2 -2
- package/dist/client/AgentPanel.js.map +1 -1
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +71 -6
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/components/ui/dropdown-menu.js +2 -2
- package/dist/client/components/ui/dropdown-menu.js.map +1 -1
- package/dist/client/resources/ResourcesPanel.d.ts.map +1 -1
- package/dist/client/resources/ResourcesPanel.js +6 -6
- package/dist/client/resources/ResourcesPanel.js.map +1 -1
- package/dist/client/settings/useBuilderStatus.d.ts.map +1 -1
- package/dist/client/settings/useBuilderStatus.js +6 -2
- package/dist/client/settings/useBuilderStatus.js.map +1 -1
- package/dist/client/sharing/ShareButton.d.ts +2 -0
- package/dist/client/sharing/ShareButton.d.ts.map +1 -1
- package/dist/client/sharing/ShareButton.js +26 -3
- package/dist/client/sharing/ShareButton.js.map +1 -1
- package/dist/server/agent-chat-plugin.d.ts +14 -0
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +77 -12
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/builder-browser.d.ts +8 -6
- package/dist/server/builder-browser.d.ts.map +1 -1
- package/dist/server/builder-browser.js +54 -32
- package/dist/server/builder-browser.js.map +1 -1
- package/dist/server/core-routes-plugin.d.ts +7 -0
- package/dist/server/core-routes-plugin.d.ts.map +1 -1
- package/dist/server/core-routes-plugin.js +100 -74
- package/dist/server/core-routes-plugin.js.map +1 -1
- package/package.json +1 -1
|
@@ -9,6 +9,7 @@ export declare const BUILDER_CALLBACK_PATH = "/_agent-native/builder/callback";
|
|
|
9
9
|
* connect time and read it back on the callback.
|
|
10
10
|
*/
|
|
11
11
|
export declare const BUILDER_STATE_PARAM = "_an_state";
|
|
12
|
+
export declare const BUILDER_CONNECT_PARAM = "_an_connect";
|
|
12
13
|
export interface BuilderBrowserStatus {
|
|
13
14
|
configured: boolean;
|
|
14
15
|
builderEnabled: boolean;
|
|
@@ -55,6 +56,9 @@ export declare function signBuilderCallbackState(sessionEmail: string): string;
|
|
|
55
56
|
* false on any malformed, forged, expired, or cross-session token.
|
|
56
57
|
*/
|
|
57
58
|
export declare function verifyBuilderCallbackState(token: string | null | undefined, sessionEmail: string): boolean;
|
|
59
|
+
export declare function signBuilderConnectToken(ownerEmail: string): string;
|
|
60
|
+
export declare function verifyBuilderConnectToken(token: string | null | undefined, ownerEmail: string): boolean;
|
|
61
|
+
export declare function appendBuilderConnectToken(connectUrl: string, ownerEmail: string): string;
|
|
58
62
|
export declare function getBuilderAppHost(): string;
|
|
59
63
|
export declare function getBuilderApiHost(): string;
|
|
60
64
|
export declare function getBuilderBranchProjectId(): string;
|
|
@@ -74,12 +78,10 @@ export declare function isBuilderBranchingEnabled(): boolean;
|
|
|
74
78
|
*/
|
|
75
79
|
export declare function buildBuilderCliAuthUrl(origin: string, state?: string | null): string;
|
|
76
80
|
/**
|
|
77
|
-
* The URL surfaced to clients
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
* into a status response that may be cached or rendered for a different
|
|
82
|
-
* session.
|
|
81
|
+
* The bare URL surfaced to clients as `connectUrl`. The status route appends
|
|
82
|
+
* a short-lived signed connect token when it knows the current owner; this
|
|
83
|
+
* helper stays bare so server-rendered cards can still render without a
|
|
84
|
+
* request-bound owner and the connect route can fall back to Fetch Metadata.
|
|
83
85
|
*/
|
|
84
86
|
export declare function getBuilderBrowserConnectUrl(origin: string): string;
|
|
85
87
|
export declare function getBuilderBrowserStatus(origin: string): BuilderBrowserStatus;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"builder-browser.d.ts","sourceRoot":"","sources":["../../src/server/builder-browser.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AASlC,eAAO,MAAM,qBAAqB,oCAAoC,CAAC;AAEvE;;;;;;;GAOG;AACH,eAAO,MAAM,mBAAmB,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"builder-browser.d.ts","sourceRoot":"","sources":["../../src/server/builder-browser.ts"],"names":[],"mappings":"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"}
|
|
@@ -15,35 +15,28 @@ export const BUILDER_CALLBACK_PATH = "/_agent-native/builder/callback";
|
|
|
15
15
|
* connect time and read it back on the callback.
|
|
16
16
|
*/
|
|
17
17
|
export const BUILDER_STATE_PARAM = "_an_state";
|
|
18
|
+
export const BUILDER_CONNECT_PARAM = "_an_connect";
|
|
18
19
|
const BUILDER_STATE_TTL_MS = 10 * 60 * 1000;
|
|
19
|
-
function
|
|
20
|
-
|
|
20
|
+
function signingKeyForPurpose(purpose) {
|
|
21
|
+
// Preserve the original callback-state signing key for any in-flight legacy
|
|
22
|
+
// callbacks; use a separate key domain for connect-entry tokens.
|
|
23
|
+
return purpose === "callback"
|
|
24
|
+
? `builder-csrf:${getAuthSecret()}`
|
|
25
|
+
: `builder-connect:${getAuthSecret()}`;
|
|
26
|
+
}
|
|
27
|
+
function macForParts(purpose, nonce, emailEncoded, ts) {
|
|
28
|
+
return createHmac("sha256", signingKeyForPurpose(purpose))
|
|
21
29
|
.update(`${nonce}.${emailEncoded}.${ts}`)
|
|
22
30
|
.digest("base64url");
|
|
23
31
|
}
|
|
24
|
-
|
|
25
|
-
* Mint a signed CSRF state token bound to the current session's email
|
|
26
|
-
* and a fresh nonce. Round-trips through Builder's cli-auth flow inside
|
|
27
|
-
* the redirect_url query string and is verified on the callback before
|
|
28
|
-
* any keys are written.
|
|
29
|
-
*
|
|
30
|
-
* Why bind to email: it's the only stable, universally-available
|
|
31
|
-
* identity field across all auth modes (Better Auth, BYOA, AUTH_MODE=local).
|
|
32
|
-
* Binding to the session token instead would put the cookie value in a
|
|
33
|
-
* URL that may end up in server logs / browser history.
|
|
34
|
-
*/
|
|
35
|
-
export function signBuilderCallbackState(sessionEmail) {
|
|
32
|
+
function signEmailBoundBuilderToken(ownerEmail, purpose) {
|
|
36
33
|
const nonce = randomBytes(16).toString("base64url");
|
|
37
34
|
const ts = Date.now();
|
|
38
|
-
const emailEncoded = Buffer.from(
|
|
39
|
-
const mac = macForParts(nonce, emailEncoded, ts);
|
|
35
|
+
const emailEncoded = Buffer.from(ownerEmail, "utf8").toString("base64url");
|
|
36
|
+
const mac = macForParts(purpose, nonce, emailEncoded, ts);
|
|
40
37
|
return `${nonce}.${emailEncoded}.${ts}.${mac}`;
|
|
41
38
|
}
|
|
42
|
-
|
|
43
|
-
* Verify a state token produced by `signBuilderCallbackState`. Returns
|
|
44
|
-
* false on any malformed, forged, expired, or cross-session token.
|
|
45
|
-
*/
|
|
46
|
-
export function verifyBuilderCallbackState(token, sessionEmail) {
|
|
39
|
+
function verifyEmailBoundBuilderToken(token, ownerEmail, purpose) {
|
|
47
40
|
if (typeof token !== "string" || token.length === 0)
|
|
48
41
|
return false;
|
|
49
42
|
const parts = token.split(".");
|
|
@@ -59,22 +52,53 @@ export function verifyBuilderCallbackState(token, sessionEmail) {
|
|
|
59
52
|
catch {
|
|
60
53
|
return false;
|
|
61
54
|
}
|
|
62
|
-
if (boundEmail !==
|
|
55
|
+
if (boundEmail !== ownerEmail)
|
|
63
56
|
return false;
|
|
64
57
|
const ts = Number(tsStr);
|
|
65
58
|
if (!Number.isFinite(ts))
|
|
66
59
|
return false;
|
|
67
|
-
// Reject expired AND far-future timestamps
|
|
68
|
-
//
|
|
69
|
-
// an arbitrarily-long-lived token.
|
|
60
|
+
// Reject expired AND far-future timestamps so leaked tokens do not gain an
|
|
61
|
+
// arbitrary lifetime through clock skew or forged future issue times.
|
|
70
62
|
if (Math.abs(Date.now() - ts) > BUILDER_STATE_TTL_MS)
|
|
71
63
|
return false;
|
|
72
|
-
const expected = Buffer.from(macForParts(nonce, emailEncoded, ts));
|
|
64
|
+
const expected = Buffer.from(macForParts(purpose, nonce, emailEncoded, ts));
|
|
73
65
|
const candidate = Buffer.from(mac);
|
|
74
66
|
if (expected.length !== candidate.length)
|
|
75
67
|
return false;
|
|
76
68
|
return timingSafeEqual(expected, candidate);
|
|
77
69
|
}
|
|
70
|
+
/**
|
|
71
|
+
* Mint a signed CSRF state token bound to the current session's email
|
|
72
|
+
* and a fresh nonce. Round-trips through Builder's cli-auth flow inside
|
|
73
|
+
* the redirect_url query string and is verified on the callback before
|
|
74
|
+
* any keys are written.
|
|
75
|
+
*
|
|
76
|
+
* Why bind to email: it's the only stable, universally-available
|
|
77
|
+
* identity field across all auth modes (Better Auth, BYOA, AUTH_MODE=local).
|
|
78
|
+
* Binding to the session token instead would put the cookie value in a
|
|
79
|
+
* URL that may end up in server logs / browser history.
|
|
80
|
+
*/
|
|
81
|
+
export function signBuilderCallbackState(sessionEmail) {
|
|
82
|
+
return signEmailBoundBuilderToken(sessionEmail, "callback");
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Verify a state token produced by `signBuilderCallbackState`. Returns
|
|
86
|
+
* false on any malformed, forged, expired, or cross-session token.
|
|
87
|
+
*/
|
|
88
|
+
export function verifyBuilderCallbackState(token, sessionEmail) {
|
|
89
|
+
return verifyEmailBoundBuilderToken(token, sessionEmail, "callback");
|
|
90
|
+
}
|
|
91
|
+
export function signBuilderConnectToken(ownerEmail) {
|
|
92
|
+
return signEmailBoundBuilderToken(ownerEmail, "connect");
|
|
93
|
+
}
|
|
94
|
+
export function verifyBuilderConnectToken(token, ownerEmail) {
|
|
95
|
+
return verifyEmailBoundBuilderToken(token, ownerEmail, "connect");
|
|
96
|
+
}
|
|
97
|
+
export function appendBuilderConnectToken(connectUrl, ownerEmail) {
|
|
98
|
+
const url = new URL(connectUrl);
|
|
99
|
+
url.searchParams.set(BUILDER_CONNECT_PARAM, signBuilderConnectToken(ownerEmail));
|
|
100
|
+
return url.toString();
|
|
101
|
+
}
|
|
78
102
|
function isAllowedBrowserReturnUrl(urlString) {
|
|
79
103
|
try {
|
|
80
104
|
const parsed = new URL(urlString);
|
|
@@ -148,12 +172,10 @@ export function buildBuilderCliAuthUrl(origin, state = null) {
|
|
|
148
172
|
return url.toString();
|
|
149
173
|
}
|
|
150
174
|
/**
|
|
151
|
-
* The URL surfaced to clients
|
|
152
|
-
*
|
|
153
|
-
*
|
|
154
|
-
*
|
|
155
|
-
* into a status response that may be cached or rendered for a different
|
|
156
|
-
* session.
|
|
175
|
+
* The bare URL surfaced to clients as `connectUrl`. The status route appends
|
|
176
|
+
* a short-lived signed connect token when it knows the current owner; this
|
|
177
|
+
* helper stays bare so server-rendered cards can still render without a
|
|
178
|
+
* request-bound owner and the connect route can fall back to Fetch Metadata.
|
|
157
179
|
*/
|
|
158
180
|
export function getBuilderBrowserConnectUrl(origin) {
|
|
159
181
|
return `${normalizeOrigin(origin)}${getAppBasePath()}/_agent-native/builder/connect`;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"builder-browser.js","sourceRoot":"","sources":["../../src/server/builder-browser.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHmac, randomBytes, timingSafeEqual } from \"node:crypto\";\nimport type { H3Event } from \"h3\";\nimport { getAuthSecret } from \"./better-auth-instance.js\";\nimport { getAppBasePath, getOrigin } from \"./google-oauth.js\";\n\nconst DEFAULT_BUILDER_APP_HOST = \"https://builder.io\";\nconst DEFAULT_BUILDER_API_HOST = \"https://api.builder.io\";\nconst BUILDER_BROWSER_HOST = \"agent-native-browser\";\nconst BUILDER_BROWSER_CLIENT_ID = \"Agent Native Browser\";\n\nexport const BUILDER_CALLBACK_PATH = \"/_agent-native/builder/callback\";\n\n/**\n * Query-param name carrying the signed CSRF state on the connect→callback\n * round-trip. Prefixed with `_an_` to avoid collisions if Builder ever\n * adds standard OAuth `state` support to cli-auth. Builder preserves\n * the path/query of `redirect_url` verbatim when redirecting back, so\n * we embed `_an_state=…` inside the redirect_url query string at\n * connect time and read it back on the callback.\n */\nexport const BUILDER_STATE_PARAM = \"_an_state\";\n\nconst BUILDER_STATE_TTL_MS = 10 * 60 * 1000;\n\nexport interface BuilderBrowserStatus {\n configured: boolean;\n builderEnabled: boolean;\n branchProjectIdConfigured: boolean;\n branchProjectId?: string;\n /**\n * True when `BUILDER_PRIVATE_KEY` is set at the deployment level. Every\n * user of this deploy shares the operator's Builder identity; the UI\n * must hide the per-user connect/disconnect flow and show a read-only\n * \"managed by deployment\" state instead.\n */\n envManaged: boolean;\n appHost: string;\n apiHost: string;\n connectUrl: string;\n publicKeyConfigured: boolean;\n privateKeyConfigured: boolean;\n userId?: string;\n orgName?: string;\n orgKind?: string;\n}\n\nexport interface BrowserConnectionArgs {\n sessionId?: string;\n projectId?: string;\n branchName?: string;\n proxyOrigin?: string;\n proxyDefaultOrigin?: string;\n proxyDestination?: string;\n}\n\nfunction macForParts(nonce: string, emailEncoded: string, ts: number): string {\n return createHmac(\"sha256\", `builder-csrf:${getAuthSecret()}`)\n .update(`${nonce}.${emailEncoded}.${ts}`)\n .digest(\"base64url\");\n}\n\n/**\n * Mint a signed CSRF state token bound to the current session's email\n * and a fresh nonce. Round-trips through Builder's cli-auth flow inside\n * the redirect_url query string and is verified on the callback before\n * any keys are written.\n *\n * Why bind to email: it's the only stable, universally-available\n * identity field across all auth modes (Better Auth, BYOA, AUTH_MODE=local).\n * Binding to the session token instead would put the cookie value in a\n * URL that may end up in server logs / browser history.\n */\nexport function signBuilderCallbackState(sessionEmail: string): string {\n const nonce = randomBytes(16).toString(\"base64url\");\n const ts = Date.now();\n const emailEncoded = Buffer.from(sessionEmail, \"utf8\").toString(\"base64url\");\n const mac = macForParts(nonce, emailEncoded, ts);\n return `${nonce}.${emailEncoded}.${ts}.${mac}`;\n}\n\n/**\n * Verify a state token produced by `signBuilderCallbackState`. Returns\n * false on any malformed, forged, expired, or cross-session token.\n */\nexport function verifyBuilderCallbackState(\n token: string | null | undefined,\n sessionEmail: string,\n): boolean {\n if (typeof token !== \"string\" || token.length === 0) return false;\n const parts = token.split(\".\");\n if (parts.length !== 4) return false;\n const [nonce, emailEncoded, tsStr, mac] = parts;\n if (!nonce || !emailEncoded || !tsStr || !mac) return false;\n\n let boundEmail: string;\n try {\n boundEmail = Buffer.from(emailEncoded, \"base64url\").toString(\"utf8\");\n } catch {\n return false;\n }\n if (boundEmail !== sessionEmail) return false;\n\n const ts = Number(tsStr);\n if (!Number.isFinite(ts)) return false;\n // Reject expired AND far-future timestamps — a clock-skew attacker\n // (or a bug that mints states with `ts` in the future) shouldn't get\n // an arbitrarily-long-lived token.\n if (Math.abs(Date.now() - ts) > BUILDER_STATE_TTL_MS) return false;\n\n const expected = Buffer.from(macForParts(nonce, emailEncoded, ts));\n const candidate = Buffer.from(mac);\n if (expected.length !== candidate.length) return false;\n return timingSafeEqual(expected, candidate);\n}\n\nfunction isAllowedBrowserReturnUrl(urlString: string): boolean {\n try {\n const parsed = new URL(urlString);\n const hostname = parsed.hostname.toLowerCase();\n const isAllowedProtocol =\n parsed.protocol === \"http:\" || parsed.protocol === \"https:\";\n const isLocalhost =\n hostname === \"localhost\" ||\n hostname === \"127.0.0.1\" ||\n hostname === \"[::1]\";\n const isBuilderDomain =\n hostname === \"builder.io\" || hostname.endsWith(\".builder.io\");\n const isAgentNativeDomain =\n hostname === \"agent-native.com\" || hostname.endsWith(\".agent-native.com\");\n return (\n isAllowedProtocol &&\n (isLocalhost || isBuilderDomain || isAgentNativeDomain)\n );\n } catch {\n return false;\n }\n}\n\nfunction normalizeOrigin(origin: string): string {\n return origin.replace(/\\/+$/, \"\");\n}\n\nexport function getBuilderAppHost(): string {\n return (\n process.env.BUILDER_APP_HOST ||\n process.env.BUILDER_PUBLIC_APP_HOST ||\n DEFAULT_BUILDER_APP_HOST\n );\n}\n\nexport function getBuilderApiHost(): string {\n return (\n process.env.AIR_HOST ||\n process.env.BUILDER_HOST ||\n process.env.BUILDER_API_HOST ||\n DEFAULT_BUILDER_API_HOST\n );\n}\n\nfunction getConfiguredBuilderBranchProjectId(): string | undefined {\n const projectId =\n process.env.DISPATCH_BUILDER_PROJECT_ID ||\n process.env.BUILDER_BRANCH_PROJECT_ID ||\n process.env.BUILDER_PROJECT_ID;\n return projectId?.trim() || undefined;\n}\n\nexport function getBuilderBranchProjectId(): string {\n return getConfiguredBuilderBranchProjectId() || \"\";\n}\n\nexport function isBuilderBranchingEnabled(): boolean {\n return !!getConfiguredBuilderBranchProjectId();\n}\n\n/**\n * Build the Builder cli-auth URL for the connect popup. When a signed\n * `state` token is supplied it is embedded inside the `redirect_url`\n * query string so it survives Builder's redirect verbatim — Builder\n * preserves the redirect_url's existing query when appending p-key /\n * api-key / etc., so we don't depend on Builder echoing a top-level\n * `state` parameter (it doesn't).\n *\n * The user-facing connect entry point is `/_agent-native/builder/connect`\n * (a server-side 302). Status / chat-card responses surface that path\n * rather than the cli-auth URL directly, so the 302 handler can mint a\n * fresh state bound to the current session on every click.\n */\nexport function buildBuilderCliAuthUrl(\n origin: string,\n state: string | null = null,\n): string {\n const normalizedOrigin = normalizeOrigin(origin);\n const appBasePath = getAppBasePath();\n const callbackUrl = new URL(\n `${appBasePath}${BUILDER_CALLBACK_PATH}`,\n normalizedOrigin,\n );\n if (state) {\n callbackUrl.searchParams.set(BUILDER_STATE_PARAM, state);\n }\n const url = new URL(\"/cli-auth\", getBuilderAppHost());\n url.searchParams.set(\"response_type\", \"code\");\n url.searchParams.set(\"host\", BUILDER_BROWSER_HOST);\n url.searchParams.set(\"client_id\", BUILDER_BROWSER_CLIENT_ID);\n url.searchParams.set(\"redirect_url\", callbackUrl.toString());\n url.searchParams.set(\"preview_url\", `${normalizedOrigin}${appBasePath}`);\n url.searchParams.set(\"framework\", \"agent-native\");\n return url.toString();\n}\n\n/**\n * The URL surfaced to clients (chat card, settings panels, status\n * endpoint) as `connectUrl`. Pointing every entry point at our local 302\n * means the cli-auth URL — and the CSRF state token bound to the current\n * session — are minted server-side at click time, instead of being baked\n * into a status response that may be cached or rendered for a different\n * session.\n */\nexport function getBuilderBrowserConnectUrl(origin: string): string {\n return `${normalizeOrigin(origin)}${getAppBasePath()}/_agent-native/builder/connect`;\n}\n\nexport function getBuilderBrowserStatus(origin: string): BuilderBrowserStatus {\n const branchProjectId = getConfiguredBuilderBranchProjectId();\n const envManaged = !!process.env.BUILDER_PRIVATE_KEY;\n return {\n configured: !!(\n process.env.BUILDER_PRIVATE_KEY && process.env.BUILDER_PUBLIC_KEY\n ),\n builderEnabled: isBuilderBranchingEnabled(),\n branchProjectIdConfigured: !!branchProjectId,\n branchProjectId: branchProjectId || undefined,\n envManaged,\n appHost: getBuilderAppHost(),\n apiHost: getBuilderApiHost(),\n connectUrl: getBuilderBrowserConnectUrl(origin),\n publicKeyConfigured: !!process.env.BUILDER_PUBLIC_KEY,\n privateKeyConfigured: !!process.env.BUILDER_PRIVATE_KEY,\n userId: process.env.BUILDER_USER_ID || undefined,\n orgName: process.env.BUILDER_ORG_NAME || undefined,\n orgKind: process.env.BUILDER_ORG_KIND || undefined,\n };\n}\n\nexport function getBuilderBrowserStatusForEvent(\n event: H3Event,\n): BuilderBrowserStatus {\n return getBuilderBrowserStatus(getOrigin(event));\n}\n\n/**\n * Env vars written by the Builder CLI-auth callback. Single source of truth\n * for the connect/disconnect key set — `getBuilderCallbackEnvVars` and the\n * disconnect handler's scrub loop both derive from this list, so drift\n * (e.g. disconnect silently leaving `BUILDER_USER_ID` behind because\n * someone added a key to one site but not the other) is impossible.\n */\nexport const BUILDER_ENV_KEYS = [\n \"BUILDER_PRIVATE_KEY\",\n \"BUILDER_PUBLIC_KEY\",\n \"BUILDER_USER_ID\",\n \"BUILDER_ORG_NAME\",\n \"BUILDER_ORG_KIND\",\n] as const;\n\nexport type BuilderEnvKey = (typeof BUILDER_ENV_KEYS)[number];\n\nexport function getBuilderCallbackEnvVars(params: {\n privateKey?: string | null;\n publicKey?: string | null;\n userId?: string | null;\n orgName?: string | null;\n orgKind?: string | null;\n}) {\n const values: Record<BuilderEnvKey, string> = {\n BUILDER_PRIVATE_KEY: params.privateKey?.trim() || \"\",\n BUILDER_PUBLIC_KEY: params.publicKey?.trim() || \"\",\n BUILDER_USER_ID: params.userId?.trim() || \"\",\n BUILDER_ORG_NAME: params.orgName?.trim() || \"\",\n BUILDER_ORG_KIND: params.orgKind?.trim() || \"\",\n };\n return BUILDER_ENV_KEYS.map((key) => ({ key, value: values[key] }));\n}\n\nexport function resolveSafePreviewUrl(\n previewUrl: string | null | undefined,\n event: H3Event,\n): string {\n if (previewUrl && isAllowedBrowserReturnUrl(previewUrl)) {\n return previewUrl;\n }\n return getOrigin(event);\n}\n\n/**\n * Inline theme-detection script that runs before the body paints. Reads the\n * app's stored theme preference (same `localStorage.theme` key used by the\n * client-side theme manager) and falls back to `prefers-color-scheme`. This\n * way the popup matches whatever theme the user already picked in the app\n * — light, dark, or auto — instead of always rendering in OS-default mode.\n */\nconst BUILDER_CALLBACK_THEME_SCRIPT = `<script>\n(function () {\n try {\n var stored = window.localStorage && window.localStorage.getItem(\"theme\");\n var resolved;\n if (stored === \"light\" || stored === \"dark\") {\n resolved = stored;\n } else {\n var mq = window.matchMedia && window.matchMedia(\"(prefers-color-scheme: dark)\");\n resolved = mq && mq.matches ? \"dark\" : \"light\";\n }\n document.documentElement.classList.add(resolved);\n document.documentElement.style.colorScheme = resolved;\n } catch (e) {}\n})();\n</script>`;\n\n/**\n * Brand-aligned CSS for the Builder connect callback / error pages.\n *\n * Uses the same neutral-zinc palette and Inter font as the rest of the\n * framework's templates (see `templates/*\\/app/global.css`). Tokens map to\n * the same HSL values the templates set on `:root` / `.dark`, so the popup\n * reads as part of the same app — not a stranded marketing page.\n */\nconst BUILDER_CALLBACK_BASE_CSS = `\n :root {\n --bg: hsl(0 0% 100%);\n --fg: hsl(220 10% 10%);\n --muted-fg: hsl(220 5% 45%);\n --card: hsl(0 0% 100%);\n --border: hsl(220 10% 90%);\n --primary: hsl(220 10% 15%);\n --primary-fg: hsl(0 0% 100%);\n --primary-hover: hsl(220 10% 25%);\n --success-bg: hsl(143 50% 96%);\n --success-fg: hsl(143 60% 32%);\n --error-fg: hsl(0 75% 45%);\n --error-bg: hsl(0 80% 97%);\n --error-border: hsl(0 80% 92%);\n }\n :root.dark {\n --bg: hsl(220 6% 6%);\n --fg: hsl(0 0% 92%);\n --muted-fg: hsl(220 4% 60%);\n --card: hsl(220 5% 8%);\n --border: hsl(220 4% 14%);\n --primary: hsl(0 0% 92%);\n --primary-fg: hsl(220 6% 6%);\n --primary-hover: hsl(0 0% 75%);\n --success-bg: hsl(143 30% 12%);\n --success-fg: hsl(143 50% 70%);\n --error-fg: hsl(0 80% 75%);\n --error-bg: hsl(0 35% 12%);\n --error-border: hsl(0 30% 20%);\n }\n *, *::before, *::after { box-sizing: border-box; }\n html, body { height: 100%; }\n body {\n margin: 0;\n min-height: 100vh;\n display: grid;\n place-items: center;\n background: var(--bg);\n color: var(--fg);\n font-family: \"Inter\", ui-sans-serif, system-ui, -apple-system, \"Segoe UI\", \"Helvetica Neue\", Arial, sans-serif;\n font-size: 14px;\n line-height: 1.55;\n font-feature-settings: \"cv02\", \"cv03\", \"cv04\", \"cv11\";\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n padding: 24px;\n }\n .card {\n width: min(420px, 100%);\n border: 1px solid var(--border);\n border-radius: 12px;\n padding: 32px 28px;\n background: var(--card);\n text-align: center;\n }\n .icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 44px;\n height: 44px;\n border-radius: 999px;\n margin-bottom: 16px;\n }\n .icon svg { width: 22px; height: 22px; display: block; }\n .icon-success { background: var(--success-bg); color: var(--success-fg); }\n .icon-error { background: var(--error-bg); color: var(--error-fg); }\n h1 {\n margin: 0 0 6px;\n font-size: 17px;\n font-weight: 600;\n letter-spacing: -0.01em;\n color: var(--fg);\n }\n p {\n margin: 0 0 4px;\n color: var(--fg);\n font-size: 14px;\n }\n p.muted { color: var(--muted-fg); }\n .btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n height: 36px;\n padding: 0 16px;\n margin-top: 20px;\n background: var(--primary);\n color: var(--primary-fg);\n border-radius: 8px;\n font-size: 13px;\n font-weight: 500;\n text-decoration: none;\n border: none;\n cursor: pointer;\n }\n .btn:hover { background: var(--primary-hover); }\n pre.error-detail {\n margin: 16px 0 0;\n padding: 10px 12px;\n background: var(--error-bg);\n border: 1px solid var(--error-border);\n border-radius: 8px;\n color: var(--error-fg);\n font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;\n font-size: 12px;\n line-height: 1.5;\n text-align: left;\n white-space: pre-wrap;\n word-break: break-word;\n }\n`;\n\nexport function createBuilderBrowserCallbackPage(previewUrl: string): string {\n const escapedUrl = JSON.stringify(previewUrl);\n return `<!doctype html>\n<html lang=\"en\">\n <head>\n <meta charset=\"utf-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no\" />\n <title>Builder connected</title>\n <link rel=\"preconnect\" href=\"https://fonts.googleapis.com\" />\n <link rel=\"preconnect\" href=\"https://fonts.gstatic.com\" crossorigin />\n <link href=\"https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap\" rel=\"stylesheet\" />\n ${BUILDER_CALLBACK_THEME_SCRIPT}\n <style>${BUILDER_CALLBACK_BASE_CSS}</style>\n </head>\n <body>\n <main class=\"card\" role=\"status\" aria-live=\"polite\">\n <span class=\"icon icon-success\" aria-hidden=\"true\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"></polyline></svg>\n </span>\n <h1>Builder connected</h1>\n <p>Browser access is now available to your app.</p>\n <p class=\"muted\">You can close this tab and return to the workspace.</p>\n <a class=\"btn\" href=${escapedUrl}>Open the workspace</a>\n </main>\n <script>\n // If we're a popup opened by the app, close ourselves and let the\n // parent tab keep polling for connection status. If close() is\n // blocked (e.g. we're the top-level tab because popups were\n // downgraded), fall back to navigating back to the workspace.\n window.setTimeout(function () {\n try { window.close(); } catch (e) {}\n window.setTimeout(function () {\n if (!window.closed) {\n window.location.replace(${escapedUrl});\n }\n }, 200);\n }, 700);\n </script>\n </body>\n</html>`;\n}\n\n/**\n * HTML page rendered inside the OAuth popup when the callback handler caught\n * an error persisting the per-user Builder credentials. Without this, the\n * popup would show the success page even though the write failed — leaving\n * the parent window stuck on \"Waiting for Builder…\" until the 5-minute poll\n * timeout fires (Midhun reported this on 2026-04-28).\n *\n * The page does two things:\n * 1. Shows the user a clear \"couldn't save credentials\" message with the\n * underlying error so they can retry or report.\n * 2. `postMessage`s the parent (same-origin opener) so the connect-flow\n * polling stops immediately rather than waiting for the next /status\n * poll to surface the SQL `builder-connect-error:<email>` row.\n */\nexport function createBuilderBrowserCallbackErrorPage(message: string): string {\n const escapedMessage = JSON.stringify(message);\n return `<!doctype html>\n<html lang=\"en\">\n <head>\n <meta charset=\"utf-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no\" />\n <title>Builder connect failed</title>\n <link rel=\"preconnect\" href=\"https://fonts.googleapis.com\" />\n <link rel=\"preconnect\" href=\"https://fonts.gstatic.com\" crossorigin />\n <link href=\"https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap\" rel=\"stylesheet\" />\n ${BUILDER_CALLBACK_THEME_SCRIPT}\n <style>${BUILDER_CALLBACK_BASE_CSS}</style>\n </head>\n <body>\n <main class=\"card\" role=\"alert\" aria-live=\"assertive\">\n <span class=\"icon icon-error\" aria-hidden=\"true\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0Z\"></path><line x1=\"12\" y1=\"9\" x2=\"12\" y2=\"13\"></line><line x1=\"12\" y1=\"17\" x2=\"12.01\" y2=\"17\"></line></svg>\n </span>\n <h1>Couldn't save Builder connection</h1>\n <p class=\"muted\">Builder authorized your account but the server couldn't persist the credentials.</p>\n <pre class=\"error-detail\" id=\"msg\"></pre>\n <p class=\"muted\" style=\"margin-top:12px\">You can close this tab and try again from settings.</p>\n </main>\n <script>\n try {\n var msg = ${escapedMessage};\n document.getElementById(\"msg\").textContent = msg;\n // Notify the parent tab immediately so its polling loop stops\n // without waiting for the next /builder/status tick.\n //\n // BroadcastChannel works across same-origin windows regardless of\n // opener access — it is the only reliable channel here because\n // popups opened with window.open(..., \"noopener\") or links with\n // rel=\"noopener\" have window.opener === null. The legacy\n // window.opener.postMessage path is kept as a belt-and-suspenders\n // fallback for non-BroadcastChannel environments.\n try {\n var bc = new BroadcastChannel(\"builder-connect:\" + window.location.host);\n bc.postMessage({ type: \"builder-connect-error\", message: msg });\n bc.close();\n } catch (e) {}\n if (window.opener && !window.opener.closed) {\n try {\n window.opener.postMessage(\n { type: \"builder-connect-error\", message: msg },\n window.location.origin,\n );\n } catch (e) {}\n }\n } catch (e) {}\n </script>\n </body>\n</html>`;\n}\n\nexport interface RunBuilderAgentArgs {\n prompt: string;\n projectId?: string;\n branchName?: string;\n userEmail?: string;\n userId?: string;\n}\n\nexport interface RunBuilderAgentResult {\n branchName: string;\n projectId: string;\n url: string;\n status: string;\n}\n\nfunction normalizeBuilderApiString(value: unknown, fieldName: string): string {\n if (typeof value !== \"string\" || !value.trim()) {\n throw new Error(`Builder agent run returned a blank ${fieldName}`);\n }\n const trimmed = value.trim();\n if (/[\\u0000-\\u001f\\u007f]/.test(trimmed)) {\n throw new Error(`Builder agent run returned a malformed ${fieldName}`);\n }\n return trimmed;\n}\n\nfunction normalizeBuilderBranchUrl(value: unknown): string {\n const urlString = normalizeBuilderApiString(value, \"url\");\n let parsed: URL;\n try {\n parsed = new URL(urlString);\n } catch {\n throw new Error(\"Builder agent run returned a malformed url\");\n }\n if (parsed.protocol !== \"https:\" && parsed.protocol !== \"http:\") {\n throw new Error(\"Builder agent run returned a malformed url\");\n }\n if (\n parsed.hostname !== \"builder.io\" &&\n !parsed.hostname.endsWith(\".builder.io\")\n ) {\n throw new Error(\"Builder agent run returned a non-Builder url\");\n }\n return parsed.toString();\n}\n\n/**\n * POST a prompt to the Builder agents-run API. The Builder agent runs in a\n * cloud sandbox and writes code to a branch; the returned URL opens that\n * branch in the Visual Editor so the user can watch progress.\n *\n * Spec: https://www.builder.io/c/docs/agents-run-api\n */\nexport async function runBuilderAgent(\n args: RunBuilderAgentArgs,\n): Promise<RunBuilderAgentResult> {\n const { resolveBuilderCredentials } =\n await import(\"./credential-provider.js\");\n const creds = await resolveBuilderCredentials();\n if (!creds.privateKey || !creds.publicKey) {\n throw new Error(\"Builder keys are not configured\");\n }\n if (!args.prompt || !args.prompt.trim()) {\n throw new Error(\"prompt is required\");\n }\n const projectId = args.projectId?.trim();\n if (!projectId) {\n throw new Error(\n \"Builder project ID is not configured. Set DISPATCH_BUILDER_PROJECT_ID, BUILDER_BRANCH_PROJECT_ID, or BUILDER_PROJECT_ID.\",\n );\n }\n const builderUserId = args.userId || creds.userId || undefined;\n const builderUserEmail = builderUserId ? undefined : args.userEmail;\n if (!builderUserEmail && !builderUserId) {\n throw new Error(\"userEmail or userId is required\");\n }\n\n const url = new URL(\"/agents/run\", getBuilderApiHost());\n url.searchParams.set(\"apiKey\", creds.publicKey);\n\n const body: Record<string, unknown> = {\n userMessage: { userPrompt: args.prompt },\n projectId,\n };\n if (args.branchName) body.branchName = args.branchName;\n if (builderUserEmail) body.userEmail = builderUserEmail;\n if (builderUserId) body.userId = builderUserId;\n\n const response = await fetch(url, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${creds.privateKey}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(body),\n });\n\n const parsed = (await response.json().catch(() => ({}))) as Record<\n string,\n unknown\n >;\n if (!response.ok) {\n const msg =\n typeof parsed.error === \"string\"\n ? parsed.error\n : `Builder agent run failed (${response.status})`;\n throw new Error(msg);\n }\n\n return {\n branchName: normalizeBuilderApiString(parsed.branchName, \"branchName\"),\n projectId:\n typeof parsed.projectId === \"string\" && parsed.projectId.trim()\n ? parsed.projectId.trim()\n : projectId,\n url: normalizeBuilderBranchUrl(parsed.url),\n status:\n typeof parsed.status === \"string\" && parsed.status.trim()\n ? parsed.status.trim()\n : \"processing\",\n };\n}\n\nexport async function requestBuilderBrowserConnection(\n args: BrowserConnectionArgs,\n): Promise<Record<string, unknown>> {\n const { resolveBuilderCredentials } =\n await import(\"./credential-provider.js\");\n const creds = await resolveBuilderCredentials();\n if (!creds.privateKey || !creds.publicKey) {\n throw new Error(\"Builder browser access is not configured\");\n }\n\n const sessionId = args.sessionId?.trim();\n if (!sessionId) {\n throw new Error(\"sessionId is required\");\n }\n\n const url = new URL(\"/codegen/get-browser-connection\", getBuilderApiHost());\n url.searchParams.set(\"apiKey\", creds.publicKey);\n if (creds.userId) {\n url.searchParams.set(\"userId\", creds.userId);\n }\n\n const response = await fetch(url, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${creds.privateKey}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n sessionId,\n projectId: args.projectId || undefined,\n branchName: args.branchName || undefined,\n proxyOrigin: args.proxyOrigin || undefined,\n proxyDefaultOrigin: args.proxyDefaultOrigin || undefined,\n proxyDst: args.proxyDestination || undefined,\n }),\n });\n\n const body = (await response.json().catch(() => ({}))) as Record<\n string,\n unknown\n >;\n if (!response.ok) {\n const error =\n typeof body.error === \"string\"\n ? body.error\n : `Builder browser request failed (${response.status})`;\n throw new Error(error);\n }\n\n return body;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"builder-browser.js","sourceRoot":"","sources":["../../src/server/builder-browser.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHmac, randomBytes, timingSafeEqual } from \"node:crypto\";\nimport type { H3Event } from \"h3\";\nimport { getAuthSecret } from \"./better-auth-instance.js\";\nimport { getAppBasePath, getOrigin } from \"./google-oauth.js\";\n\nconst DEFAULT_BUILDER_APP_HOST = \"https://builder.io\";\nconst DEFAULT_BUILDER_API_HOST = \"https://api.builder.io\";\nconst BUILDER_BROWSER_HOST = \"agent-native-browser\";\nconst BUILDER_BROWSER_CLIENT_ID = \"Agent Native Browser\";\n\nexport const BUILDER_CALLBACK_PATH = \"/_agent-native/builder/callback\";\n\n/**\n * Query-param name carrying the signed CSRF state on the connect→callback\n * round-trip. Prefixed with `_an_` to avoid collisions if Builder ever\n * adds standard OAuth `state` support to cli-auth. Builder preserves\n * the path/query of `redirect_url` verbatim when redirecting back, so\n * we embed `_an_state=…` inside the redirect_url query string at\n * connect time and read it back on the callback.\n */\nexport const BUILDER_STATE_PARAM = \"_an_state\";\nexport const BUILDER_CONNECT_PARAM = \"_an_connect\";\n\nconst BUILDER_STATE_TTL_MS = 10 * 60 * 1000;\n\nexport interface BuilderBrowserStatus {\n configured: boolean;\n builderEnabled: boolean;\n branchProjectIdConfigured: boolean;\n branchProjectId?: string;\n /**\n * True when `BUILDER_PRIVATE_KEY` is set at the deployment level. Every\n * user of this deploy shares the operator's Builder identity; the UI\n * must hide the per-user connect/disconnect flow and show a read-only\n * \"managed by deployment\" state instead.\n */\n envManaged: boolean;\n appHost: string;\n apiHost: string;\n connectUrl: string;\n publicKeyConfigured: boolean;\n privateKeyConfigured: boolean;\n userId?: string;\n orgName?: string;\n orgKind?: string;\n}\n\nexport interface BrowserConnectionArgs {\n sessionId?: string;\n projectId?: string;\n branchName?: string;\n proxyOrigin?: string;\n proxyDefaultOrigin?: string;\n proxyDestination?: string;\n}\n\ntype BuilderSignedTokenPurpose = \"callback\" | \"connect\";\n\nfunction signingKeyForPurpose(purpose: BuilderSignedTokenPurpose): string {\n // Preserve the original callback-state signing key for any in-flight legacy\n // callbacks; use a separate key domain for connect-entry tokens.\n return purpose === \"callback\"\n ? `builder-csrf:${getAuthSecret()}`\n : `builder-connect:${getAuthSecret()}`;\n}\n\nfunction macForParts(\n purpose: BuilderSignedTokenPurpose,\n nonce: string,\n emailEncoded: string,\n ts: number,\n): string {\n return createHmac(\"sha256\", signingKeyForPurpose(purpose))\n .update(`${nonce}.${emailEncoded}.${ts}`)\n .digest(\"base64url\");\n}\n\nfunction signEmailBoundBuilderToken(\n ownerEmail: string,\n purpose: BuilderSignedTokenPurpose,\n): string {\n const nonce = randomBytes(16).toString(\"base64url\");\n const ts = Date.now();\n const emailEncoded = Buffer.from(ownerEmail, \"utf8\").toString(\"base64url\");\n const mac = macForParts(purpose, nonce, emailEncoded, ts);\n return `${nonce}.${emailEncoded}.${ts}.${mac}`;\n}\n\nfunction verifyEmailBoundBuilderToken(\n token: string | null | undefined,\n ownerEmail: string,\n purpose: BuilderSignedTokenPurpose,\n): boolean {\n if (typeof token !== \"string\" || token.length === 0) return false;\n const parts = token.split(\".\");\n if (parts.length !== 4) return false;\n const [nonce, emailEncoded, tsStr, mac] = parts;\n if (!nonce || !emailEncoded || !tsStr || !mac) return false;\n\n let boundEmail: string;\n try {\n boundEmail = Buffer.from(emailEncoded, \"base64url\").toString(\"utf8\");\n } catch {\n return false;\n }\n if (boundEmail !== ownerEmail) return false;\n\n const ts = Number(tsStr);\n if (!Number.isFinite(ts)) return false;\n // Reject expired AND far-future timestamps so leaked tokens do not gain an\n // arbitrary lifetime through clock skew or forged future issue times.\n if (Math.abs(Date.now() - ts) > BUILDER_STATE_TTL_MS) return false;\n\n const expected = Buffer.from(macForParts(purpose, nonce, emailEncoded, ts));\n const candidate = Buffer.from(mac);\n if (expected.length !== candidate.length) return false;\n return timingSafeEqual(expected, candidate);\n}\n\n/**\n * Mint a signed CSRF state token bound to the current session's email\n * and a fresh nonce. Round-trips through Builder's cli-auth flow inside\n * the redirect_url query string and is verified on the callback before\n * any keys are written.\n *\n * Why bind to email: it's the only stable, universally-available\n * identity field across all auth modes (Better Auth, BYOA, AUTH_MODE=local).\n * Binding to the session token instead would put the cookie value in a\n * URL that may end up in server logs / browser history.\n */\nexport function signBuilderCallbackState(sessionEmail: string): string {\n return signEmailBoundBuilderToken(sessionEmail, \"callback\");\n}\n\n/**\n * Verify a state token produced by `signBuilderCallbackState`. Returns\n * false on any malformed, forged, expired, or cross-session token.\n */\nexport function verifyBuilderCallbackState(\n token: string | null | undefined,\n sessionEmail: string,\n): boolean {\n return verifyEmailBoundBuilderToken(token, sessionEmail, \"callback\");\n}\n\nexport function signBuilderConnectToken(ownerEmail: string): string {\n return signEmailBoundBuilderToken(ownerEmail, \"connect\");\n}\n\nexport function verifyBuilderConnectToken(\n token: string | null | undefined,\n ownerEmail: string,\n): boolean {\n return verifyEmailBoundBuilderToken(token, ownerEmail, \"connect\");\n}\n\nexport function appendBuilderConnectToken(\n connectUrl: string,\n ownerEmail: string,\n): string {\n const url = new URL(connectUrl);\n url.searchParams.set(\n BUILDER_CONNECT_PARAM,\n signBuilderConnectToken(ownerEmail),\n );\n return url.toString();\n}\n\nfunction isAllowedBrowserReturnUrl(urlString: string): boolean {\n try {\n const parsed = new URL(urlString);\n const hostname = parsed.hostname.toLowerCase();\n const isAllowedProtocol =\n parsed.protocol === \"http:\" || parsed.protocol === \"https:\";\n const isLocalhost =\n hostname === \"localhost\" ||\n hostname === \"127.0.0.1\" ||\n hostname === \"[::1]\";\n const isBuilderDomain =\n hostname === \"builder.io\" || hostname.endsWith(\".builder.io\");\n const isAgentNativeDomain =\n hostname === \"agent-native.com\" || hostname.endsWith(\".agent-native.com\");\n return (\n isAllowedProtocol &&\n (isLocalhost || isBuilderDomain || isAgentNativeDomain)\n );\n } catch {\n return false;\n }\n}\n\nfunction normalizeOrigin(origin: string): string {\n return origin.replace(/\\/+$/, \"\");\n}\n\nexport function getBuilderAppHost(): string {\n return (\n process.env.BUILDER_APP_HOST ||\n process.env.BUILDER_PUBLIC_APP_HOST ||\n DEFAULT_BUILDER_APP_HOST\n );\n}\n\nexport function getBuilderApiHost(): string {\n return (\n process.env.AIR_HOST ||\n process.env.BUILDER_HOST ||\n process.env.BUILDER_API_HOST ||\n DEFAULT_BUILDER_API_HOST\n );\n}\n\nfunction getConfiguredBuilderBranchProjectId(): string | undefined {\n const projectId =\n process.env.DISPATCH_BUILDER_PROJECT_ID ||\n process.env.BUILDER_BRANCH_PROJECT_ID ||\n process.env.BUILDER_PROJECT_ID;\n return projectId?.trim() || undefined;\n}\n\nexport function getBuilderBranchProjectId(): string {\n return getConfiguredBuilderBranchProjectId() || \"\";\n}\n\nexport function isBuilderBranchingEnabled(): boolean {\n return !!getConfiguredBuilderBranchProjectId();\n}\n\n/**\n * Build the Builder cli-auth URL for the connect popup. When a signed\n * `state` token is supplied it is embedded inside the `redirect_url`\n * query string so it survives Builder's redirect verbatim — Builder\n * preserves the redirect_url's existing query when appending p-key /\n * api-key / etc., so we don't depend on Builder echoing a top-level\n * `state` parameter (it doesn't).\n *\n * The user-facing connect entry point is `/_agent-native/builder/connect`\n * (a server-side 302). Status / chat-card responses surface that path\n * rather than the cli-auth URL directly, so the 302 handler can mint a\n * fresh state bound to the current session on every click.\n */\nexport function buildBuilderCliAuthUrl(\n origin: string,\n state: string | null = null,\n): string {\n const normalizedOrigin = normalizeOrigin(origin);\n const appBasePath = getAppBasePath();\n const callbackUrl = new URL(\n `${appBasePath}${BUILDER_CALLBACK_PATH}`,\n normalizedOrigin,\n );\n if (state) {\n callbackUrl.searchParams.set(BUILDER_STATE_PARAM, state);\n }\n const url = new URL(\"/cli-auth\", getBuilderAppHost());\n url.searchParams.set(\"response_type\", \"code\");\n url.searchParams.set(\"host\", BUILDER_BROWSER_HOST);\n url.searchParams.set(\"client_id\", BUILDER_BROWSER_CLIENT_ID);\n url.searchParams.set(\"redirect_url\", callbackUrl.toString());\n url.searchParams.set(\"preview_url\", `${normalizedOrigin}${appBasePath}`);\n url.searchParams.set(\"framework\", \"agent-native\");\n return url.toString();\n}\n\n/**\n * The bare URL surfaced to clients as `connectUrl`. The status route appends\n * a short-lived signed connect token when it knows the current owner; this\n * helper stays bare so server-rendered cards can still render without a\n * request-bound owner and the connect route can fall back to Fetch Metadata.\n */\nexport function getBuilderBrowserConnectUrl(origin: string): string {\n return `${normalizeOrigin(origin)}${getAppBasePath()}/_agent-native/builder/connect`;\n}\n\nexport function getBuilderBrowserStatus(origin: string): BuilderBrowserStatus {\n const branchProjectId = getConfiguredBuilderBranchProjectId();\n const envManaged = !!process.env.BUILDER_PRIVATE_KEY;\n return {\n configured: !!(\n process.env.BUILDER_PRIVATE_KEY && process.env.BUILDER_PUBLIC_KEY\n ),\n builderEnabled: isBuilderBranchingEnabled(),\n branchProjectIdConfigured: !!branchProjectId,\n branchProjectId: branchProjectId || undefined,\n envManaged,\n appHost: getBuilderAppHost(),\n apiHost: getBuilderApiHost(),\n connectUrl: getBuilderBrowserConnectUrl(origin),\n publicKeyConfigured: !!process.env.BUILDER_PUBLIC_KEY,\n privateKeyConfigured: !!process.env.BUILDER_PRIVATE_KEY,\n userId: process.env.BUILDER_USER_ID || undefined,\n orgName: process.env.BUILDER_ORG_NAME || undefined,\n orgKind: process.env.BUILDER_ORG_KIND || undefined,\n };\n}\n\nexport function getBuilderBrowserStatusForEvent(\n event: H3Event,\n): BuilderBrowserStatus {\n return getBuilderBrowserStatus(getOrigin(event));\n}\n\n/**\n * Env vars written by the Builder CLI-auth callback. Single source of truth\n * for the connect/disconnect key set — `getBuilderCallbackEnvVars` and the\n * disconnect handler's scrub loop both derive from this list, so drift\n * (e.g. disconnect silently leaving `BUILDER_USER_ID` behind because\n * someone added a key to one site but not the other) is impossible.\n */\nexport const BUILDER_ENV_KEYS = [\n \"BUILDER_PRIVATE_KEY\",\n \"BUILDER_PUBLIC_KEY\",\n \"BUILDER_USER_ID\",\n \"BUILDER_ORG_NAME\",\n \"BUILDER_ORG_KIND\",\n] as const;\n\nexport type BuilderEnvKey = (typeof BUILDER_ENV_KEYS)[number];\n\nexport function getBuilderCallbackEnvVars(params: {\n privateKey?: string | null;\n publicKey?: string | null;\n userId?: string | null;\n orgName?: string | null;\n orgKind?: string | null;\n}) {\n const values: Record<BuilderEnvKey, string> = {\n BUILDER_PRIVATE_KEY: params.privateKey?.trim() || \"\",\n BUILDER_PUBLIC_KEY: params.publicKey?.trim() || \"\",\n BUILDER_USER_ID: params.userId?.trim() || \"\",\n BUILDER_ORG_NAME: params.orgName?.trim() || \"\",\n BUILDER_ORG_KIND: params.orgKind?.trim() || \"\",\n };\n return BUILDER_ENV_KEYS.map((key) => ({ key, value: values[key] }));\n}\n\nexport function resolveSafePreviewUrl(\n previewUrl: string | null | undefined,\n event: H3Event,\n): string {\n if (previewUrl && isAllowedBrowserReturnUrl(previewUrl)) {\n return previewUrl;\n }\n return getOrigin(event);\n}\n\n/**\n * Inline theme-detection script that runs before the body paints. Reads the\n * app's stored theme preference (same `localStorage.theme` key used by the\n * client-side theme manager) and falls back to `prefers-color-scheme`. This\n * way the popup matches whatever theme the user already picked in the app\n * — light, dark, or auto — instead of always rendering in OS-default mode.\n */\nconst BUILDER_CALLBACK_THEME_SCRIPT = `<script>\n(function () {\n try {\n var stored = window.localStorage && window.localStorage.getItem(\"theme\");\n var resolved;\n if (stored === \"light\" || stored === \"dark\") {\n resolved = stored;\n } else {\n var mq = window.matchMedia && window.matchMedia(\"(prefers-color-scheme: dark)\");\n resolved = mq && mq.matches ? \"dark\" : \"light\";\n }\n document.documentElement.classList.add(resolved);\n document.documentElement.style.colorScheme = resolved;\n } catch (e) {}\n})();\n</script>`;\n\n/**\n * Brand-aligned CSS for the Builder connect callback / error pages.\n *\n * Uses the same neutral-zinc palette and Inter font as the rest of the\n * framework's templates (see `templates/*\\/app/global.css`). Tokens map to\n * the same HSL values the templates set on `:root` / `.dark`, so the popup\n * reads as part of the same app — not a stranded marketing page.\n */\nconst BUILDER_CALLBACK_BASE_CSS = `\n :root {\n --bg: hsl(0 0% 100%);\n --fg: hsl(220 10% 10%);\n --muted-fg: hsl(220 5% 45%);\n --card: hsl(0 0% 100%);\n --border: hsl(220 10% 90%);\n --primary: hsl(220 10% 15%);\n --primary-fg: hsl(0 0% 100%);\n --primary-hover: hsl(220 10% 25%);\n --success-bg: hsl(143 50% 96%);\n --success-fg: hsl(143 60% 32%);\n --error-fg: hsl(0 75% 45%);\n --error-bg: hsl(0 80% 97%);\n --error-border: hsl(0 80% 92%);\n }\n :root.dark {\n --bg: hsl(220 6% 6%);\n --fg: hsl(0 0% 92%);\n --muted-fg: hsl(220 4% 60%);\n --card: hsl(220 5% 8%);\n --border: hsl(220 4% 14%);\n --primary: hsl(0 0% 92%);\n --primary-fg: hsl(220 6% 6%);\n --primary-hover: hsl(0 0% 75%);\n --success-bg: hsl(143 30% 12%);\n --success-fg: hsl(143 50% 70%);\n --error-fg: hsl(0 80% 75%);\n --error-bg: hsl(0 35% 12%);\n --error-border: hsl(0 30% 20%);\n }\n *, *::before, *::after { box-sizing: border-box; }\n html, body { height: 100%; }\n body {\n margin: 0;\n min-height: 100vh;\n display: grid;\n place-items: center;\n background: var(--bg);\n color: var(--fg);\n font-family: \"Inter\", ui-sans-serif, system-ui, -apple-system, \"Segoe UI\", \"Helvetica Neue\", Arial, sans-serif;\n font-size: 14px;\n line-height: 1.55;\n font-feature-settings: \"cv02\", \"cv03\", \"cv04\", \"cv11\";\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n padding: 24px;\n }\n .card {\n width: min(420px, 100%);\n border: 1px solid var(--border);\n border-radius: 12px;\n padding: 32px 28px;\n background: var(--card);\n text-align: center;\n }\n .icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 44px;\n height: 44px;\n border-radius: 999px;\n margin-bottom: 16px;\n }\n .icon svg { width: 22px; height: 22px; display: block; }\n .icon-success { background: var(--success-bg); color: var(--success-fg); }\n .icon-error { background: var(--error-bg); color: var(--error-fg); }\n h1 {\n margin: 0 0 6px;\n font-size: 17px;\n font-weight: 600;\n letter-spacing: -0.01em;\n color: var(--fg);\n }\n p {\n margin: 0 0 4px;\n color: var(--fg);\n font-size: 14px;\n }\n p.muted { color: var(--muted-fg); }\n .btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n height: 36px;\n padding: 0 16px;\n margin-top: 20px;\n background: var(--primary);\n color: var(--primary-fg);\n border-radius: 8px;\n font-size: 13px;\n font-weight: 500;\n text-decoration: none;\n border: none;\n cursor: pointer;\n }\n .btn:hover { background: var(--primary-hover); }\n pre.error-detail {\n margin: 16px 0 0;\n padding: 10px 12px;\n background: var(--error-bg);\n border: 1px solid var(--error-border);\n border-radius: 8px;\n color: var(--error-fg);\n font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;\n font-size: 12px;\n line-height: 1.5;\n text-align: left;\n white-space: pre-wrap;\n word-break: break-word;\n }\n`;\n\nexport function createBuilderBrowserCallbackPage(previewUrl: string): string {\n const escapedUrl = JSON.stringify(previewUrl);\n return `<!doctype html>\n<html lang=\"en\">\n <head>\n <meta charset=\"utf-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no\" />\n <title>Builder connected</title>\n <link rel=\"preconnect\" href=\"https://fonts.googleapis.com\" />\n <link rel=\"preconnect\" href=\"https://fonts.gstatic.com\" crossorigin />\n <link href=\"https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap\" rel=\"stylesheet\" />\n ${BUILDER_CALLBACK_THEME_SCRIPT}\n <style>${BUILDER_CALLBACK_BASE_CSS}</style>\n </head>\n <body>\n <main class=\"card\" role=\"status\" aria-live=\"polite\">\n <span class=\"icon icon-success\" aria-hidden=\"true\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"></polyline></svg>\n </span>\n <h1>Builder connected</h1>\n <p>Browser access is now available to your app.</p>\n <p class=\"muted\">You can close this tab and return to the workspace.</p>\n <a class=\"btn\" href=${escapedUrl}>Open the workspace</a>\n </main>\n <script>\n // If we're a popup opened by the app, close ourselves and let the\n // parent tab keep polling for connection status. If close() is\n // blocked (e.g. we're the top-level tab because popups were\n // downgraded), fall back to navigating back to the workspace.\n window.setTimeout(function () {\n try { window.close(); } catch (e) {}\n window.setTimeout(function () {\n if (!window.closed) {\n window.location.replace(${escapedUrl});\n }\n }, 200);\n }, 700);\n </script>\n </body>\n</html>`;\n}\n\n/**\n * HTML page rendered inside the OAuth popup when the callback handler caught\n * an error persisting the per-user Builder credentials. Without this, the\n * popup would show the success page even though the write failed — leaving\n * the parent window stuck on \"Waiting for Builder…\" until the 5-minute poll\n * timeout fires (Midhun reported this on 2026-04-28).\n *\n * The page does two things:\n * 1. Shows the user a clear \"couldn't save credentials\" message with the\n * underlying error so they can retry or report.\n * 2. `postMessage`s the parent (same-origin opener) so the connect-flow\n * polling stops immediately rather than waiting for the next /status\n * poll to surface the SQL `builder-connect-error:<email>` row.\n */\nexport function createBuilderBrowserCallbackErrorPage(message: string): string {\n const escapedMessage = JSON.stringify(message);\n return `<!doctype html>\n<html lang=\"en\">\n <head>\n <meta charset=\"utf-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no\" />\n <title>Builder connect failed</title>\n <link rel=\"preconnect\" href=\"https://fonts.googleapis.com\" />\n <link rel=\"preconnect\" href=\"https://fonts.gstatic.com\" crossorigin />\n <link href=\"https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap\" rel=\"stylesheet\" />\n ${BUILDER_CALLBACK_THEME_SCRIPT}\n <style>${BUILDER_CALLBACK_BASE_CSS}</style>\n </head>\n <body>\n <main class=\"card\" role=\"alert\" aria-live=\"assertive\">\n <span class=\"icon icon-error\" aria-hidden=\"true\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0Z\"></path><line x1=\"12\" y1=\"9\" x2=\"12\" y2=\"13\"></line><line x1=\"12\" y1=\"17\" x2=\"12.01\" y2=\"17\"></line></svg>\n </span>\n <h1>Couldn't save Builder connection</h1>\n <p class=\"muted\">Builder authorized your account but the server couldn't persist the credentials.</p>\n <pre class=\"error-detail\" id=\"msg\"></pre>\n <p class=\"muted\" style=\"margin-top:12px\">You can close this tab and try again from settings.</p>\n </main>\n <script>\n try {\n var msg = ${escapedMessage};\n document.getElementById(\"msg\").textContent = msg;\n // Notify the parent tab immediately so its polling loop stops\n // without waiting for the next /builder/status tick.\n //\n // BroadcastChannel works across same-origin windows regardless of\n // opener access — it is the only reliable channel here because\n // popups opened with window.open(..., \"noopener\") or links with\n // rel=\"noopener\" have window.opener === null. The legacy\n // window.opener.postMessage path is kept as a belt-and-suspenders\n // fallback for non-BroadcastChannel environments.\n try {\n var bc = new BroadcastChannel(\"builder-connect:\" + window.location.host);\n bc.postMessage({ type: \"builder-connect-error\", message: msg });\n bc.close();\n } catch (e) {}\n if (window.opener && !window.opener.closed) {\n try {\n window.opener.postMessage(\n { type: \"builder-connect-error\", message: msg },\n window.location.origin,\n );\n } catch (e) {}\n }\n } catch (e) {}\n </script>\n </body>\n</html>`;\n}\n\nexport interface RunBuilderAgentArgs {\n prompt: string;\n projectId?: string;\n branchName?: string;\n userEmail?: string;\n userId?: string;\n}\n\nexport interface RunBuilderAgentResult {\n branchName: string;\n projectId: string;\n url: string;\n status: string;\n}\n\nfunction normalizeBuilderApiString(value: unknown, fieldName: string): string {\n if (typeof value !== \"string\" || !value.trim()) {\n throw new Error(`Builder agent run returned a blank ${fieldName}`);\n }\n const trimmed = value.trim();\n if (/[\\u0000-\\u001f\\u007f]/.test(trimmed)) {\n throw new Error(`Builder agent run returned a malformed ${fieldName}`);\n }\n return trimmed;\n}\n\nfunction normalizeBuilderBranchUrl(value: unknown): string {\n const urlString = normalizeBuilderApiString(value, \"url\");\n let parsed: URL;\n try {\n parsed = new URL(urlString);\n } catch {\n throw new Error(\"Builder agent run returned a malformed url\");\n }\n if (parsed.protocol !== \"https:\" && parsed.protocol !== \"http:\") {\n throw new Error(\"Builder agent run returned a malformed url\");\n }\n if (\n parsed.hostname !== \"builder.io\" &&\n !parsed.hostname.endsWith(\".builder.io\")\n ) {\n throw new Error(\"Builder agent run returned a non-Builder url\");\n }\n return parsed.toString();\n}\n\n/**\n * POST a prompt to the Builder agents-run API. The Builder agent runs in a\n * cloud sandbox and writes code to a branch; the returned URL opens that\n * branch in the Visual Editor so the user can watch progress.\n *\n * Spec: https://www.builder.io/c/docs/agents-run-api\n */\nexport async function runBuilderAgent(\n args: RunBuilderAgentArgs,\n): Promise<RunBuilderAgentResult> {\n const { resolveBuilderCredentials } =\n await import(\"./credential-provider.js\");\n const creds = await resolveBuilderCredentials();\n if (!creds.privateKey || !creds.publicKey) {\n throw new Error(\"Builder keys are not configured\");\n }\n if (!args.prompt || !args.prompt.trim()) {\n throw new Error(\"prompt is required\");\n }\n const projectId = args.projectId?.trim();\n if (!projectId) {\n throw new Error(\n \"Builder project ID is not configured. Set DISPATCH_BUILDER_PROJECT_ID, BUILDER_BRANCH_PROJECT_ID, or BUILDER_PROJECT_ID.\",\n );\n }\n const builderUserId = args.userId || creds.userId || undefined;\n const builderUserEmail = builderUserId ? undefined : args.userEmail;\n if (!builderUserEmail && !builderUserId) {\n throw new Error(\"userEmail or userId is required\");\n }\n\n const url = new URL(\"/agents/run\", getBuilderApiHost());\n url.searchParams.set(\"apiKey\", creds.publicKey);\n\n const body: Record<string, unknown> = {\n userMessage: { userPrompt: args.prompt },\n projectId,\n };\n if (args.branchName) body.branchName = args.branchName;\n if (builderUserEmail) body.userEmail = builderUserEmail;\n if (builderUserId) body.userId = builderUserId;\n\n const response = await fetch(url, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${creds.privateKey}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(body),\n });\n\n const parsed = (await response.json().catch(() => ({}))) as Record<\n string,\n unknown\n >;\n if (!response.ok) {\n const msg =\n typeof parsed.error === \"string\"\n ? parsed.error\n : `Builder agent run failed (${response.status})`;\n throw new Error(msg);\n }\n\n return {\n branchName: normalizeBuilderApiString(parsed.branchName, \"branchName\"),\n projectId:\n typeof parsed.projectId === \"string\" && parsed.projectId.trim()\n ? parsed.projectId.trim()\n : projectId,\n url: normalizeBuilderBranchUrl(parsed.url),\n status:\n typeof parsed.status === \"string\" && parsed.status.trim()\n ? parsed.status.trim()\n : \"processing\",\n };\n}\n\nexport async function requestBuilderBrowserConnection(\n args: BrowserConnectionArgs,\n): Promise<Record<string, unknown>> {\n const { resolveBuilderCredentials } =\n await import(\"./credential-provider.js\");\n const creds = await resolveBuilderCredentials();\n if (!creds.privateKey || !creds.publicKey) {\n throw new Error(\"Builder browser access is not configured\");\n }\n\n const sessionId = args.sessionId?.trim();\n if (!sessionId) {\n throw new Error(\"sessionId is required\");\n }\n\n const url = new URL(\"/codegen/get-browser-connection\", getBuilderApiHost());\n url.searchParams.set(\"apiKey\", creds.publicKey);\n if (creds.userId) {\n url.searchParams.set(\"userId\", creds.userId);\n }\n\n const response = await fetch(url, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${creds.privateKey}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n sessionId,\n projectId: args.projectId || undefined,\n branchName: args.branchName || undefined,\n proxyOrigin: args.proxyOrigin || undefined,\n proxyDefaultOrigin: args.proxyDefaultOrigin || undefined,\n proxyDst: args.proxyDestination || undefined,\n }),\n });\n\n const body = (await response.json().catch(() => ({}))) as Record<\n string,\n unknown\n >;\n if (!response.ok) {\n const error =\n typeof body.error === \"string\"\n ? body.error\n : `Builder browser request failed (${response.status})`;\n throw new Error(error);\n }\n\n return body;\n}\n"]}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { H3Event } from "h3";
|
|
1
2
|
import type { EnvKeyConfig } from "./create-server.js";
|
|
2
3
|
/**
|
|
3
4
|
* The base path prefix for all framework-level routes.
|
|
@@ -32,6 +33,12 @@ export interface CoreRoutesPluginOptions {
|
|
|
32
33
|
disableAppState?: boolean;
|
|
33
34
|
/** Env key configuration. Enables env-status and env-vars routes. */
|
|
34
35
|
envKeys?: EnvKeyConfig[];
|
|
36
|
+
/**
|
|
37
|
+
* Optional owner resolver for narrowly-scoped public routes. Used by public
|
|
38
|
+
* pages that let anonymous viewers connect Builder credentials for their
|
|
39
|
+
* own browser-scoped agent session.
|
|
40
|
+
*/
|
|
41
|
+
anonymousOwner?: (event: H3Event) => string | null | Promise<string | null>;
|
|
35
42
|
}
|
|
36
43
|
/**
|
|
37
44
|
* Creates a Nitro plugin that mounts all standard agent-native framework routes.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"core-routes-plugin.d.ts","sourceRoot":"","sources":["../../src/server/core-routes-plugin.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"core-routes-plugin.d.ts","sourceRoot":"","sources":["../../src/server/core-routes-plugin.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAKlC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AA4EvD;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,mBAAmB,CAAC;AAqCvD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,GACb,MAAM,GAAG,IAAI,CAWf;AAUD,KAAK,cAAc,GAAG,CAAC,QAAQ,EAAE,GAAG,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAE9D,MAAM,WAAW,uBAAuB;IACtC,wEAAwE;IACxE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,yCAAyC;IACzC,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,oDAAoD;IACpD,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,2DAA2D;IAC3D,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,qEAAqE;IACrE,OAAO,CAAC,EAAE,YAAY,EAAE,CAAC;IACzB;;;;OAIG;IACH,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;CAC7E;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,GAAE,uBAA4B,GACpC,cAAc,CAoyDhB;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,uBAAuB,EAAE,cAAyC,CAAC"}
|