@classytic/arc 2.15.3 → 2.16.0
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/README.md +1 -0
- package/bin/arc.js +12 -0
- package/dist/{BaseController-dx3m2J8V.mjs → BaseController-DlCCTIxJ.mjs} +61 -19
- package/dist/{HookSystem-Iiebom92.mjs → HookSystem-Cmf7-Etp.mjs} +8 -4
- package/dist/{QueryCache-D41bfdBB.d.mts → QueryCache-SvmT_9ti.d.mts} +1 -1
- package/dist/{ResourceRegistry-CTERg_2x.mjs → ResourceRegistry-f48hFk3m.mjs} +52 -9
- package/dist/audit/index.d.mts +1 -1
- package/dist/audit/index.mjs +4 -2
- package/dist/auth/index.d.mts +4 -4
- package/dist/auth/index.mjs +4 -4
- package/dist/auth/redis-session.d.mts +1 -1
- package/dist/{betterAuthOpenApi--M_i87dQ.mjs → betterAuthOpenApi-ClWxaceA.mjs} +10 -6
- package/dist/buildHandler-BZX6zzDM.mjs +300 -0
- package/dist/cache/index.d.mts +3 -3
- package/dist/cache/index.mjs +3 -3
- package/dist/{caching-SM8gghN6.mjs → caching-TeHE8G-v.mjs} +1 -1
- package/dist/cli/commands/describe.d.mts +35 -1
- package/dist/cli/commands/describe.mjs +52 -12
- package/dist/cli/commands/docs.d.mts +1 -4
- package/dist/cli/commands/docs.mjs +4 -16
- package/dist/cli/commands/generate.d.mts +2 -20
- package/dist/cli/commands/generate.mjs +1 -546
- package/dist/cli/commands/init.d.mts +2 -40
- package/dist/cli/commands/init.mjs +1 -3036
- package/dist/cli/commands/introspect.mjs +53 -64
- package/dist/cli/index.d.mts +2 -2
- package/dist/cli/index.mjs +2 -2
- package/dist/{constants-Cxde4rpC.mjs → constants-TrJVIJl0.mjs} +7 -0
- package/dist/core/index.d.mts +3 -3
- package/dist/core/index.mjs +5 -5
- package/dist/{core-CvmOqEms.mjs → core-DBJ_j6rX.mjs} +222 -44
- package/dist/createActionRouter-DUpN3Dd1.mjs +288 -0
- package/dist/{createAggregationRouter-B0bPDf5b.mjs → createAggregationRouter-Dq-TUCuY.mjs} +3 -2
- package/dist/{createApp-PFegs47-.mjs → createApp-DNccuhyI.mjs} +16 -14
- package/dist/{defineEvent-D5h7EvAx.mjs → defineEvent-DRwY0fYm.mjs} +1 -1
- package/dist/docs/index.d.mts +2 -2
- package/dist/docs/index.mjs +1 -1
- package/dist/{errorHandler-Bk-AGhkU.mjs → errorHandler-DpoXQHZ9.mjs} +17 -14
- package/dist/errors-C1lX_jlm.d.mts +91 -0
- package/dist/{eventPlugin-CaKTYkYM.mjs → eventPlugin-C2cGqtRO.mjs} +1 -1
- package/dist/{eventPlugin-qXpqTebY.d.mts → eventPlugin-CtHC_av1.d.mts} +1 -1
- package/dist/events/index.d.mts +3 -3
- package/dist/events/index.mjs +5 -5
- package/dist/events/transports/redis-stream-entry.d.mts +1 -1
- package/dist/events/transports/redis.d.mts +1 -1
- package/dist/factory/index.d.mts +1 -1
- package/dist/factory/index.mjs +2 -2
- package/dist/{fields-COhcH3fk.d.mts → fields-Anj0xdih.d.mts} +1 -1
- package/dist/generate-BWFwgcCM.d.mts +38 -0
- package/dist/generate-CYac-OLv.mjs +654 -0
- package/dist/hooks/index.d.mts +1 -1
- package/dist/hooks/index.mjs +1 -1
- package/dist/idempotency/index.d.mts +2 -2
- package/dist/idempotency/index.mjs +1 -1
- package/dist/idempotency/redis.d.mts +1 -1
- package/dist/{index-BTqLEvhu.d.mts → index-3oIimXQn.d.mts} +12 -12
- package/dist/{index-BstGxcc3.d.mts → index-B-ulKx5P.d.mts} +55 -4
- package/dist/{index-BswOSJCE.d.mts → index-CkW0flkU.d.mts} +355 -16
- package/dist/index.d.mts +6 -6
- package/dist/index.mjs +7 -8
- package/dist/init-Dv71MsJr.d.mts +71 -0
- package/dist/init-HDvoO9L5.mjs +3098 -0
- package/dist/integrations/event-gateway.d.mts +2 -2
- package/dist/integrations/event-gateway.mjs +1 -1
- package/dist/integrations/index.d.mts +2 -2
- package/dist/integrations/jobs.mjs +3 -3
- package/dist/integrations/mcp/index.d.mts +239 -7
- package/dist/integrations/mcp/index.mjs +2 -528
- package/dist/integrations/mcp/testing.d.mts +2 -2
- package/dist/integrations/mcp/testing.mjs +6 -10
- package/dist/integrations/streamline.d.mts +71 -2
- package/dist/integrations/streamline.mjs +81 -8
- package/dist/integrations/websocket-redis.d.mts +1 -1
- package/dist/integrations/websocket.d.mts +1 -1
- package/dist/integrations/websocket.mjs +1 -0
- package/dist/loadResourcesFromEntry-BLMEI2Xa.mjs +51 -0
- package/dist/{resourceToTools-tFYUNmM0.mjs → mcpPlugin-7vGV51ED.mjs} +1021 -318
- package/dist/{memory-UBydS5ku.mjs → memory-QOLe11D5.mjs} +2 -0
- package/dist/middleware/index.d.mts +1 -1
- package/dist/middleware/index.mjs +1 -1
- package/dist/{openapi-BHXhoX8O.mjs → openapi-34T9yNwd.mjs} +47 -36
- package/dist/permissions/index.d.mts +2 -2
- package/dist/permissions/index.mjs +1 -1
- package/dist/{permissions-ohQyv50e.mjs → permissions-CTxMrreC.mjs} +2 -2
- package/dist/{pipe-Zr0KXjQe.mjs → pipe-DiCyvyPN.mjs} +1 -0
- package/dist/pipeline/index.d.mts +1 -1
- package/dist/pipeline/index.mjs +1 -1
- package/dist/plugins/index.d.mts +5 -5
- package/dist/plugins/index.mjs +10 -10
- package/dist/plugins/response-cache.mjs +5 -5
- package/dist/plugins/tracing-entry.d.mts +1 -1
- package/dist/plugins/tracing-entry.mjs +1 -1
- package/dist/{pluralize-DQgqgifU.mjs → pluralize-B9M8xvy-.mjs} +2 -1
- package/dist/presets/filesUpload.d.mts +4 -4
- package/dist/presets/filesUpload.mjs +2 -2
- package/dist/presets/index.d.mts +1 -1
- package/dist/presets/index.mjs +1 -1
- package/dist/presets/multiTenant.d.mts +1 -1
- package/dist/presets/multiTenant.mjs +4 -3
- package/dist/presets/search.d.mts +2 -2
- package/dist/presets/search.mjs +1 -1
- package/dist/{presets-BbkjdPeH.mjs → presets-C9BE6WaZ.mjs} +2 -2
- package/dist/{queryCachePlugin-m1XsgAIJ.mjs → queryCachePlugin-B4XMSSe7.mjs} +2 -2
- package/dist/{queryCachePlugin-CqMdLI2-.d.mts → queryCachePlugin-Biqzfbi5.d.mts} +2 -2
- package/dist/{redis-DiMkdHEl.d.mts → redis-Cyzrz6SX.d.mts} +1 -1
- package/dist/{redis-stream-D6HzR1Z_.d.mts → redis-stream-DT-YjzrB.d.mts} +1 -1
- package/dist/registry/index.d.mts +319 -2
- package/dist/registry/index.mjs +3 -3
- package/dist/registry-BBE23CDj.mjs +576 -0
- package/dist/{routerShared-DrOa-26E.mjs → routerShared-CZV5aabX.mjs} +3 -3
- package/dist/scope/index.d.mts +3 -3
- package/dist/scope/index.mjs +3 -3
- package/dist/{sse-Bz-5ZeTt.mjs → sse-BY6sTy4P.mjs} +1 -1
- package/dist/testing/index.d.mts +2 -2
- package/dist/testing/index.mjs +16 -7
- package/dist/testing/storageContract.d.mts +1 -1
- package/dist/types/index.d.mts +5 -5
- package/dist/types/storage.d.mts +1 -1
- package/dist/{types-C_s5moIu.mjs → types-Bi0r0vjG.mjs} +53 -1
- package/dist/{types-BQsjgQzS.d.mts → types-BsJMEQ4D.d.mts} +106 -12
- package/dist/{types-DrBaUwyV.d.mts → types-D-fYtKjb.d.mts} +33 -10
- package/dist/{types-CTYvcwHe.d.mts → types-DVfpSfx2.d.mts} +42 -1
- package/dist/utils/index.d.mts +1286 -2
- package/dist/utils/index.mjs +1 -1
- package/dist/{utils-_h9B3c57.mjs → utils-DC5ycPfr.mjs} +89 -40
- package/dist/{buildHandler-CcFOpJLh.mjs → validate-By96rH0r.mjs} +8 -299
- package/dist/{versioning-hmkPcDlX.d.mts → versioning-ZwX9tmbS.d.mts} +1 -1
- package/package.json +22 -29
- package/skills/arc/SKILL.md +299 -689
- package/skills/arc/references/auth.md +19 -7
- package/skills/arc-code-review/SKILL.md +1 -1
- package/skills/arc-code-review/references/arc-cheatsheet.md +100 -322
- package/dist/createActionRouter-S3MLVYot.mjs +0 -220
- package/dist/index-bRjYu21O.d.mts +0 -1320
- package/dist/org/index.d.mts +0 -66
- package/dist/org/index.mjs +0 -486
- package/dist/org/types.d.mts +0 -82
- package/dist/org/types.mjs +0 -1
- package/dist/registry-I-ogLgL9.mjs +0 -46
- /package/dist/{EventTransport-CT_52aWU.d.mts → EventTransport-C-2oAHtw.d.mts} +0 -0
- /package/dist/{EventTransport-DLWoUMHy.mjs → EventTransport-Hxvv5QQz.mjs} +0 -0
- /package/dist/{actionPermissions-CyUkQu6O.mjs → actionPermissions-Bjmvn7Eb.mjs} +0 -0
- /package/dist/{elevation-BXOWoGCF.d.mts → elevation-0YBpa663.d.mts} +0 -0
- /package/dist/{elevation-DgoeTyfX.mjs → elevation-Dci0AYLT.mjs} +0 -0
- /package/dist/{errorHandler-DFr45ZG4.d.mts → errorHandler-mHuyWzZE.d.mts} +0 -0
- /package/dist/{externalPaths-BD5nw6St.d.mts → externalPaths-DFg-2KTp.d.mts} +0 -0
- /package/dist/{interface-beEtJyWM.d.mts → interface-CH0OQudo.d.mts} +0 -0
- /package/dist/{interface-DfLGcus7.d.mts → interface-NwJ_qPlY.d.mts} +0 -0
- /package/dist/{keys-CGcCbNyu.mjs → keys-DopsCuyQ.mjs} +0 -0
- /package/dist/{loadResources-DBMQg_Aj.mjs → loadResources-ChQEj8ih.mjs} +0 -0
- /package/dist/{metrics-Qnvwc-LQ.mjs → metrics-TuOmguhi.mjs} +0 -0
- /package/dist/{replyHelpers-CK-FNO8E.mjs → replyHelpers-C-gD32oF.mjs} +0 -0
- /package/dist/{schemaIR-lYhC2gE5.mjs → schemaIR-Ctc89DSn.mjs} +0 -0
- /package/dist/{sessionManager-C4Le_UB3.d.mts → sessionManager-BqFegc0W.d.mts} +0 -0
- /package/dist/{storage-Dfzt4VTl.d.mts → storage-D2KZJAmn.d.mts} +0 -0
- /package/dist/{store-helpers-BkIN9-vu.mjs → store-helpers-B0sunfZZ.mjs} +0 -0
- /package/dist/{tracing-QJVprktp.d.mts → tracing-Dm8n7Cnn.d.mts} +0 -0
- /package/dist/{versioning-BUrT5aP4.mjs → versioning-B6mimogM.mjs} +0 -0
- /package/dist/{websocket-ChC2rqe1.d.mts → websocket-BkjeGZRn.d.mts} +0 -0
|
@@ -1,6 +1,22 @@
|
|
|
1
1
|
import { f as createError, i as NotFoundError, r as ForbiddenError } from "../errors-j4aJm1Wg.mjs";
|
|
2
|
+
import fp from "fastify-plugin";
|
|
2
3
|
//#region src/integrations/streamline.ts
|
|
3
4
|
/**
|
|
5
|
+
* Streamline >= 2.3.3 dead-letter discriminator. The run.status stays
|
|
6
|
+
* `'failed'`; the discrimination is `error.code`:
|
|
7
|
+
* - `'stale_heartbeat'` — sweeper terminated; transient crash signal.
|
|
8
|
+
* - `'dead_lettered'` — exceeded `maxStaleRecoveries`; permanent.
|
|
9
|
+
* - `'VERSION_MISMATCH'` — engine deployed a step graph the run can't
|
|
10
|
+
* resume against; admin must rewind / migrate / cancel.
|
|
11
|
+
*
|
|
12
|
+
* Hosts switch on `error.code` for dashboards / alerting.
|
|
13
|
+
*/
|
|
14
|
+
const STREAMLINE_FAILURE_CODES = {
|
|
15
|
+
STALE_HEARTBEAT: "stale_heartbeat",
|
|
16
|
+
DEAD_LETTERED: "dead_lettered",
|
|
17
|
+
VERSION_MISMATCH: "VERSION_MISMATCH"
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
4
20
|
* Full event list published on a streamline workflow's internal `eventBus`
|
|
5
21
|
* (tracks streamline 2.3's `EventPayloadMap` in
|
|
6
22
|
* `@classytic/streamline/src/core/events.ts`).
|
|
@@ -44,6 +60,7 @@ const STREAMLINE_TERMINAL_EVENTS = [
|
|
|
44
60
|
];
|
|
45
61
|
const streamlinePluginImpl = async (fastify, options) => {
|
|
46
62
|
const { workflows, prefix = "/workflows", auth = true, bridgeEvents = true, enableStreaming = false, enableHookEndpoint = false, tenantResolver, bypassTenantResolver, permissions: perms } = options;
|
|
63
|
+
const routeScope = prefix;
|
|
47
64
|
const bridgeBus = options.bridgeBusEvents ?? false;
|
|
48
65
|
const registry = /* @__PURE__ */ new Map();
|
|
49
66
|
for (const wf of workflows) {
|
|
@@ -70,10 +87,35 @@ const streamlinePluginImpl = async (fastify, options) => {
|
|
|
70
87
|
return check(request);
|
|
71
88
|
};
|
|
72
89
|
for (const [id, wf] of registry) {
|
|
73
|
-
const routePrefix = `${
|
|
90
|
+
const routePrefix = `${routeScope}/${id}`;
|
|
74
91
|
fastify.post(`${routePrefix}/start`, { preHandler: authPreHandler }, async (request, reply) => {
|
|
75
92
|
if (!await checkPerm("start", request)) throw new ForbiddenError();
|
|
76
|
-
const
|
|
93
|
+
const body = request.body;
|
|
94
|
+
if (body !== null && body !== void 0 && typeof body !== "object") throw createError(422, `[Arc/Streamline] '/${id}/start' body must be a JSON object.`, {
|
|
95
|
+
code: "arc.streamline.invalid_body",
|
|
96
|
+
workflowId: id
|
|
97
|
+
});
|
|
98
|
+
const envelopeKeys = new Set([
|
|
99
|
+
"input",
|
|
100
|
+
"meta",
|
|
101
|
+
"idempotencyKey",
|
|
102
|
+
"priority"
|
|
103
|
+
]);
|
|
104
|
+
const bodyRecord = body ?? {};
|
|
105
|
+
const unknownKeys = Object.keys(bodyRecord).filter((k) => !envelopeKeys.has(k));
|
|
106
|
+
const hasInputKey = Object.hasOwn(bodyRecord, "input");
|
|
107
|
+
if (unknownKeys.length > 0 && !hasInputKey) throw createError(422, `[Arc/Streamline] '/${id}/start' expects '{ input: {...} }'. Got top-level keys [${unknownKeys.join(", ")}] but no 'input' key. Wrap your workflow payload: { "input": { ${unknownKeys.map((k) => `"${k}": ...`).join(", ")} } }.`, {
|
|
108
|
+
code: "arc.streamline.missing_input_envelope",
|
|
109
|
+
workflowId: id,
|
|
110
|
+
received: unknownKeys,
|
|
111
|
+
expected: "input"
|
|
112
|
+
});
|
|
113
|
+
if (unknownKeys.length > 0) throw createError(422, `[Arc/Streamline] '/${id}/start' got unknown top-level keys [${unknownKeys.join(", ")}]. Allowed envelope keys: input, meta, idempotencyKey, priority. Did you mean to nest these under 'input'?`, {
|
|
114
|
+
code: "arc.streamline.unknown_envelope_keys",
|
|
115
|
+
workflowId: id,
|
|
116
|
+
unknown: unknownKeys
|
|
117
|
+
});
|
|
118
|
+
const { input, meta, idempotencyKey, priority } = bodyRecord;
|
|
77
119
|
const tenantOpts = resolveTenantOpts(request);
|
|
78
120
|
const run = await wf.start(input, {
|
|
79
121
|
meta,
|
|
@@ -161,6 +203,24 @@ const streamlinePluginImpl = async (fastify, options) => {
|
|
|
161
203
|
const { runId } = request.params;
|
|
162
204
|
return await wf.engine.execute(runId);
|
|
163
205
|
});
|
|
206
|
+
const deleteRepo = wf.container?.repository;
|
|
207
|
+
const repoDeleteFn = deleteRepo?.delete;
|
|
208
|
+
const repoGetByIdFn = deleteRepo?.getById;
|
|
209
|
+
if (repoDeleteFn && repoGetByIdFn) fastify.delete(`${routePrefix}/runs/:runId`, { preHandler: authPreHandler }, async (request, reply) => {
|
|
210
|
+
if (!await checkPerm("cancel", request)) throw new ForbiddenError();
|
|
211
|
+
const { runId } = request.params;
|
|
212
|
+
const tenantOpts = resolveTenantOpts(request);
|
|
213
|
+
const repoOpts = {
|
|
214
|
+
...tenantOpts.tenantId !== void 0 ? { tenantId: tenantOpts.tenantId } : {},
|
|
215
|
+
...tenantOpts.bypassTenant ? { bypassTenant: true } : {}
|
|
216
|
+
};
|
|
217
|
+
if (!await repoGetByIdFn(runId, repoOpts)) throw new NotFoundError(`Workflow run ${runId} not found`);
|
|
218
|
+
try {
|
|
219
|
+
await wf.cancel(runId);
|
|
220
|
+
} catch {}
|
|
221
|
+
await repoDeleteFn(runId, repoOpts);
|
|
222
|
+
return reply.status(204).send();
|
|
223
|
+
});
|
|
164
224
|
if (wf.engine.waitFor) fastify.get(`${routePrefix}/runs/:runId/wait`, { preHandler: authPreHandler }, async (request, _reply) => {
|
|
165
225
|
if (!await checkPerm("get", request)) throw new ForbiddenError();
|
|
166
226
|
const { runId } = request.params;
|
|
@@ -239,7 +299,7 @@ const streamlinePluginImpl = async (fastify, options) => {
|
|
|
239
299
|
}
|
|
240
300
|
if (enableHookEndpoint) {
|
|
241
301
|
let resumeHookFn;
|
|
242
|
-
fastify.post(`${
|
|
302
|
+
fastify.post(`${routeScope}/hooks/:token`, { preHandler: authPreHandler }, async (request, _reply) => {
|
|
243
303
|
if (!resumeHookFn) resumeHookFn = (await import("@classytic/streamline")).resumeHook;
|
|
244
304
|
const { token } = request.params;
|
|
245
305
|
const result = await resumeHookFn(token, request.body);
|
|
@@ -249,7 +309,7 @@ const streamlinePluginImpl = async (fastify, options) => {
|
|
|
249
309
|
};
|
|
250
310
|
});
|
|
251
311
|
}
|
|
252
|
-
fastify.get(
|
|
312
|
+
fastify.get(routeScope || "/", { preHandler: authPreHandler }, async () => {
|
|
253
313
|
return Array.from(registry.entries()).map(([id, wf]) => ({
|
|
254
314
|
id,
|
|
255
315
|
name: wf.definition.name ?? id,
|
|
@@ -257,10 +317,23 @@ const streamlinePluginImpl = async (fastify, options) => {
|
|
|
257
317
|
}));
|
|
258
318
|
});
|
|
259
319
|
fastify.addHook("onClose", async () => {
|
|
260
|
-
for (const wf of registry.values())
|
|
320
|
+
for (const wf of registry.values()) {
|
|
321
|
+
wf.shutdown?.();
|
|
322
|
+
wf.container?.dispose?.();
|
|
323
|
+
}
|
|
261
324
|
});
|
|
262
325
|
};
|
|
263
|
-
/**
|
|
264
|
-
|
|
326
|
+
/**
|
|
327
|
+
* Pluggable streamline integration for Arc.
|
|
328
|
+
*
|
|
329
|
+
* Wrapped in `fastify-plugin` so Fastify treats `options.prefix` as a
|
|
330
|
+
* plain plugin option (NOT an encapsulation prefix). Without the wrapper,
|
|
331
|
+
* Fastify would prepend `options.prefix` to every route, then the plugin
|
|
332
|
+
* code would prepend it again — the duplicate-prefix bug.
|
|
333
|
+
*/
|
|
334
|
+
const streamlinePlugin = fp(streamlinePluginImpl, {
|
|
335
|
+
name: "streamline-routes",
|
|
336
|
+
fastify: "5.x"
|
|
337
|
+
});
|
|
265
338
|
//#endregion
|
|
266
|
-
export { STREAMLINE_BUS_EVENTS, STREAMLINE_TERMINAL_EVENTS, streamlinePlugin };
|
|
339
|
+
export { STREAMLINE_BUS_EVENTS, STREAMLINE_FAILURE_CODES, STREAMLINE_TERMINAL_EVENTS, streamlinePlugin };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as WebSocketMessage, c as WebSocketAdapter, i as WebSocketClient, n as websocketPlugin, o as WebSocketPluginOptions, r as AuthResult, s as LocalWebSocketAdapter, t as RoomManager } from "../websocket-
|
|
1
|
+
import { a as WebSocketMessage, c as WebSocketAdapter, i as WebSocketClient, n as websocketPlugin, o as WebSocketPluginOptions, r as AuthResult, s as LocalWebSocketAdapter, t as RoomManager } from "../websocket-BkjeGZRn.mjs";
|
|
2
2
|
export { AuthResult, LocalWebSocketAdapter, RoomManager, WebSocketAdapter, WebSocketClient, WebSocketMessage, WebSocketPluginOptions, websocketPlugin };
|
|
@@ -375,6 +375,7 @@ const websocketPluginImpl = async (fastify, options) => {
|
|
|
375
375
|
if (room.startsWith("org:")) {
|
|
376
376
|
const parts = room.split(":");
|
|
377
377
|
const orgId = parts[1];
|
|
378
|
+
if (!orgId) return;
|
|
378
379
|
const actualRoom = parts.slice(2).join(":");
|
|
379
380
|
rooms.broadcastToOrg(orgId, actualRoom, message);
|
|
380
381
|
} else rooms.broadcast(room, message);
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { t as ResourceRegistry } from "./ResourceRegistry-f48hFk3m.mjs";
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
import { pathToFileURL } from "node:url";
|
|
4
|
+
//#region src/cli/utils/loadResourcesFromEntry.ts
|
|
5
|
+
/**
|
|
6
|
+
* Shared loader for CLI commands that need to read a host's resource graph
|
|
7
|
+
* from a built entry file (`introspect`, `docs`, `describe`).
|
|
8
|
+
*
|
|
9
|
+
* Each command historically duplicated the same dance: `pathToFileURL` →
|
|
10
|
+
* dynamic `import()` → walk the module's exports → match anything that
|
|
11
|
+
* looks structurally like a `ResourceDefinition` (carries `name`,
|
|
12
|
+
* `_registryMeta`, `toPlugin`) → register into a fresh `ResourceRegistry`.
|
|
13
|
+
* Extracting the duplication here means a future signature change to
|
|
14
|
+
* the registry surface or the resource-shape sentinel only touches one
|
|
15
|
+
* spot.
|
|
16
|
+
*
|
|
17
|
+
* The structural match (vs `instanceof ResourceDefinition`) is deliberate:
|
|
18
|
+
* the host's entry file is a compiled `dist/` artifact that may have been
|
|
19
|
+
* built against a different arc minor version, so a class-identity check
|
|
20
|
+
* would reject genuinely-compatible objects across version drift.
|
|
21
|
+
*/
|
|
22
|
+
/**
|
|
23
|
+
* Load the host's entry file, walk its exports, and register every
|
|
24
|
+
* `ResourceDefinition`-shaped value into a fresh `ResourceRegistry`.
|
|
25
|
+
*
|
|
26
|
+
* Returns `{ registry, registered }`:
|
|
27
|
+
* - `registry` is populated and ready to query (`getAll()`, `getStats()`,
|
|
28
|
+
* `getIntrospection()`).
|
|
29
|
+
* - `registered` is the count — callers can short-circuit with a
|
|
30
|
+
* friendly "no resources found" message when it's zero.
|
|
31
|
+
*/
|
|
32
|
+
async function loadResourcesFromEntry(entryPath) {
|
|
33
|
+
const entryModule = await import(pathToFileURL(resolve(process.cwd(), entryPath)).href);
|
|
34
|
+
const registry = new ResourceRegistry();
|
|
35
|
+
let registered = 0;
|
|
36
|
+
const tryRegister = (value) => {
|
|
37
|
+
if (value && typeof value === "object" && "name" in value && "_registryMeta" in value && "toPlugin" in value) {
|
|
38
|
+
const resourceLike = value;
|
|
39
|
+
registry.register(resourceLike, resourceLike._registryMeta ?? {});
|
|
40
|
+
registered++;
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
for (const exported of Object.values(entryModule)) if (Array.isArray(exported)) for (const entry of exported) tryRegister(entry);
|
|
44
|
+
else tryRegister(exported);
|
|
45
|
+
return {
|
|
46
|
+
registry,
|
|
47
|
+
registered
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
//#endregion
|
|
51
|
+
export { loadResourcesFromEntry as t };
|