@junejs/server 0.1.3 → 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 (128) 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 -30
  18. package/dist/build.js +135 -296
  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 +6 -7
  71. package/dist/route-scan-BMbBzPIB.d.ts +20 -0
  72. package/dist/route-scan.d.ts +2 -0
  73. package/dist/route-scan.js +100 -0
  74. package/dist/router.d.ts +12 -13
  75. package/dist/router.js +51 -38
  76. package/dist/rsc-build.d.ts +6 -7
  77. package/dist/rsc-bundle.d.ts +6 -7
  78. package/dist/rsc-manifest.d.ts +5 -6
  79. package/dist/rsc-runtime/flight-render-routes.d.ts +3 -4
  80. package/dist/rsc-runtime/flight-render.d.ts +2 -3
  81. package/dist/rsc-runtime/flight-to-html.d.ts +2 -3
  82. package/dist/rsc-runtime/flight-to-html.js +3 -2
  83. package/dist/rsc-runtime/rsc-worker.js +11 -8
  84. package/dist/rsc-runtime/rsdw-shims.d.ts +2 -1
  85. package/dist/segment.d.ts +4 -5
  86. package/dist/sqlite-driver.d.ts +11 -11
  87. package/dist/sqlite-driver.js +17 -4
  88. package/dist/static-files.d.ts +4 -5
  89. package/dist/tsconfig-jsx.d.ts +4 -4
  90. package/dist/tsconfig-jsx.js +1 -1
  91. package/dist/turn-events.d.ts +4 -0
  92. package/dist/turn-events.js +46 -0
  93. package/dist/web-manifest.d.ts +5 -0
  94. package/dist/web-manifest.js +42 -0
  95. package/dist/worker-2qbQjj2c.d.ts +64 -0
  96. package/dist/worker.d.ts +2 -57
  97. package/dist/worker.js +69 -27
  98. package/package.json +22 -9
  99. package/src/adapter.ts +84 -3
  100. package/src/agent-compile.ts +271 -0
  101. package/src/agent-discover.ts +77 -63
  102. package/src/agent-durable.ts +998 -30
  103. package/src/agent-native.ts +370 -35
  104. package/src/app.ts +75 -6
  105. package/src/build.ts +230 -446
  106. package/src/config-freeze.ts +109 -0
  107. package/src/connection-auth.ts +101 -0
  108. package/src/content-freeze.ts +151 -0
  109. package/src/content.ts +55 -4
  110. package/src/core-version.ts +34 -0
  111. package/src/dev.ts +41 -8
  112. package/src/favicon.ts +325 -0
  113. package/src/host.ts +4 -3
  114. package/src/icon-letter.ts +14 -0
  115. package/src/index.ts +22 -0
  116. package/src/isolate-local.ts +33 -0
  117. package/src/llms-links.ts +96 -0
  118. package/src/manifest.ts +130 -0
  119. package/src/negotiate.ts +39 -15
  120. package/src/pipeline.ts +494 -44
  121. package/src/route-scan.ts +161 -0
  122. package/src/router.ts +66 -54
  123. package/src/rsc-runtime/rsc-worker.tsx +5 -4
  124. package/src/sqlite-driver.ts +36 -6
  125. package/src/tsconfig-jsx.ts +2 -2
  126. package/src/turn-events.ts +43 -0
  127. package/src/web-manifest.ts +38 -0
  128. package/src/worker.ts +131 -35
package/dist/build.d.ts CHANGED
@@ -1,41 +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
- generated?: boolean;
19
- layouts: string[];
20
- loading?: string;
21
- };
22
- declare const isBunSpecifier: (id: string) => boolean;
23
- declare function resolveDeployAdapter(deploy: JuneConfig["deploy"]): JuneAdapter;
24
- declare function scanRoutes(appDir: string, dir?: string, layouts?: string[], out?: RouteEntry[], loading?: string): Promise<RouteEntry[]>;
25
- declare function generateContent(appRoot: string): Promise<string[]>;
26
- declare function freezeConfig(appRoot: string): Promise<{
27
- document: DocumentConfig;
28
- agent: WorkerManifest["agent"];
29
- i18n: WorkerManifest["i18n"];
30
- earlyHints: string[];
31
- buildExternal: string[];
32
- }>;
33
- declare function normalizeBase(base?: string): string;
34
- declare function workerName(raw: string): string;
35
- declare function buildManifest(appRoot: string): Promise<WorkerManifest>;
36
- declare function juneBuild(appRoot: string, options?: {
13
+ export declare const isBunSpecifier: (id: string) => boolean;
14
+ export declare function juneBuild(appRoot: string, options?: {
37
15
  outDir?: string;
38
16
  external?: string[];
39
17
  }): Promise<BuildResult>;
40
18
  //#endregion
41
- 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,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,12 +234,12 @@ ${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");
@@ -465,6 +254,7 @@ ${adapterEntry.wrap("pipeline")}
465
254
  plugins: [rolldownCssModulesPlugin(cssModuleMaps)],
466
255
  external: (id) => {
467
256
  if (isBunSpecifier(id)) return true;
257
+ if (id.startsWith("cloudflare:")) return true;
468
258
  if (/\.(wasm|ttf|otf|woff2?|png|jpe?g|avif|webp)$/.test(id)) return true;
469
259
  return [...adapter.buildExternal ?? [], ...options.external ?? frozen.buildExternal].some((e) => id === e || id.startsWith(`${e}/`));
470
260
  },
@@ -483,7 +273,14 @@ ${adapterEntry.wrap("pipeline")}
483
273
  if (cssAsset) manifest.document.styles = `/${cssAsset}`;
484
274
  if (clientAsset) manifest.document.clientScript = `/${clientAsset}`;
485
275
  if (moduleCssAsset) manifest.document.moduleStyles = `/${moduleCssAsset}`;
486
- 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 });
487
284
  let hasAssets = false;
488
285
  const publicDir = join(appRoot, "public");
489
286
  const publicFiles = [];
@@ -505,7 +302,20 @@ ${adapterEntry.wrap("pipeline")}
505
302
  }
506
303
  if (publicFiles.length) hasAssets = true;
507
304
  }
508
- 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
+ }
509
319
  const i18n = frozen.i18n;
510
320
  const prerenderOne = async (reqPath, def) => {
511
321
  const stem = reqPath === "/" ? "index" : reqPath.slice(1);
@@ -519,7 +329,7 @@ ${adapterEntry.wrap("pipeline")}
519
329
  if (def.md !== false) targets.push([mdReq, mdFile]);
520
330
  if (typeof def.json === "function") targets.push([jsonReq, jsonFile]);
521
331
  for (const [rp, file] of targets) {
522
- const res = await worker.fetch(new Request(`https://prerender.june${rp}`));
332
+ const res = await worker.fetch(new Request(`${PRERENDER_ORIGIN}${rp}`));
523
333
  if (!res.ok) throw new Error(`prerender ${rp} → ${res.status}`);
524
334
  const dest = join(assetsDir, file);
525
335
  await mkdir(dirname(dest), { recursive: true });
@@ -528,6 +338,10 @@ ${adapterEntry.wrap("pipeline")}
528
338
  prerendered.push(reqPath);
529
339
  hasAssets = true;
530
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
+ }
531
345
  const localeVariants = (path) => isStatic && i18n ? [...new Set(Object.keys(i18n.locales).map((l) => localeHref(i18n, path, l)))] : [path];
532
346
  for (const r of routes.filter((x) => !x.dynamic)) {
533
347
  const def = manifest.routes[r.path];
@@ -540,19 +354,36 @@ ${adapterEntry.wrap("pipeline")}
540
354
  const sp = dyn.def.staticPaths;
541
355
  if (!sp) continue;
542
356
  const paths = typeof sp === "function" ? await sp() : sp;
357
+ dyn.def.staticPaths = paths;
543
358
  for (const p of paths) await prerenderOne(p, dyn.def);
544
359
  }
545
- for (const [reqPath, file] of [
360
+ const extra = [
546
361
  ["/favicon.svg", "favicon.svg"],
362
+ ["/manifest.webmanifest", "manifest.webmanifest"],
547
363
  ["/llms.txt", "llms.txt"],
548
364
  ["/sitemap.xml", "sitemap.xml"]
549
- ]) {
550
- 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}`));
551
372
  if (!res.ok) continue;
552
- 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);
553
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
+ }
554
385
  }
555
- 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__`));
556
387
  await writeFile(join(assetsDir, "404.html"), Buffer.from(await nf.arrayBuffer()));
557
388
  hasAssets = true;
558
389
  }
@@ -570,11 +401,18 @@ ${adapterEntry.wrap("pipeline")}
570
401
  hasAssets = true;
571
402
  }
572
403
  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
- } } : {};
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
+ };
578
416
  await adapter.emit({
579
417
  appRoot,
580
418
  outDir,
@@ -586,6 +424,7 @@ ${adapterEntry.wrap("pipeline")}
586
424
  publicFiles
587
425
  });
588
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})`);
589
428
  return {
590
429
  outFile,
591
430
  routes: routes.filter((r) => !r.dynamic).map((r) => r.path),
@@ -595,4 +434,4 @@ ${adapterEntry.wrap("pipeline")}
595
434
  };
596
435
  }
597
436
  //#endregion
598
- 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 };