@agent-native/core 0.158.9 → 0.159.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/corpus/templates/clips/app/components/recorder/recording-toolbar.tsx +2 -2
- package/corpus/templates/clips/app/i18n/en-US.ts +7 -2
- package/corpus/templates/clips/app/routes/record.tsx +147 -5
- package/dist/a2a/auth-policy.d.ts +0 -6
- package/dist/a2a/auth-policy.js +2 -1
- package/dist/a2a/client.js +10 -12
- package/dist/agent/durable-background.js +3 -2
- package/dist/agent/engine/registry.js +5 -4
- package/dist/agent/run-manager.js +8 -20
- package/dist/app-config/a2a.d.ts +14 -0
- package/dist/app-config/a2a.js +42 -0
- package/dist/app-config/agent.d.ts +18 -0
- package/dist/app-config/agent.js +69 -0
- package/dist/app-config/app.d.ts +33 -0
- package/dist/app-config/app.js +100 -0
- package/dist/app-config/describe.d.ts +26 -0
- package/dist/app-config/describe.js +61 -0
- package/dist/app-config/env-layer.d.ts +37 -0
- package/dist/app-config/env-layer.js +136 -0
- package/dist/app-config/index.d.ts +2 -0
- package/dist/app-config/index.js +2 -0
- package/dist/app-config/integrations.d.ts +5 -0
- package/dist/app-config/integrations.js +11 -0
- package/dist/app-config/private-blob.d.ts +14 -0
- package/dist/app-config/private-blob.js +19 -0
- package/dist/app-config/schema.d.ts +55 -0
- package/dist/app-config/schema.js +31 -0
- package/dist/app-config/store.d.ts +42 -0
- package/dist/app-config/store.js +104 -0
- package/dist/app-config/workspace.d.ts +21 -0
- package/dist/app-config/workspace.js +35 -0
- package/dist/cli/agent.js +2 -1
- package/dist/cli/code-agent-executor.js +5 -4
- package/dist/client/analytics.d.ts +9 -0
- package/dist/client/frame.js +11 -1
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/deploy/build.js +36 -0
- package/dist/file-upload/actions/upload-image.d.ts +1 -1
- package/dist/integrations/a2a-continuation-processor.js +12 -9
- package/dist/integrations/adapters/email.js +2 -1
- package/dist/integrations/adapters/telegram.js +2 -1
- package/dist/integrations/adapters/whatsapp.js +2 -1
- package/dist/integrations/webhook-handler.d.ts +7 -2
- package/dist/integrations/webhook-handler.js +9 -31
- package/dist/observability/routes.d.ts +5 -5
- package/dist/onboarding/app-profile.js +2 -4
- package/dist/onboarding/default-steps.js +4 -4
- package/dist/private-blob/registry.d.ts +5 -0
- package/dist/private-blob/registry.js +19 -8
- package/dist/progress/routes.d.ts +1 -1
- package/dist/provider-api/actions/custom-provider-registration.d.ts +13 -13
- package/dist/provider-api/actions/provider-api.d.ts +11 -11
- package/dist/provider-api/corpus-jobs.d.ts +2 -2
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/scripts/agent-engines/list-agent-engines.js +4 -2
- package/dist/secrets/routes.d.ts +9 -9
- package/dist/server/agent-chat/action-filters-a2a.js +5 -4
- package/dist/server/agent-chat/run-code-tools.js +3 -4
- package/dist/server/agent-chat-plugin.js +4 -3
- package/dist/server/agent-discovery.js +7 -5
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/app-origin-config.d.ts +23 -0
- package/dist/server/app-origin-config.js +43 -0
- package/dist/server/auth.js +21 -1
- package/dist/server/core-routes-plugin.js +3 -3
- package/dist/server/credential-provider.js +7 -8
- package/dist/server/embed-session.js +2 -1
- package/dist/server/identity-sso.js +6 -2
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.js +1 -0
- package/dist/server/oauth-public-origin.js +10 -14
- package/dist/server/oauth-return-url.js +5 -9
- package/dist/server/self-dispatch.js +5 -2
- package/dist/server/ssr-handler.js +2 -0
- package/dist/server/workspace-provider-oauth.js +2 -4
- package/dist/sharing/actions/create-agent-resource-link.js +2 -2
- package/dist/usage/metrics-store.js +2 -1
- package/package.json +3 -3
|
@@ -311,11 +311,9 @@ export declare function createProviderApiActions(runtime: Pick<ProviderApiRuntim
|
|
|
311
311
|
notes?: string | undefined;
|
|
312
312
|
scope?: "org" | "user" | undefined;
|
|
313
313
|
}, {
|
|
314
|
+
deleted?: undefined;
|
|
314
315
|
id?: undefined;
|
|
315
316
|
provider?: undefined;
|
|
316
|
-
deleted?: undefined;
|
|
317
|
-
found?: undefined;
|
|
318
|
-
message?: undefined;
|
|
319
317
|
providers: {
|
|
320
318
|
id: string;
|
|
321
319
|
label: string;
|
|
@@ -326,44 +324,46 @@ export declare function createProviderApiActions(runtime: Pick<ProviderApiRuntim
|
|
|
326
324
|
updatedAt: number;
|
|
327
325
|
}[];
|
|
328
326
|
count: number;
|
|
327
|
+
found?: undefined;
|
|
329
328
|
registered?: undefined;
|
|
330
329
|
label?: undefined;
|
|
330
|
+
message?: undefined;
|
|
331
331
|
} | {
|
|
332
|
-
id?: undefined;
|
|
333
332
|
deleted?: undefined;
|
|
334
|
-
|
|
333
|
+
id?: undefined;
|
|
335
334
|
providers?: undefined;
|
|
336
335
|
count?: undefined;
|
|
337
336
|
found: boolean;
|
|
338
337
|
provider: import("../custom-registry.js").CustomProviderConfig;
|
|
339
338
|
registered?: undefined;
|
|
340
339
|
label?: undefined;
|
|
340
|
+
message?: undefined;
|
|
341
341
|
} | {
|
|
342
|
-
provider?: undefined;
|
|
343
342
|
deleted?: undefined;
|
|
344
|
-
|
|
343
|
+
provider?: undefined;
|
|
345
344
|
providers?: undefined;
|
|
346
345
|
count?: undefined;
|
|
347
346
|
found: boolean;
|
|
348
347
|
id: string;
|
|
349
348
|
registered?: undefined;
|
|
350
349
|
label?: undefined;
|
|
350
|
+
message?: undefined;
|
|
351
351
|
} | {
|
|
352
352
|
provider?: undefined;
|
|
353
|
-
found?: undefined;
|
|
354
|
-
message?: undefined;
|
|
355
353
|
providers?: undefined;
|
|
356
354
|
count?: undefined;
|
|
355
|
+
found?: undefined;
|
|
357
356
|
deleted: boolean;
|
|
358
357
|
id: string;
|
|
359
358
|
registered?: undefined;
|
|
360
359
|
label?: undefined;
|
|
360
|
+
message?: undefined;
|
|
361
361
|
} | {
|
|
362
|
-
provider?: undefined;
|
|
363
362
|
deleted?: undefined;
|
|
364
|
-
|
|
363
|
+
provider?: undefined;
|
|
365
364
|
providers?: undefined;
|
|
366
365
|
count?: undefined;
|
|
366
|
+
found?: undefined;
|
|
367
367
|
registered: boolean;
|
|
368
368
|
id: string;
|
|
369
369
|
label: string;
|
|
@@ -73,6 +73,7 @@ export declare function createProviderCorpusJobAction(options: CreateProviderCor
|
|
|
73
73
|
offset?: unknown;
|
|
74
74
|
limit?: unknown;
|
|
75
75
|
}, {
|
|
76
|
+
deleted?: undefined;
|
|
76
77
|
jobs: {
|
|
77
78
|
id: string;
|
|
78
79
|
name: string;
|
|
@@ -83,7 +84,6 @@ export declare function createProviderCorpusJobAction(options: CreateProviderCor
|
|
|
83
84
|
updatedAt: string;
|
|
84
85
|
}[];
|
|
85
86
|
total: number;
|
|
86
|
-
deleted?: undefined;
|
|
87
87
|
jobId?: undefined;
|
|
88
88
|
} | {
|
|
89
89
|
jobs?: undefined;
|
|
@@ -91,9 +91,9 @@ export declare function createProviderCorpusJobAction(options: CreateProviderCor
|
|
|
91
91
|
deleted: boolean;
|
|
92
92
|
jobId: string;
|
|
93
93
|
} | {
|
|
94
|
+
deleted?: undefined;
|
|
94
95
|
jobs?: undefined;
|
|
95
96
|
total?: undefined;
|
|
96
|
-
deleted?: undefined;
|
|
97
97
|
jobId?: undefined;
|
|
98
98
|
hits: Record<string, unknown>[];
|
|
99
99
|
offset: number;
|
|
@@ -48,8 +48,8 @@ export declare function handleUpdateResource(event: any): Promise<import("./stor
|
|
|
48
48
|
}>;
|
|
49
49
|
/** DELETE /_agent-native/resources/:id — delete a resource */
|
|
50
50
|
export declare function handleDeleteResource(event: any): Promise<{
|
|
51
|
-
error: string;
|
|
52
51
|
ok?: undefined;
|
|
52
|
+
error: string;
|
|
53
53
|
} | {
|
|
54
54
|
error?: undefined;
|
|
55
55
|
ok: boolean;
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
import { getAgentAppModelDefaultForCurrentRequest } from "../../agent/app-model-defaults.js";
|
|
5
5
|
import { DEFAULT_MODEL } from "../../agent/default-model.js";
|
|
6
6
|
import { listAgentEngines, registerBuiltinEngines, detectEngineFromEnv, detectEngineFromUserSecrets, getAgentEngineEntry, isAgentEnginePackageInstalled, isStoredEngineUsableForRequest, normalizeModelForEngine, resolveEnginePreservesCustomModels, } from "../../agent/engine/index.js";
|
|
7
|
+
import { getAppConfig } from "../../app-config/index.js";
|
|
7
8
|
import { getSetting } from "../../settings/index.js";
|
|
8
9
|
export const tool = {
|
|
9
10
|
description: 'List all available AI agent engines (Anthropic, OpenAI, Gemini, Groq, etc.) and the currently selected engine. Use this to check what engines are available before calling manage-agent-engine with action="set".',
|
|
@@ -37,8 +38,9 @@ export async function run(args = {}) {
|
|
|
37
38
|
!!appDefaultEntry &&
|
|
38
39
|
(await isStoredEngineUsableForRequest(appDefault, appDefaultEntry));
|
|
39
40
|
const detectedFromUser = await detectEngineFromUserSecrets();
|
|
40
|
-
const
|
|
41
|
-
|
|
41
|
+
const configuredEngine = getAppConfig().agent.engine;
|
|
42
|
+
const envEntry = configuredEngine
|
|
43
|
+
? getAgentEngineEntry(configuredEngine)
|
|
42
44
|
: undefined;
|
|
43
45
|
const envUsable = !!envEntry &&
|
|
44
46
|
(await isStoredEngineUsableForRequest({ engine: envEntry.name }, envEntry));
|
package/dist/secrets/routes.d.ts
CHANGED
|
@@ -34,37 +34,37 @@ export declare function createListSecretsHandler(): import("h3").EventHandlerWit
|
|
|
34
34
|
/** POST /_agent-native/secrets/:key — write a secret. */
|
|
35
35
|
export declare function createWriteSecretHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
|
|
36
36
|
error: string;
|
|
37
|
-
status?: undefined;
|
|
38
37
|
ok?: undefined;
|
|
38
|
+
status?: undefined;
|
|
39
39
|
} | {
|
|
40
|
+
error?: undefined;
|
|
40
41
|
ok: boolean;
|
|
41
42
|
status: string;
|
|
42
|
-
error?: undefined;
|
|
43
43
|
} | {
|
|
44
|
+
ok?: undefined;
|
|
44
45
|
error: string;
|
|
45
46
|
removed?: undefined;
|
|
46
|
-
ok?: undefined;
|
|
47
47
|
} | {
|
|
48
|
+
error?: undefined;
|
|
48
49
|
ok: boolean;
|
|
49
50
|
removed: boolean;
|
|
50
|
-
error?: undefined;
|
|
51
51
|
}>>;
|
|
52
52
|
/**
|
|
53
53
|
* POST /_agent-native/secrets/:key/test — validate an optional candidate value
|
|
54
54
|
* or the current stored value without changing anything.
|
|
55
55
|
*/
|
|
56
56
|
export declare function createTestSecretHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
|
|
57
|
+
ok?: undefined;
|
|
57
58
|
error: string;
|
|
58
59
|
note?: undefined;
|
|
59
|
-
ok?: undefined;
|
|
60
60
|
} | {
|
|
61
|
+
error?: undefined;
|
|
61
62
|
ok: boolean;
|
|
62
63
|
note?: undefined;
|
|
63
|
-
error?: undefined;
|
|
64
64
|
} | {
|
|
65
|
+
error?: undefined;
|
|
65
66
|
ok: boolean;
|
|
66
67
|
note: string;
|
|
67
|
-
error?: undefined;
|
|
68
68
|
} | {
|
|
69
69
|
note?: undefined;
|
|
70
70
|
ok: boolean;
|
|
@@ -95,11 +95,11 @@ export interface AdHocSecretPayload {
|
|
|
95
95
|
export declare function createAdHocSecretHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<AdHocSecretPayload[] | {
|
|
96
96
|
error: string;
|
|
97
97
|
} | {
|
|
98
|
+
error?: undefined;
|
|
98
99
|
ok: boolean;
|
|
99
100
|
key: string;
|
|
100
|
-
error?: undefined;
|
|
101
101
|
} | {
|
|
102
|
+
error?: undefined;
|
|
102
103
|
ok: boolean;
|
|
103
104
|
removed: boolean;
|
|
104
|
-
error?: undefined;
|
|
105
105
|
}>>;
|
|
@@ -5,6 +5,7 @@ import { resolveMainChatMaxOutputTokens } from "../../agent/engine/output-tokens
|
|
|
5
5
|
import { filterInitialEngineTools, resolveAgentRequestReasoningEffort, } from "../../agent/production-agent.js";
|
|
6
6
|
import { runAgentLoopDirectWithSoftTimeout } from "../../agent/run-loop-with-resume.js";
|
|
7
7
|
import { resolveRunSoftTimeoutMs } from "../../agent/run-manager.js";
|
|
8
|
+
import { getAppConfig } from "../../app-config/index.js";
|
|
8
9
|
import { isFrameworkGroupedAction } from "../../framework-tools.js";
|
|
9
10
|
import { isAuthenticatedReadAction, isAutoReadExcludedActionName, } from "../../mcp/build-server.js";
|
|
10
11
|
import { withConfiguredAppBasePath } from "../app-base-path.js";
|
|
@@ -173,10 +174,10 @@ export function buildAuthenticatedAgentA2ASkills(actions, options) {
|
|
|
173
174
|
});
|
|
174
175
|
}
|
|
175
176
|
export function resolveArtifactBaseUrl(event) {
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
177
|
+
// An artifact link is user-facing, so the canonical URL wins; the platform's
|
|
178
|
+
// per-deploy URLs are the fallback, not the other way round (that ordering
|
|
179
|
+
// belongs to self-dispatch, which has to reach *this* deploy).
|
|
180
|
+
const fromEnv = getAppConfig().app.url ?? process.env.URL ?? process.env.DEPLOY_URL;
|
|
180
181
|
if (fromEnv)
|
|
181
182
|
return withConfiguredAppBasePath(String(fromEnv));
|
|
182
183
|
try {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { getAppConfig } from "../../app-config/index.js";
|
|
1
2
|
/**
|
|
2
3
|
* Load the sandboxed code-execution tool entries for one action registry:
|
|
3
4
|
* `run-code`, bounded `tool-orchestration`, plus its `get-code-execution` poll companion. The poll tool is
|
|
@@ -49,8 +50,6 @@ export async function loadRunCodeToolEntries(supplier, runCodeOptions) {
|
|
|
49
50
|
* persisted resource scoped to "this app deployment".
|
|
50
51
|
*/
|
|
51
52
|
function resolveDataProgramsAppId() {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
process.env.APP_NAME?.trim() ||
|
|
55
|
-
"app");
|
|
53
|
+
const app = getAppConfig().app;
|
|
54
|
+
return app.id ?? app.name ?? "app";
|
|
56
55
|
}
|
|
@@ -20,6 +20,7 @@ import { buildCurrentTimeUserContext, buildRuntimeContextPrompt, } from "../agen
|
|
|
20
20
|
import { buildAssistantMessage, buildUserMessage, claimQueuedMessage, extractThreadMeta, foldAssistantTurn, hasClaimedQueuedMessage, mergeThreadDataForClientSave, upsertUserMessage, } from "../agent/thread-data-builder.js";
|
|
21
21
|
import { appendThreadDebugHistory } from "../agent/thread-debug-history.js";
|
|
22
22
|
import { attachToolSearch } from "../agent/tool-search.js";
|
|
23
|
+
import { getAppConfig } from "../app-config/index.js";
|
|
23
24
|
import { readAppStateForCurrentTab } from "../application-state/script-helpers.js";
|
|
24
25
|
import { runChatThreadDataMigrations } from "../chat-threads/migrations.js";
|
|
25
26
|
import { adoptThreadScopeIfUnscoped, createThread, forkThread, getThread, registerChatThreadsShareable, resolveRunThreadScope, resolveThreadAccess, listThreads, searchThreads, renameThread, createThreadShareLink, getThreadByShareToken, getThreadShareState, revokeThreadShareLink, setThreadArchived, setThreadPinned, setThreadScope, updateThreadData, withThreadDataLock, deleteThread, setThreadQueuedMessages, setThreadSourceIfMissing, } from "../chat-threads/store.js";
|
|
@@ -315,7 +316,7 @@ export function createAgentChatPlugin(options) {
|
|
|
315
316
|
const hostedHarnessConfig = await loadHostedHarnessConfig();
|
|
316
317
|
// AGENT_MODE=production forces production agent constraints even in dev
|
|
317
318
|
const canToggle = (env === "development" || env === "test") &&
|
|
318
|
-
|
|
319
|
+
getAppConfig().agent.mode !== "production";
|
|
319
320
|
const routePath = options?.path ?? "/_agent-native/agent-chat";
|
|
320
321
|
const a2aAgentDelegationEnabled = resolveA2AAgentDelegationEnabled(options);
|
|
321
322
|
// Mutable mode flag — persisted to the `settings` table so a user who
|
|
@@ -3222,8 +3223,8 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
|
|
|
3222
3223
|
}
|
|
3223
3224
|
}));
|
|
3224
3225
|
const modelDefaultsAppId = normalizeAgentAppModelDefaultAppId(options?.appId ??
|
|
3225
|
-
|
|
3226
|
-
|
|
3226
|
+
getAppConfig().app.id ??
|
|
3227
|
+
getAppConfig().app.template ??
|
|
3227
3228
|
"app") ?? "app";
|
|
3228
3229
|
const resolveModelDefaultsContext = async (event) => {
|
|
3229
3230
|
const session = await getSession(event).catch(() => null);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
|
+
import { getAppConfig } from "../app-config/index.js";
|
|
4
5
|
import { TEMPLATES } from "../cli/templates-meta.js";
|
|
5
6
|
import { DEFAULT_WORKSPACE_APP_AUDIENCE, normalizeWorkspaceAppAudience, normalizeWorkspaceAppPathList, workspaceAppAudienceFromPackageJson, workspaceAppRouteAccessFromPackageJson, } from "../shared/workspace-app-audience.js";
|
|
6
7
|
import { getRequestOrgId, getRequestUserEmail } from "./request-context.js";
|
|
@@ -519,11 +520,12 @@ function readWorkspaceAppsFromFilesystem() {
|
|
|
519
520
|
return apps.length ? apps : null;
|
|
520
521
|
}
|
|
521
522
|
function workspaceBaseUrl() {
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
process.env.
|
|
523
|
+
const config = getAppConfig();
|
|
524
|
+
// `URL` / `DEPLOY_URL` stay raw: they are platform facts, not app config.
|
|
525
|
+
return (config.workspace.gatewayUrl ??
|
|
526
|
+
config.app.url ??
|
|
527
|
+
process.env.URL ??
|
|
528
|
+
process.env.DEPLOY_URL ??
|
|
527
529
|
null);
|
|
528
530
|
}
|
|
529
531
|
function workspaceAppUrl(app, hostedLoopbackFallbackUrl) {
|
|
@@ -27,10 +27,10 @@ export declare function resolveAgentEngineApiKeyWriteTarget(event: H3Event, scop
|
|
|
27
27
|
export declare function createAgentEngineApiKeyHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
|
|
28
28
|
error: any;
|
|
29
29
|
} | {
|
|
30
|
+
error?: undefined;
|
|
30
31
|
ok: boolean;
|
|
31
32
|
key: string;
|
|
32
33
|
baseUrlKey?: string;
|
|
33
34
|
scope: AgentEngineApiKeyScope;
|
|
34
|
-
error?: undefined;
|
|
35
35
|
}>>;
|
|
36
36
|
export {};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project this app's origins into the client shell.
|
|
3
|
+
*
|
|
4
|
+
* The browser needs these to build cross-frame and workspace-relative URLs.
|
|
5
|
+
* Historically that was done by mirroring each key with a `VITE_` twin, because
|
|
6
|
+
* Vite only inlines `VITE_`-prefixed variables into the bundle — so every
|
|
7
|
+
* consumer ended up writing both spellings, and half of each chain was dead on
|
|
8
|
+
* whichever side it happened to run.
|
|
9
|
+
*
|
|
10
|
+
* The mirror answered "how does this value reach the browser", never "what is
|
|
11
|
+
* this value". This is that answer instead: one declared field on the server,
|
|
12
|
+
* delivered through the same shell script Sentry and PostHog already use.
|
|
13
|
+
*
|
|
14
|
+
* Every value here is impersonal and identical for every visitor, which is what
|
|
15
|
+
* makes it safe inside the CDN-cached SSR shell (`guard:ssr-cache-shell`).
|
|
16
|
+
* Never add a per-user or per-request value to this object.
|
|
17
|
+
*/
|
|
18
|
+
export declare function resolvePublicAppOriginConfig(): {
|
|
19
|
+
appUrl?: string;
|
|
20
|
+
workspaceGatewayUrl?: string;
|
|
21
|
+
workspaceOAuthOrigin?: string;
|
|
22
|
+
} | null;
|
|
23
|
+
export declare function getAppOriginClientConfigScript(): string | null;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { getAppConfig } from "../app-config/index.js";
|
|
2
|
+
/**
|
|
3
|
+
* Project this app's origins into the client shell.
|
|
4
|
+
*
|
|
5
|
+
* The browser needs these to build cross-frame and workspace-relative URLs.
|
|
6
|
+
* Historically that was done by mirroring each key with a `VITE_` twin, because
|
|
7
|
+
* Vite only inlines `VITE_`-prefixed variables into the bundle — so every
|
|
8
|
+
* consumer ended up writing both spellings, and half of each chain was dead on
|
|
9
|
+
* whichever side it happened to run.
|
|
10
|
+
*
|
|
11
|
+
* The mirror answered "how does this value reach the browser", never "what is
|
|
12
|
+
* this value". This is that answer instead: one declared field on the server,
|
|
13
|
+
* delivered through the same shell script Sentry and PostHog already use.
|
|
14
|
+
*
|
|
15
|
+
* Every value here is impersonal and identical for every visitor, which is what
|
|
16
|
+
* makes it safe inside the CDN-cached SSR shell (`guard:ssr-cache-shell`).
|
|
17
|
+
* Never add a per-user or per-request value to this object.
|
|
18
|
+
*/
|
|
19
|
+
export function resolvePublicAppOriginConfig() {
|
|
20
|
+
const config = getAppConfig();
|
|
21
|
+
const resolved = {
|
|
22
|
+
...(config.app.url ? { appUrl: config.app.url } : {}),
|
|
23
|
+
...(config.workspace.gatewayUrl
|
|
24
|
+
? { workspaceGatewayUrl: config.workspace.gatewayUrl }
|
|
25
|
+
: {}),
|
|
26
|
+
...(config.workspace.oauthOrigin
|
|
27
|
+
? { workspaceOAuthOrigin: config.workspace.oauthOrigin }
|
|
28
|
+
: {}),
|
|
29
|
+
};
|
|
30
|
+
return Object.keys(resolved).length > 0 ? resolved : null;
|
|
31
|
+
}
|
|
32
|
+
export function getAppOriginClientConfigScript() {
|
|
33
|
+
const config = resolvePublicAppOriginConfig();
|
|
34
|
+
if (!config)
|
|
35
|
+
return null;
|
|
36
|
+
return [
|
|
37
|
+
"<script data-agent-native-app-origin-config>",
|
|
38
|
+
"window.__AGENT_NATIVE_CONFIG__=Object.assign({},window.__AGENT_NATIVE_CONFIG__,",
|
|
39
|
+
JSON.stringify(config),
|
|
40
|
+
");",
|
|
41
|
+
"</script>",
|
|
42
|
+
].join("");
|
|
43
|
+
}
|
package/dist/server/auth.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import crypto from "node:crypto";
|
|
2
2
|
import { defineEventHandler, getMethod, getQuery, getRequestIP, setResponseHeader, setResponseStatus, getCookie, setCookie, deleteCookie, getHeader, } from "h3";
|
|
3
|
+
import { getAppConfig } from "../app-config/index.js";
|
|
3
4
|
import { EMBED_START_PATH } from "../shared/embed-auth.js";
|
|
4
5
|
import { EMBED_TARGET_HEADER } from "../shared/embed-auth.js";
|
|
5
6
|
import { FIRST_RUN_ONBOARDING_COOKIE, FIRST_RUN_ONBOARDING_MAX_AGE, } from "../shared/first-run-onboarding.js";
|
|
@@ -425,6 +426,17 @@ function getSetCookieHeaders(headers) {
|
|
|
425
426
|
.map((value) => value.trim())
|
|
426
427
|
.filter(Boolean);
|
|
427
428
|
}
|
|
429
|
+
function cookieNames(header) {
|
|
430
|
+
return (header ?? "")
|
|
431
|
+
.split(";")
|
|
432
|
+
.map((part) => part.split("=", 1)[0]?.trim() ?? "")
|
|
433
|
+
.filter(Boolean);
|
|
434
|
+
}
|
|
435
|
+
function setCookieNames(headers) {
|
|
436
|
+
return getSetCookieHeaders(headers)
|
|
437
|
+
.map((cookie) => cookie.split("=", 1)[0]?.trim() ?? "")
|
|
438
|
+
.filter(Boolean);
|
|
439
|
+
}
|
|
428
440
|
function extractSessionTokenFromSetCookies(response) {
|
|
429
441
|
try {
|
|
430
442
|
for (const sc of getSetCookieHeaders(response.headers)) {
|
|
@@ -1683,6 +1695,9 @@ function logMagicLinkVerificationResponse(event, source, response, preConsume) {
|
|
|
1683
1695
|
responseLocation: redactMagicLinkUrl(response.headers.get("location") || "", getOrigin(event)),
|
|
1684
1696
|
producer: invalidToken ? "better-auth.magic-link.verify" : undefined,
|
|
1685
1697
|
reason: invalidToken ? "consumeVerificationValue returned null" : undefined,
|
|
1698
|
+
requestCookieNames: cookieNames(getHeader(event, "cookie")),
|
|
1699
|
+
responseSetCookieCount: getSetCookieHeaders(response.headers).length,
|
|
1700
|
+
responseSetCookieNames: setCookieNames(response.headers),
|
|
1686
1701
|
preConsume,
|
|
1687
1702
|
classification: invalidToken
|
|
1688
1703
|
? preConsume?.lookup === "present" && preConsume.expiryState === "valid"
|
|
@@ -2694,7 +2709,7 @@ function isHttpsRequest(event) {
|
|
|
2694
2709
|
const url = req?.url;
|
|
2695
2710
|
if (typeof url === "string" && url.startsWith("https://"))
|
|
2696
2711
|
return true;
|
|
2697
|
-
const appUrl =
|
|
2712
|
+
const appUrl = getAppConfig().app.url ?? "";
|
|
2698
2713
|
if (appUrl.startsWith("https://"))
|
|
2699
2714
|
return true;
|
|
2700
2715
|
}
|
|
@@ -3361,6 +3376,11 @@ async function mountBetterAuthRoutes(app, options) {
|
|
|
3361
3376
|
});
|
|
3362
3377
|
return oauthErrorPage(AUTH_MAGIC_LINK_FALLBACK);
|
|
3363
3378
|
}
|
|
3379
|
+
logMagicLinkDebug(event, "callback-session-lookup", {
|
|
3380
|
+
source: "desktop-callback",
|
|
3381
|
+
flow: oauthDebugFlowId(flowId),
|
|
3382
|
+
requestCookieNames: cookieNames(getHeader(event, "cookie")),
|
|
3383
|
+
});
|
|
3364
3384
|
const session = await getSession(event);
|
|
3365
3385
|
if (!session?.email || !session.token) {
|
|
3366
3386
|
setDesktopExchangeError(flowId, {
|
|
@@ -5,6 +5,7 @@ import { registerBuiltinEngines } from "../agent/engine/builtin.js";
|
|
|
5
5
|
import { OPENAI_BASE_URL_ENV_VAR, PROVIDER_ENV_META, } from "../agent/engine/provider-env-vars.js";
|
|
6
6
|
import { isAgentEngineSettingConfigured, getAgentEngineEntry, detectEngineFromEnv, detectEngineFromUserSecrets, isStoredEngineUsableForRequest, normalizeModelForEngine, } from "../agent/engine/registry.js";
|
|
7
7
|
import { canUpdateAgentLoopSettings, readAgentLoopSettings, resetAgentLoopSettings, validateMaxIterationsInput, writeAgentLoopSettings, } from "../agent/loop-settings.js";
|
|
8
|
+
import { getAppConfig } from "../app-config/index.js";
|
|
8
9
|
import { getState, putState, deleteState, listComposeDrafts, getComposeDraft, putComposeDraft, deleteComposeDraft, deleteAllComposeDrafts, getStateMany, } from "../application-state/handlers.js";
|
|
9
10
|
import { mountBrowserSessionRoutes } from "../browser-sessions/routes.js";
|
|
10
11
|
import { mountDbAdminRoutes } from "../db-admin/routes.js";
|
|
@@ -102,9 +103,8 @@ export async function resolveAgentEngineStatus(deps) {
|
|
|
102
103
|
openAiBaseUrlConfigured,
|
|
103
104
|
};
|
|
104
105
|
}
|
|
105
|
-
const
|
|
106
|
-
|
|
107
|
-
: undefined;
|
|
106
|
+
const configuredEngine = getAppConfig().agent.engine;
|
|
107
|
+
const envEntry = configuredEngine ? lookupEntry(configuredEngine) : undefined;
|
|
108
108
|
if (envEntry) {
|
|
109
109
|
if (!(await deps.isStoredEngineUsable({ engine: envEntry.name }, envEntry)))
|
|
110
110
|
return { configured: false, openAiBaseUrlConfigured };
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
*/
|
|
20
20
|
import { createHash } from "node:crypto";
|
|
21
21
|
import { CREDENTIAL_STORE_UNAVAILABLE_ERROR_CODE } from "../agent/engine/credential-errors.js";
|
|
22
|
+
import { getAppConfig } from "../app-config/index.js";
|
|
22
23
|
import { getDbExec, isLocalDatabase, isTransientDatabaseError, } from "../db/client.js";
|
|
23
24
|
import { getOrgSetting } from "../settings/org-settings.js";
|
|
24
25
|
import { getRequestUserEmail, getRequestOrgId } from "./request-context.js";
|
|
@@ -35,14 +36,12 @@ async function canReadDesignatedVaultFallback(vaultOrgId, credentialKey) {
|
|
|
35
36
|
// Manual mode is still usable across a Dispatch vault org and a separate
|
|
36
37
|
// app org, but only for this app's explicit active grant. The app identity
|
|
37
38
|
// comes from deployment configuration, never from request input.
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
.find((value) => value?.trim())
|
|
45
|
-
?.trim();
|
|
39
|
+
//
|
|
40
|
+
// `workspaceId` first is load-bearing: `vault_grants` rows are written with
|
|
41
|
+
// the id a workspace deploy assigns, so preferring the generic `id` would
|
|
42
|
+
// look grants up under a name nobody granted.
|
|
43
|
+
const app = getAppConfig().app;
|
|
44
|
+
const appId = app.workspaceId ?? app.id ?? app.name;
|
|
46
45
|
if (!appId) {
|
|
47
46
|
return { status: "denied", reason: "missing-app-id" };
|
|
48
47
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import crypto from "node:crypto";
|
|
2
2
|
import { getCookie, getHeader, getQuery, setCookie, setResponseHeader, } from "h3";
|
|
3
|
+
import { getAppConfig } from "../app-config/index.js";
|
|
3
4
|
import { getDbExec, intType, isPostgres } from "../db/client.js";
|
|
4
5
|
import { ensureTableExists } from "../db/ddl-guard.js";
|
|
5
6
|
import { EMBED_MODE_QUERY_PARAM, EMBED_SESSION_COOKIE, EMBED_TARGET_HEADER, EMBED_TARGET_QUERY_PARAM, EMBED_TOKEN_QUERY_PARAM, } from "../shared/embed-auth.js";
|
|
@@ -651,7 +652,7 @@ function isHttpsRequest(event) {
|
|
|
651
652
|
const url = event.url?.toString?.() ?? "";
|
|
652
653
|
if (url.startsWith("https://"))
|
|
653
654
|
return true;
|
|
654
|
-
const appUrl =
|
|
655
|
+
const appUrl = getAppConfig().app.url ?? "";
|
|
655
656
|
if (appUrl.startsWith("https://"))
|
|
656
657
|
return true;
|
|
657
658
|
}
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
import { createHash, randomBytes } from "node:crypto";
|
|
16
16
|
import { deleteCookie, getCookie, getHeader, getMethod, setCookie } from "h3";
|
|
17
17
|
import * as jose from "jose";
|
|
18
|
+
import { getAppConfig } from "../app-config/index.js";
|
|
18
19
|
import { GOOGLE_AUTH_REQUIRED_MESSAGE, isGoogleSignInRequiredForEmail, } from "../org/auth-policy.js";
|
|
19
20
|
import { SIGN_IN_ENTRY_PATH } from "../shared/sign-in-journey.js";
|
|
20
21
|
import { getAppName } from "./app-name.js";
|
|
@@ -98,8 +99,11 @@ function normalizeAuthority(raw) {
|
|
|
98
99
|
}
|
|
99
100
|
}
|
|
100
101
|
function resolveAppId(event) {
|
|
101
|
-
|
|
102
|
-
|
|
102
|
+
// Generic id first here, unlike credential scoping: SSO identifies this app
|
|
103
|
+
// instance to an authority, it does not look up a row keyed by the id a
|
|
104
|
+
// workspace deploy assigned.
|
|
105
|
+
const app = getAppConfig().app;
|
|
106
|
+
const configured = app.id ?? app.workspaceId;
|
|
103
107
|
if (configured)
|
|
104
108
|
return configured;
|
|
105
109
|
const name = getAppName();
|
package/dist/server/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export { defineAppConfig, getAppConfig, resetAppConfigForTests, appConfigSchema, type AppConfig, type AppConfigInput, } from "../app-config/index.js";
|
|
1
2
|
export { createServer, type CreateServerOptions, type EnvKeyConfig, } from "./create-server.js";
|
|
2
3
|
export { startIntervalJob, type IntervalJobOptions, type IntervalJobHandle, } from "./interval-job.js";
|
|
3
4
|
export { AGENT_BACKGROUND_PROCESSOR_FIELD, AGENT_BACKGROUND_PROCESSOR_ROUTE, AGENT_BACKGROUND_PROCESSOR_ROUTE_FIELD, dispatchPathTargetsNetlifyBackgroundFunction, isInBackgroundFunctionRuntime, resolveDurableBackgroundDispatchPath, } from "../agent/durable-background.js";
|
package/dist/server/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export { defineAppConfig, getAppConfig, resetAppConfigForTests, appConfigSchema, } from "../app-config/index.js";
|
|
1
2
|
export { createServer, } from "./create-server.js";
|
|
2
3
|
export { startIntervalJob, } from "./interval-job.js";
|
|
3
4
|
export { AGENT_BACKGROUND_PROCESSOR_FIELD, AGENT_BACKGROUND_PROCESSOR_ROUTE, AGENT_BACKGROUND_PROCESSOR_ROUTE_FIELD, dispatchPathTargetsNetlifyBackgroundFunction, isInBackgroundFunctionRuntime, resolveDurableBackgroundDispatchPath, } from "../agent/durable-background.js";
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { getAppConfig } from "../app-config/index.js";
|
|
1
2
|
function normalizeOrigin(raw) {
|
|
2
3
|
if (!raw)
|
|
3
4
|
return "";
|
|
@@ -21,21 +22,16 @@ function isLoopbackOrigin(origin) {
|
|
|
21
22
|
}
|
|
22
23
|
}
|
|
23
24
|
export function getPublicOAuthOrigin() {
|
|
25
|
+
const config = getAppConfig();
|
|
26
|
+
// An OAuth callback has to be publicly reachable, so a loopback origin is
|
|
27
|
+
// useless and we keep looking. This used to walk eight env keys — each
|
|
28
|
+
// canonical spelling followed by its `VITE_` mirror — so a loopback
|
|
29
|
+
// `APP_URL` could still fall through to a public `BETTER_AUTH_URL`. Those
|
|
30
|
+
// are one declared value now, so the skip is per concept, not per spelling.
|
|
24
31
|
for (const raw of [
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
process.env.VITE_APP_URL,
|
|
29
|
-
process.env.BETTER_AUTH_URL,
|
|
30
|
-
process.env.VITE_BETTER_AUTH_URL,
|
|
31
|
-
]) {
|
|
32
|
-
const origin = normalizeOrigin(raw);
|
|
33
|
-
if (origin && !isLoopbackOrigin(origin))
|
|
34
|
-
return origin;
|
|
35
|
-
}
|
|
36
|
-
for (const raw of [
|
|
37
|
-
process.env.WORKSPACE_GATEWAY_URL,
|
|
38
|
-
process.env.VITE_WORKSPACE_GATEWAY_URL,
|
|
32
|
+
config.workspace.oauthOrigin,
|
|
33
|
+
config.app.url,
|
|
34
|
+
config.workspace.gatewayUrl,
|
|
39
35
|
]) {
|
|
40
36
|
const origin = normalizeOrigin(raw);
|
|
41
37
|
if (origin && !isLoopbackOrigin(origin))
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { getAppConfig } from "../app-config/index.js";
|
|
1
2
|
function normalizeOrigin(raw) {
|
|
2
3
|
if (!raw)
|
|
3
4
|
return "";
|
|
@@ -39,15 +40,10 @@ function isBuilderPreviewOrigin(origin) {
|
|
|
39
40
|
}
|
|
40
41
|
}
|
|
41
42
|
export function getWorkspaceGatewayReturnOrigin() {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
const origin = normalizeOrigin(raw);
|
|
47
|
-
if (origin && isLoopbackOrigin(origin))
|
|
48
|
-
return origin;
|
|
49
|
-
}
|
|
50
|
-
return "";
|
|
43
|
+
// Loopback-only, inverted from getPublicOAuthOrigin: this is the local-dev
|
|
44
|
+
// gateway a return URL may point back at.
|
|
45
|
+
const origin = normalizeOrigin(getAppConfig().workspace.gatewayUrl);
|
|
46
|
+
return origin && isLoopbackOrigin(origin) ? origin : "";
|
|
51
47
|
}
|
|
52
48
|
function allowedOAuthReturnOrigins(allowDefaultLoopback) {
|
|
53
49
|
const out = new Set();
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { getAppConfig } from "../app-config/index.js";
|
|
1
2
|
import { isLocalDatabase } from "../db/client.js";
|
|
2
3
|
import { signInternalToken } from "../integrations/internal-token.js";
|
|
3
4
|
/**
|
|
@@ -57,11 +58,13 @@ function readHeader(event, name) {
|
|
|
57
58
|
* fallback to a bad host there would drop background work invisibly.
|
|
58
59
|
*/
|
|
59
60
|
export function resolveSelfDispatchBaseUrl(event) {
|
|
61
|
+
// The first three are platform facts — Netlify sets them per deploy, and
|
|
62
|
+
// they are what makes this resolve to *this* deployment rather than the
|
|
63
|
+
// canonical one. `app.url` is the last rung, not the first, for that reason.
|
|
60
64
|
const fromEnv = process.env.DEPLOY_PRIME_URL ||
|
|
61
65
|
process.env.DEPLOY_URL ||
|
|
62
66
|
process.env.URL ||
|
|
63
|
-
|
|
64
|
-
process.env.BETTER_AUTH_URL;
|
|
67
|
+
getAppConfig().app.url;
|
|
65
68
|
if (fromEnv)
|
|
66
69
|
return withConfiguredAppBasePath(String(fromEnv));
|
|
67
70
|
if (process.env.NODE_ENV === "production" || !isLocalDatabase()) {
|
|
@@ -21,6 +21,7 @@ import { isMcpPublicPath } from "../mcp/route-paths.js";
|
|
|
21
21
|
import { DEFAULT_SPECULATION_RULES_PATH, resolveSsrCacheHeaders, resolveSsrCacheKeyHeaders, } from "../shared/cache-control.js";
|
|
22
22
|
import { AGENT_NATIVE_SOCIAL_IMAGE_ALT, AGENT_NATIVE_SOCIAL_IMAGE_HEIGHT, AGENT_NATIVE_SOCIAL_IMAGE_PATH, AGENT_NATIVE_SOCIAL_IMAGE_TYPE, AGENT_NATIVE_SOCIAL_IMAGE_WIDTH, withAgentNativeSocialImageCacheBuster, } from "../shared/social-meta.js";
|
|
23
23
|
import { getAppBasePathFromViteEnv, stripAppBasePath as canonicalStripAppBasePath, } from "./app-base-path.js";
|
|
24
|
+
import { getAppOriginClientConfigScript } from "./app-origin-config.js";
|
|
24
25
|
import { captureError } from "./capture-error.js";
|
|
25
26
|
import { getPostHogClientConfigScript } from "./posthog-config.js";
|
|
26
27
|
import { runWithRequestContext } from "./request-context.js";
|
|
@@ -307,6 +308,7 @@ async function rewriteMountedResponse(response, basePath, pathname, requestUrl)
|
|
|
307
308
|
getSentryClientConfigScript(),
|
|
308
309
|
getPostHogClientConfigScript(),
|
|
309
310
|
getRealtimeClientConfigScript(),
|
|
311
|
+
getAppOriginClientConfigScript(),
|
|
310
312
|
]
|
|
311
313
|
.filter(Boolean)
|
|
312
314
|
.join("") || null;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import crypto from "node:crypto";
|
|
2
2
|
import { deleteCookie, defineEventHandler, getCookie, getMethod, getQuery, setCookie, setResponseStatus, } from "h3";
|
|
3
|
+
import { getAppConfig } from "../app-config/index.js";
|
|
3
4
|
import { getWorkspaceConnectionProvider, } from "../connections/catalog.js";
|
|
4
5
|
import { saveOAuthTokens, setOAuthDisplayName } from "../oauth-tokens/store.js";
|
|
5
6
|
import { getRegisteredAppRoles, resolveAppRole } from "../org/app-roles.js";
|
|
@@ -44,10 +45,7 @@ export async function handleWorkspaceProviderOAuthStart(event, providerId) {
|
|
|
44
45
|
if (!session?.email)
|
|
45
46
|
return unauthorized(event);
|
|
46
47
|
const query = getQuery(event);
|
|
47
|
-
const appId = normalizeAppId(text(query.appId) ??
|
|
48
|
-
process.env.AGENT_NATIVE_WORKSPACE_APP_ID ??
|
|
49
|
-
process.env.VITE_AGENT_NATIVE_WORKSPACE_APP_ID ??
|
|
50
|
-
"creative-context");
|
|
48
|
+
const appId = normalizeAppId(text(query.appId) ?? getAppConfig().app.workspaceId ?? "creative-context");
|
|
51
49
|
const orgContext = await requireWorkspaceProviderOAuthAdmin(event, appId);
|
|
52
50
|
if (!orgContext) {
|
|
53
51
|
return { error: WORKSPACE_OAUTH_ADMIN_ERROR };
|