veryfront 0.1.58 → 0.1.60

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/esm/deno.js CHANGED
@@ -1,6 +1,6 @@
1
1
  export default {
2
2
  "name": "veryfront",
3
- "version": "0.1.58",
3
+ "version": "0.1.60",
4
4
  "license": "Apache-2.0",
5
5
  "nodeModulesDir": "auto",
6
6
  "exclude": [
@@ -26,6 +26,11 @@ export interface ChatHandlerOptions {
26
26
  */
27
27
  beforeStream?: ChatHandlerBeforeStream;
28
28
  }
29
+ /** Options when passing an agent instance directly. */
30
+ export interface ChatHandlerConfigWithAgent extends ChatHandlerOptions {
31
+ /** The agent instance to use (bypasses registry lookup). */
32
+ agent: import("./types.js").Agent;
33
+ }
29
34
  /**
30
35
  * Create a POST handler for a chat API route.
31
36
  *
@@ -33,11 +38,20 @@ export interface ChatHandlerOptions {
33
38
  * - App Router: `app/api/chat/route.ts` — handler receives `(request, context)`
34
39
  * - Pages Router: `pages/api/chat.ts` — handler receives `(ctx)`
35
40
  *
41
+ * Accepts either:
42
+ * - `createChatHandler("agentId", options?)` — looks up agent by ID from the registry
43
+ * - `createChatHandler({ agent, ...options })` — uses the provided agent instance directly
44
+ *
36
45
  * @example
37
46
  * ```ts
38
- * import { createChatHandler } from "veryfront/agent";
47
+ * // By agent ID (requires auto-discovery registration)
39
48
  * export const POST = createChatHandler("assistant");
49
+ *
50
+ * // By agent instance (no registry needed)
51
+ * import { myAgent } from "../../agents/my-agent";
52
+ * export const POST = createChatHandler({ agent: myAgent, beforeStream: ... });
40
53
  * ```
41
54
  */
42
55
  export declare function createChatHandler(agentId: string, options?: ChatHandlerOptions): (requestOrCtx: unknown) => Promise<dntShim.Response>;
56
+ export declare function createChatHandler(config: ChatHandlerConfigWithAgent, options?: ChatHandlerOptions): (requestOrCtx: unknown) => Promise<dntShim.Response>;
43
57
  //# sourceMappingURL=chat-handler.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"chat-handler.d.ts","sourceRoot":"","sources":["../../../src/src/agent/chat-handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,qBAAqB,CAAC;AAG/C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AA8K1C,MAAM,MAAM,uBAAuB,GAAG,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,GAAG;IAAE,EAAE,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAE5E,MAAM,WAAW,8BAA8B;IAC7C,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC;IACzB,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,6BAA6B;IAC5C,OAAO,CAAC,EAAE,uBAAuB,EAAE,CAAC;IACpC,MAAM,CAAC,EAAE,uBAAuB,EAAE,CAAC;IACnC,eAAe,CAAC,EAAE,uBAAuB,EAAE,CAAC;IAC5C,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAED,MAAM,MAAM,uBAAuB,GAAG,CACpC,KAAK,EAAE,8BAA8B,KAEnC,IAAI,GACJ,OAAO,CAAC,QAAQ,GAChB,6BAA6B,GAC7B,OAAO,CAAC,IAAI,GAAG,OAAO,CAAC,QAAQ,GAAG,6BAA6B,CAAC,CAAC;AAiCrE,mFAAmF;AACnF,MAAM,WAAW,kBAAkB;IACjC,uFAAuF;IACvF,OAAO,CAAC,EACJ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACvB,CAAC,CACD,OAAO,EAAE,OAAO,CAAC,OAAO,KACrB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;IACnE;;;OAGG;IACH,YAAY,CAAC,EAAE,uBAAuB,CAAC;CACxC;AAgDD;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,kBAAkB,IAED,cAAc,OAAO,KAAG,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CA+E7E"}
1
+ {"version":3,"file":"chat-handler.d.ts","sourceRoot":"","sources":["../../../src/src/agent/chat-handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,qBAAqB,CAAC;AAG/C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AA8K1C,MAAM,MAAM,uBAAuB,GAAG,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,GAAG;IAAE,EAAE,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAE5E,MAAM,WAAW,8BAA8B;IAC7C,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC;IACzB,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,6BAA6B;IAC5C,OAAO,CAAC,EAAE,uBAAuB,EAAE,CAAC;IACpC,MAAM,CAAC,EAAE,uBAAuB,EAAE,CAAC;IACnC,eAAe,CAAC,EAAE,uBAAuB,EAAE,CAAC;IAC5C,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAED,MAAM,MAAM,uBAAuB,GAAG,CACpC,KAAK,EAAE,8BAA8B,KAEnC,IAAI,GACJ,OAAO,CAAC,QAAQ,GAChB,6BAA6B,GAC7B,OAAO,CAAC,IAAI,GAAG,OAAO,CAAC,QAAQ,GAAG,6BAA6B,CAAC,CAAC;AAiCrE,mFAAmF;AACnF,MAAM,WAAW,kBAAkB;IACjC,uFAAuF;IACvF,OAAO,CAAC,EACJ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACvB,CAAC,CACD,OAAO,EAAE,OAAO,CAAC,OAAO,KACrB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;IACnE;;;OAGG;IACH,YAAY,CAAC,EAAE,uBAAuB,CAAC;CACxC;AAED,uDAAuD;AACvD,MAAM,WAAW,0BAA2B,SAAQ,kBAAkB;IACpE,4DAA4D;IAC5D,KAAK,EAAE,OAAO,YAAY,EAAE,KAAK,CAAC;CACnC;AAwDD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,kBAAkB,GAC3B,CAAC,YAAY,EAAE,OAAO,KAAK,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;AACxD,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,0BAA0B,EAClC,OAAO,CAAC,EAAE,kBAAkB,GAC3B,CAAC,YAAY,EAAE,OAAO,KAAK,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC"}
@@ -155,6 +155,11 @@ function applyBeforeStreamResult(baseMessages, result) {
155
155
  ...normalizeHookMessages(result.append, "append", idCounter),
156
156
  ];
157
157
  }
158
+ function mergeChatHandlerConfig(config, options) {
159
+ if (!options)
160
+ return config;
161
+ return { ...options, ...config };
162
+ }
158
163
  /**
159
164
  * Extract the raw Request from either a raw Request or a Pages Router APIContext.
160
165
  * Pages Router handlers receive `(ctx)` where `ctx.request` is the Request.
@@ -195,29 +200,26 @@ function extractRequest(requestOrCtx) {
195
200
  detail: "Invalid handler argument: expected Request or APIContext",
196
201
  });
197
202
  }
198
- /**
199
- * Create a POST handler for a chat API route.
200
- *
201
- * Works with both App Router and Pages Router:
202
- * - App Router: `app/api/chat/route.ts` — handler receives `(request, context)`
203
- * - Pages Router: `pages/api/chat.ts` — handler receives `(ctx)`
204
- *
205
- * @example
206
- * ```ts
207
- * import { createChatHandler } from "veryfront/agent";
208
- * export const POST = createChatHandler("assistant");
209
- * ```
210
- */
211
- export function createChatHandler(agentId, options) {
203
+ export function createChatHandler(agentIdOrConfig, options) {
212
204
  return async function POST(requestOrCtx) {
213
205
  const request = extractRequest(requestOrCtx);
214
206
  let agent;
215
- try {
216
- agent = getAgent(agentId);
207
+ if (typeof agentIdOrConfig === "object" && agentIdOrConfig !== null && "agent" in agentIdOrConfig) {
208
+ // Object-based API: createChatHandler({ agent, beforeStream, ... })
209
+ const config = mergeChatHandlerConfig(agentIdOrConfig, options);
210
+ agent = config.agent;
211
+ options = config;
217
212
  }
218
- catch (error) {
219
- agentLogger.debug("getAgent lookup failed", { error });
220
- return dntShim.Response.json({ error: "Agent not found" }, { status: 404 });
213
+ else {
214
+ // String-based API: createChatHandler("agentId", options?)
215
+ const agentId = agentIdOrConfig;
216
+ try {
217
+ agent = getAgent(agentId);
218
+ }
219
+ catch (error) {
220
+ agentLogger.debug("getAgent lookup failed", { error });
221
+ return dntShim.Response.json({ error: "Agent not found" }, { status: 404 });
222
+ }
221
223
  }
222
224
  if (!agent) {
223
225
  return dntShim.Response.json({ error: "Agent not found" }, { status: 404 });
@@ -84,6 +84,6 @@ export { getTextFromParts, getToolArguments, hasArgs, hasInput } from "./types.j
84
84
  export { BufferMemory, ConversationMemory, createMemory, createRedisMemory, type Memory, type MemoryPersistence, type MemoryStats, type RedisClient, RedisMemory, type RedisMemoryConfig, SummaryMemory, } from "./memory/index.js";
85
85
  export { agentAsTool, createWorkflow, getAgent, getAgentsAsTools, getAllAgentIds, registerAgent, type WorkflowConfig, type WorkflowResult, type WorkflowStep, } from "./composition/index.js";
86
86
  export { agent } from "./factory.js";
87
- export { type ChatHandlerBeforeStream, type ChatHandlerBeforeStreamContext, type ChatHandlerBeforeStreamResult, type ChatHandlerMessageInput, type ChatHandlerOptions, createChatHandler, } from "./chat-handler.js";
87
+ export { type ChatHandlerBeforeStream, type ChatHandlerBeforeStreamContext, type ChatHandlerBeforeStreamResult, type ChatHandlerConfigWithAgent, type ChatHandlerMessageInput, type ChatHandlerOptions, createChatHandler, } from "./chat-handler.js";
88
88
  export { AgentRuntime } from "./runtime/index.js";
89
89
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/src/agent/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+EG;AACH,OAAO,yBAAyB,CAAC;AAGjC,YAAY,EACV,KAAK,EACL,WAAW,EACX,YAAY,EACZ,eAAe,EACf,aAAa,EACb,WAAW,EACX,iBAAiB,EACjB,UAAU,EACV,YAAY,EACZ,OAAO,IAAI,YAAY,EACvB,WAAW,EACX,aAAa,EACb,WAAW,EACX,mBAAmB,EACnB,cAAc,EACd,QAAQ,EACR,YAAY,EACZ,oBAAoB,EACpB,qBAAqB,EACrB,cAAc,GACf,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEnF,OAAO,EACL,YAAY,EACZ,kBAAkB,EAClB,YAAY,EACZ,iBAAiB,EACjB,KAAK,MAAM,EACX,KAAK,iBAAiB,EACtB,KAAK,WAAW,EAChB,KAAK,WAAW,EAChB,WAAW,EACX,KAAK,iBAAiB,EACtB,aAAa,GACd,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,WAAW,EACX,cAAc,EACd,QAAQ,EACR,gBAAgB,EAChB,cAAc,EACd,aAAa,EACb,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,KAAK,YAAY,GAClB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AACrC,OAAO,EACL,KAAK,uBAAuB,EAC5B,KAAK,8BAA8B,EACnC,KAAK,6BAA6B,EAClC,KAAK,uBAAuB,EAC5B,KAAK,kBAAkB,EACvB,iBAAiB,GAClB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/src/agent/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+EG;AACH,OAAO,yBAAyB,CAAC;AAGjC,YAAY,EACV,KAAK,EACL,WAAW,EACX,YAAY,EACZ,eAAe,EACf,aAAa,EACb,WAAW,EACX,iBAAiB,EACjB,UAAU,EACV,YAAY,EACZ,OAAO,IAAI,YAAY,EACvB,WAAW,EACX,aAAa,EACb,WAAW,EACX,mBAAmB,EACnB,cAAc,EACd,QAAQ,EACR,YAAY,EACZ,oBAAoB,EACpB,qBAAqB,EACrB,cAAc,GACf,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEnF,OAAO,EACL,YAAY,EACZ,kBAAkB,EAClB,YAAY,EACZ,iBAAiB,EACjB,KAAK,MAAM,EACX,KAAK,iBAAiB,EACtB,KAAK,WAAW,EAChB,KAAK,WAAW,EAChB,WAAW,EACX,KAAK,iBAAiB,EACtB,aAAa,GACd,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,WAAW,EACX,cAAc,EACd,QAAQ,EACR,gBAAgB,EAChB,cAAc,EACd,aAAa,EACb,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,KAAK,YAAY,GAClB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AACrC,OAAO,EACL,KAAK,uBAAuB,EAC5B,KAAK,8BAA8B,EACnC,KAAK,6BAA6B,EAClC,KAAK,0BAA0B,EAC/B,KAAK,uBAAuB,EAC5B,KAAK,kBAAkB,EACvB,iBAAiB,GAClB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"discovery-engine.d.ts","sourceRoot":"","sources":["../../../src/src/discovery/discovery-engine.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,OAAO,KAAK,EACV,eAAe,EAEf,eAAe,EAEhB,MAAM,YAAY,CAAC;AA6DpB;;GAEG;AACH,wBAAsB,WAAW,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,eAAe,CAAC,CA0EnF"}
1
+ {"version":3,"file":"discovery-engine.d.ts","sourceRoot":"","sources":["../../../src/src/discovery/discovery-engine.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,OAAO,KAAK,EACV,eAAe,EAEf,eAAe,EAEhB,MAAM,YAAY,CAAC;AAqIpB;;GAEG;AACH,wBAAsB,WAAW,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,eAAe,CAAC,CA0EnF"}
@@ -11,31 +11,80 @@ import { registerSkill, skillRegistry } from "../skill/registry.js";
11
11
  import { importModule } from "./transpiler.js";
12
12
  import { findTypeScriptFiles } from "./file-discovery.js";
13
13
  import { agentHandler, discoverSkills, promptHandler, resourceHandler, taskHandler, toolHandler, workflowHandler, } from "./handlers/index.js";
14
+ import { filenameToId } from "./discovery-utils.js";
14
15
  import { join } from "../platform/compat/path/index.js";
15
16
  const logger = agentLogger.component("discovery");
17
+ function isIndexModule(file) {
18
+ const normalized = file.replace("file://", "");
19
+ return /(?:^|\/)index\.(?:ts|tsx|js|jsx)$/.test(normalized);
20
+ }
21
+ function compareDiscoveryFiles(a, b) {
22
+ const aIsIndex = isIndexModule(a);
23
+ const bIsIndex = isIndexModule(b);
24
+ if (aIsIndex !== bIsIndex)
25
+ return aIsIndex ? 1 : -1;
26
+ return a.localeCompare(b);
27
+ }
28
+ function collectDiscoveryCandidates(module, handler) {
29
+ const defaultItem = module.default;
30
+ if (handler.validate(defaultItem)) {
31
+ return [{ exportName: "default", item: defaultItem }];
32
+ }
33
+ const candidates = [];
34
+ for (const [exportName, value] of Object.entries(module)) {
35
+ if (exportName === "default")
36
+ continue;
37
+ if (!handler.validate(value))
38
+ continue;
39
+ candidates.push({ exportName, item: value });
40
+ }
41
+ return candidates;
42
+ }
43
+ function getCandidateId(candidate, file, dir, handler, useExportNameFallback) {
44
+ const derivedId = handler.getId(candidate.item, file, dir);
45
+ if (!useExportNameFallback)
46
+ return derivedId;
47
+ const fileId = filenameToId(file);
48
+ if (derivedId !== fileId)
49
+ return derivedId;
50
+ return candidate.exportName;
51
+ }
16
52
  /**
17
53
  * Discover items of a specific type in a directory
18
54
  */
19
55
  async function discoverItems(dir, result, context, handler, verbose) {
20
- const files = await findTypeScriptFiles(dir, context);
56
+ const files = (await findTypeScriptFiles(dir, context)).sort(compareDiscoveryFiles);
57
+ const resultMap = handler.getResultMap(result);
21
58
  if (verbose) {
22
59
  logger.info(`Found ${files.length} ${handler.typeName} files in ${dir}`);
23
60
  }
24
61
  for (const file of files) {
25
62
  try {
26
63
  const module = await importModule(file, context);
27
- const item = module.default;
28
- if (!handler.validate(item)) {
64
+ const candidates = collectDiscoveryCandidates(module, handler);
65
+ if (candidates.length === 0) {
29
66
  if (verbose) {
30
67
  logger.warn(`${file} does not export a valid ${handler.typeName}`);
31
68
  }
32
69
  continue;
33
70
  }
34
- const id = handler.getId(item, file, dir);
35
- const registered = handler.register(id, item, file, dir);
36
- handler.getResultMap(result).set(id, registered);
37
- if (verbose) {
38
- logger.info(`Registered ${handler.typeName}: ${id}`);
71
+ const useExportNameFallback = candidates.length > 1 || isIndexModule(file);
72
+ for (const candidate of candidates) {
73
+ const id = getCandidateId(candidate, file, dir, handler, useExportNameFallback);
74
+ if (resultMap.has(id)) {
75
+ if (verbose) {
76
+ logger.warn(`Duplicate ${handler.typeName} "${id}" in ${file}; keeping first`);
77
+ }
78
+ continue;
79
+ }
80
+ const registered = handler.register(id, candidate.item, file, dir);
81
+ resultMap.set(id, registered);
82
+ if (verbose) {
83
+ const exportSuffix = candidate.exportName === "default"
84
+ ? ""
85
+ : ` (export: ${candidate.exportName})`;
86
+ logger.info(`Registered ${handler.typeName}: ${id}${exportSuffix}`);
87
+ }
39
88
  }
40
89
  }
41
90
  catch (error) {
@@ -1 +1 @@
1
- {"version":3,"file":"module-server.d.ts","sourceRoot":"","sources":["../../../../src/src/modules/server/module-server.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,OAAO,KAAK,OAAO,MAAM,wBAAwB,CAAC;AAIlD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AAkBtE;;;;;;;;;GASG;AACH,eAAO,MAAM,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAkDrD,CAAC;AASF,MAAM,WAAW,mBAAmB;IAClC,yDAAyD;IACzD,SAAS,EAAE,MAAM,CAAC;IAClB,6BAA6B;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,sBAAsB;IACtB,OAAO,EAAE,cAAc,CAAC;IACxB,uBAAuB;IACvB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,+DAA+D;IAC/D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gFAAgF;IAChF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mDAAmD;IACnD,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,uDAAuD;IACvD,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,yDAAyD;IACzD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,sFAAsF;IACtF,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,sDAAsD;AACtD,wBAAgB,WAAW,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CAqTzG;AAuND;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,GAAG,OAAO,CAG7D"}
1
+ {"version":3,"file":"module-server.d.ts","sourceRoot":"","sources":["../../../../src/src/modules/server/module-server.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,OAAO,KAAK,OAAO,MAAM,wBAAwB,CAAC;AAIlD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AAkBtE;;;;;;;;;GASG;AACH,eAAO,MAAM,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAsDrD,CAAC;AASF,MAAM,WAAW,mBAAmB;IAClC,yDAAyD;IACzD,SAAS,EAAE,MAAM,CAAC;IAClB,6BAA6B;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,sBAAsB;IACtB,OAAO,EAAE,cAAc,CAAC;IACxB,uBAAuB;IACvB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,+DAA+D;IAC/D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gFAAgF;IAChF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mDAAmD;IACnD,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,uDAAuD;IACvD,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,yDAAyD;IACzD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,sFAAsF;IACtF,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,sDAAsD;AACtD,wBAAgB,WAAW,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CAqTzG;AAwND;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,GAAG,OAAO,CAG7D"}
@@ -3,7 +3,7 @@ import * as dntShim from "../../../_dnt.shims.js";
3
3
  import { join } from "../../platform/compat/path/index.js";
4
4
  import { createFileSystem } from "../../platform/compat/fs.js";
5
5
  import { transformToESM } from "../../transforms/esm-transform.js";
6
- import { serverLogger } from "../../utils/index.js";
6
+ import { serverLogger, VERSION } from "../../utils/index.js";
7
7
  import { HTTP_NOT_FOUND, HTTP_OK, HTTP_SERVER_ERROR } from "../../utils/index.js";
8
8
  import { getContentTypeForPath } from "../../server/handlers/utils/content-types.js";
9
9
  import { createSecureFs } from "../../security/index.js";
@@ -76,6 +76,10 @@ export default {};
76
76
  `export default {};`,
77
77
  ].join("\n") + "\n",
78
78
  "_dnt.polyfills": `export default {};\n`,
79
+ // Deno import-map alias stub for browser/HTTP-served framework modules.
80
+ // Must be a JS module (not JSON) because esbuild strips `with { type: "json" }`
81
+ // at es2020 target, and browsers reject JSON MIME type without the assertion.
82
+ "_veryfront/_deno-config": `export default ${JSON.stringify({ version: VERSION })};\n`,
79
83
  };
80
84
  const DEV_MODULE_PREFIX = /^\/(?:_vf_modules|_veryfront\/modules)\//;
81
85
  const SNIPPET_MODULE_PREFIX = /^\/_vf_modules\/_snippets\/([a-f0-9]+)\.js/;
@@ -331,6 +335,7 @@ const EMBEDDED_SRC_DIR = join(FRAMEWORK_ROOT, "dist", "framework-src");
331
335
  async function findSourceFile(secureFs, projectDir, basePath) {
332
336
  // Extensions including .src for compiled binary embedded sources
333
337
  const extensions = [
338
+ ".json",
334
339
  ".tsx.src",
335
340
  ".ts.src",
336
341
  ".jsx.src",
@@ -347,7 +352,7 @@ async function findSourceFile(secureFs, projectDir, basePath) {
347
352
  logger.debug("findSourceFile called", { projectDir, basePath });
348
353
  const hasKnownExt = extensions.some((ext) => basePath.endsWith(ext));
349
354
  const rawBasePathWithoutExt = hasKnownExt
350
- ? basePath.replace(/\.(tsx|ts|jsx|js|mdx|md)(\.src)?$/, "")
355
+ ? basePath.replace(/\.(json|tsx|ts|jsx|js|mdx|md)(\.src)?$/, "")
351
356
  : basePath;
352
357
  let basePathWithoutExt = rawBasePathWithoutExt.replace(/^\/+/, "");
353
358
  if (basePathWithoutExt.startsWith("_vf_modules/")) {
@@ -374,7 +379,7 @@ async function findSourceFile(secureFs, projectDir, basePath) {
374
379
  basePath: basePathWithoutExt,
375
380
  });
376
381
  return {
377
- path: `embedded:${basePathWithoutExt}`,
382
+ path: `embedded:${basePath}`,
378
383
  isFrameworkFile: true,
379
384
  embeddedContent,
380
385
  };
@@ -1 +1 @@
1
- {"version":3,"file":"veryfront-strategy.d.ts","sourceRoot":"","sources":["../../../../../src/src/transforms/import-rewriter/strategies/veryfront-strategy.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EACV,qBAAqB,EACrB,mBAAmB,EACnB,cAAc,EACd,aAAa,EACd,MAAM,aAAa,CAAC;AAkBrB,qBAAa,iBAAkB,YAAW,qBAAqB;IAC7D,QAAQ,CAAC,IAAI,eAAe;IAC5B,QAAQ,CAAC,QAAQ,OAAO;IAExB,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,GAAG,OAAO;IAQzD,OAAO,CAAC,IAAI,EAAE,mBAAmB,EAAE,GAAG,EAAE,cAAc,GAAG,aAAa;CA2CvE;AAED,eAAO,MAAM,iBAAiB,mBAA0B,CAAC"}
1
+ {"version":3,"file":"veryfront-strategy.d.ts","sourceRoot":"","sources":["../../../../../src/src/transforms/import-rewriter/strategies/veryfront-strategy.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EACV,qBAAqB,EACrB,mBAAmB,EACnB,cAAc,EACd,aAAa,EACd,MAAM,aAAa,CAAC;AAkBrB,qBAAa,iBAAkB,YAAW,qBAAqB;IAC7D,QAAQ,CAAC,IAAI,eAAe;IAC5B,QAAQ,CAAC,QAAQ,OAAO;IAExB,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,GAAG,OAAO;IASzD,OAAO,CAAC,IAAI,EAAE,mBAAmB,EAAE,GAAG,EAAE,cAAc,GAAG,aAAa;CAkDvE;AAED,eAAO,MAAM,iBAAiB,mBAA0B,CAAC"}
@@ -22,10 +22,17 @@ export class VeryfrontStrategy {
22
22
  matches(specifier, _ctx) {
23
23
  return (specifier.startsWith("#veryfront/") ||
24
24
  specifier.startsWith("veryfront/") ||
25
- specifier === "veryfront");
25
+ specifier === "veryfront" ||
26
+ specifier === "#deno-config");
26
27
  }
27
28
  rewrite(info, ctx) {
28
29
  const specifier = info.specifier;
30
+ // Handle #deno-config — Deno import-map alias that doesn't exist in browsers.
31
+ // Rewrite to a JS module (not JSON) because esbuild strips `with { type: "json" }`
32
+ // at es2020 target and browsers reject JSON MIME without the assertion.
33
+ if (specifier === "#deno-config") {
34
+ return { specifier: "/_vf_modules/_veryfront/_deno-config.js" };
35
+ }
29
36
  // Handle #veryfront/* (internal framework imports)
30
37
  if (specifier.startsWith("#veryfront/")) {
31
38
  const path = specifier.slice("#veryfront/".length);
@@ -1,4 +1,4 @@
1
- export declare const VERSION: string;
1
+ export declare const VERSION = "0.1.59";
2
2
  export declare const SERVER_START_TIME: number;
3
3
  export interface BuildVersion {
4
4
  framework: string;
@@ -1 +1 @@
1
- {"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../../../src/src/utils/version.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,OAAO,EAAE,MAA6B,CAAC;AAEpD,eAAO,MAAM,iBAAiB,EAAE,MAAmB,CAAC;AAEpD,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,wBAAgB,kBAAkB,CAAC,gBAAgB,CAAC,EAAE,MAAM,GAAG,YAAY,CAM1E"}
1
+ {"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../../../src/src/utils/version.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,OAAO,WAAW,CAAC;AAEhC,eAAO,MAAM,iBAAiB,EAAE,MAAmB,CAAC;AAEpD,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,wBAAgB,kBAAkB,CAAC,gBAAgB,CAAC,EAAE,MAAM,GAAG,YAAY,CAM1E"}
@@ -1,9 +1,6 @@
1
- import denoConfig from "../../deno.js";
2
- function getVersionFromDeno() {
3
- return typeof denoConfig.version === "string" ? denoConfig.version : "0.0.0";
4
- }
5
- // Use deno.json version directly to avoid env access at module load
6
- export const VERSION = getVersionFromDeno();
1
+ // Keep in sync with deno.json version.
2
+ // scripts/release.ts updates this constant during releases.
3
+ export const VERSION = "0.1.59";
7
4
  export const SERVER_START_TIME = Date.now();
8
5
  export function createBuildVersion(projectUpdatedAt) {
9
6
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "veryfront",
3
- "version": "0.1.58",
3
+ "version": "0.1.60",
4
4
  "description": "The simplest way to build AI-powered apps",
5
5
  "keywords": [
6
6
  "react",
package/src/deno.js CHANGED
@@ -1,6 +1,6 @@
1
1
  export default {
2
2
  "name": "veryfront",
3
- "version": "0.1.58",
3
+ "version": "0.1.60",
4
4
  "license": "Apache-2.0",
5
5
  "nodeModulesDir": "auto",
6
6
  "exclude": [
@@ -245,6 +245,20 @@ export interface ChatHandlerOptions {
245
245
  beforeStream?: ChatHandlerBeforeStream;
246
246
  }
247
247
 
248
+ /** Options when passing an agent instance directly. */
249
+ export interface ChatHandlerConfigWithAgent extends ChatHandlerOptions {
250
+ /** The agent instance to use (bypasses registry lookup). */
251
+ agent: import("./types.js").Agent;
252
+ }
253
+
254
+ function mergeChatHandlerConfig(
255
+ config: ChatHandlerConfigWithAgent,
256
+ options?: ChatHandlerOptions,
257
+ ): ChatHandlerConfigWithAgent {
258
+ if (!options) return config;
259
+ return { ...options, ...config };
260
+ }
261
+
248
262
  /**
249
263
  * Extract the raw Request from either a raw Request or a Pages Router APIContext.
250
264
  * Pages Router handlers receive `(ctx)` where `ctx.request` is the Request.
@@ -298,25 +312,55 @@ function extractRequest(requestOrCtx: unknown): dntShim.Request {
298
312
  * - App Router: `app/api/chat/route.ts` — handler receives `(request, context)`
299
313
  * - Pages Router: `pages/api/chat.ts` — handler receives `(ctx)`
300
314
  *
315
+ * Accepts either:
316
+ * - `createChatHandler("agentId", options?)` — looks up agent by ID from the registry
317
+ * - `createChatHandler({ agent, ...options })` — uses the provided agent instance directly
318
+ *
301
319
  * @example
302
320
  * ```ts
303
- * import { createChatHandler } from "veryfront/agent";
321
+ * // By agent ID (requires auto-discovery registration)
304
322
  * export const POST = createChatHandler("assistant");
323
+ *
324
+ * // By agent instance (no registry needed)
325
+ * import { myAgent } from "../../agents/my-agent";
326
+ * export const POST = createChatHandler({ agent: myAgent, beforeStream: ... });
305
327
  * ```
306
328
  */
307
329
  export function createChatHandler(
308
330
  agentId: string,
309
331
  options?: ChatHandlerOptions,
332
+ ): (requestOrCtx: unknown) => Promise<dntShim.Response>;
333
+ export function createChatHandler(
334
+ config: ChatHandlerConfigWithAgent,
335
+ options?: ChatHandlerOptions,
336
+ ): (requestOrCtx: unknown) => Promise<dntShim.Response>;
337
+ export function createChatHandler(
338
+ agentIdOrConfig: string | ChatHandlerConfigWithAgent,
339
+ options?: ChatHandlerOptions,
310
340
  ) {
311
341
  return async function POST(requestOrCtx: unknown): Promise<dntShim.Response> {
312
342
  const request = extractRequest(requestOrCtx);
343
+
313
344
  let agent: ReturnType<typeof getAgent> | undefined;
314
- try {
315
- agent = getAgent(agentId);
316
- } catch (error) {
317
- agentLogger.debug("getAgent lookup failed", { error });
318
- return dntShim.Response.json({ error: "Agent not found" }, { status: 404 });
345
+
346
+ if (
347
+ typeof agentIdOrConfig === "object" && agentIdOrConfig !== null && "agent" in agentIdOrConfig
348
+ ) {
349
+ // Object-based API: createChatHandler({ agent, beforeStream, ... })
350
+ const config = mergeChatHandlerConfig(agentIdOrConfig, options);
351
+ agent = config.agent;
352
+ options = config;
353
+ } else {
354
+ // String-based API: createChatHandler("agentId", options?)
355
+ const agentId = agentIdOrConfig as string;
356
+ try {
357
+ agent = getAgent(agentId);
358
+ } catch (error) {
359
+ agentLogger.debug("getAgent lookup failed", { error });
360
+ return dntShim.Response.json({ error: "Agent not found" }, { status: 404 });
361
+ }
319
362
  }
363
+
320
364
  if (!agent) {
321
365
  return dntShim.Response.json({ error: "Agent not found" }, { status: 404 });
322
366
  }
@@ -137,6 +137,7 @@ export {
137
137
  type ChatHandlerBeforeStream,
138
138
  type ChatHandlerBeforeStreamContext,
139
139
  type ChatHandlerBeforeStreamResult,
140
+ type ChatHandlerConfigWithAgent,
140
141
  type ChatHandlerMessageInput,
141
142
  type ChatHandlerOptions,
142
143
  createChatHandler,
@@ -26,10 +26,62 @@ import {
26
26
  toolHandler,
27
27
  workflowHandler,
28
28
  } from "./handlers/index.js";
29
+ import { filenameToId } from "./discovery-utils.js";
29
30
  import { join } from "../platform/compat/path/index.js";
30
31
 
31
32
  const logger = agentLogger.component("discovery");
32
33
 
34
+ type DiscoveryCandidate<T> = {
35
+ exportName: string;
36
+ item: T;
37
+ };
38
+
39
+ function isIndexModule(file: string): boolean {
40
+ const normalized = file.replace("file://", "");
41
+ return /(?:^|\/)index\.(?:ts|tsx|js|jsx)$/.test(normalized);
42
+ }
43
+
44
+ function compareDiscoveryFiles(a: string, b: string): number {
45
+ const aIsIndex = isIndexModule(a);
46
+ const bIsIndex = isIndexModule(b);
47
+ if (aIsIndex !== bIsIndex) return aIsIndex ? 1 : -1;
48
+ return a.localeCompare(b);
49
+ }
50
+
51
+ function collectDiscoveryCandidates<T>(
52
+ module: unknown,
53
+ handler: DiscoveryHandler<T>,
54
+ ): DiscoveryCandidate<T>[] {
55
+ const defaultItem = (module as { default?: T }).default;
56
+ if (handler.validate(defaultItem)) {
57
+ return [{ exportName: "default", item: defaultItem }];
58
+ }
59
+
60
+ const candidates: DiscoveryCandidate<T>[] = [];
61
+ for (const [exportName, value] of Object.entries(module as Record<string, unknown>)) {
62
+ if (exportName === "default") continue;
63
+ if (!handler.validate(value)) continue;
64
+ candidates.push({ exportName, item: value });
65
+ }
66
+
67
+ return candidates;
68
+ }
69
+
70
+ function getCandidateId<T>(
71
+ candidate: DiscoveryCandidate<T>,
72
+ file: string,
73
+ dir: string,
74
+ handler: DiscoveryHandler<T>,
75
+ useExportNameFallback: boolean,
76
+ ): string {
77
+ const derivedId = handler.getId(candidate.item, file, dir);
78
+ if (!useExportNameFallback) return derivedId;
79
+
80
+ const fileId = filenameToId(file);
81
+ if (derivedId !== fileId) return derivedId;
82
+ return candidate.exportName;
83
+ }
84
+
33
85
  /**
34
86
  * Discover items of a specific type in a directory
35
87
  */
@@ -40,7 +92,8 @@ async function discoverItems<T>(
40
92
  handler: DiscoveryHandler<T>,
41
93
  verbose?: boolean,
42
94
  ): Promise<void> {
43
- const files = await findTypeScriptFiles(dir, context);
95
+ const files = (await findTypeScriptFiles(dir, context)).sort(compareDiscoveryFiles);
96
+ const resultMap = handler.getResultMap(result);
44
97
 
45
98
  if (verbose) {
46
99
  logger.info(`Found ${files.length} ${handler.typeName} files in ${dir}`);
@@ -49,21 +102,40 @@ async function discoverItems<T>(
49
102
  for (const file of files) {
50
103
  try {
51
104
  const module = await importModule(file, context);
52
- const item = (module as { default?: T }).default;
53
-
54
- if (!handler.validate(item)) {
105
+ const candidates = collectDiscoveryCandidates(module, handler);
106
+ if (candidates.length === 0) {
55
107
  if (verbose) {
56
108
  logger.warn(`${file} does not export a valid ${handler.typeName}`);
57
109
  }
58
110
  continue;
59
111
  }
60
112
 
61
- const id = handler.getId(item, file, dir);
62
- const registered = handler.register(id, item, file, dir);
63
- handler.getResultMap(result).set(id, registered);
113
+ const useExportNameFallback = candidates.length > 1 || isIndexModule(file);
114
+ for (const candidate of candidates) {
115
+ const id = getCandidateId(
116
+ candidate,
117
+ file,
118
+ dir,
119
+ handler,
120
+ useExportNameFallback,
121
+ );
122
+
123
+ if (resultMap.has(id)) {
124
+ if (verbose) {
125
+ logger.warn(`Duplicate ${handler.typeName} "${id}" in ${file}; keeping first`);
126
+ }
127
+ continue;
128
+ }
64
129
 
65
- if (verbose) {
66
- logger.info(`Registered ${handler.typeName}: ${id}`);
130
+ const registered = handler.register(id, candidate.item, file, dir);
131
+ resultMap.set(id, registered);
132
+
133
+ if (verbose) {
134
+ const exportSuffix = candidate.exportName === "default"
135
+ ? ""
136
+ : ` (export: ${candidate.exportName})`;
137
+ logger.info(`Registered ${handler.typeName}: ${id}${exportSuffix}`);
138
+ }
67
139
  }
68
140
  } catch (error) {
69
141
  result.errors.push({ file, error: ensureError(error) });
@@ -6,7 +6,7 @@ import { join } from "../../platform/compat/path/index.js";
6
6
  import type { RuntimeAdapter } from "../../platform/adapters/base.js";
7
7
  import { createFileSystem } from "../../platform/compat/fs.js";
8
8
  import { type TransformOptions, transformToESM } from "../../transforms/esm-transform.js";
9
- import { serverLogger } from "../../utils/index.js";
9
+ import { serverLogger, VERSION } from "../../utils/index.js";
10
10
  import { HTTP_NOT_FOUND, HTTP_OK, HTTP_SERVER_ERROR } from "../../utils/index.js";
11
11
  import { getContentTypeForPath } from "../../server/handlers/utils/content-types.js";
12
12
  import { createSecureFs } from "../../security/index.js";
@@ -81,6 +81,10 @@ export default {};
81
81
  `export default {};`,
82
82
  ].join("\n") + "\n",
83
83
  "_dnt.polyfills": `export default {};\n`,
84
+ // Deno import-map alias stub for browser/HTTP-served framework modules.
85
+ // Must be a JS module (not JSON) because esbuild strips `with { type: "json" }`
86
+ // at es2020 target, and browsers reject JSON MIME type without the assertion.
87
+ "_veryfront/_deno-config": `export default ${JSON.stringify({ version: VERSION })};\n`,
84
88
  };
85
89
 
86
90
  const DEV_MODULE_PREFIX = /^\/(?:_vf_modules|_veryfront\/modules)\//;
@@ -449,6 +453,7 @@ async function findSourceFile(
449
453
  ): Promise<FindSourceFileResult | null> {
450
454
  // Extensions including .src for compiled binary embedded sources
451
455
  const extensions = [
456
+ ".json",
452
457
  ".tsx.src",
453
458
  ".ts.src",
454
459
  ".jsx.src",
@@ -467,7 +472,7 @@ async function findSourceFile(
467
472
 
468
473
  const hasKnownExt = extensions.some((ext) => basePath.endsWith(ext));
469
474
  const rawBasePathWithoutExt = hasKnownExt
470
- ? basePath.replace(/\.(tsx|ts|jsx|js|mdx|md)(\.src)?$/, "")
475
+ ? basePath.replace(/\.(json|tsx|ts|jsx|js|mdx|md)(\.src)?$/, "")
471
476
  : basePath;
472
477
  let basePathWithoutExt = rawBasePathWithoutExt.replace(/^\/+/, "");
473
478
  if (basePathWithoutExt.startsWith("_vf_modules/")) {
@@ -496,7 +501,7 @@ async function findSourceFile(
496
501
  basePath: basePathWithoutExt,
497
502
  });
498
503
  return {
499
- path: `embedded:${basePathWithoutExt}`,
504
+ path: `embedded:${basePath}`,
500
505
  isFrameworkFile: true,
501
506
  embeddedContent,
502
507
  };
@@ -36,13 +36,21 @@ export class VeryfrontStrategy implements ImportRewriteStrategy {
36
36
  return (
37
37
  specifier.startsWith("#veryfront/") ||
38
38
  specifier.startsWith("veryfront/") ||
39
- specifier === "veryfront"
39
+ specifier === "veryfront" ||
40
+ specifier === "#deno-config"
40
41
  );
41
42
  }
42
43
 
43
44
  rewrite(info: ImportSpecifierInfo, ctx: RewriteContext): RewriteResult {
44
45
  const specifier = info.specifier;
45
46
 
47
+ // Handle #deno-config — Deno import-map alias that doesn't exist in browsers.
48
+ // Rewrite to a JS module (not JSON) because esbuild strips `with { type: "json" }`
49
+ // at es2020 target and browsers reject JSON MIME without the assertion.
50
+ if (specifier === "#deno-config") {
51
+ return { specifier: "/_vf_modules/_veryfront/_deno-config.js" };
52
+ }
53
+
46
54
  // Handle #veryfront/* (internal framework imports)
47
55
  if (specifier.startsWith("#veryfront/")) {
48
56
  const path = specifier.slice("#veryfront/".length);
@@ -1,11 +1,6 @@
1
- import denoConfig from "../../deno.js";
2
-
3
- function getVersionFromDeno(): string {
4
- return typeof denoConfig.version === "string" ? denoConfig.version : "0.0.0";
5
- }
6
-
7
- // Use deno.json version directly to avoid env access at module load
8
- export const VERSION: string = getVersionFromDeno();
1
+ // Keep in sync with deno.json version.
2
+ // scripts/release.ts updates this constant during releases.
3
+ export const VERSION = "0.1.59";
9
4
 
10
5
  export const SERVER_START_TIME: number = Date.now();
11
6