@junejs/server 0.1.3 → 0.2.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.
Files changed (131) hide show
  1. package/assets/icon-latin.LICENSE.txt +92 -0
  2. package/assets/icon-latin.ttf +0 -0
  3. package/dist/adapter-D0UnYBuN.d.ts +64 -0
  4. package/dist/adapter.d.ts +2 -56
  5. package/dist/adapter.js +107 -6
  6. package/dist/agent-compile.d.ts +38 -0
  7. package/dist/agent-compile.js +145 -0
  8. package/dist/agent-discover.d.ts +4 -4
  9. package/dist/agent-discover.js +30 -44
  10. package/dist/agent-durable.d.ts +94 -19
  11. package/dist/agent-durable.js +647 -32
  12. package/dist/agent-native.d.ts +44 -13
  13. package/dist/agent-native.js +264 -27
  14. package/dist/app.d.ts +5 -5
  15. package/dist/app.js +42 -10
  16. package/dist/assets.d.ts +23 -0
  17. package/dist/assets.js +123 -0
  18. package/dist/blob.d.ts +4 -5
  19. package/dist/build.d.ts +8 -30
  20. package/dist/build.js +143 -298
  21. package/dist/client-bundle.d.ts +8 -9
  22. package/dist/client-bundle.js +1 -1
  23. package/dist/config-freeze-r5p-vTWv.d.ts +17 -0
  24. package/dist/config-freeze.d.ts +2 -0
  25. package/dist/config-freeze.js +54 -0
  26. package/dist/config-loader.d.ts +3 -4
  27. package/dist/connection-auth.d.ts +38 -0
  28. package/dist/connection-auth.js +31 -0
  29. package/dist/content-freeze-CyiW2fRK.d.ts +4 -0
  30. package/dist/content-freeze.d.ts +2 -0
  31. package/dist/content-freeze.js +83 -0
  32. package/dist/content.d.ts +22 -9
  33. package/dist/content.js +43 -3
  34. package/dist/core-version.d.ts +4 -0
  35. package/dist/core-version.js +12 -0
  36. package/dist/css-modules-ambient.d.ts +2 -1
  37. package/dist/css-modules.d.ts +10 -11
  38. package/dist/css.d.ts +9 -10
  39. package/dist/d1-migrate.d.ts +6 -7
  40. package/dist/d1-migrate.js +3 -2
  41. package/dist/db.d.ts +2 -2
  42. package/dist/deploy.d.ts +3 -4
  43. package/dist/deploy.js +3 -2
  44. package/dist/dev-reload.d.ts +3 -4
  45. package/dist/dev.d.ts +8 -5
  46. package/dist/dev.js +40 -9
  47. package/dist/favicon.d.ts +37 -0
  48. package/dist/favicon.js +248 -0
  49. package/dist/host.d.ts +6 -5
  50. package/dist/host.js +2 -1
  51. package/dist/icon-letter.d.ts +3 -0
  52. package/dist/icon-letter.js +8 -0
  53. package/dist/index.d.ts +11 -5
  54. package/dist/index.js +9 -3
  55. package/dist/instrumentation.d.ts +2 -3
  56. package/dist/instrumentation.js +2 -1
  57. package/dist/island-registry.d.ts +6 -7
  58. package/dist/isolate-local.d.ts +5 -0
  59. package/dist/isolate-local.js +12 -0
  60. package/dist/kv.d.ts +3 -4
  61. package/dist/llms-links.d.ts +9 -0
  62. package/dist/llms-links.js +65 -0
  63. package/dist/manifest-CwTT1zVs.d.ts +11 -0
  64. package/dist/manifest.d.ts +2 -0
  65. package/dist/manifest.js +113 -0
  66. package/dist/negotiate.d.ts +4 -3
  67. package/dist/negotiate.js +24 -14
  68. package/dist/{pipeline-CCp9idQ4.d.ts → pipeline-BHUjBO0G.d.ts} +13 -1
  69. package/dist/pipeline.d.ts +2 -2
  70. package/dist/pipeline.js +286 -35
  71. package/dist/resources.d.ts +5 -6
  72. package/dist/route-rank.d.ts +6 -7
  73. package/dist/route-scan-BMbBzPIB.d.ts +20 -0
  74. package/dist/route-scan.d.ts +2 -0
  75. package/dist/route-scan.js +100 -0
  76. package/dist/router.d.ts +12 -13
  77. package/dist/router.js +51 -38
  78. package/dist/rsc-build.d.ts +6 -7
  79. package/dist/rsc-bundle.d.ts +6 -7
  80. package/dist/rsc-manifest.d.ts +5 -6
  81. package/dist/rsc-runtime/flight-render-routes.d.ts +3 -4
  82. package/dist/rsc-runtime/flight-render.d.ts +2 -3
  83. package/dist/rsc-runtime/flight-to-html.d.ts +2 -3
  84. package/dist/rsc-runtime/flight-to-html.js +3 -2
  85. package/dist/rsc-runtime/rsc-worker.js +11 -8
  86. package/dist/rsc-runtime/rsdw-shims.d.ts +2 -1
  87. package/dist/segment.d.ts +4 -5
  88. package/dist/sqlite-driver.d.ts +11 -11
  89. package/dist/sqlite-driver.js +17 -4
  90. package/dist/static-files.d.ts +4 -5
  91. package/dist/tsconfig-jsx.d.ts +4 -4
  92. package/dist/tsconfig-jsx.js +1 -1
  93. package/dist/turn-events.d.ts +4 -0
  94. package/dist/turn-events.js +46 -0
  95. package/dist/web-manifest.d.ts +5 -0
  96. package/dist/web-manifest.js +42 -0
  97. package/dist/worker-2qbQjj2c.d.ts +64 -0
  98. package/dist/worker.d.ts +2 -57
  99. package/dist/worker.js +69 -27
  100. package/package.json +28 -9
  101. package/src/adapter.ts +149 -4
  102. package/src/agent-compile.ts +271 -0
  103. package/src/agent-discover.ts +77 -63
  104. package/src/agent-durable.ts +998 -30
  105. package/src/agent-native.ts +370 -35
  106. package/src/app.ts +75 -6
  107. package/src/assets.ts +200 -0
  108. package/src/build.ts +241 -449
  109. package/src/config-freeze.ts +109 -0
  110. package/src/connection-auth.ts +101 -0
  111. package/src/content-freeze.ts +151 -0
  112. package/src/content.ts +55 -4
  113. package/src/core-version.ts +34 -0
  114. package/src/dev.ts +41 -8
  115. package/src/favicon.ts +325 -0
  116. package/src/host.ts +4 -3
  117. package/src/icon-letter.ts +14 -0
  118. package/src/index.ts +22 -0
  119. package/src/isolate-local.ts +33 -0
  120. package/src/llms-links.ts +96 -0
  121. package/src/manifest.ts +130 -0
  122. package/src/negotiate.ts +39 -15
  123. package/src/pipeline.ts +494 -44
  124. package/src/route-scan.ts +161 -0
  125. package/src/router.ts +66 -54
  126. package/src/rsc-runtime/rsc-worker.tsx +5 -4
  127. package/src/sqlite-driver.ts +36 -6
  128. package/src/tsconfig-jsx.ts +2 -2
  129. package/src/turn-events.ts +43 -0
  130. package/src/web-manifest.ts +38 -0
  131. package/src/worker.ts +131 -35
package/dist/build.js CHANGED
@@ -1,286 +1,29 @@
1
- import { deno, staticSite, vercel, workers } from "./adapter.js";
1
+ import { jsxTransform } from "./tsconfig-jsx.js";
2
+ import { generateAgentModule } from "./agent-compile.js";
2
3
  import { findMiddlewareFile } from "./router.js";
4
+ import { scanAppRoutes, scanRoutes } from "./route-scan.js";
3
5
  import { resolveBoundary } from "./segment.js";
4
6
  import { buildModuleCss, registerCssModules, rolldownCssModulesPlugin } from "./css-modules.js";
5
- import { jsxTransform } from "./tsconfig-jsx.js";
6
- import { CLIENT_SCRIPT_URL, bundleClientToFile, findClientEntry } from "./client-bundle.js";
7
+ import { bundleClientToFile, findClientEntry } from "./client-bundle.js";
7
8
  import { generateIslandRegistry } from "./island-registry.js";
8
- import { STYLES_URL, cssTargets, findGlobalCss, globalCssUsesTailwind, minifyCss, processCss } from "./css.js";
9
+ import { cssTargets, minifyCss, processCss } from "./css.js";
9
10
  import { RESERVED_PREFIX } from "./static-files.js";
10
- import { findJuneConfigPath, loadJuneConfig } from "./config-loader.js";
11
- import { generateContentModule } from "./content.js";
11
+ import { GENERATED_ICONS, googleFontFetcher, publicFileCheck, renderIcons, resolveIcons } from "./favicon.js";
12
+ import { loadJuneConfig } from "./config-loader.js";
13
+ import { freezeConfig, normalizeBase, resolveDeployAdapter, workerName } from "./config-freeze.js";
14
+ import { generateContent } from "./content-freeze.js";
12
15
  import { createWorker } from "./worker.js";
16
+ import { buildManifest, importLayout } from "./manifest.js";
13
17
  import { buildRsc, findRscRoutes } from "./rsc-build.js";
14
18
  import { existsSync, lstatSync } from "node:fs";
15
- import { copyFile, mkdir, readFile, readdir, rm, writeFile } from "node:fs/promises";
19
+ import { copyFile, mkdir, readdir, rm, writeFile } from "node:fs/promises";
16
20
  import { basename, dirname, join, relative, resolve, sep } from "node:path";
17
- import { pathToFileURL } from "node:url";
18
- import { routeFromModule } from "@junejs/core/route";
19
- import { resolveAgent, resolveClientRouter, resolveSpeculationRules } from "@junejs/core/config";
21
+ import { PRERENDER_ORIGIN } from "@junejs/core/document";
20
22
  import { buildLinkHeader } from "@junejs/core/discovery";
21
23
  import { localeHref } from "@junejs/core/i18n";
22
24
  import { createHash } from "node:crypto";
23
- import { execFileSync } from "node:child_process";
24
25
  //#region src/build.ts
25
- const PAGE_BASENAMES = /* @__PURE__ */ new Set(["page", "index"]);
26
- const ROUTE_EXTS = [
27
- ".tsx",
28
- ".jsx",
29
- ".ts",
30
- ".js"
31
- ];
32
- const isRouteGroup = (name) => /^\(.+\)$/.test(name);
33
26
  const isBunSpecifier = (id) => id === "bun" || id.startsWith("bun:");
34
- function resolveDeployAdapter(deploy) {
35
- if (deploy?.adapter) return deploy.adapter;
36
- switch (deploy?.target) {
37
- case "static": return staticSite();
38
- case "vercel": return vercel();
39
- case "deno": return deno();
40
- default: return workers({
41
- name: deploy?.name,
42
- domain: deploy?.domain
43
- });
44
- }
45
- }
46
- function segmentFile(dir, base) {
47
- return ROUTE_EXTS.map((e) => join(dir, `${base}${e}`)).find(existsSync);
48
- }
49
- async function scanRoutes(appDir, dir = appDir, layouts = [], out = [], loading) {
50
- const ownLayout = segmentFile(dir, "layout");
51
- const chain = ownLayout ? [...layouts, ownLayout] : layouts;
52
- const nearestLoading = segmentFile(dir, "loading") ?? loading;
53
- const entries = await readdir(dir, { withFileTypes: true }).catch(() => []);
54
- for (const e of entries) {
55
- if (e.name.startsWith("_") || e.name.startsWith(".")) continue;
56
- const full = join(dir, e.name);
57
- if (e.isDirectory()) {
58
- await scanRoutes(appDir, full, chain, out, nearestLoading);
59
- continue;
60
- }
61
- const ext = e.name.match(/\.[^.]+$/)?.[0] ?? "";
62
- if (!ROUTE_EXTS.includes(ext)) continue;
63
- const base = basename(e.name, ext);
64
- const resource = base === "route";
65
- if (!PAGE_BASENAMES.has(base) && !resource) continue;
66
- const relDir = relative(appDir, dir);
67
- const path = "/" + (relDir === "" ? [] : relDir.split(sep).filter((s) => !isRouteGroup(s))).join("/");
68
- out.push({
69
- path: path === "/" ? "/" : path,
70
- file: full,
71
- dynamic: /\[.+\]/.test(path),
72
- resource,
73
- layouts: chain,
74
- loading: nearestLoading
75
- });
76
- }
77
- return out;
78
- }
79
- async function generateContent(appRoot) {
80
- const contentDir = join(appRoot, "content");
81
- await mkdir(join(appRoot, "app"), { recursive: true });
82
- const emit = async (sources, knownLocales) => {
83
- const { code, names } = generateContentModule(contentDir, knownLocales, sources);
84
- await writeFile(join(appRoot, "app", "_content.ts"), code);
85
- return names;
86
- };
87
- const resolveSources = (sources) => sources.map((s) => ({
88
- ...s,
89
- dir: resolve(appRoot, s.dir)
90
- }));
91
- const declaredLocales = (config) => config.i18n ? [.../* @__PURE__ */ new Set([config.i18n.defaultLocale, ...Object.keys(config.i18n.locales)])] : [];
92
- let config = null;
93
- try {
94
- config = await loadJuneConfig(appRoot);
95
- } catch {}
96
- if (config) return emit(resolveSources(config.content?.sources ?? []), declaredLocales(config));
97
- const names = await emit([], void 0);
98
- await seedContentImports(appRoot);
99
- const probed = probeConfigFresh(appRoot);
100
- if (probed === null) {
101
- console.warn("[june gen] june.config.ts failed to load — content.sources/i18n locales (if any) not applied");
102
- return names;
103
- }
104
- return emit(resolveSources(probed.sources), probed.locales);
105
- }
106
- async function seedContentImports(appRoot) {
107
- const cfgPath = findJuneConfigPath(appRoot);
108
- if (!cfgPath) return;
109
- const contentFile = join(appRoot, "app", "_content.ts");
110
- const current = existsSync(contentFile) ? await readFile(contentFile, "utf8") : "";
111
- const cfgSrc = await readFile(cfgPath, "utf8");
112
- const isIdent = (s) => /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(s);
113
- const seen = /* @__PURE__ */ new Set();
114
- const stubs = [];
115
- for (const m of cfgSrc.matchAll(/import\s*(?:type\s+)?\{([^}]*)\}\s*from\s*["'][^"']*app\/_content(?:\.\w+)?["']/g)) {
116
- const inner = (m[1] ?? "").replace(/\/\*[\s\S]*?\*\//g, "").replace(/\/\/[^\n]*/g, "");
117
- for (const part of inner.split(",")) {
118
- const name = part.replace(/\btype\b/g, "").split(/\s+as\s+/).pop()?.trim();
119
- if (!name || !isIdent(name) || seen.has(name)) continue;
120
- seen.add(name);
121
- const reName = name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
122
- if (!new RegExp(`export (?:const|function|type) ${reName}\\b`).test(current)) stubs.push(`export const ${name}: ContentEntry[] = [];`);
123
- }
124
- }
125
- if (stubs.length) await writeFile(contentFile, current + stubs.join("\n") + "\n");
126
- }
127
- function probeConfigFresh(appRoot) {
128
- const path = findJuneConfigPath(appRoot);
129
- if (!path) return {
130
- sources: [],
131
- locales: []
132
- };
133
- const code = `import(${JSON.stringify(pathToFileURL(path).href)}).then((m) => { const c = m.default ?? {}; process.stdout.write("\\n__JUNE_CONTENT__" + JSON.stringify({ sources: c.content?.sources ?? [], locales: c.i18n ? [...new Set([c.i18n.defaultLocale, ...Object.keys(c.i18n.locales ?? {})])] : [] }) + "__END__"); }, () => process.exit(42));`;
134
- try {
135
- const m = execFileSync(process.execPath, [
136
- ...process.execArgv,
137
- "-e",
138
- code
139
- ], {
140
- encoding: "utf8",
141
- stdio: [
142
- "ignore",
143
- "pipe",
144
- "ignore"
145
- ]
146
- }).match(/__JUNE_CONTENT__(.*?)__END__/s);
147
- return m ? JSON.parse(m[1]) : null;
148
- } catch {
149
- return null;
150
- }
151
- }
152
- async function freezeConfig(appRoot) {
153
- const cfg = await loadJuneConfig(appRoot);
154
- const hasClient = findClientEntry(join(appRoot, "app")) !== void 0 || findClientEntry(join(appRoot, ".june", "routes")) !== void 0;
155
- const hasCss = findGlobalCss(join(appRoot, "app")) !== null;
156
- return {
157
- document: {
158
- site: cfg.site ?? {},
159
- speculationRules: resolveSpeculationRules(cfg.speculation ?? void 0),
160
- speculationDelivery: "inline",
161
- viewTransitions: cfg.viewTransitions ?? true,
162
- cssReset: cfg.cssReset ?? !globalCssUsesTailwind(join(appRoot, "app")),
163
- clientRouter: resolveClientRouter(cfg.clientRouter),
164
- clientScript: hasClient ? CLIENT_SCRIPT_URL : null,
165
- styles: hasCss ? STYLES_URL : null,
166
- basePath: normalizeBase(cfg.basePath)
167
- },
168
- agent: resolveAgent(cfg.agent),
169
- i18n: cfg.i18n,
170
- earlyHints: cfg.earlyHints ?? [],
171
- buildExternal: cfg.build?.external ?? []
172
- };
173
- }
174
- function normalizeBase(base) {
175
- if (!base) return "";
176
- const b = base.startsWith("/") ? base : `/${base}`;
177
- return b.endsWith("/") ? b.slice(0, -1) : b;
178
- }
179
- async function importLayout(file) {
180
- const mod = await import(pathToFileURL(file).href);
181
- return typeof mod.default === "function" ? {
182
- component: mod.default,
183
- boundary: mod.segmentBoundary === true
184
- } : null;
185
- }
186
- function workerName(raw) {
187
- return raw.replace(/^@[^/]+\//, "").toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "") || "app";
188
- }
189
- async function buildManifest(appRoot) {
190
- const appDir = join(appRoot, "app");
191
- const juneRoutesDir = join(appRoot, ".june", "routes");
192
- const frozen = await freezeConfig(appRoot);
193
- const appRoutes = await scanRoutes(appDir);
194
- const frameworkRoutes = existsSync(juneRoutesDir) ? await scanRoutes(juneRoutesDir) : [];
195
- const appPaths = new Set(appRoutes.map((r) => r.path));
196
- const scanned = [...appRoutes, ...frameworkRoutes.filter((r) => !appPaths.has(r.path)).map((r) => ({
197
- ...r,
198
- generated: true
199
- }))].sort((a, b) => a.path.localeCompare(b.path));
200
- const generatedRoutes = scanned.filter((r) => r.generated).map((r) => r.path);
201
- const layoutCache = /* @__PURE__ */ new Map();
202
- const loadCached = async (f) => {
203
- if (!layoutCache.has(f)) layoutCache.set(f, await importLayout(f));
204
- return layoutCache.get(f) ?? null;
205
- };
206
- const componentsFor = async (files) => {
207
- const items = [];
208
- for (const f of files) {
209
- const c = await loadCached(f);
210
- items.push({
211
- file: f,
212
- entry: c?.component ?? null,
213
- boundary: !!c?.boundary
214
- });
215
- }
216
- return resolveBoundary(items);
217
- };
218
- const loadingCache = /* @__PURE__ */ new Map();
219
- const loadingFor = async (file) => {
220
- if (!file) return void 0;
221
- if (!loadingCache.has(file)) {
222
- const loaded = await importLayout(file);
223
- loadingCache.set(file, loaded ? loaded.component : null);
224
- }
225
- return loadingCache.get(file) ?? void 0;
226
- };
227
- const routes = {};
228
- const dynamicRoutes = [];
229
- const resourceRoutes = [];
230
- const layoutChains = {};
231
- const layoutBoundaries = {};
232
- const loadings = {};
233
- for (const r of scanned) {
234
- const mod = await import(pathToFileURL(r.file).href);
235
- if (r.resource) {
236
- const handler = mod.default;
237
- if (typeof handler === "function") resourceRoutes.push({
238
- pattern: r.path,
239
- handler
240
- });
241
- continue;
242
- }
243
- const def = routeFromModule(mod);
244
- if (!def) continue;
245
- const { chain, boundaryIndex, key } = await componentsFor(r.layouts);
246
- const loading = await loadingFor(r.loading);
247
- if (r.dynamic) {
248
- dynamicRoutes.push({
249
- pattern: r.path,
250
- def
251
- });
252
- layoutChains[r.path] = chain;
253
- } else {
254
- routes[r.path] = def;
255
- layoutChains[r.path] = chain;
256
- }
257
- if (boundaryIndex !== null && key !== null) layoutBoundaries[r.path] = {
258
- index: boundaryIndex,
259
- key
260
- };
261
- if (loading) loadings[r.path] = loading;
262
- }
263
- let extra;
264
- const extraFile = findMiddlewareFile(appDir);
265
- if (extraFile) {
266
- const mod = await import(pathToFileURL(extraFile).href);
267
- if (typeof mod.default === "function") extra = mod.default;
268
- }
269
- return {
270
- routes,
271
- dynamicRoutes,
272
- resourceRoutes,
273
- ...generatedRoutes.length ? { generatedRoutes } : {},
274
- layoutChains,
275
- layoutBoundaries,
276
- loadings,
277
- document: frozen.document,
278
- agent: frozen.agent,
279
- i18n: frozen.i18n,
280
- earlyHints: frozen.earlyHints,
281
- extra
282
- };
283
- }
284
27
  function importPath(fromDir, file) {
285
28
  const p = relative(fromDir, file).split(sep).join("/").replace(/\.[^.]+$/, "");
286
29
  return p.startsWith(".") ? p : `./${p}`;
@@ -305,14 +48,7 @@ async function juneBuild(appRoot, options = {}) {
305
48
  force: true
306
49
  });
307
50
  const contentCollections = await generateContent(appRoot);
308
- const juneRoutesDir2 = join(appRoot, ".june", "routes");
309
- const appRoutes2 = await scanRoutes(appDir);
310
- const frameworkRoutes2 = existsSync(juneRoutesDir2) ? await scanRoutes(juneRoutesDir2) : [];
311
- const appPaths2 = new Set(appRoutes2.map((r) => r.path));
312
- const routes = [...appRoutes2, ...frameworkRoutes2.filter((r) => !appPaths2.has(r.path)).map((r) => ({
313
- ...r,
314
- generated: true
315
- }))].sort((a, b) => a.path.localeCompare(b.path));
51
+ const routes = await scanAppRoutes(appRoot);
316
52
  if (routes.length === 0) throw new Error(`no page.* routes found under ${appDir} or .june/routes/`);
317
53
  const frozen = await freezeConfig(appRoot);
318
54
  if (frozen.i18n?.resolveLocale) console.warn("[june build] i18n.resolveLocale is not yet wired into the built worker (URL-pinned + built-in negotiation work; the hook runs in dev only).");
@@ -325,6 +61,24 @@ async function juneBuild(appRoot, options = {}) {
325
61
  } : void 0 },
326
62
  config: fullConfig
327
63
  });
64
+ const agentDir = join(appDir, frozen.agent.runtime.dir);
65
+ let agentModule = null;
66
+ if (frozen.agent.runtime.enabled) {
67
+ const generated = generateAgentModule(agentDir);
68
+ if (generated && adapter.capabilities.durableObjects) agentModule = generated;
69
+ else if (generated) console.warn(`[june build] app/${frozen.agent.runtime.dir}/ found, but the ${adapter.name}() target has no Durable Objects — the durable agent is not mounted.`);
70
+ }
71
+ if (agentModule) {
72
+ const sdkResolvable = (fromDir) => {
73
+ for (let d = resolve(fromDir);;) {
74
+ if (existsSync(join(d, "node_modules", "@anthropic-ai", "sdk", "package.json"))) return true;
75
+ const parent = dirname(d);
76
+ if (parent === d) return false;
77
+ d = parent;
78
+ }
79
+ };
80
+ if (!sdkResolvable(appRoot)) throw new Error(`app/${frozen.agent.runtime.dir}/ mounts a durable agent whose model is Claude — add the SDK to the app so it bundles for workerd: bun add @anthropic-ai/sdk`);
81
+ }
328
82
  const cssOut = await processCss(appDir, { minify: true });
329
83
  let cssAsset = null;
330
84
  if (cssOut !== null) {
@@ -405,7 +159,7 @@ async function juneBuild(appRoot, options = {}) {
405
159
  const layoutBoundariesField = boundaries.length ? `\n layoutBoundaries: {\n${boundaries.join("\n")}\n },` : "";
406
160
  const builtExtraFile = findMiddlewareFile(appDir);
407
161
  if (builtExtraFile) imports.push(`import extra from ${JSON.stringify(importPath(genDir, builtExtraFile))};`);
408
- const linkHeader = buildLinkHeader(frozen.agent);
162
+ const linkHeader = buildLinkHeader(frozen.agent, { catalogs: !frozen.document.basePath });
409
163
  const adapterEntry = adapter.entry({ linkHeader });
410
164
  const resourceFlags = {
411
165
  db: !!resourcesCfg?.db,
@@ -417,7 +171,8 @@ async function juneBuild(appRoot, options = {}) {
417
171
  imports.push(`import { turso } from "@junejs/server/db";`);
418
172
  imports.push(`import { memoizeResources } from "@junejs/server/resources";`);
419
173
  } else if (hasResources) imports.push(`import { bindWorkerResources } from "@junejs/server/resources";`);
420
- const resourcesField = tursoDb ? `\n resources: memoizeResources({ db: turso() }),` : hasResources ? `\n resources: bindWorkerResources(${JSON.stringify(resourceFlags)}),` : "";
174
+ const resourcesExpr = tursoDb ? `memoizeResources({ db: turso() })` : hasResources ? `bindWorkerResources(${JSON.stringify(resourceFlags)})` : null;
175
+ const resourcesField = resourcesExpr ? `\n resources: ${resourcesExpr},` : "";
421
176
  const dataLayerModule = fullConfig.dataLayer?.module;
422
177
  if (dataLayerModule) imports.push(`import { installDataLayer } from ${JSON.stringify(dataLayerModule)};`);
423
178
  const dataLayerBoot = dataLayerModule ? "\ninstallDataLayer();\n" : "";
@@ -427,10 +182,44 @@ async function juneBuild(appRoot, options = {}) {
427
182
  imports.push(`import { services as __appServices } from ${JSON.stringify(spec)};`);
428
183
  }
429
184
  const servicesField = servicesModule ? `\n services: __appServices,` : "";
185
+ if (agentModule) {
186
+ imports.push(`import __agentModule from ${JSON.stringify(importPath(genDir, agentModule.file))};`);
187
+ imports.push(`import { assembleDurable } from "@junejs/core/agent-config";`);
188
+ imports.push(`import { anthropic } from "@junejs/core/agent-models";`);
189
+ imports.push(`import { AgentDurableObject } from "@junejs/server/agent-durable";`);
190
+ imports.push(`import { DurableObject } from "cloudflare:workers";`);
191
+ imports.push(`import Anthropic from "@anthropic-ai/sdk";`);
192
+ }
193
+ const agentPreamble = agentModule ? `\nconst __agentDef = assembleDurable(__agentModule);\n` : "";
194
+ const agentNameField = agentModule ? `\n agentName: __agentModule.config.name,\n agentChannels: __agentDef.channels,` : "";
195
+ const doClass = agentModule ? `
196
+ // The durable agent: one Durable Object per session, the compiled agent/
197
+ // directory as its definition — adapted tools (+ read_skill when skills exist),
198
+ // the assembled system prompt, channel factories resolved with the DO's own
199
+ // env, and the app's declared resources opened from THIS isolate's env (lazily,
200
+ // at the first turn — the same ambient db a tool sees in native dev). Model:
201
+ // Anthropic over a statically bundled client (workerd cannot resolve a bare
202
+ // import at runtime), keyed by the ANTHROPIC_API_KEY secret — a missing secret
203
+ // surfaces as the SDK's own clear construction error on the first agent request.
204
+ export class JuneAgentDO extends DurableObject {
205
+ #agent = new AgentDurableObject(this.ctx, {
206
+ ...__agentDef,
207
+ model: anthropic({ model: __agentModule.config.model, client: new Anthropic({ apiKey: (this.env as { ANTHROPIC_API_KEY?: string }).ANTHROPIC_API_KEY }) }),
208
+ env: this.env,${resourcesExpr ? `\n resources: ${resourcesExpr},` : ""}${servicesModule ? "\n services: __appServices(this.env)," : ""}
209
+ });
210
+ fetch(req: Request): Promise<Response> {
211
+ return this.#agent.fetch(req);
212
+ }
213
+ // Delivers input announcements left undelivered — a failed hook's retry, or the watchdog (#260).
214
+ alarm(): Promise<void> {
215
+ return this.#agent.alarm();
216
+ }
217
+ }
218
+ ` : "";
430
219
  const entry = `// AUTO-GENERATED by \`june build\` — do not edit. Regenerate: june build .
431
220
  ${adapterEntry.imports.join("\n")}
432
221
  ${imports.join("\n")}
433
- ${dataLayerBoot}
222
+ ${dataLayerBoot}${agentPreamble}
434
223
  const pipeline = createWorker({
435
224
  routes: {
436
225
  ${statics.join("\n")}
@@ -445,15 +234,16 @@ ${chains.join("\n")}
445
234
  ${loadings.join("\n")}
446
235
  },
447
236
  document: ${JSON.stringify(frozen.document, null, 2).replace(/\n/g, "\n ")},
448
- agent: ${JSON.stringify(frozen.agent)},${frozen.i18n ? `\n i18n: ${JSON.stringify(frozen.i18n)},` : ""}
237
+ agent: ${JSON.stringify(frozen.agent)},${agentNameField}${frozen.i18n ? `\n i18n: ${JSON.stringify(frozen.i18n)},` : ""}
449
238
  earlyHints: ${JSON.stringify(frozen.earlyHints)},${builtExtraFile ? "\n extra," : ""}${resourcesField}${servicesField}
450
239
  });
451
240
 
452
241
  ${adapterEntry.wrap("pipeline")}
453
- `;
242
+ ${doClass}`;
454
243
  const entryFile = join(genDir, "worker-entry.tsx");
455
244
  await writeFile(entryFile, entry);
456
245
  const { rolldown } = await import("rolldown");
246
+ const binaryImports = /* @__PURE__ */ new Set();
457
247
  const bundle = await rolldown({
458
248
  input: entryFile,
459
249
  cwd: appRoot,
@@ -465,7 +255,12 @@ ${adapterEntry.wrap("pipeline")}
465
255
  plugins: [rolldownCssModulesPlugin(cssModuleMaps)],
466
256
  external: (id) => {
467
257
  if (isBunSpecifier(id)) return true;
468
- if (/\.(wasm|ttf|otf|woff2?|png|jpe?g|avif|webp)$/.test(id)) return true;
258
+ if (id.startsWith("cloudflare:")) return true;
259
+ const binary = /\.(wasm|ttf|otf|woff2?|png|jpe?g|avif|webp)$/i.exec(id);
260
+ if (binary) {
261
+ binaryImports.add(binary[1].toLowerCase());
262
+ return true;
263
+ }
469
264
  return [...adapter.buildExternal ?? [], ...options.external ?? frozen.buildExternal].some((e) => id === e || id.startsWith(`${e}/`));
470
265
  },
471
266
  resolve: { conditionNames: adapter.conditions }
@@ -483,7 +278,14 @@ ${adapterEntry.wrap("pipeline")}
483
278
  if (cssAsset) manifest.document.styles = `/${cssAsset}`;
484
279
  if (clientAsset) manifest.document.clientScript = `/${clientAsset}`;
485
280
  if (moduleCssAsset) manifest.document.moduleStyles = `/${moduleCssAsset}`;
486
- const worker = createWorker(manifest);
281
+ const isStatic = adapter.capabilities.runtime === "static";
282
+ if (isStatic) manifest.agent = {
283
+ ...manifest.agent,
284
+ mcp: false,
285
+ api: false,
286
+ webmcp: false
287
+ };
288
+ const worker = createWorker(manifest, { staticBuild: isStatic });
487
289
  let hasAssets = false;
488
290
  const publicDir = join(appRoot, "public");
489
291
  const publicFiles = [];
@@ -505,7 +307,20 @@ ${adapterEntry.wrap("pipeline")}
505
307
  }
506
308
  if (publicFiles.length) hasAssets = true;
507
309
  }
508
- const isStatic = adapter.capabilities.runtime === "static";
310
+ const site = frozen.document.site;
311
+ if (resolveIcons(site, publicFileCheck(publicDir)).generate) {
312
+ const icons = await renderIcons({
313
+ site,
314
+ fetchFont: googleFontFetcher(join(appRoot, "node_modules", ".cache", "june", "fonts")),
315
+ warn: (msg) => console.warn(msg)
316
+ });
317
+ await mkdir(assetsDir, { recursive: true });
318
+ for (const file of GENERATED_ICONS) {
319
+ await writeFile(join(assetsDir, file), icons[file]);
320
+ publicFiles.push(file);
321
+ }
322
+ hasAssets = true;
323
+ }
509
324
  const i18n = frozen.i18n;
510
325
  const prerenderOne = async (reqPath, def) => {
511
326
  const stem = reqPath === "/" ? "index" : reqPath.slice(1);
@@ -519,7 +334,7 @@ ${adapterEntry.wrap("pipeline")}
519
334
  if (def.md !== false) targets.push([mdReq, mdFile]);
520
335
  if (typeof def.json === "function") targets.push([jsonReq, jsonFile]);
521
336
  for (const [rp, file] of targets) {
522
- const res = await worker.fetch(new Request(`https://prerender.june${rp}`));
337
+ const res = await worker.fetch(new Request(`${PRERENDER_ORIGIN}${rp}`));
523
338
  if (!res.ok) throw new Error(`prerender ${rp} → ${res.status}`);
524
339
  const dest = join(assetsDir, file);
525
340
  await mkdir(dirname(dest), { recursive: true });
@@ -528,6 +343,10 @@ ${adapterEntry.wrap("pipeline")}
528
343
  prerendered.push(reqPath);
529
344
  hasAssets = true;
530
345
  };
346
+ if (isStatic && i18n) {
347
+ const onDomain = Object.keys(i18n.locales).filter((l) => i18n.locales[l].domain);
348
+ if (onDomain.length) throw new Error(`[june build] the static() target serves one host, so i18n locales with their own domain are not supported (${onDomain.join(", ")}). Give them a path prefix instead, e.g. { path: "/${onDomain[0]}" }.`);
349
+ }
531
350
  const localeVariants = (path) => isStatic && i18n ? [...new Set(Object.keys(i18n.locales).map((l) => localeHref(i18n, path, l)))] : [path];
532
351
  for (const r of routes.filter((x) => !x.dynamic)) {
533
352
  const def = manifest.routes[r.path];
@@ -540,19 +359,36 @@ ${adapterEntry.wrap("pipeline")}
540
359
  const sp = dyn.def.staticPaths;
541
360
  if (!sp) continue;
542
361
  const paths = typeof sp === "function" ? await sp() : sp;
362
+ dyn.def.staticPaths = paths;
543
363
  for (const p of paths) await prerenderOne(p, dyn.def);
544
364
  }
545
- for (const [reqPath, file] of [
365
+ const extra = [
546
366
  ["/favicon.svg", "favicon.svg"],
367
+ ["/manifest.webmanifest", "manifest.webmanifest"],
547
368
  ["/llms.txt", "llms.txt"],
548
369
  ["/sitemap.xml", "sitemap.xml"]
549
- ]) {
550
- const res = await worker.fetch(new Request(`https://prerender.june${reqPath}`));
370
+ ];
371
+ if (manifest.agent.discovery && !manifest.document.site.url && !manifest.document.deployOrigin) console.warn("[june build] no sitemap.xml: set site.url (or deploy.domain) in june.config.ts so its URLs are absolute.");
372
+ const doc = manifest.document;
373
+ if (manifest.agent.discovery && !doc.basePath && (doc.site.url || doc.deployOrigin)) extra.push(["/.well-known/ai-catalog.json", ".well-known/ai-catalog.json"], ["/.well-known/ard.json", ".well-known/ard.json"], ["/.well-known/agent-skills/index.json", ".well-known/agent-skills/index.json"]);
374
+ for (let i = 0; i < extra.length; i++) {
375
+ const [reqPath, file] = extra[i];
376
+ const res = await worker.fetch(new Request(`${PRERENDER_ORIGIN}${reqPath}`));
551
377
  if (!res.ok) continue;
552
- await writeFile(join(assetsDir, file), Buffer.from(await res.arrayBuffer()));
378
+ const bytes = Buffer.from(await res.arrayBuffer());
379
+ await mkdir(dirname(join(assetsDir, file)), { recursive: true });
380
+ await writeFile(join(assetsDir, file), bytes);
553
381
  hasAssets = true;
382
+ if (file.endsWith("agent-skills/index.json")) {
383
+ const index = JSON.parse(bytes.toString("utf8"));
384
+ for (const s of index.skills ?? []) {
385
+ if (!s.url) continue;
386
+ const p = new URL(s.url, PRERENDER_ORIGIN).pathname;
387
+ extra.push([p, p.slice(1)]);
388
+ }
389
+ }
554
390
  }
555
- const nf = await worker.fetch(new Request("https://prerender.june/__june_not_found__"));
391
+ const nf = await worker.fetch(new Request(`${PRERENDER_ORIGIN}/__june_not_found__`));
556
392
  await writeFile(join(assetsDir, "404.html"), Buffer.from(await nf.arrayBuffer()));
557
393
  hasAssets = true;
558
394
  }
@@ -570,11 +406,18 @@ ${adapterEntry.wrap("pipeline")}
570
406
  hasAssets = true;
571
407
  }
572
408
  const pkgPath = join(appRoot, "package.json");
573
- const defaultName = workerName((existsSync(pkgPath) ? JSON.parse(await Bun.file(pkgPath).text()).name : void 0) ?? basename(appRoot));
574
- const plan = resourcesCfg?.db && resourcesCfg.db.kind !== "turso" ? { db: {
575
- binding: "DB",
576
- databaseName: `${defaultName}-db`
577
- } } : {};
409
+ const pkgName = existsSync(pkgPath) ? JSON.parse(await Bun.file(pkgPath).text()).name : void 0;
410
+ const defaultName = workerName(pkgName ?? basename(appRoot));
411
+ const plan = {
412
+ ...resourcesCfg?.db && resourcesCfg.db.kind !== "turso" ? { db: {
413
+ binding: "DB",
414
+ databaseName: `${defaultName}-db`
415
+ } } : {},
416
+ ...agentModule ? { agent: {
417
+ binding: "AGENT",
418
+ className: "JuneAgentDO"
419
+ } } : {}
420
+ };
578
421
  await adapter.emit({
579
422
  appRoot,
580
423
  outDir,
@@ -583,9 +426,11 @@ ${adapterEntry.wrap("pipeline")}
583
426
  config: fullConfig,
584
427
  plan,
585
428
  defaultName,
586
- publicFiles
429
+ publicFiles,
430
+ binaryImports: [...binaryImports].sort()
587
431
  });
588
432
  if (plan.db) console.log(` ↳ d1 binding "${plan.db.binding}" emitted — set database_id in wrangler.jsonc (wrangler d1 create ${plan.db.databaseName})`);
433
+ if (plan.agent) console.log(` ↳ durable agent mounted (${plan.agent.className} → env.${plan.agent.binding}; chat at ${frozen.agent.runtime.chat.path})`);
589
434
  return {
590
435
  outFile,
591
436
  routes: routes.filter((r) => !r.dynamic).map((r) => r.path),
@@ -595,4 +440,4 @@ ${adapterEntry.wrap("pipeline")}
595
440
  };
596
441
  }
597
442
  //#endregion
598
- export { buildManifest, freezeConfig, generateContent, isBunSpecifier, juneBuild, normalizeBase, resolveDeployAdapter, scanRoutes, workerName };
443
+ export { buildManifest, freezeConfig, generateContent, isBunSpecifier, juneBuild, normalizeBase, resolveDeployAdapter, scanAppRoutes, scanRoutes, workerName };
@@ -1,15 +1,14 @@
1
1
  import { ModuleMaps } from "./css-modules.js";
2
2
  //#region src/client-bundle.d.ts
3
- declare const CLIENT_SCRIPT_URL = "/_june/client.js";
4
- declare function findClientEntry(appDir: string): string | undefined;
3
+ export declare const CLIENT_SCRIPT_URL = "/_june/client.js";
4
+ export declare function findClientEntry(appDir: string): string | undefined;
5
5
  type BundleMode = "development" | "production";
6
- declare function isExpectedClientLog(log: {
6
+ export declare function isExpectedClientLog(log: {
7
7
  code?: string;
8
8
  exporter?: string;
9
9
  }): boolean;
10
- type ClientChunks = Map<string, string>;
11
- declare function bundleClientSplit(entryFile: string, cwd: string, mode: BundleMode, maps?: ModuleMaps): Promise<ClientChunks>;
12
- declare function bundleClientToString(entryFile: string, cwd: string, maps?: ModuleMaps): Promise<string>;
13
- declare function bundleClientToFile(entryFile: string, cwd: string, destDir: string, maps?: ModuleMaps): Promise<string>;
14
- //#endregion
15
- export { CLIENT_SCRIPT_URL, ClientChunks, bundleClientSplit, bundleClientToFile, bundleClientToString, findClientEntry, isExpectedClientLog };
10
+ export type ClientChunks = Map<string, string>;
11
+ export declare function bundleClientSplit(entryFile: string, cwd: string, mode: BundleMode, maps?: ModuleMaps): Promise<ClientChunks>;
12
+ export declare function bundleClientToString(entryFile: string, cwd: string, maps?: ModuleMaps): Promise<string>;
13
+ export declare function bundleClientToFile(entryFile: string, cwd: string, destDir: string, maps?: ModuleMaps): Promise<string>;
14
+ //#endregion
@@ -1,5 +1,5 @@
1
- import { rolldownCssModulesPlugin } from "./css-modules.js";
2
1
  import { jsxTransform } from "./tsconfig-jsx.js";
2
+ import { rolldownCssModulesPlugin } from "./css-modules.js";
3
3
  import { existsSync } from "node:fs";
4
4
  import { mkdir, writeFile } from "node:fs/promises";
5
5
  import { dirname, join } from "node:path";
@@ -0,0 +1,17 @@
1
+ import { i as JuneAdapter } from "./adapter-D0UnYBuN.js";
2
+ import { n as WorkerManifest } from "./worker-2qbQjj2c.js";
3
+ import { JuneConfig } from "@junejs/core/config";
4
+ import { DocumentConfig } from "@junejs/core/document";
5
+ //#region src/config-freeze.d.ts
6
+ declare function resolveDeployAdapter(deploy: JuneConfig["deploy"]): JuneAdapter;
7
+ declare function freezeConfig(appRoot: string): Promise<{
8
+ document: DocumentConfig;
9
+ agent: WorkerManifest["agent"];
10
+ i18n: WorkerManifest["i18n"];
11
+ earlyHints: string[];
12
+ buildExternal: string[];
13
+ }>;
14
+ declare function normalizeBase(base?: string): string;
15
+ declare function workerName(raw: string): string;
16
+ //#endregion
17
+ export { workerName as i, normalizeBase as n, resolveDeployAdapter as r, freezeConfig as t };
@@ -0,0 +1,2 @@
1
+ import { i as workerName, n as normalizeBase, r as resolveDeployAdapter, t as freezeConfig } from "./config-freeze-r5p-vTWv.js";
2
+ export { freezeConfig, normalizeBase, resolveDeployAdapter, workerName };