@agent-native/core 0.189.0-nightly-20260925200527 → 0.189.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.
Files changed (34) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/templates/content/CHANGELOG.md +6 -0
  3. package/corpus/templates/content/vite.config.ts +2 -38
  4. package/corpus/templates/design/CHANGELOG.md +4 -0
  5. package/corpus/templates/mail/app/components/layout/AppLayout.tsx +36 -11
  6. package/corpus/templates/mail/app/hooks/use-inbox-threads.ts +82 -0
  7. package/corpus/templates/mail/app/pages/InboxPage.tsx +18 -19
  8. package/corpus/templates/mail/changelog/2026-09-25-keep-inbox-tab-counts-consistent-when-switching-tabs.md +6 -0
  9. package/corpus/templates/slides/CHANGELOG.md +4 -0
  10. package/dist/cli/index.js +1 -2
  11. package/dist/collab/awareness.d.ts +2 -2
  12. package/dist/deploy/build.d.ts +1 -1
  13. package/dist/deploy/build.js +9 -348
  14. package/dist/deploy/workspace-deploy.d.ts +2 -2
  15. package/dist/deploy/workspace-deploy.js +9 -130
  16. package/dist/file-upload/actions/upload-image.d.ts +1 -1
  17. package/dist/notifications/routes.d.ts +3 -3
  18. package/dist/observability/routes.d.ts +6 -6
  19. package/dist/org/handlers.d.ts +1 -1
  20. package/dist/progress/routes.d.ts +1 -1
  21. package/dist/resources/handlers.d.ts +1 -1
  22. package/dist/secrets/routes.d.ts +3 -3
  23. package/dist/server/agent-engine-ollama-models-route.d.ts +1 -1
  24. package/dist/vite/client.d.ts +1 -1
  25. package/docs/content/a2a-protocol.mdx +2 -2
  26. package/docs/content/cloudflare.mdx +2 -10
  27. package/docs/content/deploy-an-app.mdx +0 -1
  28. package/docs/content/deployment.mdx +2 -8
  29. package/docs/content/environment-variables.mdx +1 -1
  30. package/docs/content/multi-app-workspace.mdx +1 -1
  31. package/docs/content/netlify.mdx +1 -1
  32. package/docs/content/real-time-collaboration.mdx +6 -6
  33. package/docs/content/workspace-deployment.mdx +4 -15
  34. package/package.json +4 -4
@@ -8,7 +8,6 @@
8
8
  * 3. Bundles everything with esbuild into the target format
9
9
  *
10
10
  * Supported presets:
11
- * - cloudflare_pages: Outputs dist/ with _worker.js for Cloudflare Pages
12
11
  * - cloudflare_module: Outputs a native Cloudflare Worker under .output/server
13
12
  * - aws_amplify: Uses Nitro's .amplify-hosting deployment specification
14
13
  *
@@ -42,7 +41,7 @@ import { createAgentNativeConfigContext, loadResolvedAgentNativeConfig, readAgen
42
41
  import { cloneServerBundleForFunction, copyDir, pruneSsrIslandFromRewritingClone, readPackageManifest, SERVERLESS_BROWSER_RUNTIME_PACKAGES, } from "./function-bundle.js";
43
42
  import { collectImmutableAssetPaths, IMMUTABLE_ASSET_CACHE_CONTROL, IMMUTABLE_ASSET_CACHE_HEADERS, prefixAssetPath, } from "./immutable-assets.js";
44
43
  import { writeNetlifyStaticHeaders } from "./netlify-static-headers.js";
45
- import { discoverApiRoutes, discoverPlugins, discoverActionFiles, getMissingDefaultPlugins, DEFAULT_PLUGIN_REGISTRY, } from "./route-discovery.js";
44
+ import { discoverPlugins, DEFAULT_PLUGIN_REGISTRY, } from "./route-discovery.js";
46
45
  import { getWorkspaceCoreExports, } from "./workspace-core.js";
47
46
  const cwd = process.cwd();
48
47
  const preset = process.env.NITRO_PRESET || "node";
@@ -2345,295 +2344,6 @@ export function generateCloudflarePagesStaticShellFromManifest(manifest, basePat
2345
2344
  : EMPTY_REACT_ROUTER_TURBO_STREAM;
2346
2345
  return `<!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"/><link rel="icon" type="image/svg+xml" href="/favicon.svg"/>${modulePreloads}${stylesheets}</head><body>${STATIC_SHELL_LOADING_MARKUP}<script>window.__reactRouterContext = ${JSON.stringify(context)};window.__reactRouterContext.stream = new ReadableStream({start(controller){window.__reactRouterContext.streamController = controller;}}).pipeThrough(new TextEncoderStream());</script><script type="module" async="">${routeModuleScript}</script><!--$--><script>window.__reactRouterContext.streamController.enqueue(${JSON.stringify(encodedInitialState)});</script><!--$--><script>window.__reactRouterContext.streamController.close();</script><!--/$--><!--/$--></body></html>`;
2347
2346
  }
2348
- function writeCloudflarePagesStaticShell({ serverDir, distDir, tmpDir, }) {
2349
- const serverEntry = path.join(serverDir, "index.js");
2350
- if (!fs.existsSync(serverEntry)) {
2351
- throw new Error(`React Router server build not found at ${serverEntry}`);
2352
- }
2353
- const outFile = path.join(distDir, "index.html");
2354
- const renderScript = path.join(tmpDir, "render-cloudflare-static-shell.mjs");
2355
- const basePath = normalizeConfiguredAppBasePath();
2356
- fs.writeFileSync(renderScript, `
2357
- import fs from "node:fs";
2358
- import { createRequire } from "node:module";
2359
- import { pathToFileURL } from "node:url";
2360
-
2361
- const cwd = ${JSON.stringify(cwd)};
2362
- const serverEntry = ${JSON.stringify(serverEntry)};
2363
- const outFile = ${JSON.stringify(outFile)};
2364
- const basePath = ${JSON.stringify(basePath)};
2365
-
2366
- const requireFromApp = createRequire(cwd + "/package.json");
2367
- const reactRouterEntry = requireFromApp.resolve("react-router");
2368
- const { createRequestHandler } = await import(pathToFileURL(reactRouterEntry).href);
2369
- const serverBuild = await import(pathToFileURL(serverEntry).href);
2370
- const handler = createRequestHandler(serverBuild, "production");
2371
- const pathname = basePath ? basePath + "/" : "/";
2372
- const response = await handler(
2373
- new Request(new URL(pathname, "https://agent-native.local"), {
2374
- headers: { "X-React-Router-SPA-Mode": "yes" },
2375
- }),
2376
- );
2377
- const html = await response.text();
2378
-
2379
- if (!html || !html.includes("__reactRouterContext") || !html.includes("entry.client")) {
2380
- throw new Error("React Router did not render a usable Cloudflare Pages static shell");
2381
- }
2382
-
2383
- fs.writeFileSync(outFile, html);
2384
- process.exit(0);
2385
- `);
2386
- try {
2387
- execFileSync(process.execPath, [renderScript], {
2388
- cwd,
2389
- env: {
2390
- ...process.env,
2391
- NODE_ENV: process.env.NODE_ENV || "production",
2392
- IS_RR_BUILD_REQUEST: "yes",
2393
- },
2394
- stdio: "inherit",
2395
- });
2396
- console.log("[deploy] Wrote Cloudflare Pages static app shell.");
2397
- }
2398
- catch (error) {
2399
- const message = error instanceof Error ? error.message : String(error);
2400
- console.warn(`[deploy] React Router static shell render failed; using manifest fallback. ${message}`);
2401
- fs.writeFileSync(outFile, generateCloudflarePagesStaticShellFromManifest(findReactRouterManifest(distDir), basePath));
2402
- console.log("[deploy] Wrote Cloudflare Pages static app shell fallback.");
2403
- }
2404
- }
2405
- /**
2406
- * Build for Cloudflare Pages.
2407
- * Output structure:
2408
- * dist/
2409
- * _worker.js (bundled worker entry)
2410
- * assets/ (static client assets)
2411
- */
2412
- async function buildCloudflarePages() {
2413
- generateActionRegistryForProject(cwd);
2414
- const buildDir = path.join(cwd, "build");
2415
- const clientDir = path.join(buildDir, "client");
2416
- const serverDir = path.join(buildDir, "server");
2417
- const distDir = path.join(cwd, "dist");
2418
- // Verify build output exists
2419
- if (!fs.existsSync(clientDir) || !fs.existsSync(serverDir)) {
2420
- console.error("Build output not found at build/client/ and build/server/. Run react-router build first.");
2421
- process.exit(1);
2422
- }
2423
- // Clean dist
2424
- if (fs.existsSync(distDir)) {
2425
- fs.rmSync(distDir, { recursive: true });
2426
- }
2427
- fs.mkdirSync(distDir, { recursive: true });
2428
- // Copy client assets to dist/
2429
- copyDir(clientDir, distDir);
2430
- const tmpDir = path.join(cwd, ".deploy-tmp");
2431
- fs.mkdirSync(tmpDir, { recursive: true });
2432
- writeCloudflarePagesStaticShell({ serverDir, distDir, tmpDir });
2433
- // Exclude _worker.js from being served as a public asset
2434
- fs.writeFileSync(path.join(distDir, ".assetsignore"), "_worker.js\n");
2435
- // Write package metadata inside _worker.js/ for the ES module worker that
2436
- // Wrangler compiles and uploads for Cloudflare Pages.
2437
- fs.mkdirSync(path.join(distDir, "_worker.js"), { recursive: true });
2438
- fs.writeFileSync(path.join(distDir, "_worker.js", "package.json"), JSON.stringify({ main: "index.js", type: "module" }));
2439
- // Create empty stub for native modules that wrangler's bundler needs to resolve
2440
- const stubsDir = path.join(distDir, "_worker.js", "stubs");
2441
- fs.mkdirSync(stubsDir, { recursive: true });
2442
- fs.writeFileSync(path.join(stubsDir, "empty.js"), "export default {}; export const watch = () => ({ close() {} }); export const Database = class {};\n");
2443
- // Discover routes, plugins, actions, and the workspace core (if any).
2444
- const routes = await discoverApiRoutes(cwd);
2445
- const plugins = await discoverPlugins(cwd);
2446
- const actions = await discoverActionFiles(cwd);
2447
- const missingDefaults = await getMissingDefaultPlugins(cwd);
2448
- const workspaceCore = await getWorkspaceCoreExports(cwd);
2449
- const includeReactRouterSsr = false;
2450
- const workspaceSlotCount = workspaceCore
2451
- ? Object.keys(workspaceCore.plugins).length
2452
- : 0;
2453
- console.log(`[deploy] ${routes.length} API routes, ${actions.length} actions, ${plugins.length} plugins (${plugins.filter((p) => isNodeOnlyPlugin(p)).length} skipped as Node-only), ${missingDefaults.length} auto-mounted defaults${workspaceCore ? `, workspace-core ${workspaceCore.packageName} (${workspaceSlotCount} plugin slots)` : ""}`);
2454
- // Generate the worker entry
2455
- const immutableAssetPaths = collectImmutableAssetPaths(clientDir);
2456
- const entrySource = generateWorkerEntry(routes, plugins, missingDefaults, actions, workspaceCore, immutableAssetPaths, normalizeConfiguredAppBasePath(), { includeReactRouterSsr });
2457
- // Create _worker.js output directory
2458
- const workerOutDir = path.join(distDir, "_worker.js");
2459
- fs.mkdirSync(workerOutDir, { recursive: true });
2460
- // Write the worker entry
2461
- const entryFile = path.join(workerOutDir, "index.js");
2462
- // Rewrite the server-build import to point at the copied files when this
2463
- // worker intentionally includes React Router SSR.
2464
- const adjustedEntry = includeReactRouterSsr
2465
- ? entrySource.replace(`import * as serverBuild from "./server-build.js";`, `import * as serverBuild from "./server/index.js";`)
2466
- : entrySource;
2467
- // Write a temp file for esbuild to bundle everything into a single worker entry.
2468
- // When React Router SSR is enabled, the server build is copied to tmp so
2469
- // esbuild can resolve it. Cloudflare Pages currently uses a static app shell
2470
- // instead so the worker stays under the platform bundle size limit.
2471
- // Name the entry "index.js" so esbuild outputs index.js in the outdir,
2472
- // matching the _worker.js/index.js entry point that Cloudflare Pages expects.
2473
- const tmpEntry = path.join(tmpDir, "index.js");
2474
- fs.writeFileSync(tmpEntry, adjustedEntry);
2475
- if (includeReactRouterSsr) {
2476
- copyDir(serverDir, path.join(tmpDir, "server"));
2477
- }
2478
- // Create a require shim so CJS require("fs") calls resolve via ESM imports.
2479
- // This is injected via esbuild --inject to replace its broken __require shim.
2480
- fs.writeFileSync(path.join(tmpDir, "_require-shim.js"), generateRequireShim());
2481
- const nitroServerAssetsStub = path.join(tmpDir, "_nitro-server-assets-stub.js");
2482
- fs.writeFileSync(nitroServerAssetsStub, [
2483
- "const empty = async () => undefined;",
2484
- "export const assets = {",
2485
- " getItem: empty,",
2486
- " getItemRaw: empty,",
2487
- " getKeys: async () => [],",
2488
- " getMeta: async () => undefined,",
2489
- " hasItem: async () => false,",
2490
- "};",
2491
- "export default assets;",
2492
- "",
2493
- ].join("\n"));
2494
- // Create stub modules for native/Node-only deps that can't run on Workers.
2495
- // These get resolved by esbuild instead of the real modules, avoiding bundling
2496
- // native code that would fail on the Workers runtime.
2497
- const stubDir = path.join(tmpDir, "node_modules");
2498
- for (const [mod, source] of Object.entries(CLOUDFLARE_WORKER_STUB_MODULES)) {
2499
- const modDir = path.join(stubDir, mod);
2500
- fs.mkdirSync(modDir, { recursive: true });
2501
- fs.writeFileSync(path.join(modDir, "index.js"), source);
2502
- fs.writeFileSync(path.join(modDir, "package.json"), JSON.stringify({ name: mod, main: "index.js", type: "module" }));
2503
- }
2504
- for (const [mod, source] of Object.entries(CLOUDFLARE_WORKER_STUB_SUBPATH_MODULES)) {
2505
- fs.writeFileSync(path.join(stubDir, `${mod.replace(/\//g, "__")}.js`), source);
2506
- }
2507
- const stubAliases = cloudflareWorkerStubAliasArgs(stubDir);
2508
- const nodeBuiltinStubDir = path.join(tmpDir, "node-builtin-stubs");
2509
- fs.mkdirSync(nodeBuiltinStubDir, { recursive: true });
2510
- const nodeBuiltinStubAliases = [];
2511
- for (const [mod, source] of Object.entries(CLOUDFLARE_WORKER_NODE_BUILTIN_STUB_MODULES).sort(([a], [b]) => b.length - a.length)) {
2512
- const stubFile = path.join(nodeBuiltinStubDir, `${mod.replace(/\W+/g, "_")}.js`);
2513
- fs.writeFileSync(stubFile, source);
2514
- nodeBuiltinStubAliases.push(`--alias:${mod}=${stubFile}`, `--alias:node:${mod}=${stubFile}`);
2515
- }
2516
- const esbuildBin = findEsbuild();
2517
- // Externalize node builtins (both bare and node: prefixed) — the require
2518
- // shim handles bare ones. Also alias every `node:*` specifier to its bare
2519
- // name so esbuild emits `import from "fs"` everywhere, never
2520
- // `import from "node:fs"`. CF Pages Functions (wrangler 3.x, nodejs_compat
2521
- // v1) rejects the `node:` prefix in chunks with:
2522
- // No such module "node:fs" imported from chunks/...
2523
- // The alias is the authoritative fix; the post-build strip stays as belt
2524
- // & suspenders in case esbuild emits a node: string via some other path.
2525
- const builtinNames = getNodeBuiltinNames();
2526
- // Only externalize bare names. node:* externals would otherwise pin
2527
- // the prefix in output; instead we alias node:* → bare so anything that
2528
- // resolves past alias land as bare externals.
2529
- const nodeBuiltinStubs = new Set(Object.keys(CLOUDFLARE_WORKER_NODE_BUILTIN_STUB_MODULES));
2530
- const nodeExternals = builtinNames
2531
- .filter((n) => !nodeBuiltinStubs.has(n))
2532
- .sort((a, b) => b.length - a.length)
2533
- .map((n) => `--external:${n}`);
2534
- const nodeAliases = builtinNames
2535
- .filter((n) => !nodeBuiltinStubs.has(n))
2536
- .sort((a, b) => b.length - a.length)
2537
- .map((n) => `--alias:node:${n}=${n}`);
2538
- // Hard externalize large client-only / node-only libraries so they don't
2539
- // bloat the edge worker. These are never executed in the CF Pages runtime
2540
- // — mermaid/excalidraw render in the browser, pdf-parse and @google/genai
2541
- // run from node-only action scripts. Without this, slides' bundle hits
2542
- // the 25 MiB Pages Functions limit.
2543
- //
2544
- // @anthropic-ai/tokenizer (tiktoken .wasm) and @resvg/resvg-js (native
2545
- // .node binding) can't be bundled by esbuild at all — no loader for those
2546
- // files. Both import sites degrade gracefully when the runtime import
2547
- // fails: context-xray token counts fall back to char/4 estimates and the
2548
- // OG image route falls back to SVG.
2549
- const heavyClientExternals = CLOUDFLARE_WORKER_ESBUILD_EXTERNALS.filter((p) => !Object.prototype.hasOwnProperty.call(CLOUDFLARE_WORKER_STUB_MODULES, p)).map((p) => `--external:${p}`);
2550
- execFileSync(esbuildBin, [
2551
- tmpEntry,
2552
- "--bundle",
2553
- "--format=esm",
2554
- "--target=es2022",
2555
- // browser platform for npm resolution; node builtins externalized separately
2556
- "--platform=browser",
2557
- "--minify",
2558
- // Single-file bundle (no --splitting). CF Pages Functions' deploy
2559
- // validator fails to load chunked _worker.js/ bundles even when the
2560
- // chunks contain only bare node-builtin imports (wrangler 3.101.0
2561
- // + nodejs_compat v2). Matches main's working config.
2562
- `--outdir=${workerOutDir}`,
2563
- "--conditions=workerd,worker,import",
2564
- // The ssr-handler imports a virtual module that only exists at dev time
2565
- "--external:virtual:react-router/server-build",
2566
- `--alias:#nitro/virtual/server-assets=${nitroServerAssetsStub}`,
2567
- // Banner: override the __require shim that esbuild generates for CJS modules.
2568
- // This provides a real require() backed by ESM imports of node builtins.
2569
- // Without this, CF Workers rejects the bundle because esbuild's default
2570
- // __require shim throws "Dynamic require of X is not supported".
2571
- `--banner:js=${generateRequireShim()}`,
2572
- // Externalize node: builtins — CF Workers runtime provides them
2573
- ...nodeExternals,
2574
- ...heavyClientExternals,
2575
- ...stubAliases,
2576
- ...nodeBuiltinStubAliases,
2577
- // Rewrite node:* -> bare names so chunks never contain node: imports
2578
- ...nodeAliases,
2579
- ], { stdio: "inherit", cwd });
2580
- // Clean up tmp
2581
- fs.rmSync(tmpDir, { recursive: true });
2582
- // Rewrite the external virtual import to a local stub.
2583
- // esbuild externalizes "virtual:react-router/server-build" (used by ssr-handler),
2584
- // but wrangler re-bundles and chokes on it. Replace the import with a no-op stub.
2585
- const virtualStub = path.join(workerOutDir, "chunks", "_virtual-stub.js");
2586
- fs.mkdirSync(path.dirname(virtualStub), { recursive: true });
2587
- fs.writeFileSync(virtualStub, "export default {};\n");
2588
- // Post-build patches — apply to ALL .js files in the worker output directory
2589
- // (entry + chunks) since code can land in any chunk after splitting.
2590
- const allJsFiles = getAllJsFiles(workerOutDir);
2591
- for (const jsFile of allJsFiles) {
2592
- let code = fs.readFileSync(jsFile, "utf-8");
2593
- // Strip "node:" prefix from all imports/requires. Cloudflare Pages
2594
- // Functions runs under nodejs_compat v1, which exposes builtins as
2595
- // bare names ("fs") and rejects "node:fs" at worker init:
2596
- // No such module "node:fs" imported from chunks/...
2597
- // (Workers-on-the-edge use v2 and require the prefix; Pages lags.)
2598
- // Preserve the original quote char (single vs double) when rewriting —
2599
- // esbuild's minifier sometimes places `import('node:buffer')` inside a
2600
- // double-quoted string literal; swapping to double quotes breaks the
2601
- // outer literal and produces `Unexpected identifier 'buffer'`.
2602
- code = code.replace(/\bfrom(\s*)(["'])node:([^"']+)\2/g, (_, ws, q, mod) => `from${ws}${q}${mod}${q}`);
2603
- code = code.replace(/\bimport(\s*)(["'])node:([^"']+)\2/g, (_, ws, q, mod) => `import${ws}${q}${mod}${q}`);
2604
- // Strip `node:` prefix from any string literal that names a node
2605
- // builtin. Covers dynamic imports, require(), getBuiltinModule(),
2606
- // and minified wrappers like `Ut("node:fs")` that Nitro/h3 emit.
2607
- // Pages' loader scans chunks for `"node:*"` literals and fails with
2608
- // 'No such module "node:fs"' whether or not the string is reached
2609
- // at runtime. Scoping to known builtins avoids touching user data.
2610
- // Sorted longest-first so `fs/promises` matches before `fs`.
2611
- const builtinsPattern = [...NODE_BUILTINS]
2612
- .sort((a, b) => b.length - a.length)
2613
- .join("|");
2614
- const builtinRe = new RegExp(`(["'])node:(${builtinsPattern})\\1`, "g");
2615
- code = code.replace(builtinRe, (_, q, mod) => `${q}${mod}${q}`);
2616
- // Rewrite virtual:react-router/server-build imports to the local stub.
2617
- // The generated entry handles SSR directly; this import is dead code from ssr-handler.
2618
- const relStub = path
2619
- .relative(path.dirname(jsFile), virtualStub)
2620
- .replace(/\\/g, "/");
2621
- code = code.replace(/["']virtual:react-router\/server-build["']/g, `"./${relStub}"`);
2622
- // Patch createRequire(import.meta.url) — import.meta.url is undefined in CF Workers.
2623
- // Matches both `from "module"` and `from "node:module"` — with the node:
2624
- // prefix preserved (for nodejs_compat_v2), the latter is what esbuild now emits.
2625
- code = code.replace(/\bimport\s*\{\s*createRequire\s+as\s+([\w$]+)\s*\}\s*from\s*["'](?:node:)?module["']\s*;/g, "var $1 = function() { return typeof require !== 'undefined' ? require : function(m) { throw new Error('require not supported: ' + m); }; };");
2626
- // Patch setInterval/setTimeout at module scope — CF Workers disallows timers in global scope.
2627
- code = shimCloudflarePagesModuleTimers(code);
2628
- assertNoCloudflareWorkerStubDynamicImports(code, jsFile);
2629
- fs.writeFileSync(jsFile, code);
2630
- }
2631
- // Report size
2632
- const entrySize = fs.statSync(entryFile).size;
2633
- const totalSize = getDirSize(workerOutDir);
2634
- const chunkCount = allJsFiles.length - 1; // exclude entry
2635
- console.log(`[deploy] Cloudflare Pages output written to dist/ (entry: ${(entrySize / 1024).toFixed(0)}KB, ${chunkCount} chunks, total: ${(totalSize / 1024 / 1024).toFixed(1)}MB)`);
2636
- }
2637
2347
  const NODE_BUILTINS = [
2638
2348
  "assert",
2639
2349
  "async_hooks",
@@ -2685,41 +2395,6 @@ const NODE_BUILTINS = [
2685
2395
  export function getNodeBuiltinNames() {
2686
2396
  return NODE_BUILTINS;
2687
2397
  }
2688
- /**
2689
- * Generate a require() shim that bridges CJS require("fs") calls to ESM imports.
2690
- * Injected via esbuild --inject so CJS deps work on Workers runtime.
2691
- */
2692
- function generateRequireShim() {
2693
- // Shim Node builtins that Cloudflare Pages can import, and return lazy
2694
- // unavailable proxies for builtins that Pages Functions reject at upload
2695
- // time (child_process, fs, net, etc.). This lets optional Node-only code stay
2696
- // present in the shared bundle without making worker initialization fail.
2697
- const stubbed = new Set(Object.keys(CLOUDFLARE_WORKER_NODE_BUILTIN_STUB_MODULES));
2698
- const shimmed = NODE_BUILTINS.filter((name) => !stubbed.has(name));
2699
- // Bare module names — CF Pages Functions runs under nodejs_compat v1,
2700
- // which rejects "node:fs" and only accepts "fs". The post-build pass in
2701
- // buildCloudflarePages() also strips any `node:` prefix that esbuild or
2702
- // dependencies emit elsewhere.
2703
- const imports = shimmed
2704
- .map((m) => `import __${m.replace("/", "_")} from "${m}";`)
2705
- .join("");
2706
- // Only bare-name keys. Pages' Functions loader appears to scan chunks
2707
- // for "node:*" string literals and pre-resolves them as module specs —
2708
- // so keeping "node:fs" as an object key caused deploy to fail with
2709
- // 'No such module "node:fs"' even though nothing imported it. The
2710
- // post-build strip turns every runtime `require("node:fs")` into
2711
- // `require("fs")` so bare keys are sufficient.
2712
- const entries = shimmed
2713
- .map((m) => `"${m}":__${m.replace("/", "_")}`)
2714
- .join(",");
2715
- const stubEntries = Array.from(stubbed)
2716
- .sort()
2717
- .map((m) => `"${m}":__unavailable("${m}")`)
2718
- .join(",");
2719
- const allEntries = [entries, stubEntries].filter(Boolean).join(",");
2720
- const messageChannelPolyfill = `if(typeof MessageChannel==="undefined"){globalThis.MessageChannel=class{constructor(){const a={onmessage:null},b={onmessage:null};a.postMessage=d=>{if(b.onmessage)setTimeout(()=>b.onmessage({data:d}),0)};b.postMessage=d=>{if(a.onmessage)setTimeout(()=>a.onmessage({data:d}),0)};this.port1=a;this.port2=b}}}`;
2721
- return `${imports}\n${messageChannelPolyfill}\nconst __unavailable=(m)=>new Proxy({}, { get(_target, prop) { return (..._args) => { throw new Error(m + "." + String(prop) + " is unavailable in Cloudflare Pages workers"); }; } });\nconst __mods={${allEntries}};export var require=globalThis.require||function(m){const r=__mods[m];if(r!==undefined)return r;throw new Error("Cannot require: "+m)};\n`;
2722
- }
2723
2398
  function findEsbuild() {
2724
2399
  // Try to resolve esbuild's binary via Node module resolution
2725
2400
  // This works regardless of hoisting or .bin symlink creation
@@ -2754,21 +2429,6 @@ function findWorkspaceRoot(dir) {
2754
2429
  }
2755
2430
  return null;
2756
2431
  }
2757
- /** Recursively collect all .js files in a directory. */
2758
- function getAllJsFiles(dir) {
2759
- const results = [];
2760
- const entries = fs.readdirSync(dir, { withFileTypes: true });
2761
- for (const entry of entries) {
2762
- const fullPath = path.join(dir, entry.name);
2763
- if (entry.isDirectory()) {
2764
- results.push(...getAllJsFiles(fullPath));
2765
- }
2766
- else if (entry.name.endsWith(".js")) {
2767
- results.push(fullPath);
2768
- }
2769
- }
2770
- return results;
2771
- }
2772
2432
  function getDirSize(dir) {
2773
2433
  let size = 0;
2774
2434
  const entries = fs.readdirSync(dir, { withFileTypes: true });
@@ -5453,17 +5113,18 @@ export default bundle;
5453
5113
  await nitro.close();
5454
5114
  console.log(`[deploy] Nitro build complete for preset "${preset}".`);
5455
5115
  }
5116
+ export function assertCloudflarePagesPresetRemoved(targetPreset) {
5117
+ if (targetPreset === "cloudflare_pages" ||
5118
+ targetPreset === "cloudflare-pages") {
5119
+ console.error(`[deploy] Unsupported preset "${targetPreset}". Cloudflare Pages was removed. Use cloudflare_module for Cloudflare Workers.`);
5120
+ process.exit(1);
5121
+ }
5122
+ }
5456
5123
  async function main() {
5457
5124
  console.log(`[deploy] Building for ${preset}...`);
5125
+ assertCloudflarePagesPresetRemoved(preset);
5458
5126
  await resolveDeployFrameworkRoutePrefix();
5459
5127
  switch (preset) {
5460
- case "cloudflare_pages":
5461
- case "cloudflare-pages":
5462
- // Cloudflare Workers require a single-file bundle that wrangler can deploy.
5463
- // Nitro's native presets produce split chunks that wrangler can't upload
5464
- // as multi-module Workers. Use the custom esbuild-based bundler.
5465
- await buildCloudflarePages();
5466
- break;
5467
5128
  case "cloudflare_module":
5468
5129
  case "cloudflare-module":
5469
5130
  await buildWithNitro();
@@ -15,14 +15,14 @@
15
15
  * want the whole workspace behind one domain.
16
16
  */
17
17
  import { execFileSync } from "child_process";
18
- export type WorkspaceDeployPreset = "cloudflare_pages" | "netlify" | "vercel";
18
+ export type WorkspaceDeployPreset = "netlify" | "vercel";
19
19
  export interface WorkspaceDeployOptions {
20
20
  args?: string[];
21
21
  /** Override the workspace root (defaults to walking up from cwd). */
22
22
  workspaceRoot?: string;
23
23
  /** Only build — don't invoke the deploy platform CLI. */
24
24
  buildOnly?: boolean;
25
- /** Target preset. Defaults to `cloudflare_pages`. */
25
+ /** Target preset. Defaults to `netlify`. */
26
26
  preset?: WorkspaceDeployPreset;
27
27
  /** @internal Override process execution in tests. */
28
28
  execFile?: typeof execFileSync;
@@ -130,7 +130,7 @@ export async function runWorkspaceDeploy(opts = {}) {
130
130
  buildOneApp(workspaceRoot, appsDir, app, preset, execFile, workspaceApps, workspaceAuthMode);
131
131
  moveAppBuildIntoWorkspaceOutput(workspaceRoot, appsDir, app, preset, distDir, vercelOutputDir, workspaceApps, workspaceAuthMode);
132
132
  }
133
- writeWorkspaceAppManifests(workspaceRoot, distDir, apps, workspaceApps, preset);
133
+ writeWorkspaceAppManifests(workspaceRoot, apps, workspaceApps, preset);
134
134
  if (workspaceRootPage === "directory") {
135
135
  writeWorkspaceDirectoryPage(preset === "vercel" ? path.join(vercelOutputDir, "static") : distDir, workspaceApps);
136
136
  }
@@ -138,11 +138,8 @@ export async function runWorkspaceDeploy(opts = {}) {
138
138
  writeNetlifyRedirects(distDir, apps, workspaceRootPage);
139
139
  writeNetlifyHeaders(distDir, apps);
140
140
  }
141
- else if (preset === "vercel") {
142
- writeVercelBuildConfig(vercelOutputDir, apps, workspaceRootPage);
143
- }
144
141
  else {
145
- writeCloudflareRoutingManifest(distDir, apps, workspaceRootPage);
142
+ writeVercelBuildConfig(vercelOutputDir, apps, workspaceRootPage);
146
143
  }
147
144
  if (buildOnly) {
148
145
  const outputDir = preset === "vercel" ? vercelOutputDir : distDir;
@@ -154,11 +151,8 @@ export async function runWorkspaceDeploy(opts = {}) {
154
151
  if (preset === "netlify") {
155
152
  console.log(` netlify deploy --prod --dir=dist --functions=.netlify/functions-internal\n`);
156
153
  }
157
- else if (preset === "vercel") {
158
- console.log(` vercel deploy --prebuilt\n`);
159
- }
160
154
  else {
161
- console.log(` wrangler pages deploy dist\n`);
155
+ console.log(` vercel deploy --prebuilt\n`);
162
156
  }
163
157
  console.log(`All apps live at https://<origin>/<app-name>/*. Log in once on any app\nand the session is shared across the workspace.`);
164
158
  }
@@ -230,8 +224,7 @@ function moveAppBuildIntoWorkspaceOutput(workspaceRoot, appsDir, app, preset, di
230
224
  return;
231
225
  }
232
226
  // Resolve the per-app build output: prefer dist/ (standard), fall back to
233
- // .output/ (Nitro's default). The Cloudflare preset emits into dist/
234
- // containing the worker + assets.
227
+ // .output/ (Nitro's default).
235
228
  const candidates = ["dist", ".output"];
236
229
  const src = candidates
237
230
  .map((c) => path.join(appDir, c))
@@ -251,11 +244,6 @@ function moveAppBuildIntoWorkspaceOutput(workspaceRoot, appsDir, app, preset, di
251
244
  fs.rmSync(path.join(target, app), { recursive: true, force: true });
252
245
  copyNetlifyFunctionIntoWorkspace(workspaceRoot, appsDir, app, workspaceApps, target, workspaceAuthMode);
253
246
  }
254
- else {
255
- const target = path.join(distDir, app);
256
- fs.mkdirSync(target, { recursive: true });
257
- copyDir(src, target);
258
- }
259
247
  }
260
248
  function copyVercelAppBuildIntoWorkspace(appsDir, app, vercelOutputDir, workspaceApps, workspaceAuthMode) {
261
249
  const appDir = path.join(appsDir, app);
@@ -288,107 +276,6 @@ function copyVercelAppBuildIntoWorkspace(appsDir, app, vercelOutputDir, workspac
288
276
  cloneServerBundleForFunction(functionSrc, functionDest);
289
277
  patchVercelFunctionEntry(functionDest, app, workspaceApps, workspaceAuthMode);
290
278
  }
291
- /**
292
- * Write the Cloudflare Pages `_routes.json` and a dispatcher `_worker.js` at
293
- * the workspace dist root so each app is reachable under /<app>/*.
294
- */
295
- function writeCloudflareRoutingManifest(distDir, apps, rootPage) {
296
- const dispatchFaviconAsset = apps.includes("dispatch")
297
- ? dispatchRootFaviconAsset(distDir)
298
- : null;
299
- // _routes.json tells Cloudflare which paths are dynamic (Functions) vs
300
- // static. Mark both /<app> and /<app>/* as include so every app's worker
301
- // handles its root and subtree.
302
- const include = [
303
- ...apps.flatMap((a) => [`/${a}`, `/${a}/*`]),
304
- ...apps.flatMap((app) => workspaceOAuthDiscoveryRoutes(app).flatMap(({ path, descendants }) => [
305
- path,
306
- ...(descendants ? [`${path}/*`] : []),
307
- ])),
308
- ];
309
- if (rootPage !== "directory")
310
- include.push("/");
311
- if (apps.includes("dispatch")) {
312
- include.push(`${workspaceFrameworkRoutePrefix()}/*`);
313
- include.push("/.well-known/*");
314
- include.push(...DISPATCH_WORKSPACE_ROOT_REDIRECTS.map(([from]) => `/${from}`));
315
- include.push("/apps/*");
316
- if (dispatchFaviconAsset)
317
- include.push("/favicon.ico");
318
- }
319
- const routes = {
320
- version: 1,
321
- include,
322
- exclude: [],
323
- };
324
- fs.writeFileSync(path.join(distDir, "_routes.json"), JSON.stringify(routes, null, 2) + "\n");
325
- // Dispatcher worker: inspects the path and forwards to the matching
326
- // per-app worker.
327
- const imports = apps
328
- .map((a) => `import ${moduleIdent(a)} from "./${a}/_worker.js";`)
329
- .join("\n");
330
- const dispatch = apps
331
- .map((a) => ` if (pathname === "/${a}" || pathname === "/${a}.data" || pathname.startsWith("/${a}/")) return ${moduleIdent(a)}.fetch(requestForMountedApp(request, "/${a}"), env, ctx);`)
332
- .join("\n");
333
- const workspaceOAuthRoutes = apps
334
- .flatMap((app) => workspaceOAuthDiscoveryRoutes(app).map(({ path, descendants }) => {
335
- const matches = descendants
336
- ? `pathname === ${JSON.stringify(path)} || pathname.startsWith(${JSON.stringify(`${path}/`)})`
337
- : `pathname === ${JSON.stringify(path)}`;
338
- return ` if (${matches}) return ${moduleIdent(app)}.fetch(request, env, ctx);`;
339
- }))
340
- .join("\n");
341
- const dispatchRootFrameworkRoutes = apps.includes("dispatch")
342
- ? ` if (pathname === ${JSON.stringify(workspaceFrameworkRoutePrefix())} || pathname.startsWith(${JSON.stringify(`${workspaceFrameworkRoutePrefix()}/`)}) || pathname === "/.well-known" || pathname.startsWith("/.well-known/")) return ${moduleIdent("dispatch")}.fetch(request, env, ctx);
343
- `
344
- : "";
345
- const dispatchRootFaviconRoute = dispatchFaviconAsset
346
- ? ` if (pathname === "/favicon.ico") return Response.redirect(new URL("/dispatch/${dispatchFaviconAsset}", request.url).toString(), 302);
347
- `
348
- : "";
349
- const dispatchRootAliasRoutes = apps.includes("dispatch")
350
- ? DISPATCH_WORKSPACE_ROOT_REDIRECTS.map(([from, to]) => ` if (pathname === "/${from}") return Response.redirect(new URL("/dispatch/${to}" + search, request.url).toString(), 302);`).join("\n") + "\n"
351
- : "";
352
- const dispatchRootDynamicAliasRoutes = apps.includes("dispatch")
353
- ? ` if (pathname.startsWith("/apps/")) return Response.redirect(new URL("/dispatch" + pathname + search, request.url).toString(), 302);
354
- `
355
- : "";
356
- const dispatchMountedRootRedirect = apps.includes("dispatch")
357
- ? ` if (pathname === "/dispatch" || pathname === "/dispatch/") return Response.redirect(new URL("/dispatch/overview" + search, request.url).toString(), 302);
358
- `
359
- : "";
360
- const rootRedirect = rootPage === "directory"
361
- ? ""
362
- : ` if (pathname === "/") {
363
- return Response.redirect(new URL("${cloudflareRootRedirectPath(apps)}", request.url).toString(), 302);
364
- }
365
- `;
366
- const worker = `${imports}
367
-
368
- function requestForMountedApp(request, basePath) {
369
- const url = new URL(request.url);
370
- if (url.pathname !== basePath && url.pathname !== \`\${basePath}/\`) {
371
- return request;
372
- }
373
- url.pathname = \`\${basePath}//\`;
374
- return new Request(url, request);
375
- }
376
-
377
- export default {
378
- async fetch(request, env, ctx) {
379
- const { pathname, search } = new URL(request.url);
380
- ${workspaceOAuthRoutes}
381
- ${dispatchRootFrameworkRoutes}${dispatchRootFaviconRoute}${dispatchRootAliasRoutes}${dispatchRootDynamicAliasRoutes}${dispatchMountedRootRedirect}${dispatch}
382
- ${rootRedirect}
383
- return new Response("Not found", { status: 404 });
384
- },
385
- };
386
- `;
387
- fs.writeFileSync(path.join(distDir, "_worker.js"), worker);
388
- }
389
- function cloudflareRootRedirectPath(apps) {
390
- return apps.includes("dispatch") ? "/dispatch/overview" : `/${apps[0]}/`;
391
- }
392
279
  function workspaceOAuthDiscoveryRoutes(app) {
393
280
  return [
394
281
  {
@@ -1212,16 +1099,14 @@ function appUsesNetlifyUnpooledDatabaseUrl(appDir) {
1212
1099
  return false;
1213
1100
  }
1214
1101
  }
1215
- function writeWorkspaceAppManifests(workspaceRoot, distDir, apps, workspaceApps, preset) {
1102
+ function writeWorkspaceAppManifests(workspaceRoot, apps, workspaceApps, preset) {
1216
1103
  const manifest = JSON.stringify({
1217
1104
  version: 1,
1218
1105
  apps: workspaceApps,
1219
1106
  }, null, 2);
1220
1107
  const targets = preset === "netlify"
1221
1108
  ? apps.map((app) => path.join(netlifyFunctionsDir(workspaceRoot), `${app}-server`, WORKSPACE_APPS_MANIFEST_DIR, WORKSPACE_APPS_MANIFEST_FILE))
1222
- : preset === "vercel"
1223
- ? apps.map((app) => path.join(workspaceRoot, VERCEL_OUTPUT_DIR, "functions", `${app}-server.func`, WORKSPACE_APPS_MANIFEST_DIR, WORKSPACE_APPS_MANIFEST_FILE))
1224
- : apps.map((app) => path.join(distDir, app, WORKSPACE_APPS_MANIFEST_DIR, WORKSPACE_APPS_MANIFEST_FILE));
1109
+ : apps.map((app) => path.join(workspaceRoot, VERCEL_OUTPUT_DIR, "functions", `${app}-server.func`, WORKSPACE_APPS_MANIFEST_DIR, WORKSPACE_APPS_MANIFEST_FILE));
1225
1110
  for (const target of targets) {
1226
1111
  fs.mkdirSync(path.dirname(target), { recursive: true });
1227
1112
  fs.writeFileSync(target, `${manifest}\n`);
@@ -1525,7 +1410,7 @@ function resolvePreset(optionPreset, args) {
1525
1410
  return (optionPreset ??
1526
1411
  parsePresetArg(args) ??
1527
1412
  normalizePreset(process.env.NITRO_PRESET) ??
1528
- "cloudflare_pages");
1413
+ "netlify");
1529
1414
  }
1530
1415
  function assertWorkspaceDeployProductionEnv(opts) {
1531
1416
  if (!isProductionWorkspaceDeploy(opts))
@@ -1550,9 +1435,6 @@ function isProductionWorkspaceDeploy(opts) {
1550
1435
  process.env.NETLIFY_LOCAL !== "true") {
1551
1436
  return true;
1552
1437
  }
1553
- if (opts.preset === "cloudflare_pages" && process.env.CF_PAGES === "1") {
1554
- return true;
1555
- }
1556
1438
  if (opts.preset === "vercel" && process.env.VERCEL === "1") {
1557
1439
  return true;
1558
1440
  }
@@ -1562,16 +1444,13 @@ function normalizePreset(value) {
1562
1444
  if (!value)
1563
1445
  return null;
1564
1446
  if (value === "cloudflare_pages" || value === "cloudflare-pages") {
1565
- return "cloudflare_pages";
1447
+ throw new Error(`Unsupported workspace deploy preset "${value}". Cloudflare Pages was removed. Supported presets: netlify, vercel. For standalone Cloudflare Workers use NITRO_PRESET=cloudflare_module.`);
1566
1448
  }
1567
1449
  if (value === "netlify")
1568
1450
  return "netlify";
1569
1451
  if (value === "vercel")
1570
1452
  return "vercel";
1571
- throw new Error(`Unsupported workspace deploy preset "${value}". Supported presets: cloudflare_pages, netlify, vercel.`);
1572
- }
1573
- function moduleIdent(app) {
1574
- return "app_" + app.replace(/[^a-zA-Z0-9_]/g, "_");
1453
+ throw new Error(`Unsupported workspace deploy preset "${value}". Supported presets: netlify, vercel.`);
1575
1454
  }
1576
1455
  function workspaceAppAudienceForApp(workspaceApps, app) {
1577
1456
  return (workspaceApps.find((entry) => entry.id === app)?.audience ??
@@ -44,9 +44,9 @@ declare const _default: import("../../action.js").ActionDefinition<{
44
44
  url: string;
45
45
  id: string;
46
46
  provider: string;
47
- error?: undefined;
48
47
  configured?: undefined;
49
48
  connectPath?: undefined;
49
+ error?: undefined;
50
50
  } | {
51
51
  url?: undefined;
52
52
  id?: undefined;