@agent-native/core 0.7.12 → 0.7.13
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/README.md +1 -1
- package/dist/agent/engine/ai-sdk-engine.d.ts.map +1 -1
- package/dist/agent/engine/ai-sdk-engine.js +26 -8
- package/dist/agent/engine/ai-sdk-engine.js.map +1 -1
- package/dist/agent/engine/builder-engine.d.ts +19 -0
- package/dist/agent/engine/builder-engine.d.ts.map +1 -0
- package/dist/agent/engine/builder-engine.js +430 -0
- package/dist/agent/engine/builder-engine.js.map +1 -0
- package/dist/agent/engine/builtin.d.ts.map +1 -1
- package/dist/agent/engine/builtin.js +26 -10
- package/dist/agent/engine/builtin.js.map +1 -1
- 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 +20 -1
- package/dist/agent/engine/registry.d.ts.map +1 -1
- package/dist/agent/engine/registry.js +49 -1
- package/dist/agent/engine/registry.js.map +1 -1
- package/dist/agent/engine/types.d.ts +30 -0
- package/dist/agent/engine/types.d.ts.map +1 -1
- package/dist/agent/engine/types.js +19 -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 +65 -7
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/agent/run-manager.d.ts.map +1 -1
- package/dist/agent/run-manager.js +11 -1
- package/dist/agent/run-manager.js.map +1 -1
- package/dist/agent/thread-data-builder.d.ts +4 -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/agent/types.d.ts +8 -0
- package/dist/agent/types.d.ts.map +1 -1
- package/dist/checkpoints/service.d.ts +1 -0
- package/dist/checkpoints/service.d.ts.map +1 -1
- package/dist/checkpoints/service.js +26 -2
- package/dist/checkpoints/service.js.map +1 -1
- package/dist/cli/create.d.ts +30 -0
- package/dist/cli/create.d.ts.map +1 -1
- package/dist/cli/create.js +25 -13
- package/dist/cli/create.js.map +1 -1
- package/dist/client/AgentPanel.js +1 -1
- package/dist/client/AgentPanel.js.map +1 -1
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +49 -10
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/ConnectBuilderCard.d.ts +1 -7
- package/dist/client/ConnectBuilderCard.d.ts.map +1 -1
- package/dist/client/ConnectBuilderCard.js +30 -132
- package/dist/client/ConnectBuilderCard.js.map +1 -1
- package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
- package/dist/client/MultiTabAssistantChat.js +30 -9
- package/dist/client/MultiTabAssistantChat.js.map +1 -1
- package/dist/client/analytics.d.ts +5 -8
- package/dist/client/analytics.d.ts.map +1 -1
- package/dist/client/analytics.js +53 -11
- package/dist/client/analytics.js.map +1 -1
- package/dist/client/builder-mark.d.ts +9 -0
- package/dist/client/builder-mark.d.ts.map +1 -0
- package/dist/client/builder-mark.js +10 -0
- package/dist/client/builder-mark.js.map +1 -0
- package/dist/client/components/ui/popover.d.ts +8 -0
- package/dist/client/components/ui/popover.d.ts.map +1 -0
- package/dist/client/components/ui/popover.js +11 -0
- package/dist/client/components/ui/popover.js.map +1 -0
- package/dist/client/composer/ComposerPlusMenu.d.ts +2 -0
- package/dist/client/composer/ComposerPlusMenu.d.ts.map +1 -0
- package/dist/client/composer/ComposerPlusMenu.js +244 -0
- package/dist/client/composer/ComposerPlusMenu.js.map +1 -0
- package/dist/client/composer/TiptapComposer.d.ts.map +1 -1
- package/dist/client/composer/TiptapComposer.js +9 -5
- package/dist/client/composer/TiptapComposer.js.map +1 -1
- package/dist/client/composer/useVoiceDictation.d.ts.map +1 -1
- package/dist/client/composer/useVoiceDictation.js +4 -2
- package/dist/client/composer/useVoiceDictation.js.map +1 -1
- package/dist/client/error-format.d.ts +2 -0
- package/dist/client/error-format.d.ts.map +1 -0
- package/dist/client/error-format.js +31 -0
- package/dist/client/error-format.js.map +1 -0
- package/dist/client/index.d.ts +3 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +3 -1
- package/dist/client/index.js.map +1 -1
- package/dist/client/observability/ObservabilityDashboard.d.ts +5 -0
- package/dist/client/observability/ObservabilityDashboard.d.ts.map +1 -0
- package/dist/client/observability/ObservabilityDashboard.js +169 -0
- package/dist/client/observability/ObservabilityDashboard.js.map +1 -0
- package/dist/client/observability/ThumbsFeedback.d.ts +8 -0
- package/dist/client/observability/ThumbsFeedback.d.ts.map +1 -0
- package/dist/client/observability/ThumbsFeedback.js +64 -0
- package/dist/client/observability/ThumbsFeedback.js.map +1 -0
- package/dist/client/observability/index.d.ts +4 -0
- package/dist/client/observability/index.d.ts.map +1 -0
- package/dist/client/observability/index.js +4 -0
- package/dist/client/observability/index.js.map +1 -0
- package/dist/client/observability/useObservability.d.ts +128 -0
- package/dist/client/observability/useObservability.d.ts.map +1 -0
- package/dist/client/observability/useObservability.js +109 -0
- package/dist/client/observability/useObservability.js.map +1 -0
- package/dist/client/onboarding/OnboardingPanel.d.ts.map +1 -1
- package/dist/client/onboarding/OnboardingPanel.js +34 -92
- package/dist/client/onboarding/OnboardingPanel.js.map +1 -1
- package/dist/client/org/RequireActiveOrg.d.ts +33 -0
- package/dist/client/org/RequireActiveOrg.d.ts.map +1 -0
- package/dist/client/org/RequireActiveOrg.js +63 -0
- package/dist/client/org/RequireActiveOrg.js.map +1 -0
- package/dist/client/org/hooks.d.ts.map +1 -1
- package/dist/client/org/hooks.js +50 -15
- package/dist/client/org/hooks.js.map +1 -1
- package/dist/client/org/index.d.ts +1 -0
- package/dist/client/org/index.d.ts.map +1 -1
- package/dist/client/org/index.js +1 -0
- package/dist/client/org/index.js.map +1 -1
- package/dist/client/resources/ResourcesPanel.js +3 -3
- package/dist/client/resources/ResourcesPanel.js.map +1 -1
- package/dist/client/settings/AutomationsSection.js +1 -1
- package/dist/client/settings/AutomationsSection.js.map +1 -1
- package/dist/client/settings/BrowserSection.js +1 -1
- package/dist/client/settings/BrowserSection.js.map +1 -1
- package/dist/client/settings/SettingsPanel.d.ts.map +1 -1
- package/dist/client/settings/SettingsPanel.js +112 -12
- package/dist/client/settings/SettingsPanel.js.map +1 -1
- package/dist/client/settings/VoiceTranscriptionSection.d.ts.map +1 -1
- package/dist/client/settings/VoiceTranscriptionSection.js +10 -4
- package/dist/client/settings/VoiceTranscriptionSection.js.map +1 -1
- package/dist/client/settings/useBuilderStatus.d.ts +26 -0
- package/dist/client/settings/useBuilderStatus.d.ts.map +1 -1
- package/dist/client/settings/useBuilderStatus.js +128 -4
- package/dist/client/settings/useBuilderStatus.js.map +1 -1
- package/dist/client/sse-event-processor.d.ts +2 -0
- package/dist/client/sse-event-processor.d.ts.map +1 -1
- package/dist/client/sse-event-processor.js +6 -2
- package/dist/client/sse-event-processor.js.map +1 -1
- package/dist/client/transcription/BuilderTranscriptionCta.d.ts +9 -0
- package/dist/client/transcription/BuilderTranscriptionCta.d.ts.map +1 -0
- package/dist/client/transcription/BuilderTranscriptionCta.js +18 -0
- package/dist/client/transcription/BuilderTranscriptionCta.js.map +1 -0
- package/dist/client/transcription/use-live-transcription.d.ts +29 -0
- package/dist/client/transcription/use-live-transcription.d.ts.map +1 -0
- package/dist/client/transcription/use-live-transcription.js +156 -0
- package/dist/client/transcription/use-live-transcription.js.map +1 -0
- package/dist/client/use-builder-enabled.d.ts +17 -0
- package/dist/client/use-builder-enabled.d.ts.map +1 -0
- package/dist/client/use-builder-enabled.js +36 -0
- package/dist/client/use-builder-enabled.js.map +1 -0
- package/dist/client/use-db-sync.d.ts.map +1 -1
- package/dist/client/use-db-sync.js +4 -2
- package/dist/client/use-db-sync.js.map +1 -1
- package/dist/client/useProductionAgent.d.ts.map +1 -1
- package/dist/client/useProductionAgent.js +3 -1
- package/dist/client/useProductionAgent.js.map +1 -1
- package/dist/db/migrations.d.ts +9 -0
- package/dist/db/migrations.d.ts.map +1 -1
- package/dist/db/migrations.js +75 -10
- package/dist/db/migrations.js.map +1 -1
- package/dist/file-upload/builder.d.ts.map +1 -1
- package/dist/file-upload/builder.js +11 -4
- package/dist/file-upload/builder.js.map +1 -1
- package/dist/jobs/tools.d.ts.map +1 -1
- package/dist/jobs/tools.js +137 -161
- package/dist/jobs/tools.js.map +1 -1
- package/dist/notifications/actions.d.ts +2 -2
- package/dist/notifications/actions.d.ts.map +1 -1
- package/dist/notifications/actions.js +77 -69
- package/dist/notifications/actions.js.map +1 -1
- package/dist/observability/evals.d.ts +22 -0
- package/dist/observability/evals.d.ts.map +1 -0
- package/dist/observability/evals.js +371 -0
- package/dist/observability/evals.js.map +1 -0
- package/dist/observability/experiments.d.ts +24 -0
- package/dist/observability/experiments.d.ts.map +1 -0
- package/dist/observability/experiments.js +274 -0
- package/dist/observability/experiments.js.map +1 -0
- package/dist/observability/feedback.d.ts +14 -0
- package/dist/observability/feedback.d.ts.map +1 -0
- package/dist/observability/feedback.js +256 -0
- package/dist/observability/feedback.js.map +1 -0
- package/dist/observability/index.d.ts +6 -0
- package/dist/observability/index.d.ts.map +1 -0
- package/dist/observability/index.js +5 -0
- package/dist/observability/index.js.map +1 -0
- package/dist/observability/plugin.d.ts +2 -0
- package/dist/observability/plugin.d.ts.map +1 -0
- package/dist/observability/plugin.js +12 -0
- package/dist/observability/plugin.js.map +1 -0
- package/dist/observability/routes.d.ts +68 -0
- package/dist/observability/routes.d.ts.map +1 -0
- package/dist/observability/routes.js +301 -0
- package/dist/observability/routes.js.map +1 -0
- package/dist/observability/store.d.ts +77 -0
- package/dist/observability/store.d.ts.map +1 -0
- package/dist/observability/store.js +976 -0
- package/dist/observability/store.js.map +1 -0
- package/dist/observability/traces.d.ts +37 -0
- package/dist/observability/traces.d.ts.map +1 -0
- package/dist/observability/traces.js +182 -0
- package/dist/observability/traces.js.map +1 -0
- package/dist/observability/types.d.ts +159 -0
- package/dist/observability/types.d.ts.map +1 -0
- package/dist/observability/types.js +16 -0
- package/dist/observability/types.js.map +1 -0
- package/dist/onboarding/default-steps.d.ts.map +1 -1
- package/dist/onboarding/default-steps.js +6 -5
- package/dist/onboarding/default-steps.js.map +1 -1
- package/dist/onboarding/types.d.ts +10 -1
- package/dist/onboarding/types.d.ts.map +1 -1
- package/dist/org/context.d.ts +8 -1
- package/dist/org/context.d.ts.map +1 -1
- package/dist/org/context.js +163 -6
- package/dist/org/context.js.map +1 -1
- package/dist/org/handlers.d.ts.map +1 -1
- package/dist/org/handlers.js +49 -30
- package/dist/org/handlers.js.map +1 -1
- package/dist/progress/actions.d.ts +3 -0
- package/dist/progress/actions.d.ts.map +1 -1
- package/dist/progress/actions.js +86 -110
- package/dist/progress/actions.js.map +1 -1
- package/dist/progress/routes.d.ts +1 -1
- package/dist/progress/routes.js +1 -1
- package/dist/scripts/agent-engines/list-agent-engines.js +1 -1
- package/dist/scripts/agent-engines/list-agent-engines.js.map +1 -1
- package/dist/scripts/agent-engines/manage-agent-engine.d.ts +10 -0
- package/dist/scripts/agent-engines/manage-agent-engine.d.ts.map +1 -0
- package/dist/scripts/agent-engines/manage-agent-engine.js +47 -0
- package/dist/scripts/agent-engines/manage-agent-engine.js.map +1 -0
- package/dist/scripts/agent-engines/set-agent-engine.js +2 -2
- package/dist/scripts/agent-engines/set-agent-engine.js.map +1 -1
- package/dist/server/agent-chat-plugin.d.ts +39 -0
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +707 -443
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/agent-teams.js +1 -1
- package/dist/server/agent-teams.js.map +1 -1
- package/dist/server/analytics.d.ts +5 -6
- package/dist/server/analytics.d.ts.map +1 -1
- package/dist/server/analytics.js +6 -14
- package/dist/server/analytics.js.map +1 -1
- package/dist/server/app-name.d.ts +5 -2
- package/dist/server/app-name.d.ts.map +1 -1
- package/dist/server/app-name.js +14 -3
- package/dist/server/app-name.js.map +1 -1
- package/dist/server/app-url.d.ts.map +1 -1
- package/dist/server/app-url.js +10 -1
- package/dist/server/app-url.js.map +1 -1
- package/dist/server/auth.d.ts +2 -0
- package/dist/server/auth.d.ts.map +1 -1
- package/dist/server/auth.js +153 -2
- package/dist/server/auth.js.map +1 -1
- package/dist/server/better-auth-instance.d.ts +2 -0
- package/dist/server/better-auth-instance.d.ts.map +1 -1
- package/dist/server/better-auth-instance.js +4 -0
- package/dist/server/better-auth-instance.js.map +1 -1
- package/dist/server/builder-browser.d.ts +59 -1
- package/dist/server/builder-browser.d.ts.map +1 -1
- package/dist/server/builder-browser.js +127 -11
- package/dist/server/builder-browser.js.map +1 -1
- package/dist/server/core-routes-plugin.d.ts.map +1 -1
- package/dist/server/core-routes-plugin.js +208 -6
- package/dist/server/core-routes-plugin.js.map +1 -1
- package/dist/server/credential-provider.d.ts +7 -0
- package/dist/server/credential-provider.d.ts.map +1 -1
- package/dist/server/credential-provider.js +10 -0
- package/dist/server/credential-provider.js.map +1 -1
- package/dist/server/onboarding-html.d.ts.map +1 -1
- package/dist/server/onboarding-html.js +29 -4
- package/dist/server/onboarding-html.js.map +1 -1
- package/dist/server/poll.d.ts.map +1 -1
- package/dist/server/poll.js +46 -5
- package/dist/server/poll.js.map +1 -1
- package/dist/server/ssr-handler.d.ts.map +1 -1
- package/dist/server/ssr-handler.js +2 -1
- package/dist/server/ssr-handler.js.map +1 -1
- package/dist/server/transcribe-voice.d.ts.map +1 -1
- package/dist/server/transcribe-voice.js +44 -5
- package/dist/server/transcribe-voice.js.map +1 -1
- package/dist/styles/agent-native.css +11 -2
- package/dist/templates/default/.agents/skills/progress/SKILL.md +14 -12
- package/dist/templates/default/app/root.tsx +7 -0
- package/dist/transcription/builder-transcription.d.ts +27 -0
- package/dist/transcription/builder-transcription.d.ts.map +1 -0
- package/dist/transcription/builder-transcription.js +41 -0
- package/dist/transcription/builder-transcription.js.map +1 -0
- package/dist/triggers/actions.d.ts +3 -0
- package/dist/triggers/actions.d.ts.map +1 -1
- package/dist/triggers/actions.js +189 -213
- package/dist/triggers/actions.js.map +1 -1
- package/docs/content/agent-mentions.md +1 -1
- package/docs/content/automations.md +22 -19
- package/docs/content/cloneable-saas.md +2 -2
- package/docs/content/deployment.md +21 -61
- package/docs/content/getting-started.md +1 -1
- package/docs/content/key-concepts.md +1 -1
- package/docs/content/{enterprise-workspace.md → multi-app-workspace.md} +3 -3
- package/docs/content/multi-tenancy.md +1 -1
- package/docs/content/progress.md +11 -11
- package/docs/content/template-dispatch.md +3 -3
- package/docs/content/workspace-management.md +1 -1
- package/package.json +9 -2
- package/src/templates/default/.agents/skills/progress/SKILL.md +14 -12
- package/src/templates/default/app/root.tsx +7 -0
|
@@ -1,4 +1,14 @@
|
|
|
1
1
|
import type { H3Event } from "h3";
|
|
2
|
+
export declare const BUILDER_CALLBACK_PATH = "/_agent-native/builder/callback";
|
|
3
|
+
/**
|
|
4
|
+
* Query-param name carrying the signed CSRF state on the connect→callback
|
|
5
|
+
* round-trip. Prefixed with `_an_` to avoid collisions if Builder ever
|
|
6
|
+
* adds standard OAuth `state` support to cli-auth. Builder preserves
|
|
7
|
+
* the path/query of `redirect_url` verbatim when redirecting back, so
|
|
8
|
+
* we embed `_an_state=…` inside the redirect_url query string at
|
|
9
|
+
* connect time and read it back on the callback.
|
|
10
|
+
*/
|
|
11
|
+
export declare const BUILDER_STATE_PARAM = "_an_state";
|
|
2
12
|
export interface BuilderBrowserStatus {
|
|
3
13
|
configured: boolean;
|
|
4
14
|
builderEnabled: boolean;
|
|
@@ -19,11 +29,59 @@ export interface BrowserConnectionArgs {
|
|
|
19
29
|
proxyDefaultOrigin?: string;
|
|
20
30
|
proxyDestination?: string;
|
|
21
31
|
}
|
|
32
|
+
/**
|
|
33
|
+
* Mint a signed CSRF state token bound to the current session's email
|
|
34
|
+
* and a fresh nonce. Round-trips through Builder's cli-auth flow inside
|
|
35
|
+
* the redirect_url query string and is verified on the callback before
|
|
36
|
+
* any keys are written.
|
|
37
|
+
*
|
|
38
|
+
* Why bind to email: it's the only stable, universally-available
|
|
39
|
+
* identity field across all auth modes (Better Auth, BYOA, AUTH_MODE=local).
|
|
40
|
+
* Binding to the session token instead would put the cookie value in a
|
|
41
|
+
* URL that may end up in server logs / browser history.
|
|
42
|
+
*/
|
|
43
|
+
export declare function signBuilderCallbackState(sessionEmail: string): string;
|
|
44
|
+
/**
|
|
45
|
+
* Verify a state token produced by `signBuilderCallbackState`. Returns
|
|
46
|
+
* false on any malformed, forged, expired, or cross-session token.
|
|
47
|
+
*/
|
|
48
|
+
export declare function verifyBuilderCallbackState(token: string | null | undefined, sessionEmail: string): boolean;
|
|
22
49
|
export declare function getBuilderAppHost(): string;
|
|
23
50
|
export declare function getBuilderApiHost(): string;
|
|
51
|
+
/**
|
|
52
|
+
* Build the Builder cli-auth URL for the connect popup. When a signed
|
|
53
|
+
* `state` token is supplied it is embedded inside the `redirect_url`
|
|
54
|
+
* query string so it survives Builder's redirect verbatim — Builder
|
|
55
|
+
* preserves the redirect_url's existing query when appending p-key /
|
|
56
|
+
* api-key / etc., so we don't depend on Builder echoing a top-level
|
|
57
|
+
* `state` parameter (it doesn't).
|
|
58
|
+
*
|
|
59
|
+
* The user-facing connect entry point is `/_agent-native/builder/connect`
|
|
60
|
+
* (a server-side 302). Status / chat-card responses surface that path
|
|
61
|
+
* rather than the cli-auth URL directly, so the 302 handler can mint a
|
|
62
|
+
* fresh state bound to the current session on every click.
|
|
63
|
+
*/
|
|
64
|
+
export declare function buildBuilderCliAuthUrl(origin: string, state?: string | null): string;
|
|
65
|
+
/**
|
|
66
|
+
* The URL surfaced to clients (chat card, settings panels, status
|
|
67
|
+
* endpoint) as `connectUrl`. Pointing every entry point at our local 302
|
|
68
|
+
* means the cli-auth URL — and the CSRF state token bound to the current
|
|
69
|
+
* session — are minted server-side at click time, instead of being baked
|
|
70
|
+
* into a status response that may be cached or rendered for a different
|
|
71
|
+
* session.
|
|
72
|
+
*/
|
|
24
73
|
export declare function getBuilderBrowserConnectUrl(origin: string): string;
|
|
25
74
|
export declare function getBuilderBrowserStatus(origin: string): BuilderBrowserStatus;
|
|
26
75
|
export declare function getBuilderBrowserStatusForEvent(event: H3Event): BuilderBrowserStatus;
|
|
76
|
+
/**
|
|
77
|
+
* Env vars written by the Builder CLI-auth callback. Single source of truth
|
|
78
|
+
* for the connect/disconnect key set — `getBuilderCallbackEnvVars` and the
|
|
79
|
+
* disconnect handler's scrub loop both derive from this list, so drift
|
|
80
|
+
* (e.g. disconnect silently leaving `BUILDER_USER_ID` behind because
|
|
81
|
+
* someone added a key to one site but not the other) is impossible.
|
|
82
|
+
*/
|
|
83
|
+
export declare const BUILDER_ENV_KEYS: readonly ["BUILDER_PRIVATE_KEY", "BUILDER_PUBLIC_KEY", "BUILDER_USER_ID", "BUILDER_ORG_NAME", "BUILDER_ORG_KIND"];
|
|
84
|
+
export type BuilderEnvKey = (typeof BUILDER_ENV_KEYS)[number];
|
|
27
85
|
export declare function getBuilderCallbackEnvVars(params: {
|
|
28
86
|
privateKey?: string | null;
|
|
29
87
|
publicKey?: string | null;
|
|
@@ -31,7 +89,7 @@ export declare function getBuilderCallbackEnvVars(params: {
|
|
|
31
89
|
orgName?: string | null;
|
|
32
90
|
orgKind?: string | null;
|
|
33
91
|
}): {
|
|
34
|
-
key:
|
|
92
|
+
key: "BUILDER_PRIVATE_KEY" | "BUILDER_ORG_NAME" | "BUILDER_PUBLIC_KEY" | "BUILDER_USER_ID" | "BUILDER_ORG_KIND";
|
|
35
93
|
value: string;
|
|
36
94
|
}[];
|
|
37
95
|
export declare function resolveSafePreviewUrl(previewUrl: string | null | undefined, event: H3Event): string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"builder-browser.d.ts","sourceRoot":"","sources":["../../src/server/builder-browser.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"builder-browser.d.ts","sourceRoot":"","sources":["../../src/server/builder-browser.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,8 +1,80 @@
|
|
|
1
|
+
import { createHmac, randomBytes, timingSafeEqual } from "node:crypto";
|
|
2
|
+
import { getAuthSecret } from "./better-auth-instance.js";
|
|
1
3
|
import { getOrigin } from "./google-oauth.js";
|
|
2
4
|
const DEFAULT_BUILDER_APP_HOST = "https://builder.io";
|
|
3
5
|
const DEFAULT_BUILDER_API_HOST = "https://api.builder.io";
|
|
4
6
|
const BUILDER_BROWSER_HOST = "agent-native-browser";
|
|
5
7
|
const BUILDER_BROWSER_CLIENT_ID = "Agent Native Browser";
|
|
8
|
+
export const BUILDER_CALLBACK_PATH = "/_agent-native/builder/callback";
|
|
9
|
+
/**
|
|
10
|
+
* Query-param name carrying the signed CSRF state on the connect→callback
|
|
11
|
+
* round-trip. Prefixed with `_an_` to avoid collisions if Builder ever
|
|
12
|
+
* adds standard OAuth `state` support to cli-auth. Builder preserves
|
|
13
|
+
* the path/query of `redirect_url` verbatim when redirecting back, so
|
|
14
|
+
* we embed `_an_state=…` inside the redirect_url query string at
|
|
15
|
+
* connect time and read it back on the callback.
|
|
16
|
+
*/
|
|
17
|
+
export const BUILDER_STATE_PARAM = "_an_state";
|
|
18
|
+
const BUILDER_STATE_TTL_MS = 10 * 60 * 1000;
|
|
19
|
+
function macForParts(nonce, emailEncoded, ts) {
|
|
20
|
+
return createHmac("sha256", `builder-csrf:${getAuthSecret()}`)
|
|
21
|
+
.update(`${nonce}.${emailEncoded}.${ts}`)
|
|
22
|
+
.digest("base64url");
|
|
23
|
+
}
|
|
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) {
|
|
36
|
+
const nonce = randomBytes(16).toString("base64url");
|
|
37
|
+
const ts = Date.now();
|
|
38
|
+
const emailEncoded = Buffer.from(sessionEmail, "utf8").toString("base64url");
|
|
39
|
+
const mac = macForParts(nonce, emailEncoded, ts);
|
|
40
|
+
return `${nonce}.${emailEncoded}.${ts}.${mac}`;
|
|
41
|
+
}
|
|
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) {
|
|
47
|
+
if (typeof token !== "string" || token.length === 0)
|
|
48
|
+
return false;
|
|
49
|
+
const parts = token.split(".");
|
|
50
|
+
if (parts.length !== 4)
|
|
51
|
+
return false;
|
|
52
|
+
const [nonce, emailEncoded, tsStr, mac] = parts;
|
|
53
|
+
if (!nonce || !emailEncoded || !tsStr || !mac)
|
|
54
|
+
return false;
|
|
55
|
+
let boundEmail;
|
|
56
|
+
try {
|
|
57
|
+
boundEmail = Buffer.from(emailEncoded, "base64url").toString("utf8");
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
if (boundEmail !== sessionEmail)
|
|
63
|
+
return false;
|
|
64
|
+
const ts = Number(tsStr);
|
|
65
|
+
if (!Number.isFinite(ts))
|
|
66
|
+
return false;
|
|
67
|
+
// Reject expired AND far-future timestamps — a clock-skew attacker
|
|
68
|
+
// (or a bug that mints states with `ts` in the future) shouldn't get
|
|
69
|
+
// an arbitrarily-long-lived token.
|
|
70
|
+
if (Math.abs(Date.now() - ts) > BUILDER_STATE_TTL_MS)
|
|
71
|
+
return false;
|
|
72
|
+
const expected = Buffer.from(macForParts(nonce, emailEncoded, ts));
|
|
73
|
+
const candidate = Buffer.from(mac);
|
|
74
|
+
if (expected.length !== candidate.length)
|
|
75
|
+
return false;
|
|
76
|
+
return timingSafeEqual(expected, candidate);
|
|
77
|
+
}
|
|
6
78
|
function isAllowedBrowserReturnUrl(urlString) {
|
|
7
79
|
try {
|
|
8
80
|
const parsed = new URL(urlString);
|
|
@@ -12,7 +84,9 @@ function isAllowedBrowserReturnUrl(urlString) {
|
|
|
12
84
|
hostname === "127.0.0.1" ||
|
|
13
85
|
hostname === "[::1]";
|
|
14
86
|
const isBuilderDomain = hostname === "builder.io" || hostname.endsWith(".builder.io");
|
|
15
|
-
|
|
87
|
+
const isAgentNativeDomain = hostname === "agent-native.com" || hostname.endsWith(".agent-native.com");
|
|
88
|
+
return (isAllowedProtocol &&
|
|
89
|
+
(isLocalhost || isBuilderDomain || isAgentNativeDomain));
|
|
16
90
|
}
|
|
17
91
|
catch {
|
|
18
92
|
return false;
|
|
@@ -32,18 +106,45 @@ export function getBuilderApiHost() {
|
|
|
32
106
|
process.env.BUILDER_API_HOST ||
|
|
33
107
|
DEFAULT_BUILDER_API_HOST);
|
|
34
108
|
}
|
|
35
|
-
|
|
109
|
+
/**
|
|
110
|
+
* Build the Builder cli-auth URL for the connect popup. When a signed
|
|
111
|
+
* `state` token is supplied it is embedded inside the `redirect_url`
|
|
112
|
+
* query string so it survives Builder's redirect verbatim — Builder
|
|
113
|
+
* preserves the redirect_url's existing query when appending p-key /
|
|
114
|
+
* api-key / etc., so we don't depend on Builder echoing a top-level
|
|
115
|
+
* `state` parameter (it doesn't).
|
|
116
|
+
*
|
|
117
|
+
* The user-facing connect entry point is `/_agent-native/builder/connect`
|
|
118
|
+
* (a server-side 302). Status / chat-card responses surface that path
|
|
119
|
+
* rather than the cli-auth URL directly, so the 302 handler can mint a
|
|
120
|
+
* fresh state bound to the current session on every click.
|
|
121
|
+
*/
|
|
122
|
+
export function buildBuilderCliAuthUrl(origin, state = null) {
|
|
36
123
|
const normalizedOrigin = normalizeOrigin(origin);
|
|
37
|
-
const callbackUrl =
|
|
124
|
+
const callbackUrl = new URL(BUILDER_CALLBACK_PATH, normalizedOrigin);
|
|
125
|
+
if (state) {
|
|
126
|
+
callbackUrl.searchParams.set(BUILDER_STATE_PARAM, state);
|
|
127
|
+
}
|
|
38
128
|
const url = new URL("/cli-auth", getBuilderAppHost());
|
|
39
129
|
url.searchParams.set("response_type", "code");
|
|
40
130
|
url.searchParams.set("host", BUILDER_BROWSER_HOST);
|
|
41
131
|
url.searchParams.set("client_id", BUILDER_BROWSER_CLIENT_ID);
|
|
42
|
-
url.searchParams.set("redirect_url", callbackUrl);
|
|
132
|
+
url.searchParams.set("redirect_url", callbackUrl.toString());
|
|
43
133
|
url.searchParams.set("preview_url", normalizedOrigin);
|
|
44
134
|
url.searchParams.set("framework", "agent-native");
|
|
45
135
|
return url.toString();
|
|
46
136
|
}
|
|
137
|
+
/**
|
|
138
|
+
* The URL surfaced to clients (chat card, settings panels, status
|
|
139
|
+
* endpoint) as `connectUrl`. Pointing every entry point at our local 302
|
|
140
|
+
* means the cli-auth URL — and the CSRF state token bound to the current
|
|
141
|
+
* session — are minted server-side at click time, instead of being baked
|
|
142
|
+
* into a status response that may be cached or rendered for a different
|
|
143
|
+
* session.
|
|
144
|
+
*/
|
|
145
|
+
export function getBuilderBrowserConnectUrl(origin) {
|
|
146
|
+
return `${normalizeOrigin(origin)}/_agent-native/builder/connect`;
|
|
147
|
+
}
|
|
47
148
|
export function getBuilderBrowserStatus(origin) {
|
|
48
149
|
return {
|
|
49
150
|
configured: !!(process.env.BUILDER_PRIVATE_KEY && process.env.BUILDER_PUBLIC_KEY),
|
|
@@ -61,14 +162,29 @@ export function getBuilderBrowserStatus(origin) {
|
|
|
61
162
|
export function getBuilderBrowserStatusForEvent(event) {
|
|
62
163
|
return getBuilderBrowserStatus(getOrigin(event));
|
|
63
164
|
}
|
|
165
|
+
/**
|
|
166
|
+
* Env vars written by the Builder CLI-auth callback. Single source of truth
|
|
167
|
+
* for the connect/disconnect key set — `getBuilderCallbackEnvVars` and the
|
|
168
|
+
* disconnect handler's scrub loop both derive from this list, so drift
|
|
169
|
+
* (e.g. disconnect silently leaving `BUILDER_USER_ID` behind because
|
|
170
|
+
* someone added a key to one site but not the other) is impossible.
|
|
171
|
+
*/
|
|
172
|
+
export const BUILDER_ENV_KEYS = [
|
|
173
|
+
"BUILDER_PRIVATE_KEY",
|
|
174
|
+
"BUILDER_PUBLIC_KEY",
|
|
175
|
+
"BUILDER_USER_ID",
|
|
176
|
+
"BUILDER_ORG_NAME",
|
|
177
|
+
"BUILDER_ORG_KIND",
|
|
178
|
+
];
|
|
64
179
|
export function getBuilderCallbackEnvVars(params) {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
180
|
+
const values = {
|
|
181
|
+
BUILDER_PRIVATE_KEY: params.privateKey?.trim() || "",
|
|
182
|
+
BUILDER_PUBLIC_KEY: params.publicKey?.trim() || "",
|
|
183
|
+
BUILDER_USER_ID: params.userId?.trim() || "",
|
|
184
|
+
BUILDER_ORG_NAME: params.orgName?.trim() || "",
|
|
185
|
+
BUILDER_ORG_KIND: params.orgKind?.trim() || "",
|
|
186
|
+
};
|
|
187
|
+
return BUILDER_ENV_KEYS.map((key) => ({ key, value: values[key] }));
|
|
72
188
|
}
|
|
73
189
|
export function resolveSafePreviewUrl(previewUrl, event) {
|
|
74
190
|
if (previewUrl && isAllowedBrowserReturnUrl(previewUrl)) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"builder-browser.js","sourceRoot":"","sources":["../../src/server/builder-browser.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"builder-browser.js","sourceRoot":"","sources":["../../src/server/builder-browser.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"core-routes-plugin.d.ts","sourceRoot":"","sources":["../../src/server/core-routes-plugin.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"core-routes-plugin.d.ts","sourceRoot":"","sources":["../../src/server/core-routes-plugin.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAuDvD;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,mBAAmB,CAAC;AAEvD,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;CAC1B;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,GAAE,uBAA4B,GACpC,cAAc,CA4gChB;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,uBAAuB,EAAE,cAAyC,CAAC"}
|
|
@@ -5,7 +5,7 @@ import { createPollHandler } from "./poll.js";
|
|
|
5
5
|
import { createSSEHandler } from "./sse.js";
|
|
6
6
|
import { upsertEnvFile } from "./create-server.js";
|
|
7
7
|
import { readBody } from "./h3-helpers.js";
|
|
8
|
-
import { createBuilderBrowserCallbackPage, getBuilderBrowserStatusForEvent, getBuilderCallbackEnvVars, resolveSafePreviewUrl, runBuilderAgent, } from "./builder-browser.js";
|
|
8
|
+
import { BUILDER_ENV_KEYS, BUILDER_STATE_PARAM, buildBuilderCliAuthUrl, createBuilderBrowserCallbackPage, getBuilderBrowserStatusForEvent, getBuilderCallbackEnvVars, resolveSafePreviewUrl, runBuilderAgent, signBuilderCallbackState, verifyBuilderCallbackState, } from "./builder-browser.js";
|
|
9
9
|
import { getState, putState, deleteState, listComposeDrafts, getComposeDraft, putComposeDraft, deleteComposeDraft, deleteAllComposeDrafts, } from "../application-state/handlers.js";
|
|
10
10
|
import { getSetting, putSetting, deleteSetting } from "../settings/store.js";
|
|
11
11
|
import { getSession } from "./auth.js";
|
|
@@ -55,12 +55,57 @@ export function createCoreRoutesPlugin(options = {}) {
|
|
|
55
55
|
// No-op when called from inside the bootstrap (auto-mount path).
|
|
56
56
|
// Otherwise wait so other default plugins finish mounting first.
|
|
57
57
|
await awaitBootstrap(nitroApp);
|
|
58
|
+
// Restore env vars from the settings table. On serverless, .env
|
|
59
|
+
// writes don't persist across invocations — the DB is the durable
|
|
60
|
+
// store. Only set keys that are currently empty so explicit env
|
|
61
|
+
// vars (Netlify dashboard, process-level) always win.
|
|
62
|
+
try {
|
|
63
|
+
const persisted = (await getSetting("persisted-env-vars"));
|
|
64
|
+
if (persisted) {
|
|
65
|
+
for (const [k, v] of Object.entries(persisted)) {
|
|
66
|
+
if (typeof v === "string" && !process.env[k]) {
|
|
67
|
+
process.env[k] = v;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
// DB not ready yet — skip
|
|
74
|
+
}
|
|
75
|
+
// Honor Builder disconnect. Nitro's dev env-runner preserves
|
|
76
|
+
// `process.env` across `.env` file reloads inside the same worker, so
|
|
77
|
+
// deleting BUILDER_PRIVATE_KEY in the disconnect handler can bleed
|
|
78
|
+
// back through an env-runner restart. We persist a
|
|
79
|
+
// `builder-disconnected` flag in SQL and scrub BUILDER_* on every
|
|
80
|
+
// plugin init while the flag is set. The flag is cleared by the
|
|
81
|
+
// Builder cli-auth callback when the user re-connects.
|
|
82
|
+
try {
|
|
83
|
+
const disconnected = (await getSetting("builder-disconnected"));
|
|
84
|
+
if (disconnected) {
|
|
85
|
+
for (const key of BUILDER_ENV_KEYS) {
|
|
86
|
+
delete process.env[key];
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
// DB not ready — skip; the disconnect flag will be enforced on the
|
|
92
|
+
// next plugin boot once the settings table is reachable.
|
|
93
|
+
}
|
|
58
94
|
// Register framework-level secrets (OPENAI_API_KEY for composer voice
|
|
59
95
|
// transcription, etc.). Each registration is guarded so templates that
|
|
60
96
|
// already registered the same key win.
|
|
61
97
|
registerFrameworkSecrets();
|
|
62
98
|
registerBuiltinProviders();
|
|
63
99
|
registerBuiltinNotificationChannels();
|
|
100
|
+
try {
|
|
101
|
+
const { createObservabilityHandler } = await import("../observability/routes.js");
|
|
102
|
+
const { ensureObservabilityTables } = await import("../observability/store.js");
|
|
103
|
+
ensureObservabilityTables().catch(() => { });
|
|
104
|
+
getH3App(nitroApp).use(`${FRAMEWORK_ROUTE_PREFIX}/observability`, createObservabilityHandler());
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
// Observability module not available — skip
|
|
108
|
+
}
|
|
64
109
|
const P = FRAMEWORK_ROUTE_PREFIX;
|
|
65
110
|
// CORS for framework routes. Desktop tray apps (Tauri/Electron) run on
|
|
66
111
|
// their own dev origin (e.g. localhost:1420) and make credentialed
|
|
@@ -110,15 +155,46 @@ export function createCoreRoutesPlugin(options = {}) {
|
|
|
110
155
|
message: process.env.PING_MESSAGE ?? "pong",
|
|
111
156
|
})));
|
|
112
157
|
}
|
|
113
|
-
getH3App(nitroApp).use(`${P}/builder/status`, defineEventHandler((event) =>
|
|
158
|
+
getH3App(nitroApp).use(`${P}/builder/status`, defineEventHandler(async (event) => {
|
|
159
|
+
const status = getBuilderBrowserStatusForEvent(event);
|
|
160
|
+
// Honor the SQL disconnect flag even when process.env still has
|
|
161
|
+
// BUILDER_* (dev env-runner weirdness — see plugin init above).
|
|
162
|
+
try {
|
|
163
|
+
const disconnected = await getSetting("builder-disconnected");
|
|
164
|
+
if (disconnected) {
|
|
165
|
+
return {
|
|
166
|
+
...status,
|
|
167
|
+
configured: false,
|
|
168
|
+
privateKeyConfigured: false,
|
|
169
|
+
publicKeyConfigured: false,
|
|
170
|
+
userId: undefined,
|
|
171
|
+
orgName: undefined,
|
|
172
|
+
orgKind: undefined,
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
catch {
|
|
177
|
+
// DB not reachable — fall back to env-only status.
|
|
178
|
+
}
|
|
179
|
+
return status;
|
|
180
|
+
}));
|
|
114
181
|
// Lightweight 302 to the Builder CLI-auth URL. Lets clients do
|
|
115
182
|
// `window.open('/_agent-native/builder/connect', '_blank')` synchronously
|
|
116
183
|
// inside a click handler, avoiding the popup-blocker downgrade that
|
|
117
|
-
// happens when an await sits before window.open.
|
|
118
|
-
|
|
119
|
-
|
|
184
|
+
// happens when an await sits before window.open. We mint a signed
|
|
185
|
+
// CSRF state here and embed it in the callback URL we hand to
|
|
186
|
+
// Builder; the callback handler verifies it before accepting any
|
|
187
|
+
// keys. See `signBuilderCallbackState` for the threat model.
|
|
188
|
+
getH3App(nitroApp).use(`${P}/builder/connect`, defineEventHandler(async (event) => {
|
|
189
|
+
const session = await getSession(event).catch(() => null);
|
|
190
|
+
if (!session?.email) {
|
|
191
|
+
setResponseStatus(event, 401);
|
|
192
|
+
return { error: "Authentication required" };
|
|
193
|
+
}
|
|
194
|
+
const state = signBuilderCallbackState(session.email);
|
|
195
|
+
const cliAuthUrl = buildBuilderCliAuthUrl(getOrigin(event), state);
|
|
120
196
|
setResponseStatus(event, 302);
|
|
121
|
-
setResponseHeader(event, "Location",
|
|
197
|
+
setResponseHeader(event, "Location", cliAuthUrl);
|
|
122
198
|
return "";
|
|
123
199
|
}));
|
|
124
200
|
// Hardcoded for the early preview — later this will come from workspace/org
|
|
@@ -182,7 +258,22 @@ export function createCoreRoutesPlugin(options = {}) {
|
|
|
182
258
|
setResponseStatus(event, 405);
|
|
183
259
|
return { error: "Method not allowed" };
|
|
184
260
|
}
|
|
261
|
+
// Session blocks anonymous callers; the signed state below blocks
|
|
262
|
+
// CSRF (session cookies are SameSite=None;Secure for the iframe
|
|
263
|
+
// editor, so they ride along on attacker-crafted top-level links).
|
|
264
|
+
const session = await getSession(event).catch(() => null);
|
|
265
|
+
if (!session?.email) {
|
|
266
|
+
setResponseStatus(event, 401);
|
|
267
|
+
return { error: "Authentication required" };
|
|
268
|
+
}
|
|
185
269
|
const requestUrl = new URL(`${event.url?.pathname || "/"}${event.url?.search || ""}`, getOrigin(event));
|
|
270
|
+
const state = requestUrl.searchParams.get(BUILDER_STATE_PARAM);
|
|
271
|
+
if (!verifyBuilderCallbackState(state, session.email)) {
|
|
272
|
+
setResponseStatus(event, 403);
|
|
273
|
+
return {
|
|
274
|
+
error: "Invalid or expired connect token. Restart the Builder connect flow from Settings.",
|
|
275
|
+
};
|
|
276
|
+
}
|
|
186
277
|
const privateKey = requestUrl.searchParams.get("p-key");
|
|
187
278
|
const publicKey = requestUrl.searchParams.get("api-key");
|
|
188
279
|
if (!privateKey || !publicKey) {
|
|
@@ -196,6 +287,16 @@ export function createCoreRoutesPlugin(options = {}) {
|
|
|
196
287
|
orgName: requestUrl.searchParams.get("org-name"),
|
|
197
288
|
orgKind: requestUrl.searchParams.get("kind"),
|
|
198
289
|
});
|
|
290
|
+
// Clear the disconnect flag first — a prior disconnect would
|
|
291
|
+
// otherwise cause the plugin init to scrub these keys right back
|
|
292
|
+
// out on the next env-runner reload.
|
|
293
|
+
try {
|
|
294
|
+
await deleteSetting("builder-disconnected");
|
|
295
|
+
}
|
|
296
|
+
catch {
|
|
297
|
+
// DB not ready — proceed; the worst case is a stale disconnect
|
|
298
|
+
// flag that gets cleared on the next reconnect attempt.
|
|
299
|
+
}
|
|
199
300
|
// Prefer the workspace root .env when in an enterprise workspace so
|
|
200
301
|
// Builder credentials are shared across every app automatically.
|
|
201
302
|
try {
|
|
@@ -211,10 +312,96 @@ export function createCoreRoutesPlugin(options = {}) {
|
|
|
211
312
|
for (const { key, value } of vars) {
|
|
212
313
|
process.env[key] = value;
|
|
213
314
|
}
|
|
315
|
+
// Persist to settings table so serverless cold starts can
|
|
316
|
+
// restore credentials (.env writes don't survive on Netlify).
|
|
317
|
+
try {
|
|
318
|
+
const envMap = {};
|
|
319
|
+
for (const { key, value } of vars)
|
|
320
|
+
envMap[key] = value;
|
|
321
|
+
const existing = (await getSetting("persisted-env-vars")) ?? {};
|
|
322
|
+
await putSetting("persisted-env-vars", { ...existing, ...envMap });
|
|
323
|
+
}
|
|
324
|
+
catch {
|
|
325
|
+
// DB not ready yet — skip
|
|
326
|
+
}
|
|
214
327
|
const previewUrl = resolveSafePreviewUrl(requestUrl.searchParams.get("preview-url"), event);
|
|
215
328
|
setResponseHeader(event, "Content-Type", "text/html; charset=utf-8");
|
|
216
329
|
return createBuilderBrowserCallbackPage(previewUrl);
|
|
217
330
|
}));
|
|
331
|
+
// POST /_agent-native/builder/disconnect — revoke the stored Builder
|
|
332
|
+
// credentials so the next turn falls back to BYO / env detection. Mirrors
|
|
333
|
+
// the callback handler's three write locations: the template `.env` file,
|
|
334
|
+
// the in-process `process.env`, and the `persisted-env-vars` settings row
|
|
335
|
+
// (rehydrated on serverless cold starts). All three must be cleared to
|
|
336
|
+
// avoid a "still connected after disconnect" state on restart.
|
|
337
|
+
getH3App(nitroApp).use(`${P}/builder/disconnect`, defineEventHandler(async (event) => {
|
|
338
|
+
if (getMethod(event) !== "POST") {
|
|
339
|
+
setResponseStatus(event, 405);
|
|
340
|
+
return { error: "Method not allowed" };
|
|
341
|
+
}
|
|
342
|
+
const session = await getSession(event).catch(() => null);
|
|
343
|
+
if (!session?.email) {
|
|
344
|
+
setResponseStatus(event, 401);
|
|
345
|
+
return { error: "unauthorized" };
|
|
346
|
+
}
|
|
347
|
+
// We intentionally do NOT rewrite the `.env` file on disconnect.
|
|
348
|
+
// A `.env` write triggers nitro's file watcher → env-runner
|
|
349
|
+
// restart, which tears down in-flight SSE / HMR connections and
|
|
350
|
+
// surfaces as `read ECONNRESET` in the vite overlay. The
|
|
351
|
+
// authoritative disconnect signal is the SQL `builder-disconnected`
|
|
352
|
+
// flag (checked in plugin init, the status endpoint, and the
|
|
353
|
+
// Builder engine before any gateway call). `.env` keys, if any
|
|
354
|
+
// survive, are neutered by the flag-driven scrub in plugin init.
|
|
355
|
+
// 1. Write the disconnect flag. This is load-bearing — every
|
|
356
|
+
// subsequent check (plugin init scrub, /builder/status override,
|
|
357
|
+
// BuilderEngine.stream short-circuit) reads this flag. If the
|
|
358
|
+
// write fails, we FAIL HARD: clearing process.env without
|
|
359
|
+
// persisting the flag means the next env-runner reload would
|
|
360
|
+
// silently restore BUILDER_* from whatever inherited env the
|
|
361
|
+
// worker was spawned with, and the user would see "Disconnected"
|
|
362
|
+
// in the UI that flips back to "Connected" moments later.
|
|
363
|
+
try {
|
|
364
|
+
await putSetting("builder-disconnected", { at: Date.now() });
|
|
365
|
+
}
|
|
366
|
+
catch (err) {
|
|
367
|
+
setResponseStatus(event, 500);
|
|
368
|
+
return {
|
|
369
|
+
ok: false,
|
|
370
|
+
error: "Could not persist disconnect flag — your Builder connection is unchanged. Please retry.",
|
|
371
|
+
cause: err instanceof Error ? err.message : String(err),
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
// 2. Scrub the persisted-env-vars row so serverless cold starts
|
|
375
|
+
// don't rehydrate BUILDER_* from SQL. Best-effort: the disconnect
|
|
376
|
+
// flag above already prevents Builder from being used; this is
|
|
377
|
+
// cleanup.
|
|
378
|
+
let warnPersisted;
|
|
379
|
+
try {
|
|
380
|
+
const existing = (await getSetting("persisted-env-vars")) ?? {};
|
|
381
|
+
const cleaned = {};
|
|
382
|
+
for (const [k, v] of Object.entries(existing)) {
|
|
383
|
+
if (!BUILDER_ENV_KEYS.includes(k))
|
|
384
|
+
cleaned[k] = v;
|
|
385
|
+
}
|
|
386
|
+
await putSetting("persisted-env-vars", cleaned);
|
|
387
|
+
}
|
|
388
|
+
catch (err) {
|
|
389
|
+
warnPersisted = err instanceof Error ? err.message : String(err);
|
|
390
|
+
}
|
|
391
|
+
// 3. Clear in-process env vars so the current worker stops routing
|
|
392
|
+
// through Builder immediately. Nitro's env-runner may re-populate
|
|
393
|
+
// these across a module reload, but by then the `builder-disconnected`
|
|
394
|
+
// flag will be enforced at the plugin-init scrub.
|
|
395
|
+
for (const key of BUILDER_ENV_KEYS) {
|
|
396
|
+
delete process.env[key];
|
|
397
|
+
}
|
|
398
|
+
return {
|
|
399
|
+
ok: true,
|
|
400
|
+
...(warnPersisted
|
|
401
|
+
? { warnings: { persistedEnvVars: warnPersisted } }
|
|
402
|
+
: {}),
|
|
403
|
+
};
|
|
404
|
+
}));
|
|
218
405
|
// Proxy to Builder's agents-run API for background code changes.
|
|
219
406
|
getH3App(nitroApp).use(`${P}/builder/agents-run`, defineEventHandler(async (event) => {
|
|
220
407
|
if (getMethod(event) !== "POST") {
|
|
@@ -266,6 +453,10 @@ export function createCoreRoutesPlugin(options = {}) {
|
|
|
266
453
|
// Env key management — framework keys are always included
|
|
267
454
|
const frameworkEnvKeys = [
|
|
268
455
|
{ key: "ENABLE_BUILDER", label: "Enable Builder.io features" },
|
|
456
|
+
{
|
|
457
|
+
key: "AGENT_ENGINE_PREFER_BYO_KEY",
|
|
458
|
+
label: "Prefer BYO LLM key over Builder gateway (default: false — gateway wins)",
|
|
459
|
+
},
|
|
269
460
|
...Object.values(PROVIDER_ENV_META).map(({ envVar, label }) => ({
|
|
270
461
|
key: envVar,
|
|
271
462
|
label,
|
|
@@ -349,6 +540,17 @@ export function createCoreRoutesPlugin(options = {}) {
|
|
|
349
540
|
for (const { key, value } of filtered) {
|
|
350
541
|
process.env[key] = value;
|
|
351
542
|
}
|
|
543
|
+
// Persist to settings table for serverless cold-start recovery.
|
|
544
|
+
try {
|
|
545
|
+
const envMap = {};
|
|
546
|
+
for (const { key, value } of filtered)
|
|
547
|
+
envMap[key] = value;
|
|
548
|
+
const existing = (await getSetting("persisted-env-vars")) ?? {};
|
|
549
|
+
await putSetting("persisted-env-vars", { ...existing, ...envMap });
|
|
550
|
+
}
|
|
551
|
+
catch {
|
|
552
|
+
// DB not ready yet — skip
|
|
553
|
+
}
|
|
352
554
|
return { saved: filtered.map((v) => v.key) };
|
|
353
555
|
}));
|
|
354
556
|
}
|