@agent-native/core 0.205.0 → 0.206.0-nightly-20261009011246
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/a2a/client.d.ts +2 -2
- package/dist/agent/engine/anthropic-engine.d.ts +1 -1
- package/dist/agent/engine/builder-engine.d.ts +1 -1
- package/dist/agent/engine/builder-engine.js +23 -8
- package/dist/agent/engine/error-telemetry.d.ts +5 -0
- package/dist/agent/engine/error-telemetry.js +41 -0
- package/dist/agent/engine/registry.d.ts +1 -6
- package/dist/agent/engine/registry.js +2 -31
- package/dist/agent/model-config.d.ts +26 -14
- package/dist/agent/model-config.js +131 -8
- package/dist/agent/model-version.d.ts +19 -0
- package/dist/agent/model-version.js +153 -0
- package/dist/agent/production-agent.d.ts +1 -0
- package/dist/agent/production-agent.js +24 -6
- package/dist/agent/provider-model-selection.js +6 -4
- package/dist/agent/run-manager.js +5 -11
- package/dist/agent/thread-data-builder.js +14 -6
- package/dist/authorization/check-action.js +8 -4
- package/dist/chat-threads/store.js +22 -9
- package/dist/client/analytics.d.ts +1 -0
- package/dist/client/analytics.js +10 -2
- package/dist/client/chat/runtime.js +18 -0
- package/dist/client/chat-model-groups.d.ts +3 -0
- package/dist/client/error-format.js +10 -7
- package/dist/client/onboarding/use-onboarding.d.ts +12 -0
- package/dist/client/onboarding/use-onboarding.js +491 -4
- package/dist/client/session-replay-privacy.d.ts +8 -0
- package/dist/client/session-replay-privacy.js +8 -0
- package/dist/client/session-replay.d.ts +1 -0
- package/dist/client/session-replay.js +18 -9
- package/dist/client/sse-event-processor.js +10 -6
- package/dist/client/use-chat-models.d.ts +5 -0
- package/dist/client/use-chat-models.js +51 -5
- package/dist/client/use-session.d.ts +8 -1
- package/dist/client/use-session.js +20 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/deploy/build.js +353 -3
- package/dist/file-upload/actions/upload-image.d.ts +2 -2
- package/dist/jobs/backfill-run-history-ownership.d.ts +12 -0
- package/dist/jobs/backfill-run-history-ownership.js +87 -0
- package/dist/jobs/background-automation-runner.js +3 -9
- package/dist/jobs/remote-execution.js +3 -9
- package/dist/jobs/run-history-ownership.d.ts +5 -0
- package/dist/jobs/run-history-ownership.js +16 -0
- package/dist/jobs/run-now.js +2 -3
- package/dist/localization/agent-resources-messages.d.ts +3 -0
- package/dist/localization/agent-resources-messages.js +33 -0
- package/dist/mcp/actions/create-org-service-token.js +5 -7
- package/dist/mcp/build-server.d.ts +23 -18
- package/dist/mcp/build-server.js +220 -212
- package/dist/mcp/connect-route.d.ts +11 -2
- package/dist/mcp/connect-route.js +34 -24
- package/dist/mcp/connect-store.d.ts +9 -13
- package/dist/mcp/connect-store.js +11 -24
- package/dist/mcp/credential-membership.js +17 -6
- package/dist/mcp/oauth-route.d.ts +11 -1
- package/dist/mcp/oauth-route.js +28 -6
- package/dist/mcp/oauth-token.d.ts +12 -2
- package/dist/mcp/oauth-token.js +15 -4
- package/dist/mcp/server.js +9 -5
- package/dist/notifications/routes.d.ts +2 -2
- package/dist/observability/posthog-ai.d.ts +1 -0
- package/dist/observability/posthog-ai.js +20 -8
- package/dist/observability/routes.d.ts +6 -6
- package/dist/observability/traces.js +61 -39
- package/dist/org/app-roles.d.ts +8 -1
- package/dist/org/app-roles.js +29 -9
- package/dist/org/context.js +24 -8
- package/dist/org/index.d.ts +2 -2
- package/dist/org/workspace-app-identity.d.ts +1 -0
- package/dist/org/workspace-app-identity.js +25 -0
- package/dist/progress/routes.d.ts +1 -1
- package/dist/provider-api/actions/custom-provider-registration.d.ts +11 -11
- package/dist/provider-api/actions/provider-api.d.ts +3 -3
- package/dist/provider-api/corpus-jobs.d.ts +2 -2
- package/dist/scripts/agent-engines/list-agent-engines.js +1 -0
- package/dist/server/action-routes.js +8 -1
- package/dist/server/agent-chat-plugin.js +1 -0
- package/dist/server/agent-engine-default-model-route.d.ts +1 -1
- package/dist/server/auth.js +33 -17
- package/dist/server/bearer-credential-refusal.d.ts +23 -0
- package/dist/server/bearer-credential-refusal.js +67 -0
- package/dist/server/better-auth-instance.js +13 -6
- package/dist/server/builder-browser.d.ts +2 -0
- package/dist/server/builder-browser.js +16 -3
- package/dist/server/capture-error.d.ts +1 -0
- package/dist/server/capture-error.js +28 -4
- package/dist/server/complete-text.js +16 -3
- package/dist/server/core-routes-plugin.js +2 -0
- package/dist/server/dev-action-bridge.js +7 -1
- package/dist/server/google-oauth.js +6 -3
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.js +1 -1
- package/dist/server/realtime-token.d.ts +1 -1
- package/dist/server/recap-image-route.js +4 -0
- package/dist/server/request-context.d.ts +16 -0
- package/dist/server/request-context.js +17 -0
- package/dist/shared/agent-chat-context.d.ts +1 -0
- package/dist/shared/agent-chat-context.js +26 -0
- package/dist/shared/index.d.ts +1 -1
- package/dist/shared/index.js +1 -1
- package/dist/shared/reasoning-effort.js +10 -1
- package/dist/shared/ssr-session-bootstrap.d.ts +7 -0
- package/dist/shared/ssr-session-bootstrap.js +21 -0
- package/dist/sharing/access.js +86 -5
- package/dist/templates/builder-code-starter/server/routes/index.get.ts +2 -0
- package/dist/triggers/routes.js +2 -1
- package/docs/content/automation-connectors.mdx +5 -3
- package/docs/content/automations.mdx +78 -49
- package/docs/content/observability.mdx +16 -5
- package/docs/content/organizations-teams-permissions.mdx +44 -2
- package/docs/content/recurring-jobs.mdx +4 -8
- package/docs/content/template-forms.mdx +6 -0
- package/package.json +5 -4
- package/src/templates/builder-code-starter/server/routes/index.get.ts +2 -0
|
@@ -504,17 +504,21 @@ async function readChunkWithProgressTimeout(reader, lastMeaningfulEventAt, noPro
|
|
|
504
504
|
function isAutoRecoverableError(ev, errMsg) {
|
|
505
505
|
const code = String(ev.errorCode ?? "").toLowerCase();
|
|
506
506
|
const msg = errMsg.toLowerCase();
|
|
507
|
-
//
|
|
508
|
-
// list as well as the message sniff — matching the server's
|
|
509
|
-
// `isRecoverableContinuationError`. The repeat guards stop a turn with a
|
|
507
|
+
// Explicit terminal classifications outrank EVERY inference below — the
|
|
508
|
+
// code list as well as the message sniff — matching the server's precedence
|
|
509
|
+
// in `isRecoverableContinuationError`. The repeat guards stop a turn with a
|
|
510
510
|
// message that names the looping tool, so a stop on
|
|
511
511
|
// `list-workspace-connections` matched the "connection" sniff and
|
|
512
512
|
// auto-continued the very loop it was emitted to break; the background
|
|
513
513
|
// no-progress breaker stops one while PRESERVING the underlying transient
|
|
514
514
|
// code (so the failure stays diagnosable), so reading the code instead of the
|
|
515
515
|
// flag re-POSTs the exact chain the server just refused to continue.
|
|
516
|
-
if (ev.recoverable === false)
|
|
516
|
+
if (ev.providerRetryable === false || ev.recoverable === false)
|
|
517
517
|
return false;
|
|
518
|
+
// A recoverable server timeout is a continuation boundary, even though its
|
|
519
|
+
// visitor-facing message sounds terminal.
|
|
520
|
+
if (code === "run_timeout" && ev.recoverable === true)
|
|
521
|
+
return true;
|
|
518
522
|
// These messages can carry `recoverable: true` for banner rendering, but
|
|
519
523
|
// repeating the request would retry the same rejected credential or a run
|
|
520
524
|
// the user already stopped.
|
|
@@ -539,6 +543,7 @@ function isAutoRecoverableError(ev, errMsg) {
|
|
|
539
543
|
code === "gateway_not_enabled" ||
|
|
540
544
|
code === "missing_api_key" ||
|
|
541
545
|
code === "missing_credentials" ||
|
|
546
|
+
code === "invalid_request" ||
|
|
542
547
|
code === "invalid_request_error" ||
|
|
543
548
|
code === "request_too_large" ||
|
|
544
549
|
code === "not_found_error" ||
|
|
@@ -1619,8 +1624,7 @@ export function processEvent(ev, content, toolCallCounter, tabId, state, context
|
|
|
1619
1624
|
}
|
|
1620
1625
|
if (ev.type === "error") {
|
|
1621
1626
|
const errMsg = ev.error ?? "Unknown error";
|
|
1622
|
-
if ((ev
|
|
1623
|
-
isAutoRecoverableError(ev, errMsg)) {
|
|
1627
|
+
if (isAutoRecoverableError(ev, errMsg)) {
|
|
1624
1628
|
const normalized = normalizeChatError(errMsg, ev.errorCode);
|
|
1625
1629
|
return {
|
|
1626
1630
|
action: "auto_continue",
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { DEFAULT_MODEL } from "../agent/default-model.js";
|
|
2
|
+
import { type ModelEngineConfig } from "../agent/model-version.js";
|
|
2
3
|
export { DEFAULT_MODEL };
|
|
3
4
|
import { type ReasoningEffort } from "../shared/reasoning-effort.js";
|
|
4
5
|
import { type EngineModelGroup } from "./chat-model-groups.js";
|
|
@@ -36,6 +37,10 @@ export interface PersistedModelSelection {
|
|
|
36
37
|
export type ChatModelCatalogLoad = {
|
|
37
38
|
state: "available";
|
|
38
39
|
groups: EngineModelGroup[];
|
|
40
|
+
/** Runtime normalization config for the engines represented in groups. */
|
|
41
|
+
modelEngines: Readonly<Record<string, ModelEngineConfig>>;
|
|
42
|
+
/** The server-selected engine, independent of a persisted chat choice. */
|
|
43
|
+
currentModelEngine: ModelEngineConfig | null;
|
|
39
44
|
/** The server's current model, or `DEFAULT_MODEL` when it names none. */
|
|
40
45
|
defaultModel: string;
|
|
41
46
|
/**
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useCallback, useEffect, useRef, useState } from "react";
|
|
2
2
|
import { DEFAULT_MODEL } from "../agent/default-model.js";
|
|
3
|
-
import {
|
|
3
|
+
import { upgradeModelForProvider, } from "../agent/model-version.js";
|
|
4
4
|
export { DEFAULT_MODEL };
|
|
5
5
|
import { DEFAULT_REASONING_EFFORT, getReasoningEffortOptionsForModel, resolveReasoningEffortSelection, } from "../shared/reasoning-effort.js";
|
|
6
6
|
import { fetchOllamaModels } from "./agent-engine-key.js";
|
|
@@ -54,6 +54,7 @@ export async function loadChatModelCatalog() {
|
|
|
54
54
|
const builderConnected = builderResult.value?.configured === true;
|
|
55
55
|
const currentEngineName = enginesData.current?.engine;
|
|
56
56
|
const currentModel = enginesData.current?.model;
|
|
57
|
+
const currentEngine = enginesData.engines.find((engine) => engine.name === currentEngineName);
|
|
57
58
|
const build = (engines) => buildChatModelGroups({
|
|
58
59
|
engines,
|
|
59
60
|
configuredKeys,
|
|
@@ -61,10 +62,55 @@ export async function loadChatModelCatalog() {
|
|
|
61
62
|
currentEngineName,
|
|
62
63
|
currentModel,
|
|
63
64
|
});
|
|
65
|
+
const groups = build(enginesData.engines);
|
|
66
|
+
const modelEngines = Object.fromEntries(enginesData.engines.flatMap((engine) => {
|
|
67
|
+
if (!engine.defaultModel)
|
|
68
|
+
return [];
|
|
69
|
+
const selectableModels = groups
|
|
70
|
+
.filter((group) => group.engine === engine.name)
|
|
71
|
+
.flatMap((group) => group.models);
|
|
72
|
+
const supportedModels = engine.runtimeSupportedModels ??
|
|
73
|
+
engine.supportedModels ??
|
|
74
|
+
selectableModels;
|
|
75
|
+
if (supportedModels.length === 0)
|
|
76
|
+
return [];
|
|
77
|
+
return [
|
|
78
|
+
[
|
|
79
|
+
engine.name,
|
|
80
|
+
{
|
|
81
|
+
name: engine.name,
|
|
82
|
+
label: engine.label,
|
|
83
|
+
defaultModel: engine.defaultModel,
|
|
84
|
+
supportedModels,
|
|
85
|
+
selectableModels,
|
|
86
|
+
...(engine.acceptsCustomModels
|
|
87
|
+
? { acceptsCustomModels: true }
|
|
88
|
+
: {}),
|
|
89
|
+
...(engine.preserveCustomModels
|
|
90
|
+
? { preserveCustomModels: true }
|
|
91
|
+
: {}),
|
|
92
|
+
},
|
|
93
|
+
],
|
|
94
|
+
];
|
|
95
|
+
}));
|
|
96
|
+
const currentModelEngine = currentEngineName
|
|
97
|
+
? (modelEngines[currentEngineName] ?? null)
|
|
98
|
+
: null;
|
|
99
|
+
const currentEngineModels = groups
|
|
100
|
+
.filter((group) => group.engine === currentEngineName)
|
|
101
|
+
.flatMap((group) => group.models);
|
|
102
|
+
const defaultModelCandidates = currentEngine?.runtimeSupportedModels ?? currentEngineModels;
|
|
103
|
+
const defaultModel = currentModel
|
|
104
|
+
? currentEngine?.preserveCustomModels
|
|
105
|
+
? currentModel
|
|
106
|
+
: (upgradeModelForProvider(currentModel, defaultModelCandidates, currentEngineName ?? "") ?? currentModel)
|
|
107
|
+
: DEFAULT_MODEL;
|
|
64
108
|
return {
|
|
65
109
|
state: "available",
|
|
66
|
-
groups
|
|
67
|
-
|
|
110
|
+
groups,
|
|
111
|
+
modelEngines,
|
|
112
|
+
currentModelEngine,
|
|
113
|
+
defaultModel,
|
|
68
114
|
loadLiveGroups: async () => {
|
|
69
115
|
// Gated on Ollama actually being the current engine (not merely present
|
|
70
116
|
// in the catalog, which it always is): every app registers it by
|
|
@@ -300,14 +346,14 @@ export function useChatModels({ storageKey = DEFAULT_STORAGE_KEY, enabled = true
|
|
|
300
346
|
const model = group.preserveCustomModels &&
|
|
301
347
|
selection.selectedEngine === group.engine
|
|
302
348
|
? selection.selectedModel
|
|
303
|
-
:
|
|
349
|
+
: upgradeModelForProvider(selection.selectedModel, group.models, group.engine);
|
|
304
350
|
return model ? [{ group, model }] : [];
|
|
305
351
|
});
|
|
306
352
|
const upgradeCandidateKeys = new Set(upgradeCandidates.map(({ group, model }) => JSON.stringify([group.engine, model])));
|
|
307
353
|
const upgradedSelection = upgradeCandidateKeys.size === 1 ? upgradeCandidates[0] : undefined;
|
|
308
354
|
const selectedGroup = exactSelectedGroup ?? upgradedSelection?.group;
|
|
309
355
|
if (selectedGroup) {
|
|
310
|
-
const selectedModel =
|
|
356
|
+
const selectedModel = upgradeModelForProvider(selection.selectedModel, selectedGroup.models, selectedGroup.engine) ?? selection.selectedModel;
|
|
311
357
|
const nextSelection = {
|
|
312
358
|
...selection,
|
|
313
359
|
selectedModel,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { AuthSession } from "../server/auth.js";
|
|
2
2
|
export type { AuthSession };
|
|
3
|
-
export { isSessionNavigationPending } from "../shared/ssr-session-bootstrap.js";
|
|
3
|
+
export { hasSessionHint, isSessionNavigationPending, } from "../shared/ssr-session-bootstrap.js";
|
|
4
4
|
/**
|
|
5
5
|
* What the session endpoint said that the page acted on: a signed-out body,
|
|
6
6
|
* an HTTP 401, or a signed-in answer. Recorded with every session-driven
|
|
@@ -25,6 +25,13 @@ interface UseSessionResult {
|
|
|
25
25
|
}
|
|
26
26
|
export declare function notifySessionInvalidated(): void;
|
|
27
27
|
export declare function isSigningOut(): boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Whether the session this tab holds is the answer to the page load's first
|
|
30
|
+
* session read. A request the load sent before the session was known belongs
|
|
31
|
+
* to the account this session names only while this holds: once a retry or an
|
|
32
|
+
* invalidation answers instead, another tab may have changed the cookies.
|
|
33
|
+
*/
|
|
34
|
+
export declare function isSessionFromFirstRead(): boolean;
|
|
28
35
|
/**
|
|
29
36
|
* Re-resolve the session because an authenticated request came back 401.
|
|
30
37
|
*
|
|
@@ -4,7 +4,7 @@ import { setSentryUser, trackEvent, trackSessionStatus } from "./analytics.js";
|
|
|
4
4
|
import { agentNativeApiDisabledReason } from "./api-surface.js";
|
|
5
5
|
import { expireClientStatusResult, fetchAuthSessionStatus, invalidateClientStatusRequest, SESSION_RESULT_LIFETIME_MS, } from "./client-status-requests.js";
|
|
6
6
|
import { getFrameOrigin, getFramePostMessageTargetOrigin } from "./frame.js";
|
|
7
|
-
export { isSessionNavigationPending } from "../shared/ssr-session-bootstrap.js";
|
|
7
|
+
export { hasSessionHint, isSessionNavigationPending, } from "../shared/ssr-session-bootstrap.js";
|
|
8
8
|
let cachedEvidence;
|
|
9
9
|
let lastResolution;
|
|
10
10
|
/**
|
|
@@ -47,6 +47,11 @@ let sessionRequest;
|
|
|
47
47
|
let trackedSessionIdentity;
|
|
48
48
|
let trackedSessionAuthUserId;
|
|
49
49
|
let sessionGeneration = 0;
|
|
50
|
+
// The page load's own session read is the only one sent with the cookies a
|
|
51
|
+
// request made before the session was known also carried. A retry or a reset
|
|
52
|
+
// replaces it for the life of the document.
|
|
53
|
+
let firstSessionReadUnsent = true;
|
|
54
|
+
let cachedSessionFromFirstRead = false;
|
|
50
55
|
let sessionInvalidationListenersInstalled = false;
|
|
51
56
|
let staleSessionRecheck;
|
|
52
57
|
let signingOut = false;
|
|
@@ -130,6 +135,8 @@ function notifyParentAuthState(status) {
|
|
|
130
135
|
}
|
|
131
136
|
function resetSessionCache() {
|
|
132
137
|
sessionGeneration += 1;
|
|
138
|
+
firstSessionReadUnsent = false;
|
|
139
|
+
cachedSessionFromFirstRead = false;
|
|
133
140
|
cachedSession = undefined;
|
|
134
141
|
cachedSessionAt = 0;
|
|
135
142
|
cachedEvidence = undefined;
|
|
@@ -223,6 +230,15 @@ export function notifySessionInvalidated() {
|
|
|
223
230
|
export function isSigningOut() {
|
|
224
231
|
return signingOut;
|
|
225
232
|
}
|
|
233
|
+
/**
|
|
234
|
+
* Whether the session this tab holds is the answer to the page load's first
|
|
235
|
+
* session read. A request the load sent before the session was known belongs
|
|
236
|
+
* to the account this session names only while this holds: once a retry or an
|
|
237
|
+
* invalidation answers instead, another tab may have changed the cookies.
|
|
238
|
+
*/
|
|
239
|
+
export function isSessionFromFirstRead() {
|
|
240
|
+
return cachedSession !== undefined && cachedSessionFromFirstRead;
|
|
241
|
+
}
|
|
226
242
|
const UNAUTHORIZED_RECHECK_MIN_INTERVAL_MS = 5_000;
|
|
227
243
|
let lastUnauthorizedRecheckAt = 0;
|
|
228
244
|
/**
|
|
@@ -282,6 +298,8 @@ function fetchSharedSession() {
|
|
|
282
298
|
if (sessionRequest)
|
|
283
299
|
return sessionRequest;
|
|
284
300
|
const requestGeneration = sessionGeneration;
|
|
301
|
+
const firstRead = firstSessionReadUnsent;
|
|
302
|
+
firstSessionReadUnsent = false;
|
|
285
303
|
let request;
|
|
286
304
|
const requestResult = (async () => {
|
|
287
305
|
try {
|
|
@@ -306,6 +324,7 @@ function fetchSharedSession() {
|
|
|
306
324
|
: data;
|
|
307
325
|
cachedSession = session;
|
|
308
326
|
cachedSessionAt = Date.now();
|
|
327
|
+
cachedSessionFromFirstRead = firstRead;
|
|
309
328
|
cachedEvidence = session
|
|
310
329
|
? "signed_in"
|
|
311
330
|
: result.state === "unavailable"
|
package/dist/deploy/build.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { execFileSync } from "child_process";
|
|
3
3
|
import fs from "fs";
|
|
4
|
-
import { createRequire } from "module";
|
|
4
|
+
import { createRequire, isBuiltin } from "module";
|
|
5
5
|
import path from "path";
|
|
6
6
|
import { fileURLToPath } from "url";
|
|
7
7
|
import { runInNewContext } from "vm";
|
|
@@ -3853,6 +3853,342 @@ function copyInstalledFfmpegStaticPackage(serverDir) {
|
|
|
3853
3853
|
copyDir(src, path.join(serverDir, "node_modules", FFMPEG_STATIC_PACKAGE_NAME));
|
|
3854
3854
|
console.log("[deploy] Copied ffmpeg-static into the server bundle for media transcription fallback.");
|
|
3855
3855
|
}
|
|
3856
|
+
function exclusiveBrowserInstallerPackages(functionDir) {
|
|
3857
|
+
const nodeModulesDir = path.join(functionDir, "node_modules");
|
|
3858
|
+
if (!fs.existsSync(path.join(nodeModulesDir, "@puppeteer/browsers")))
|
|
3859
|
+
return new Set();
|
|
3860
|
+
const functionRoot = fs.realpathSync(functionDir);
|
|
3861
|
+
const isWithinFunction = (directory) => {
|
|
3862
|
+
const relative = path.relative(functionRoot, directory);
|
|
3863
|
+
return (relative === "" ||
|
|
3864
|
+
(relative !== ".." &&
|
|
3865
|
+
!relative.startsWith(`..${path.sep}`) &&
|
|
3866
|
+
!path.isAbsolute(relative)));
|
|
3867
|
+
};
|
|
3868
|
+
const packageSegments = (name) => {
|
|
3869
|
+
const segments = name.split("/");
|
|
3870
|
+
if (!name ||
|
|
3871
|
+
name.includes("\\") ||
|
|
3872
|
+
segments.some((segment) => !segment || segment === "." || segment === "..") ||
|
|
3873
|
+
segments.length > 2 ||
|
|
3874
|
+
(segments.length === 2 && !segments[0].startsWith("@")) ||
|
|
3875
|
+
(segments.length === 1 && segments[0].startsWith("@")))
|
|
3876
|
+
return null;
|
|
3877
|
+
return segments;
|
|
3878
|
+
};
|
|
3879
|
+
const resolvePackageDirectory = (segments, fromPackageDir, resolvedPackageDir) => {
|
|
3880
|
+
if (resolvedPackageDir) {
|
|
3881
|
+
const resolved = fs.realpathSync(resolvedPackageDir);
|
|
3882
|
+
if (!isWithinFunction(resolved))
|
|
3883
|
+
return null;
|
|
3884
|
+
return fs.statSync(resolved).isDirectory() ? resolved : null;
|
|
3885
|
+
}
|
|
3886
|
+
let current = fromPackageDir ?? functionRoot;
|
|
3887
|
+
if (!isWithinFunction(current))
|
|
3888
|
+
return null;
|
|
3889
|
+
while (isWithinFunction(current)) {
|
|
3890
|
+
if (current === functionRoot ||
|
|
3891
|
+
path.basename(current) !== "node_modules") {
|
|
3892
|
+
const candidate = path.join(current, "node_modules", ...segments);
|
|
3893
|
+
if (fs.existsSync(candidate)) {
|
|
3894
|
+
const resolved = fs.realpathSync(candidate);
|
|
3895
|
+
// A nearer out-of-bound install must not fall through to another version.
|
|
3896
|
+
if (!isWithinFunction(resolved))
|
|
3897
|
+
return null;
|
|
3898
|
+
if (fs.statSync(resolved).isDirectory())
|
|
3899
|
+
return resolved;
|
|
3900
|
+
return null;
|
|
3901
|
+
}
|
|
3902
|
+
}
|
|
3903
|
+
if (current === functionRoot)
|
|
3904
|
+
break;
|
|
3905
|
+
const parent = path.dirname(current);
|
|
3906
|
+
if (parent === current)
|
|
3907
|
+
break;
|
|
3908
|
+
current = parent;
|
|
3909
|
+
}
|
|
3910
|
+
return null;
|
|
3911
|
+
};
|
|
3912
|
+
const candidateReferencesByFile = new Map();
|
|
3913
|
+
const packageReferencesByDirectory = new Map();
|
|
3914
|
+
const isEnoent = (error) => error !== null &&
|
|
3915
|
+
typeof error === "object" &&
|
|
3916
|
+
"code" in error &&
|
|
3917
|
+
error.code === "ENOENT";
|
|
3918
|
+
const isMissingDanglingSymlink = (fileStats, error) => fileStats.isSymbolicLink() && isEnoent(error);
|
|
3919
|
+
const resolveScannablePath = (filePath) => {
|
|
3920
|
+
const fileStats = fs.lstatSync(filePath);
|
|
3921
|
+
let resolvedPath;
|
|
3922
|
+
try {
|
|
3923
|
+
resolvedPath = fs.realpathSync(filePath);
|
|
3924
|
+
}
|
|
3925
|
+
catch (error) {
|
|
3926
|
+
if (isMissingDanglingSymlink(fileStats, error))
|
|
3927
|
+
return null;
|
|
3928
|
+
throw error;
|
|
3929
|
+
}
|
|
3930
|
+
if (!isWithinFunction(resolvedPath))
|
|
3931
|
+
return null;
|
|
3932
|
+
let stats;
|
|
3933
|
+
try {
|
|
3934
|
+
stats = fs.statSync(filePath);
|
|
3935
|
+
}
|
|
3936
|
+
catch (error) {
|
|
3937
|
+
if (isMissingDanglingSymlink(fileStats, error))
|
|
3938
|
+
return null;
|
|
3939
|
+
throw error;
|
|
3940
|
+
}
|
|
3941
|
+
return { path: resolvedPath, stats };
|
|
3942
|
+
};
|
|
3943
|
+
const collect = (roots, scanPackageReferences) => {
|
|
3944
|
+
const collected = new Set();
|
|
3945
|
+
const visited = new Set();
|
|
3946
|
+
const visit = (request, parentPackageDir) => {
|
|
3947
|
+
const name = typeof request === "string" ? request : request.name;
|
|
3948
|
+
const fromPackageDir = typeof request === "string" ? parentPackageDir : request.fromPackageDir;
|
|
3949
|
+
const segments = packageSegments(name);
|
|
3950
|
+
if (!segments)
|
|
3951
|
+
return;
|
|
3952
|
+
if (scanPackageReferences &&
|
|
3953
|
+
SERVERLESS_FUNCTION_PACKAGE_DENYLIST.has(name))
|
|
3954
|
+
return;
|
|
3955
|
+
collected.add(name);
|
|
3956
|
+
const packageDir = resolvePackageDirectory(segments, fromPackageDir, typeof request === "string" ? undefined : request.resolvedPackageDir);
|
|
3957
|
+
if (!packageDir)
|
|
3958
|
+
return;
|
|
3959
|
+
const manifest = readPackageManifest(packageDir);
|
|
3960
|
+
const version = typeof manifest?.version === "string" ? manifest.version : "";
|
|
3961
|
+
const identity = `${packageDir}\0${version}`;
|
|
3962
|
+
if (visited.has(identity))
|
|
3963
|
+
return;
|
|
3964
|
+
visited.add(identity);
|
|
3965
|
+
if (scanPackageReferences) {
|
|
3966
|
+
for (const reference of scanPackageReferences(packageDir))
|
|
3967
|
+
visit(reference);
|
|
3968
|
+
}
|
|
3969
|
+
for (const field of [
|
|
3970
|
+
...RUNTIME_PACKAGE_DEPENDENCY_FIELDS,
|
|
3971
|
+
"peerDependencies",
|
|
3972
|
+
]) {
|
|
3973
|
+
const dependencies = manifest?.[field];
|
|
3974
|
+
if (!dependencies ||
|
|
3975
|
+
typeof dependencies !== "object" ||
|
|
3976
|
+
Array.isArray(dependencies))
|
|
3977
|
+
continue;
|
|
3978
|
+
for (const dependency of Object.keys(dependencies))
|
|
3979
|
+
visit(dependency, packageDir);
|
|
3980
|
+
}
|
|
3981
|
+
};
|
|
3982
|
+
for (const root of roots)
|
|
3983
|
+
visit(root);
|
|
3984
|
+
return collected;
|
|
3985
|
+
};
|
|
3986
|
+
const candidates = collect([
|
|
3987
|
+
"puppeteer",
|
|
3988
|
+
"puppeteer-core",
|
|
3989
|
+
"chromium-bidi",
|
|
3990
|
+
"@puppeteer/browsers",
|
|
3991
|
+
]);
|
|
3992
|
+
const findResolvedCandidate = (specifier, fromPackageDir) => {
|
|
3993
|
+
if (!specifier.startsWith("./") &&
|
|
3994
|
+
!specifier.startsWith("../") &&
|
|
3995
|
+
!path.isAbsolute(specifier))
|
|
3996
|
+
return;
|
|
3997
|
+
const target = path.resolve(fromPackageDir, specifier);
|
|
3998
|
+
if (!isWithinFunction(target))
|
|
3999
|
+
return;
|
|
4000
|
+
let match;
|
|
4001
|
+
for (const name of candidates) {
|
|
4002
|
+
if (SERVERLESS_FUNCTION_PACKAGE_DENYLIST.has(name))
|
|
4003
|
+
continue;
|
|
4004
|
+
const marker = `${path.sep}node_modules${path.sep}${name
|
|
4005
|
+
.split("/")
|
|
4006
|
+
.join(path.sep)}`;
|
|
4007
|
+
const markerStart = target.lastIndexOf(marker);
|
|
4008
|
+
const suffix = target[markerStart + marker.length];
|
|
4009
|
+
if (markerStart < 0 || (suffix !== undefined && suffix !== path.sep))
|
|
4010
|
+
continue;
|
|
4011
|
+
const candidateDir = target.slice(0, markerStart + marker.length);
|
|
4012
|
+
if (!fs.existsSync(candidateDir))
|
|
4013
|
+
continue;
|
|
4014
|
+
const resolvedPackageDir = fs.realpathSync(candidateDir);
|
|
4015
|
+
if (!isWithinFunction(resolvedPackageDir) ||
|
|
4016
|
+
!fs.statSync(resolvedPackageDir).isDirectory())
|
|
4017
|
+
continue;
|
|
4018
|
+
if (!match || markerStart > match.markerStart)
|
|
4019
|
+
match = { name, resolvedPackageDir, markerStart };
|
|
4020
|
+
}
|
|
4021
|
+
return (match && {
|
|
4022
|
+
name: match.name,
|
|
4023
|
+
resolvedPackageDir: match.resolvedPackageDir,
|
|
4024
|
+
});
|
|
4025
|
+
};
|
|
4026
|
+
const isNonPackageSpecifier = (specifier) => path.isAbsolute(specifier) ||
|
|
4027
|
+
specifier.startsWith(".") ||
|
|
4028
|
+
specifier.startsWith("#") ||
|
|
4029
|
+
/^[A-Za-z][A-Za-z\d+.-]*:/.test(specifier);
|
|
4030
|
+
const findResolvedPackage = (specifier, fromPackageDir) => {
|
|
4031
|
+
const relativeCandidate = findResolvedCandidate(specifier, fromPackageDir);
|
|
4032
|
+
if (relativeCandidate)
|
|
4033
|
+
return relativeCandidate;
|
|
4034
|
+
if (isNonPackageSpecifier(specifier))
|
|
4035
|
+
return;
|
|
4036
|
+
const specifierSegments = specifier.split("/");
|
|
4037
|
+
const name = specifierSegments[0]?.startsWith("@")
|
|
4038
|
+
? specifierSegments.slice(0, 2).join("/")
|
|
4039
|
+
: specifierSegments[0];
|
|
4040
|
+
const segments = name && packageSegments(name);
|
|
4041
|
+
if (!name ||
|
|
4042
|
+
!segments ||
|
|
4043
|
+
isBuiltin(name) ||
|
|
4044
|
+
SERVERLESS_FUNCTION_PACKAGE_DENYLIST.has(name))
|
|
4045
|
+
return;
|
|
4046
|
+
const resolvedPackageDir = resolvePackageDirectory(segments, fromPackageDir);
|
|
4047
|
+
return resolvedPackageDir ? { name, resolvedPackageDir } : undefined;
|
|
4048
|
+
};
|
|
4049
|
+
const findPackageImportReferences = (packageDir, packageManifest = readPackageManifest(packageDir)) => {
|
|
4050
|
+
const imports = packageManifest?.imports;
|
|
4051
|
+
if (!imports || typeof imports !== "object" || Array.isArray(imports))
|
|
4052
|
+
return [];
|
|
4053
|
+
const targets = [];
|
|
4054
|
+
const collectTargets = (value) => {
|
|
4055
|
+
if (typeof value === "string") {
|
|
4056
|
+
targets.push(value);
|
|
4057
|
+
}
|
|
4058
|
+
else if (Array.isArray(value)) {
|
|
4059
|
+
for (const target of value)
|
|
4060
|
+
collectTargets(target);
|
|
4061
|
+
}
|
|
4062
|
+
else if (value && typeof value === "object") {
|
|
4063
|
+
for (const target of Object.values(value))
|
|
4064
|
+
collectTargets(target);
|
|
4065
|
+
}
|
|
4066
|
+
};
|
|
4067
|
+
for (const target of Object.values(imports))
|
|
4068
|
+
collectTargets(target);
|
|
4069
|
+
const references = new Map();
|
|
4070
|
+
for (const target of targets) {
|
|
4071
|
+
const resolved = findResolvedPackage(target, packageDir);
|
|
4072
|
+
if (resolved) {
|
|
4073
|
+
const reference = { ...resolved, fromPackageDir: packageDir };
|
|
4074
|
+
references.set(`${reference.name}\0${reference.resolvedPackageDir}`, reference);
|
|
4075
|
+
continue;
|
|
4076
|
+
}
|
|
4077
|
+
if (isNonPackageSpecifier(target))
|
|
4078
|
+
continue;
|
|
4079
|
+
const targetSegments = target.split("/");
|
|
4080
|
+
const packageName = targetSegments[0]?.startsWith("@")
|
|
4081
|
+
? targetSegments.slice(0, 2).join("/")
|
|
4082
|
+
: targetSegments[0];
|
|
4083
|
+
if (packageName?.includes("*")) {
|
|
4084
|
+
for (const name of candidates) {
|
|
4085
|
+
if (SERVERLESS_FUNCTION_PACKAGE_DENYLIST.has(name))
|
|
4086
|
+
continue;
|
|
4087
|
+
const reference = { name, fromPackageDir: packageDir };
|
|
4088
|
+
references.set(`${name}\0`, reference);
|
|
4089
|
+
}
|
|
4090
|
+
continue;
|
|
4091
|
+
}
|
|
4092
|
+
}
|
|
4093
|
+
return [...references.values()];
|
|
4094
|
+
};
|
|
4095
|
+
const manifest = readPackageManifest(functionDir);
|
|
4096
|
+
// Nitro's manifest flattens transitive dependencies, so installer children
|
|
4097
|
+
// are not independent runtime roots merely because they appear there.
|
|
4098
|
+
const retained = new Set(PACKAGE_DEPENDENCY_FIELDS.flatMap((field) => Object.keys(manifest?.[field] ?? {})).filter((name) => !candidates.has(name) &&
|
|
4099
|
+
!SERVERLESS_FUNCTION_PACKAGE_DENYLIST.has(name)));
|
|
4100
|
+
const findCandidateReferences = (resolvedFilePath) => {
|
|
4101
|
+
const cached = candidateReferencesByFile.get(resolvedFilePath);
|
|
4102
|
+
if (cached)
|
|
4103
|
+
return cached;
|
|
4104
|
+
const fromPackageDir = path.dirname(resolvedFilePath);
|
|
4105
|
+
const source = fs.readFileSync(resolvedFilePath, "utf8");
|
|
4106
|
+
const references = new Map();
|
|
4107
|
+
const addReference = (reference) => {
|
|
4108
|
+
const identity = `${reference.name}\0${reference.fromPackageDir}\0${reference.resolvedPackageDir ?? ""}`;
|
|
4109
|
+
references.set(identity, reference);
|
|
4110
|
+
};
|
|
4111
|
+
const literalSpecifier = /\b(?:import|export)\s*(?:[^;'"`]*?\s*from\s*)?(['"`])([^'"`]+)\1|\b(?:import\s*\.\s*meta\s*\.\s*resolve|import|require(?:\s*\.\s*resolve)?)\s*\(\s*(['"`])([^'"`]+)\3/g;
|
|
4112
|
+
for (const match of source.matchAll(literalSpecifier)) {
|
|
4113
|
+
const specifier = match[2] ?? match[4];
|
|
4114
|
+
if (!specifier)
|
|
4115
|
+
continue;
|
|
4116
|
+
const resolved = findResolvedPackage(specifier, fromPackageDir);
|
|
4117
|
+
if (resolved)
|
|
4118
|
+
addReference({ ...resolved, fromPackageDir });
|
|
4119
|
+
}
|
|
4120
|
+
for (const name of candidates) {
|
|
4121
|
+
if (!SERVERLESS_FUNCTION_PACKAGE_DENYLIST.has(name) &&
|
|
4122
|
+
source.includes(name) &&
|
|
4123
|
+
(hasExternalSsrRuntimeReference(source, name) ||
|
|
4124
|
+
["/", '"', "'", "`"].some((boundary) => source.includes(`node_modules/${name}${boundary}`))))
|
|
4125
|
+
addReference({ name, fromPackageDir });
|
|
4126
|
+
}
|
|
4127
|
+
const found = [...references.values()];
|
|
4128
|
+
candidateReferencesByFile.set(resolvedFilePath, found);
|
|
4129
|
+
return found;
|
|
4130
|
+
};
|
|
4131
|
+
const collectTreeReferences = (roots) => {
|
|
4132
|
+
const references = new Map();
|
|
4133
|
+
const visitedDirectories = new Set();
|
|
4134
|
+
const visitedFiles = new Set();
|
|
4135
|
+
const visit = (entryPath) => {
|
|
4136
|
+
const resolved = resolveScannablePath(entryPath);
|
|
4137
|
+
if (!resolved)
|
|
4138
|
+
return;
|
|
4139
|
+
if (resolved.stats.isDirectory()) {
|
|
4140
|
+
if (visitedDirectories.has(resolved.path))
|
|
4141
|
+
return;
|
|
4142
|
+
visitedDirectories.add(resolved.path);
|
|
4143
|
+
for (const entry of fs.readdirSync(resolved.path, {
|
|
4144
|
+
withFileTypes: true,
|
|
4145
|
+
})) {
|
|
4146
|
+
if (entry.isDirectory() ||
|
|
4147
|
+
entry.isSymbolicLink() ||
|
|
4148
|
+
(entry.isFile() && /\.(?:[cm]?js)$/.test(entry.name)))
|
|
4149
|
+
visit(path.join(resolved.path, entry.name));
|
|
4150
|
+
}
|
|
4151
|
+
return;
|
|
4152
|
+
}
|
|
4153
|
+
if (!resolved.stats.isFile() ||
|
|
4154
|
+
!/\.(?:[cm]?js)$/.test(path.basename(entryPath)) ||
|
|
4155
|
+
visitedFiles.has(resolved.path))
|
|
4156
|
+
return;
|
|
4157
|
+
visitedFiles.add(resolved.path);
|
|
4158
|
+
for (const reference of findCandidateReferences(resolved.path)) {
|
|
4159
|
+
const identity = `${reference.name}\0${reference.fromPackageDir}\0${reference.resolvedPackageDir ?? ""}`;
|
|
4160
|
+
references.set(identity, reference);
|
|
4161
|
+
}
|
|
4162
|
+
};
|
|
4163
|
+
for (const root of roots)
|
|
4164
|
+
visit(root);
|
|
4165
|
+
return [...references.values()];
|
|
4166
|
+
};
|
|
4167
|
+
const emittedRoots = fs
|
|
4168
|
+
.readdirSync(functionDir, { withFileTypes: true })
|
|
4169
|
+
.filter((entry) => entry.name !== "node_modules" &&
|
|
4170
|
+
(entry.isDirectory() ||
|
|
4171
|
+
entry.isSymbolicLink() ||
|
|
4172
|
+
(entry.isFile() && /\.(?:[cm]?js)$/.test(entry.name))))
|
|
4173
|
+
.map((entry) => path.join(functionDir, entry.name));
|
|
4174
|
+
const emittedReferences = collectTreeReferences(emittedRoots);
|
|
4175
|
+
const needed = collect([
|
|
4176
|
+
...retained,
|
|
4177
|
+
...emittedReferences,
|
|
4178
|
+
...findPackageImportReferences(functionDir, manifest),
|
|
4179
|
+
], (packageDir) => {
|
|
4180
|
+
const cached = packageReferencesByDirectory.get(packageDir);
|
|
4181
|
+
if (cached)
|
|
4182
|
+
return cached;
|
|
4183
|
+
const references = [
|
|
4184
|
+
...collectTreeReferences([packageDir]),
|
|
4185
|
+
...findPackageImportReferences(packageDir),
|
|
4186
|
+
];
|
|
4187
|
+
packageReferencesByDirectory.set(packageDir, references);
|
|
4188
|
+
return references;
|
|
4189
|
+
});
|
|
4190
|
+
return new Set([...candidates].filter((name) => !needed.has(name)));
|
|
4191
|
+
}
|
|
3856
4192
|
export function sanitizeServerlessFunctionPackageManifest(functionDir) {
|
|
3857
4193
|
if (!functionDir || !fs.existsSync(functionDir))
|
|
3858
4194
|
return;
|
|
@@ -3866,13 +4202,17 @@ export function sanitizeServerlessFunctionPackageManifest(functionDir) {
|
|
|
3866
4202
|
catch {
|
|
3867
4203
|
return;
|
|
3868
4204
|
}
|
|
4205
|
+
const deniedPackages = new Set([
|
|
4206
|
+
...SERVERLESS_FUNCTION_PACKAGE_DENYLIST,
|
|
4207
|
+
...exclusiveBrowserInstallerPackages(functionDir),
|
|
4208
|
+
]);
|
|
3869
4209
|
let removed = 0;
|
|
3870
4210
|
for (const field of PACKAGE_DEPENDENCY_FIELDS) {
|
|
3871
4211
|
const deps = packageJson[field];
|
|
3872
4212
|
if (!deps || typeof deps !== "object" || Array.isArray(deps))
|
|
3873
4213
|
continue;
|
|
3874
4214
|
const depRecord = deps;
|
|
3875
|
-
for (const packageName of
|
|
4215
|
+
for (const packageName of deniedPackages) {
|
|
3876
4216
|
if (Object.prototype.hasOwnProperty.call(depRecord, packageName)) {
|
|
3877
4217
|
delete depRecord[packageName];
|
|
3878
4218
|
removed++;
|
|
@@ -3883,7 +4223,7 @@ export function sanitizeServerlessFunctionPackageManifest(functionDir) {
|
|
|
3883
4223
|
}
|
|
3884
4224
|
}
|
|
3885
4225
|
const nodeModulesDir = path.join(functionDir, "node_modules");
|
|
3886
|
-
for (const packageName of
|
|
4226
|
+
for (const packageName of deniedPackages) {
|
|
3887
4227
|
const packageDir = path.join(nodeModulesDir, ...packageName.split("/"));
|
|
3888
4228
|
if (fs.existsSync(packageDir)) {
|
|
3889
4229
|
fs.rmSync(packageDir, { recursive: true, force: true });
|
|
@@ -4029,6 +4369,12 @@ export async function runNitroBuildPipeline(opts) {
|
|
|
4029
4369
|
patchReactRouterServerManifestInOutput(nitro.options.output.serverDir, trustedClientDirectory, resolvedClientDir);
|
|
4030
4370
|
}
|
|
4031
4371
|
}
|
|
4372
|
+
function removeServerSourceMaps(serverDir) {
|
|
4373
|
+
const sourceMaps = fs.globSync("**/*.map", { cwd: serverDir });
|
|
4374
|
+
for (const sourceMap of sourceMaps) {
|
|
4375
|
+
fs.rmSync(path.join(serverDir, sourceMap), { force: true });
|
|
4376
|
+
}
|
|
4377
|
+
}
|
|
4032
4378
|
function resolveNitroClientDirectory(cwd, defaultClientDirectory) {
|
|
4033
4379
|
const configured = process.env[PREBUILT_CLIENT_DIRECTORY_ENV]?.trim();
|
|
4034
4380
|
const clientDirectory = configured
|
|
@@ -4357,6 +4703,10 @@ export default bundle;
|
|
|
4357
4703
|
if (isCloudflareModulePreset(preset)) {
|
|
4358
4704
|
bundleYjsRuntimeForServerlessOutput(nitro.options.output.serverDir, cwd);
|
|
4359
4705
|
}
|
|
4706
|
+
if (sentryServerSourceMapPlugins.length > 0) {
|
|
4707
|
+
removeServerSourceMaps(nitro.options.output.serverDir);
|
|
4708
|
+
console.log("[deploy] Ensured Nitro server output is free of source maps before function packaging.");
|
|
4709
|
+
}
|
|
4360
4710
|
if (preset === "netlify") {
|
|
4361
4711
|
if (isDurableBackgroundEmitRequired()) {
|
|
4362
4712
|
emitSingleTemplateNetlifyBackgroundFunction(cwd);
|
|
@@ -33,9 +33,9 @@ declare const _default: import("../../action.js").ActionDefinition<{
|
|
|
33
33
|
idempotencyKey: string;
|
|
34
34
|
deleted: boolean;
|
|
35
35
|
} | {
|
|
36
|
-
id?: undefined;
|
|
37
36
|
error: string;
|
|
38
37
|
url?: undefined;
|
|
38
|
+
id?: undefined;
|
|
39
39
|
provider?: undefined;
|
|
40
40
|
configured?: undefined;
|
|
41
41
|
} | {
|
|
@@ -45,8 +45,8 @@ declare const _default: import("../../action.js").ActionDefinition<{
|
|
|
45
45
|
configured?: undefined;
|
|
46
46
|
error?: undefined;
|
|
47
47
|
} | {
|
|
48
|
-
id?: undefined;
|
|
49
48
|
url?: undefined;
|
|
49
|
+
id?: undefined;
|
|
50
50
|
provider?: undefined;
|
|
51
51
|
error: string;
|
|
52
52
|
configured: boolean;
|