@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.
- package/dist/adapter.d.ts +56 -0
- package/dist/adapter.js +211 -0
- package/dist/agent-discover.d.ts +5 -0
- package/dist/agent-discover.js +75 -0
- package/dist/agent-durable.d.ts +72 -0
- package/dist/agent-durable.js +141 -0
- package/dist/agent-native.d.ts +40 -0
- package/dist/agent-native.js +179 -0
- package/dist/app.d.ts +15 -0
- package/dist/app.js +252 -0
- package/dist/blob.d.ts +23 -0
- package/dist/blob.js +78 -0
- package/dist/build.d.ts +40 -0
- package/dist/build.js +582 -0
- package/dist/client-bundle.d.ts +15 -0
- package/dist/client-bundle.js +91 -0
- package/dist/config-loader.d.ts +9 -0
- package/dist/config-loader.js +25 -0
- package/dist/content.d.ts +39 -0
- package/dist/content.js +201 -0
- package/dist/css-modules-ambient.d.ts +10 -0
- package/dist/css-modules.d.ts +24 -0
- package/dist/css-modules.js +127 -0
- package/dist/css.d.ts +14 -0
- package/dist/css.js +114 -0
- package/dist/d1-BkdUg9kg.d.ts +24 -0
- package/dist/d1-migrate.d.ts +31 -0
- package/dist/d1-migrate.js +156 -0
- package/dist/d1.d.ts +2 -0
- package/dist/d1.js +32 -0
- package/dist/db.d.ts +11 -0
- package/dist/db.js +20 -0
- package/dist/deploy.d.ts +25 -0
- package/dist/deploy.js +158 -0
- package/dist/dev-reload.d.ts +5 -0
- package/dist/dev-reload.js +123 -0
- package/dist/dev.d.ts +13 -0
- package/dist/dev.js +55 -0
- package/dist/host.d.ts +25 -0
- package/dist/host.js +107 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.js +26 -0
- package/dist/instrumentation.d.ts +4 -0
- package/dist/instrumentation.js +15 -0
- package/dist/island-registry.d.ts +8 -0
- package/dist/island-registry.js +117 -0
- package/dist/kv.d.ts +8 -0
- package/dist/kv.js +35 -0
- package/dist/migrate-BbWt-PuB.d.ts +32 -0
- package/dist/migrate.d.ts +2 -0
- package/dist/migrate.js +115 -0
- package/dist/mysql-driver-BsrWVqbp.d.ts +12 -0
- package/dist/mysql-driver.d.ts +2 -0
- package/dist/mysql-driver.js +52 -0
- package/dist/negotiate.d.ts +11 -0
- package/dist/negotiate.js +39 -0
- package/dist/pipeline-B2V6tKfO.d.ts +49 -0
- package/dist/pipeline.d.ts +2 -0
- package/dist/pipeline.js +235 -0
- package/dist/postgres-driver-DkkBFikA.d.ts +15 -0
- package/dist/postgres-driver.d.ts +2 -0
- package/dist/postgres-driver.js +50 -0
- package/dist/resources.d.ts +15 -0
- package/dist/resources.js +31 -0
- package/dist/router.d.ts +32 -0
- package/dist/router.js +183 -0
- package/dist/rsc-build.d.ts +17 -0
- package/dist/rsc-build.js +68 -0
- package/dist/rsc-bundle.d.ts +8 -0
- package/dist/rsc-bundle.js +39 -0
- package/dist/rsc-manifest.d.ts +8 -0
- package/dist/rsc-manifest.js +67 -0
- package/dist/rsc-runtime/flight-render-routes.d.ts +5 -0
- package/dist/rsc-runtime/flight-render-routes.js +26 -0
- package/dist/rsc-runtime/flight-render.d.ts +4 -0
- package/dist/rsc-runtime/flight-render.js +21 -0
- package/dist/rsc-runtime/flight-to-html.d.ts +4 -0
- package/dist/rsc-runtime/flight-to-html.js +32 -0
- package/dist/rsc-runtime/rsc-worker.d.ts +6 -0
- package/dist/rsc-runtime/rsc-worker.js +46 -0
- package/dist/rsc-runtime/rsdw-shims.d.ts +42 -0
- package/dist/segment.d.ts +14 -0
- package/dist/segment.js +33 -0
- package/dist/sqlite-driver.d.ts +25 -0
- package/dist/sqlite-driver.js +102 -0
- package/dist/static-files.d.ts +6 -0
- package/dist/static-files.js +56 -0
- package/dist/tsconfig-jsx.d.ts +15 -0
- package/dist/tsconfig-jsx.js +35 -0
- package/dist/turso-driver-C1wEigMZ.d.ts +22 -0
- package/dist/turso-driver.d.ts +2 -0
- package/dist/turso-driver.js +68 -0
- package/dist/worker.d.ts +55 -0
- package/dist/worker.js +211 -0
- package/package.json +115 -23
- package/src/adapter.ts +20 -7
- package/src/agent-discover.ts +5 -2
- package/src/agent-durable.ts +108 -4
- package/src/app.ts +74 -2
- package/src/build.ts +52 -3
- package/src/client-bundle.ts +3 -1
- package/src/index.ts +4 -0
- package/src/rsc-bundle.ts +3 -2
- package/src/static-files.ts +84 -0
- 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,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 };
|
package/dist/worker.d.ts
ADDED
|
@@ -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.
|
|
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
|
-
".":
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
"./
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
"./
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
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.
|
|
37
|
-
"@junejs/db": ">=0.0.33-dev.
|
|
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:
|
|
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"],
|
package/src/agent-discover.ts
CHANGED
|
@@ -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
|