@agent-native/core 0.8.2 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -4
- package/dist/agent/engine/builder-engine.d.ts.map +1 -1
- package/dist/agent/engine/builder-engine.js +5 -4
- package/dist/agent/engine/builder-engine.js.map +1 -1
- package/dist/agent/engine/registry.d.ts +6 -3
- package/dist/agent/engine/registry.d.ts.map +1 -1
- package/dist/agent/engine/registry.js +8 -17
- package/dist/agent/engine/registry.js.map +1 -1
- package/dist/agent/production-agent.d.ts +1 -1
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +28 -11
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/agent/run-manager.d.ts +10 -0
- package/dist/agent/run-manager.d.ts.map +1 -1
- package/dist/agent/run-manager.js +89 -7
- package/dist/agent/run-manager.js.map +1 -1
- package/dist/agent/run-store.d.ts +4 -1
- package/dist/agent/run-store.d.ts.map +1 -1
- package/dist/agent/run-store.js +6 -5
- package/dist/agent/run-store.js.map +1 -1
- package/dist/agent/thread-data-builder.d.ts +12 -0
- package/dist/agent/thread-data-builder.d.ts.map +1 -1
- package/dist/agent/thread-data-builder.js +96 -0
- package/dist/agent/thread-data-builder.js.map +1 -1
- package/dist/cli/create.d.ts +9 -0
- package/dist/cli/create.d.ts.map +1 -1
- package/dist/cli/create.js +29 -11
- package/dist/cli/create.js.map +1 -1
- package/dist/cli/index.js +177 -22
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/workspace-dev.js +66 -5
- package/dist/cli/workspace-dev.js.map +1 -1
- package/dist/client/AgentPanel.d.ts.map +1 -1
- package/dist/client/AgentPanel.js +6 -20
- package/dist/client/AgentPanel.js.map +1 -1
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +146 -107
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/agent-chat-adapter.d.ts.map +1 -1
- package/dist/client/agent-chat-adapter.js +143 -22
- package/dist/client/agent-chat-adapter.js.map +1 -1
- package/dist/client/agent-sidebar-state.d.ts +3 -0
- package/dist/client/agent-sidebar-state.d.ts.map +1 -0
- package/dist/client/agent-sidebar-state.js +24 -0
- package/dist/client/agent-sidebar-state.js.map +1 -0
- package/dist/client/analytics.d.ts +39 -0
- package/dist/client/analytics.d.ts.map +1 -1
- package/dist/client/analytics.js +74 -0
- package/dist/client/analytics.js.map +1 -1
- package/dist/client/components/PresenceBar.d.ts.map +1 -1
- package/dist/client/components/PresenceBar.js +21 -15
- package/dist/client/components/PresenceBar.js.map +1 -1
- package/dist/client/components/ui/tooltip.d.ts +2 -1
- package/dist/client/components/ui/tooltip.d.ts.map +1 -1
- package/dist/client/components/ui/tooltip.js +9 -2
- package/dist/client/components/ui/tooltip.js.map +1 -1
- package/dist/client/composer/ComposerPlusMenu.d.ts.map +1 -1
- package/dist/client/composer/ComposerPlusMenu.js +51 -17
- package/dist/client/composer/ComposerPlusMenu.js.map +1 -1
- package/dist/client/composer/PromptComposer.d.ts.map +1 -1
- package/dist/client/composer/PromptComposer.js +30 -0
- package/dist/client/composer/PromptComposer.js.map +1 -1
- package/dist/client/composer/TiptapComposer.d.ts.map +1 -1
- package/dist/client/composer/TiptapComposer.js +31 -5
- package/dist/client/composer/TiptapComposer.js.map +1 -1
- package/dist/client/composer/VoiceButton.d.ts.map +1 -1
- package/dist/client/composer/VoiceButton.js +9 -8
- package/dist/client/composer/VoiceButton.js.map +1 -1
- package/dist/client/dev-overlay/DevOverlay.d.ts.map +1 -1
- package/dist/client/dev-overlay/DevOverlay.js +4 -3
- package/dist/client/dev-overlay/DevOverlay.js.map +1 -1
- package/dist/client/error-format.d.ts.map +1 -1
- package/dist/client/error-format.js +6 -0
- package/dist/client/error-format.js.map +1 -1
- package/dist/client/extensions/EmbeddedExtension.d.ts.map +1 -1
- package/dist/client/extensions/EmbeddedExtension.js +14 -3
- package/dist/client/extensions/EmbeddedExtension.js.map +1 -1
- package/dist/client/extensions/ExtensionEditor.d.ts.map +1 -1
- package/dist/client/extensions/ExtensionEditor.js +6 -5
- package/dist/client/extensions/ExtensionEditor.js.map +1 -1
- package/dist/client/extensions/ExtensionSlot.d.ts.map +1 -1
- package/dist/client/extensions/ExtensionSlot.js +2 -1
- package/dist/client/extensions/ExtensionSlot.js.map +1 -1
- package/dist/client/extensions/ExtensionViewer.d.ts.map +1 -1
- package/dist/client/extensions/ExtensionViewer.js +40 -19
- package/dist/client/extensions/ExtensionViewer.js.map +1 -1
- package/dist/client/extensions/ExtensionsSidebarSection.d.ts.map +1 -1
- package/dist/client/extensions/ExtensionsSidebarSection.js +52 -51
- package/dist/client/extensions/ExtensionsSidebarSection.js.map +1 -1
- package/dist/client/index.d.ts +2 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +2 -1
- package/dist/client/index.js.map +1 -1
- package/dist/client/integrations/IntegrationCard.d.ts.map +1 -1
- package/dist/client/integrations/IntegrationCard.js +2 -1
- package/dist/client/integrations/IntegrationCard.js.map +1 -1
- package/dist/client/integrations/IntegrationsPanel.d.ts.map +1 -1
- package/dist/client/integrations/IntegrationsPanel.js +3 -2
- package/dist/client/integrations/IntegrationsPanel.js.map +1 -1
- package/dist/client/notifications/NotificationsBell.d.ts.map +1 -1
- package/dist/client/notifications/NotificationsBell.js +42 -6
- package/dist/client/notifications/NotificationsBell.js.map +1 -1
- package/dist/client/onboarding/OnboardingPanel.d.ts.map +1 -1
- package/dist/client/onboarding/OnboardingPanel.js +3 -2
- package/dist/client/onboarding/OnboardingPanel.js.map +1 -1
- package/dist/client/onboarding/SetupButton.d.ts.map +1 -1
- package/dist/client/onboarding/SetupButton.js +14 -13
- package/dist/client/onboarding/SetupButton.js.map +1 -1
- package/dist/client/org/InvitationBanner.d.ts +8 -2
- package/dist/client/org/InvitationBanner.d.ts.map +1 -1
- package/dist/client/org/InvitationBanner.js +28 -7
- package/dist/client/org/InvitationBanner.js.map +1 -1
- package/dist/client/org/OrgSwitcher.d.ts.map +1 -1
- package/dist/client/org/OrgSwitcher.js +29 -5
- package/dist/client/org/OrgSwitcher.js.map +1 -1
- package/dist/client/org/TeamPage.d.ts.map +1 -1
- package/dist/client/org/TeamPage.js +9 -7
- package/dist/client/org/TeamPage.js.map +1 -1
- package/dist/client/resources/ResourceEditor.d.ts.map +1 -1
- package/dist/client/resources/ResourceEditor.js +2 -1
- package/dist/client/resources/ResourceEditor.js.map +1 -1
- package/dist/client/resources/ResourcesPanel.d.ts.map +1 -1
- package/dist/client/resources/ResourcesPanel.js +48 -14
- package/dist/client/resources/ResourcesPanel.js.map +1 -1
- package/dist/client/resources/use-mcp-servers.d.ts +2 -0
- package/dist/client/resources/use-mcp-servers.d.ts.map +1 -1
- package/dist/client/resources/use-mcp-servers.js +59 -3
- package/dist/client/resources/use-mcp-servers.js.map +1 -1
- package/dist/client/settings/AgentsSection.d.ts.map +1 -1
- package/dist/client/settings/AgentsSection.js +8 -7
- package/dist/client/settings/AgentsSection.js.map +1 -1
- package/dist/client/settings/AutomationsSection.d.ts.map +1 -1
- package/dist/client/settings/AutomationsSection.js +4 -3
- package/dist/client/settings/AutomationsSection.js.map +1 -1
- package/dist/client/settings/SecretsSection.d.ts.map +1 -1
- package/dist/client/settings/SecretsSection.js +11 -1
- package/dist/client/settings/SecretsSection.js.map +1 -1
- package/dist/client/settings/SettingsPanel.d.ts.map +1 -1
- package/dist/client/settings/SettingsPanel.js +15 -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 +13 -30
- package/dist/client/settings/VoiceTranscriptionSection.js.map +1 -1
- package/dist/client/settings/index.d.ts +1 -1
- package/dist/client/settings/index.d.ts.map +1 -1
- package/dist/client/settings/index.js.map +1 -1
- package/dist/client/settings/useBuilderStatus.d.ts.map +1 -1
- package/dist/client/settings/useBuilderStatus.js +27 -1
- package/dist/client/settings/useBuilderStatus.js.map +1 -1
- package/dist/client/sharing/ShareButton.d.ts +4 -0
- package/dist/client/sharing/ShareButton.d.ts.map +1 -1
- package/dist/client/sharing/ShareButton.js +5 -1
- package/dist/client/sharing/ShareButton.js.map +1 -1
- package/dist/client/sse-event-processor.d.ts +1 -1
- package/dist/client/sse-event-processor.d.ts.map +1 -1
- package/dist/client/sse-event-processor.js +59 -11
- package/dist/client/sse-event-processor.js.map +1 -1
- package/dist/client/use-db-sync.d.ts.map +1 -1
- package/dist/client/use-db-sync.js +100 -19
- package/dist/client/use-db-sync.js.map +1 -1
- package/dist/client/use-session.d.ts.map +1 -1
- package/dist/client/use-session.js +14 -2
- package/dist/client/use-session.js.map +1 -1
- package/dist/collab/client.d.ts +1 -0
- package/dist/collab/client.d.ts.map +1 -1
- package/dist/collab/client.js +18 -1
- package/dist/collab/client.js.map +1 -1
- package/dist/deploy/build.d.ts.map +1 -1
- package/dist/deploy/build.js +5 -0
- package/dist/deploy/build.js.map +1 -1
- package/dist/deploy/route-discovery.d.ts.map +1 -1
- package/dist/deploy/route-discovery.js +1 -0
- package/dist/deploy/route-discovery.js.map +1 -1
- package/dist/deploy/workspace-core.d.ts +1 -1
- package/dist/deploy/workspace-core.d.ts.map +1 -1
- package/dist/deploy/workspace-core.js +1 -0
- package/dist/deploy/workspace-core.js.map +1 -1
- package/dist/extensions/actions.d.ts.map +1 -1
- package/dist/extensions/actions.js +17 -3
- package/dist/extensions/actions.js.map +1 -1
- package/dist/extensions/routes.js +1 -1
- package/dist/extensions/routes.js.map +1 -1
- package/dist/extensions/schema.d.ts +14 -14
- package/dist/extensions/schema.d.ts.map +1 -1
- package/dist/extensions/schema.js +4 -4
- package/dist/extensions/schema.js.map +1 -1
- package/dist/extensions/store.d.ts.map +1 -1
- package/dist/extensions/store.js +23 -0
- package/dist/extensions/store.js.map +1 -1
- package/dist/extensions/theme.d.ts +8 -1
- package/dist/extensions/theme.d.ts.map +1 -1
- package/dist/extensions/theme.js +43 -34
- package/dist/extensions/theme.js.map +1 -1
- package/dist/mcp-client/routes.d.ts +1 -0
- package/dist/mcp-client/routes.d.ts.map +1 -1
- package/dist/mcp-client/routes.js +28 -1
- package/dist/mcp-client/routes.js.map +1 -1
- package/dist/org/auto-join-domain.d.ts +28 -0
- package/dist/org/auto-join-domain.d.ts.map +1 -0
- package/dist/org/auto-join-domain.js +92 -0
- package/dist/org/auto-join-domain.js.map +1 -0
- package/dist/org/index.d.ts +2 -0
- package/dist/org/index.d.ts.map +1 -1
- package/dist/org/index.js +1 -0
- package/dist/org/index.js.map +1 -1
- package/dist/scripts/db/exec.d.ts.map +1 -1
- package/dist/scripts/db/exec.js +27 -1
- package/dist/scripts/db/exec.js.map +1 -1
- package/dist/scripts/db/index.d.ts.map +1 -1
- package/dist/scripts/db/index.js +1 -0
- package/dist/scripts/db/index.js.map +1 -1
- package/dist/scripts/db/reset-dev-owner.d.ts +27 -0
- package/dist/scripts/db/reset-dev-owner.d.ts.map +1 -0
- package/dist/scripts/db/reset-dev-owner.js +225 -0
- package/dist/scripts/db/reset-dev-owner.js.map +1 -0
- package/dist/scripts/db/scoping.d.ts.map +1 -1
- package/dist/scripts/db/scoping.js +15 -30
- package/dist/scripts/db/scoping.js.map +1 -1
- package/dist/scripts/dev-session.d.ts +46 -0
- package/dist/scripts/dev-session.d.ts.map +1 -0
- package/dist/scripts/dev-session.js +81 -0
- package/dist/scripts/dev-session.js.map +1 -0
- package/dist/scripts/runner.d.ts.map +1 -1
- package/dist/scripts/runner.js +21 -0
- package/dist/scripts/runner.js.map +1 -1
- package/dist/secrets/register.d.ts +1 -1
- package/dist/secrets/register.d.ts.map +1 -1
- package/dist/secrets/register.js +4 -2
- package/dist/secrets/register.js.map +1 -1
- package/dist/secrets/routes.d.ts.map +1 -1
- package/dist/secrets/routes.js +32 -0
- package/dist/secrets/routes.js.map +1 -1
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +77 -102
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/auth.d.ts.map +1 -1
- package/dist/server/auth.js +33 -0
- package/dist/server/auth.js.map +1 -1
- package/dist/server/better-auth-instance.d.ts.map +1 -1
- package/dist/server/better-auth-instance.js +11 -0
- package/dist/server/better-auth-instance.js.map +1 -1
- package/dist/server/builder-browser.d.ts.map +1 -1
- package/dist/server/builder-browser.js +169 -68
- 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 +56 -13
- package/dist/server/core-routes-plugin.js.map +1 -1
- package/dist/server/credential-provider.d.ts +49 -6
- package/dist/server/credential-provider.d.ts.map +1 -1
- package/dist/server/credential-provider.js +133 -38
- package/dist/server/credential-provider.js.map +1 -1
- package/dist/server/design-token-utils.d.ts +13 -2
- package/dist/server/design-token-utils.d.ts.map +1 -1
- package/dist/server/design-token-utils.js +48 -16
- package/dist/server/design-token-utils.js.map +1 -1
- package/dist/server/framework-request-handler.d.ts.map +1 -1
- package/dist/server/framework-request-handler.js +31 -0
- package/dist/server/framework-request-handler.js.map +1 -1
- package/dist/server/google-realtime-session.d.ts.map +1 -1
- package/dist/server/google-realtime-session.js +19 -6
- package/dist/server/google-realtime-session.js.map +1 -1
- package/dist/server/index.d.ts +2 -0
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +2 -0
- package/dist/server/index.js.map +1 -1
- package/dist/server/onboarding-html.d.ts.map +1 -1
- package/dist/server/onboarding-html.js +142 -14
- package/dist/server/onboarding-html.js.map +1 -1
- package/dist/server/request-context.d.ts +17 -0
- package/dist/server/request-context.d.ts.map +1 -1
- package/dist/server/request-context.js +40 -1
- package/dist/server/request-context.js.map +1 -1
- package/dist/server/sentry-plugin.d.ts +11 -0
- package/dist/server/sentry-plugin.d.ts.map +1 -0
- package/dist/server/sentry-plugin.js +116 -0
- package/dist/server/sentry-plugin.js.map +1 -0
- package/dist/server/sentry.d.ts +92 -0
- package/dist/server/sentry.d.ts.map +1 -0
- package/dist/server/sentry.js +287 -0
- package/dist/server/sentry.js.map +1 -0
- package/dist/server/transcribe-voice.d.ts +2 -4
- package/dist/server/transcribe-voice.d.ts.map +1 -1
- package/dist/server/transcribe-voice.js +4 -16
- package/dist/server/transcribe-voice.js.map +1 -1
- package/dist/server/voice-providers-status.d.ts.map +1 -1
- package/dist/server/voice-providers-status.js +19 -35
- package/dist/server/voice-providers-status.js.map +1 -1
- package/dist/styles/agent-native.css +15 -0
- package/docs/content/cloneable-saas.md +7 -9
- package/docs/content/deployment.md +6 -2
- package/docs/content/dispatch.md +1 -1
- package/docs/content/extensions.md +177 -142
- package/docs/content/faq.md +2 -2
- package/docs/content/getting-started.md +13 -11
- package/docs/content/multi-app-workspace.md +2 -2
- package/docs/content/observability.md +47 -0
- package/docs/content/pure-agent-apps.md +1 -1
- package/docs/content/template-clips.md +3 -3
- package/docs/content/template-design.md +3 -3
- package/docs/content/template-dispatch.md +1 -1
- package/docs/content/template-forms.md +1 -1
- package/docs/content/template-mail.md +1 -1
- package/docs/content/what-is-agent-native.md +4 -4
- package/docs/content/workspace.md +1 -1
- package/package.json +1 -1
|
@@ -17,6 +17,19 @@
|
|
|
17
17
|
* shape is meant to grow to cover future managed credential integrations
|
|
18
18
|
* (e.g. additional Builder-hosted services) without rewrites.
|
|
19
19
|
*/
|
|
20
|
+
/**
|
|
21
|
+
* Decide which `app_secrets` scope a Builder/credential write should use.
|
|
22
|
+
*
|
|
23
|
+
* Org scope ("everyone in this org sees these credentials") wins when the
|
|
24
|
+
* connecting user is an owner or admin of an active org — the write
|
|
25
|
+
* privileges shared infra. A plain member or a user without an active
|
|
26
|
+
* org falls through to per-user scope so a teammate can't silently
|
|
27
|
+
* overwrite the org-shared connection.
|
|
28
|
+
*/
|
|
29
|
+
export declare function resolveCredentialWriteScope(email: string, orgId: string | null | undefined, role: string | null | undefined): {
|
|
30
|
+
scope: "user" | "org";
|
|
31
|
+
scopeId: string;
|
|
32
|
+
};
|
|
20
33
|
export declare class FeatureNotConfiguredError extends Error {
|
|
21
34
|
readonly requiredCredential: string;
|
|
22
35
|
readonly builderConnectUrl?: string;
|
|
@@ -71,7 +84,18 @@ export declare function resolveBuilderCredentials(): Promise<{
|
|
|
71
84
|
orgKind: string | null;
|
|
72
85
|
}>;
|
|
73
86
|
/**
|
|
74
|
-
* Write Builder credentials
|
|
87
|
+
* Write Builder credentials to `app_secrets`.
|
|
88
|
+
*
|
|
89
|
+
* Scope decision (see `resolveCredentialWriteScope`): when the connecting
|
|
90
|
+
* user is owner/admin of an active org we write at `scope: "org"` so every
|
|
91
|
+
* member of that org auto-resolves the credentials via
|
|
92
|
+
* `resolveBuilderCredential`'s org fallback — no per-user re-connect
|
|
93
|
+
* needed. A plain member or a user with no active org writes at
|
|
94
|
+
* `scope: "user"` (the safe default that doesn't trample the org's shared
|
|
95
|
+
* connection).
|
|
96
|
+
*
|
|
97
|
+
* Returns the actual scope/scopeId used so the caller can show "Connected
|
|
98
|
+
* for Builder.io" vs "Connected (personal)" in the UI.
|
|
75
99
|
*/
|
|
76
100
|
export declare function writeBuilderCredentials(email: string, creds: {
|
|
77
101
|
privateKey: string;
|
|
@@ -79,14 +103,33 @@ export declare function writeBuilderCredentials(email: string, creds: {
|
|
|
79
103
|
userId?: string | null;
|
|
80
104
|
orgName?: string | null;
|
|
81
105
|
orgKind?: string | null;
|
|
82
|
-
}
|
|
106
|
+
}, options?: {
|
|
107
|
+
orgId?: string | null;
|
|
108
|
+
role?: string | null;
|
|
109
|
+
}): Promise<{
|
|
110
|
+
scope: "user" | "org";
|
|
111
|
+
scopeId: string;
|
|
112
|
+
}>;
|
|
83
113
|
/**
|
|
84
|
-
* Delete Builder credentials
|
|
114
|
+
* Delete Builder credentials.
|
|
115
|
+
*
|
|
116
|
+
* Default behaviour: clears only this user's per-user override (so a
|
|
117
|
+
* member can disconnect their personal Builder identity without
|
|
118
|
+
* collapsing the org-wide connection for every teammate). To revoke the
|
|
119
|
+
* org's shared connection, pass `{ orgId, role }` for an owner/admin —
|
|
120
|
+
* matching the same authority gate `writeBuilderCredentials` uses on
|
|
121
|
+
* write. Plain members can never reach the org-scoped row.
|
|
85
122
|
*/
|
|
86
|
-
export declare function deleteBuilderCredentials(email: string
|
|
123
|
+
export declare function deleteBuilderCredentials(email: string, options?: {
|
|
124
|
+
orgId?: string | null;
|
|
125
|
+
role?: string | null;
|
|
126
|
+
}): Promise<{
|
|
127
|
+
scope: "user" | "org";
|
|
128
|
+
scopeId: string;
|
|
129
|
+
}>;
|
|
87
130
|
/**
|
|
88
|
-
* Resolve a
|
|
89
|
-
*
|
|
131
|
+
* Resolve a request-scoped secret. Reads from `app_secrets` first (current
|
|
132
|
+
* user override, active org, then workspace row); falls back to `process.env`
|
|
90
133
|
* only for unauthenticated/CLI/background contexts.
|
|
91
134
|
*/
|
|
92
135
|
export declare function resolveSecret(key: string): Promise<string | null>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"credential-provider.d.ts","sourceRoot":"","sources":["../../src/server/credential-provider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAIH,qBAAa,yBAA0B,SAAQ,KAAK;IAClD,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;IACpC,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IACpC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;gBAElB,IAAI,EAAE;QAChB,kBAAkB,EAAE,MAAM,CAAC;QAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,iBAAiB,CAAC,EAAE,MAAM,CAAC;QAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB;CAUF;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAEvE;AAwBD,wBAAsB,wBAAwB,CAC5C,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"credential-provider.d.ts","sourceRoot":"","sources":["../../src/server/credential-provider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAIH;;;;;;;;GAQG;AACH,wBAAgB,2BAA2B,CACzC,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAChC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC9B;IAAE,KAAK,EAAE,MAAM,GAAG,KAAK,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAK5C;AAED,qBAAa,yBAA0B,SAAQ,KAAK;IAClD,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;IACpC,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IACpC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;gBAElB,IAAI,EAAE;QAChB,kBAAkB,EAAE,MAAM,CAAC;QAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,iBAAiB,CAAC,EAAE,MAAM,CAAC;QAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB;CAUF;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAEvE;AAwBD,wBAAsB,wBAAwB,CAC5C,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAyCxB;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,IAAI,OAAO,CAE7C;AAED;;;;;GAKG;AACH,wBAAsB,wBAAwB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAEvE;AAED;;;GAGG;AACH,wBAAsB,wBAAwB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAGvE;AAED;;;GAGG;AACH,wBAAsB,2BAA2B,IAAI,OAAO,CAAC,OAAO,CAAC,CAEpE;AAED;;;GAGG;AACH,wBAAsB,yBAAyB,IAAI,OAAO,CAAC;IACzD,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB,CAAC,CASD;AAUD;;;;;;;;;;;;;GAaG;AACH,wBAAsB,uBAAuB,CAC3C,KAAK,EAAE,MAAM,EACb,KAAK,EAAE;IACL,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB,EACD,OAAO,CAAC,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GACxD,OAAO,CAAC;IAAE,KAAK,EAAE,MAAM,GAAG,KAAK,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CAgCrD;AAED;;;;;;;;;GASG;AACH,wBAAsB,wBAAwB,CAC5C,KAAK,EAAE,MAAM,EACb,OAAO,CAAC,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GACxD,OAAO,CAAC;IAAE,KAAK,EAAE,MAAM,GAAG,KAAK,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CAiBrD;AAeD;;;;GAIG;AACH,wBAAsB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAoDvE;AAOD;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,IAAI,OAAO,CAE9C;AAED,yEAAyE;AACzE,wBAAgB,qBAAqB,IAAI,MAAM,CAO9C;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,IAAI,MAAM,CAKjD;AAED,uEAAuE;AACvE,wBAAgB,oBAAoB,IAAI,MAAM,GAAG,IAAI,CAGpD"}
|
|
@@ -17,7 +17,22 @@
|
|
|
17
17
|
* shape is meant to grow to cover future managed credential integrations
|
|
18
18
|
* (e.g. additional Builder-hosted services) without rewrites.
|
|
19
19
|
*/
|
|
20
|
-
import { getRequestUserEmail } from "./request-context.js";
|
|
20
|
+
import { getRequestUserEmail, getRequestOrgId } from "./request-context.js";
|
|
21
|
+
/**
|
|
22
|
+
* Decide which `app_secrets` scope a Builder/credential write should use.
|
|
23
|
+
*
|
|
24
|
+
* Org scope ("everyone in this org sees these credentials") wins when the
|
|
25
|
+
* connecting user is an owner or admin of an active org — the write
|
|
26
|
+
* privileges shared infra. A plain member or a user without an active
|
|
27
|
+
* org falls through to per-user scope so a teammate can't silently
|
|
28
|
+
* overwrite the org-shared connection.
|
|
29
|
+
*/
|
|
30
|
+
export function resolveCredentialWriteScope(email, orgId, role) {
|
|
31
|
+
if (orgId && (role === "owner" || role === "admin")) {
|
|
32
|
+
return { scope: "org", scopeId: orgId };
|
|
33
|
+
}
|
|
34
|
+
return { scope: "user", scopeId: email };
|
|
35
|
+
}
|
|
21
36
|
export class FeatureNotConfiguredError extends Error {
|
|
22
37
|
requiredCredential;
|
|
23
38
|
builderConnectUrl;
|
|
@@ -67,23 +82,39 @@ export async function resolveBuilderCredential(key) {
|
|
|
67
82
|
const envValue = readDeployCredentialEnv(key);
|
|
68
83
|
if (envValue)
|
|
69
84
|
return envValue;
|
|
70
|
-
// No env value: per-user OAuth fallback.
|
|
71
85
|
const email = getRequestUserEmail();
|
|
72
|
-
if (email)
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
86
|
+
if (!email)
|
|
87
|
+
return null;
|
|
88
|
+
try {
|
|
89
|
+
const { readAppSecret } = await import("../secrets/storage.js");
|
|
90
|
+
// 1. Per-user override: a user can paste their own key in settings to
|
|
91
|
+
// overrule the org-shared one (handy for a personal sandbox).
|
|
92
|
+
const userSecret = await readAppSecret({
|
|
93
|
+
key,
|
|
94
|
+
scope: "user",
|
|
95
|
+
scopeId: email,
|
|
96
|
+
});
|
|
97
|
+
if (userSecret)
|
|
98
|
+
return userSecret.value;
|
|
99
|
+
// 2. Per-org shared credential: when one teammate connects Builder
|
|
100
|
+
// as an owner/admin we write the OAuth result at org scope so
|
|
101
|
+
// every member of that org gets the AI chat working without
|
|
102
|
+
// re-running the connect flow. Resolution falls back here
|
|
103
|
+
// silently — the caller never has to know which scope answered.
|
|
104
|
+
const orgId = getRequestOrgId();
|
|
105
|
+
if (orgId) {
|
|
106
|
+
const orgSecret = await readAppSecret({
|
|
76
107
|
key,
|
|
77
|
-
scope: "
|
|
78
|
-
scopeId:
|
|
108
|
+
scope: "org",
|
|
109
|
+
scopeId: orgId,
|
|
79
110
|
});
|
|
80
|
-
if (
|
|
81
|
-
return
|
|
82
|
-
}
|
|
83
|
-
catch {
|
|
84
|
-
// Secrets table not ready — treat as missing.
|
|
111
|
+
if (orgSecret)
|
|
112
|
+
return orgSecret.value;
|
|
85
113
|
}
|
|
86
114
|
}
|
|
115
|
+
catch {
|
|
116
|
+
// Secrets table not ready — treat as missing.
|
|
117
|
+
}
|
|
87
118
|
return null;
|
|
88
119
|
}
|
|
89
120
|
/**
|
|
@@ -134,11 +165,30 @@ export async function resolveBuilderCredentials() {
|
|
|
134
165
|
]);
|
|
135
166
|
return { privateKey, publicKey, userId, orgName, orgKind };
|
|
136
167
|
}
|
|
168
|
+
const BUILDER_CREDENTIAL_KEYS = [
|
|
169
|
+
"BUILDER_PRIVATE_KEY",
|
|
170
|
+
"BUILDER_PUBLIC_KEY",
|
|
171
|
+
"BUILDER_USER_ID",
|
|
172
|
+
"BUILDER_ORG_NAME",
|
|
173
|
+
"BUILDER_ORG_KIND",
|
|
174
|
+
];
|
|
137
175
|
/**
|
|
138
|
-
* Write Builder credentials
|
|
176
|
+
* Write Builder credentials to `app_secrets`.
|
|
177
|
+
*
|
|
178
|
+
* Scope decision (see `resolveCredentialWriteScope`): when the connecting
|
|
179
|
+
* user is owner/admin of an active org we write at `scope: "org"` so every
|
|
180
|
+
* member of that org auto-resolves the credentials via
|
|
181
|
+
* `resolveBuilderCredential`'s org fallback — no per-user re-connect
|
|
182
|
+
* needed. A plain member or a user with no active org writes at
|
|
183
|
+
* `scope: "user"` (the safe default that doesn't trample the org's shared
|
|
184
|
+
* connection).
|
|
185
|
+
*
|
|
186
|
+
* Returns the actual scope/scopeId used so the caller can show "Connected
|
|
187
|
+
* for Builder.io" vs "Connected (personal)" in the UI.
|
|
139
188
|
*/
|
|
140
|
-
export async function writeBuilderCredentials(email, creds) {
|
|
189
|
+
export async function writeBuilderCredentials(email, creds, options) {
|
|
141
190
|
const { writeAppSecret } = await import("../secrets/storage.js");
|
|
191
|
+
const target = resolveCredentialWriteScope(email, options?.orgId ?? null, options?.role ?? null);
|
|
142
192
|
const entries = [
|
|
143
193
|
{ key: "BUILDER_PRIVATE_KEY", value: creds.privateKey },
|
|
144
194
|
{ key: "BUILDER_PUBLIC_KEY", value: creds.publicKey },
|
|
@@ -152,36 +202,49 @@ export async function writeBuilderCredentials(email, creds) {
|
|
|
152
202
|
if (creds.orgKind) {
|
|
153
203
|
entries.push({ key: "BUILDER_ORG_KIND", value: creds.orgKind });
|
|
154
204
|
}
|
|
155
|
-
await Promise.all(entries.map(({ key, value }) => writeAppSecret({
|
|
205
|
+
await Promise.all(entries.map(({ key, value }) => writeAppSecret({
|
|
206
|
+
key,
|
|
207
|
+
value,
|
|
208
|
+
scope: target.scope,
|
|
209
|
+
scopeId: target.scopeId,
|
|
210
|
+
})));
|
|
211
|
+
return target;
|
|
156
212
|
}
|
|
157
213
|
/**
|
|
158
|
-
* Delete Builder credentials
|
|
214
|
+
* Delete Builder credentials.
|
|
215
|
+
*
|
|
216
|
+
* Default behaviour: clears only this user's per-user override (so a
|
|
217
|
+
* member can disconnect their personal Builder identity without
|
|
218
|
+
* collapsing the org-wide connection for every teammate). To revoke the
|
|
219
|
+
* org's shared connection, pass `{ orgId, role }` for an owner/admin —
|
|
220
|
+
* matching the same authority gate `writeBuilderCredentials` uses on
|
|
221
|
+
* write. Plain members can never reach the org-scoped row.
|
|
159
222
|
*/
|
|
160
|
-
export async function deleteBuilderCredentials(email) {
|
|
223
|
+
export async function deleteBuilderCredentials(email, options) {
|
|
161
224
|
const { deleteAppSecret } = await import("../secrets/storage.js");
|
|
162
|
-
const
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
await Promise.all(keys.map((key) => deleteAppSecret({ key, scope: "user", scopeId: email }).catch(() => { })));
|
|
225
|
+
const target = resolveCredentialWriteScope(email, options?.orgId ?? null, options?.role ?? null);
|
|
226
|
+
await Promise.all(BUILDER_CREDENTIAL_KEYS.map((key) => deleteAppSecret({
|
|
227
|
+
key,
|
|
228
|
+
scope: target.scope,
|
|
229
|
+
scopeId: target.scopeId,
|
|
230
|
+
}).catch(() => { })));
|
|
231
|
+
return target;
|
|
170
232
|
}
|
|
171
233
|
// ---------------------------------------------------------------------------
|
|
172
|
-
// Generic
|
|
234
|
+
// Generic request-scoped secret resolution
|
|
173
235
|
//
|
|
174
236
|
// New consumers should prefer this over reading `process.env.X` directly.
|
|
175
|
-
// User-pasted secrets live in `app_secrets` (encrypted
|
|
176
|
-
// settings UI / onboarding panels write
|
|
177
|
-
// the fallback for unauthenticated/CLI/background
|
|
178
|
-
// no user to scope by — never the silent fallback
|
|
179
|
-
// request, since on a multi-tenant deploy that would
|
|
180
|
-
// every user as whoever set the deploy-level key
|
|
237
|
+
// User-pasted and shared secrets live in `app_secrets` (encrypted). The
|
|
238
|
+
// settings UI / onboarding panels can write user, org, or workspace rows.
|
|
239
|
+
// Deploy-level env vars are the fallback for unauthenticated/CLI/background
|
|
240
|
+
// contexts where there's no user to scope by — never the silent fallback
|
|
241
|
+
// for an authenticated request, since on a multi-tenant deploy that would
|
|
242
|
+
// silently identify every user as whoever set the deploy-level key
|
|
243
|
+
// (KVesta Space, 2026-04).
|
|
181
244
|
// ---------------------------------------------------------------------------
|
|
182
245
|
/**
|
|
183
|
-
* Resolve a
|
|
184
|
-
*
|
|
246
|
+
* Resolve a request-scoped secret. Reads from `app_secrets` first (current
|
|
247
|
+
* user override, active org, then workspace row); falls back to `process.env`
|
|
185
248
|
* only for unauthenticated/CLI/background contexts.
|
|
186
249
|
*/
|
|
187
250
|
export async function resolveSecret(key) {
|
|
@@ -189,13 +252,45 @@ export async function resolveSecret(key) {
|
|
|
189
252
|
if (email) {
|
|
190
253
|
try {
|
|
191
254
|
const { readAppSecret } = await import("../secrets/storage.js");
|
|
192
|
-
|
|
255
|
+
// Per-user override first.
|
|
256
|
+
const userSecret = await readAppSecret({
|
|
193
257
|
key,
|
|
194
258
|
scope: "user",
|
|
195
259
|
scopeId: email,
|
|
196
260
|
});
|
|
197
|
-
if (
|
|
198
|
-
return
|
|
261
|
+
if (userSecret?.value)
|
|
262
|
+
return userSecret.value;
|
|
263
|
+
const orgId = getRequestOrgId();
|
|
264
|
+
if (orgId) {
|
|
265
|
+
// Fall back to the active org's shared row, when present. Builder
|
|
266
|
+
// Connect uses this first-class org scope.
|
|
267
|
+
const orgSecret = await readAppSecret({
|
|
268
|
+
key,
|
|
269
|
+
scope: "org",
|
|
270
|
+
scopeId: orgId,
|
|
271
|
+
});
|
|
272
|
+
if (orgSecret?.value)
|
|
273
|
+
return orgSecret.value;
|
|
274
|
+
// Registered secrets historically used "workspace" scope for
|
|
275
|
+
// org-shared configuration. Keep reading it so Settings status and
|
|
276
|
+
// runtime resolution agree.
|
|
277
|
+
const workspaceSecret = await readAppSecret({
|
|
278
|
+
key,
|
|
279
|
+
scope: "workspace",
|
|
280
|
+
scopeId: orgId,
|
|
281
|
+
});
|
|
282
|
+
if (workspaceSecret?.value)
|
|
283
|
+
return workspaceSecret.value;
|
|
284
|
+
}
|
|
285
|
+
else {
|
|
286
|
+
const soloWorkspaceSecret = await readAppSecret({
|
|
287
|
+
key,
|
|
288
|
+
scope: "workspace",
|
|
289
|
+
scopeId: `solo:${email}`,
|
|
290
|
+
});
|
|
291
|
+
if (soloWorkspaceSecret?.value)
|
|
292
|
+
return soloWorkspaceSecret.value;
|
|
293
|
+
}
|
|
199
294
|
}
|
|
200
295
|
catch {
|
|
201
296
|
// Secrets table not ready — treat as missing.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"credential-provider.js","sourceRoot":"","sources":["../../src/server/credential-provider.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Credential provider abstraction.\n *\n * Every feature that needs an external credential (Anthropic API key,\n * Google OAuth tokens, OpenAI key, Slack bot token, etc.) should go through\n * one of the resolve*() helpers here instead of reading `process.env`\n * directly. That way the same feature can work in three modes:\n *\n * 1. User set their own key in .env → use it directly\n * 2. User connected Builder via `/cli-auth` → route through Builder proxy\n * 3. Neither → throw FeatureNotConfigured\n *\n * Templates catch FeatureNotConfigured and show a \"Connect Builder (1 click) /\n * set up your own key (guide)\" card.\n *\n * Today these helpers are used by the Builder-hosted LLM gateway, and the\n * shape is meant to grow to cover future managed credential integrations\n * (e.g. additional Builder-hosted services) without rewrites.\n */\n\nimport { getRequestUserEmail } from \"./request-context.js\";\n\nexport class FeatureNotConfiguredError extends Error {\n readonly requiredCredential: string;\n readonly builderConnectUrl?: string;\n readonly byokDocsUrl?: string;\n\n constructor(opts: {\n requiredCredential: string;\n message?: string;\n builderConnectUrl?: string;\n byokDocsUrl?: string;\n }) {\n super(\n opts.message ??\n `Feature requires credential \"${opts.requiredCredential}\". Connect Builder or set your own key.`,\n );\n this.name = \"FeatureNotConfiguredError\";\n this.requiredCredential = opts.requiredCredential;\n this.builderConnectUrl = opts.builderConnectUrl;\n this.byokDocsUrl = opts.byokDocsUrl;\n }\n}\n\n/**\n * Deployment-level credential fallback for single-tenant/local operation.\n * Multi-tenant call sites must gate this explicitly before calling.\n */\nexport function readDeployCredentialEnv(key: string): string | undefined {\n return process.env[key] || undefined;\n}\n\n// ---------------------------------------------------------------------------\n// Builder credential resolution — two mutually-exclusive deployment modes:\n//\n// 1. **Single-tenant / env-managed.** When BUILDER_PRIVATE_KEY is set at\n// the deployment level, it is THE Builder identity for every user of\n// this deploy. The operator setting the env explicitly opts in to\n// \"everyone shares one Builder space\" — same shape as DATABASE_URL or\n// BETTER_AUTH_SECRET. The UI hides the per-user connect/disconnect\n// flow when env-managed (see `isBuilderEnvManaged`).\n//\n// 2. **Multi-tenant / per-user OAuth.** When the env is unset, each user\n// OAuth-connects their own Builder via the cli-auth flow. Their keys\n// land in `app_secrets` (scope=user, scopeId=email) via the callback\n// handler. They can disconnect via the settings panel.\n//\n// To run multi-tenant SaaS: leave the env unset. Setting BUILDER_PRIVATE_KEY\n// on a multi-tenant deploy will silently route every authenticated user\n// through the env-key owner's Builder identity — that was the KVesta Space\n// cross-tenant attribution leak (2026-04). The mode is binary: env-set\n// means single-tenant intent.\n// ---------------------------------------------------------------------------\n\nexport async function resolveBuilderCredential(\n key: string,\n): Promise<string | null> {\n // Env-managed mode wins when set: deploy-level Builder identity for\n // every user. Per-user app_secrets (left over from a previous OAuth\n // connection or a mode switch) are intentionally ignored — the\n // operator's deploy-level config is authoritative.\n const envValue = readDeployCredentialEnv(key);\n if (envValue) return envValue;\n\n // No env value: per-user OAuth fallback.\n const email = getRequestUserEmail();\n if (email) {\n try {\n const { readAppSecret } = await import(\"../secrets/storage.js\");\n const secret = await readAppSecret({\n key,\n scope: \"user\",\n scopeId: email,\n });\n if (secret) return secret.value;\n } catch {\n // Secrets table not ready — treat as missing.\n }\n }\n return null;\n}\n\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, and per-user\n * connect/disconnect is disabled. UIs read this via `/builder/status` to\n * swap the \"Connect Builder\" prompts for a read-only \"managed by deployment\"\n * chip and to suppress the disconnect button.\n */\nexport function isBuilderEnvManaged(): boolean {\n return !!process.env.BUILDER_PRIVATE_KEY;\n}\n\n/**\n * Resolve the Builder private key for the current request. In env-managed\n * mode (deploy-level `BUILDER_PRIVATE_KEY` set) returns the env value for\n * every caller. Otherwise reads the current user's per-user OAuth-stored\n * key from `app_secrets`.\n */\nexport async function resolveBuilderPrivateKey(): Promise<string | null> {\n return resolveBuilderCredential(\"BUILDER_PRIVATE_KEY\");\n}\n\n/**\n * Resolve the current user's Builder auth header.\n * Returns `\"Bearer <key>\"` or null.\n */\nexport async function resolveBuilderAuthHeader(): Promise<string | null> {\n const key = await resolveBuilderPrivateKey();\n return key ? `Bearer ${key}` : null;\n}\n\n/**\n * Check whether the current user has a Builder private key configured\n * (per-user or deployment-level).\n */\nexport async function resolveHasBuilderPrivateKey(): Promise<boolean> {\n return !!(await resolveBuilderPrivateKey());\n}\n\n/**\n * Resolve all per-user Builder credentials. Used by the status endpoint\n * and agent-chat-plugin to get orgName, userId, etc.\n */\nexport async function resolveBuilderCredentials(): Promise<{\n privateKey: string | null;\n publicKey: string | null;\n userId: string | null;\n orgName: string | null;\n orgKind: string | null;\n}> {\n const [privateKey, publicKey, userId, orgName, orgKind] = await Promise.all([\n resolveBuilderCredential(\"BUILDER_PRIVATE_KEY\"),\n resolveBuilderCredential(\"BUILDER_PUBLIC_KEY\"),\n resolveBuilderCredential(\"BUILDER_USER_ID\"),\n resolveBuilderCredential(\"BUILDER_ORG_NAME\"),\n resolveBuilderCredential(\"BUILDER_ORG_KIND\"),\n ]);\n return { privateKey, publicKey, userId, orgName, orgKind };\n}\n\n/**\n * Write Builder credentials for the current user to per-user app_secrets.\n */\nexport async function writeBuilderCredentials(\n email: string,\n creds: {\n privateKey: string;\n publicKey: string;\n userId?: string | null;\n orgName?: string | null;\n orgKind?: string | null;\n },\n): Promise<void> {\n const { writeAppSecret } = await import(\"../secrets/storage.js\");\n const entries: Array<{ key: string; value: string }> = [\n { key: \"BUILDER_PRIVATE_KEY\", value: creds.privateKey },\n { key: \"BUILDER_PUBLIC_KEY\", value: creds.publicKey },\n ];\n if (creds.userId) {\n entries.push({ key: \"BUILDER_USER_ID\", value: creds.userId });\n }\n if (creds.orgName) {\n entries.push({ key: \"BUILDER_ORG_NAME\", value: creds.orgName });\n }\n if (creds.orgKind) {\n entries.push({ key: \"BUILDER_ORG_KIND\", value: creds.orgKind });\n }\n await Promise.all(\n entries.map(({ key, value }) =>\n writeAppSecret({ key, value, scope: \"user\", scopeId: email }),\n ),\n );\n}\n\n/**\n * Delete Builder credentials for the current user from app_secrets.\n */\nexport async function deleteBuilderCredentials(email: string): Promise<void> {\n const { deleteAppSecret } = await import(\"../secrets/storage.js\");\n const keys = [\n \"BUILDER_PRIVATE_KEY\",\n \"BUILDER_PUBLIC_KEY\",\n \"BUILDER_USER_ID\",\n \"BUILDER_ORG_NAME\",\n \"BUILDER_ORG_KIND\",\n ];\n await Promise.all(\n keys.map((key) =>\n deleteAppSecret({ key, scope: \"user\", scopeId: email }).catch(() => {}),\n ),\n );\n}\n\n// ---------------------------------------------------------------------------\n// Generic per-user secret resolution\n//\n// New consumers should prefer this over reading `process.env.X` directly.\n// User-pasted secrets live in `app_secrets` (encrypted, scope=user); the\n// settings UI / onboarding panels write here. Deploy-level env vars are\n// the fallback for unauthenticated/CLI/background contexts where there's\n// no user to scope by — never the silent fallback for an authenticated\n// request, since on a multi-tenant deploy that would silently identify\n// every user as whoever set the deploy-level key (KVesta Space, 2026-04).\n// ---------------------------------------------------------------------------\n\n/**\n * Resolve a per-user secret. Reads from `app_secrets` first (scoped by\n * the current request's authenticated user); falls back to `process.env`\n * only for unauthenticated/CLI/background contexts.\n */\nexport async function resolveSecret(key: string): Promise<string | null> {\n const email = getRequestUserEmail();\n if (email) {\n try {\n const { readAppSecret } = await import(\"../secrets/storage.js\");\n const secret = await readAppSecret({\n key,\n scope: \"user\",\n scopeId: email,\n });\n if (secret?.value) return secret.value;\n } catch {\n // Secrets table not ready — treat as missing.\n }\n // Authenticated multi-tenant context: never fall back to process.env.\n // The deploy-level value would silently impersonate the actual key\n // owner across every tenant.\n return null;\n }\n // Unauthenticated / local-dev / CLI / background context: env fallback\n // is safe because there's no user to mis-identify.\n return process.env[key] || null;\n}\n\n// ---------------------------------------------------------------------------\n// Synchronous helpers — env-only fallbacks for contexts where per-user\n// lookup isn't possible (sync isConfigured checks, CLI scripts).\n// ---------------------------------------------------------------------------\n\n/**\n * True when a Builder private key is configured at the deployment level.\n *\n * This is the same check as `isBuilderEnvManaged()` (env-managed mode is\n * defined as \"deploy-level BUILDER_PRIVATE_KEY is set\"). Prefer\n * `isBuilderEnvManaged()` for new call sites — its name reflects what the\n * boolean means semantically. For \"does this user have access to Builder\n * (env or per-user)?\" use the async `resolveHasBuilderPrivateKey()`.\n */\nexport function hasBuilderPrivateKey(): boolean {\n return !!process.env.BUILDER_PRIVATE_KEY;\n}\n\n/** The origin for Builder-proxied API calls. Overridable for testing. */\nexport function getBuilderProxyOrigin(): string {\n return (\n process.env.BUILDER_PROXY_ORIGIN ||\n process.env.AIR_HOST ||\n process.env.BUILDER_API_HOST ||\n \"https://ai-services.builder.io\"\n );\n}\n\n/**\n * Base URL for the public Builder LLM gateway (distinct from the internal\n * proxy origin above — the public gateway lives at api.builder.io/codegen,\n * while the internal origin is ai-services.builder.io).\n * Override via BUILDER_GATEWAY_BASE_URL for staging / testing.\n */\nexport function getBuilderGatewayBaseUrl(): string {\n return (\n process.env.BUILDER_GATEWAY_BASE_URL ||\n \"https://api.builder.io/codegen/gateway/v1\"\n );\n}\n\n/** Authorization header value for Builder-proxied calls (env-only). */\nexport function getBuilderAuthHeader(): string | null {\n const key = process.env.BUILDER_PRIVATE_KEY;\n return key ? `Bearer ${key}` : null;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"credential-provider.js","sourceRoot":"","sources":["../../src/server/credential-provider.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Credential provider abstraction.\n *\n * Every feature that needs an external credential (Anthropic API key,\n * Google OAuth tokens, OpenAI key, Slack bot token, etc.) should go through\n * one of the resolve*() helpers here instead of reading `process.env`\n * directly. That way the same feature can work in three modes:\n *\n * 1. User set their own key in .env → use it directly\n * 2. User connected Builder via `/cli-auth` → route through Builder proxy\n * 3. Neither → throw FeatureNotConfigured\n *\n * Templates catch FeatureNotConfigured and show a \"Connect Builder (1 click) /\n * set up your own key (guide)\" card.\n *\n * Today these helpers are used by the Builder-hosted LLM gateway, and the\n * shape is meant to grow to cover future managed credential integrations\n * (e.g. additional Builder-hosted services) without rewrites.\n */\n\nimport { getRequestUserEmail, getRequestOrgId } from \"./request-context.js\";\n\n/**\n * Decide which `app_secrets` scope a Builder/credential write should use.\n *\n * Org scope (\"everyone in this org sees these credentials\") wins when the\n * connecting user is an owner or admin of an active org — the write\n * privileges shared infra. A plain member or a user without an active\n * org falls through to per-user scope so a teammate can't silently\n * overwrite the org-shared connection.\n */\nexport function resolveCredentialWriteScope(\n email: string,\n orgId: string | null | undefined,\n role: string | null | undefined,\n): { scope: \"user\" | \"org\"; scopeId: string } {\n if (orgId && (role === \"owner\" || role === \"admin\")) {\n return { scope: \"org\", scopeId: orgId };\n }\n return { scope: \"user\", scopeId: email };\n}\n\nexport class FeatureNotConfiguredError extends Error {\n readonly requiredCredential: string;\n readonly builderConnectUrl?: string;\n readonly byokDocsUrl?: string;\n\n constructor(opts: {\n requiredCredential: string;\n message?: string;\n builderConnectUrl?: string;\n byokDocsUrl?: string;\n }) {\n super(\n opts.message ??\n `Feature requires credential \"${opts.requiredCredential}\". Connect Builder or set your own key.`,\n );\n this.name = \"FeatureNotConfiguredError\";\n this.requiredCredential = opts.requiredCredential;\n this.builderConnectUrl = opts.builderConnectUrl;\n this.byokDocsUrl = opts.byokDocsUrl;\n }\n}\n\n/**\n * Deployment-level credential fallback for single-tenant/local operation.\n * Multi-tenant call sites must gate this explicitly before calling.\n */\nexport function readDeployCredentialEnv(key: string): string | undefined {\n return process.env[key] || undefined;\n}\n\n// ---------------------------------------------------------------------------\n// Builder credential resolution — two mutually-exclusive deployment modes:\n//\n// 1. **Single-tenant / env-managed.** When BUILDER_PRIVATE_KEY is set at\n// the deployment level, it is THE Builder identity for every user of\n// this deploy. The operator setting the env explicitly opts in to\n// \"everyone shares one Builder space\" — same shape as DATABASE_URL or\n// BETTER_AUTH_SECRET. The UI hides the per-user connect/disconnect\n// flow when env-managed (see `isBuilderEnvManaged`).\n//\n// 2. **Multi-tenant / per-user OAuth.** When the env is unset, each user\n// OAuth-connects their own Builder via the cli-auth flow. Their keys\n// land in `app_secrets` (scope=user, scopeId=email) via the callback\n// handler. They can disconnect via the settings panel.\n//\n// To run multi-tenant SaaS: leave the env unset. Setting BUILDER_PRIVATE_KEY\n// on a multi-tenant deploy will silently route every authenticated user\n// through the env-key owner's Builder identity — that was the KVesta Space\n// cross-tenant attribution leak (2026-04). The mode is binary: env-set\n// means single-tenant intent.\n// ---------------------------------------------------------------------------\n\nexport async function resolveBuilderCredential(\n key: string,\n): Promise<string | null> {\n // Env-managed mode wins when set: deploy-level Builder identity for\n // every user. Per-user app_secrets (left over from a previous OAuth\n // connection or a mode switch) are intentionally ignored — the\n // operator's deploy-level config is authoritative.\n const envValue = readDeployCredentialEnv(key);\n if (envValue) return envValue;\n\n const email = getRequestUserEmail();\n if (!email) return null;\n\n try {\n const { readAppSecret } = await import(\"../secrets/storage.js\");\n\n // 1. Per-user override: a user can paste their own key in settings to\n // overrule the org-shared one (handy for a personal sandbox).\n const userSecret = await readAppSecret({\n key,\n scope: \"user\",\n scopeId: email,\n });\n if (userSecret) return userSecret.value;\n\n // 2. Per-org shared credential: when one teammate connects Builder\n // as an owner/admin we write the OAuth result at org scope so\n // every member of that org gets the AI chat working without\n // re-running the connect flow. Resolution falls back here\n // silently — the caller never has to know which scope answered.\n const orgId = getRequestOrgId();\n if (orgId) {\n const orgSecret = await readAppSecret({\n key,\n scope: \"org\",\n scopeId: orgId,\n });\n if (orgSecret) return orgSecret.value;\n }\n } catch {\n // Secrets table not ready — treat as missing.\n }\n return null;\n}\n\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, and per-user\n * connect/disconnect is disabled. UIs read this via `/builder/status` to\n * swap the \"Connect Builder\" prompts for a read-only \"managed by deployment\"\n * chip and to suppress the disconnect button.\n */\nexport function isBuilderEnvManaged(): boolean {\n return !!process.env.BUILDER_PRIVATE_KEY;\n}\n\n/**\n * Resolve the Builder private key for the current request. In env-managed\n * mode (deploy-level `BUILDER_PRIVATE_KEY` set) returns the env value for\n * every caller. Otherwise reads the current user's per-user OAuth-stored\n * key from `app_secrets`.\n */\nexport async function resolveBuilderPrivateKey(): Promise<string | null> {\n return resolveBuilderCredential(\"BUILDER_PRIVATE_KEY\");\n}\n\n/**\n * Resolve the current user's Builder auth header.\n * Returns `\"Bearer <key>\"` or null.\n */\nexport async function resolveBuilderAuthHeader(): Promise<string | null> {\n const key = await resolveBuilderPrivateKey();\n return key ? `Bearer ${key}` : null;\n}\n\n/**\n * Check whether the current user has a Builder private key configured\n * (per-user or deployment-level).\n */\nexport async function resolveHasBuilderPrivateKey(): Promise<boolean> {\n return !!(await resolveBuilderPrivateKey());\n}\n\n/**\n * Resolve all per-user Builder credentials. Used by the status endpoint\n * and agent-chat-plugin to get orgName, userId, etc.\n */\nexport async function resolveBuilderCredentials(): Promise<{\n privateKey: string | null;\n publicKey: string | null;\n userId: string | null;\n orgName: string | null;\n orgKind: string | null;\n}> {\n const [privateKey, publicKey, userId, orgName, orgKind] = await Promise.all([\n resolveBuilderCredential(\"BUILDER_PRIVATE_KEY\"),\n resolveBuilderCredential(\"BUILDER_PUBLIC_KEY\"),\n resolveBuilderCredential(\"BUILDER_USER_ID\"),\n resolveBuilderCredential(\"BUILDER_ORG_NAME\"),\n resolveBuilderCredential(\"BUILDER_ORG_KIND\"),\n ]);\n return { privateKey, publicKey, userId, orgName, orgKind };\n}\n\nconst BUILDER_CREDENTIAL_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\n/**\n * Write Builder credentials to `app_secrets`.\n *\n * Scope decision (see `resolveCredentialWriteScope`): when the connecting\n * user is owner/admin of an active org we write at `scope: \"org\"` so every\n * member of that org auto-resolves the credentials via\n * `resolveBuilderCredential`'s org fallback — no per-user re-connect\n * needed. A plain member or a user with no active org writes at\n * `scope: \"user\"` (the safe default that doesn't trample the org's shared\n * connection).\n *\n * Returns the actual scope/scopeId used so the caller can show \"Connected\n * for Builder.io\" vs \"Connected (personal)\" in the UI.\n */\nexport async function writeBuilderCredentials(\n email: string,\n creds: {\n privateKey: string;\n publicKey: string;\n userId?: string | null;\n orgName?: string | null;\n orgKind?: string | null;\n },\n options?: { orgId?: string | null; role?: string | null },\n): Promise<{ scope: \"user\" | \"org\"; scopeId: string }> {\n const { writeAppSecret } = await import(\"../secrets/storage.js\");\n const target = resolveCredentialWriteScope(\n email,\n options?.orgId ?? null,\n options?.role ?? null,\n );\n\n const entries: Array<{ key: string; value: string }> = [\n { key: \"BUILDER_PRIVATE_KEY\", value: creds.privateKey },\n { key: \"BUILDER_PUBLIC_KEY\", value: creds.publicKey },\n ];\n if (creds.userId) {\n entries.push({ key: \"BUILDER_USER_ID\", value: creds.userId });\n }\n if (creds.orgName) {\n entries.push({ key: \"BUILDER_ORG_NAME\", value: creds.orgName });\n }\n if (creds.orgKind) {\n entries.push({ key: \"BUILDER_ORG_KIND\", value: creds.orgKind });\n }\n await Promise.all(\n entries.map(({ key, value }) =>\n writeAppSecret({\n key,\n value,\n scope: target.scope,\n scopeId: target.scopeId,\n }),\n ),\n );\n return target;\n}\n\n/**\n * Delete Builder credentials.\n *\n * Default behaviour: clears only this user's per-user override (so a\n * member can disconnect their personal Builder identity without\n * collapsing the org-wide connection for every teammate). To revoke the\n * org's shared connection, pass `{ orgId, role }` for an owner/admin —\n * matching the same authority gate `writeBuilderCredentials` uses on\n * write. Plain members can never reach the org-scoped row.\n */\nexport async function deleteBuilderCredentials(\n email: string,\n options?: { orgId?: string | null; role?: string | null },\n): Promise<{ scope: \"user\" | \"org\"; scopeId: string }> {\n const { deleteAppSecret } = await import(\"../secrets/storage.js\");\n const target = resolveCredentialWriteScope(\n email,\n options?.orgId ?? null,\n options?.role ?? null,\n );\n await Promise.all(\n BUILDER_CREDENTIAL_KEYS.map((key) =>\n deleteAppSecret({\n key,\n scope: target.scope,\n scopeId: target.scopeId,\n }).catch(() => {}),\n ),\n );\n return target;\n}\n\n// ---------------------------------------------------------------------------\n// Generic request-scoped secret resolution\n//\n// New consumers should prefer this over reading `process.env.X` directly.\n// User-pasted and shared secrets live in `app_secrets` (encrypted). The\n// settings UI / onboarding panels can write user, org, or workspace rows.\n// Deploy-level env vars are the fallback for unauthenticated/CLI/background\n// contexts where there's no user to scope by — never the silent fallback\n// for an authenticated request, since on a multi-tenant deploy that would\n// silently identify every user as whoever set the deploy-level key\n// (KVesta Space, 2026-04).\n// ---------------------------------------------------------------------------\n\n/**\n * Resolve a request-scoped secret. Reads from `app_secrets` first (current\n * user override, active org, then workspace row); falls back to `process.env`\n * only for unauthenticated/CLI/background contexts.\n */\nexport async function resolveSecret(key: string): Promise<string | null> {\n const email = getRequestUserEmail();\n if (email) {\n try {\n const { readAppSecret } = await import(\"../secrets/storage.js\");\n // Per-user override first.\n const userSecret = await readAppSecret({\n key,\n scope: \"user\",\n scopeId: email,\n });\n if (userSecret?.value) return userSecret.value;\n\n const orgId = getRequestOrgId();\n if (orgId) {\n // Fall back to the active org's shared row, when present. Builder\n // Connect uses this first-class org scope.\n const orgSecret = await readAppSecret({\n key,\n scope: \"org\",\n scopeId: orgId,\n });\n if (orgSecret?.value) return orgSecret.value;\n\n // Registered secrets historically used \"workspace\" scope for\n // org-shared configuration. Keep reading it so Settings status and\n // runtime resolution agree.\n const workspaceSecret = await readAppSecret({\n key,\n scope: \"workspace\",\n scopeId: orgId,\n });\n if (workspaceSecret?.value) return workspaceSecret.value;\n } else {\n const soloWorkspaceSecret = await readAppSecret({\n key,\n scope: \"workspace\",\n scopeId: `solo:${email}`,\n });\n if (soloWorkspaceSecret?.value) return soloWorkspaceSecret.value;\n }\n } catch {\n // Secrets table not ready — treat as missing.\n }\n // Authenticated multi-tenant context: never fall back to process.env.\n // The deploy-level value would silently impersonate the actual key\n // owner across every tenant.\n return null;\n }\n // Unauthenticated / local-dev / CLI / background context: env fallback\n // is safe because there's no user to mis-identify.\n return process.env[key] || null;\n}\n\n// ---------------------------------------------------------------------------\n// Synchronous helpers — env-only fallbacks for contexts where per-user\n// lookup isn't possible (sync isConfigured checks, CLI scripts).\n// ---------------------------------------------------------------------------\n\n/**\n * True when a Builder private key is configured at the deployment level.\n *\n * This is the same check as `isBuilderEnvManaged()` (env-managed mode is\n * defined as \"deploy-level BUILDER_PRIVATE_KEY is set\"). Prefer\n * `isBuilderEnvManaged()` for new call sites — its name reflects what the\n * boolean means semantically. For \"does this user have access to Builder\n * (env or per-user)?\" use the async `resolveHasBuilderPrivateKey()`.\n */\nexport function hasBuilderPrivateKey(): boolean {\n return !!process.env.BUILDER_PRIVATE_KEY;\n}\n\n/** The origin for Builder-proxied API calls. Overridable for testing. */\nexport function getBuilderProxyOrigin(): string {\n return (\n process.env.BUILDER_PROXY_ORIGIN ||\n process.env.AIR_HOST ||\n process.env.BUILDER_API_HOST ||\n \"https://ai-services.builder.io\"\n );\n}\n\n/**\n * Base URL for the public Builder LLM gateway (distinct from the internal\n * proxy origin above — the public gateway lives at api.builder.io/codegen,\n * while the internal origin is ai-services.builder.io).\n * Override via BUILDER_GATEWAY_BASE_URL for staging / testing.\n */\nexport function getBuilderGatewayBaseUrl(): string {\n return (\n process.env.BUILDER_GATEWAY_BASE_URL ||\n \"https://api.builder.io/codegen/gateway/v1\"\n );\n}\n\n/** Authorization header value for Builder-proxied calls (env-only). */\nexport function getBuilderAuthHeader(): string | null {\n const key = process.env.BUILDER_PRIVATE_KEY;\n return key ? `Bearer ${key}` : null;\n}\n"]}
|
|
@@ -78,6 +78,15 @@ export interface UrlExtractionResult {
|
|
|
78
78
|
ogImage?: string;
|
|
79
79
|
favicon?: string;
|
|
80
80
|
}
|
|
81
|
+
export interface GitHubFetchOptions {
|
|
82
|
+
token?: string | null;
|
|
83
|
+
}
|
|
84
|
+
export interface GitHubJsonResult<T = unknown> {
|
|
85
|
+
ok: boolean;
|
|
86
|
+
status: number;
|
|
87
|
+
data: T | null;
|
|
88
|
+
message?: string;
|
|
89
|
+
}
|
|
81
90
|
/** Validate a URL is safe to fetch (blocks localhost, private IPs, metadata endpoints). */
|
|
82
91
|
export declare function validateUrl(url: string): void;
|
|
83
92
|
/** Parse a GitHub URL or "org/repo" shorthand into owner + repo. */
|
|
@@ -85,10 +94,12 @@ export declare function parseOwnerRepo(raw: string): {
|
|
|
85
94
|
owner: string;
|
|
86
95
|
repo: string;
|
|
87
96
|
};
|
|
97
|
+
/** Fetch a path from the GitHub Contents API as JSON with status details. */
|
|
98
|
+
export declare function fetchGitHubJsonResult<T = unknown>(owner: string, repo: string, path: string, options?: GitHubFetchOptions): Promise<GitHubJsonResult<T>>;
|
|
88
99
|
/** Fetch a path from the GitHub Contents API as JSON. Returns null on error. */
|
|
89
|
-
export declare function fetchGitHubJson(owner: string, repo: string, path: string): Promise<unknown>;
|
|
100
|
+
export declare function fetchGitHubJson(owner: string, repo: string, path: string, options?: GitHubFetchOptions): Promise<unknown>;
|
|
90
101
|
/** Fetch raw file content from the GitHub Contents API. Returns null on error or oversize. */
|
|
91
|
-
export declare function fetchGitHubRaw(owner: string, repo: string, path: string): Promise<string | null>;
|
|
102
|
+
export declare function fetchGitHubRaw(owner: string, repo: string, path: string, options?: GitHubFetchOptions): Promise<string | null>;
|
|
92
103
|
/** Extract colors, fonts, spacing, borderRadius from a Tailwind config file string. */
|
|
93
104
|
export declare function parseTailwindConfig(content: string): Record<string, unknown>;
|
|
94
105
|
/** Extract CSS custom properties and @font-face / Google Fonts from CSS content. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"design-token-utils.d.ts","sourceRoot":"","sources":["../../src/server/design-token-utils.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAMH,kEAAkE;AAClE,eAAO,MAAM,SAAS,KAAK,CAAC;AAE5B,6CAA6C;AAC7C,eAAO,MAAM,aAAa,QAAa,CAAC;AAExC,qDAAqD;AACrD,eAAO,MAAM,aAAa,QAAQ,CAAC;AAEnC,uDAAuD;AACvD,eAAO,MAAM,aAAa,EAAE,MAAM,EAOjC,CAAC;AAEF,0EAA0E;AAC1E,eAAO,MAAM,eAAe,EAAE,MAAM,EASnC,CAAC;AAEF,6CAA6C;AAC7C,eAAO,MAAM,cAAc,KAAK,CAAC;AAEjC,mDAAmD;AACnD,eAAO,MAAM,oBAAoB,QAAa,CAAC;AAE/C,yDAAyD;AACzD,eAAO,MAAM,YAAY,QAAkC,CAAC;AAE5D,6CAA6C;AAC7C,eAAO,MAAM,cAAc,QACoM,CAAC;AAEhO,iEAAiE;AACjE,eAAO,MAAM,YAAY,QACma,CAAC;AAE7b,uEAAuE;AACvE,eAAO,MAAM,iBAAiB,QAC0B,CAAC;AAEzD,mEAAmE;AACnE,eAAO,MAAM,mBAAmB,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,EAgBhE,CAAC;AAMF,MAAM,MAAM,WAAW,GACnB,cAAc,GACd,UAAU,GACV,aAAa,GACb,KAAK,GACL,OAAO,CAAC;AAEZ,MAAM,WAAW,SAAS;IACxB,mBAAmB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAAC;IACxD,KAAK,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;CAC7B;AAED,MAAM,WAAW,oBAAoB;IACnC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACvC;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,mBAAmB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5C,KAAK,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC7C,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,WAAW,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,OAAO,CAAA;KAAE,EAAE,CAAC;IACjE,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CACxB;AAED,MAAM,WAAW,mBAAmB;IAClC,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,mBAAmB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7C,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,SAAS,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAChD,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAMD,2FAA2F;AAC3F,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CA2B7C;AAMD,oEAAoE;AACpE,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG;IAC3C,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd,
|
|
1
|
+
{"version":3,"file":"design-token-utils.d.ts","sourceRoot":"","sources":["../../src/server/design-token-utils.ts"],"names":[],"mappings":"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"}
|
|
@@ -102,41 +102,73 @@ export function validateUrl(url) {
|
|
|
102
102
|
// ---------------------------------------------------------------------------
|
|
103
103
|
/** Parse a GitHub URL or "org/repo" shorthand into owner + repo. */
|
|
104
104
|
export function parseOwnerRepo(raw) {
|
|
105
|
-
const
|
|
105
|
+
const cleaned = raw
|
|
106
|
+
.trim()
|
|
107
|
+
.replace(/[?#].*$/, "")
|
|
108
|
+
.replace(/\/+$/, "");
|
|
109
|
+
const sshMatch = cleaned.match(/^(?:ssh:\/\/)?git@github\.com[:/]([^/]+)\/([^/]+?)(?:\.git)?$/);
|
|
110
|
+
if (sshMatch) {
|
|
111
|
+
return { owner: sshMatch[1], repo: sshMatch[2] };
|
|
112
|
+
}
|
|
113
|
+
const shorthand = cleaned.match(/^([^/\s]+)\/([^/\s]+?)(?:\.git)?$/);
|
|
106
114
|
if (shorthand) {
|
|
107
115
|
return { owner: shorthand[1], repo: shorthand[2] };
|
|
108
116
|
}
|
|
109
|
-
const urlMatch =
|
|
117
|
+
const urlMatch = cleaned.match(/github\.com[:/]([^/]+)\/([^/]+?)(?:\.git)?(?:\/.*)?$/);
|
|
110
118
|
if (urlMatch) {
|
|
111
119
|
return { owner: urlMatch[1], repo: urlMatch[2] };
|
|
112
120
|
}
|
|
113
121
|
throw new Error("Could not parse GitHub owner/repo from URL. " +
|
|
114
|
-
'Expected format: "https://github.com/org/repo" or "org/repo"');
|
|
122
|
+
'Expected format: "https://github.com/org/repo", "org/repo", or "git@github.com:org/repo.git"');
|
|
115
123
|
}
|
|
116
124
|
/** Fetch a path from the GitHub Contents API as JSON. Returns null on error. */
|
|
117
|
-
|
|
125
|
+
function githubHeaders(accept, options = {}) {
|
|
126
|
+
return {
|
|
127
|
+
Accept: accept,
|
|
128
|
+
"User-Agent": "AgentNative/1.0",
|
|
129
|
+
...(options.token ? { Authorization: `Bearer ${options.token}` } : {}),
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
/** Fetch a path from the GitHub Contents API as JSON with status details. */
|
|
133
|
+
export async function fetchGitHubJsonResult(owner, repo, path, options = {}) {
|
|
118
134
|
const url = `https://api.github.com/repos/${owner}/${repo}/contents/${path}`;
|
|
119
135
|
validateUrl(url);
|
|
120
136
|
const res = await fetch(url, {
|
|
121
|
-
headers:
|
|
122
|
-
Accept: "application/vnd.github.v3+json",
|
|
123
|
-
"User-Agent": "AgentNative/1.0",
|
|
124
|
-
},
|
|
137
|
+
headers: githubHeaders("application/vnd.github.v3+json", options),
|
|
125
138
|
signal: AbortSignal.timeout(FETCH_TIMEOUT),
|
|
126
139
|
});
|
|
127
|
-
if (!res.ok)
|
|
128
|
-
|
|
129
|
-
|
|
140
|
+
if (!res.ok) {
|
|
141
|
+
let message;
|
|
142
|
+
try {
|
|
143
|
+
const body = (await res.json());
|
|
144
|
+
if (typeof body.message === "string")
|
|
145
|
+
message = body.message;
|
|
146
|
+
}
|
|
147
|
+
catch {
|
|
148
|
+
try {
|
|
149
|
+
const text = await res.text();
|
|
150
|
+
if (text)
|
|
151
|
+
message = text.slice(0, 200);
|
|
152
|
+
}
|
|
153
|
+
catch {
|
|
154
|
+
// Keep the status-only result.
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return { ok: false, status: res.status, data: null, message };
|
|
158
|
+
}
|
|
159
|
+
return { ok: true, status: res.status, data: (await res.json()) };
|
|
160
|
+
}
|
|
161
|
+
/** Fetch a path from the GitHub Contents API as JSON. Returns null on error. */
|
|
162
|
+
export async function fetchGitHubJson(owner, repo, path, options = {}) {
|
|
163
|
+
const result = await fetchGitHubJsonResult(owner, repo, path, options);
|
|
164
|
+
return result.ok ? result.data : null;
|
|
130
165
|
}
|
|
131
166
|
/** Fetch raw file content from the GitHub Contents API. Returns null on error or oversize. */
|
|
132
|
-
export async function fetchGitHubRaw(owner, repo, path) {
|
|
167
|
+
export async function fetchGitHubRaw(owner, repo, path, options = {}) {
|
|
133
168
|
const url = `https://api.github.com/repos/${owner}/${repo}/contents/${path}`;
|
|
134
169
|
validateUrl(url);
|
|
135
170
|
const res = await fetch(url, {
|
|
136
|
-
headers:
|
|
137
|
-
Accept: "application/vnd.github.v3.raw",
|
|
138
|
-
"User-Agent": "AgentNative/1.0",
|
|
139
|
-
},
|
|
171
|
+
headers: githubHeaders("application/vnd.github.v3.raw", options),
|
|
140
172
|
signal: AbortSignal.timeout(FETCH_TIMEOUT),
|
|
141
173
|
});
|
|
142
174
|
if (!res.ok)
|