You're Invited:Meet the Socket Team at RSAC and BSidesSF 2026, March 23–26.RSVP
Socket
Book a DemoSign in
Socket

veryfront

Package Overview
Dependencies
Maintainers
1
Versions
304
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

veryfront - npm Package Compare versions

Comparing version
0.1.59
to
0.1.60
+1
-1
esm/deno.js
export default {
"name": "veryfront",
"version": "0.1.59",
"version": "0.1.60",
"license": "Apache-2.0",

@@ -5,0 +5,0 @@ "nodeModulesDir": "auto",

@@ -29,2 +29,7 @@ import * as dntShim from "../../_dnt.shims.js";

}
/** Options when passing an agent instance directly. */
export interface ChatHandlerConfigWithAgent extends ChatHandlerOptions {
/** The agent instance to use (bypasses registry lookup). */
agent: import("./types.js").Agent;
}
/**

@@ -37,9 +42,18 @@ * Create a POST handler for a chat API route.

*
* Accepts either:
* - `createChatHandler("agentId", options?)` — looks up agent by ID from the registry
* - `createChatHandler({ agent, ...options })` — uses the provided agent instance directly
*
* @example
* ```ts
* import { createChatHandler } from "veryfront/agent";
* // By agent ID (requires auto-discovery registration)
* export const POST = createChatHandler("assistant");
*
* // By agent instance (no registry needed)
* import { myAgent } from "../../agents/my-agent";
* export const POST = createChatHandler({ agent: myAgent, beforeStream: ... });
* ```
*/
export declare function createChatHandler(agentId: string, options?: ChatHandlerOptions): (requestOrCtx: unknown) => Promise<dntShim.Response>;
export declare function createChatHandler(config: ChatHandlerConfigWithAgent, options?: ChatHandlerOptions): (requestOrCtx: unknown) => Promise<dntShim.Response>;
//# sourceMappingURL=chat-handler.d.ts.map

@@ -1,1 +0,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"}
{"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"}

@@ -158,2 +158,7 @@ import * as dntShim from "../../_dnt.shims.js";

}
function mergeChatHandlerConfig(config, options) {
if (!options)
return config;
return { ...options, ...config };
}
/**

@@ -199,25 +204,22 @@ * Extract the raw Request from either a raw Request or a Pages Router APIContext.

}
/**
* Create a POST handler for a chat API route.
*
* Works with both App Router and Pages Router:
* - App Router: `app/api/chat/route.ts` — handler receives `(request, context)`
* - Pages Router: `pages/api/chat.ts` — handler receives `(ctx)`
*
* @example
* ```ts
* import { createChatHandler } from "veryfront/agent";
* export const POST = createChatHandler("assistant");
* ```
*/
export function createChatHandler(agentId, options) {
export function createChatHandler(agentIdOrConfig, options) {
return async function POST(requestOrCtx) {
const request = extractRequest(requestOrCtx);
let agent;
try {
agent = getAgent(agentId);
if (typeof agentIdOrConfig === "object" && agentIdOrConfig !== null && "agent" in agentIdOrConfig) {
// Object-based API: createChatHandler({ agent, beforeStream, ... })
const config = mergeChatHandlerConfig(agentIdOrConfig, options);
agent = config.agent;
options = config;
}
catch (error) {
agentLogger.debug("getAgent lookup failed", { error });
return dntShim.Response.json({ error: "Agent not found" }, { status: 404 });
else {
// String-based API: createChatHandler("agentId", options?)
const agentId = agentIdOrConfig;
try {
agent = getAgent(agentId);
}
catch (error) {
agentLogger.debug("getAgent lookup failed", { error });
return dntShim.Response.json({ error: "Agent not found" }, { status: 404 });
}
}

@@ -224,0 +226,0 @@ if (!agent) {

@@ -87,4 +87,4 @@ /**

export { agent } from "./factory.js";
export { type ChatHandlerBeforeStream, type ChatHandlerBeforeStreamContext, type ChatHandlerBeforeStreamResult, type ChatHandlerMessageInput, type ChatHandlerOptions, createChatHandler, } from "./chat-handler.js";
export { type ChatHandlerBeforeStream, type ChatHandlerBeforeStreamContext, type ChatHandlerBeforeStreamResult, type ChatHandlerConfigWithAgent, type ChatHandlerMessageInput, type ChatHandlerOptions, createChatHandler, } from "./chat-handler.js";
export { AgentRuntime } from "./runtime/index.js";
//# sourceMappingURL=index.d.ts.map

@@ -1,1 +0,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"}
{"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 +0,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"}
{"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"}

@@ -14,4 +14,40 @@ /**

import { agentHandler, discoverSkills, promptHandler, resourceHandler, taskHandler, toolHandler, workflowHandler, } from "./handlers/index.js";
import { filenameToId } from "./discovery-utils.js";
import { join } from "../platform/compat/path/index.js";
const logger = agentLogger.component("discovery");
function isIndexModule(file) {
const normalized = file.replace("file://", "");
return /(?:^|\/)index\.(?:ts|tsx|js|jsx)$/.test(normalized);
}
function compareDiscoveryFiles(a, b) {
const aIsIndex = isIndexModule(a);
const bIsIndex = isIndexModule(b);
if (aIsIndex !== bIsIndex)
return aIsIndex ? 1 : -1;
return a.localeCompare(b);
}
function collectDiscoveryCandidates(module, handler) {
const defaultItem = module.default;
if (handler.validate(defaultItem)) {
return [{ exportName: "default", item: defaultItem }];
}
const candidates = [];
for (const [exportName, value] of Object.entries(module)) {
if (exportName === "default")
continue;
if (!handler.validate(value))
continue;
candidates.push({ exportName, item: value });
}
return candidates;
}
function getCandidateId(candidate, file, dir, handler, useExportNameFallback) {
const derivedId = handler.getId(candidate.item, file, dir);
if (!useExportNameFallback)
return derivedId;
const fileId = filenameToId(file);
if (derivedId !== fileId)
return derivedId;
return candidate.exportName;
}
/**

@@ -21,3 +57,4 @@ * Discover items of a specific type in a directory

async function discoverItems(dir, result, context, handler, verbose) {
const files = await findTypeScriptFiles(dir, context);
const files = (await findTypeScriptFiles(dir, context)).sort(compareDiscoveryFiles);
const resultMap = handler.getResultMap(result);
if (verbose) {

@@ -29,4 +66,4 @@ logger.info(`Found ${files.length} ${handler.typeName} files in ${dir}`);

const module = await importModule(file, context);
const item = module.default;
if (!handler.validate(item)) {
const candidates = collectDiscoveryCandidates(module, handler);
if (candidates.length === 0) {
if (verbose) {

@@ -37,7 +74,19 @@ logger.warn(`${file} does not export a valid ${handler.typeName}`);

}
const id = handler.getId(item, file, dir);
const registered = handler.register(id, item, file, dir);
handler.getResultMap(result).set(id, registered);
if (verbose) {
logger.info(`Registered ${handler.typeName}: ${id}`);
const useExportNameFallback = candidates.length > 1 || isIndexModule(file);
for (const candidate of candidates) {
const id = getCandidateId(candidate, file, dir, handler, useExportNameFallback);
if (resultMap.has(id)) {
if (verbose) {
logger.warn(`Duplicate ${handler.typeName} "${id}" in ${file}; keeping first`);
}
continue;
}
const registered = handler.register(id, candidate.item, file, dir);
resultMap.set(id, registered);
if (verbose) {
const exportSuffix = candidate.exportName === "default"
? ""
: ` (export: ${candidate.exportName})`;
logger.info(`Registered ${handler.typeName}: ${id}${exportSuffix}`);
}
}

@@ -44,0 +93,0 @@ }

{
"name": "veryfront",
"version": "0.1.59",
"version": "0.1.60",
"description": "The simplest way to build AI-powered apps",

@@ -5,0 +5,0 @@ "keywords": [

export default {
"name": "veryfront",
"version": "0.1.59",
"version": "0.1.60",
"license": "Apache-2.0",

@@ -5,0 +5,0 @@ "nodeModulesDir": "auto",

@@ -248,2 +248,16 @@ import * as dntShim from "../../_dnt.shims.js";

/** Options when passing an agent instance directly. */
export interface ChatHandlerConfigWithAgent extends ChatHandlerOptions {
/** The agent instance to use (bypasses registry lookup). */
agent: import("./types.js").Agent;
}
function mergeChatHandlerConfig(
config: ChatHandlerConfigWithAgent,
options?: ChatHandlerOptions,
): ChatHandlerConfigWithAgent {
if (!options) return config;
return { ...options, ...config };
}
/**

@@ -302,6 +316,14 @@ * Extract the raw Request from either a raw Request or a Pages Router APIContext.

*
* Accepts either:
* - `createChatHandler("agentId", options?)` — looks up agent by ID from the registry
* - `createChatHandler({ agent, ...options })` — uses the provided agent instance directly
*
* @example
* ```ts
* import { createChatHandler } from "veryfront/agent";
* // By agent ID (requires auto-discovery registration)
* export const POST = createChatHandler("assistant");
*
* // By agent instance (no registry needed)
* import { myAgent } from "../../agents/my-agent";
* export const POST = createChatHandler({ agent: myAgent, beforeStream: ... });
* ```

@@ -312,12 +334,34 @@ */

options?: ChatHandlerOptions,
): (requestOrCtx: unknown) => Promise<dntShim.Response>;
export function createChatHandler(
config: ChatHandlerConfigWithAgent,
options?: ChatHandlerOptions,
): (requestOrCtx: unknown) => Promise<dntShim.Response>;
export function createChatHandler(
agentIdOrConfig: string | ChatHandlerConfigWithAgent,
options?: ChatHandlerOptions,
) {
return async function POST(requestOrCtx: unknown): Promise<dntShim.Response> {
const request = extractRequest(requestOrCtx);
let agent: ReturnType<typeof getAgent> | undefined;
try {
agent = getAgent(agentId);
} catch (error) {
agentLogger.debug("getAgent lookup failed", { error });
return dntShim.Response.json({ error: "Agent not found" }, { status: 404 });
if (
typeof agentIdOrConfig === "object" && agentIdOrConfig !== null && "agent" in agentIdOrConfig
) {
// Object-based API: createChatHandler({ agent, beforeStream, ... })
const config = mergeChatHandlerConfig(agentIdOrConfig, options);
agent = config.agent;
options = config;
} else {
// String-based API: createChatHandler("agentId", options?)
const agentId = agentIdOrConfig as string;
try {
agent = getAgent(agentId);
} catch (error) {
agentLogger.debug("getAgent lookup failed", { error });
return dntShim.Response.json({ error: "Agent not found" }, { status: 404 });
}
}
if (!agent) {

@@ -324,0 +368,0 @@ return dntShim.Response.json({ error: "Agent not found" }, { status: 404 });

@@ -140,2 +140,3 @@ /**

type ChatHandlerBeforeStreamResult,
type ChatHandlerConfigWithAgent,
type ChatHandlerMessageInput,

@@ -142,0 +143,0 @@ type ChatHandlerOptions,

@@ -29,2 +29,3 @@ /**

} from "./handlers/index.js";
import { filenameToId } from "./discovery-utils.js";
import { join } from "../platform/compat/path/index.js";

@@ -34,2 +35,53 @@

type DiscoveryCandidate<T> = {
exportName: string;
item: T;
};
function isIndexModule(file: string): boolean {
const normalized = file.replace("file://", "");
return /(?:^|\/)index\.(?:ts|tsx|js|jsx)$/.test(normalized);
}
function compareDiscoveryFiles(a: string, b: string): number {
const aIsIndex = isIndexModule(a);
const bIsIndex = isIndexModule(b);
if (aIsIndex !== bIsIndex) return aIsIndex ? 1 : -1;
return a.localeCompare(b);
}
function collectDiscoveryCandidates<T>(
module: unknown,
handler: DiscoveryHandler<T>,
): DiscoveryCandidate<T>[] {
const defaultItem = (module as { default?: T }).default;
if (handler.validate(defaultItem)) {
return [{ exportName: "default", item: defaultItem }];
}
const candidates: DiscoveryCandidate<T>[] = [];
for (const [exportName, value] of Object.entries(module as Record<string, unknown>)) {
if (exportName === "default") continue;
if (!handler.validate(value)) continue;
candidates.push({ exportName, item: value });
}
return candidates;
}
function getCandidateId<T>(
candidate: DiscoveryCandidate<T>,
file: string,
dir: string,
handler: DiscoveryHandler<T>,
useExportNameFallback: boolean,
): string {
const derivedId = handler.getId(candidate.item, file, dir);
if (!useExportNameFallback) return derivedId;
const fileId = filenameToId(file);
if (derivedId !== fileId) return derivedId;
return candidate.exportName;
}
/**

@@ -45,3 +97,4 @@ * Discover items of a specific type in a directory

): Promise<void> {
const files = await findTypeScriptFiles(dir, context);
const files = (await findTypeScriptFiles(dir, context)).sort(compareDiscoveryFiles);
const resultMap = handler.getResultMap(result);

@@ -55,5 +108,4 @@ if (verbose) {

const module = await importModule(file, context);
const item = (module as { default?: T }).default;
if (!handler.validate(item)) {
const candidates = collectDiscoveryCandidates(module, handler);
if (candidates.length === 0) {
if (verbose) {

@@ -65,8 +117,28 @@ logger.warn(`${file} does not export a valid ${handler.typeName}`);

const id = handler.getId(item, file, dir);
const registered = handler.register(id, item, file, dir);
handler.getResultMap(result).set(id, registered);
const useExportNameFallback = candidates.length > 1 || isIndexModule(file);
for (const candidate of candidates) {
const id = getCandidateId(
candidate,
file,
dir,
handler,
useExportNameFallback,
);
if (verbose) {
logger.info(`Registered ${handler.typeName}: ${id}`);
if (resultMap.has(id)) {
if (verbose) {
logger.warn(`Duplicate ${handler.typeName} "${id}" in ${file}; keeping first`);
}
continue;
}
const registered = handler.register(id, candidate.item, file, dir);
resultMap.set(id, registered);
if (verbose) {
const exportSuffix = candidate.exportName === "default"
? ""
: ` (export: ${candidate.exportName})`;
logger.info(`Registered ${handler.typeName}: ${id}${exportSuffix}`);
}
}

@@ -73,0 +145,0 @@ } catch (error) {