@junejs/server 1.0.0-dev.42 → 1.0.0-dev.45
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/agent-native.d.ts +8 -1
- package/dist/agent-native.js +45 -3
- package/dist/app.d.ts +1 -0
- package/dist/app.js +10 -1
- package/dist/build.d.ts +3 -3
- package/dist/build.js +4 -2
- package/dist/{config-freeze-ZWC_Qd4h.d.ts → config-freeze-CyXvNqi2.d.ts} +1 -1
- package/dist/config-freeze.d.ts +1 -1
- package/dist/dev.d.ts +6 -2
- package/dist/dev.js +40 -9
- package/dist/host.d.ts +1 -0
- package/dist/host.js +2 -1
- package/dist/index.d.ts +4 -4
- package/dist/index.js +1 -1
- package/dist/{manifest-DSNX4I-G.d.ts → manifest-CwTT1zVs.d.ts} +1 -1
- package/dist/manifest.d.ts +1 -1
- package/dist/manifest.js +3 -1
- package/dist/pipeline.js +15 -6
- package/dist/route-rank.d.ts +10 -0
- package/dist/route-rank.js +38 -0
- package/dist/route-scan-BMbBzPIB.d.ts +20 -0
- package/dist/route-scan.d.ts +2 -2
- package/dist/route-scan.js +47 -2
- package/dist/router.js +58 -44
- package/dist/{worker-Dv4l6Ybs.d.ts → worker-2qbQjj2c.d.ts} +1 -0
- package/dist/worker.d.ts +1 -1
- package/dist/worker.js +52 -76
- package/package.json +3 -3
- package/src/agent-native.ts +75 -4
- package/src/app.ts +22 -1
- package/src/build.ts +7 -1
- package/src/dev.ts +41 -8
- package/src/host.ts +4 -3
- package/src/manifest.ts +2 -0
- package/src/pipeline.ts +20 -4
- package/src/route-rank.ts +60 -0
- package/src/route-scan.ts +78 -1
- package/src/router.ts +75 -58
- package/src/worker.ts +66 -82
- package/dist/route-scan-DMlwoESy.d.ts +0 -13
package/dist/agent-native.d.ts
CHANGED
|
@@ -19,11 +19,13 @@ export declare class NativeRuntime implements Runtime {
|
|
|
19
19
|
private readonly db;
|
|
20
20
|
private readonly announceRetry;
|
|
21
21
|
private readonly maxSessions;
|
|
22
|
+
private closing;
|
|
22
23
|
constructor(agents: Record<string, AgentDef>, db: SyncSqlite, opts?: NativeRuntimeOptions);
|
|
23
24
|
agentDef(name: string): AgentDef | undefined;
|
|
24
25
|
session(agent: string, id: string): AgentSession;
|
|
25
26
|
get sessionCount(): number;
|
|
26
27
|
recoverAnnouncements(): void;
|
|
28
|
+
close(): Promise<void>;
|
|
27
29
|
private evictIdle;
|
|
28
30
|
}
|
|
29
31
|
export declare function createNativeRuntime(agents: Record<string, AgentDef>, path?: string, opts?: NativeRuntimeOptions): Promise<NativeRuntime>;
|
|
@@ -32,16 +34,21 @@ export declare class MemoryRuntime implements Runtime {
|
|
|
32
34
|
private stores;
|
|
33
35
|
private readonly agents;
|
|
34
36
|
private readonly announceRetry;
|
|
37
|
+
private closed;
|
|
35
38
|
constructor(agents: Record<string, AgentDef>);
|
|
36
39
|
agentDef(name: string): AgentDef | undefined;
|
|
37
40
|
session(agent: string, id: string): AgentSession;
|
|
41
|
+
close(): Promise<void>;
|
|
38
42
|
}
|
|
39
43
|
export type AgentBackend = "native" | "memory" | "durable";
|
|
44
|
+
export type InProcessRuntime = Runtime & {
|
|
45
|
+
close(): Promise<void>;
|
|
46
|
+
};
|
|
40
47
|
export declare function createAgentRuntime(agents: Record<string, AgentDef>, opts?: {
|
|
41
48
|
backend?: AgentBackend;
|
|
42
49
|
path?: string;
|
|
43
50
|
maxSessions?: number;
|
|
44
|
-
}): Promise<
|
|
51
|
+
}): Promise<InProcessRuntime>;
|
|
45
52
|
export declare function mountAgent(agent: AgentDefinition, runtime: Runtime, opts?: {
|
|
46
53
|
chatPath?: string;
|
|
47
54
|
channels?: boolean;
|
package/dist/agent-native.js
CHANGED
|
@@ -93,6 +93,7 @@ var InProcEventSink = class {
|
|
|
93
93
|
var AnnouncementRetry = class {
|
|
94
94
|
flush;
|
|
95
95
|
state = /* @__PURE__ */ new Map();
|
|
96
|
+
stopped = false;
|
|
96
97
|
constructor(flush) {
|
|
97
98
|
this.flush = flush;
|
|
98
99
|
}
|
|
@@ -102,6 +103,7 @@ var AnnouncementRetry = class {
|
|
|
102
103
|
this.state.delete(key);
|
|
103
104
|
}
|
|
104
105
|
failed(key, agent, id) {
|
|
106
|
+
if (this.stopped) return;
|
|
105
107
|
const s = this.state.get(key) ?? { failures: 0 };
|
|
106
108
|
this.state.set(key, s);
|
|
107
109
|
if (s.timer) return;
|
|
@@ -113,7 +115,13 @@ var AnnouncementRetry = class {
|
|
|
113
115
|
}, delay);
|
|
114
116
|
s.timer.unref?.();
|
|
115
117
|
}
|
|
118
|
+
stop() {
|
|
119
|
+
this.stopped = true;
|
|
120
|
+
for (const s of this.state.values()) if (s.timer) clearTimeout(s.timer);
|
|
121
|
+
this.state.clear();
|
|
122
|
+
}
|
|
116
123
|
};
|
|
124
|
+
const ownedDbs = /* @__PURE__ */ new WeakSet();
|
|
117
125
|
function wireAnnouncements(session, def, retry) {
|
|
118
126
|
const hook = def.onInputAnnouncement;
|
|
119
127
|
if (hook) {
|
|
@@ -149,6 +157,7 @@ var NativeRuntime = class {
|
|
|
149
157
|
this.session(agent, id).flushAnnouncements();
|
|
150
158
|
});
|
|
151
159
|
maxSessions;
|
|
160
|
+
closing;
|
|
152
161
|
constructor(agents, db, opts = {}) {
|
|
153
162
|
assertCoreRuntimeVersion("NativeRuntime");
|
|
154
163
|
this.agents = agents;
|
|
@@ -164,6 +173,7 @@ var NativeRuntime = class {
|
|
|
164
173
|
session(agent, id) {
|
|
165
174
|
const key = `${agent}:${id}`;
|
|
166
175
|
const hit = this.actors.get(key);
|
|
176
|
+
if (!hit && this.closing) throw new Error(`NativeRuntime is closed: cannot open session "${key}"`);
|
|
167
177
|
if (hit) {
|
|
168
178
|
this.actors.delete(key);
|
|
169
179
|
this.actors.set(key, hit);
|
|
@@ -191,6 +201,18 @@ var NativeRuntime = class {
|
|
|
191
201
|
if (first && this.agents[first.agent]?.onInputAnnouncement) this.session(first.agent, first.session);
|
|
192
202
|
}
|
|
193
203
|
}
|
|
204
|
+
close() {
|
|
205
|
+
this.closing ??= (async () => {
|
|
206
|
+
this.announceRetry.stop();
|
|
207
|
+
while ([...this.actors.values()].some((a) => !a.session.idle())) await new Promise((r) => setTimeout(r, 10));
|
|
208
|
+
this.actors.clear();
|
|
209
|
+
if (ownedDbs.has(this.db)) {
|
|
210
|
+
ownedDbs.delete(this.db);
|
|
211
|
+
this.db.close();
|
|
212
|
+
}
|
|
213
|
+
})();
|
|
214
|
+
return this.closing;
|
|
215
|
+
}
|
|
194
216
|
evictIdle() {
|
|
195
217
|
if (this.actors.size < this.maxSessions) return;
|
|
196
218
|
for (const [key, a] of this.actors) {
|
|
@@ -200,9 +222,21 @@ var NativeRuntime = class {
|
|
|
200
222
|
}
|
|
201
223
|
};
|
|
202
224
|
async function createNativeRuntime(agents, path = ":memory:", opts = {}) {
|
|
203
|
-
const
|
|
204
|
-
|
|
205
|
-
|
|
225
|
+
const db = await openLocalSqliteSync(path);
|
|
226
|
+
ownedDbs.add(db);
|
|
227
|
+
let runtime;
|
|
228
|
+
try {
|
|
229
|
+
runtime = new NativeRuntime(agents, db, opts);
|
|
230
|
+
runtime.recoverAnnouncements();
|
|
231
|
+
return runtime;
|
|
232
|
+
} catch (err) {
|
|
233
|
+
if (runtime) await runtime.close();
|
|
234
|
+
else {
|
|
235
|
+
ownedDbs.delete(db);
|
|
236
|
+
db.close();
|
|
237
|
+
}
|
|
238
|
+
throw err;
|
|
239
|
+
}
|
|
206
240
|
}
|
|
207
241
|
var MemorySessionStore = class {
|
|
208
242
|
msgs = [];
|
|
@@ -259,6 +293,7 @@ var MemoryRuntime = class {
|
|
|
259
293
|
announceRetry = new AnnouncementRetry((agent, id) => {
|
|
260
294
|
this.session(agent, id).flushAnnouncements();
|
|
261
295
|
});
|
|
296
|
+
closed = false;
|
|
262
297
|
constructor(agents) {
|
|
263
298
|
assertCoreRuntimeVersion("MemoryRuntime");
|
|
264
299
|
this.agents = agents;
|
|
@@ -270,6 +305,7 @@ var MemoryRuntime = class {
|
|
|
270
305
|
const key = `${agent}:${id}`;
|
|
271
306
|
let a = this.actors.get(key);
|
|
272
307
|
if (!a) {
|
|
308
|
+
if (this.closed) throw new Error(`MemoryRuntime is closed: cannot open session "${key}"`);
|
|
273
309
|
const def = this.agents[agent];
|
|
274
310
|
if (!def) throw new Error(`unknown agent: ${agent}`);
|
|
275
311
|
const store = new MemorySessionStore();
|
|
@@ -280,6 +316,12 @@ var MemoryRuntime = class {
|
|
|
280
316
|
}
|
|
281
317
|
return a;
|
|
282
318
|
}
|
|
319
|
+
async close() {
|
|
320
|
+
this.closed = true;
|
|
321
|
+
this.announceRetry.stop();
|
|
322
|
+
this.actors.clear();
|
|
323
|
+
this.stores.clear();
|
|
324
|
+
}
|
|
283
325
|
};
|
|
284
326
|
async function createAgentRuntime(agents, opts = {}) {
|
|
285
327
|
const backend = opts.backend ?? "native";
|
package/dist/app.d.ts
CHANGED
package/dist/app.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { discoverAgent } from "./agent-discover.js";
|
|
2
2
|
import { createAgentRuntime, mountAgent, toAgentDef } from "./agent-native.js";
|
|
3
3
|
import { findMiddlewareFile, isResourceFile, listRoutes, matchRouteTree, resolveNotFound, routeFiles } from "./router.js";
|
|
4
|
+
import { routeProblems, scanRoutes } from "./route-scan.js";
|
|
4
5
|
import { createPipeline } from "./pipeline.js";
|
|
5
6
|
import { resolveBoundary } from "./segment.js";
|
|
6
7
|
import { memoizeResources } from "./resources.js";
|
|
@@ -115,6 +116,7 @@ function createApp({ appDir: appDirInput, config = {} }) {
|
|
|
115
116
|
config.dataLayer?.install();
|
|
116
117
|
let pipelinePromise;
|
|
117
118
|
const getPipeline = () => pipelinePromise ??= buildPipeline();
|
|
119
|
+
let agentRuntime;
|
|
118
120
|
async function buildPipeline() {
|
|
119
121
|
const { maps, css } = await getModuleCss();
|
|
120
122
|
await registerCssModules(maps);
|
|
@@ -138,6 +140,7 @@ function createApp({ appDir: appDirInput, config = {} }) {
|
|
|
138
140
|
const backend = agent.runtime.backend === "durable" ? "native" : agent.runtime.backend;
|
|
139
141
|
const model = anthropic({ model: def.model });
|
|
140
142
|
const rt = await createAgentRuntime({ [def.name]: toAgentDef(def, model) }, { backend });
|
|
143
|
+
agentRuntime = rt;
|
|
141
144
|
const mounted = mountAgent(def, rt, {
|
|
142
145
|
chatPath: agent.runtime.chat.path,
|
|
143
146
|
channels: agent.runtime.channels
|
|
@@ -257,6 +260,8 @@ function createApp({ appDir: appDirInput, config = {} }) {
|
|
|
257
260
|
return toPipeline();
|
|
258
261
|
},
|
|
259
262
|
async warmup() {
|
|
263
|
+
const problems = routeProblems([await scanRoutes(appDir), hasJuneRoutes ? await scanRoutes(juneRoutesDir) : []], dirname(appDir));
|
|
264
|
+
if (problems) console.error(problems);
|
|
260
265
|
const files = await routeFiles(appDir, { pageConvention: true });
|
|
261
266
|
if (hasJuneRoutes) files.push(...await routeFiles(juneRoutesDir, { pageConvention: true }));
|
|
262
267
|
for (const file of files) await import(pathToFileURL(file).href).catch((err) => {
|
|
@@ -264,7 +269,11 @@ function createApp({ appDir: appDirInput, config = {} }) {
|
|
|
264
269
|
});
|
|
265
270
|
},
|
|
266
271
|
routePaths,
|
|
267
|
-
earlyHints: () => config.earlyHints ?? []
|
|
272
|
+
earlyHints: () => config.earlyHints ?? [],
|
|
273
|
+
async close() {
|
|
274
|
+
await pipelinePromise?.catch(() => {});
|
|
275
|
+
await agentRuntime?.close();
|
|
276
|
+
}
|
|
268
277
|
};
|
|
269
278
|
}
|
|
270
279
|
//#endregion
|
package/dist/build.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { a as scanAppRoutes, o as scanRoutes, t as RouteEntry } from "./route-scan-BMbBzPIB.js";
|
|
2
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-
|
|
4
|
-
import { n as buildManifest } from "./manifest-
|
|
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
6
|
export type BuildResult = {
|
|
7
7
|
outFile: string;
|
package/dist/build.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { jsxTransform } from "./tsconfig-jsx.js";
|
|
2
2
|
import { generateAgentModule } from "./agent-compile.js";
|
|
3
3
|
import { findMiddlewareFile } from "./router.js";
|
|
4
|
+
import { scanAppRoutes, scanRoutes } from "./route-scan.js";
|
|
4
5
|
import { resolveBoundary } from "./segment.js";
|
|
5
6
|
import { buildModuleCss, registerCssModules, rolldownCssModulesPlugin } from "./css-modules.js";
|
|
6
7
|
import { bundleClientToFile, findClientEntry } from "./client-bundle.js";
|
|
@@ -12,7 +13,6 @@ import { loadJuneConfig } from "./config-loader.js";
|
|
|
12
13
|
import { freezeConfig, normalizeBase, resolveDeployAdapter, workerName } from "./config-freeze.js";
|
|
13
14
|
import { generateContent } from "./content-freeze.js";
|
|
14
15
|
import { createWorker } from "./worker.js";
|
|
15
|
-
import { scanAppRoutes, scanRoutes } from "./route-scan.js";
|
|
16
16
|
import { buildManifest, importLayout } from "./manifest.js";
|
|
17
17
|
import { buildRsc, findRscRoutes } from "./rsc-build.js";
|
|
18
18
|
import { existsSync, lstatSync } from "node:fs";
|
|
@@ -154,6 +154,8 @@ async function juneBuild(appRoot, options = {}) {
|
|
|
154
154
|
if (r.loading) loadings.push(` ${JSON.stringify(r.path)}: ${loadingId(r.loading)},`);
|
|
155
155
|
});
|
|
156
156
|
const resourceRoutesField = resources.length ? `\n resourceRoutes: [\n${resources.join("\n")}\n ],` : "";
|
|
157
|
+
const generatedPaths = routes.filter((r) => r.generated).map((r) => r.path);
|
|
158
|
+
const generatedRoutesField = generatedPaths.length ? `\n generatedRoutes: ${JSON.stringify(generatedPaths)},` : "";
|
|
157
159
|
const layoutBoundariesField = boundaries.length ? `\n layoutBoundaries: {\n${boundaries.join("\n")}\n },` : "";
|
|
158
160
|
const builtExtraFile = findMiddlewareFile(appDir);
|
|
159
161
|
if (builtExtraFile) imports.push(`import extra from ${JSON.stringify(importPath(genDir, builtExtraFile))};`);
|
|
@@ -224,7 +226,7 @@ ${statics.join("\n")}
|
|
|
224
226
|
},
|
|
225
227
|
dynamicRoutes: [
|
|
226
228
|
${dynamics.join("\n")}
|
|
227
|
-
],${resourceRoutesField}
|
|
229
|
+
],${resourceRoutesField}${generatedRoutesField}
|
|
228
230
|
layoutChains: {
|
|
229
231
|
${chains.join("\n")}
|
|
230
232
|
},${layoutBoundariesField}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { i as JuneAdapter } from "./adapter-DcZ-W1-7.js";
|
|
2
|
-
import { n as WorkerManifest } from "./worker-
|
|
2
|
+
import { n as WorkerManifest } from "./worker-2qbQjj2c.js";
|
|
3
3
|
import { JuneConfig } from "@junejs/core/config";
|
|
4
4
|
import { DocumentConfig } from "@junejs/core/document";
|
|
5
5
|
//#region src/config-freeze.d.ts
|
package/dist/config-freeze.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { i as workerName, n as normalizeBase, r as resolveDeployAdapter, t as freezeConfig } from "./config-freeze-
|
|
1
|
+
import { i as workerName, n as normalizeBase, r as resolveDeployAdapter, t as freezeConfig } from "./config-freeze-CyXvNqi2.js";
|
|
2
2
|
export { freezeConfig, normalizeBase, resolveDeployAdapter, workerName };
|
package/dist/dev.d.ts
CHANGED
|
@@ -3,10 +3,14 @@ import { JuneHost, ServeHandle } from "./host.js";
|
|
|
3
3
|
export type DevServerOptions = {
|
|
4
4
|
appDir: string;
|
|
5
5
|
port?: number;
|
|
6
|
+
hostname?: string;
|
|
6
7
|
host?: JuneHost;
|
|
7
8
|
};
|
|
8
|
-
export
|
|
9
|
+
export declare function devUrl(hostname: string, port: number): string;
|
|
10
|
+
export declare function devAllowedHosts(configured: readonly string[] | undefined, hostname: string): string[];
|
|
11
|
+
export type DevServer = Omit<ServeHandle, "stop"> & {
|
|
9
12
|
url: string;
|
|
13
|
+
stop(force?: boolean): Promise<void>;
|
|
10
14
|
};
|
|
11
|
-
export declare function startDevServer({ appDir, port, host }: DevServerOptions): Promise<DevServer>;
|
|
15
|
+
export declare function startDevServer({ appDir, port, hostname, host }: DevServerOptions): Promise<DevServer>;
|
|
12
16
|
//#endregion
|
package/dist/dev.js
CHANGED
|
@@ -9,17 +9,42 @@ import { watch } from "node:fs";
|
|
|
9
9
|
import { dirname } from "node:path";
|
|
10
10
|
import { createServer } from "node:net";
|
|
11
11
|
//#region src/dev.ts
|
|
12
|
-
|
|
12
|
+
function devUrl(hostname, port) {
|
|
13
|
+
if ([
|
|
14
|
+
"127.0.0.1",
|
|
15
|
+
"0.0.0.0",
|
|
16
|
+
"::",
|
|
17
|
+
"localhost"
|
|
18
|
+
].includes(hostname)) return `http://localhost:${port}`;
|
|
19
|
+
return `http://${hostname.includes(":") ? `[${hostname}]` : hostname}:${port}`;
|
|
20
|
+
}
|
|
21
|
+
function devAllowedHosts(configured, hostname) {
|
|
22
|
+
const hosts = /* @__PURE__ */ new Set([
|
|
23
|
+
"localhost",
|
|
24
|
+
".localhost",
|
|
25
|
+
...configured ?? []
|
|
26
|
+
]);
|
|
27
|
+
if (!/^[\d.]+$|:/.test(hostname)) hosts.add(hostname.toLowerCase());
|
|
28
|
+
return [...hosts];
|
|
29
|
+
}
|
|
30
|
+
async function findFreePort(start, hostname, tries = 20) {
|
|
13
31
|
for (let p = start; p < start + tries; p++) if (await new Promise((resolve) => {
|
|
14
32
|
const probe = createServer();
|
|
15
33
|
probe.once("error", () => resolve(false));
|
|
16
|
-
probe.listen(p, () => probe.close(() => resolve(true)));
|
|
34
|
+
probe.listen(p, hostname, () => probe.close(() => resolve(true)));
|
|
17
35
|
})) return p;
|
|
18
36
|
throw new Error(`june dev: no free port between ${start} and ${start + tries - 1}`);
|
|
19
37
|
}
|
|
20
|
-
async function startDevServer({ appDir, port = 3e3, host: host$1 = host }) {
|
|
38
|
+
async function startDevServer({ appDir, port = 3e3, hostname = "127.0.0.1", host: host$1 = host }) {
|
|
21
39
|
await installAsyncContext();
|
|
22
|
-
const
|
|
40
|
+
const loaded = await loadJuneConfig(appDir);
|
|
41
|
+
const config = {
|
|
42
|
+
...loaded,
|
|
43
|
+
agent: {
|
|
44
|
+
...loaded.agent,
|
|
45
|
+
allowedHosts: devAllowedHosts(loaded.agent?.allowedHosts, hostname)
|
|
46
|
+
}
|
|
47
|
+
};
|
|
23
48
|
const m = await migrateApp(dirname(appDir), config);
|
|
24
49
|
if (m?.applied.length) console.log(`[june] migrated: ${m.applied.join(", ")}`);
|
|
25
50
|
if (m?.blocked) console.warn(`[june] ${blockedMessage(m.blocked)}`);
|
|
@@ -28,11 +53,12 @@ async function startDevServer({ appDir, port = 3e3, host: host$1 = host }) {
|
|
|
28
53
|
config
|
|
29
54
|
});
|
|
30
55
|
await app.warmup();
|
|
31
|
-
const freePort = await findFreePort(port);
|
|
56
|
+
const freePort = await findFreePort(port, hostname);
|
|
32
57
|
if (freePort !== port) console.log(`[june] port ${port} is taken → using ${freePort}`);
|
|
33
58
|
port = freePort;
|
|
34
59
|
const handle = host$1.serve(withLiveReload((req) => app.fetch(req)), {
|
|
35
60
|
port,
|
|
61
|
+
hostname,
|
|
36
62
|
earlyHints: () => app.earlyHints()
|
|
37
63
|
});
|
|
38
64
|
if (findGlobalCss(appDir)) {
|
|
@@ -44,12 +70,17 @@ async function startDevServer({ appDir, port = 3e3, host: host$1 = host }) {
|
|
|
44
70
|
});
|
|
45
71
|
processCssCached(appDir).catch(() => {});
|
|
46
72
|
}
|
|
47
|
-
const url =
|
|
48
|
-
|
|
73
|
+
const url = devUrl(hostname, handle.port);
|
|
74
|
+
const lan = hostname === "127.0.0.1" ? "" : ` · listening on ${hostname}`;
|
|
75
|
+
console.log(`june dev → ${url} (host: ${host$1.name})${lan}`);
|
|
49
76
|
return {
|
|
50
77
|
...handle,
|
|
51
|
-
url
|
|
78
|
+
url,
|
|
79
|
+
async stop(force) {
|
|
80
|
+
handle.stop(force);
|
|
81
|
+
await app.close();
|
|
82
|
+
}
|
|
52
83
|
};
|
|
53
84
|
}
|
|
54
85
|
//#endregion
|
|
55
|
-
export { startDevServer };
|
|
86
|
+
export { devAllowedHosts, devUrl, startDevServer };
|
package/dist/host.d.ts
CHANGED
|
@@ -13,6 +13,7 @@ export interface JuneHost {
|
|
|
13
13
|
readonly name: "bun" | "node";
|
|
14
14
|
serve(handler: (req: Request) => Promise<Response>, opts: {
|
|
15
15
|
port: number;
|
|
16
|
+
hostname?: string;
|
|
16
17
|
earlyHints?: () => string[];
|
|
17
18
|
}): ServeHandle;
|
|
18
19
|
spawnModule(entry: string, args: string[], opts: {
|
package/dist/host.js
CHANGED
|
@@ -9,6 +9,7 @@ function bunHost() {
|
|
|
9
9
|
serve(handler, opts) {
|
|
10
10
|
const server = Bun.serve({
|
|
11
11
|
port: opts.port,
|
|
12
|
+
hostname: opts.hostname,
|
|
12
13
|
fetch: handler,
|
|
13
14
|
idleTimeout: 0
|
|
14
15
|
});
|
|
@@ -64,7 +65,7 @@ function nodeHost() {
|
|
|
64
65
|
res.end("Internal Server Error");
|
|
65
66
|
}
|
|
66
67
|
});
|
|
67
|
-
server.listen(opts.port);
|
|
68
|
+
server.listen(opts.port, opts.hostname);
|
|
68
69
|
return {
|
|
69
70
|
get port() {
|
|
70
71
|
const addr = server.address();
|
package/dist/index.d.ts
CHANGED
|
@@ -2,12 +2,12 @@ import { a as ResourcePlan, c as staticSite, i as JuneAdapter, l as vercel, n as
|
|
|
2
2
|
import { AGENT_MODULE_FILE, AgentDirScan, emitAgentModule, findAgentDir, generateAgentModule, scanAgentDir } from "./agent-compile.js";
|
|
3
3
|
import { CreateAppOptions, JuneApp, createApp } from "./app.js";
|
|
4
4
|
import { R2Bucket, localBlob, r2 } from "./blob.js";
|
|
5
|
-
import {
|
|
5
|
+
import { o as scanRoutes } from "./route-scan-BMbBzPIB.js";
|
|
6
6
|
import { t as generateContent } from "./content-freeze-CyiW2fRK.js";
|
|
7
7
|
import { a as Pipeline, d as createPipeline, n as LayoutComponent, o as PipelineConfig, s as Resolved, u as RouteResolver } from "./pipeline-BHUjBO0G.js";
|
|
8
|
-
import { n as WorkerManifest, r as createWorker } from "./worker-
|
|
9
|
-
import { t as freezeConfig } from "./config-freeze-
|
|
10
|
-
import { n as buildManifest } from "./manifest-
|
|
8
|
+
import { n as WorkerManifest, r as createWorker } from "./worker-2qbQjj2c.js";
|
|
9
|
+
import { t as freezeConfig } from "./config-freeze-CyXvNqi2.js";
|
|
10
|
+
import { n as buildManifest } from "./manifest-CwTT1zVs.js";
|
|
11
11
|
import { BuildResult, juneBuild } from "./build.js";
|
|
12
12
|
import { loadJuneConfig } from "./config-loader.js";
|
|
13
13
|
import { AccountTokenStore, BetterAuthLike, ConnectionAuth, LinkedAccountAuthOptions, betterAuthAccessToken, betterAuthAccountTokenStore, linkedAccountAuth } from "./connection-auth.js";
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { deno, staticSite, vercel, workers } from "./adapter.js";
|
|
2
2
|
import { AGENT_MODULE_FILE, emitAgentModule, findAgentDir, generateAgentModule, scanAgentDir } from "./agent-compile.js";
|
|
3
3
|
import { listRoutes, matchRoute, matchRouteTree, resolveNotFound } from "./router.js";
|
|
4
|
+
import { scanRoutes } from "./route-scan.js";
|
|
4
5
|
import { negotiate } from "./negotiate.js";
|
|
5
6
|
import { createPipeline } from "./pipeline.js";
|
|
6
7
|
import { d1 } from "./d1.js";
|
|
@@ -12,7 +13,6 @@ import { freezeConfig } from "./config-freeze.js";
|
|
|
12
13
|
import { collection, entry } from "./content.js";
|
|
13
14
|
import { generateContent } from "./content-freeze.js";
|
|
14
15
|
import { createWorker } from "./worker.js";
|
|
15
|
-
import { scanRoutes } from "./route-scan.js";
|
|
16
16
|
import { buildManifest } from "./manifest.js";
|
|
17
17
|
import { juneBuild } from "./build.js";
|
|
18
18
|
import { betterAuthAccessToken, betterAuthAccountTokenStore, linkedAccountAuth } from "./connection-auth.js";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { n as LayoutComponent } from "./pipeline-BHUjBO0G.js";
|
|
2
|
-
import { n as WorkerManifest } from "./worker-
|
|
2
|
+
import { n as WorkerManifest } from "./worker-2qbQjj2c.js";
|
|
3
3
|
//#region src/manifest.d.ts
|
|
4
4
|
type ImportedLayout = {
|
|
5
5
|
component: LayoutComponent;
|
package/dist/manifest.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as buildManifest, r as importLayout, t as ImportedLayout } from "./manifest-
|
|
1
|
+
import { n as buildManifest, r as importLayout, t as ImportedLayout } from "./manifest-CwTT1zVs.js";
|
|
2
2
|
export { ImportedLayout, buildManifest, importLayout };
|
package/dist/manifest.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { findMiddlewareFile } from "./router.js";
|
|
2
|
+
import { scanAppRoutes } from "./route-scan.js";
|
|
2
3
|
import { resolveBoundary } from "./segment.js";
|
|
3
4
|
import { freezeConfig } from "./config-freeze.js";
|
|
4
|
-
import { scanAppRoutes } from "./route-scan.js";
|
|
5
5
|
import { existsSync } from "node:fs";
|
|
6
6
|
import { basename, join } from "node:path";
|
|
7
7
|
import { pathToFileURL } from "node:url";
|
|
@@ -47,6 +47,7 @@ async function buildManifest(appRoot) {
|
|
|
47
47
|
const routes = {};
|
|
48
48
|
const dynamicRoutes = [];
|
|
49
49
|
const resourceRoutes = [];
|
|
50
|
+
const generatedRoutes = scanned.filter((r) => r.generated).map((r) => r.path);
|
|
50
51
|
const layoutChains = {};
|
|
51
52
|
const layoutBoundaries = {};
|
|
52
53
|
const loadings = {};
|
|
@@ -96,6 +97,7 @@ async function buildManifest(appRoot) {
|
|
|
96
97
|
routes,
|
|
97
98
|
dynamicRoutes,
|
|
98
99
|
resourceRoutes,
|
|
100
|
+
...generatedRoutes.length ? { generatedRoutes } : {},
|
|
99
101
|
layoutChains,
|
|
100
102
|
layoutBoundaries,
|
|
101
103
|
loadings,
|
package/dist/pipeline.js
CHANGED
|
@@ -9,8 +9,8 @@ import React, { Suspense, use } from "react";
|
|
|
9
9
|
import { renderToReadableStream } from "react-dom/server";
|
|
10
10
|
import { Document, PRERENDER_ORIGIN, documentTitle, pageCanonical } from "@junejs/core/document";
|
|
11
11
|
import { AGENT_SKILLS_INDEX_PATH, AI_CATALOG_PATH, API_CATALOG_CONTENT_TYPE, ARD_PATH, MCP_SERVER_CARD_TYPE, agentSkillsIndex, aiCatalog, apiCatalog, buildLinkHeader, llmsTxt, mcpServerCard, robotsTxt, siteSkill, sitemapXml } from "@junejs/core/discovery";
|
|
12
|
-
import { mcpHandler, mcpServerIdentity, mcpTools } from "@junejs/core/mcp";
|
|
13
|
-
import { OPENAPI_MEDIA_TYPE, apiActionId, apiHandler, apiNamespaceResponse, isApiNamespace, openApiDocument } from "@junejs/core/api";
|
|
12
|
+
import { mcpForbidden, mcpHandler, mcpServerIdentity, mcpTools, originRejection } from "@junejs/core/mcp";
|
|
13
|
+
import { OPENAPI_MEDIA_TYPE, apiActionId, apiForbidden, apiHandler, apiNamespaceResponse, isApiNamespace, openApiDocument } from "@junejs/core/api";
|
|
14
14
|
import { LOCALE_COOKIE, localeAlternates, localeDir, matchPinnedLocale, negotiateLocale } from "@junejs/core/i18n";
|
|
15
15
|
//#region src/pipeline.ts
|
|
16
16
|
function readCookie(request, name) {
|
|
@@ -368,18 +368,25 @@ function createPipeline(cfg) {
|
|
|
368
368
|
default: return null;
|
|
369
369
|
}
|
|
370
370
|
}
|
|
371
|
+
const originPolicy = {
|
|
372
|
+
allowedOrigins: agent.allowedOrigins,
|
|
373
|
+
allowedHosts: agent.allowedHosts
|
|
374
|
+
};
|
|
375
|
+
const callerIdentity = async (request) => request.method === "POST" && cfg.identity ? await cfg.identity(request) : void 0;
|
|
371
376
|
async function handleRequest(request) {
|
|
372
377
|
const url = new URL(request.url);
|
|
373
378
|
if (url.pathname === "/mcp") {
|
|
374
379
|
if (!agent.mcp) return notFoundResponse("view", url.pathname);
|
|
375
|
-
const
|
|
380
|
+
const refused = originRejection(request, originPolicy);
|
|
381
|
+
if (refused !== void 0) return mcpForbidden(refused);
|
|
382
|
+
const identity = await callerIdentity(request);
|
|
376
383
|
return mcpHandler(request, {
|
|
377
384
|
request,
|
|
378
385
|
...identity
|
|
379
386
|
}, mcpServerIdentity(url.origin, {
|
|
380
387
|
site: docConfig.site,
|
|
381
388
|
agent
|
|
382
|
-
}));
|
|
389
|
+
}), originPolicy);
|
|
383
390
|
}
|
|
384
391
|
if (agent.api) {
|
|
385
392
|
if (url.pathname === "/openapi.json" && (request.method === "GET" || request.method === "HEAD")) {
|
|
@@ -394,11 +401,13 @@ function createPipeline(cfg) {
|
|
|
394
401
|
}
|
|
395
402
|
const actionId = apiActionId(url.pathname);
|
|
396
403
|
if (actionId) {
|
|
397
|
-
const
|
|
404
|
+
const refused = originRejection(request, originPolicy);
|
|
405
|
+
if (refused !== void 0) return apiForbidden(request, refused);
|
|
406
|
+
const identity = await callerIdentity(request);
|
|
398
407
|
return apiHandler(request, actionId, {
|
|
399
408
|
request,
|
|
400
409
|
...identity
|
|
401
|
-
});
|
|
410
|
+
}, originPolicy);
|
|
402
411
|
}
|
|
403
412
|
}
|
|
404
413
|
if (request.method === "OPTIONS" && agent.discovery && agent.mcp && url.pathname === SERVER_CARD_PATH) return new Response(null, {
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
//#region src/route-rank.d.ts
|
|
2
|
+
export type SegmentKind = "static" | "param" | "optional" | "catchAll" | "optionalCatchAll";
|
|
3
|
+
export declare function parseSegment(segment: string): {
|
|
4
|
+
kind: SegmentKind;
|
|
5
|
+
name?: string;
|
|
6
|
+
};
|
|
7
|
+
export declare function segmentRank(segment: string): number;
|
|
8
|
+
export declare function compareSegments(a: string, b: string): number;
|
|
9
|
+
export declare function compareRoutePatterns(a: string, b: string): number;
|
|
10
|
+
//#endregion
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
//#region src/route-rank.ts
|
|
2
|
+
const DYNAMIC = /^\[(\[)?(\.\.\.)?([A-Za-z_][A-Za-z0-9_]*)\](\])?$/;
|
|
3
|
+
function parseSegment(segment) {
|
|
4
|
+
const m = segment.match(DYNAMIC);
|
|
5
|
+
if (!m || !!m[1] !== !!m[4]) return { kind: "static" };
|
|
6
|
+
const optional = !!m[1];
|
|
7
|
+
return {
|
|
8
|
+
kind: !!m[2] ? optional ? "optionalCatchAll" : "catchAll" : optional ? "optional" : "param",
|
|
9
|
+
name: m[3]
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
const RANK = {
|
|
13
|
+
static: 0,
|
|
14
|
+
param: 1,
|
|
15
|
+
optional: 2,
|
|
16
|
+
catchAll: 3,
|
|
17
|
+
optionalCatchAll: 4
|
|
18
|
+
};
|
|
19
|
+
function segmentRank(segment) {
|
|
20
|
+
return RANK[parseSegment(segment).kind];
|
|
21
|
+
}
|
|
22
|
+
function compareSegments(a, b) {
|
|
23
|
+
return segmentRank(a) - segmentRank(b) || (a < b ? -1 : a > b ? 1 : 0);
|
|
24
|
+
}
|
|
25
|
+
function compareRoutePatterns(a, b) {
|
|
26
|
+
const as = a.split("/").filter(Boolean);
|
|
27
|
+
const bs = b.split("/").filter(Boolean);
|
|
28
|
+
for (let i = 0; i < Math.max(as.length, bs.length); i++) {
|
|
29
|
+
const x = as[i];
|
|
30
|
+
const y = bs[i];
|
|
31
|
+
if (x === void 0) return -1;
|
|
32
|
+
if (y === void 0) return 1;
|
|
33
|
+
if (x !== y) return compareSegments(x, y);
|
|
34
|
+
}
|
|
35
|
+
return 0;
|
|
36
|
+
}
|
|
37
|
+
//#endregion
|
|
38
|
+
export { compareRoutePatterns, compareSegments, parseSegment, segmentRank };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
//#region src/route-scan.d.ts
|
|
2
|
+
type RouteEntry = {
|
|
3
|
+
path: string;
|
|
4
|
+
file: string;
|
|
5
|
+
dynamic: boolean;
|
|
6
|
+
resource?: boolean;
|
|
7
|
+
generated?: boolean;
|
|
8
|
+
layouts: string[];
|
|
9
|
+
loading?: string;
|
|
10
|
+
};
|
|
11
|
+
declare function scanRoutes(appDir: string, dir?: string, layouts?: string[], out?: RouteEntry[], loading?: string): Promise<RouteEntry[]>;
|
|
12
|
+
declare function scanAppRoutes(appRoot: string): Promise<RouteEntry[]>;
|
|
13
|
+
declare function routeConflicts(routes: RouteEntry[]): Array<{
|
|
14
|
+
path: string;
|
|
15
|
+
files: string[];
|
|
16
|
+
}>;
|
|
17
|
+
declare function misplacedSegments(routes: RouteEntry[]): RouteEntry[];
|
|
18
|
+
declare function routeProblems(trees: RouteEntry[][], appRoot: string): string | null;
|
|
19
|
+
//#endregion
|
|
20
|
+
export { scanAppRoutes as a, routeProblems as i, misplacedSegments as n, scanRoutes as o, routeConflicts as r, RouteEntry as t };
|
package/dist/route-scan.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export { RouteEntry, scanAppRoutes, scanRoutes };
|
|
1
|
+
import { a as scanAppRoutes, i as routeProblems, n as misplacedSegments, o as scanRoutes, r as routeConflicts, t as RouteEntry } from "./route-scan-BMbBzPIB.js";
|
|
2
|
+
export { RouteEntry, misplacedSegments, routeConflicts, routeProblems, scanAppRoutes, scanRoutes };
|
package/dist/route-scan.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { parseSegment } from "./route-rank.js";
|
|
1
2
|
import { existsSync } from "node:fs";
|
|
2
3
|
import { readdir } from "node:fs/promises";
|
|
3
4
|
import { basename, join, relative, sep } from "node:path";
|
|
@@ -48,8 +49,52 @@ async function scanAppRoutes(appRoot) {
|
|
|
48
49
|
const juneRoutesDir = join(appRoot, ".june", "routes");
|
|
49
50
|
const appRoutes = await scanRoutes(appDir);
|
|
50
51
|
const frameworkRoutes = existsSync(juneRoutesDir) ? await scanRoutes(juneRoutesDir) : [];
|
|
52
|
+
const problems = routeProblems([appRoutes, frameworkRoutes], appRoot);
|
|
53
|
+
if (problems) throw new Error(problems);
|
|
51
54
|
const appPaths = new Set(appRoutes.map((r) => r.path));
|
|
52
|
-
|
|
55
|
+
const generated = frameworkRoutes.filter((r) => !appPaths.has(r.path)).map((r) => ({
|
|
56
|
+
...r,
|
|
57
|
+
generated: true
|
|
58
|
+
}));
|
|
59
|
+
return [...appRoutes, ...generated].sort((a, b) => a.path.localeCompare(b.path));
|
|
60
|
+
}
|
|
61
|
+
function routeConflicts(routes) {
|
|
62
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
63
|
+
for (const r of routes) {
|
|
64
|
+
const key = `${r.resource ? "route" : "page"} ${r.path}`;
|
|
65
|
+
const hit = byKey.get(key);
|
|
66
|
+
if (hit) hit.files.push(r.file);
|
|
67
|
+
else byKey.set(key, {
|
|
68
|
+
path: r.path,
|
|
69
|
+
files: [r.file]
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
return [...byKey.values()].filter((c) => c.files.length > 1).map((c) => ({
|
|
73
|
+
path: c.path,
|
|
74
|
+
files: c.files.sort()
|
|
75
|
+
})).sort((a, b) => a.path.localeCompare(b.path));
|
|
76
|
+
}
|
|
77
|
+
const ENDS_PATH = /* @__PURE__ */ new Set([
|
|
78
|
+
"optional",
|
|
79
|
+
"catchAll",
|
|
80
|
+
"optionalCatchAll"
|
|
81
|
+
]);
|
|
82
|
+
const beforeLast = (path) => path.split("/").filter(Boolean).slice(0, -1).map((s) => parseSegment(s).kind);
|
|
83
|
+
function misplacedSegments(routes) {
|
|
84
|
+
return routes.filter((r) => beforeLast(r.path).some((k) => ENDS_PATH.has(k))).sort((a, b) => a.path.localeCompare(b.path) || a.file.localeCompare(b.file));
|
|
85
|
+
}
|
|
86
|
+
function routeProblems(trees, appRoot) {
|
|
87
|
+
const rel = (f) => relative(appRoot, f).split(sep).join("/");
|
|
88
|
+
const sections = [];
|
|
89
|
+
const conflicts = trees.flatMap(routeConflicts);
|
|
90
|
+
if (conflicts.length) sections.push("[june] more than one route file resolves to the same path — keep one per path:\n" + conflicts.map((c) => ` ${c.path}: ${c.files.map(rel).join(", ")}`).join("\n"));
|
|
91
|
+
const misplaced = trees.flatMap(misplacedSegments);
|
|
92
|
+
if (misplaced.length) {
|
|
93
|
+
const lines = misplaced.map((r) => ` ${r.path}: ${rel(r.file)}`);
|
|
94
|
+
if (misplaced.some((r) => beforeLast(r.path).includes("optional"))) lines.push(" Unlike SvelteKit, June does not skip a [[param]] mid-path. For a locale prefix, set i18n.locales in june.config.ts instead of a [[lang]] directory.");
|
|
95
|
+
sections.push("[june] an optional or catch-all segment must be the last segment of a route path — nothing may follow it:\n" + lines.join("\n"));
|
|
96
|
+
}
|
|
97
|
+
return sections.length ? sections.join("\n") : null;
|
|
53
98
|
}
|
|
54
99
|
//#endregion
|
|
55
|
-
export { scanAppRoutes, scanRoutes };
|
|
100
|
+
export { misplacedSegments, routeConflicts, routeProblems, scanAppRoutes, scanRoutes };
|