@junejs/server 1.0.0-dev.17 → 1.0.0-dev.20

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.
@@ -0,0 +1,62 @@
1
+ import { JuneConfig } from "@junejs/core/config";
2
+ //#region src/adapter.d.ts
3
+ type AdapterCapabilities = {
4
+ runtime: "edge" | "node" | "serverless" | "native" | "static";
5
+ persistentConnections: boolean;
6
+ assets: "platform" | "server" | "none";
7
+ durableObjects?: boolean;
8
+ };
9
+ type AdapterEntry = {
10
+ imports: string[];
11
+ wrap(pipelineVar: string): string;
12
+ };
13
+ type ResourcePlan = {
14
+ db?: {
15
+ binding: string;
16
+ databaseName: string;
17
+ };
18
+ agent?: {
19
+ binding: string;
20
+ className: string;
21
+ };
22
+ };
23
+ type AdapterEmitContext = {
24
+ appRoot: string;
25
+ outDir: string;
26
+ hasAssets: boolean;
27
+ linkHeader: string | null;
28
+ config: JuneConfig;
29
+ plan: ResourcePlan;
30
+ defaultName: string;
31
+ publicFiles?: string[];
32
+ };
33
+ interface JuneAdapter {
34
+ readonly name: string;
35
+ readonly capabilities: AdapterCapabilities;
36
+ readonly conditions: string[];
37
+ readonly buildExternal?: string[];
38
+ validate?(ctx: {
39
+ plan: ResourcePlan;
40
+ config: JuneConfig;
41
+ }): void;
42
+ entry(opts: {
43
+ linkHeader: string | null;
44
+ }): AdapterEntry;
45
+ emit(ctx: AdapterEmitContext): Promise<void>;
46
+ }
47
+ declare function hasDurableBinding(text: string, file: string, binding: string, className: string): boolean;
48
+ declare function workers(opts?: {
49
+ name?: string;
50
+ domain?: string;
51
+ }): JuneAdapter;
52
+ declare function vercel(opts?: {
53
+ runtime?: "node" | "edge";
54
+ regions?: string[];
55
+ }): JuneAdapter;
56
+ declare function deno(opts?: {
57
+ org?: string;
58
+ app?: string;
59
+ }): JuneAdapter;
60
+ declare function staticSite(): JuneAdapter;
61
+ //#endregion
62
+ export { ResourcePlan as a, staticSite as c, JuneAdapter as i, vercel as l, AdapterEmitContext as n, deno as o, AdapterEntry as r, hasDurableBinding as s, AdapterCapabilities as t, workers as u };
package/dist/adapter.d.ts CHANGED
@@ -1,62 +1,2 @@
1
- import { JuneConfig } from "@junejs/core/config";
2
- //#region src/adapter.d.ts
3
- type AdapterCapabilities = {
4
- runtime: "edge" | "node" | "serverless" | "native" | "static";
5
- persistentConnections: boolean;
6
- assets: "platform" | "server" | "none";
7
- durableObjects?: boolean;
8
- };
9
- type AdapterEntry = {
10
- imports: string[];
11
- wrap(pipelineVar: string): string;
12
- };
13
- type ResourcePlan = {
14
- db?: {
15
- binding: string;
16
- databaseName: string;
17
- };
18
- agent?: {
19
- binding: string;
20
- className: string;
21
- };
22
- };
23
- type AdapterEmitContext = {
24
- appRoot: string;
25
- outDir: string;
26
- hasAssets: boolean;
27
- linkHeader: string | null;
28
- config: JuneConfig;
29
- plan: ResourcePlan;
30
- defaultName: string;
31
- publicFiles?: string[];
32
- };
33
- interface JuneAdapter {
34
- readonly name: string;
35
- readonly capabilities: AdapterCapabilities;
36
- readonly conditions: string[];
37
- readonly buildExternal?: string[];
38
- validate?(ctx: {
39
- plan: ResourcePlan;
40
- config: JuneConfig;
41
- }): void;
42
- entry(opts: {
43
- linkHeader: string | null;
44
- }): AdapterEntry;
45
- emit(ctx: AdapterEmitContext): Promise<void>;
46
- }
47
- declare function hasDurableBinding(text: string, file: string, binding: string, className: string): boolean;
48
- declare function workers(opts?: {
49
- name?: string;
50
- domain?: string;
51
- }): JuneAdapter;
52
- declare function vercel(opts?: {
53
- runtime?: "node" | "edge";
54
- regions?: string[];
55
- }): JuneAdapter;
56
- declare function deno(opts?: {
57
- org?: string;
58
- app?: string;
59
- }): JuneAdapter;
60
- declare function staticSite(): JuneAdapter;
61
- //#endregion
1
+ import { a as ResourcePlan, c as staticSite, i as JuneAdapter, l as vercel, n as AdapterEmitContext, o as deno, r as AdapterEntry, s as hasDurableBinding, t as AdapterCapabilities, u as workers } from "./adapter-DcZ-W1-7.js";
62
2
  export { AdapterCapabilities, AdapterEmitContext, AdapterEntry, JuneAdapter, ResourcePlan, deno, hasDurableBinding, staticSite, vercel, workers };
@@ -5,6 +5,10 @@ type AgentDirScan = {
5
5
  name: string;
6
6
  hasConfig: boolean;
7
7
  instructions: string | null;
8
+ surfaceVariants: {
9
+ source: string;
10
+ raw: string;
11
+ }[];
8
12
  tools: string[];
9
13
  skills: {
10
14
  name: string;
@@ -15,6 +15,10 @@ function scanAgentDir(dir) {
15
15
  name: basename(dir),
16
16
  hasConfig: existsSync(join(dir, "agent.ts")),
17
17
  instructions: existsSync(instructionsFile) ? readFileSync(instructionsFile, "utf8") : null,
18
+ surfaceVariants: readdirSync(dir, { withFileTypes: true }).filter((e) => e.isFile()).map((e) => e.name.match(/^instructions\.([a-z0-9_-]+)\.md$/)).filter((m) => m !== null).sort((a, b) => a[1].localeCompare(b[1])).map((m) => ({
19
+ source: m[1],
20
+ raw: readFileSync(join(dir, m[0]), "utf8")
21
+ })),
18
22
  tools: list(join(dir, "tools"), ".ts").map((f) => `./tools/${f}`),
19
23
  skills: list(join(dir, "skills"), ".md").map((f) => ({
20
24
  name: basename(f, ".md"),
@@ -27,7 +31,7 @@ function scanAgentDir(dir) {
27
31
  })),
28
32
  connections: list(join(dir, "connections"), ".ts").map((f) => `./connections/${f}`)
29
33
  };
30
- return !scan.hasConfig && scan.instructions === null && !scan.tools.length && !scan.skills.length && !scan.channels.length && !scan.channelOverlays.length && !scan.connections.length ? null : scan;
34
+ return !scan.hasConfig && scan.instructions === null && !scan.tools.length && !scan.skills.length && !scan.channels.length && !scan.surfaceVariants.length && !scan.channelOverlays.length && !scan.connections.length ? null : scan;
31
35
  }
32
36
  function identFor(prefix, spec, taken) {
33
37
  const stem = basename(spec).replace(/\.ts$/, "").replace(/[^A-Za-z0-9]/g, "_");
@@ -68,7 +72,7 @@ function emitAgentModule(scan, opts) {
68
72
  ""
69
73
  ];
70
74
  if (!scan.hasConfig) lines.push(`const config = { name: ${JSON.stringify(scan.name)} };`, "");
71
- lines.push("export const agentModule: AgentModule = {", " config,", ` instructions: ${JSON.stringify(scan.instructions ?? "")},`, ` tools: [${toolIds.join(", ")}],`, scan.skills.length ? ` skills: [\n${scan.skills.map((s) => ` parseSkill(${JSON.stringify(s.name)}, ${JSON.stringify(s.raw)}),`).join("\n")}\n ],` : " skills: [],", channelIds.length ? ` channels: { ${channelIds.map((c) => `${JSON.stringify(c.key)}: ${c.id}`).join(", ")} },` : " channels: {},", scan.channelOverlays.length ? ` channelInstructions: {\n${scan.channelOverlays.map((o) => ` ${JSON.stringify(o.source)}: ${JSON.stringify(o.raw)},`).join("\n")}\n },` : " channelInstructions: {},", ` connections: [${connectionIds.join(", ")}],`, "};", "export default agentModule;", "");
75
+ lines.push("export const agentModule: AgentModule = {", " config,", ` instructions: ${JSON.stringify(scan.instructions ?? "")},`, scan.surfaceVariants.length ? ` surfaceInstructions: {\n${scan.surfaceVariants.map((v) => ` ${JSON.stringify(v.source)}: ${JSON.stringify(v.raw)},`).join("\n")}\n },` : " surfaceInstructions: {},", ` tools: [${toolIds.join(", ")}],`, scan.skills.length ? ` skills: [\n${scan.skills.map((s) => ` parseSkill(${JSON.stringify(s.name)}, ${JSON.stringify(s.raw)}),`).join("\n")}\n ],` : " skills: [],", channelIds.length ? ` channels: { ${channelIds.map((c) => `${JSON.stringify(c.key)}: ${c.id}`).join(", ")} },` : " channels: {},", scan.channelOverlays.length ? ` channelInstructions: {\n${scan.channelOverlays.map((o) => ` ${JSON.stringify(o.source)}: ${JSON.stringify(o.raw)},`).join("\n")}\n },` : " channelInstructions: {},", ` connections: [${connectionIds.join(", ")}],`, "};", "export default agentModule;", "");
72
76
  return lines.join("\n");
73
77
  }
74
78
  function findAgentDir(root, dirName = "agent") {
@@ -118,6 +122,8 @@ function sniffTsExtensions(dir) {
118
122
  function generateAgentModule(dir, opts) {
119
123
  const scan = scanAgentDir(dir);
120
124
  if (!scan) return null;
125
+ for (const o of scan.channelOverlays) console.warn(`[june] deprecated: channels/${o.source}.md — move it to instructions.${o.source}.md at the agent root (per-surface behavior is agent-level; see junebuild/june#149).`);
126
+ for (const e of readdirSync(dir, { withFileTypes: true })) if (e.isFile() && /^instructions\..+\.md$/.test(e.name) && !/^instructions\.[a-z0-9_-]+\.md$/.test(e.name)) console.warn(`[june] ${e.name}: unrecognized instructions variant — only single-segment sources (instructions.<source>.md) are parsed today; locale variants are a planned follow-up (junebuild/june#149). This file is ignored.`);
121
127
  const code = emitAgentModule(scan, { tsExtensions: opts?.tsExtensions ?? sniffTsExtensions(dir) });
122
128
  const file = join(dir, AGENT_MODULE_FILE);
123
129
  const stale = (existsSync(file) ? readFileSync(file, "utf8") : null) !== code;
@@ -13,6 +13,13 @@ async function discoverAgentModule(dir) {
13
13
  const config = existsSync(configFile) ? (await import(pathToFileURL(configFile).href)).default : { name: basename(dir) };
14
14
  const instructionsFile = join(dir, "instructions.md");
15
15
  const instructions = existsSync(instructionsFile) ? await readFile(instructionsFile, "utf8") : "";
16
+ const surfaceInstructions = {};
17
+ if (existsSync(dir)) for (const e of await readdir(dir, { withFileTypes: true })) {
18
+ if (!e.isFile() || !/^instructions\..+\.md$/.test(e.name)) continue;
19
+ const m = e.name.match(/^instructions\.([a-z0-9_-]+)\.md$/);
20
+ if (m) surfaceInstructions[m[1]] = await readFile(join(dir, e.name), "utf8");
21
+ else console.warn(`[june] ${e.name}: unrecognized instructions variant — only single-segment sources (instructions.<source>.md) are parsed today; locale variants are a planned follow-up (junebuild/june#149). This file is ignored.`);
22
+ }
16
23
  const tools = [];
17
24
  for (const f of await scan(join(dir, "tools"), ".ts")) {
18
25
  const mod = await import(pathToFileURL(f).href);
@@ -26,7 +33,11 @@ async function discoverAgentModule(dir) {
26
33
  if (mod.default) channels[basename(f, ".ts")] = mod.default;
27
34
  }
28
35
  const channelInstructions = {};
29
- for (const f of await scan(join(dir, "channels"), ".md")) channelInstructions[basename(f, ".md")] = await readFile(f, "utf8");
36
+ for (const f of await scan(join(dir, "channels"), ".md")) {
37
+ const source = basename(f, ".md");
38
+ console.warn(`[june] deprecated: channels/${source}.md — move it to instructions.${source}.md at the agent root (per-surface behavior is agent-level; see junebuild/june#149).`);
39
+ channelInstructions[source] = await readFile(f, "utf8");
40
+ }
30
41
  const connections = [];
31
42
  for (const f of await scan(join(dir, "connections"), ".ts")) {
32
43
  const mod = await import(pathToFileURL(f).href);
@@ -35,6 +46,7 @@ async function discoverAgentModule(dir) {
35
46
  return {
36
47
  config,
37
48
  instructions,
49
+ surfaceInstructions,
38
50
  tools,
39
51
  skills,
40
52
  channels,
@@ -1,5 +1,6 @@
1
1
  import { Channel, ChannelFactory } from "@junejs/core/agent-config";
2
- import { InboundEvent, Model, Msg, ProactiveTrigger, SessionStore, Tool, TurnError, TurnEvent, TurnFailurePhase } from "@junejs/core/agent-runtime";
2
+ import { ChannelPolicy, InboundEvent, Model, Msg, ProactiveTrigger, SessionStore, Tool, TurnError, TurnEvent, TurnFailurePhase } from "@junejs/core/agent-runtime";
3
+ import { Connection } from "@junejs/core/connections";
3
4
  import { Resources } from "@junejs/core/resources";
4
5
  //#region src/agent-durable.d.ts
5
6
  type SqlStorageValue = ArrayBuffer | string | number | null;
@@ -47,10 +48,11 @@ type DoAgentDef = {
47
48
  model: Model;
48
49
  tools: Tool[];
49
50
  instructions?: string;
50
- channelInstructions?: Record<string, string>;
51
+ channelInstructions?: Record<string, string | ChannelPolicy>;
51
52
  channels?: (Channel | ChannelFactory)[];
52
53
  env?: unknown;
53
54
  resources?: Resources | ((env: unknown) => Promise<Resources> | Resources);
55
+ connections?: Connection[];
54
56
  services?: unknown;
55
57
  onTurnError?: (failure: {
56
58
  turnId: string;
@@ -71,9 +73,13 @@ declare class AgentDurableObject {
71
73
  private readonly channelInstructions?;
72
74
  private readonly resourcesInput;
73
75
  private resourcesOpened;
76
+ private readonly connectionsInput;
77
+ private connectionsOpened;
74
78
  private readonly doEnv;
75
79
  private readonly services;
76
80
  private resolveResources;
81
+ private resolveConnections;
82
+ private ready;
77
83
  constructor(state: DurableObjectState, def: DoAgentDef);
78
84
  private resolveSession;
79
85
  turn(input: {
@@ -1,7 +1,8 @@
1
1
  import { isolateLocal } from "./isolate-local.js";
2
2
  import { assertCoreRuntimeVersion } from "./core-version.js";
3
- import { DeliverUnsupportedError, channelDispatch, resolveChannel } from "@junejs/core/agent-config";
3
+ import { DeliverUnsupportedError, actionToTool, channelDispatch, resolveChannel } from "@junejs/core/agent-config";
4
4
  import { AgentSession, ResumeAuthorizationError, withSystem } from "@junejs/core/agent-runtime";
5
+ import { connectAll } from "@junejs/core/connections";
5
6
  import { ensureScope, runInScope } from "@junejs/db";
6
7
  //#region src/agent-durable.ts
7
8
  var DoSessionStore = class {
@@ -101,16 +102,37 @@ var AgentDurableObject = class {
101
102
  channelInstructions;
102
103
  resourcesInput;
103
104
  resourcesOpened;
105
+ connectionsInput;
106
+ connectionsOpened;
104
107
  doEnv;
105
108
  services;
106
109
  resolveResources() {
107
110
  return this.resourcesOpened ??= Promise.resolve(typeof this.resourcesInput === "function" ? this.resourcesInput(this.doEnv) : this.resourcesInput ?? {});
108
111
  }
112
+ resolveConnections() {
113
+ return this.connectionsOpened ??= (async () => {
114
+ if (!this.connectionsInput?.length) return;
115
+ const { actions, report } = await connectAll(this.connectionsInput);
116
+ for (const r of report) if (r.error) console.error(`[june] agent "${this.name}": connection "${r.name}" (${r.url}) failed: ${r.error}`);
117
+ const seen = new Set(this.tools.map((t) => t.spec.name));
118
+ for (const a of actions) {
119
+ const tool = actionToTool(a);
120
+ if (seen.has(tool.spec.name)) throw new Error(`AgentDurableObject(${this.name}): duplicate tool name "${tool.spec.name}" from a connection — rename so dispatch is unambiguous.`);
121
+ seen.add(tool.spec.name);
122
+ this.tools.push(tool);
123
+ }
124
+ })();
125
+ }
126
+ async ready() {
127
+ const [resources] = await Promise.all([this.resolveResources(), this.resolveConnections()]);
128
+ return resources;
129
+ }
109
130
  constructor(state, def) {
110
131
  assertCoreRuntimeVersion(`AgentDurableObject(${def.name ?? "agent"})`);
111
132
  const store = new DoSessionStore(state.storage);
112
133
  const model = def.instructions ? withSystem(def.model, def.instructions) : def.model;
113
134
  this.resourcesInput = def.resources;
135
+ this.connectionsInput = def.connections;
114
136
  this.doEnv = def.env;
115
137
  this.services = def.services;
116
138
  const name = def.name ?? "agent";
@@ -151,6 +173,10 @@ var AgentDurableObject = class {
151
173
  this.tools = tools;
152
174
  this.channels = channels;
153
175
  this.channelInstructions = def.channelInstructions;
176
+ if (def.channelInstructions) {
177
+ const names = new Set(channels.map((c) => c.name));
178
+ for (const source of Object.keys(def.channelInstructions)) if (!names.has(source)) console.warn(`[june] agent "${name}": surface policy "${source}" matches no channel wired into this DO (${[...names].join(", ") || "none"}) — it will never fire.`);
179
+ }
154
180
  }
155
181
  resolveSession(key) {
156
182
  if (key !== void 0) assertSessionKey(key);
@@ -168,7 +194,7 @@ var AgentDurableObject = class {
168
194
  }
169
195
  async turn(input) {
170
196
  await ensureScope();
171
- const resources = await this.resolveResources();
197
+ const resources = await this.ready();
172
198
  const session = this.resolveSession(input.session);
173
199
  return runInScope({
174
200
  resources,
@@ -177,7 +203,7 @@ var AgentDurableObject = class {
177
203
  }
178
204
  async start(input) {
179
205
  await ensureScope();
180
- const resources = await this.resolveResources();
206
+ const resources = await this.ready();
181
207
  const session = this.resolveSession(input.session);
182
208
  return runInScope({
183
209
  resources,
@@ -206,7 +232,7 @@ var AgentDurableObject = class {
206
232
  deliverChannel = this.channels.find((c) => c.name === event.source);
207
233
  if (!deliverChannel?.deliver) return Response.json({ error: `agent "${this.name}": no deliver()-capable channel named "${event.source}" is wired into this DO (DoAgentDef.channels) — the turn was NOT started` }, { status: 501 });
208
234
  }
209
- const resources = await this.resolveResources();
235
+ const resources = await this.ready();
210
236
  let session;
211
237
  let started;
212
238
  try {
@@ -259,7 +285,7 @@ var AgentDurableObject = class {
259
285
  resumeChannel = this.channels.find((c) => c.name === source);
260
286
  if (!resumeChannel?.deliverResume) return Response.json({ error: `agent "${this.name}": no deliverResume()-capable channel named "${source}" is wired into this DO (DoAgentDef.channels) — the answer was NOT applied` }, { status: 501 });
261
287
  }
262
- const resources = await this.resolveResources();
288
+ const resources = await this.ready();
263
289
  let session;
264
290
  try {
265
291
  session = this.resolveSession(key);
package/dist/build.d.ts CHANGED
@@ -1,7 +1,7 @@
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";
1
+ import { n as scanAppRoutes, r as scanRoutes, t as RouteEntry } from "./route-scan-DMlwoESy.js";
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-DwI-Rmvq.js";
4
+ import { n as buildManifest } from "./manifest-gcNWqWoI.js";
5
5
  //#region src/build.d.ts
6
6
  type BuildResult = {
7
7
  outFile: string;
@@ -10,31 +10,10 @@ type BuildResult = {
10
10
  contentCollections: string[];
11
11
  prerendered: string[];
12
12
  };
13
- type RouteEntry = {
14
- path: string;
15
- file: string;
16
- dynamic: boolean;
17
- resource?: boolean;
18
- layouts: string[];
19
- loading?: string;
20
- };
21
13
  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
14
  declare function juneBuild(appRoot: string, options?: {
36
15
  outDir?: string;
37
16
  external?: string[];
38
17
  }): Promise<BuildResult>;
39
18
  //#endregion
40
- export { BuildResult, buildManifest, freezeConfig, generateContent, isBunSpecifier, juneBuild, normalizeBase, resolveDeployAdapter, scanRoutes, workerName };
19
+ export { BuildResult, type RouteEntry, buildManifest, freezeConfig, generateContent, isBunSpecifier, juneBuild, normalizeBase, resolveDeployAdapter, scanAppRoutes, scanRoutes, workerName };