@junejs/server 1.0.0-dev.42 → 1.0.0-dev.47

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/dist/agent-durable.d.ts +4 -0
  2. package/dist/agent-durable.js +22 -4
  3. package/dist/agent-native.d.ts +18 -2
  4. package/dist/agent-native.js +62 -8
  5. package/dist/app.d.ts +1 -0
  6. package/dist/app.js +18 -2
  7. package/dist/build.d.ts +3 -3
  8. package/dist/build.js +4 -2
  9. package/dist/{config-freeze-ZWC_Qd4h.d.ts → config-freeze-CyXvNqi2.d.ts} +1 -1
  10. package/dist/config-freeze.d.ts +1 -1
  11. package/dist/core-version.js +1 -1
  12. package/dist/dev.d.ts +6 -2
  13. package/dist/dev.js +40 -9
  14. package/dist/host.d.ts +1 -0
  15. package/dist/host.js +2 -1
  16. package/dist/index.d.ts +4 -4
  17. package/dist/index.js +2 -2
  18. package/dist/{manifest-DSNX4I-G.d.ts → manifest-CwTT1zVs.d.ts} +1 -1
  19. package/dist/manifest.d.ts +1 -1
  20. package/dist/manifest.js +3 -1
  21. package/dist/pipeline.js +15 -6
  22. package/dist/route-rank.d.ts +10 -0
  23. package/dist/route-rank.js +38 -0
  24. package/dist/route-scan-BMbBzPIB.d.ts +20 -0
  25. package/dist/route-scan.d.ts +2 -2
  26. package/dist/route-scan.js +47 -2
  27. package/dist/router.js +58 -44
  28. package/dist/sqlite-driver.d.ts +1 -0
  29. package/dist/sqlite-driver.js +17 -4
  30. package/dist/{worker-Dv4l6Ybs.d.ts → worker-2qbQjj2c.d.ts} +1 -0
  31. package/dist/worker.d.ts +1 -1
  32. package/dist/worker.js +59 -77
  33. package/package.json +3 -3
  34. package/src/agent-durable.ts +24 -3
  35. package/src/agent-native.ts +99 -13
  36. package/src/app.ts +34 -2
  37. package/src/build.ts +7 -1
  38. package/src/core-version.ts +1 -1
  39. package/src/dev.ts +41 -8
  40. package/src/host.ts +4 -3
  41. package/src/manifest.ts +2 -0
  42. package/src/pipeline.ts +20 -4
  43. package/src/route-rank.ts +60 -0
  44. package/src/route-scan.ts +78 -1
  45. package/src/router.ts +75 -58
  46. package/src/sqlite-driver.ts +36 -6
  47. package/src/worker.ts +76 -82
  48. package/dist/route-scan-DMlwoESy.d.ts +0 -13
@@ -1,5 +1,6 @@
1
1
  import { Channel, ChannelFactory } from "@junejs/core/agent-config";
2
2
  import { AuthorizeAnswer, ChannelPolicy, InboundEvent, InputAnnouncement, Model, Msg, NoteKind, ProactiveTrigger, SessionStore, Tool, TurnError, TurnEvent, TurnFailurePhase } from "@junejs/core/agent-runtime";
3
+ import { FileStore } from "@junejs/core/agent-files";
3
4
  import { Connection } from "@junejs/core/connections";
4
5
  import { Resources } from "@junejs/core/resources";
5
6
  //#region src/agent-durable.d.ts
@@ -63,6 +64,7 @@ export type DoAgentDef = {
63
64
  }) => void | Promise<void>;
64
65
  authorizeAnswer?: AuthorizeAnswer;
65
66
  onInputAnnouncement?: (a: InputAnnouncement) => void | Promise<void>;
67
+ files?: FileStore;
66
68
  };
67
69
  export declare class AgentDurableObject {
68
70
  private session;
@@ -83,6 +85,7 @@ export declare class AgentDurableObject {
83
85
  private readonly authorizeAnswer?;
84
86
  private readonly onInputAnnouncement?;
85
87
  private readonly storage;
88
+ private readonly files;
86
89
  private announceFailures;
87
90
  private resolveResources;
88
91
  private resolveConnections;
@@ -140,5 +143,6 @@ export declare function durableChannelSurface(getNamespace: () => DurableObjectN
140
143
  env: unknown;
141
144
  services?: (env: unknown) => unknown;
142
145
  waitUntil?: (p: Promise<unknown>) => void;
146
+ files?: FileStore;
143
147
  }): (req: Request) => Promise<Response | null>;
144
148
  //#endregion
@@ -2,7 +2,8 @@ import { observeTurnEvents } from "./turn-events.js";
2
2
  import { isolateLocal } from "./isolate-local.js";
3
3
  import { assertCoreRuntimeVersion } from "./core-version.js";
4
4
  import { DeliverUnsupportedError, actionToTool, channelDispatch, resolveChannel } from "@junejs/core/agent-config";
5
- import { AgentSession, ResumeAuthorizationError, grantAnswer, withSystem } from "@junejs/core/agent-runtime";
5
+ import { AgentSession, FatalToolError, ResumeAuthorizationError, grantAnswer, withSystem } from "@junejs/core/agent-runtime";
6
+ import { blobFileStore } from "@junejs/core/agent-files";
6
7
  import { connectAll } from "@junejs/core/connections";
7
8
  import { ensureScope, runInScope } from "@junejs/db";
8
9
  //#region src/agent-durable.ts
@@ -111,6 +112,7 @@ var AgentDurableObject = class {
111
112
  authorizeAnswer;
112
113
  onInputAnnouncement;
113
114
  storage;
115
+ files;
114
116
  announceFailures = 0;
115
117
  resolveResources() {
116
118
  return this.resourcesOpened ??= Promise.resolve(typeof this.resourcesInput === "function" ? this.resourcesInput(this.doEnv) : this.resourcesInput ?? {});
@@ -145,6 +147,11 @@ var AgentDurableObject = class {
145
147
  this.onInputAnnouncement = def.onInputAnnouncement;
146
148
  this.storage = state.storage;
147
149
  const name = def.name ?? "agent";
150
+ this.files = def.files ?? blobFileStore(async () => {
151
+ const blob = (await this.resolveResources()).blob;
152
+ if (!blob) throw new FatalToolError(`agent "${name}": no file store — declare a blob resource (DoAgentDef.resources) or pass DoAgentDef.files`);
153
+ return blob;
154
+ });
148
155
  const sink = new InProcEventSink();
149
156
  sink.subscribe((e) => {
150
157
  if (e.type === "turn.started") this.armWatchdog();
@@ -202,6 +209,7 @@ var AgentDurableObject = class {
202
209
  if (key !== void 0 && key !== "self" && stored === void 0) this.store.setSessionKey(key);
203
210
  this.sessionKey = resolved;
204
211
  this.session = new AgentSession(this.name, resolved, this.store, this.sink, this.model, this.tools, crossDoUnsupported, this.channelInstructions);
212
+ this.session.files = this.files;
205
213
  this.session.onDequeue = (heldTurnId, held) => {
206
214
  if (held.hostContext?.deliver && held.event) this.deliverHeld(this.session, heldTurnId, held.event);
207
215
  };
@@ -260,7 +268,10 @@ var AgentDurableObject = class {
260
268
  this.ready().then((resources) => runInScope({
261
269
  resources,
262
270
  services: this.services
263
- }, () => channel.deliver(target, events, { session: this.sessionKey }))).catch(logRenderFailure).finally(() => {
271
+ }, () => channel.deliver(target, events, {
272
+ session: this.sessionKey,
273
+ files: this.files
274
+ }))).catch(logRenderFailure).finally(() => {
264
275
  it.return?.();
265
276
  });
266
277
  } catch (err) {
@@ -355,7 +366,10 @@ var AgentDurableObject = class {
355
366
  Promise.resolve().then(() => runInScope({
356
367
  resources,
357
368
  services: this.services
358
- }, () => deliverChannel.deliver(target, events, { session: this.sessionKey }))).catch(logRenderFailure).finally(() => {
369
+ }, () => deliverChannel.deliver(target, events, {
370
+ session: this.sessionKey,
371
+ files: this.files
372
+ }))).catch(logRenderFailure).finally(() => {
359
373
  it.return?.();
360
374
  });
361
375
  } catch (err) {
@@ -419,7 +433,10 @@ var AgentDurableObject = class {
419
433
  Promise.resolve().then(() => runInScope({
420
434
  resources,
421
435
  services: this.services
422
- }, () => resumeChannel.deliverResume(target, events, { session: this.sessionKey }))).catch(logRenderFailure).finally(() => {
436
+ }, () => resumeChannel.deliverResume(target, events, {
437
+ session: this.sessionKey,
438
+ files: this.files
439
+ }))).catch(logRenderFailure).finally(() => {
423
440
  it.return?.();
424
441
  });
425
442
  } catch (err) {
@@ -612,6 +629,7 @@ function durableChannelSurface(getNamespace, opts) {
612
629
  },
613
630
  services: resolveServices(opts.services, opts.env, opts.agentName),
614
631
  waitUntil: opts.waitUntil,
632
+ files: opts.files,
615
633
  run: async (message, o) => {
616
634
  const namespace = getNamespace();
617
635
  if (!namespace) throw new Error("durableChannelSurface: no Durable Object namespace bound (env.AGENT)");
@@ -1,6 +1,7 @@
1
1
  import { SyncSqlite } from "./sqlite-driver.js";
2
2
  import { AgentDefinition, ChannelContext } from "@junejs/core/agent-config";
3
3
  import { AgentSession, ChannelPolicy, InputAnnouncement, Model, Runtime, Tool } from "@junejs/core/agent-runtime";
4
+ import { FileStore } from "@junejs/core/agent-files";
4
5
  //#region src/agent-native.d.ts
5
6
  export type AgentDef = {
6
7
  model: Model;
@@ -12,6 +13,7 @@ export type AgentDef = {
12
13
  export declare function toAgentDef(agent: AgentDefinition, model: Model): AgentDef;
13
14
  export type NativeRuntimeOptions = {
14
15
  maxSessions?: number;
16
+ files?: FileStore;
15
17
  };
16
18
  export declare class NativeRuntime implements Runtime {
17
19
  private actors;
@@ -19,11 +21,14 @@ export declare class NativeRuntime implements Runtime {
19
21
  private readonly db;
20
22
  private readonly announceRetry;
21
23
  private readonly maxSessions;
24
+ private closing;
25
+ readonly files: FileStore | undefined;
22
26
  constructor(agents: Record<string, AgentDef>, db: SyncSqlite, opts?: NativeRuntimeOptions);
23
27
  agentDef(name: string): AgentDef | undefined;
24
28
  session(agent: string, id: string): AgentSession;
25
29
  get sessionCount(): number;
26
30
  recoverAnnouncements(): void;
31
+ close(): Promise<void>;
27
32
  private evictIdle;
28
33
  }
29
34
  export declare function createNativeRuntime(agents: Record<string, AgentDef>, path?: string, opts?: NativeRuntimeOptions): Promise<NativeRuntime>;
@@ -32,20 +37,31 @@ export declare class MemoryRuntime implements Runtime {
32
37
  private stores;
33
38
  private readonly agents;
34
39
  private readonly announceRetry;
35
- constructor(agents: Record<string, AgentDef>);
40
+ private closed;
41
+ readonly files: FileStore | undefined;
42
+ constructor(agents: Record<string, AgentDef>, opts?: {
43
+ files?: FileStore;
44
+ });
36
45
  agentDef(name: string): AgentDef | undefined;
37
46
  session(agent: string, id: string): AgentSession;
47
+ close(): Promise<void>;
38
48
  }
39
49
  export type AgentBackend = "native" | "memory" | "durable";
50
+ export type InProcessRuntime = Runtime & {
51
+ close(): Promise<void>;
52
+ readonly files?: FileStore;
53
+ };
40
54
  export declare function createAgentRuntime(agents: Record<string, AgentDef>, opts?: {
41
55
  backend?: AgentBackend;
42
56
  path?: string;
43
57
  maxSessions?: number;
44
- }): Promise<Runtime>;
58
+ files?: FileStore;
59
+ }): Promise<InProcessRuntime>;
45
60
  export declare function mountAgent(agent: AgentDefinition, runtime: Runtime, opts?: {
46
61
  chatPath?: string;
47
62
  channels?: boolean;
48
63
  services?: unknown;
64
+ files?: FileStore;
49
65
  }): {
50
66
  surface: (req: Request) => Promise<Response | null>;
51
67
  fetch: (req: Request) => Promise<Response | null>;
@@ -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,10 +157,13 @@ var NativeRuntime = class {
149
157
  this.session(agent, id).flushAnnouncements();
150
158
  });
151
159
  maxSessions;
160
+ closing;
161
+ files;
152
162
  constructor(agents, db, opts = {}) {
153
163
  assertCoreRuntimeVersion("NativeRuntime");
154
164
  this.agents = agents;
155
165
  this.db = db;
166
+ this.files = opts.files;
156
167
  const max = opts.maxSessions ?? 1e3;
157
168
  if (!(Number.isInteger(max) && max >= 1) && max !== Infinity) throw new RangeError(`NativeRuntime: maxSessions must be an integer >= 1 (or Infinity for no cap), got ${max}`);
158
169
  this.maxSessions = max;
@@ -164,6 +175,7 @@ var NativeRuntime = class {
164
175
  session(agent, id) {
165
176
  const key = `${agent}:${id}`;
166
177
  const hit = this.actors.get(key);
178
+ if (!hit && this.closing) throw new Error(`NativeRuntime is closed: cannot open session "${key}"`);
167
179
  if (hit) {
168
180
  this.actors.delete(key);
169
181
  this.actors.set(key, hit);
@@ -173,7 +185,9 @@ var NativeRuntime = class {
173
185
  if (!def) throw new Error(`unknown agent: ${agent}`);
174
186
  const model = def.instructions ? withSystem(def.model, def.instructions) : def.model;
175
187
  const sink = new InProcEventSink();
176
- const session = wireAnnouncements(new AgentSession(agent, id, new SqliteSessionStore(this.db, key), sink, model, def.tools, this, def.channelInstructions), def, this.announceRetry);
188
+ const built = new AgentSession(agent, id, new SqliteSessionStore(this.db, key), sink, model, def.tools, this, def.channelInstructions);
189
+ built.files = this.files;
190
+ const session = wireAnnouncements(built, def, this.announceRetry);
177
191
  this.evictIdle();
178
192
  this.actors.set(key, {
179
193
  session,
@@ -191,6 +205,18 @@ var NativeRuntime = class {
191
205
  if (first && this.agents[first.agent]?.onInputAnnouncement) this.session(first.agent, first.session);
192
206
  }
193
207
  }
208
+ close() {
209
+ this.closing ??= (async () => {
210
+ this.announceRetry.stop();
211
+ while ([...this.actors.values()].some((a) => !a.session.idle())) await new Promise((r) => setTimeout(r, 10));
212
+ this.actors.clear();
213
+ if (ownedDbs.has(this.db)) {
214
+ ownedDbs.delete(this.db);
215
+ this.db.close();
216
+ }
217
+ })();
218
+ return this.closing;
219
+ }
194
220
  evictIdle() {
195
221
  if (this.actors.size < this.maxSessions) return;
196
222
  for (const [key, a] of this.actors) {
@@ -200,9 +226,21 @@ var NativeRuntime = class {
200
226
  }
201
227
  };
202
228
  async function createNativeRuntime(agents, path = ":memory:", opts = {}) {
203
- const runtime = new NativeRuntime(agents, await openLocalSqliteSync(path), opts);
204
- runtime.recoverAnnouncements();
205
- return runtime;
229
+ const db = await openLocalSqliteSync(path);
230
+ ownedDbs.add(db);
231
+ let runtime;
232
+ try {
233
+ runtime = new NativeRuntime(agents, db, opts);
234
+ runtime.recoverAnnouncements();
235
+ return runtime;
236
+ } catch (err) {
237
+ if (runtime) await runtime.close();
238
+ else {
239
+ ownedDbs.delete(db);
240
+ db.close();
241
+ }
242
+ throw err;
243
+ }
206
244
  }
207
245
  var MemorySessionStore = class {
208
246
  msgs = [];
@@ -259,9 +297,12 @@ var MemoryRuntime = class {
259
297
  announceRetry = new AnnouncementRetry((agent, id) => {
260
298
  this.session(agent, id).flushAnnouncements();
261
299
  });
262
- constructor(agents) {
300
+ closed = false;
301
+ files;
302
+ constructor(agents, opts = {}) {
263
303
  assertCoreRuntimeVersion("MemoryRuntime");
264
304
  this.agents = agents;
305
+ this.files = opts.files;
265
306
  }
266
307
  agentDef(name) {
267
308
  return this.agents[name];
@@ -270,21 +311,33 @@ var MemoryRuntime = class {
270
311
  const key = `${agent}:${id}`;
271
312
  let a = this.actors.get(key);
272
313
  if (!a) {
314
+ if (this.closed) throw new Error(`MemoryRuntime is closed: cannot open session "${key}"`);
273
315
  const def = this.agents[agent];
274
316
  if (!def) throw new Error(`unknown agent: ${agent}`);
275
317
  const store = new MemorySessionStore();
276
318
  this.stores.set(key, store);
277
319
  const model = def.instructions ? withSystem(def.model, def.instructions) : def.model;
278
- a = wireAnnouncements(new AgentSession(agent, id, store, new InProcEventSink(), model, def.tools, this, def.channelInstructions), def, this.announceRetry);
320
+ const built = new AgentSession(agent, id, store, new InProcEventSink(), model, def.tools, this, def.channelInstructions);
321
+ built.files = this.files;
322
+ a = wireAnnouncements(built, def, this.announceRetry);
279
323
  this.actors.set(key, a);
280
324
  }
281
325
  return a;
282
326
  }
327
+ async close() {
328
+ this.closed = true;
329
+ this.announceRetry.stop();
330
+ this.actors.clear();
331
+ this.stores.clear();
332
+ }
283
333
  };
284
334
  async function createAgentRuntime(agents, opts = {}) {
285
335
  const backend = opts.backend ?? "native";
286
- if (backend === "memory") return new MemoryRuntime(agents);
287
- if (backend === "native") return createNativeRuntime(agents, opts.path, { maxSessions: opts.maxSessions });
336
+ if (backend === "memory") return new MemoryRuntime(agents, { files: opts.files });
337
+ if (backend === "native") return createNativeRuntime(agents, opts.path, {
338
+ maxSessions: opts.maxSessions,
339
+ files: opts.files
340
+ });
288
341
  throw new Error("backend 'durable' is the Cloudflare Durable Object target — construct AgentDurableObject in your worker, not via createAgentRuntime");
289
342
  }
290
343
  function warnOnDrift(agent, runtime) {
@@ -304,6 +357,7 @@ function mountAgent(agent, runtime, opts = {}) {
304
357
  const ctx = {
305
358
  agent,
306
359
  services: opts.services,
360
+ files: opts.files ?? runtime.files,
307
361
  run: (message, o) => runtime.session(agent.name, o?.session ?? "default").turn({
308
362
  turnId: o?.turnId,
309
363
  userText: message,
package/dist/app.d.ts CHANGED
@@ -9,6 +9,7 @@ export type JuneApp = {
9
9
  warmup(): Promise<void>;
10
10
  routePaths(): Promise<string[]>;
11
11
  earlyHints(): string[];
12
+ close(): Promise<void>;
12
13
  };
13
14
  export declare function createApp({ appDir: appDirInput, config }: CreateAppOptions): JuneApp;
14
15
  //#endregion
package/dist/app.js CHANGED
@@ -1,9 +1,11 @@
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";
8
+ import { localBlob } from "./blob.js";
7
9
  import { MODULE_STYLES_URL, buildModuleCss, registerCssModules } from "./css-modules.js";
8
10
  import { CLIENT_SCRIPT_URL, bundleClientSplit, findClientEntry } from "./client-bundle.js";
9
11
  import { generateIslandRegistry } from "./island-registry.js";
@@ -14,6 +16,7 @@ import { existsSync, lstatSync, realpathSync } from "node:fs";
14
16
  import { readFile } from "node:fs/promises";
15
17
  import { dirname, join, resolve } from "node:path";
16
18
  import { pathToFileURL } from "node:url";
19
+ import { blobFileStore, memoryFileStore } from "@junejs/core/agent-files";
17
20
  import { routeFromModule } from "@junejs/core/route";
18
21
  import { deployOrigin, resolveAgent, resolveClientRouter, resolveSpeculationRules } from "@junejs/core/config";
19
22
  import { runWithTrace } from "@junejs/core/instrumentation";
@@ -115,6 +118,7 @@ function createApp({ appDir: appDirInput, config = {} }) {
115
118
  config.dataLayer?.install();
116
119
  let pipelinePromise;
117
120
  const getPipeline = () => pipelinePromise ??= buildPipeline();
121
+ let agentRuntime;
118
122
  async function buildPipeline() {
119
123
  const { maps, css } = await getModuleCss();
120
124
  await registerCssModules(maps);
@@ -137,7 +141,13 @@ function createApp({ appDir: appDirInput, config = {} }) {
137
141
  const def = await discoverAgent(agentDir);
138
142
  const backend = agent.runtime.backend === "durable" ? "native" : agent.runtime.backend;
139
143
  const model = anthropic({ model: def.model });
140
- const rt = await createAgentRuntime({ [def.name]: toAgentDef(def, model) }, { backend });
144
+ let blobOpened;
145
+ const files = backend === "memory" ? memoryFileStore() : blobFileStore(() => blobOpened ??= resources().then(async (r) => r.blob ?? await localBlob().open()));
146
+ const rt = await createAgentRuntime({ [def.name]: toAgentDef(def, model) }, {
147
+ backend,
148
+ files
149
+ });
150
+ agentRuntime = rt;
141
151
  const mounted = mountAgent(def, rt, {
142
152
  chatPath: agent.runtime.chat.path,
143
153
  channels: agent.runtime.channels
@@ -257,6 +267,8 @@ function createApp({ appDir: appDirInput, config = {} }) {
257
267
  return toPipeline();
258
268
  },
259
269
  async warmup() {
270
+ const problems = routeProblems([await scanRoutes(appDir), hasJuneRoutes ? await scanRoutes(juneRoutesDir) : []], dirname(appDir));
271
+ if (problems) console.error(problems);
260
272
  const files = await routeFiles(appDir, { pageConvention: true });
261
273
  if (hasJuneRoutes) files.push(...await routeFiles(juneRoutesDir, { pageConvention: true }));
262
274
  for (const file of files) await import(pathToFileURL(file).href).catch((err) => {
@@ -264,7 +276,11 @@ function createApp({ appDir: appDirInput, config = {} }) {
264
276
  });
265
277
  },
266
278
  routePaths,
267
- earlyHints: () => config.earlyHints ?? []
279
+ earlyHints: () => config.earlyHints ?? [],
280
+ async close() {
281
+ await pipelinePromise?.catch(() => {});
282
+ await agentRuntime?.close();
283
+ }
268
284
  };
269
285
  }
270
286
  //#endregion
package/dist/build.d.ts CHANGED
@@ -1,7 +1,7 @@
1
- import { n as scanAppRoutes, r as scanRoutes, t as RouteEntry } from "./route-scan-DMlwoESy.js";
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-ZWC_Qd4h.js";
4
- import { n as buildManifest } from "./manifest-DSNX4I-G.js";
3
+ import { i as workerName, n as normalizeBase, r as resolveDeployAdapter, t as freezeConfig } from "./config-freeze-CyXvNqi2.js";
4
+ import { n as buildManifest } from "./manifest-CwTT1zVs.js";
5
5
  //#region src/build.d.ts
6
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-Dv4l6Ybs.js";
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
@@ -1,2 +1,2 @@
1
- import { i as workerName, n as normalizeBase, r as resolveDeployAdapter, t as freezeConfig } from "./config-freeze-ZWC_Qd4h.js";
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 };
@@ -1,6 +1,6 @@
1
1
  import * as coreRuntime from "@junejs/core/agent-runtime";
2
2
  //#region src/core-version.ts
3
- const EXPECTED_CORE_RUNTIME_API = 6;
3
+ const EXPECTED_CORE_RUNTIME_API = 7;
4
4
  function assertCoreRuntimeVersion(surface) {
5
5
  checkCoreRuntimeVersion(surface, coreRuntime.RUNTIME_API_VERSION);
6
6
  }
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 type DevServer = ServeHandle & {
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
- async function findFreePort(start, tries = 20) {
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 config = await loadJuneConfig(appDir);
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 = `http://localhost:${handle.port}`;
48
- console.log(`june dev → ${url} (host: ${host$1.name})`);
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 { r as scanRoutes } from "./route-scan-DMlwoESy.js";
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-Dv4l6Ybs.js";
9
- import { t as freezeConfig } from "./config-freeze-ZWC_Qd4h.js";
10
- import { n as buildManifest } from "./manifest-DSNX4I-G.js";
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,18 +1,18 @@
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";
7
8
  import { bindWorkerResources, memoizeResources } from "./resources.js";
8
- import { createApp } from "./app.js";
9
9
  import { localBlob, r2 } from "./blob.js";
10
+ import { createApp } from "./app.js";
10
11
  import { loadJuneConfig } from "./config-loader.js";
11
12
  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-Dv4l6Ybs.js";
2
+ import { n as WorkerManifest } from "./worker-2qbQjj2c.js";
3
3
  //#region src/manifest.d.ts
4
4
  type ImportedLayout = {
5
5
  component: LayoutComponent;
@@ -1,2 +1,2 @@
1
- import { n as buildManifest, r as importLayout, t as ImportedLayout } from "./manifest-DSNX4I-G.js";
1
+ import { n as buildManifest, r as importLayout, t as ImportedLayout } from "./manifest-CwTT1zVs.js";
2
2
  export { ImportedLayout, buildManifest, importLayout };