@junejs/server 0.1.0-dev.4 → 0.1.0-dev.5
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 +55 -0
- package/dist/adapter.js +204 -0
- package/dist/agent-discover.d.ts +5 -0
- package/dist/agent-discover.js +75 -0
- package/dist/agent-durable.d.ts +60 -0
- package/dist/agent-durable.js +106 -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 +218 -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 +551 -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/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 +209 -0
- package/package.json +115 -23
- package/src/adapter.ts +4 -4
- package/src/client-bundle.ts +3 -1
- package/src/rsc-bundle.ts +3 -2
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import { openLocalSqliteSync } from "./sqlite-driver.js";
|
|
2
|
+
import { channelFetch } from "@junejs/core/agent-config";
|
|
3
|
+
import { AgentSession, withSystem } from "@junejs/core/agent-runtime";
|
|
4
|
+
//#region src/agent-native.ts
|
|
5
|
+
function initSchema(db) {
|
|
6
|
+
db.exec(`CREATE TABLE IF NOT EXISTS agent_sessions (session_id TEXT PRIMARY KEY, status TEXT)`);
|
|
7
|
+
db.exec(`CREATE TABLE IF NOT EXISTS agent_messages (seq INTEGER PRIMARY KEY AUTOINCREMENT, session_id TEXT, body TEXT)`);
|
|
8
|
+
db.exec(`CREATE TABLE IF NOT EXISTS agent_steps (session_id TEXT, id TEXT, output TEXT, PRIMARY KEY (session_id, id))`);
|
|
9
|
+
}
|
|
10
|
+
var SqliteSessionStore = class {
|
|
11
|
+
db;
|
|
12
|
+
sid;
|
|
13
|
+
constructor(db, sid) {
|
|
14
|
+
this.db = db;
|
|
15
|
+
this.sid = sid;
|
|
16
|
+
}
|
|
17
|
+
appendMessage(m) {
|
|
18
|
+
this.db.query("INSERT INTO agent_messages (session_id, body) VALUES (?, ?)").run(this.sid, JSON.stringify(m));
|
|
19
|
+
}
|
|
20
|
+
messages() {
|
|
21
|
+
return this.db.query("SELECT body FROM agent_messages WHERE session_id = ? ORDER BY seq").all(this.sid).map((r) => JSON.parse(r.body));
|
|
22
|
+
}
|
|
23
|
+
hasUserTurn(turnId) {
|
|
24
|
+
return this.messages().some((m) => m.role === "user" && m.turnId === turnId);
|
|
25
|
+
}
|
|
26
|
+
getStep(id) {
|
|
27
|
+
const r = this.db.query("SELECT output FROM agent_steps WHERE session_id = ? AND id = ?").get(this.sid, id);
|
|
28
|
+
return r ? JSON.parse(r.output) : void 0;
|
|
29
|
+
}
|
|
30
|
+
putStep(id, output) {
|
|
31
|
+
this.db.query("INSERT INTO agent_steps (session_id, id, output) VALUES (?, ?, ?)").run(this.sid, id, JSON.stringify(output));
|
|
32
|
+
}
|
|
33
|
+
getStatus() {
|
|
34
|
+
return this.db.query("SELECT status FROM agent_sessions WHERE session_id = ?").get(this.sid)?.status ?? "new";
|
|
35
|
+
}
|
|
36
|
+
setStatus(s) {
|
|
37
|
+
this.db.query("INSERT INTO agent_sessions (session_id, status) VALUES (?, ?) ON CONFLICT(session_id) DO UPDATE SET status = ?").run(this.sid, s, s);
|
|
38
|
+
}
|
|
39
|
+
tx(fn) {
|
|
40
|
+
this.db.exec("BEGIN");
|
|
41
|
+
try {
|
|
42
|
+
const out = fn();
|
|
43
|
+
this.db.exec("COMMIT");
|
|
44
|
+
return out;
|
|
45
|
+
} catch (e) {
|
|
46
|
+
this.db.exec("ROLLBACK");
|
|
47
|
+
throw e;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
unwrap() {
|
|
51
|
+
return this.db;
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
var InProcBroadcaster = class {
|
|
55
|
+
subs = /* @__PURE__ */ new Set();
|
|
56
|
+
publish(turnId) {
|
|
57
|
+
this.subs.forEach((cb) => {
|
|
58
|
+
try {
|
|
59
|
+
cb(turnId);
|
|
60
|
+
} catch {}
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
subscribe(cb) {
|
|
64
|
+
this.subs.add(cb);
|
|
65
|
+
return () => this.subs.delete(cb);
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
var NativeRuntime = class {
|
|
69
|
+
actors = /* @__PURE__ */ new Map();
|
|
70
|
+
agents;
|
|
71
|
+
db;
|
|
72
|
+
constructor(agents, db) {
|
|
73
|
+
this.agents = agents;
|
|
74
|
+
this.db = db;
|
|
75
|
+
initSchema(db);
|
|
76
|
+
}
|
|
77
|
+
session(agent, id) {
|
|
78
|
+
const key = `${agent}:${id}`;
|
|
79
|
+
let a = this.actors.get(key);
|
|
80
|
+
if (!a) {
|
|
81
|
+
const def = this.agents[agent];
|
|
82
|
+
if (!def) throw new Error(`unknown agent: ${agent}`);
|
|
83
|
+
const model = def.instructions ? withSystem(def.model, def.instructions) : def.model;
|
|
84
|
+
a = new AgentSession(agent, id, new SqliteSessionStore(this.db, key), new InProcBroadcaster(), model, def.tools, this);
|
|
85
|
+
this.actors.set(key, a);
|
|
86
|
+
}
|
|
87
|
+
return a;
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
async function createNativeRuntime(agents, path = ":memory:") {
|
|
91
|
+
return new NativeRuntime(agents, await openLocalSqliteSync(path));
|
|
92
|
+
}
|
|
93
|
+
var MemorySessionStore = class {
|
|
94
|
+
msgs = [];
|
|
95
|
+
steps = /* @__PURE__ */ new Map();
|
|
96
|
+
status = "new";
|
|
97
|
+
appendMessage(m) {
|
|
98
|
+
this.msgs.push(m);
|
|
99
|
+
}
|
|
100
|
+
messages() {
|
|
101
|
+
return this.msgs.slice();
|
|
102
|
+
}
|
|
103
|
+
hasUserTurn(turnId) {
|
|
104
|
+
return this.msgs.some((m) => m.role === "user" && m.turnId === turnId);
|
|
105
|
+
}
|
|
106
|
+
getStep(id) {
|
|
107
|
+
return this.steps.has(id) ? this.steps.get(id) : void 0;
|
|
108
|
+
}
|
|
109
|
+
putStep(id, output) {
|
|
110
|
+
this.steps.set(id, output);
|
|
111
|
+
}
|
|
112
|
+
getStatus() {
|
|
113
|
+
return this.status;
|
|
114
|
+
}
|
|
115
|
+
setStatus(s) {
|
|
116
|
+
this.status = s;
|
|
117
|
+
}
|
|
118
|
+
tx(fn) {
|
|
119
|
+
return fn();
|
|
120
|
+
}
|
|
121
|
+
unwrap() {}
|
|
122
|
+
};
|
|
123
|
+
var MemoryRuntime = class {
|
|
124
|
+
actors = /* @__PURE__ */ new Map();
|
|
125
|
+
stores = /* @__PURE__ */ new Map();
|
|
126
|
+
agents;
|
|
127
|
+
constructor(agents) {
|
|
128
|
+
this.agents = agents;
|
|
129
|
+
}
|
|
130
|
+
session(agent, id) {
|
|
131
|
+
const key = `${agent}:${id}`;
|
|
132
|
+
let a = this.actors.get(key);
|
|
133
|
+
if (!a) {
|
|
134
|
+
const def = this.agents[agent];
|
|
135
|
+
if (!def) throw new Error(`unknown agent: ${agent}`);
|
|
136
|
+
const store = new MemorySessionStore();
|
|
137
|
+
this.stores.set(key, store);
|
|
138
|
+
a = new AgentSession(agent, id, store, new InProcBroadcaster(), def.model, def.tools, this);
|
|
139
|
+
this.actors.set(key, a);
|
|
140
|
+
}
|
|
141
|
+
return a;
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
async function createAgentRuntime(agents, opts = {}) {
|
|
145
|
+
const backend = opts.backend ?? "native";
|
|
146
|
+
if (backend === "memory") return new MemoryRuntime(agents);
|
|
147
|
+
if (backend === "native") return createNativeRuntime(agents, opts.path);
|
|
148
|
+
throw new Error("backend 'durable' is the Cloudflare Durable Object target — construct AgentDurableObject in your worker, not via createAgentRuntime");
|
|
149
|
+
}
|
|
150
|
+
function mountAgent(agent, runtime, opts = {}) {
|
|
151
|
+
const chatPath = opts.chatPath ?? "/message";
|
|
152
|
+
const channelsOn = opts.channels ?? true;
|
|
153
|
+
const ctx = {
|
|
154
|
+
agent,
|
|
155
|
+
run: (message, o) => runtime.session(agent.name, o?.session ?? "default").turn({
|
|
156
|
+
turnId: o?.turnId,
|
|
157
|
+
userText: message
|
|
158
|
+
})
|
|
159
|
+
};
|
|
160
|
+
const channels = channelFetch(agent, ctx);
|
|
161
|
+
const surface = async (req) => {
|
|
162
|
+
const url = new URL(req.url);
|
|
163
|
+
if (req.method === "POST" && url.pathname === chatPath) {
|
|
164
|
+
const { message, session } = await req.json();
|
|
165
|
+
return Response.json({ text: await ctx.run(message, { session }) });
|
|
166
|
+
}
|
|
167
|
+
return channelsOn ? channels(req) : null;
|
|
168
|
+
};
|
|
169
|
+
return {
|
|
170
|
+
ctx,
|
|
171
|
+
surface,
|
|
172
|
+
fetch: channels,
|
|
173
|
+
startAll: async () => {
|
|
174
|
+
await Promise.all(agent.channels.filter((c) => c.start).map((c) => c.start(ctx)));
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
//#endregion
|
|
179
|
+
export { MemoryRuntime, NativeRuntime, createAgentRuntime, createNativeRuntime, mountAgent };
|
package/dist/app.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { JuneConfig } from "@junejs/core/config";
|
|
2
|
+
//#region src/app.d.ts
|
|
3
|
+
type CreateAppOptions = {
|
|
4
|
+
appDir: string;
|
|
5
|
+
config?: JuneConfig;
|
|
6
|
+
};
|
|
7
|
+
type JuneApp = {
|
|
8
|
+
fetch(request: Request): Promise<Response>;
|
|
9
|
+
warmup(): Promise<void>;
|
|
10
|
+
routePaths(): Promise<string[]>;
|
|
11
|
+
earlyHints(): string[];
|
|
12
|
+
};
|
|
13
|
+
declare function createApp({ appDir: appDirInput, config }: CreateAppOptions): JuneApp;
|
|
14
|
+
//#endregion
|
|
15
|
+
export { CreateAppOptions, JuneApp, createApp };
|
package/dist/app.js
ADDED
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import { discoverAgent } from "./agent-discover.js";
|
|
2
|
+
import { createAgentRuntime, mountAgent } from "./agent-native.js";
|
|
3
|
+
import { findMiddlewareFile, isResourceFile, listRoutes, matchRouteTree, resolveNotFound, routeFiles } from "./router.js";
|
|
4
|
+
import { createPipeline } from "./pipeline.js";
|
|
5
|
+
import { resolveBoundary } from "./segment.js";
|
|
6
|
+
import { memoizeResources } from "./resources.js";
|
|
7
|
+
import { MODULE_STYLES_URL, buildModuleCss, registerCssModules } from "./css-modules.js";
|
|
8
|
+
import { CLIENT_SCRIPT_URL, bundleClientSplit, findClientEntry } from "./client-bundle.js";
|
|
9
|
+
import { generateIslandRegistry } from "./island-registry.js";
|
|
10
|
+
import { STYLES_URL, findGlobalCss, globalCssUsesTailwind, processCssCached } from "./css.js";
|
|
11
|
+
import { existsSync } from "node:fs";
|
|
12
|
+
import { dirname, join, resolve } from "node:path";
|
|
13
|
+
import { pathToFileURL } from "node:url";
|
|
14
|
+
import { buildSystemPrompt } from "@junejs/core/agent-config";
|
|
15
|
+
import { routeFromModule } from "@junejs/core/route";
|
|
16
|
+
import { resolveAgent, resolveClientRouter, resolveSpeculationRules } from "@junejs/core/config";
|
|
17
|
+
import { runWithTrace } from "@junejs/core/instrumentation";
|
|
18
|
+
import { anthropic } from "@junejs/core/agent-models";
|
|
19
|
+
//#region src/app.ts
|
|
20
|
+
const layoutCache = /* @__PURE__ */ new Map();
|
|
21
|
+
async function loadLayout(file) {
|
|
22
|
+
const cached = layoutCache.get(file);
|
|
23
|
+
if (cached !== void 0) return cached;
|
|
24
|
+
const mod = await import(pathToFileURL(file).href);
|
|
25
|
+
const result = typeof mod.default === "function" ? {
|
|
26
|
+
component: mod.default,
|
|
27
|
+
boundary: mod.segmentBoundary === true
|
|
28
|
+
} : null;
|
|
29
|
+
layoutCache.set(file, result);
|
|
30
|
+
return result;
|
|
31
|
+
}
|
|
32
|
+
const loadingCache = /* @__PURE__ */ new Map();
|
|
33
|
+
async function nearestLoading(segments) {
|
|
34
|
+
const file = [...segments].reverse().find((s) => s.loading)?.loading;
|
|
35
|
+
if (!file) return void 0;
|
|
36
|
+
const cached = loadingCache.get(file);
|
|
37
|
+
if (cached) return cached;
|
|
38
|
+
const mod = await import(pathToFileURL(file).href);
|
|
39
|
+
if (typeof mod.default !== "function") return void 0;
|
|
40
|
+
loadingCache.set(file, mod.default);
|
|
41
|
+
return mod.default;
|
|
42
|
+
}
|
|
43
|
+
async function loadChain(segments) {
|
|
44
|
+
const items = [];
|
|
45
|
+
for (const seg of segments) {
|
|
46
|
+
if (!seg.layout) continue;
|
|
47
|
+
const L = await loadLayout(seg.layout);
|
|
48
|
+
items.push({
|
|
49
|
+
file: seg.layout,
|
|
50
|
+
entry: L?.component ?? null,
|
|
51
|
+
boundary: !!L?.boundary
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
const { chain, boundaryIndex, key } = resolveBoundary(items);
|
|
55
|
+
return {
|
|
56
|
+
chain,
|
|
57
|
+
boundaryIndex,
|
|
58
|
+
boundaryKey: key
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
function createApp({ appDir: appDirInput, config = {} }) {
|
|
62
|
+
const appDir = resolve(appDirInput);
|
|
63
|
+
const juneRoutesDir = join(dirname(appDir), ".june", "routes");
|
|
64
|
+
const hasJuneRoutes = existsSync(juneRoutesDir);
|
|
65
|
+
const agent = resolveAgent(config.agent);
|
|
66
|
+
const speculation = config.speculation;
|
|
67
|
+
const clientEntry = findClientEntry(appDir) ?? findClientEntry(join(dirname(appDir), ".june", "routes"));
|
|
68
|
+
const cssEntry = findGlobalCss(appDir);
|
|
69
|
+
const docConfig = {
|
|
70
|
+
site: config.site ?? {},
|
|
71
|
+
speculationRules: resolveSpeculationRules(speculation ?? void 0),
|
|
72
|
+
speculationDelivery: speculation ? speculation.delivery ?? "inline" : "inline",
|
|
73
|
+
viewTransitions: config.viewTransitions ?? true,
|
|
74
|
+
cssReset: config.cssReset ?? !globalCssUsesTailwind(appDir),
|
|
75
|
+
clientRouter: resolveClientRouter(config.clientRouter),
|
|
76
|
+
clientScript: clientEntry ? CLIENT_SCRIPT_URL : null,
|
|
77
|
+
styles: cssEntry ? STYLES_URL : null
|
|
78
|
+
};
|
|
79
|
+
let moduleCssPromise;
|
|
80
|
+
const getModuleCss = () => moduleCssPromise ??= buildModuleCss(appDir, dirname(appDir));
|
|
81
|
+
let clientBundle;
|
|
82
|
+
const serveClient = () => clientBundle ??= getModuleCss().then(async ({ maps }) => {
|
|
83
|
+
await generateIslandRegistry(appDir);
|
|
84
|
+
return bundleClientSplit(clientEntry, dirname(appDir), "development", maps);
|
|
85
|
+
});
|
|
86
|
+
const routePaths = async () => {
|
|
87
|
+
const own = await listRoutes(appDir, { pageConvention: true });
|
|
88
|
+
if (!hasJuneRoutes) return own;
|
|
89
|
+
const seen = new Set(own);
|
|
90
|
+
const gen = (await listRoutes(juneRoutesDir, { pageConvention: true })).filter((p) => !seen.has(p));
|
|
91
|
+
return [...own, ...gen].sort();
|
|
92
|
+
};
|
|
93
|
+
const resources = memoizeResources(config.resources);
|
|
94
|
+
config.dataLayer?.install();
|
|
95
|
+
let pipelinePromise;
|
|
96
|
+
const getPipeline = () => pipelinePromise ??= buildPipeline();
|
|
97
|
+
async function buildPipeline() {
|
|
98
|
+
const { maps, css } = await getModuleCss();
|
|
99
|
+
await registerCssModules(maps);
|
|
100
|
+
if (css !== null) docConfig.moduleStyles = MODULE_STYLES_URL;
|
|
101
|
+
const { notFound } = await resolveNotFound(appDir, "/");
|
|
102
|
+
let notFoundComponent;
|
|
103
|
+
if (notFound) {
|
|
104
|
+
const mod = await import(pathToFileURL(notFound).href);
|
|
105
|
+
if (typeof mod.default === "function") notFoundComponent = mod.default;
|
|
106
|
+
}
|
|
107
|
+
let extra;
|
|
108
|
+
const extraFile = findMiddlewareFile(appDir);
|
|
109
|
+
if (extraFile) {
|
|
110
|
+
const mod = await import(pathToFileURL(extraFile).href);
|
|
111
|
+
if (typeof mod.default === "function") extra = mod.default;
|
|
112
|
+
}
|
|
113
|
+
let agentSurface;
|
|
114
|
+
const agentDir = join(appDir, agent.runtime.dir);
|
|
115
|
+
if (agent.runtime.enabled && existsSync(agentDir)) {
|
|
116
|
+
const def = await discoverAgent(agentDir);
|
|
117
|
+
const backend = agent.runtime.backend === "durable" ? "native" : agent.runtime.backend;
|
|
118
|
+
const model = anthropic({ model: def.model });
|
|
119
|
+
const mounted = mountAgent(def, await createAgentRuntime({ [def.name]: {
|
|
120
|
+
model,
|
|
121
|
+
tools: def.tools,
|
|
122
|
+
instructions: buildSystemPrompt(def)
|
|
123
|
+
} }, { backend }), {
|
|
124
|
+
chatPath: agent.runtime.chat.path,
|
|
125
|
+
channels: agent.runtime.channels
|
|
126
|
+
});
|
|
127
|
+
agentSurface = (req) => mounted.surface(req);
|
|
128
|
+
await mounted.startAll();
|
|
129
|
+
}
|
|
130
|
+
return createPipeline({
|
|
131
|
+
extra,
|
|
132
|
+
docConfig,
|
|
133
|
+
agent,
|
|
134
|
+
agentSurface,
|
|
135
|
+
i18n: config.i18n,
|
|
136
|
+
routeList: routePaths,
|
|
137
|
+
earlyHints: config.earlyHints,
|
|
138
|
+
resources,
|
|
139
|
+
notFoundComponent,
|
|
140
|
+
resolve: async (pathname) => {
|
|
141
|
+
const match = await matchRouteTree(appDir, pathname, { pageConvention: true }) ?? (hasJuneRoutes ? await matchRouteTree(juneRoutesDir, pathname, { pageConvention: true }) : null);
|
|
142
|
+
if (!match) return null;
|
|
143
|
+
const mod = await import(pathToFileURL(match.file).href);
|
|
144
|
+
if (isResourceFile(match.file)) {
|
|
145
|
+
const handler = mod.default;
|
|
146
|
+
if (typeof handler !== "function") return null;
|
|
147
|
+
return {
|
|
148
|
+
handler,
|
|
149
|
+
params: match.params
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
const def = routeFromModule(mod);
|
|
153
|
+
if (!def) return null;
|
|
154
|
+
const { chain, boundaryIndex, boundaryKey } = await loadChain(match.segments);
|
|
155
|
+
return {
|
|
156
|
+
def,
|
|
157
|
+
params: match.params,
|
|
158
|
+
chain,
|
|
159
|
+
boundaryIndex,
|
|
160
|
+
boundaryKey,
|
|
161
|
+
loading: await nearestLoading(match.segments)
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
function newTrace() {
|
|
167
|
+
return {
|
|
168
|
+
id: crypto.randomUUID(),
|
|
169
|
+
startedAt: performance.now(),
|
|
170
|
+
events: []
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
return {
|
|
174
|
+
fetch(request) {
|
|
175
|
+
if (cssEntry && new URL(request.url).pathname === "/_june/global.css") return processCssCached(appDir).then((css) => new Response(css ?? "", { headers: { "content-type": "text/css; charset=utf-8" } }), (err) => {
|
|
176
|
+
console.error("[june] global.css failed:", err);
|
|
177
|
+
return new Response(`/* global.css failed: ${err instanceof Error ? err.message : String(err)} */\n`, {
|
|
178
|
+
status: 500,
|
|
179
|
+
headers: { "content-type": "text/css; charset=utf-8" }
|
|
180
|
+
});
|
|
181
|
+
});
|
|
182
|
+
if (new URL(request.url).pathname === "/_june/modules.css") return getModuleCss().then(({ css }) => new Response(css ?? "", { headers: { "content-type": "text/css; charset=utf-8" } }));
|
|
183
|
+
{
|
|
184
|
+
const pathname = new URL(request.url).pathname;
|
|
185
|
+
if (clientEntry && pathname.startsWith("/_june/") && pathname.endsWith(".js")) {
|
|
186
|
+
const file = pathname.slice(7);
|
|
187
|
+
return serveClient().then((chunks) => {
|
|
188
|
+
const code = chunks.get(file);
|
|
189
|
+
if (code === void 0) return new Response(`unknown client chunk: ${file}\n`, {
|
|
190
|
+
status: 404,
|
|
191
|
+
headers: { "content-type": "text/plain; charset=utf-8" }
|
|
192
|
+
});
|
|
193
|
+
return new Response(code, { headers: { "content-type": "text/javascript; charset=utf-8" } });
|
|
194
|
+
}, (err) => {
|
|
195
|
+
clientBundle = void 0;
|
|
196
|
+
console.error("[june] client bundle failed:", err);
|
|
197
|
+
return new Response(`client bundle failed: ${err instanceof Error ? err.message : String(err)}\n`, {
|
|
198
|
+
status: 500,
|
|
199
|
+
headers: { "content-type": "text/plain; charset=utf-8" }
|
|
200
|
+
});
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
return runWithTrace(newTrace(), async () => (await getPipeline()).fetch(request));
|
|
205
|
+
},
|
|
206
|
+
async warmup() {
|
|
207
|
+
const files = await routeFiles(appDir, { pageConvention: true });
|
|
208
|
+
if (hasJuneRoutes) files.push(...await routeFiles(juneRoutesDir, { pageConvention: true }));
|
|
209
|
+
for (const file of files) await import(pathToFileURL(file).href).catch((err) => {
|
|
210
|
+
console.error(`[june] failed to load route ${file}`, err);
|
|
211
|
+
});
|
|
212
|
+
},
|
|
213
|
+
routePaths,
|
|
214
|
+
earlyHints: () => config.earlyHints ?? []
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
//#endregion
|
|
218
|
+
export { createApp };
|
package/dist/blob.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { BlobFactory } from "@junejs/core/resources";
|
|
2
|
+
//#region src/blob.d.ts
|
|
3
|
+
declare function localBlob(opts?: {
|
|
4
|
+
dir?: string;
|
|
5
|
+
}): BlobFactory;
|
|
6
|
+
interface R2ObjectBody {
|
|
7
|
+
arrayBuffer(): Promise<ArrayBuffer>;
|
|
8
|
+
}
|
|
9
|
+
interface R2Bucket {
|
|
10
|
+
get(key: string): Promise<R2ObjectBody | null>;
|
|
11
|
+
put(key: string, data: ArrayBuffer | Uint8Array | string): Promise<unknown>;
|
|
12
|
+
delete(key: string): Promise<void>;
|
|
13
|
+
list(opts?: {
|
|
14
|
+
prefix?: string;
|
|
15
|
+
}): Promise<{
|
|
16
|
+
objects: {
|
|
17
|
+
key: string;
|
|
18
|
+
}[];
|
|
19
|
+
}>;
|
|
20
|
+
}
|
|
21
|
+
declare function r2(bucket: R2Bucket): BlobFactory;
|
|
22
|
+
//#endregion
|
|
23
|
+
export { R2Bucket, localBlob, r2 };
|
package/dist/blob.js
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { mkdir, readFile, readdir, rm, writeFile } from "node:fs/promises";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
//#region src/blob.ts
|
|
4
|
+
function safeKey(key) {
|
|
5
|
+
if (key.startsWith("/") || key.split(/[\\/]/).includes("..")) throw new Error(`unsafe blob key: ${key}`);
|
|
6
|
+
return key;
|
|
7
|
+
}
|
|
8
|
+
function localBlobHandle(dir) {
|
|
9
|
+
return {
|
|
10
|
+
async get(key) {
|
|
11
|
+
const file = join(dir, safeKey(key));
|
|
12
|
+
try {
|
|
13
|
+
return new Uint8Array(await readFile(file));
|
|
14
|
+
} catch {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
async put(key, data) {
|
|
19
|
+
const file = join(dir, safeKey(key));
|
|
20
|
+
await mkdir(dirname(file), { recursive: true });
|
|
21
|
+
await writeFile(file, typeof data === "string" ? data : Buffer.from(data));
|
|
22
|
+
},
|
|
23
|
+
async delete(key) {
|
|
24
|
+
await rm(join(dir, safeKey(key)), { force: true });
|
|
25
|
+
},
|
|
26
|
+
async list(prefix = "") {
|
|
27
|
+
const out = [];
|
|
28
|
+
async function walk(d, base) {
|
|
29
|
+
let entries;
|
|
30
|
+
try {
|
|
31
|
+
entries = await readdir(d, { withFileTypes: true });
|
|
32
|
+
} catch {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
for (const e of entries) {
|
|
36
|
+
const rel = base ? `${base}/${e.name}` : e.name;
|
|
37
|
+
if (e.isDirectory()) await walk(join(d, e.name), rel);
|
|
38
|
+
else if (rel.startsWith(prefix)) out.push(rel);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
await walk(dir, "");
|
|
42
|
+
return out.sort();
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
function localBlob(opts = {}) {
|
|
47
|
+
const dir = opts.dir ?? ".june/blob";
|
|
48
|
+
return {
|
|
49
|
+
kind: "local",
|
|
50
|
+
open: async () => {
|
|
51
|
+
await mkdir(dir, { recursive: true });
|
|
52
|
+
return localBlobHandle(dir);
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
function r2(bucket) {
|
|
57
|
+
const handle = {
|
|
58
|
+
async get(key) {
|
|
59
|
+
const obj = await bucket.get(key);
|
|
60
|
+
return obj ? new Uint8Array(await obj.arrayBuffer()) : null;
|
|
61
|
+
},
|
|
62
|
+
async put(key, data) {
|
|
63
|
+
await bucket.put(key, data);
|
|
64
|
+
},
|
|
65
|
+
async delete(key) {
|
|
66
|
+
await bucket.delete(key);
|
|
67
|
+
},
|
|
68
|
+
async list(prefix) {
|
|
69
|
+
return (await bucket.list({ prefix })).objects.map((o) => o.key);
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
return {
|
|
73
|
+
kind: "r2",
|
|
74
|
+
open: async () => handle
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
//#endregion
|
|
78
|
+
export { localBlob, r2 };
|
package/dist/build.d.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
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";
|
|
5
|
+
//#region src/build.d.ts
|
|
6
|
+
type BuildResult = {
|
|
7
|
+
outFile: string;
|
|
8
|
+
routes: string[];
|
|
9
|
+
dynamicRoutes: string[];
|
|
10
|
+
contentCollections: string[];
|
|
11
|
+
prerendered: string[];
|
|
12
|
+
};
|
|
13
|
+
type RouteEntry = {
|
|
14
|
+
path: string;
|
|
15
|
+
file: string;
|
|
16
|
+
dynamic: boolean;
|
|
17
|
+
resource?: boolean;
|
|
18
|
+
layouts: string[];
|
|
19
|
+
loading?: string;
|
|
20
|
+
};
|
|
21
|
+
declare const isBunSpecifier: (id: string) => boolean;
|
|
22
|
+
declare function resolveDeployAdapter(deploy: JuneConfig["deploy"]): JuneAdapter;
|
|
23
|
+
declare function scanRoutes(appDir: string, dir?: string, layouts?: string[], out?: RouteEntry[], loading?: string): Promise<RouteEntry[]>;
|
|
24
|
+
declare function generateContent(appRoot: string): Promise<string[]>;
|
|
25
|
+
declare function freezeConfig(appRoot: string): Promise<{
|
|
26
|
+
document: DocumentConfig;
|
|
27
|
+
agent: WorkerManifest["agent"];
|
|
28
|
+
i18n: WorkerManifest["i18n"];
|
|
29
|
+
earlyHints: string[];
|
|
30
|
+
buildExternal: string[];
|
|
31
|
+
}>;
|
|
32
|
+
declare function normalizeBase(base?: string): string;
|
|
33
|
+
declare function workerName(raw: string): string;
|
|
34
|
+
declare function buildManifest(appRoot: string): Promise<WorkerManifest>;
|
|
35
|
+
declare function juneBuild(appRoot: string, options?: {
|
|
36
|
+
outDir?: string;
|
|
37
|
+
external?: string[];
|
|
38
|
+
}): Promise<BuildResult>;
|
|
39
|
+
//#endregion
|
|
40
|
+
export { BuildResult, buildManifest, freezeConfig, generateContent, isBunSpecifier, juneBuild, normalizeBase, resolveDeployAdapter, scanRoutes, workerName };
|