@junejs/server 0.1.0-dev.4 → 0.1.0-dev.7

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 (105) hide show
  1. package/dist/adapter.d.ts +56 -0
  2. package/dist/adapter.js +211 -0
  3. package/dist/agent-discover.d.ts +5 -0
  4. package/dist/agent-discover.js +75 -0
  5. package/dist/agent-durable.d.ts +72 -0
  6. package/dist/agent-durable.js +141 -0
  7. package/dist/agent-native.d.ts +40 -0
  8. package/dist/agent-native.js +179 -0
  9. package/dist/app.d.ts +15 -0
  10. package/dist/app.js +252 -0
  11. package/dist/blob.d.ts +23 -0
  12. package/dist/blob.js +78 -0
  13. package/dist/build.d.ts +40 -0
  14. package/dist/build.js +582 -0
  15. package/dist/client-bundle.d.ts +15 -0
  16. package/dist/client-bundle.js +91 -0
  17. package/dist/config-loader.d.ts +9 -0
  18. package/dist/config-loader.js +25 -0
  19. package/dist/content.d.ts +39 -0
  20. package/dist/content.js +201 -0
  21. package/dist/css-modules-ambient.d.ts +10 -0
  22. package/dist/css-modules.d.ts +24 -0
  23. package/dist/css-modules.js +127 -0
  24. package/dist/css.d.ts +14 -0
  25. package/dist/css.js +114 -0
  26. package/dist/d1-BkdUg9kg.d.ts +24 -0
  27. package/dist/d1-migrate.d.ts +31 -0
  28. package/dist/d1-migrate.js +156 -0
  29. package/dist/d1.d.ts +2 -0
  30. package/dist/d1.js +32 -0
  31. package/dist/db.d.ts +11 -0
  32. package/dist/db.js +20 -0
  33. package/dist/deploy.d.ts +25 -0
  34. package/dist/deploy.js +158 -0
  35. package/dist/dev-reload.d.ts +5 -0
  36. package/dist/dev-reload.js +123 -0
  37. package/dist/dev.d.ts +13 -0
  38. package/dist/dev.js +55 -0
  39. package/dist/host.d.ts +25 -0
  40. package/dist/host.js +107 -0
  41. package/dist/index.d.ts +26 -0
  42. package/dist/index.js +26 -0
  43. package/dist/instrumentation.d.ts +4 -0
  44. package/dist/instrumentation.js +15 -0
  45. package/dist/island-registry.d.ts +8 -0
  46. package/dist/island-registry.js +117 -0
  47. package/dist/kv.d.ts +8 -0
  48. package/dist/kv.js +35 -0
  49. package/dist/migrate-BbWt-PuB.d.ts +32 -0
  50. package/dist/migrate.d.ts +2 -0
  51. package/dist/migrate.js +115 -0
  52. package/dist/mysql-driver-BsrWVqbp.d.ts +12 -0
  53. package/dist/mysql-driver.d.ts +2 -0
  54. package/dist/mysql-driver.js +52 -0
  55. package/dist/negotiate.d.ts +11 -0
  56. package/dist/negotiate.js +39 -0
  57. package/dist/pipeline-B2V6tKfO.d.ts +49 -0
  58. package/dist/pipeline.d.ts +2 -0
  59. package/dist/pipeline.js +235 -0
  60. package/dist/postgres-driver-DkkBFikA.d.ts +15 -0
  61. package/dist/postgres-driver.d.ts +2 -0
  62. package/dist/postgres-driver.js +50 -0
  63. package/dist/resources.d.ts +15 -0
  64. package/dist/resources.js +31 -0
  65. package/dist/router.d.ts +32 -0
  66. package/dist/router.js +183 -0
  67. package/dist/rsc-build.d.ts +17 -0
  68. package/dist/rsc-build.js +68 -0
  69. package/dist/rsc-bundle.d.ts +8 -0
  70. package/dist/rsc-bundle.js +39 -0
  71. package/dist/rsc-manifest.d.ts +8 -0
  72. package/dist/rsc-manifest.js +67 -0
  73. package/dist/rsc-runtime/flight-render-routes.d.ts +5 -0
  74. package/dist/rsc-runtime/flight-render-routes.js +26 -0
  75. package/dist/rsc-runtime/flight-render.d.ts +4 -0
  76. package/dist/rsc-runtime/flight-render.js +21 -0
  77. package/dist/rsc-runtime/flight-to-html.d.ts +4 -0
  78. package/dist/rsc-runtime/flight-to-html.js +32 -0
  79. package/dist/rsc-runtime/rsc-worker.d.ts +6 -0
  80. package/dist/rsc-runtime/rsc-worker.js +46 -0
  81. package/dist/rsc-runtime/rsdw-shims.d.ts +42 -0
  82. package/dist/segment.d.ts +14 -0
  83. package/dist/segment.js +33 -0
  84. package/dist/sqlite-driver.d.ts +25 -0
  85. package/dist/sqlite-driver.js +102 -0
  86. package/dist/static-files.d.ts +6 -0
  87. package/dist/static-files.js +56 -0
  88. package/dist/tsconfig-jsx.d.ts +15 -0
  89. package/dist/tsconfig-jsx.js +35 -0
  90. package/dist/turso-driver-C1wEigMZ.d.ts +22 -0
  91. package/dist/turso-driver.d.ts +2 -0
  92. package/dist/turso-driver.js +68 -0
  93. package/dist/worker.d.ts +55 -0
  94. package/dist/worker.js +211 -0
  95. package/package.json +115 -23
  96. package/src/adapter.ts +20 -7
  97. package/src/agent-discover.ts +5 -2
  98. package/src/agent-durable.ts +108 -4
  99. package/src/app.ts +74 -2
  100. package/src/build.ts +52 -3
  101. package/src/client-bundle.ts +3 -1
  102. package/src/index.ts +4 -0
  103. package/src/rsc-bundle.ts +3 -2
  104. package/src/static-files.ts +84 -0
  105. package/src/worker.ts +46 -29
@@ -0,0 +1,35 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ //#region src/tsconfig-jsx.ts
4
+ const stripJsonc = (s) => s.replace(/\/\*[\s\S]*?\*\//g, "").replace(/(^|\s)\/\/.*$/gm, "$1").replace(/,\s*([}\]])/g, "$1");
5
+ /** Read the app's tsconfig.json and return compilerOptions.jsxImportSource.
6
+ * Follows one level of `extends` so apps that inherit from a base tsconfig
7
+ * (e.g. "@kurajs/docs/tsconfig.kura.json") are handled correctly.
8
+ * Returns undefined when absent or unreadable. */
9
+ async function appJsxImportSource(appRoot) {
10
+ const read = async (path) => {
11
+ try {
12
+ return JSON.parse(stripJsonc(await readFile(path, "utf8")));
13
+ } catch {
14
+ return;
15
+ }
16
+ };
17
+ const tc = await read(join(appRoot, "tsconfig.json"));
18
+ if (!tc) return void 0;
19
+ if (tc.compilerOptions?.jsxImportSource) return tc.compilerOptions.jsxImportSource;
20
+ if (tc.extends) {
21
+ const btc = await read(tc.extends.startsWith(".") ? join(appRoot, tc.extends) : join(appRoot, "node_modules", tc.extends));
22
+ if (btc?.compilerOptions?.jsxImportSource) return btc.compilerOptions.jsxImportSource;
23
+ }
24
+ }
25
+ /** The transform.jsx both bundles use: June's island JSX runtime, with the explicit importSource
26
+ * skipped when the app's tsconfig already declares it — rolldown then reads it from tsconfig
27
+ * silently instead of warning about the (same-value) override. */
28
+ async function jsxTransform(appRoot) {
29
+ return {
30
+ runtime: "automatic",
31
+ ...await appJsxImportSource(appRoot) === "@junejs/core" ? {} : { importSource: "@junejs/core" }
32
+ };
33
+ }
34
+ //#endregion
35
+ export { appJsxImportSource, jsxTransform };
@@ -0,0 +1,22 @@
1
+ import { DbFactory, JuneDb } from "@junejs/core/resources";
2
+ //#region src/turso-driver.d.ts
3
+ interface LibsqlResultSet {
4
+ rows: unknown[];
5
+ rowsAffected: number;
6
+ lastInsertRowid?: bigint | number;
7
+ }
8
+ interface LibsqlClientLike {
9
+ execute(stmt: {
10
+ sql: string;
11
+ args?: unknown[];
12
+ } | string): Promise<LibsqlResultSet>;
13
+ executeMultiple?(sql: string): Promise<void>;
14
+ close(): void | Promise<void>;
15
+ }
16
+ declare function libsqlJuneDb(client: LibsqlClientLike): JuneDb;
17
+ declare function turso(opts?: {
18
+ url?: string;
19
+ authToken?: string;
20
+ }): DbFactory;
21
+ //#endregion
22
+ export { turso as i, LibsqlResultSet as n, libsqlJuneDb as r, LibsqlClientLike as t };
@@ -0,0 +1,2 @@
1
+ import { i as turso, n as LibsqlResultSet, r as libsqlJuneDb, t as LibsqlClientLike } from "./turso-driver-C1wEigMZ.js";
2
+ export { LibsqlClientLike, LibsqlResultSet, libsqlJuneDb, turso };
@@ -0,0 +1,68 @@
1
+ //#region src/turso-driver.ts
2
+ function libsqlJuneDb(client) {
3
+ const self = {
4
+ dialect: "sqlite",
5
+ async query(sql, params = []) {
6
+ return (await client.execute({
7
+ sql,
8
+ args: params
9
+ })).rows;
10
+ },
11
+ async get(sql, params = []) {
12
+ return (await client.execute({
13
+ sql,
14
+ args: params
15
+ })).rows[0] ?? void 0;
16
+ },
17
+ async run(sql, params = []) {
18
+ const r = await client.execute({
19
+ sql,
20
+ args: params
21
+ });
22
+ return {
23
+ changes: r.rowsAffected ?? 0,
24
+ lastInsertRowid: Number(r.lastInsertRowid ?? 0)
25
+ };
26
+ },
27
+ async exec(sql) {
28
+ if (client.executeMultiple) await client.executeMultiple(sql);
29
+ else await client.execute(sql);
30
+ },
31
+ async transaction(fn) {
32
+ await client.execute("BEGIN");
33
+ try {
34
+ const out = await fn(self);
35
+ await client.execute("COMMIT");
36
+ return out;
37
+ } catch (e) {
38
+ await client.execute("ROLLBACK");
39
+ throw e;
40
+ }
41
+ },
42
+ async close() {
43
+ await client.close();
44
+ }
45
+ };
46
+ return self;
47
+ }
48
+ function turso(opts = {}) {
49
+ return {
50
+ kind: "turso",
51
+ open: async () => {
52
+ const url = opts.url ?? readEnv("TURSO_DATABASE_URL");
53
+ const authToken = opts.authToken ?? readEnv("TURSO_AUTH_TOKEN");
54
+ if (!url) throw new Error("turso(): no database url — pass { url } or set TURSO_DATABASE_URL in the environment.");
55
+ const mod = await import("@libsql/client/web");
56
+ const createClient = (mod.default ?? mod).createClient;
57
+ return libsqlJuneDb(createClient({
58
+ url,
59
+ authToken
60
+ }));
61
+ }
62
+ };
63
+ }
64
+ function readEnv(name) {
65
+ return typeof process !== "undefined" && process.env ? process.env[name] : void 0;
66
+ }
67
+ //#endregion
68
+ export { libsqlJuneDb, turso };
@@ -0,0 +1,55 @@
1
+ import { l as ResourceHandler, n as LayoutComponent, r as LoadingComponent, t as ExtraHandler } from "./pipeline-B2V6tKfO.js";
2
+ import { BrandedRoute } from "@junejs/core/route";
3
+ import { AgentConfig } from "@junejs/core/config";
4
+ import React from "react";
5
+ import { DocumentConfig } from "@junejs/core/document";
6
+ import { I18nConfig } from "@junejs/core/i18n";
7
+ import { Resources } from "@junejs/core/resources";
8
+ //#region src/worker.d.ts
9
+ type WorkerManifest = {
10
+ routes: Record<string, BrandedRoute>;
11
+ dynamicRoutes?: Array<{
12
+ pattern: string;
13
+ def: BrandedRoute;
14
+ }>;
15
+ resourceRoutes?: Array<{
16
+ pattern: string;
17
+ handler: ResourceHandler;
18
+ }>;
19
+ layoutChains?: Record<string, LayoutComponent[]>;
20
+ layoutBoundaries?: Record<string, {
21
+ index: number;
22
+ key: string;
23
+ }>;
24
+ loadings?: Record<string, LoadingComponent>;
25
+ document: DocumentConfig;
26
+ agent: AgentConfig;
27
+ agentName?: string;
28
+ i18n?: I18nConfig;
29
+ earlyHints?: string[];
30
+ htmlCacheControl?: string;
31
+ notFound?: React.ComponentType<{
32
+ pathname: string;
33
+ }>;
34
+ extra?: ExtraHandler;
35
+ resources?: (env?: unknown) => Promise<Resources> | Resources;
36
+ };
37
+ declare function createWorker(manifest: WorkerManifest): {
38
+ fetch(request: Request, env?: unknown): Promise<Response>;
39
+ };
40
+ type AssetEnv = {
41
+ ASSETS?: {
42
+ fetch(request: Request): Promise<Response>;
43
+ };
44
+ };
45
+ type FetchPipeline = {
46
+ fetch(request: Request, env?: unknown): Promise<Response>;
47
+ };
48
+ declare function withAssets(pipeline: FetchPipeline, opts?: {
49
+ link?: string | null;
50
+ }): {
51
+ fetch(request: Request, env?: AssetEnv): Promise<Response>;
52
+ };
53
+ declare function withDenoAssets(pipeline: FetchPipeline): (request: Request) => Promise<Response>;
54
+ //#endregion
55
+ export { WorkerManifest, createWorker, withAssets, withDenoAssets };
package/dist/worker.js ADDED
@@ -0,0 +1,211 @@
1
+ import { durableAgentSurface } from "./agent-durable.js";
2
+ import { createPipeline } from "./pipeline.js";
3
+ import { RESERVED_PREFIX, contentTypeFor, safeRelativePath } from "./static-files.js";
4
+ //#region src/worker.ts
5
+ function compilePattern(pattern) {
6
+ const names = [];
7
+ let source = "";
8
+ let allOptional = true;
9
+ for (const seg of pattern.split("/").filter(Boolean)) {
10
+ const oca = seg.match(/^\[\[\.\.\.(\w+)\]\]$/);
11
+ if (oca) {
12
+ names.push(oca[1]);
13
+ source += "(?:/(.+))?";
14
+ continue;
15
+ }
16
+ const ca = seg.match(/^\[\.\.\.(\w+)\]$/);
17
+ if (ca) {
18
+ names.push(ca[1]);
19
+ source += "/(.+)";
20
+ allOptional = false;
21
+ continue;
22
+ }
23
+ const op = seg.match(/^\[\[(\w+)\]\]$/);
24
+ if (op) {
25
+ names.push(op[1]);
26
+ source += "(?:/([^/]+))?";
27
+ continue;
28
+ }
29
+ const p = seg.match(/^\[(\w+)\]$/);
30
+ if (p) {
31
+ names.push(p[1]);
32
+ source += "/([^/]+)";
33
+ allOptional = false;
34
+ continue;
35
+ }
36
+ source += "/" + seg.replace(/[.*+?^${}()|\\]/g, "\\$&");
37
+ allOptional = false;
38
+ }
39
+ if (source === "") return {
40
+ regex: /^\/$/,
41
+ names
42
+ };
43
+ return {
44
+ regex: new RegExp(allOptional ? `^(?:${source}|/)$` : `^${source}$`),
45
+ names
46
+ };
47
+ }
48
+ function createWorker(manifest) {
49
+ const dynamic = (manifest.dynamicRoutes ?? []).map((d) => ({
50
+ ...compilePattern(d.pattern),
51
+ def: d.def,
52
+ pattern: d.pattern
53
+ }));
54
+ const resources = (manifest.resourceRoutes ?? []).map((r) => ({
55
+ ...compilePattern(r.pattern),
56
+ handler: r.handler,
57
+ pattern: r.pattern
58
+ }));
59
+ const routeList = [...Object.keys(manifest.routes), ...(manifest.dynamicRoutes ?? []).map((d) => d.pattern)].sort();
60
+ const chainFor = (key) => manifest.layoutChains?.[key] ?? [];
61
+ const loadingFor = (key) => manifest.loadings?.[key];
62
+ const boundaryFor = (key) => manifest.layoutBoundaries?.[key] ?? null;
63
+ let currentEnv;
64
+ const provider = manifest.resources;
65
+ const agentSurface = manifest.agent.runtime.enabled && manifest.agentName ? (() => {
66
+ const route = durableAgentSurface(() => currentEnv?.AGENT, {
67
+ agentName: manifest.agentName,
68
+ chatPath: manifest.agent.runtime.chat.path
69
+ });
70
+ return (req) => route(req);
71
+ })() : void 0;
72
+ const pipeline = createPipeline({
73
+ docConfig: manifest.document,
74
+ agent: manifest.agent,
75
+ agentSurface,
76
+ i18n: manifest.i18n,
77
+ routeList: () => routeList,
78
+ earlyHints: manifest.earlyHints,
79
+ htmlCacheControl: manifest.htmlCacheControl,
80
+ notFoundComponent: manifest.notFound,
81
+ extra: manifest.extra,
82
+ resources: provider ? () => provider(currentEnv) : void 0,
83
+ resolve: async (pathname) => {
84
+ const staticDef = manifest.routes[pathname];
85
+ if (staticDef) {
86
+ const b = boundaryFor(pathname);
87
+ return {
88
+ def: staticDef,
89
+ params: {},
90
+ chain: chainFor(pathname),
91
+ boundaryIndex: b?.index ?? null,
92
+ boundaryKey: b?.key ?? null,
93
+ loading: loadingFor(pathname)
94
+ };
95
+ }
96
+ for (const d of dynamic) {
97
+ const m = pathname.match(d.regex);
98
+ if (m) {
99
+ const params = Object.fromEntries(d.names.flatMap((n, i) => {
100
+ const v = m[i + 1];
101
+ return v === void 0 ? [] : [[n, decodeURIComponent(v)]];
102
+ }));
103
+ const b = boundaryFor(d.pattern);
104
+ return {
105
+ def: d.def,
106
+ params,
107
+ chain: chainFor(d.pattern),
108
+ boundaryIndex: b?.index ?? null,
109
+ boundaryKey: b?.key ?? null,
110
+ loading: loadingFor(d.pattern)
111
+ };
112
+ }
113
+ }
114
+ for (const r of resources) {
115
+ const m = pathname.match(r.regex);
116
+ if (m) {
117
+ const params = Object.fromEntries(r.names.flatMap((n, i) => {
118
+ const v = m[i + 1];
119
+ return v === void 0 ? [] : [[n, decodeURIComponent(v)]];
120
+ }));
121
+ return {
122
+ handler: r.handler,
123
+ params
124
+ };
125
+ }
126
+ }
127
+ return null;
128
+ }
129
+ });
130
+ return { fetch(request, env) {
131
+ currentEnv = env;
132
+ return pipeline.fetch(request);
133
+ } };
134
+ }
135
+ const estimateTokens = (s) => String(Math.ceil(s.length / 4));
136
+ function withAssets(pipeline, opts = {}) {
137
+ return { async fetch(request, env) {
138
+ const assets = env?.ASSETS;
139
+ const url = new URL(request.url);
140
+ const isPagePath = !/\.[a-z0-9]+$/i.test(url.pathname);
141
+ const accept = request.headers.get("accept") ?? "";
142
+ if (assets && request.method === "GET" && isPagePath && /text\/markdown/.test(accept)) {
143
+ const base = url.pathname === "/" ? "/index" : url.pathname.replace(/\/+$/, "");
144
+ const mdUrl = new URL(url);
145
+ mdUrl.pathname = `${base}.md`;
146
+ const a = await assets.fetch(new Request(mdUrl.toString(), { headers: request.headers }));
147
+ if (a.ok) {
148
+ const body = await a.text();
149
+ const headers = new Headers(a.headers);
150
+ headers.set("content-type", "text/markdown; charset=utf-8");
151
+ headers.set("x-markdown-tokens", estimateTokens(body));
152
+ if (opts.link) headers.set("link", opts.link);
153
+ return new Response(body, {
154
+ status: 200,
155
+ headers
156
+ });
157
+ }
158
+ }
159
+ if (assets) {
160
+ const a = await assets.fetch(request);
161
+ if (a.status !== 404) {
162
+ const ct = a.headers.get("content-type") ?? "";
163
+ const addLink = !!opts.link && ct.includes("text/html") && !a.headers.has("link");
164
+ const immutable = /\.[a-f0-9]{8,}\.(css|js)$/.test(url.pathname);
165
+ if (addLink || immutable) {
166
+ const headers = new Headers(a.headers);
167
+ if (addLink) headers.set("link", opts.link);
168
+ if (immutable) headers.set("cache-control", "public, max-age=31536000, immutable");
169
+ return new Response(a.body, {
170
+ status: a.status,
171
+ headers
172
+ });
173
+ }
174
+ return a;
175
+ }
176
+ }
177
+ return pipeline.fetch(request, env);
178
+ } };
179
+ }
180
+ function withDenoAssets(pipeline) {
181
+ return async (request) => {
182
+ const method = request.method;
183
+ if (method === "GET" || method === "HEAD") {
184
+ const url = new URL(request.url);
185
+ {
186
+ const rel = safeRelativePath(url.pathname);
187
+ if (rel !== null) try {
188
+ const assetUrl = new URL(`./assets/${rel.split("/").map(encodeURIComponent).join("/")}`, import.meta.url);
189
+ const immutable = rel.startsWith(`${RESERVED_PREFIX}/`);
190
+ const headers = {
191
+ "content-type": contentTypeFor(rel),
192
+ "cache-control": immutable ? "public, max-age=31536000, immutable" : "public, max-age=0, must-revalidate"
193
+ };
194
+ if (method === "HEAD") {
195
+ const info = await Deno.stat(assetUrl);
196
+ if (!info.isFile) throw new Error("not a file");
197
+ return new Response(null, { headers: {
198
+ ...headers,
199
+ "content-length": String(info.size)
200
+ } });
201
+ }
202
+ const file = await Deno.readFile(assetUrl);
203
+ return new Response(file, { headers });
204
+ } catch {}
205
+ }
206
+ }
207
+ return pipeline.fetch(request);
208
+ };
209
+ }
210
+ //#endregion
211
+ export { createWorker, withAssets, withDenoAssets };
package/package.json CHANGED
@@ -1,40 +1,132 @@
1
1
  {
2
2
  "name": "@junejs/server",
3
- "version": "0.1.0-dev.4",
3
+ "version": "0.1.0-dev.7",
4
4
  "description": "June host adapters + dev server. Host-coupled; depends on the pure @junejs/core contract layer.",
5
5
  "type": "module",
6
6
  "license": "MIT",
7
7
  "homepage": "https://june.build",
8
8
  "exports": {
9
- ".": "./src/index.ts",
10
- "./host": "./src/host.ts",
11
- "./agent-native": "./src/agent-native.ts",
12
- "./agent-durable": "./src/agent-durable.ts",
13
- "./agent-discover": "./src/agent-discover.ts",
14
- "./db": "./src/db.ts",
15
- "./kv": "./src/kv.ts",
16
- "./blob": "./src/blob.ts",
17
- "./resources": "./src/resources.ts",
18
- "./config": "./src/config-loader.ts",
19
- "./content": "./src/content.ts",
20
- "./router": "./src/router.ts",
21
- "./instrumentation": "./src/instrumentation.ts",
22
- "./pipeline": "./src/pipeline.ts",
23
- "./worker": "./src/worker.ts",
24
- "./build": "./src/build.ts",
25
- "./deploy": "./src/deploy.ts",
26
- "./dev": "./src/dev.ts"
9
+ ".": {
10
+ "source": "./src/index.ts",
11
+ "bun": "./src/index.ts",
12
+ "types": "./dist/index.d.ts",
13
+ "default": "./dist/index.js"
14
+ },
15
+ "./host": {
16
+ "source": "./src/host.ts",
17
+ "bun": "./src/host.ts",
18
+ "types": "./dist/host.d.ts",
19
+ "default": "./dist/host.js"
20
+ },
21
+ "./agent-native": {
22
+ "source": "./src/agent-native.ts",
23
+ "bun": "./src/agent-native.ts",
24
+ "types": "./dist/agent-native.d.ts",
25
+ "default": "./dist/agent-native.js"
26
+ },
27
+ "./agent-durable": {
28
+ "source": "./src/agent-durable.ts",
29
+ "bun": "./src/agent-durable.ts",
30
+ "types": "./dist/agent-durable.d.ts",
31
+ "default": "./dist/agent-durable.js"
32
+ },
33
+ "./agent-discover": {
34
+ "source": "./src/agent-discover.ts",
35
+ "bun": "./src/agent-discover.ts",
36
+ "types": "./dist/agent-discover.d.ts",
37
+ "default": "./dist/agent-discover.js"
38
+ },
39
+ "./db": {
40
+ "source": "./src/db.ts",
41
+ "bun": "./src/db.ts",
42
+ "types": "./dist/db.d.ts",
43
+ "default": "./dist/db.js"
44
+ },
45
+ "./kv": {
46
+ "source": "./src/kv.ts",
47
+ "bun": "./src/kv.ts",
48
+ "types": "./dist/kv.d.ts",
49
+ "default": "./dist/kv.js"
50
+ },
51
+ "./blob": {
52
+ "source": "./src/blob.ts",
53
+ "bun": "./src/blob.ts",
54
+ "types": "./dist/blob.d.ts",
55
+ "default": "./dist/blob.js"
56
+ },
57
+ "./resources": {
58
+ "source": "./src/resources.ts",
59
+ "bun": "./src/resources.ts",
60
+ "types": "./dist/resources.d.ts",
61
+ "default": "./dist/resources.js"
62
+ },
63
+ "./config": {
64
+ "source": "./src/config-loader.ts",
65
+ "bun": "./src/config-loader.ts",
66
+ "types": "./dist/config-loader.d.ts",
67
+ "default": "./dist/config-loader.js"
68
+ },
69
+ "./content": {
70
+ "source": "./src/content.ts",
71
+ "bun": "./src/content.ts",
72
+ "types": "./dist/content.d.ts",
73
+ "default": "./dist/content.js"
74
+ },
75
+ "./router": {
76
+ "source": "./src/router.ts",
77
+ "bun": "./src/router.ts",
78
+ "types": "./dist/router.d.ts",
79
+ "default": "./dist/router.js"
80
+ },
81
+ "./instrumentation": {
82
+ "source": "./src/instrumentation.ts",
83
+ "bun": "./src/instrumentation.ts",
84
+ "types": "./dist/instrumentation.d.ts",
85
+ "default": "./dist/instrumentation.js"
86
+ },
87
+ "./pipeline": {
88
+ "source": "./src/pipeline.ts",
89
+ "bun": "./src/pipeline.ts",
90
+ "types": "./dist/pipeline.d.ts",
91
+ "default": "./dist/pipeline.js"
92
+ },
93
+ "./worker": {
94
+ "source": "./src/worker.ts",
95
+ "bun": "./src/worker.ts",
96
+ "types": "./dist/worker.d.ts",
97
+ "default": "./dist/worker.js"
98
+ },
99
+ "./build": {
100
+ "source": "./src/build.ts",
101
+ "bun": "./src/build.ts",
102
+ "types": "./dist/build.d.ts",
103
+ "default": "./dist/build.js"
104
+ },
105
+ "./deploy": {
106
+ "source": "./src/deploy.ts",
107
+ "bun": "./src/deploy.ts",
108
+ "types": "./dist/deploy.d.ts",
109
+ "default": "./dist/deploy.js"
110
+ },
111
+ "./dev": {
112
+ "source": "./src/dev.ts",
113
+ "bun": "./src/dev.ts",
114
+ "types": "./dist/dev.d.ts",
115
+ "default": "./dist/dev.js"
116
+ }
27
117
  },
28
118
  "files": [
29
- "src"
119
+ "src",
120
+ "dist"
30
121
  ],
31
122
  "scripts": {
32
123
  "test": "bun test",
33
- "typecheck": "tsc --noEmit"
124
+ "typecheck": "tsc --noEmit",
125
+ "build": "tsdown"
34
126
  },
35
127
  "dependencies": {
36
- "@junejs/core": ">=0.1.0-dev.3",
37
- "@junejs/db": ">=0.0.33-dev.0",
128
+ "@junejs/core": ">=0.1.0-dev.5",
129
+ "@junejs/db": ">=0.0.33-dev.2",
38
130
  "@momiji-rs/sparkdown": "^0.0.4",
39
131
  "lightningcss": "^1.27.0",
40
132
  "oxc-parser": "^0.137.0",
package/src/adapter.ts CHANGED
@@ -8,7 +8,7 @@
8
8
  // are explicit `deploy: { adapter: vercel() }` from their own package.
9
9
  import { existsSync } from "node:fs";
10
10
  import { cp, copyFile, mkdir, readdir, rm, writeFile } from "node:fs/promises";
11
- import { basename, join } from "node:path";
11
+ import { basename, dirname, join } from "node:path";
12
12
 
13
13
  import type { JuneConfig } from "@junejs/core/config";
14
14
 
@@ -49,6 +49,10 @@ export type AdapterEmitContext = {
49
49
  plan: ResourcePlan;
50
50
  // package.json name (or sanitized dir name) — the fallback worker/app name.
51
51
  defaultName: string;
52
+ // Verbatim public/ files (forward-slash paths relative to assets/), already
53
+ // copied into outDir/assets. Adapters that build a separate static tier (vercel)
54
+ // place these there; whole-assets targets (workers/static/deno) ignore it.
55
+ publicFiles?: string[];
52
56
  };
53
57
 
54
58
  export interface JuneAdapter {
@@ -80,7 +84,7 @@ export function workers(opts?: { name?: string; domain?: string }): JuneAdapter
80
84
  return {
81
85
  name: "workers",
82
86
  capabilities: { runtime: "edge", persistentConnections: true, assets: "platform" },
83
- conditions: ["workerd", "edge", "import", "default"],
87
+ conditions: ["source", "workerd", "edge", "import", "default"],
84
88
  // workers-og is a workerd-native WASM package: rolldown cannot bundle its
85
89
  // .wasm assets (wrangler's own bundler applies the CompiledWasm rule). Mark
86
90
  // it external here so user apps never need `build: { external: ["workers-og"] }`.
@@ -183,7 +187,7 @@ export function vercel(opts?: { runtime?: "node" | "edge"; regions?: string[] })
183
187
  // listed BEFORE "edge-light", so requesting "worker" pulls the wrong renderer.
184
188
  // "edge-light" → server.edge.js, which uses Web Streams (renderToReadableStream)
185
189
  // and runs on workerd AND Node alike. Mirrors workers()'s shape.
186
- conditions: ["edge-light", "edge", "import", "default"],
190
+ conditions: ["source", "edge-light", "edge", "import", "default"],
187
191
 
188
192
  validate({ config }) {
189
193
  // turso() is libsql over HTTPS — it runs on Vercel (the build bundles the web
@@ -214,7 +218,7 @@ export function vercel(opts?: { runtime?: "node" | "edge"; regions?: string[] })
214
218
  };
215
219
  },
216
220
 
217
- async emit({ appRoot, outDir, hasAssets }) {
221
+ async emit({ appRoot, outDir, hasAssets, publicFiles }) {
218
222
  const out = join(appRoot, ".vercel", "output");
219
223
  const fnDir = join(out, "functions", `${VERCEL_FUNCTION}.func`);
220
224
  await rm(out, { recursive: true, force: true }); // clean — no stale outputs
@@ -249,11 +253,20 @@ export function vercel(opts?: { runtime?: "node" | "edge"; regions?: string[] })
249
253
  await writeFile(join(fnDir, "package.json"), JSON.stringify({ type: "module" }, null, 2) + "\n");
250
254
  }
251
255
 
252
- // static: only the hashed framework assets under /_june/ (exact-path URLs)
256
+ // static: the hashed framework assets under /_june/ (exact-path URLs)...
253
257
  if (hasAssets) {
254
258
  const src = join(outDir, "assets", "_june");
255
259
  if (existsSync(src)) await cp(src, join(out, "static", "_june"), { recursive: true });
256
260
  }
261
+ // ...plus verbatim public/ files, served by the `filesystem` route handle
262
+ // below. Only these — prerendered page HTML stays on the SSR function.
263
+ for (const rel of publicFiles ?? []) {
264
+ const from = join(outDir, "assets", rel);
265
+ if (!existsSync(from)) continue;
266
+ const to = join(out, "static", rel);
267
+ await mkdir(dirname(to), { recursive: true });
268
+ await copyFile(from, to);
269
+ }
257
270
 
258
271
  await writeFile(
259
272
  join(out, "config.json"),
@@ -293,7 +306,7 @@ export function deno(opts?: { org?: string; app?: string }): JuneAdapter {
293
306
  capabilities: { runtime: "edge", persistentConnections: true, assets: "server" },
294
307
  // "deno" first (a dep may ship a Deno-specific build); else edge-light →
295
308
  // server.edge.js (Web Streams + fetch, which Deno has).
296
- conditions: ["deno", "edge-light", "edge", "import", "default"],
309
+ conditions: ["source", "deno", "edge-light", "edge", "import", "default"],
297
310
 
298
311
  validate({ config }) {
299
312
  const kind = config.resources?.db?.kind;
@@ -365,7 +378,7 @@ export function staticSite(): JuneAdapter {
365
378
  capabilities: { runtime: "static", persistentConnections: false, assets: "none" },
366
379
  // edge-light → react-dom resolves to server.edge.js (Web Streams), which the
367
380
  // build host (Bun/Node) runs during prerender — the same choice as vercel()/deno().
368
- conditions: ["edge-light", "edge", "import", "default"],
381
+ conditions: ["source", "edge-light", "edge", "import", "default"],
369
382
  // Defensive: if an OG/image route ever slips into a static build, keep the WASM
370
383
  // renderer external so the bundle still builds (Kura drops the OG route on static).
371
384
  buildExternal: ["workers-og"],
@@ -21,7 +21,7 @@ import { basename, extname, join } from "node:path";
21
21
  import { pathToFileURL } from "node:url";
22
22
 
23
23
  import type { AnyAction } from "@junejs/core/agent";
24
- import { defineAgent, type AgentConfigFile, type AgentDefinition, type Channel, type Skill } from "@junejs/core/agent-config";
24
+ import { defineAgent, resolveChannel, type AgentConfigFile, type AgentDefinition, type Channel, type ChannelFactory, type Skill } from "@junejs/core/agent-config";
25
25
  import { connectAll, type Connection } from "@junejs/core/connections";
26
26
 
27
27
  async function scan(dir: string, ext: string): Promise<string[]> {
@@ -79,10 +79,13 @@ export async function discoverAgent(dir: string): Promise<AgentDefinition> {
79
79
  skills.push(parseSkill(basename(f, ".md"), await readFile(f, "utf8")));
80
80
  }
81
81
 
82
+ // A channel module default-exports a Channel OR a `(env) => Channel` factory (the
83
+ // form workerd needs — secrets live in env, not at module scope). On native, env is
84
+ // process.env (present at load), so resolve here; the plain form stays supported.
82
85
  const channels: Channel[] = [];
83
86
  for (const f of await scan(join(dir, "channels"), ".ts")) {
84
87
  const mod = await import(pathToFileURL(f).href);
85
- if (mod.default) channels.push(mod.default as Channel);
88
+ if (mod.default) channels.push(resolveChannel(mod.default as Channel | ChannelFactory, process.env));
86
89
  }
87
90
 
88
91
  // connections/*.ts — outbound: wire external MCP/OpenAPI servers, turning their