@junejs/server 0.1.2 → 0.2.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 (130) hide show
  1. package/assets/icon-latin.LICENSE.txt +92 -0
  2. package/assets/icon-latin.ttf +0 -0
  3. package/dist/adapter-DcZ-W1-7.d.ts +62 -0
  4. package/dist/adapter.d.ts +2 -56
  5. package/dist/adapter.js +62 -5
  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/blob.d.ts +4 -5
  17. package/dist/build.d.ts +8 -29
  18. package/dist/build.js +138 -289
  19. package/dist/client-bundle.d.ts +8 -9
  20. package/dist/client-bundle.js +1 -1
  21. package/dist/config-freeze-CyXvNqi2.d.ts +17 -0
  22. package/dist/config-freeze.d.ts +2 -0
  23. package/dist/config-freeze.js +54 -0
  24. package/dist/config-loader.d.ts +3 -4
  25. package/dist/connection-auth.d.ts +38 -0
  26. package/dist/connection-auth.js +31 -0
  27. package/dist/content-freeze-CyiW2fRK.d.ts +4 -0
  28. package/dist/content-freeze.d.ts +2 -0
  29. package/dist/content-freeze.js +83 -0
  30. package/dist/content.d.ts +22 -9
  31. package/dist/content.js +43 -3
  32. package/dist/core-version.d.ts +4 -0
  33. package/dist/core-version.js +12 -0
  34. package/dist/css-modules-ambient.d.ts +2 -1
  35. package/dist/css-modules.d.ts +10 -11
  36. package/dist/css.d.ts +9 -10
  37. package/dist/d1-migrate.d.ts +6 -7
  38. package/dist/d1-migrate.js +3 -2
  39. package/dist/db.d.ts +2 -2
  40. package/dist/deploy.d.ts +3 -4
  41. package/dist/deploy.js +3 -2
  42. package/dist/dev-reload.d.ts +3 -4
  43. package/dist/dev.d.ts +8 -5
  44. package/dist/dev.js +40 -9
  45. package/dist/favicon.d.ts +37 -0
  46. package/dist/favicon.js +248 -0
  47. package/dist/host.d.ts +6 -5
  48. package/dist/host.js +2 -1
  49. package/dist/icon-letter.d.ts +3 -0
  50. package/dist/icon-letter.js +8 -0
  51. package/dist/index.d.ts +11 -5
  52. package/dist/index.js +9 -3
  53. package/dist/instrumentation.d.ts +2 -3
  54. package/dist/instrumentation.js +2 -1
  55. package/dist/island-registry.d.ts +6 -7
  56. package/dist/isolate-local.d.ts +5 -0
  57. package/dist/isolate-local.js +12 -0
  58. package/dist/kv.d.ts +3 -4
  59. package/dist/llms-links.d.ts +9 -0
  60. package/dist/llms-links.js +65 -0
  61. package/dist/manifest-CwTT1zVs.d.ts +11 -0
  62. package/dist/manifest.d.ts +2 -0
  63. package/dist/manifest.js +113 -0
  64. package/dist/negotiate.d.ts +4 -3
  65. package/dist/negotiate.js +24 -14
  66. package/dist/{pipeline-CCp9idQ4.d.ts → pipeline-BHUjBO0G.d.ts} +13 -1
  67. package/dist/pipeline.d.ts +2 -2
  68. package/dist/pipeline.js +286 -35
  69. package/dist/resources.d.ts +5 -6
  70. package/dist/route-rank.d.ts +10 -0
  71. package/dist/route-rank.js +38 -0
  72. package/dist/route-scan-BMbBzPIB.d.ts +20 -0
  73. package/dist/route-scan.d.ts +2 -0
  74. package/dist/route-scan.js +100 -0
  75. package/dist/router.d.ts +12 -13
  76. package/dist/router.js +58 -44
  77. package/dist/rsc-build.d.ts +6 -7
  78. package/dist/rsc-bundle.d.ts +6 -7
  79. package/dist/rsc-manifest.d.ts +5 -6
  80. package/dist/rsc-runtime/flight-render-routes.d.ts +3 -4
  81. package/dist/rsc-runtime/flight-render.d.ts +2 -3
  82. package/dist/rsc-runtime/flight-to-html.d.ts +2 -3
  83. package/dist/rsc-runtime/flight-to-html.js +3 -2
  84. package/dist/rsc-runtime/rsc-worker.js +11 -8
  85. package/dist/rsc-runtime/rsdw-shims.d.ts +2 -1
  86. package/dist/segment.d.ts +4 -5
  87. package/dist/sqlite-driver.d.ts +11 -11
  88. package/dist/sqlite-driver.js +17 -4
  89. package/dist/static-files.d.ts +4 -5
  90. package/dist/tsconfig-jsx.d.ts +4 -4
  91. package/dist/tsconfig-jsx.js +1 -1
  92. package/dist/turn-events.d.ts +4 -0
  93. package/dist/turn-events.js +46 -0
  94. package/dist/web-manifest.d.ts +5 -0
  95. package/dist/web-manifest.js +42 -0
  96. package/dist/worker-2qbQjj2c.d.ts +64 -0
  97. package/dist/worker.d.ts +2 -56
  98. package/dist/worker.js +121 -103
  99. package/package.json +22 -9
  100. package/src/adapter.ts +84 -3
  101. package/src/agent-compile.ts +271 -0
  102. package/src/agent-discover.ts +77 -63
  103. package/src/agent-durable.ts +998 -30
  104. package/src/agent-native.ts +370 -35
  105. package/src/app.ts +75 -6
  106. package/src/build.ts +237 -444
  107. package/src/config-freeze.ts +109 -0
  108. package/src/connection-auth.ts +101 -0
  109. package/src/content-freeze.ts +151 -0
  110. package/src/content.ts +55 -4
  111. package/src/core-version.ts +34 -0
  112. package/src/dev.ts +41 -8
  113. package/src/favicon.ts +325 -0
  114. package/src/host.ts +4 -3
  115. package/src/icon-letter.ts +14 -0
  116. package/src/index.ts +22 -0
  117. package/src/isolate-local.ts +33 -0
  118. package/src/llms-links.ts +96 -0
  119. package/src/manifest.ts +130 -0
  120. package/src/negotiate.ts +39 -15
  121. package/src/pipeline.ts +494 -44
  122. package/src/route-rank.ts +60 -0
  123. package/src/route-scan.ts +161 -0
  124. package/src/router.ts +75 -58
  125. package/src/rsc-runtime/rsc-worker.tsx +5 -4
  126. package/src/sqlite-driver.ts +36 -6
  127. package/src/tsconfig-jsx.ts +2 -2
  128. package/src/turn-events.ts +43 -0
  129. package/src/web-manifest.ts +38 -0
  130. package/src/worker.ts +197 -117
package/dist/build.d.ts CHANGED
@@ -1,40 +1,19 @@
1
- import { JuneAdapter } from "./adapter.js";
2
- import { WorkerManifest } from "./worker.js";
3
- import { JuneConfig } from "@junejs/core/config";
4
- import { DocumentConfig } from "@junejs/core/document";
1
+ import { a as scanAppRoutes, o as scanRoutes, t as RouteEntry } from "./route-scan-BMbBzPIB.js";
2
+ import { t as generateContent } from "./content-freeze-CyiW2fRK.js";
3
+ import { i as workerName, n as normalizeBase, r as resolveDeployAdapter, t as freezeConfig } from "./config-freeze-CyXvNqi2.js";
4
+ import { n as buildManifest } from "./manifest-CwTT1zVs.js";
5
5
  //#region src/build.d.ts
6
- type BuildResult = {
6
+ export type BuildResult = {
7
7
  outFile: string;
8
8
  routes: string[];
9
9
  dynamicRoutes: string[];
10
10
  contentCollections: string[];
11
11
  prerendered: string[];
12
12
  };
13
- type RouteEntry = {
14
- path: string;
15
- file: string;
16
- dynamic: boolean;
17
- resource?: boolean;
18
- layouts: string[];
19
- loading?: string;
20
- };
21
- declare const isBunSpecifier: (id: string) => boolean;
22
- declare function resolveDeployAdapter(deploy: JuneConfig["deploy"]): JuneAdapter;
23
- declare function scanRoutes(appDir: string, dir?: string, layouts?: string[], out?: RouteEntry[], loading?: string): Promise<RouteEntry[]>;
24
- declare function generateContent(appRoot: string): Promise<string[]>;
25
- declare function freezeConfig(appRoot: string): Promise<{
26
- document: DocumentConfig;
27
- agent: WorkerManifest["agent"];
28
- i18n: WorkerManifest["i18n"];
29
- earlyHints: string[];
30
- buildExternal: string[];
31
- }>;
32
- declare function normalizeBase(base?: string): string;
33
- declare function workerName(raw: string): string;
34
- declare function buildManifest(appRoot: string): Promise<WorkerManifest>;
35
- declare function juneBuild(appRoot: string, options?: {
13
+ export declare const isBunSpecifier: (id: string) => boolean;
14
+ export declare function juneBuild(appRoot: string, options?: {
36
15
  outDir?: string;
37
16
  external?: string[];
38
17
  }): Promise<BuildResult>;
39
18
  //#endregion
40
- export { BuildResult, buildManifest, freezeConfig, generateContent, isBunSpecifier, juneBuild, normalizeBase, resolveDeployAdapter, scanRoutes, workerName };
19
+ export { type RouteEntry, buildManifest, freezeConfig, generateContent, normalizeBase, resolveDeployAdapter, scanAppRoutes, scanRoutes, workerName };
package/dist/build.js CHANGED
@@ -1,281 +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))].sort((a, b) => a.path.localeCompare(b.path));
197
- const layoutCache = /* @__PURE__ */ new Map();
198
- const loadCached = async (f) => {
199
- if (!layoutCache.has(f)) layoutCache.set(f, await importLayout(f));
200
- return layoutCache.get(f) ?? null;
201
- };
202
- const componentsFor = async (files) => {
203
- const items = [];
204
- for (const f of files) {
205
- const c = await loadCached(f);
206
- items.push({
207
- file: f,
208
- entry: c?.component ?? null,
209
- boundary: !!c?.boundary
210
- });
211
- }
212
- return resolveBoundary(items);
213
- };
214
- const loadingCache = /* @__PURE__ */ new Map();
215
- const loadingFor = async (file) => {
216
- if (!file) return void 0;
217
- if (!loadingCache.has(file)) {
218
- const loaded = await importLayout(file);
219
- loadingCache.set(file, loaded ? loaded.component : null);
220
- }
221
- return loadingCache.get(file) ?? void 0;
222
- };
223
- const routes = {};
224
- const dynamicRoutes = [];
225
- const resourceRoutes = [];
226
- const layoutChains = {};
227
- const layoutBoundaries = {};
228
- const loadings = {};
229
- for (const r of scanned) {
230
- const mod = await import(pathToFileURL(r.file).href);
231
- if (r.resource) {
232
- const handler = mod.default;
233
- if (typeof handler === "function") resourceRoutes.push({
234
- pattern: r.path,
235
- handler
236
- });
237
- continue;
238
- }
239
- const def = routeFromModule(mod);
240
- if (!def) continue;
241
- const { chain, boundaryIndex, key } = await componentsFor(r.layouts);
242
- const loading = await loadingFor(r.loading);
243
- if (r.dynamic) {
244
- dynamicRoutes.push({
245
- pattern: r.path,
246
- def
247
- });
248
- layoutChains[r.path] = chain;
249
- } else {
250
- routes[r.path] = def;
251
- layoutChains[r.path] = chain;
252
- }
253
- if (boundaryIndex !== null && key !== null) layoutBoundaries[r.path] = {
254
- index: boundaryIndex,
255
- key
256
- };
257
- if (loading) loadings[r.path] = loading;
258
- }
259
- let extra;
260
- const extraFile = findMiddlewareFile(appDir);
261
- if (extraFile) {
262
- const mod = await import(pathToFileURL(extraFile).href);
263
- if (typeof mod.default === "function") extra = mod.default;
264
- }
265
- return {
266
- routes,
267
- dynamicRoutes,
268
- resourceRoutes,
269
- layoutChains,
270
- layoutBoundaries,
271
- loadings,
272
- document: frozen.document,
273
- agent: frozen.agent,
274
- i18n: frozen.i18n,
275
- earlyHints: frozen.earlyHints,
276
- extra
277
- };
278
- }
279
27
  function importPath(fromDir, file) {
280
28
  const p = relative(fromDir, file).split(sep).join("/").replace(/\.[^.]+$/, "");
281
29
  return p.startsWith(".") ? p : `./${p}`;
@@ -300,11 +48,7 @@ async function juneBuild(appRoot, options = {}) {
300
48
  force: true
301
49
  });
302
50
  const contentCollections = await generateContent(appRoot);
303
- const juneRoutesDir2 = join(appRoot, ".june", "routes");
304
- const appRoutes2 = await scanRoutes(appDir);
305
- const frameworkRoutes2 = existsSync(juneRoutesDir2) ? await scanRoutes(juneRoutesDir2) : [];
306
- const appPaths2 = new Set(appRoutes2.map((r) => r.path));
307
- const routes = [...appRoutes2, ...frameworkRoutes2.filter((r) => !appPaths2.has(r.path))].sort((a, b) => a.path.localeCompare(b.path));
51
+ const routes = await scanAppRoutes(appRoot);
308
52
  if (routes.length === 0) throw new Error(`no page.* routes found under ${appDir} or .june/routes/`);
309
53
  const frozen = await freezeConfig(appRoot);
310
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).");
@@ -317,6 +61,24 @@ async function juneBuild(appRoot, options = {}) {
317
61
  } : void 0 },
318
62
  config: fullConfig
319
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
+ }
320
82
  const cssOut = await processCss(appDir, { minify: true });
321
83
  let cssAsset = null;
322
84
  if (cssOut !== null) {
@@ -392,10 +154,12 @@ async function juneBuild(appRoot, options = {}) {
392
154
  if (r.loading) loadings.push(` ${JSON.stringify(r.path)}: ${loadingId(r.loading)},`);
393
155
  });
394
156
  const resourceRoutesField = resources.length ? `\n resourceRoutes: [\n${resources.join("\n")}\n ],` : "";
157
+ const generatedPaths = routes.filter((r) => r.generated).map((r) => r.path);
158
+ const generatedRoutesField = generatedPaths.length ? `\n generatedRoutes: ${JSON.stringify(generatedPaths)},` : "";
395
159
  const layoutBoundariesField = boundaries.length ? `\n layoutBoundaries: {\n${boundaries.join("\n")}\n },` : "";
396
160
  const builtExtraFile = findMiddlewareFile(appDir);
397
161
  if (builtExtraFile) imports.push(`import extra from ${JSON.stringify(importPath(genDir, builtExtraFile))};`);
398
- const linkHeader = buildLinkHeader(frozen.agent);
162
+ const linkHeader = buildLinkHeader(frozen.agent, { catalogs: !frozen.document.basePath });
399
163
  const adapterEntry = adapter.entry({ linkHeader });
400
164
  const resourceFlags = {
401
165
  db: !!resourcesCfg?.db,
@@ -407,7 +171,8 @@ async function juneBuild(appRoot, options = {}) {
407
171
  imports.push(`import { turso } from "@junejs/server/db";`);
408
172
  imports.push(`import { memoizeResources } from "@junejs/server/resources";`);
409
173
  } else if (hasResources) imports.push(`import { bindWorkerResources } from "@junejs/server/resources";`);
410
- 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},` : "";
411
176
  const dataLayerModule = fullConfig.dataLayer?.module;
412
177
  if (dataLayerModule) imports.push(`import { installDataLayer } from ${JSON.stringify(dataLayerModule)};`);
413
178
  const dataLayerBoot = dataLayerModule ? "\ninstallDataLayer();\n" : "";
@@ -417,17 +182,51 @@ async function juneBuild(appRoot, options = {}) {
417
182
  imports.push(`import { services as __appServices } from ${JSON.stringify(spec)};`);
418
183
  }
419
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
+ ` : "";
420
219
  const entry = `// AUTO-GENERATED by \`june build\` — do not edit. Regenerate: june build .
421
220
  ${adapterEntry.imports.join("\n")}
422
221
  ${imports.join("\n")}
423
- ${dataLayerBoot}
222
+ ${dataLayerBoot}${agentPreamble}
424
223
  const pipeline = createWorker({
425
224
  routes: {
426
225
  ${statics.join("\n")}
427
226
  },
428
227
  dynamicRoutes: [
429
228
  ${dynamics.join("\n")}
430
- ],${resourceRoutesField}
229
+ ],${resourceRoutesField}${generatedRoutesField}
431
230
  layoutChains: {
432
231
  ${chains.join("\n")}
433
232
  },${layoutBoundariesField}
@@ -435,12 +234,12 @@ ${chains.join("\n")}
435
234
  ${loadings.join("\n")}
436
235
  },
437
236
  document: ${JSON.stringify(frozen.document, null, 2).replace(/\n/g, "\n ")},
438
- 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)},` : ""}
439
238
  earlyHints: ${JSON.stringify(frozen.earlyHints)},${builtExtraFile ? "\n extra," : ""}${resourcesField}${servicesField}
440
239
  });
441
240
 
442
241
  ${adapterEntry.wrap("pipeline")}
443
- `;
242
+ ${doClass}`;
444
243
  const entryFile = join(genDir, "worker-entry.tsx");
445
244
  await writeFile(entryFile, entry);
446
245
  const { rolldown } = await import("rolldown");
@@ -455,6 +254,7 @@ ${adapterEntry.wrap("pipeline")}
455
254
  plugins: [rolldownCssModulesPlugin(cssModuleMaps)],
456
255
  external: (id) => {
457
256
  if (isBunSpecifier(id)) return true;
257
+ if (id.startsWith("cloudflare:")) return true;
458
258
  if (/\.(wasm|ttf|otf|woff2?|png|jpe?g|avif|webp)$/.test(id)) return true;
459
259
  return [...adapter.buildExternal ?? [], ...options.external ?? frozen.buildExternal].some((e) => id === e || id.startsWith(`${e}/`));
460
260
  },
@@ -473,7 +273,14 @@ ${adapterEntry.wrap("pipeline")}
473
273
  if (cssAsset) manifest.document.styles = `/${cssAsset}`;
474
274
  if (clientAsset) manifest.document.clientScript = `/${clientAsset}`;
475
275
  if (moduleCssAsset) manifest.document.moduleStyles = `/${moduleCssAsset}`;
476
- const worker = createWorker(manifest);
276
+ const isStatic = adapter.capabilities.runtime === "static";
277
+ if (isStatic) manifest.agent = {
278
+ ...manifest.agent,
279
+ mcp: false,
280
+ api: false,
281
+ webmcp: false
282
+ };
283
+ const worker = createWorker(manifest, { staticBuild: isStatic });
477
284
  let hasAssets = false;
478
285
  const publicDir = join(appRoot, "public");
479
286
  const publicFiles = [];
@@ -495,7 +302,20 @@ ${adapterEntry.wrap("pipeline")}
495
302
  }
496
303
  if (publicFiles.length) hasAssets = true;
497
304
  }
498
- const isStatic = adapter.capabilities.runtime === "static";
305
+ const site = frozen.document.site;
306
+ if (resolveIcons(site, publicFileCheck(publicDir)).generate) {
307
+ const icons = await renderIcons({
308
+ site,
309
+ fetchFont: googleFontFetcher(join(appRoot, "node_modules", ".cache", "june", "fonts")),
310
+ warn: (msg) => console.warn(msg)
311
+ });
312
+ await mkdir(assetsDir, { recursive: true });
313
+ for (const file of GENERATED_ICONS) {
314
+ await writeFile(join(assetsDir, file), icons[file]);
315
+ publicFiles.push(file);
316
+ }
317
+ hasAssets = true;
318
+ }
499
319
  const i18n = frozen.i18n;
500
320
  const prerenderOne = async (reqPath, def) => {
501
321
  const stem = reqPath === "/" ? "index" : reqPath.slice(1);
@@ -509,7 +329,7 @@ ${adapterEntry.wrap("pipeline")}
509
329
  if (def.md !== false) targets.push([mdReq, mdFile]);
510
330
  if (typeof def.json === "function") targets.push([jsonReq, jsonFile]);
511
331
  for (const [rp, file] of targets) {
512
- const res = await worker.fetch(new Request(`https://prerender.june${rp}`));
332
+ const res = await worker.fetch(new Request(`${PRERENDER_ORIGIN}${rp}`));
513
333
  if (!res.ok) throw new Error(`prerender ${rp} → ${res.status}`);
514
334
  const dest = join(assetsDir, file);
515
335
  await mkdir(dirname(dest), { recursive: true });
@@ -518,6 +338,10 @@ ${adapterEntry.wrap("pipeline")}
518
338
  prerendered.push(reqPath);
519
339
  hasAssets = true;
520
340
  };
341
+ if (isStatic && i18n) {
342
+ const onDomain = Object.keys(i18n.locales).filter((l) => i18n.locales[l].domain);
343
+ 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]}" }.`);
344
+ }
521
345
  const localeVariants = (path) => isStatic && i18n ? [...new Set(Object.keys(i18n.locales).map((l) => localeHref(i18n, path, l)))] : [path];
522
346
  for (const r of routes.filter((x) => !x.dynamic)) {
523
347
  const def = manifest.routes[r.path];
@@ -530,19 +354,36 @@ ${adapterEntry.wrap("pipeline")}
530
354
  const sp = dyn.def.staticPaths;
531
355
  if (!sp) continue;
532
356
  const paths = typeof sp === "function" ? await sp() : sp;
357
+ dyn.def.staticPaths = paths;
533
358
  for (const p of paths) await prerenderOne(p, dyn.def);
534
359
  }
535
- for (const [reqPath, file] of [
360
+ const extra = [
536
361
  ["/favicon.svg", "favicon.svg"],
362
+ ["/manifest.webmanifest", "manifest.webmanifest"],
537
363
  ["/llms.txt", "llms.txt"],
538
364
  ["/sitemap.xml", "sitemap.xml"]
539
- ]) {
540
- const res = await worker.fetch(new Request(`https://prerender.june${reqPath}`));
365
+ ];
366
+ 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.");
367
+ const doc = manifest.document;
368
+ 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"]);
369
+ for (let i = 0; i < extra.length; i++) {
370
+ const [reqPath, file] = extra[i];
371
+ const res = await worker.fetch(new Request(`${PRERENDER_ORIGIN}${reqPath}`));
541
372
  if (!res.ok) continue;
542
- await writeFile(join(assetsDir, file), Buffer.from(await res.arrayBuffer()));
373
+ const bytes = Buffer.from(await res.arrayBuffer());
374
+ await mkdir(dirname(join(assetsDir, file)), { recursive: true });
375
+ await writeFile(join(assetsDir, file), bytes);
543
376
  hasAssets = true;
377
+ if (file.endsWith("agent-skills/index.json")) {
378
+ const index = JSON.parse(bytes.toString("utf8"));
379
+ for (const s of index.skills ?? []) {
380
+ if (!s.url) continue;
381
+ const p = new URL(s.url, PRERENDER_ORIGIN).pathname;
382
+ extra.push([p, p.slice(1)]);
383
+ }
384
+ }
544
385
  }
545
- const nf = await worker.fetch(new Request("https://prerender.june/__june_not_found__"));
386
+ const nf = await worker.fetch(new Request(`${PRERENDER_ORIGIN}/__june_not_found__`));
546
387
  await writeFile(join(assetsDir, "404.html"), Buffer.from(await nf.arrayBuffer()));
547
388
  hasAssets = true;
548
389
  }
@@ -560,11 +401,18 @@ ${adapterEntry.wrap("pipeline")}
560
401
  hasAssets = true;
561
402
  }
562
403
  const pkgPath = join(appRoot, "package.json");
563
- const defaultName = workerName((existsSync(pkgPath) ? JSON.parse(await Bun.file(pkgPath).text()).name : void 0) ?? basename(appRoot));
564
- const plan = resourcesCfg?.db && resourcesCfg.db.kind !== "turso" ? { db: {
565
- binding: "DB",
566
- databaseName: `${defaultName}-db`
567
- } } : {};
404
+ const pkgName = existsSync(pkgPath) ? JSON.parse(await Bun.file(pkgPath).text()).name : void 0;
405
+ const defaultName = workerName(pkgName ?? basename(appRoot));
406
+ const plan = {
407
+ ...resourcesCfg?.db && resourcesCfg.db.kind !== "turso" ? { db: {
408
+ binding: "DB",
409
+ databaseName: `${defaultName}-db`
410
+ } } : {},
411
+ ...agentModule ? { agent: {
412
+ binding: "AGENT",
413
+ className: "JuneAgentDO"
414
+ } } : {}
415
+ };
568
416
  await adapter.emit({
569
417
  appRoot,
570
418
  outDir,
@@ -576,6 +424,7 @@ ${adapterEntry.wrap("pipeline")}
576
424
  publicFiles
577
425
  });
578
426
  if (plan.db) console.log(` ↳ d1 binding "${plan.db.binding}" emitted — set database_id in wrangler.jsonc (wrangler d1 create ${plan.db.databaseName})`);
427
+ if (plan.agent) console.log(` ↳ durable agent mounted (${plan.agent.className} → env.${plan.agent.binding}; chat at ${frozen.agent.runtime.chat.path})`);
579
428
  return {
580
429
  outFile,
581
430
  routes: routes.filter((r) => !r.dynamic).map((r) => r.path),
@@ -585,4 +434,4 @@ ${adapterEntry.wrap("pipeline")}
585
434
  };
586
435
  }
587
436
  //#endregion
588
- export { buildManifest, freezeConfig, generateContent, isBunSpecifier, juneBuild, normalizeBase, resolveDeployAdapter, scanRoutes, workerName };
437
+ 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-DcZ-W1-7.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-CyXvNqi2.js";
2
+ export { freezeConfig, normalizeBase, resolveDeployAdapter, workerName };