@agent-native/core 0.31.2 → 0.32.1
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/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +7 -0
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/MultiTabAssistantChat.js +5 -5
- package/dist/client/MultiTabAssistantChat.js.map +1 -1
- package/dist/client/use-chat-threads.d.ts.map +1 -1
- package/dist/client/use-chat-threads.js +8 -1
- package/dist/client/use-chat-threads.js.map +1 -1
- package/dist/deploy/build.d.ts +2 -1
- package/dist/deploy/build.d.ts.map +1 -1
- package/dist/deploy/build.js +104 -42
- package/dist/deploy/build.js.map +1 -1
- package/dist/deploy/immutable-assets.d.ts.map +1 -1
- package/dist/deploy/immutable-assets.js +5 -0
- package/dist/deploy/immutable-assets.js.map +1 -1
- package/dist/server/core-routes-plugin.d.ts.map +1 -1
- package/dist/server/core-routes-plugin.js +1719 -1685
- package/dist/server/core-routes-plugin.js.map +1 -1
- package/dist/server/framework-request-handler.js +8 -6
- package/dist/server/framework-request-handler.js.map +1 -1
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +1 -1
- package/dist/server/index.js.map +1 -1
- package/dist/server/request-context.d.ts +8 -0
- package/dist/server/request-context.d.ts.map +1 -1
- package/dist/server/request-context.js +25 -4
- package/dist/server/request-context.js.map +1 -1
- package/dist/server/ssr-handler.d.ts +1 -1
- package/dist/server/ssr-handler.d.ts.map +1 -1
- package/dist/server/ssr-handler.js +54 -15
- package/dist/server/ssr-handler.js.map +1 -1
- package/dist/shared/cache-control.d.ts +6 -0
- package/dist/shared/cache-control.d.ts.map +1 -1
- package/dist/shared/cache-control.js +6 -0
- package/dist/shared/cache-control.js.map +1 -1
- package/package.json +1 -1
package/dist/deploy/build.js
CHANGED
|
@@ -22,10 +22,10 @@ import { getWorkspaceCoreExports, } from "./workspace-core.js";
|
|
|
22
22
|
import { generateActionRegistryForProject } from "../vite/action-types-plugin.js";
|
|
23
23
|
import { mcpEmbedStaticAssetRouteRules } from "../shared/mcp-embed-headers.js";
|
|
24
24
|
import { AGENT_NATIVE_DEFAULT_SOCIAL_IMAGE } from "../shared/social-meta.js";
|
|
25
|
+
import { DEFAULT_SPECULATION_RULES_PATH, DEFAULT_SSR_CACHE_CONTROL, } from "../shared/cache-control.js";
|
|
25
26
|
import { collectImmutableAssetPaths, IMMUTABLE_ASSET_CACHE_CONTROL, IMMUTABLE_ASSET_CACHE_HEADERS, prefixAssetPath, } from "./immutable-assets.js";
|
|
26
27
|
const cwd = process.cwd();
|
|
27
28
|
const preset = process.env.NITRO_PRESET || "node";
|
|
28
|
-
const DEFAULT_SSR_CACHE_CONTROL = "public, max-age=5, stale-while-revalidate=604800, stale-if-error=3600";
|
|
29
29
|
function normalizeConfiguredAppBasePath() {
|
|
30
30
|
const raw = process.env.VITE_APP_BASE_PATH || process.env.APP_BASE_PATH;
|
|
31
31
|
if (!raw || raw === "/")
|
|
@@ -49,6 +49,31 @@ function isNodeOnlyPlugin(filePath) {
|
|
|
49
49
|
const basename = path.basename(filePath, path.extname(filePath));
|
|
50
50
|
return NODE_ONLY_PLUGINS.has(basename);
|
|
51
51
|
}
|
|
52
|
+
export function generateProvidedPluginsNitroPluginSource(pluginStems) {
|
|
53
|
+
const stems = [...new Set(pluginStems.filter(Boolean))].sort();
|
|
54
|
+
return `// AUTO-GENERATED by @agent-native/core deploy build
|
|
55
|
+
import { markDefaultPluginProvided } from "@agent-native/core/server";
|
|
56
|
+
|
|
57
|
+
const pluginStems = ${JSON.stringify(stems)};
|
|
58
|
+
|
|
59
|
+
export default function markBuildDiscoveredPlugins(nitroApp) {
|
|
60
|
+
for (const stem of pluginStems) {
|
|
61
|
+
markDefaultPluginProvided(nitroApp, stem);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
`;
|
|
65
|
+
}
|
|
66
|
+
async function writeProvidedPluginsNitroPlugin() {
|
|
67
|
+
const plugins = await discoverPlugins(cwd);
|
|
68
|
+
const stems = plugins.map((plugin) => path.basename(plugin, path.extname(plugin)));
|
|
69
|
+
if (stems.length === 0)
|
|
70
|
+
return null;
|
|
71
|
+
const tmpDir = path.join(cwd, ".deploy-tmp");
|
|
72
|
+
fs.mkdirSync(tmpDir, { recursive: true });
|
|
73
|
+
const pluginPath = path.join(tmpDir, "agent-native-provided-plugins.mjs");
|
|
74
|
+
fs.writeFileSync(pluginPath, generateProvidedPluginsNitroPluginSource(stems));
|
|
75
|
+
return pluginPath;
|
|
76
|
+
}
|
|
52
77
|
function addImmutableAssetRouteRule(routeRules, pathname) {
|
|
53
78
|
const existing = routeRules[pathname] ?? {};
|
|
54
79
|
routeRules[pathname] = {
|
|
@@ -77,7 +102,7 @@ export function addImmutableAssetRouteRulesForClientBuild(routeRules, clientDir,
|
|
|
77
102
|
* `@agent-native/core/server`. This is the middle layer of the three-layer
|
|
78
103
|
* inheritance model: app local > workspace core > framework default.
|
|
79
104
|
*/
|
|
80
|
-
export function generateWorkerEntry(routes, pluginPaths, defaultPluginStems = [], actions = [], workspaceCore = null, immutableAssetPaths = []) {
|
|
105
|
+
export function generateWorkerEntry(routes, pluginPaths, defaultPluginStems = [], actions = [], workspaceCore = null, immutableAssetPaths = [], builtAppBasePath = normalizeConfiguredAppBasePath()) {
|
|
81
106
|
const routeImports = [];
|
|
82
107
|
const routeRegistrations = [];
|
|
83
108
|
for (let i = 0; i < routes.length; i++) {
|
|
@@ -126,8 +151,10 @@ export function generateWorkerEntry(routes, pluginPaths, defaultPluginStems = []
|
|
|
126
151
|
const edgePlugins = pluginPaths.filter((p) => !isNodeOnlyPlugin(p));
|
|
127
152
|
const pluginImports = [];
|
|
128
153
|
const pluginCalls = [];
|
|
154
|
+
const providedPluginStems = new Set();
|
|
129
155
|
for (let i = 0; i < edgePlugins.length; i++) {
|
|
130
156
|
const varName = `plugin_${i}`;
|
|
157
|
+
providedPluginStems.add(path.basename(edgePlugins[i], path.extname(edgePlugins[i])));
|
|
131
158
|
pluginImports.push(`import ${varName} from ${JSON.stringify(edgePlugins[i])};`);
|
|
132
159
|
pluginCalls.push(` if (typeof ${varName} === "function") {
|
|
133
160
|
await ${varName}(nitroApp);
|
|
@@ -139,6 +166,7 @@ export function generateWorkerEntry(routes, pluginPaths, defaultPluginStems = []
|
|
|
139
166
|
const edgeDefaultStems = defaultPluginStems.filter((stem) => !NODE_ONLY_PLUGINS.has(stem));
|
|
140
167
|
for (let i = 0; i < edgeDefaultStems.length; i++) {
|
|
141
168
|
const stem = edgeDefaultStems[i];
|
|
169
|
+
providedPluginStems.add(stem);
|
|
142
170
|
const varName = `defaultPlugin_${i}`;
|
|
143
171
|
const workspaceExportName = workspaceCore?.plugins?.[stem];
|
|
144
172
|
if (workspaceCore && workspaceExportName) {
|
|
@@ -156,6 +184,17 @@ export function generateWorkerEntry(routes, pluginPaths, defaultPluginStems = []
|
|
|
156
184
|
await ${varName}(nitroApp);
|
|
157
185
|
}`);
|
|
158
186
|
}
|
|
187
|
+
const generatedPluginMarks = providedPluginStems.size > 0
|
|
188
|
+
? [
|
|
189
|
+
...new Set([
|
|
190
|
+
...Object.keys(DEFAULT_PLUGIN_REGISTRY),
|
|
191
|
+
...providedPluginStems,
|
|
192
|
+
]),
|
|
193
|
+
]
|
|
194
|
+
: [];
|
|
195
|
+
if (generatedPluginMarks.length > 0) {
|
|
196
|
+
pluginImports.unshift(`import { markDefaultPluginProvided as markGeneratedPluginProvided } from "@agent-native/core/server";`);
|
|
197
|
+
}
|
|
159
198
|
return `
|
|
160
199
|
// Auto-generated worker entry point for ${preset}
|
|
161
200
|
import { H3, defineEventHandler, readBody, toResponse } from "h3";
|
|
@@ -170,9 +209,11 @@ function normalizeAppBasePath(value) {
|
|
|
170
209
|
}
|
|
171
210
|
|
|
172
211
|
function getAppBasePath() {
|
|
212
|
+
const builtAppBasePath = ${JSON.stringify(builtAppBasePath)};
|
|
173
213
|
return normalizeAppBasePath(
|
|
174
214
|
globalThis.process?.env?.VITE_APP_BASE_PATH ||
|
|
175
|
-
globalThis.process?.env?.APP_BASE_PATH
|
|
215
|
+
globalThis.process?.env?.APP_BASE_PATH ||
|
|
216
|
+
builtAppBasePath,
|
|
176
217
|
);
|
|
177
218
|
}
|
|
178
219
|
|
|
@@ -283,6 +324,7 @@ function injectHeadScript(html, script) {
|
|
|
283
324
|
}
|
|
284
325
|
|
|
285
326
|
const DEFAULT_SSR_CACHE_CONTROL = ${JSON.stringify(DEFAULT_SSR_CACHE_CONTROL)};
|
|
327
|
+
const DEFAULT_SPECULATION_RULES_PATH = ${JSON.stringify(DEFAULT_SPECULATION_RULES_PATH)};
|
|
286
328
|
const IMMUTABLE_ASSET_CACHE_CONTROL = ${JSON.stringify(IMMUTABLE_ASSET_CACHE_CONTROL)};
|
|
287
329
|
const IMMUTABLE_ASSET_PATHS = new Set(${JSON.stringify([...new Set(immutableAssetPaths)].sort())});
|
|
288
330
|
const AGENT_NATIVE_DEFAULT_SOCIAL_IMAGE = ${JSON.stringify(AGENT_NATIVE_DEFAULT_SOCIAL_IMAGE)};
|
|
@@ -312,50 +354,54 @@ function injectDefaultSocialImageMeta(html) {
|
|
|
312
354
|
return html.slice(0, headCloseIdx) + tags.join("") + html.slice(headCloseIdx);
|
|
313
355
|
}
|
|
314
356
|
|
|
315
|
-
|
|
316
|
-
const AUTH_SESSION_COOKIE_RE = /^(?:an_session(?:_[^=;]+)?|an_embed_session|[^=;]+\\.session_(?:token|data))$/;
|
|
317
|
-
|
|
318
|
-
function requestHasAuthenticatedCookie(cookieHeader) {
|
|
319
|
-
if (!cookieHeader) return false;
|
|
320
|
-
return cookieHeader
|
|
321
|
-
.split(";")
|
|
322
|
-
.map((cookie) => cookie.trim().split("=", 1)[0]?.trim())
|
|
323
|
-
.filter(Boolean)
|
|
324
|
-
.map((name) => name.replace(/^__(?:Secure|Host)-/, ""))
|
|
325
|
-
.some((name) => !ANONYMOUS_SESSION_COOKIE_NAMES.has(name) && AUTH_SESSION_COOKIE_RE.test(name));
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
function requestHasAuthSignal(request) {
|
|
329
|
-
const url = new URL(request.url);
|
|
330
|
-
return Boolean(
|
|
331
|
-
request.headers.get("authorization") ||
|
|
332
|
-
requestHasAuthenticatedCookie(request.headers.get("cookie")) ||
|
|
333
|
-
url.searchParams.has("__an_embed_token") ||
|
|
334
|
-
url.searchParams.has("_session")
|
|
335
|
-
);
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
function shouldUseDefaultSsrCacheHeader(headers, status, pathname, hasAuthSignal) {
|
|
357
|
+
function shouldUseDefaultSsrCacheHeader(headers, status, pathname) {
|
|
339
358
|
if (status < 200 || status >= 400) return false;
|
|
340
359
|
|
|
341
360
|
const contentType = (headers.get("content-type") || "").toLowerCase();
|
|
342
361
|
if (contentType.includes("text/html")) {
|
|
343
|
-
|
|
362
|
+
// SSR HTML is public app shell in this framework; any per-user state is
|
|
363
|
+
// fetched after hydration. Always enforce the framework SWR default here;
|
|
364
|
+
// route-level no-cache/private headers on SSR HTML recreate the same
|
|
365
|
+
// origin stampede this cache policy is meant to prevent.
|
|
366
|
+
return true;
|
|
344
367
|
}
|
|
345
368
|
|
|
346
369
|
if (!pathname.endsWith(".data")) return false;
|
|
347
|
-
if (hasAuthSignal) return false;
|
|
348
370
|
if (!contentType.includes("text/x-script")) return false;
|
|
349
371
|
|
|
350
|
-
|
|
351
|
-
|
|
372
|
+
// React Router marks loader .data responses no-cache by default. Agent-Native
|
|
373
|
+
// SSR is public app shell, even for browsers carrying auth-looking cookies;
|
|
374
|
+
// user/org-specific data is loaded client-side through actions/API routes
|
|
375
|
+
// after hydration. Keep .data on the same SWR policy as HTML so normal route
|
|
376
|
+
// data fetches fill CDN cache instead of bypassing it and slamming origin.
|
|
377
|
+
// Do not re-add a blanket auth-signal bypass here; logged-in browsers still
|
|
378
|
+
// need CDN-cached public route data. Worker SSR does not populate
|
|
379
|
+
// getRequestUserEmail()/accessFilter() context for private loaders, and
|
|
380
|
+
// Node/H3 has an auth-context access guard for older loaders that still do.
|
|
381
|
+
// Also do not preserve route-level private/no-store for React Router .data:
|
|
382
|
+
// if a route needs per-user data, it belongs behind a client-side action/API
|
|
383
|
+
// call rather than in the shared SSR payload.
|
|
384
|
+
return true;
|
|
352
385
|
}
|
|
353
386
|
|
|
354
|
-
function applyDefaultSsrCacheHeader(headers, status, pathname
|
|
355
|
-
if (!shouldUseDefaultSsrCacheHeader(headers, status, pathname
|
|
387
|
+
function applyDefaultSsrCacheHeader(headers, status, pathname) {
|
|
388
|
+
if (!shouldUseDefaultSsrCacheHeader(headers, status, pathname)) return;
|
|
356
389
|
headers.set("cache-control", DEFAULT_SSR_CACHE_CONTROL);
|
|
357
390
|
}
|
|
358
391
|
|
|
392
|
+
function applyDefaultSpeculationRulesHeader(headers, status, basePath) {
|
|
393
|
+
if (status < 200 || status >= 400) return;
|
|
394
|
+
if (headers.has("speculation-rules")) return;
|
|
395
|
+
|
|
396
|
+
const contentType = (headers.get("content-type") || "").toLowerCase();
|
|
397
|
+
if (!contentType.includes("text/html")) return;
|
|
398
|
+
|
|
399
|
+
// Cloudflare Speed Brain injects Speculation-Rules when origin omits this
|
|
400
|
+
// header. Those browser prefetches carry Sec-Purpose: prefetch and
|
|
401
|
+
// Cloudflare can return 503 before the request reaches origin. Publish an
|
|
402
|
+
// explicit no-op ruleset by default; apps can still provide their own header.
|
|
403
|
+
headers.set("speculation-rules", '"' + prefixMountedPath(DEFAULT_SPECULATION_RULES_PATH, basePath) + '"');
|
|
404
|
+
}
|
|
359
405
|
function isImmutableAssetRequest(request) {
|
|
360
406
|
const pathname = stripAppBasePath(new URL(request.url).pathname);
|
|
361
407
|
return IMMUTABLE_ASSET_PATHS.has(pathname);
|
|
@@ -376,10 +422,11 @@ function applyImmutableAssetCacheHeaders(response, request) {
|
|
|
376
422
|
});
|
|
377
423
|
}
|
|
378
424
|
|
|
379
|
-
async function rewriteMountedResponse(response, basePath, pathname
|
|
425
|
+
async function rewriteMountedResponse(response, basePath, pathname) {
|
|
380
426
|
const sentryClientConfigScript = getSentryClientConfigScript();
|
|
381
427
|
const headers = new Headers(response.headers);
|
|
382
|
-
applyDefaultSsrCacheHeader(headers, response.status, pathname
|
|
428
|
+
applyDefaultSsrCacheHeader(headers, response.status, pathname);
|
|
429
|
+
applyDefaultSpeculationRulesHeader(headers, response.status, basePath);
|
|
383
430
|
|
|
384
431
|
const location = headers.get("location");
|
|
385
432
|
if (location?.startsWith("/") && !location.startsWith("//")) {
|
|
@@ -466,6 +513,12 @@ async function getHandler() {
|
|
|
466
513
|
|
|
467
514
|
// Run plugins — they call getH3App(nitroApp).use(path, handler) which
|
|
468
515
|
// pushes path-prefix middleware onto app["~middleware"].
|
|
516
|
+
// Pre-mark every build-time plugin slot before any plugin awaits the runtime
|
|
517
|
+
// default bootstrap. Bundled serverless workers often lack server/plugins/
|
|
518
|
+
// on disk, so runtime discovery would otherwise auto-mount duplicate
|
|
519
|
+
// framework defaults before later custom plugins get a chance to mark
|
|
520
|
+
// themselves as provided.
|
|
521
|
+
${generatedPluginMarks.map((stem) => ` markGeneratedPluginProvided(nitroApp, ${JSON.stringify(stem)});`).join("\n")}
|
|
469
522
|
${pluginCalls.join("\n")}
|
|
470
523
|
|
|
471
524
|
// Register API routes
|
|
@@ -490,7 +543,6 @@ ${actionRegistrations.join("\n")}
|
|
|
490
543
|
return new Response(null, { status: 404 });
|
|
491
544
|
}
|
|
492
545
|
const request = requestWithPathname(event.req, p);
|
|
493
|
-
const hasAuthSignal = requestHasAuthSignal(event.req);
|
|
494
546
|
if (event.req.method === "HEAD") {
|
|
495
547
|
const getRequest = requestWithMethod(request, "GET");
|
|
496
548
|
const response = await rrHandler(getRequest);
|
|
@@ -501,11 +553,10 @@ ${actionRegistrations.join("\n")}
|
|
|
501
553
|
headers: response.headers,
|
|
502
554
|
}),
|
|
503
555
|
basePath,
|
|
504
|
-
p
|
|
505
|
-
hasAuthSignal,
|
|
556
|
+
p
|
|
506
557
|
);
|
|
507
558
|
}
|
|
508
|
-
return rewriteMountedResponse(await rrHandler(request), basePath, p
|
|
559
|
+
return rewriteMountedResponse(await rrHandler(request), basePath, p);
|
|
509
560
|
}));
|
|
510
561
|
|
|
511
562
|
_handler = app.fetch.bind(app);
|
|
@@ -1137,15 +1188,22 @@ function createDanglingOptionalDepStubs() {
|
|
|
1137
1188
|
*/
|
|
1138
1189
|
export async function runNitroBuildPipeline(opts) {
|
|
1139
1190
|
const { nitro, hooks, clientDir, publicOutputDir, appBasePath, cwd } = opts;
|
|
1191
|
+
const hasClientBuild = fs.existsSync(clientDir) && Boolean(publicOutputDir);
|
|
1192
|
+
if (hasClientBuild) {
|
|
1193
|
+
// Install hashed-asset route rules before Nitro prepares platform output.
|
|
1194
|
+
// Some presets materialize headers during prepare/copy phases, not only in
|
|
1195
|
+
// nitroBuild; adding these later leaves Netlify/Vercel static assets without
|
|
1196
|
+
// the one-year immutable CDN policy even though the runtime manifest works.
|
|
1197
|
+
nitro.options.routeRules ??= {};
|
|
1198
|
+
addImmutableAssetRouteRulesForClientBuild(nitro.options.routeRules, clientDir, appBasePath);
|
|
1199
|
+
}
|
|
1140
1200
|
await hooks.prepare(nitro);
|
|
1141
1201
|
await hooks.copyPublicAssets(nitro);
|
|
1142
|
-
if (
|
|
1202
|
+
if (hasClientBuild && publicOutputDir) {
|
|
1143
1203
|
copyDir(clientDir, publicOutputDir);
|
|
1144
1204
|
if (appBasePath) {
|
|
1145
1205
|
copyDir(clientDir, path.join(publicOutputDir, appBasePath.slice(1)));
|
|
1146
1206
|
}
|
|
1147
|
-
nitro.options.routeRules ??= {};
|
|
1148
|
-
addImmutableAssetRouteRulesForClientBuild(nitro.options.routeRules, clientDir, appBasePath);
|
|
1149
1207
|
console.log(`[deploy] Copied client assets to ${path.relative(cwd, publicOutputDir)}`);
|
|
1150
1208
|
}
|
|
1151
1209
|
await hooks.nitroBuild(nitro);
|
|
@@ -1212,6 +1270,7 @@ export default bundle;
|
|
|
1212
1270
|
pathAliases["@"] = appDir;
|
|
1213
1271
|
if (fs.existsSync(sharedDir))
|
|
1214
1272
|
pathAliases["@shared"] = sharedDir;
|
|
1273
|
+
const providedPluginsNitroPlugin = await writeProvidedPluginsNitroPlugin();
|
|
1215
1274
|
const nitro = await createNitro({
|
|
1216
1275
|
rootDir: cwd,
|
|
1217
1276
|
dev: false,
|
|
@@ -1228,6 +1287,9 @@ export default bundle;
|
|
|
1228
1287
|
virtual: {
|
|
1229
1288
|
"virtual:agents-bundle": agentsBundleModuleSource,
|
|
1230
1289
|
},
|
|
1290
|
+
...(providedPluginsNitroPlugin
|
|
1291
|
+
? { plugins: [providedPluginsNitroPlugin] }
|
|
1292
|
+
: {}),
|
|
1231
1293
|
routeRules: mcpEmbedStaticAssetRouteRules(appBasePath),
|
|
1232
1294
|
// For edge presets (cloudflare, deno), bundle all deps — node_modules
|
|
1233
1295
|
// aren't available at runtime. Netlify/Vercel/Node have node_modules.
|