@jay-framework/stack-server-runtime 0.11.0 → 0.13.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/dist/index.d.ts +430 -30
- package/dist/index.js +968 -100
- package/package.json +13 -11
package/dist/index.js
CHANGED
|
@@ -8,7 +8,7 @@ import { notFound, partialRender, phaseOutput, isJayAction } from "@jay-framewor
|
|
|
8
8
|
import fs$1 from "node:fs/promises";
|
|
9
9
|
import * as path from "node:path";
|
|
10
10
|
import path__default from "node:path";
|
|
11
|
-
import { parseJayFile, JAY_IMPORT_RESOLVER } from "@jay-framework/compiler-jay-html";
|
|
11
|
+
import { parseJayFile, JAY_IMPORT_RESOLVER, parseAction } from "@jay-framework/compiler-jay-html";
|
|
12
12
|
import { createRequire } from "module";
|
|
13
13
|
import * as fs from "node:fs";
|
|
14
14
|
import { createRequire as createRequire$1 } from "node:module";
|
|
@@ -17,6 +17,7 @@ import "js-beautify";
|
|
|
17
17
|
import fs$2 from "fs";
|
|
18
18
|
import path$1 from "path";
|
|
19
19
|
import YAML from "yaml";
|
|
20
|
+
import { getLogger } from "@jay-framework/logger";
|
|
20
21
|
import crypto from "node:crypto";
|
|
21
22
|
const serviceRegistry = /* @__PURE__ */ new Map();
|
|
22
23
|
function registerService(marker, service) {
|
|
@@ -40,9 +41,13 @@ function hasService(marker) {
|
|
|
40
41
|
function clearServiceRegistry() {
|
|
41
42
|
serviceRegistry.clear();
|
|
42
43
|
}
|
|
44
|
+
function getServiceRegistry() {
|
|
45
|
+
return serviceRegistry;
|
|
46
|
+
}
|
|
43
47
|
function resolveServices(serviceMarkers) {
|
|
44
48
|
return serviceMarkers.map((marker) => getService(marker));
|
|
45
49
|
}
|
|
50
|
+
globalThis.__JAY_SERVICE_RESOLVER__ = resolveServices;
|
|
46
51
|
const initCallbacks = [];
|
|
47
52
|
const shutdownCallbacks = [];
|
|
48
53
|
function onInit(callback) {
|
|
@@ -94,10 +99,17 @@ class DevSlowlyChangingPhase {
|
|
|
94
99
|
}
|
|
95
100
|
async runSlowlyForPage(pageParams, pageProps, parts) {
|
|
96
101
|
for (const part of parts) {
|
|
97
|
-
const { compDefinition } = part;
|
|
102
|
+
const { compDefinition, contractInfo } = part;
|
|
98
103
|
if (compDefinition.loadParams) {
|
|
99
104
|
const services = resolveServices(compDefinition.services);
|
|
100
|
-
const
|
|
105
|
+
const loadParamsArgs = contractInfo ? [
|
|
106
|
+
...services,
|
|
107
|
+
{
|
|
108
|
+
contractName: contractInfo.contractName,
|
|
109
|
+
metadata: contractInfo.metadata
|
|
110
|
+
}
|
|
111
|
+
] : services;
|
|
112
|
+
const compParams = compDefinition.loadParams(loadParamsArgs);
|
|
101
113
|
if (!await findMatchingParams(pageParams, compParams))
|
|
102
114
|
return notFound();
|
|
103
115
|
}
|
|
@@ -105,11 +117,19 @@ class DevSlowlyChangingPhase {
|
|
|
105
117
|
let slowlyViewState = {};
|
|
106
118
|
let carryForward = {};
|
|
107
119
|
for (const part of parts) {
|
|
108
|
-
const { compDefinition, key } = part;
|
|
120
|
+
const { compDefinition, key, contractInfo } = part;
|
|
109
121
|
if (compDefinition.slowlyRender) {
|
|
110
122
|
const services = resolveServices(compDefinition.services);
|
|
123
|
+
const partProps = {
|
|
124
|
+
...pageProps,
|
|
125
|
+
...pageParams,
|
|
126
|
+
...contractInfo && {
|
|
127
|
+
contractName: contractInfo.contractName,
|
|
128
|
+
metadata: contractInfo.metadata
|
|
129
|
+
}
|
|
130
|
+
};
|
|
111
131
|
const slowlyRenderedPart = await compDefinition.slowlyRender(
|
|
112
|
-
|
|
132
|
+
partProps,
|
|
113
133
|
...services
|
|
114
134
|
);
|
|
115
135
|
if (slowlyRenderedPart.kind === "PhaseOutput") {
|
|
@@ -136,12 +156,20 @@ async function renderFastChangingData(pageParams, pageProps, carryForward, parts
|
|
|
136
156
|
let fastViewState = {};
|
|
137
157
|
let fastCarryForward = {};
|
|
138
158
|
for (const part of parts) {
|
|
139
|
-
const { compDefinition, key } = part;
|
|
159
|
+
const { compDefinition, key, contractInfo } = part;
|
|
140
160
|
if (compDefinition.fastRender) {
|
|
141
161
|
const partSlowlyCarryForward = key ? carryForward[key] : carryForward;
|
|
142
162
|
const services = resolveServices(compDefinition.services);
|
|
163
|
+
const partProps = {
|
|
164
|
+
...pageProps,
|
|
165
|
+
...pageParams,
|
|
166
|
+
...contractInfo && {
|
|
167
|
+
contractName: contractInfo.contractName,
|
|
168
|
+
metadata: contractInfo.metadata
|
|
169
|
+
}
|
|
170
|
+
};
|
|
143
171
|
const fastRenderedPart = await compDefinition.fastRender(
|
|
144
|
-
|
|
172
|
+
partProps,
|
|
145
173
|
partSlowlyCarryForward,
|
|
146
174
|
...services
|
|
147
175
|
);
|
|
@@ -234,13 +262,13 @@ ${clientInitExecution}
|
|
|
234
262
|
const target = document.getElementById('target');
|
|
235
263
|
const pageComp = makeCompositeJayComponent(render, viewState, fastCarryForward, ${compositeParts}, trackByMap)
|
|
236
264
|
|
|
237
|
-
const instance = pageComp({
|
|
265
|
+
const instance = pageComp({/* placeholder for page props */})
|
|
238
266
|
${automationWrap}
|
|
239
267
|
<\/script>
|
|
240
268
|
</body>
|
|
241
269
|
</html>`;
|
|
242
270
|
}
|
|
243
|
-
const require$
|
|
271
|
+
const require$3 = createRequire(import.meta.url);
|
|
244
272
|
async function loadPageParts(vite, route, pagesBase, projectBase, jayRollupConfig, options) {
|
|
245
273
|
const exists = await fs$1.access(route.compPath, fs$1.constants.F_OK).then(() => true).catch(() => false);
|
|
246
274
|
const parts = [];
|
|
@@ -268,11 +296,12 @@ async function loadPageParts(vite, route, pagesBase, projectBase, jayRollupConfi
|
|
|
268
296
|
);
|
|
269
297
|
return jayHtmlWithValidations.mapAsync(async (jayHtml) => {
|
|
270
298
|
const usedPackages = /* @__PURE__ */ new Set();
|
|
299
|
+
const headlessInstanceComponents = [];
|
|
271
300
|
for await (const headlessImport of jayHtml.headlessImports) {
|
|
272
301
|
const module = headlessImport.codeLink.module;
|
|
273
302
|
const name = headlessImport.codeLink.names[0].name;
|
|
274
303
|
const isLocalModule = module[0] === "." || module[0] === "/";
|
|
275
|
-
const modulePath = isLocalModule ? path__default.resolve(dirName, module) : require$
|
|
304
|
+
const modulePath = isLocalModule ? path__default.resolve(dirName, module) : require$3.resolve(module, { paths: require$3.resolve.paths(dirName) });
|
|
276
305
|
const compDefinition = (await vite.ssrLoadModule(modulePath))[name];
|
|
277
306
|
const moduleImport = isLocalModule ? path__default.resolve(dirName, module) : module;
|
|
278
307
|
const isNpmPackage = !isLocalModule;
|
|
@@ -281,23 +310,101 @@ async function loadPageParts(vite, route, pagesBase, projectBase, jayRollupConfi
|
|
|
281
310
|
const packageName = module.startsWith("@") ? module.split("/").slice(0, 2).join("/") : module.split("/")[0];
|
|
282
311
|
usedPackages.add(packageName);
|
|
283
312
|
}
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
313
|
+
if (headlessImport.key) {
|
|
314
|
+
const key = headlessImport.key;
|
|
315
|
+
const part = {
|
|
316
|
+
key,
|
|
317
|
+
compDefinition,
|
|
318
|
+
clientImport: `import {${name}} from '${clientModuleImport}'`,
|
|
319
|
+
clientPart: `{comp: ${name}.comp, contextMarkers: ${name}.contexts || [], key: '${key}'}`,
|
|
320
|
+
// Include contract info for dynamic contract components
|
|
321
|
+
contractInfo: headlessImport.contract ? {
|
|
322
|
+
contractName: headlessImport.contract.name,
|
|
323
|
+
metadata: headlessImport.metadata
|
|
324
|
+
} : void 0
|
|
325
|
+
};
|
|
326
|
+
parts.push(part);
|
|
327
|
+
}
|
|
328
|
+
if (!headlessImport.key && headlessImport.contract) {
|
|
329
|
+
headlessInstanceComponents.push({
|
|
330
|
+
contractName: headlessImport.contractName,
|
|
331
|
+
compDefinition,
|
|
332
|
+
contract: headlessImport.contract
|
|
333
|
+
});
|
|
334
|
+
}
|
|
292
335
|
}
|
|
336
|
+
const headlessContracts = jayHtml.headlessImports.filter((hi) => hi.contract !== void 0 && hi.key !== void 0).map((hi) => ({
|
|
337
|
+
key: hi.key,
|
|
338
|
+
contract: hi.contract,
|
|
339
|
+
contractPath: hi.contractPath
|
|
340
|
+
}));
|
|
293
341
|
return {
|
|
294
342
|
parts,
|
|
295
343
|
serverTrackByMap: jayHtml.serverTrackByMap,
|
|
296
344
|
clientTrackByMap: jayHtml.clientTrackByMap,
|
|
297
|
-
usedPackages
|
|
345
|
+
usedPackages,
|
|
346
|
+
headlessContracts,
|
|
347
|
+
headlessInstanceComponents
|
|
298
348
|
};
|
|
299
349
|
});
|
|
300
350
|
}
|
|
351
|
+
async function slowRenderInstances(discovered, headlessInstanceComponents) {
|
|
352
|
+
const componentByContractName = /* @__PURE__ */ new Map();
|
|
353
|
+
for (const comp of headlessInstanceComponents) {
|
|
354
|
+
componentByContractName.set(comp.contractName, comp);
|
|
355
|
+
}
|
|
356
|
+
const resolvedData = [];
|
|
357
|
+
const slowViewStates = {};
|
|
358
|
+
const discoveredForFast = [];
|
|
359
|
+
const carryForwards = {};
|
|
360
|
+
for (const instance of discovered) {
|
|
361
|
+
const comp = componentByContractName.get(instance.contractName);
|
|
362
|
+
if (!comp || !comp.compDefinition.slowlyRender) {
|
|
363
|
+
continue;
|
|
364
|
+
}
|
|
365
|
+
const services = resolveServices(comp.compDefinition.services);
|
|
366
|
+
const slowResult = await comp.compDefinition.slowlyRender(instance.props, ...services);
|
|
367
|
+
if (slowResult.kind === "PhaseOutput") {
|
|
368
|
+
const coordKey = instance.coordinate.join("/");
|
|
369
|
+
resolvedData.push({
|
|
370
|
+
coordinate: instance.coordinate,
|
|
371
|
+
contract: comp.contract,
|
|
372
|
+
slowViewState: slowResult.rendered
|
|
373
|
+
});
|
|
374
|
+
slowViewStates[coordKey] = slowResult.rendered;
|
|
375
|
+
carryForwards[coordKey] = slowResult.carryForward;
|
|
376
|
+
discoveredForFast.push({
|
|
377
|
+
contractName: instance.contractName,
|
|
378
|
+
props: instance.props,
|
|
379
|
+
coordinate: instance.coordinate
|
|
380
|
+
});
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
if (discoveredForFast.length === 0) {
|
|
384
|
+
return void 0;
|
|
385
|
+
}
|
|
386
|
+
return {
|
|
387
|
+
resolvedData,
|
|
388
|
+
slowViewStates,
|
|
389
|
+
instancePhaseData: { discovered: discoveredForFast, carryForwards }
|
|
390
|
+
};
|
|
391
|
+
}
|
|
392
|
+
function validateForEachInstances(forEachInstances, headlessInstanceComponents) {
|
|
393
|
+
const componentByContractName = /* @__PURE__ */ new Map();
|
|
394
|
+
for (const comp of headlessInstanceComponents) {
|
|
395
|
+
componentByContractName.set(comp.contractName, comp);
|
|
396
|
+
}
|
|
397
|
+
const validations = [];
|
|
398
|
+
for (const instance of forEachInstances) {
|
|
399
|
+
const comp = componentByContractName.get(instance.contractName);
|
|
400
|
+
if (comp?.compDefinition.slowlyRender) {
|
|
401
|
+
validations.push(
|
|
402
|
+
`<jay:${instance.contractName}> inside forEach has a slow rendering phase. Headless components with slow phases cannot be used inside forEach because forEach items are only known at request time, after slow rendering completes. Use slowForEach instead, or remove the slow phase from the component.`
|
|
403
|
+
);
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
return validations;
|
|
407
|
+
}
|
|
301
408
|
class ActionRegistry {
|
|
302
409
|
constructor() {
|
|
303
410
|
__publicField(this, "actions", /* @__PURE__ */ new Map());
|
|
@@ -343,6 +450,34 @@ class ActionRegistry {
|
|
|
343
450
|
getNames() {
|
|
344
451
|
return Array.from(this.actions.keys());
|
|
345
452
|
}
|
|
453
|
+
/**
|
|
454
|
+
* Attaches metadata from a .jay-action file to a registered action.
|
|
455
|
+
* Called during action discovery when a plugin declares action metadata.
|
|
456
|
+
*
|
|
457
|
+
* @param actionName - The action name
|
|
458
|
+
* @param metadata - Parsed ActionMetadata from .jay-action file
|
|
459
|
+
*/
|
|
460
|
+
setMetadata(actionName, metadata) {
|
|
461
|
+
const action = this.actions.get(actionName);
|
|
462
|
+
if (action) {
|
|
463
|
+
action.metadata = metadata;
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
/**
|
|
467
|
+
* Gets all registered actions that have .jay-action metadata.
|
|
468
|
+
* These are the actions that should be exposed to AI agents.
|
|
469
|
+
*
|
|
470
|
+
* @returns Array of { actionName, metadata } for actions with metadata
|
|
471
|
+
*/
|
|
472
|
+
getActionsWithMetadata() {
|
|
473
|
+
const result = [];
|
|
474
|
+
for (const action of this.actions.values()) {
|
|
475
|
+
if (action.metadata) {
|
|
476
|
+
result.push({ actionName: action.actionName, metadata: action.metadata });
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
return result;
|
|
480
|
+
}
|
|
346
481
|
/**
|
|
347
482
|
* Clears all registered actions.
|
|
348
483
|
*/
|
|
@@ -445,10 +580,6 @@ async function executeAction(actionName, input) {
|
|
|
445
580
|
function getActionCacheHeaders(actionName) {
|
|
446
581
|
return actionRegistry.getCacheHeaders(actionName);
|
|
447
582
|
}
|
|
448
|
-
async function runAction(action, input) {
|
|
449
|
-
const services = resolveServices(action.services);
|
|
450
|
-
return action.handler(input, ...services);
|
|
451
|
-
}
|
|
452
583
|
var __defProp2 = Object.defineProperty;
|
|
453
584
|
var __defNormalProp2 = (obj, key, value) => key in obj ? __defProp2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
454
585
|
var __publicField2 = (obj, key, value) => {
|
|
@@ -478,6 +609,69 @@ new JayObjectType("Error", {
|
|
|
478
609
|
name: new JayAtomicType("string"),
|
|
479
610
|
stack: new JayAtomicType("string")
|
|
480
611
|
});
|
|
612
|
+
function isOptionalType(aType) {
|
|
613
|
+
return aType.kind === 13;
|
|
614
|
+
}
|
|
615
|
+
function isAtomicType(aType) {
|
|
616
|
+
return aType.kind === 0;
|
|
617
|
+
}
|
|
618
|
+
function isEnumType(aType) {
|
|
619
|
+
return aType.kind === 2;
|
|
620
|
+
}
|
|
621
|
+
function isImportedType(aType) {
|
|
622
|
+
return aType.kind === 4;
|
|
623
|
+
}
|
|
624
|
+
function isObjectType(aType) {
|
|
625
|
+
return aType.kind === 8;
|
|
626
|
+
}
|
|
627
|
+
function isArrayType(aType) {
|
|
628
|
+
return aType.kind === 9;
|
|
629
|
+
}
|
|
630
|
+
function jayTypeToJsonSchema(type) {
|
|
631
|
+
if (isOptionalType(type)) {
|
|
632
|
+
return jayTypeToJsonSchema(type.innerType);
|
|
633
|
+
}
|
|
634
|
+
if (isAtomicType(type)) {
|
|
635
|
+
const name = type.name.toLowerCase();
|
|
636
|
+
if (name === "string" || name === "number" || name === "boolean") {
|
|
637
|
+
return { type: name };
|
|
638
|
+
}
|
|
639
|
+
return { type: "string" };
|
|
640
|
+
}
|
|
641
|
+
if (isEnumType(type)) {
|
|
642
|
+
return { type: "string", enum: type.values };
|
|
643
|
+
}
|
|
644
|
+
if (isImportedType(type)) {
|
|
645
|
+
return { type: "object", description: `Contract: ${type.name}` };
|
|
646
|
+
}
|
|
647
|
+
if (isArrayType(type)) {
|
|
648
|
+
const itemSchema = jayTypeToJsonSchema(type.itemType);
|
|
649
|
+
if (itemSchema) {
|
|
650
|
+
return { type: "array", items: itemSchema };
|
|
651
|
+
}
|
|
652
|
+
return { type: "array" };
|
|
653
|
+
}
|
|
654
|
+
if (isObjectType(type)) {
|
|
655
|
+
const properties = {};
|
|
656
|
+
const required = [];
|
|
657
|
+
for (const [key, propType] of Object.entries(type.props)) {
|
|
658
|
+
const isOpt = isOptionalType(propType);
|
|
659
|
+
const schema = jayTypeToJsonSchema(propType);
|
|
660
|
+
if (schema) {
|
|
661
|
+
properties[key] = schema;
|
|
662
|
+
if (!isOpt) {
|
|
663
|
+
required.push(key);
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
return {
|
|
668
|
+
type: "object",
|
|
669
|
+
properties,
|
|
670
|
+
...required.length > 0 && { required }
|
|
671
|
+
};
|
|
672
|
+
}
|
|
673
|
+
return null;
|
|
674
|
+
}
|
|
481
675
|
var RuntimeMode = /* @__PURE__ */ ((RuntimeMode2) => {
|
|
482
676
|
RuntimeMode2["MainTrusted"] = "mainTrusted";
|
|
483
677
|
RuntimeMode2["MainSandbox"] = "mainSandbox";
|
|
@@ -527,6 +721,12 @@ const JAY_QUERY_PREFIX = "?jay-";
|
|
|
527
721
|
}
|
|
528
722
|
];
|
|
529
723
|
createRequire(import.meta.url);
|
|
724
|
+
function normalizeActionEntry(entry) {
|
|
725
|
+
if (typeof entry === "string") {
|
|
726
|
+
return { name: entry };
|
|
727
|
+
}
|
|
728
|
+
return { name: entry.name, action: entry.action };
|
|
729
|
+
}
|
|
530
730
|
function loadPluginManifest(pluginDir) {
|
|
531
731
|
const pluginYamlPath = path$1.join(pluginDir, "plugin.yaml");
|
|
532
732
|
if (!fs$2.existsSync(pluginYamlPath)) {
|
|
@@ -545,7 +745,63 @@ new Proxy(e, {
|
|
|
545
745
|
return t[r];
|
|
546
746
|
}
|
|
547
747
|
});
|
|
548
|
-
|
|
748
|
+
function parseActionMetadata(yamlContent, fileName) {
|
|
749
|
+
try {
|
|
750
|
+
const parsed = parseAction(yamlContent, fileName);
|
|
751
|
+
if (parsed.validations.length > 0) {
|
|
752
|
+
getLogger().warn(
|
|
753
|
+
`[ActionMetadata] ${fileName}: validation errors: ${parsed.validations.join(", ")}`
|
|
754
|
+
);
|
|
755
|
+
return null;
|
|
756
|
+
}
|
|
757
|
+
if (!parsed.val) {
|
|
758
|
+
getLogger().warn(`[ActionMetadata] ${fileName}: parsing returned no result`);
|
|
759
|
+
return null;
|
|
760
|
+
}
|
|
761
|
+
const action = parsed.val;
|
|
762
|
+
const inputJsonSchema = jayTypeToJsonSchema(action.inputType);
|
|
763
|
+
let inputSchema;
|
|
764
|
+
if (inputJsonSchema && inputJsonSchema.type === "object") {
|
|
765
|
+
inputSchema = {
|
|
766
|
+
type: "object",
|
|
767
|
+
properties: inputJsonSchema.properties || {},
|
|
768
|
+
...inputJsonSchema.required && inputJsonSchema.required.length > 0 && { required: inputJsonSchema.required }
|
|
769
|
+
};
|
|
770
|
+
} else {
|
|
771
|
+
inputSchema = { type: "object", properties: {} };
|
|
772
|
+
}
|
|
773
|
+
const metadata = {
|
|
774
|
+
name: action.name,
|
|
775
|
+
description: action.description,
|
|
776
|
+
inputSchema
|
|
777
|
+
};
|
|
778
|
+
if (action.outputType) {
|
|
779
|
+
const outputJsonSchema = jayTypeToJsonSchema(action.outputType);
|
|
780
|
+
if (outputJsonSchema) {
|
|
781
|
+
metadata.outputSchema = outputJsonSchema;
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
return metadata;
|
|
785
|
+
} catch (error) {
|
|
786
|
+
getLogger().error(
|
|
787
|
+
`[ActionMetadata] Failed to parse ${fileName}: ${error instanceof Error ? error.message : error}`
|
|
788
|
+
);
|
|
789
|
+
return null;
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
function loadActionMetadata(filePath) {
|
|
793
|
+
if (!fs.existsSync(filePath)) {
|
|
794
|
+
getLogger().warn(`[ActionMetadata] File not found: ${filePath}`);
|
|
795
|
+
return null;
|
|
796
|
+
}
|
|
797
|
+
const yamlContent = fs.readFileSync(filePath, "utf-8");
|
|
798
|
+
const fileName = path.basename(filePath);
|
|
799
|
+
return parseActionMetadata(yamlContent, fileName);
|
|
800
|
+
}
|
|
801
|
+
function resolveActionMetadataPath(actionPath, pluginDir) {
|
|
802
|
+
return path.resolve(pluginDir, actionPath);
|
|
803
|
+
}
|
|
804
|
+
const require$2 = createRequire$1(import.meta.url);
|
|
549
805
|
async function discoverAndRegisterActions(options) {
|
|
550
806
|
const {
|
|
551
807
|
projectRoot,
|
|
@@ -562,13 +818,13 @@ async function discoverAndRegisterActions(options) {
|
|
|
562
818
|
const actionsPath = path.resolve(projectRoot, actionsDir);
|
|
563
819
|
if (!fs.existsSync(actionsPath)) {
|
|
564
820
|
if (verbose) {
|
|
565
|
-
|
|
821
|
+
getLogger().info(`[Actions] No actions directory found at ${actionsPath}`);
|
|
566
822
|
}
|
|
567
823
|
return result;
|
|
568
824
|
}
|
|
569
825
|
const actionFiles = await findActionFiles(actionsPath);
|
|
570
826
|
if (verbose) {
|
|
571
|
-
|
|
827
|
+
getLogger().info(`[Actions] Found ${actionFiles.length} action file(s)`);
|
|
572
828
|
}
|
|
573
829
|
for (const filePath of actionFiles) {
|
|
574
830
|
result.scannedFiles.push(filePath);
|
|
@@ -585,12 +841,14 @@ async function discoverAndRegisterActions(options) {
|
|
|
585
841
|
result.actionNames.push(exportValue.actionName);
|
|
586
842
|
result.actionCount++;
|
|
587
843
|
if (verbose) {
|
|
588
|
-
|
|
844
|
+
getLogger().info(
|
|
845
|
+
`[Actions] Registered: ${exportValue.actionName}`
|
|
846
|
+
);
|
|
589
847
|
}
|
|
590
848
|
}
|
|
591
849
|
}
|
|
592
850
|
} catch (error) {
|
|
593
|
-
|
|
851
|
+
getLogger().error(`[Actions] Failed to import ${filePath}: ${error}`);
|
|
594
852
|
}
|
|
595
853
|
}
|
|
596
854
|
return result;
|
|
@@ -657,14 +915,14 @@ async function discoverNpmPluginActions(projectRoot, registry, verbose, viteServ
|
|
|
657
915
|
continue;
|
|
658
916
|
}
|
|
659
917
|
if (verbose) {
|
|
660
|
-
|
|
661
|
-
`[Actions] NPM plugin "${packageName}" declares actions
|
|
662
|
-
pluginConfig.actions
|
|
918
|
+
getLogger().info(
|
|
919
|
+
`[Actions] NPM plugin "${packageName}" declares actions: ${JSON.stringify(pluginConfig.actions)}`
|
|
663
920
|
);
|
|
664
921
|
}
|
|
665
922
|
const actions = await registerNpmPluginActions(
|
|
666
923
|
packageName,
|
|
667
924
|
pluginConfig,
|
|
925
|
+
pluginDir,
|
|
668
926
|
registry,
|
|
669
927
|
verbose,
|
|
670
928
|
viteServer
|
|
@@ -675,20 +933,38 @@ async function discoverNpmPluginActions(projectRoot, registry, verbose, viteServ
|
|
|
675
933
|
}
|
|
676
934
|
}
|
|
677
935
|
} catch (error) {
|
|
678
|
-
|
|
936
|
+
getLogger().error(`[Actions] Failed to read project package.json: ${error}`);
|
|
679
937
|
}
|
|
680
938
|
return allActions;
|
|
681
939
|
}
|
|
682
940
|
function tryResolvePluginYaml(packageName, projectRoot) {
|
|
683
941
|
try {
|
|
684
|
-
return require$
|
|
942
|
+
return require$2.resolve(`${packageName}/plugin.yaml`, {
|
|
685
943
|
paths: [projectRoot]
|
|
686
944
|
});
|
|
687
945
|
} catch {
|
|
688
946
|
return null;
|
|
689
947
|
}
|
|
690
948
|
}
|
|
691
|
-
|
|
949
|
+
function resolveNpmActionMetadataPath(actionPath, packageName, pluginDir) {
|
|
950
|
+
if (!actionPath.startsWith(".")) {
|
|
951
|
+
try {
|
|
952
|
+
return require$2.resolve(`${packageName}/${actionPath}`, {
|
|
953
|
+
paths: [pluginDir]
|
|
954
|
+
});
|
|
955
|
+
} catch {
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
const resolved = resolveActionMetadataPath(actionPath, pluginDir);
|
|
959
|
+
if (fs.existsSync(resolved)) {
|
|
960
|
+
return resolved;
|
|
961
|
+
}
|
|
962
|
+
getLogger().warn(
|
|
963
|
+
`[Actions] Could not resolve .jay-action file "${actionPath}" for package "${packageName}"`
|
|
964
|
+
);
|
|
965
|
+
return null;
|
|
966
|
+
}
|
|
967
|
+
async function registerNpmPluginActions(packageName, pluginConfig, pluginDir, registry, verbose, viteServer) {
|
|
692
968
|
const registeredActions = [];
|
|
693
969
|
try {
|
|
694
970
|
let pluginModule;
|
|
@@ -697,24 +973,42 @@ async function registerNpmPluginActions(packageName, pluginConfig, registry, ver
|
|
|
697
973
|
} else {
|
|
698
974
|
pluginModule = await import(packageName);
|
|
699
975
|
}
|
|
700
|
-
for (const
|
|
976
|
+
for (const entry of pluginConfig.actions) {
|
|
977
|
+
const { name: actionName, action: actionPath } = normalizeActionEntry(entry);
|
|
701
978
|
const actionExport = pluginModule[actionName];
|
|
702
979
|
if (actionExport && isJayAction(actionExport)) {
|
|
703
980
|
registry.register(actionExport);
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
981
|
+
const registeredName = actionExport.actionName;
|
|
982
|
+
registeredActions.push(registeredName);
|
|
983
|
+
if (actionPath) {
|
|
984
|
+
const metadataFilePath = resolveNpmActionMetadataPath(
|
|
985
|
+
actionPath,
|
|
986
|
+
packageName,
|
|
987
|
+
pluginDir
|
|
708
988
|
);
|
|
989
|
+
if (metadataFilePath) {
|
|
990
|
+
const metadata = loadActionMetadata(metadataFilePath);
|
|
991
|
+
if (metadata) {
|
|
992
|
+
registry.setMetadata(registeredName, metadata);
|
|
993
|
+
if (verbose) {
|
|
994
|
+
getLogger().info(
|
|
995
|
+
`[Actions] Loaded metadata for "${registeredName}" from ${actionPath}`
|
|
996
|
+
);
|
|
997
|
+
}
|
|
998
|
+
}
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
1001
|
+
if (verbose) {
|
|
1002
|
+
getLogger().info(`[Actions] Registered NPM plugin action: ${registeredName}`);
|
|
709
1003
|
}
|
|
710
1004
|
} else {
|
|
711
|
-
|
|
1005
|
+
getLogger().warn(
|
|
712
1006
|
`[Actions] NPM plugin "${packageName}" declares action "${actionName}" but it's not exported or not a JayAction`
|
|
713
1007
|
);
|
|
714
1008
|
}
|
|
715
1009
|
}
|
|
716
1010
|
} catch (importError) {
|
|
717
|
-
|
|
1011
|
+
getLogger().error(`[Actions] Failed to import NPM plugin "${packageName}": ${importError}`);
|
|
718
1012
|
}
|
|
719
1013
|
return registeredActions;
|
|
720
1014
|
}
|
|
@@ -729,7 +1023,9 @@ async function discoverPluginActions(pluginPath, projectRoot, registry = actionR
|
|
|
729
1023
|
const registeredActions = [];
|
|
730
1024
|
const pluginName = pluginConfig.name || path.basename(pluginPath);
|
|
731
1025
|
if (verbose) {
|
|
732
|
-
|
|
1026
|
+
getLogger().info(
|
|
1027
|
+
`[Actions] Plugin "${pluginName}" declares actions: ${JSON.stringify(pluginConfig.actions)}`
|
|
1028
|
+
);
|
|
733
1029
|
}
|
|
734
1030
|
let modulePath = pluginConfig.module ? path.join(pluginPath, pluginConfig.module) : path.join(pluginPath, "index.ts");
|
|
735
1031
|
if (!fs.existsSync(modulePath)) {
|
|
@@ -740,7 +1036,7 @@ async function discoverPluginActions(pluginPath, projectRoot, registry = actionR
|
|
|
740
1036
|
} else if (fs.existsSync(jsPath)) {
|
|
741
1037
|
modulePath = jsPath;
|
|
742
1038
|
} else {
|
|
743
|
-
|
|
1039
|
+
getLogger().warn(`[Actions] Plugin "${pluginName}" module not found at ${modulePath}`);
|
|
744
1040
|
return [];
|
|
745
1041
|
}
|
|
746
1042
|
}
|
|
@@ -751,31 +1047,50 @@ async function discoverPluginActions(pluginPath, projectRoot, registry = actionR
|
|
|
751
1047
|
} else {
|
|
752
1048
|
pluginModule = await import(modulePath);
|
|
753
1049
|
}
|
|
754
|
-
for (const
|
|
1050
|
+
for (const entry of pluginConfig.actions) {
|
|
1051
|
+
const { name: actionName, action: actionPath } = normalizeActionEntry(entry);
|
|
755
1052
|
const actionExport = pluginModule[actionName];
|
|
756
1053
|
if (actionExport && isJayAction(actionExport)) {
|
|
757
1054
|
registry.register(actionExport);
|
|
758
|
-
|
|
1055
|
+
const registeredName = actionExport.actionName;
|
|
1056
|
+
registeredActions.push(registeredName);
|
|
1057
|
+
if (actionPath) {
|
|
1058
|
+
const metadataFilePath = resolveActionMetadataPath(actionPath, pluginPath);
|
|
1059
|
+
const metadata = loadActionMetadata(metadataFilePath);
|
|
1060
|
+
if (metadata) {
|
|
1061
|
+
registry.setMetadata(registeredName, metadata);
|
|
1062
|
+
if (verbose) {
|
|
1063
|
+
getLogger().info(
|
|
1064
|
+
`[Actions] Loaded metadata for "${registeredName}" from ${actionPath}`
|
|
1065
|
+
);
|
|
1066
|
+
}
|
|
1067
|
+
}
|
|
1068
|
+
}
|
|
759
1069
|
if (verbose) {
|
|
760
|
-
|
|
761
|
-
`[Actions] Registered plugin action: ${actionExport.actionName}`
|
|
762
|
-
);
|
|
1070
|
+
getLogger().info(`[Actions] Registered plugin action: ${registeredName}`);
|
|
763
1071
|
}
|
|
764
1072
|
} else {
|
|
765
|
-
|
|
1073
|
+
getLogger().warn(
|
|
766
1074
|
`[Actions] Plugin "${pluginName}" declares action "${actionName}" but it's not exported or not a JayAction`
|
|
767
1075
|
);
|
|
768
1076
|
}
|
|
769
1077
|
}
|
|
770
1078
|
} catch (importError) {
|
|
771
|
-
|
|
1079
|
+
getLogger().error(
|
|
1080
|
+
`[Actions] Failed to import plugin module at ${modulePath}: ${importError}`
|
|
1081
|
+
);
|
|
772
1082
|
}
|
|
773
1083
|
return registeredActions;
|
|
774
1084
|
}
|
|
775
|
-
const
|
|
776
|
-
async function
|
|
777
|
-
const {
|
|
778
|
-
|
|
1085
|
+
const require$1 = createRequire$1(import.meta.url);
|
|
1086
|
+
async function scanPlugins(options) {
|
|
1087
|
+
const {
|
|
1088
|
+
projectRoot,
|
|
1089
|
+
verbose = false,
|
|
1090
|
+
includeDevDeps = false,
|
|
1091
|
+
discoverTransitive = false
|
|
1092
|
+
} = options;
|
|
1093
|
+
const plugins = /* @__PURE__ */ new Map();
|
|
779
1094
|
const visitedPackages = /* @__PURE__ */ new Set();
|
|
780
1095
|
const localPluginsPath = path.join(projectRoot, "src/plugins");
|
|
781
1096
|
if (fs.existsSync(localPluginsPath)) {
|
|
@@ -788,37 +1103,37 @@ async function discoverPluginsWithInit(options) {
|
|
|
788
1103
|
const manifest = loadPluginManifest(pluginPath);
|
|
789
1104
|
if (!manifest)
|
|
790
1105
|
continue;
|
|
791
|
-
const initConfig = resolvePluginInit(pluginPath, manifest.init, true);
|
|
792
|
-
if (!initConfig)
|
|
793
|
-
continue;
|
|
794
1106
|
const dependencies = await getPackageDependencies(pluginPath);
|
|
795
|
-
|
|
796
|
-
|
|
1107
|
+
const pluginName = manifest.name || entry.name;
|
|
1108
|
+
plugins.set(entry.name, {
|
|
1109
|
+
name: pluginName,
|
|
797
1110
|
pluginPath,
|
|
798
1111
|
packageName: pluginPath,
|
|
799
|
-
// For local, use path
|
|
1112
|
+
// For local, use path as identifier
|
|
800
1113
|
isLocal: true,
|
|
801
|
-
|
|
802
|
-
initExport: initConfig.export,
|
|
1114
|
+
manifest,
|
|
803
1115
|
dependencies
|
|
804
1116
|
});
|
|
805
1117
|
visitedPackages.add(pluginPath);
|
|
806
1118
|
if (verbose) {
|
|
807
|
-
|
|
808
|
-
`[PluginInit] Found local plugin with init: ${manifest.name || entry.name}`
|
|
809
|
-
);
|
|
1119
|
+
getLogger().info(`[PluginScanner] Found local plugin: ${pluginName}`);
|
|
810
1120
|
}
|
|
811
1121
|
}
|
|
812
1122
|
} catch (error) {
|
|
813
|
-
|
|
1123
|
+
if (verbose) {
|
|
1124
|
+
getLogger().warn(`[PluginScanner] Failed to scan local plugins: ${error}`);
|
|
1125
|
+
}
|
|
814
1126
|
}
|
|
815
1127
|
}
|
|
816
1128
|
const projectPackageJsonPath = path.join(projectRoot, "package.json");
|
|
817
1129
|
if (fs.existsSync(projectPackageJsonPath)) {
|
|
818
1130
|
try {
|
|
819
1131
|
const projectPackageJson = JSON.parse(fs.readFileSync(projectPackageJsonPath, "utf-8"));
|
|
820
|
-
const
|
|
821
|
-
|
|
1132
|
+
const deps = {
|
|
1133
|
+
...projectPackageJson.dependencies,
|
|
1134
|
+
...includeDevDeps ? projectPackageJson.devDependencies : {}
|
|
1135
|
+
};
|
|
1136
|
+
const packagesToCheck = Object.keys(deps);
|
|
822
1137
|
while (packagesToCheck.length > 0) {
|
|
823
1138
|
const depName = packagesToCheck.shift();
|
|
824
1139
|
if (visitedPackages.has(depName))
|
|
@@ -826,7 +1141,7 @@ async function discoverPluginsWithInit(options) {
|
|
|
826
1141
|
visitedPackages.add(depName);
|
|
827
1142
|
let pluginYamlPath;
|
|
828
1143
|
try {
|
|
829
|
-
pluginYamlPath =
|
|
1144
|
+
pluginYamlPath = require$1.resolve(`${depName}/plugin.yaml`, {
|
|
830
1145
|
paths: [projectRoot]
|
|
831
1146
|
});
|
|
832
1147
|
} catch {
|
|
@@ -836,30 +1151,77 @@ async function discoverPluginsWithInit(options) {
|
|
|
836
1151
|
const manifest = loadPluginManifest(pluginPath);
|
|
837
1152
|
if (!manifest)
|
|
838
1153
|
continue;
|
|
839
|
-
const initConfig = resolvePluginInit(pluginPath, manifest.init, false);
|
|
840
|
-
if (!initConfig)
|
|
841
|
-
continue;
|
|
842
1154
|
const dependencies = await getPackageDependencies(pluginPath);
|
|
843
|
-
plugins.
|
|
1155
|
+
plugins.set(depName, {
|
|
844
1156
|
name: manifest.name || depName,
|
|
845
1157
|
pluginPath,
|
|
846
1158
|
packageName: depName,
|
|
847
1159
|
isLocal: false,
|
|
848
|
-
|
|
849
|
-
initExport: initConfig.export,
|
|
1160
|
+
manifest,
|
|
850
1161
|
dependencies
|
|
851
1162
|
});
|
|
852
1163
|
if (verbose) {
|
|
853
|
-
|
|
1164
|
+
getLogger().info(`[PluginScanner] Found NPM plugin: ${depName}`);
|
|
854
1165
|
}
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
1166
|
+
if (discoverTransitive) {
|
|
1167
|
+
for (const transitiveDep of dependencies) {
|
|
1168
|
+
if (!visitedPackages.has(transitiveDep)) {
|
|
1169
|
+
packagesToCheck.push(transitiveDep);
|
|
1170
|
+
}
|
|
858
1171
|
}
|
|
859
1172
|
}
|
|
860
1173
|
}
|
|
861
1174
|
} catch (error) {
|
|
862
|
-
|
|
1175
|
+
if (verbose) {
|
|
1176
|
+
getLogger().warn(`[PluginScanner] Failed to scan NPM plugins: ${error}`);
|
|
1177
|
+
}
|
|
1178
|
+
}
|
|
1179
|
+
}
|
|
1180
|
+
return plugins;
|
|
1181
|
+
}
|
|
1182
|
+
async function getPackageDependencies(pluginPath) {
|
|
1183
|
+
const packageJsonPath = path.join(pluginPath, "package.json");
|
|
1184
|
+
if (!fs.existsSync(packageJsonPath)) {
|
|
1185
|
+
return [];
|
|
1186
|
+
}
|
|
1187
|
+
try {
|
|
1188
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
|
|
1189
|
+
return Object.keys(packageJson.dependencies || {});
|
|
1190
|
+
} catch {
|
|
1191
|
+
return [];
|
|
1192
|
+
}
|
|
1193
|
+
}
|
|
1194
|
+
async function discoverPluginsWithInit(options) {
|
|
1195
|
+
const { projectRoot, verbose = false } = options;
|
|
1196
|
+
const scannedPlugins = await scanPlugins({
|
|
1197
|
+
projectRoot,
|
|
1198
|
+
verbose,
|
|
1199
|
+
includeDevDeps: false,
|
|
1200
|
+
// Only runtime dependencies
|
|
1201
|
+
discoverTransitive: true
|
|
1202
|
+
// Need transitive for dependency ordering
|
|
1203
|
+
});
|
|
1204
|
+
const plugins = [];
|
|
1205
|
+
for (const [key, scanned] of scannedPlugins) {
|
|
1206
|
+
const initConfig = resolvePluginInit(
|
|
1207
|
+
scanned.pluginPath,
|
|
1208
|
+
scanned.manifest.init,
|
|
1209
|
+
scanned.isLocal
|
|
1210
|
+
);
|
|
1211
|
+
if (!initConfig)
|
|
1212
|
+
continue;
|
|
1213
|
+
plugins.push({
|
|
1214
|
+
name: scanned.name,
|
|
1215
|
+
pluginPath: scanned.pluginPath,
|
|
1216
|
+
packageName: scanned.packageName,
|
|
1217
|
+
isLocal: scanned.isLocal,
|
|
1218
|
+
initModule: initConfig.module,
|
|
1219
|
+
initExport: initConfig.export,
|
|
1220
|
+
dependencies: scanned.dependencies,
|
|
1221
|
+
global: scanned.manifest.global === true
|
|
1222
|
+
});
|
|
1223
|
+
if (verbose) {
|
|
1224
|
+
getLogger().info(`[PluginInit] Found plugin with init: ${scanned.name}`);
|
|
863
1225
|
}
|
|
864
1226
|
}
|
|
865
1227
|
return plugins;
|
|
@@ -899,18 +1261,6 @@ function resolvePluginInit(pluginPath, initConfig, isLocal) {
|
|
|
899
1261
|
return null;
|
|
900
1262
|
}
|
|
901
1263
|
}
|
|
902
|
-
async function getPackageDependencies(pluginPath) {
|
|
903
|
-
const packageJsonPath = path.join(pluginPath, "package.json");
|
|
904
|
-
if (!fs.existsSync(packageJsonPath)) {
|
|
905
|
-
return [];
|
|
906
|
-
}
|
|
907
|
-
try {
|
|
908
|
-
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
|
|
909
|
-
return Object.keys(packageJson.dependencies || {});
|
|
910
|
-
} catch {
|
|
911
|
-
return [];
|
|
912
|
-
}
|
|
913
|
-
}
|
|
914
1264
|
function sortPluginsByDependencies(plugins) {
|
|
915
1265
|
const pluginNames = new Set(plugins.map((p) => p.packageName));
|
|
916
1266
|
const sorted = [];
|
|
@@ -920,7 +1270,7 @@ function sortPluginsByDependencies(plugins) {
|
|
|
920
1270
|
if (visited.has(plugin.packageName))
|
|
921
1271
|
return;
|
|
922
1272
|
if (visiting.has(plugin.packageName)) {
|
|
923
|
-
|
|
1273
|
+
getLogger().warn(`[PluginInit] Circular dependency detected for ${plugin.name}`);
|
|
924
1274
|
return;
|
|
925
1275
|
}
|
|
926
1276
|
visiting.add(plugin.packageName);
|
|
@@ -942,6 +1292,7 @@ function sortPluginsByDependencies(plugins) {
|
|
|
942
1292
|
return sorted;
|
|
943
1293
|
}
|
|
944
1294
|
async function executePluginServerInits(plugins, viteServer, verbose = false) {
|
|
1295
|
+
const initErrors = /* @__PURE__ */ new Map();
|
|
945
1296
|
for (const plugin of plugins) {
|
|
946
1297
|
try {
|
|
947
1298
|
let modulePath;
|
|
@@ -960,14 +1311,14 @@ async function executePluginServerInits(plugins, viteServer, verbose = false) {
|
|
|
960
1311
|
}
|
|
961
1312
|
const jayInit = pluginModule[plugin.initExport];
|
|
962
1313
|
if (!jayInit || jayInit.__brand !== "JayInit") {
|
|
963
|
-
|
|
1314
|
+
getLogger().warn(
|
|
964
1315
|
`[PluginInit] Plugin "${plugin.name}" init module doesn't export a valid JayInit at "${plugin.initExport}"`
|
|
965
1316
|
);
|
|
966
1317
|
continue;
|
|
967
1318
|
}
|
|
968
1319
|
if (typeof jayInit._serverInit === "function") {
|
|
969
1320
|
if (verbose) {
|
|
970
|
-
|
|
1321
|
+
getLogger().info(`[DevServer] Running server init: ${plugin.name}`);
|
|
971
1322
|
}
|
|
972
1323
|
const clientData = await jayInit._serverInit();
|
|
973
1324
|
if (clientData !== void 0 && clientData !== null) {
|
|
@@ -975,12 +1326,14 @@ async function executePluginServerInits(plugins, viteServer, verbose = false) {
|
|
|
975
1326
|
}
|
|
976
1327
|
}
|
|
977
1328
|
} catch (error) {
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
1329
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
1330
|
+
initErrors.set(plugin.name, err);
|
|
1331
|
+
getLogger().error(
|
|
1332
|
+
`[PluginInit] Failed to execute server init for "${plugin.name}": ${error}`
|
|
981
1333
|
);
|
|
982
1334
|
}
|
|
983
1335
|
}
|
|
1336
|
+
return initErrors;
|
|
984
1337
|
}
|
|
985
1338
|
function preparePluginClientInits(plugins) {
|
|
986
1339
|
return plugins.map((plugin) => {
|
|
@@ -1146,6 +1499,509 @@ class SlowRenderCache {
|
|
|
1146
1499
|
return Array.from(this.pathToKeys.keys());
|
|
1147
1500
|
}
|
|
1148
1501
|
}
|
|
1502
|
+
const require2 = createRequire(import.meta.url);
|
|
1503
|
+
async function executeDynamicGenerator(plugin, config, projectRoot, services, verbose, viteServer) {
|
|
1504
|
+
const { pluginPath, name: pluginName, isLocal, packageName } = plugin;
|
|
1505
|
+
if (!config.generator) {
|
|
1506
|
+
throw new Error(
|
|
1507
|
+
`Plugin "${pluginName}" has dynamic_contracts entry but no generator specified`
|
|
1508
|
+
);
|
|
1509
|
+
}
|
|
1510
|
+
const isFilePath = config.generator.startsWith("./") || config.generator.startsWith("/") || config.generator.includes(".ts") || config.generator.includes(".js");
|
|
1511
|
+
let generator;
|
|
1512
|
+
if (isFilePath) {
|
|
1513
|
+
let generatorPath;
|
|
1514
|
+
if (!isLocal) {
|
|
1515
|
+
try {
|
|
1516
|
+
generatorPath = require2.resolve(`${packageName}/${config.generator}`, {
|
|
1517
|
+
paths: [projectRoot]
|
|
1518
|
+
});
|
|
1519
|
+
} catch {
|
|
1520
|
+
generatorPath = path.join(pluginPath, config.generator);
|
|
1521
|
+
}
|
|
1522
|
+
} else {
|
|
1523
|
+
generatorPath = path.join(pluginPath, config.generator);
|
|
1524
|
+
}
|
|
1525
|
+
if (!fs.existsSync(generatorPath)) {
|
|
1526
|
+
const withTs = generatorPath + ".ts";
|
|
1527
|
+
const withJs = generatorPath + ".js";
|
|
1528
|
+
if (fs.existsSync(withTs)) {
|
|
1529
|
+
generatorPath = withTs;
|
|
1530
|
+
} else if (fs.existsSync(withJs)) {
|
|
1531
|
+
generatorPath = withJs;
|
|
1532
|
+
}
|
|
1533
|
+
}
|
|
1534
|
+
if (!fs.existsSync(generatorPath)) {
|
|
1535
|
+
throw new Error(
|
|
1536
|
+
`Generator file not found for plugin "${pluginName}": ${config.generator}`
|
|
1537
|
+
);
|
|
1538
|
+
}
|
|
1539
|
+
if (verbose) {
|
|
1540
|
+
getLogger().info(` Loading generator from file: ${generatorPath}`);
|
|
1541
|
+
}
|
|
1542
|
+
let generatorModule;
|
|
1543
|
+
if (viteServer) {
|
|
1544
|
+
generatorModule = await viteServer.ssrLoadModule(generatorPath);
|
|
1545
|
+
} else {
|
|
1546
|
+
generatorModule = await import(generatorPath);
|
|
1547
|
+
}
|
|
1548
|
+
generator = generatorModule.generator || generatorModule.default;
|
|
1549
|
+
} else {
|
|
1550
|
+
if (verbose) {
|
|
1551
|
+
getLogger().info(
|
|
1552
|
+
` Loading generator export: ${config.generator} from ${packageName}`
|
|
1553
|
+
);
|
|
1554
|
+
}
|
|
1555
|
+
let pluginModule;
|
|
1556
|
+
if (viteServer) {
|
|
1557
|
+
pluginModule = await viteServer.ssrLoadModule(packageName);
|
|
1558
|
+
} else {
|
|
1559
|
+
pluginModule = await import(packageName);
|
|
1560
|
+
}
|
|
1561
|
+
generator = pluginModule[config.generator];
|
|
1562
|
+
if (!generator) {
|
|
1563
|
+
throw new Error(
|
|
1564
|
+
`Generator "${config.generator}" not exported from plugin "${pluginName}". Ensure it's exported from the package's index.ts`
|
|
1565
|
+
);
|
|
1566
|
+
}
|
|
1567
|
+
}
|
|
1568
|
+
if (!generator || typeof generator.generate !== "function") {
|
|
1569
|
+
throw new Error(
|
|
1570
|
+
`Generator "${config.generator}" for plugin "${pluginName}" must have a 'generate' function. Use makeContractGenerator() to create valid generators.`
|
|
1571
|
+
);
|
|
1572
|
+
}
|
|
1573
|
+
const resolvedServices = [];
|
|
1574
|
+
for (const marker of generator.services) {
|
|
1575
|
+
const service = services.get(marker);
|
|
1576
|
+
if (!service) {
|
|
1577
|
+
const markerName = marker.description ?? "unknown";
|
|
1578
|
+
throw new Error(
|
|
1579
|
+
`Service "${markerName}" required by ${pluginName} generator not found. Ensure it's registered in init.ts`
|
|
1580
|
+
);
|
|
1581
|
+
}
|
|
1582
|
+
resolvedServices.push(service);
|
|
1583
|
+
}
|
|
1584
|
+
if (verbose) {
|
|
1585
|
+
getLogger().info(` Executing generator...`);
|
|
1586
|
+
}
|
|
1587
|
+
return await generator.generate(...resolvedServices);
|
|
1588
|
+
}
|
|
1589
|
+
function resolveStaticContractPath(plugin, contractSpec, projectRoot) {
|
|
1590
|
+
const { pluginPath, isLocal, packageName } = plugin;
|
|
1591
|
+
if (!isLocal) {
|
|
1592
|
+
try {
|
|
1593
|
+
return require2.resolve(`${packageName}/${contractSpec}`, {
|
|
1594
|
+
paths: [projectRoot]
|
|
1595
|
+
});
|
|
1596
|
+
} catch {
|
|
1597
|
+
const possiblePaths = [
|
|
1598
|
+
path.join(pluginPath, "dist", contractSpec),
|
|
1599
|
+
path.join(pluginPath, "lib", contractSpec),
|
|
1600
|
+
path.join(pluginPath, contractSpec)
|
|
1601
|
+
];
|
|
1602
|
+
const found = possiblePaths.find((p) => fs.existsSync(p));
|
|
1603
|
+
return found || possiblePaths[0];
|
|
1604
|
+
}
|
|
1605
|
+
} else {
|
|
1606
|
+
return path.join(pluginPath, contractSpec);
|
|
1607
|
+
}
|
|
1608
|
+
}
|
|
1609
|
+
function resolveActionFilePath(actionPath, packageName, pluginPath, isLocal, projectRoot) {
|
|
1610
|
+
if (!isLocal && !actionPath.startsWith(".")) {
|
|
1611
|
+
try {
|
|
1612
|
+
return require2.resolve(`${packageName}/${actionPath}`, {
|
|
1613
|
+
paths: [projectRoot]
|
|
1614
|
+
});
|
|
1615
|
+
} catch {
|
|
1616
|
+
const possiblePaths = [
|
|
1617
|
+
path.join(pluginPath, "dist", actionPath),
|
|
1618
|
+
path.join(pluginPath, "lib", actionPath),
|
|
1619
|
+
path.join(pluginPath, actionPath)
|
|
1620
|
+
];
|
|
1621
|
+
const found = possiblePaths.find((p) => fs.existsSync(p));
|
|
1622
|
+
return found || null;
|
|
1623
|
+
}
|
|
1624
|
+
}
|
|
1625
|
+
const resolved = resolveActionMetadataPath(actionPath, pluginPath);
|
|
1626
|
+
return fs.existsSync(resolved) ? resolved : null;
|
|
1627
|
+
}
|
|
1628
|
+
function toKebabCase(str) {
|
|
1629
|
+
return str.replace(/([A-Z])/g, "-$1").toLowerCase().replace(/^-/, "");
|
|
1630
|
+
}
|
|
1631
|
+
function getJayStackVersion() {
|
|
1632
|
+
try {
|
|
1633
|
+
const packageJsonPath = path.join(__dirname, "..", "package.json");
|
|
1634
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
|
|
1635
|
+
return packageJson.version || "0.0.0";
|
|
1636
|
+
} catch {
|
|
1637
|
+
return "0.0.0";
|
|
1638
|
+
}
|
|
1639
|
+
}
|
|
1640
|
+
async function materializeContracts(options, services = /* @__PURE__ */ new Map()) {
|
|
1641
|
+
const {
|
|
1642
|
+
projectRoot,
|
|
1643
|
+
outputDir = path.join(projectRoot, "build", "materialized-contracts"),
|
|
1644
|
+
dynamicOnly = false,
|
|
1645
|
+
pluginFilter,
|
|
1646
|
+
verbose = false,
|
|
1647
|
+
viteServer
|
|
1648
|
+
} = options;
|
|
1649
|
+
const contracts = [];
|
|
1650
|
+
const pluginsIndexMap = /* @__PURE__ */ new Map();
|
|
1651
|
+
let staticCount = 0;
|
|
1652
|
+
let dynamicCount = 0;
|
|
1653
|
+
if (verbose) {
|
|
1654
|
+
getLogger().info("Scanning for plugins...");
|
|
1655
|
+
}
|
|
1656
|
+
const plugins = await scanPlugins({
|
|
1657
|
+
projectRoot,
|
|
1658
|
+
verbose,
|
|
1659
|
+
includeDevDeps: true
|
|
1660
|
+
// Include dev deps for contract discovery
|
|
1661
|
+
});
|
|
1662
|
+
if (verbose) {
|
|
1663
|
+
getLogger().info(`Found ${plugins.size} plugin(s)`);
|
|
1664
|
+
}
|
|
1665
|
+
for (const [pluginKey, plugin] of plugins) {
|
|
1666
|
+
if (pluginFilter && plugin.name !== pluginFilter && pluginKey !== pluginFilter)
|
|
1667
|
+
continue;
|
|
1668
|
+
if (verbose) {
|
|
1669
|
+
getLogger().info(`
|
|
1670
|
+
📦 Processing plugin: ${plugin.name}`);
|
|
1671
|
+
}
|
|
1672
|
+
const { manifest } = plugin;
|
|
1673
|
+
if (!dynamicOnly && manifest.contracts) {
|
|
1674
|
+
for (const contract of manifest.contracts) {
|
|
1675
|
+
const contractPath = resolveStaticContractPath(
|
|
1676
|
+
plugin,
|
|
1677
|
+
contract.contract,
|
|
1678
|
+
projectRoot
|
|
1679
|
+
);
|
|
1680
|
+
const relativePath = path.relative(projectRoot, contractPath);
|
|
1681
|
+
const entry = {
|
|
1682
|
+
plugin: plugin.name,
|
|
1683
|
+
name: contract.name,
|
|
1684
|
+
type: "static",
|
|
1685
|
+
path: "./" + relativePath
|
|
1686
|
+
};
|
|
1687
|
+
contracts.push(entry);
|
|
1688
|
+
staticCount++;
|
|
1689
|
+
const pluginRelPath = path.relative(projectRoot, plugin.pluginPath);
|
|
1690
|
+
if (!pluginsIndexMap.has(plugin.name)) {
|
|
1691
|
+
pluginsIndexMap.set(plugin.name, {
|
|
1692
|
+
path: "./" + pluginRelPath.replace(/\\/g, "/"),
|
|
1693
|
+
contracts: [],
|
|
1694
|
+
actions: []
|
|
1695
|
+
});
|
|
1696
|
+
}
|
|
1697
|
+
pluginsIndexMap.get(plugin.name).contracts.push({
|
|
1698
|
+
name: contract.name,
|
|
1699
|
+
type: "static",
|
|
1700
|
+
path: "./" + relativePath
|
|
1701
|
+
});
|
|
1702
|
+
if (verbose) {
|
|
1703
|
+
getLogger().info(` 📄 Static: ${contract.name}`);
|
|
1704
|
+
}
|
|
1705
|
+
}
|
|
1706
|
+
}
|
|
1707
|
+
if (manifest.dynamic_contracts) {
|
|
1708
|
+
const dynamicConfigs = Array.isArray(manifest.dynamic_contracts) ? manifest.dynamic_contracts : [manifest.dynamic_contracts];
|
|
1709
|
+
const pluginOutputDir = path.join(outputDir, plugin.name.replace(/[@/]/g, "_"));
|
|
1710
|
+
fs.mkdirSync(pluginOutputDir, { recursive: true });
|
|
1711
|
+
for (const config of dynamicConfigs) {
|
|
1712
|
+
if (verbose) {
|
|
1713
|
+
getLogger().info(` ⚡ Dynamic contracts (prefix: ${config.prefix})`);
|
|
1714
|
+
}
|
|
1715
|
+
try {
|
|
1716
|
+
const generatedContracts = await executeDynamicGenerator(
|
|
1717
|
+
plugin,
|
|
1718
|
+
config,
|
|
1719
|
+
projectRoot,
|
|
1720
|
+
services,
|
|
1721
|
+
verbose,
|
|
1722
|
+
viteServer
|
|
1723
|
+
);
|
|
1724
|
+
const prefix = config.prefix;
|
|
1725
|
+
for (const generated of generatedContracts) {
|
|
1726
|
+
const fullName = `${prefix}/${toKebabCase(generated.name)}`;
|
|
1727
|
+
const fileName = `${prefix}-${toKebabCase(generated.name)}.jay-contract`;
|
|
1728
|
+
const filePath = path.join(pluginOutputDir, fileName);
|
|
1729
|
+
fs.writeFileSync(filePath, generated.yaml, "utf-8");
|
|
1730
|
+
const relativePath = path.relative(projectRoot, filePath);
|
|
1731
|
+
const dynEntry = {
|
|
1732
|
+
plugin: plugin.name,
|
|
1733
|
+
name: fullName,
|
|
1734
|
+
type: "dynamic",
|
|
1735
|
+
path: "./" + relativePath,
|
|
1736
|
+
metadata: generated.metadata
|
|
1737
|
+
};
|
|
1738
|
+
contracts.push(dynEntry);
|
|
1739
|
+
dynamicCount++;
|
|
1740
|
+
const pluginRelPath = path.relative(projectRoot, plugin.pluginPath);
|
|
1741
|
+
if (!pluginsIndexMap.has(plugin.name)) {
|
|
1742
|
+
pluginsIndexMap.set(plugin.name, {
|
|
1743
|
+
path: "./" + pluginRelPath.replace(/\\/g, "/"),
|
|
1744
|
+
contracts: [],
|
|
1745
|
+
actions: []
|
|
1746
|
+
});
|
|
1747
|
+
}
|
|
1748
|
+
pluginsIndexMap.get(plugin.name).contracts.push({
|
|
1749
|
+
name: fullName,
|
|
1750
|
+
type: "dynamic",
|
|
1751
|
+
path: "./" + relativePath
|
|
1752
|
+
});
|
|
1753
|
+
if (verbose) {
|
|
1754
|
+
getLogger().info(` ⚡ Materialized: ${fullName}`);
|
|
1755
|
+
}
|
|
1756
|
+
}
|
|
1757
|
+
} catch (error) {
|
|
1758
|
+
getLogger().error(
|
|
1759
|
+
` ❌ Failed to materialize dynamic contracts for ${plugin.name} (${config.prefix}): ${error}`
|
|
1760
|
+
);
|
|
1761
|
+
}
|
|
1762
|
+
}
|
|
1763
|
+
}
|
|
1764
|
+
if (manifest.actions && Array.isArray(manifest.actions)) {
|
|
1765
|
+
for (const entry of manifest.actions) {
|
|
1766
|
+
const { name: actionName, action: actionPath } = normalizeActionEntry(entry);
|
|
1767
|
+
if (!actionPath)
|
|
1768
|
+
continue;
|
|
1769
|
+
const metadataFilePath = resolveActionFilePath(
|
|
1770
|
+
actionPath,
|
|
1771
|
+
plugin.packageName,
|
|
1772
|
+
plugin.pluginPath,
|
|
1773
|
+
plugin.isLocal,
|
|
1774
|
+
projectRoot
|
|
1775
|
+
);
|
|
1776
|
+
if (!metadataFilePath)
|
|
1777
|
+
continue;
|
|
1778
|
+
const metadata = loadActionMetadata(metadataFilePath);
|
|
1779
|
+
if (!metadata)
|
|
1780
|
+
continue;
|
|
1781
|
+
const pluginRelPath = path.relative(projectRoot, plugin.pluginPath);
|
|
1782
|
+
if (!pluginsIndexMap.has(plugin.name)) {
|
|
1783
|
+
pluginsIndexMap.set(plugin.name, {
|
|
1784
|
+
path: "./" + pluginRelPath.replace(/\\/g, "/"),
|
|
1785
|
+
contracts: [],
|
|
1786
|
+
actions: []
|
|
1787
|
+
});
|
|
1788
|
+
}
|
|
1789
|
+
const actionRelPath = path.relative(projectRoot, metadataFilePath);
|
|
1790
|
+
pluginsIndexMap.get(plugin.name).actions.push({
|
|
1791
|
+
name: metadata.name,
|
|
1792
|
+
description: metadata.description,
|
|
1793
|
+
path: "./" + actionRelPath.replace(/\\/g, "/")
|
|
1794
|
+
});
|
|
1795
|
+
if (verbose) {
|
|
1796
|
+
getLogger().info(` 🔧 Action: ${metadata.name} (${actionPath})`);
|
|
1797
|
+
}
|
|
1798
|
+
}
|
|
1799
|
+
}
|
|
1800
|
+
}
|
|
1801
|
+
const index = {
|
|
1802
|
+
materialized_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1803
|
+
jay_stack_version: getJayStackVersion(),
|
|
1804
|
+
contracts
|
|
1805
|
+
};
|
|
1806
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
1807
|
+
const indexPath = path.join(outputDir, "contracts-index.yaml");
|
|
1808
|
+
fs.writeFileSync(indexPath, YAML.stringify(index), "utf-8");
|
|
1809
|
+
const pluginsIndex = {
|
|
1810
|
+
materialized_at: index.materialized_at,
|
|
1811
|
+
jay_stack_version: index.jay_stack_version,
|
|
1812
|
+
plugins: Array.from(pluginsIndexMap.entries()).map(([name, data]) => ({
|
|
1813
|
+
name,
|
|
1814
|
+
path: data.path,
|
|
1815
|
+
contracts: data.contracts,
|
|
1816
|
+
...data.actions.length > 0 && { actions: data.actions }
|
|
1817
|
+
}))
|
|
1818
|
+
};
|
|
1819
|
+
const pluginsIndexPath = path.join(outputDir, "plugins-index.yaml");
|
|
1820
|
+
fs.writeFileSync(pluginsIndexPath, YAML.stringify(pluginsIndex), "utf-8");
|
|
1821
|
+
if (verbose) {
|
|
1822
|
+
getLogger().info(`
|
|
1823
|
+
✅ Contracts index written to: ${indexPath}`);
|
|
1824
|
+
getLogger().info(`✅ Plugins index written to: ${pluginsIndexPath}`);
|
|
1825
|
+
}
|
|
1826
|
+
return {
|
|
1827
|
+
index,
|
|
1828
|
+
staticCount,
|
|
1829
|
+
dynamicCount,
|
|
1830
|
+
outputDir
|
|
1831
|
+
};
|
|
1832
|
+
}
|
|
1833
|
+
async function listContracts(options) {
|
|
1834
|
+
const { projectRoot, dynamicOnly = false, pluginFilter } = options;
|
|
1835
|
+
const contracts = [];
|
|
1836
|
+
const plugins = await scanPlugins({
|
|
1837
|
+
projectRoot,
|
|
1838
|
+
includeDevDeps: true
|
|
1839
|
+
});
|
|
1840
|
+
for (const [pluginKey, plugin] of plugins) {
|
|
1841
|
+
if (pluginFilter && plugin.name !== pluginFilter && pluginKey !== pluginFilter)
|
|
1842
|
+
continue;
|
|
1843
|
+
const { manifest } = plugin;
|
|
1844
|
+
if (!dynamicOnly && manifest.contracts) {
|
|
1845
|
+
for (const contract of manifest.contracts) {
|
|
1846
|
+
const contractPath = resolveStaticContractPath(
|
|
1847
|
+
plugin,
|
|
1848
|
+
contract.contract,
|
|
1849
|
+
projectRoot
|
|
1850
|
+
);
|
|
1851
|
+
const relativePath = path.relative(projectRoot, contractPath);
|
|
1852
|
+
contracts.push({
|
|
1853
|
+
plugin: plugin.name,
|
|
1854
|
+
name: contract.name,
|
|
1855
|
+
type: "static",
|
|
1856
|
+
path: "./" + relativePath
|
|
1857
|
+
});
|
|
1858
|
+
}
|
|
1859
|
+
}
|
|
1860
|
+
if (manifest.dynamic_contracts) {
|
|
1861
|
+
const dynamicConfigs = Array.isArray(manifest.dynamic_contracts) ? manifest.dynamic_contracts : [manifest.dynamic_contracts];
|
|
1862
|
+
for (const config of dynamicConfigs) {
|
|
1863
|
+
contracts.push({
|
|
1864
|
+
plugin: plugin.name,
|
|
1865
|
+
name: `${config.prefix}/*`,
|
|
1866
|
+
type: "dynamic",
|
|
1867
|
+
path: "(run materialization to generate)"
|
|
1868
|
+
});
|
|
1869
|
+
}
|
|
1870
|
+
}
|
|
1871
|
+
}
|
|
1872
|
+
return {
|
|
1873
|
+
materialized_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1874
|
+
jay_stack_version: getJayStackVersion(),
|
|
1875
|
+
contracts
|
|
1876
|
+
};
|
|
1877
|
+
}
|
|
1878
|
+
async function discoverPluginsWithSetup(options) {
|
|
1879
|
+
const { projectRoot, verbose, pluginFilter } = options;
|
|
1880
|
+
const allPlugins = await scanPlugins({
|
|
1881
|
+
projectRoot,
|
|
1882
|
+
verbose,
|
|
1883
|
+
discoverTransitive: true
|
|
1884
|
+
});
|
|
1885
|
+
const pluginsWithSetup = [];
|
|
1886
|
+
for (const [packageName, plugin] of allPlugins) {
|
|
1887
|
+
if (!plugin.manifest.setup?.handler)
|
|
1888
|
+
continue;
|
|
1889
|
+
if (pluginFilter && plugin.name !== pluginFilter && packageName !== pluginFilter) {
|
|
1890
|
+
continue;
|
|
1891
|
+
}
|
|
1892
|
+
pluginsWithSetup.push({
|
|
1893
|
+
name: plugin.name,
|
|
1894
|
+
pluginPath: plugin.pluginPath,
|
|
1895
|
+
packageName: plugin.packageName,
|
|
1896
|
+
isLocal: plugin.isLocal,
|
|
1897
|
+
setupHandler: plugin.manifest.setup.handler,
|
|
1898
|
+
setupDescription: plugin.manifest.setup.description,
|
|
1899
|
+
dependencies: plugin.dependencies
|
|
1900
|
+
});
|
|
1901
|
+
if (verbose) {
|
|
1902
|
+
getLogger().info(`[Setup] Found plugin with setup: ${plugin.name}`);
|
|
1903
|
+
}
|
|
1904
|
+
}
|
|
1905
|
+
return sortByDependencies(pluginsWithSetup);
|
|
1906
|
+
}
|
|
1907
|
+
async function discoverPluginsWithReferences(options) {
|
|
1908
|
+
const { projectRoot, verbose, pluginFilter } = options;
|
|
1909
|
+
const allPlugins = await scanPlugins({
|
|
1910
|
+
projectRoot,
|
|
1911
|
+
verbose,
|
|
1912
|
+
discoverTransitive: true
|
|
1913
|
+
});
|
|
1914
|
+
const pluginsWithRefs = [];
|
|
1915
|
+
for (const [packageName, plugin] of allPlugins) {
|
|
1916
|
+
if (!plugin.manifest.setup?.references)
|
|
1917
|
+
continue;
|
|
1918
|
+
if (pluginFilter && plugin.name !== pluginFilter && packageName !== pluginFilter) {
|
|
1919
|
+
continue;
|
|
1920
|
+
}
|
|
1921
|
+
pluginsWithRefs.push({
|
|
1922
|
+
name: plugin.name,
|
|
1923
|
+
pluginPath: plugin.pluginPath,
|
|
1924
|
+
packageName: plugin.packageName,
|
|
1925
|
+
isLocal: plugin.isLocal,
|
|
1926
|
+
referencesHandler: plugin.manifest.setup.references,
|
|
1927
|
+
dependencies: plugin.dependencies
|
|
1928
|
+
});
|
|
1929
|
+
if (verbose) {
|
|
1930
|
+
getLogger().info(`[AgentKit] Found plugin with references: ${plugin.name}`);
|
|
1931
|
+
}
|
|
1932
|
+
}
|
|
1933
|
+
return sortByDependencies(pluginsWithRefs);
|
|
1934
|
+
}
|
|
1935
|
+
function sortByDependencies(plugins) {
|
|
1936
|
+
return [...plugins].sort((a, b) => {
|
|
1937
|
+
const aDepsOnB = a.dependencies.some((d) => d === b.name || d === b.packageName) ? 1 : 0;
|
|
1938
|
+
const bDepsOnA = b.dependencies.some((d) => d === a.name || d === a.packageName) ? 1 : 0;
|
|
1939
|
+
return aDepsOnB - bDepsOnA;
|
|
1940
|
+
});
|
|
1941
|
+
}
|
|
1942
|
+
async function executePluginSetup(plugin, options) {
|
|
1943
|
+
const { projectRoot, configDir, force, initError, viteServer, verbose } = options;
|
|
1944
|
+
const context = {
|
|
1945
|
+
pluginName: plugin.name,
|
|
1946
|
+
projectRoot,
|
|
1947
|
+
configDir,
|
|
1948
|
+
services: getServiceRegistry(),
|
|
1949
|
+
initError,
|
|
1950
|
+
force
|
|
1951
|
+
};
|
|
1952
|
+
const handler = await loadHandler(plugin, plugin.setupHandler, viteServer);
|
|
1953
|
+
return handler(context);
|
|
1954
|
+
}
|
|
1955
|
+
async function executePluginReferences(plugin, options) {
|
|
1956
|
+
const { projectRoot, force, initError, viteServer } = options;
|
|
1957
|
+
const referencesDir = path.join(projectRoot, "agent-kit", "references", plugin.name);
|
|
1958
|
+
const context = {
|
|
1959
|
+
pluginName: plugin.name,
|
|
1960
|
+
projectRoot,
|
|
1961
|
+
referencesDir,
|
|
1962
|
+
services: getServiceRegistry(),
|
|
1963
|
+
initError,
|
|
1964
|
+
force
|
|
1965
|
+
};
|
|
1966
|
+
const handler = await loadHandler(
|
|
1967
|
+
plugin,
|
|
1968
|
+
plugin.referencesHandler,
|
|
1969
|
+
viteServer
|
|
1970
|
+
);
|
|
1971
|
+
return handler(context);
|
|
1972
|
+
}
|
|
1973
|
+
async function loadHandler(plugin, handlerName, viteServer) {
|
|
1974
|
+
let module;
|
|
1975
|
+
if (plugin.isLocal) {
|
|
1976
|
+
const handlerPath = path.resolve(plugin.pluginPath, handlerName);
|
|
1977
|
+
if (viteServer) {
|
|
1978
|
+
module = await viteServer.ssrLoadModule(handlerPath);
|
|
1979
|
+
} else {
|
|
1980
|
+
module = await import(handlerPath);
|
|
1981
|
+
}
|
|
1982
|
+
if (typeof module[handlerName] === "function")
|
|
1983
|
+
return module[handlerName];
|
|
1984
|
+
if (typeof module.setup === "function")
|
|
1985
|
+
return module.setup;
|
|
1986
|
+
if (typeof module.default === "function")
|
|
1987
|
+
return module.default;
|
|
1988
|
+
throw new Error(
|
|
1989
|
+
`Handler "${handlerName}" not found in "${plugin.pluginPath}". Available exports: ${Object.keys(module).join(", ")}`
|
|
1990
|
+
);
|
|
1991
|
+
} else {
|
|
1992
|
+
if (viteServer) {
|
|
1993
|
+
module = await viteServer.ssrLoadModule(plugin.packageName);
|
|
1994
|
+
} else {
|
|
1995
|
+
module = await import(plugin.packageName);
|
|
1996
|
+
}
|
|
1997
|
+
if (typeof module[handlerName] !== "function") {
|
|
1998
|
+
throw new Error(
|
|
1999
|
+
`Handler "${handlerName}" not found as export in "${plugin.packageName}". Available exports: ${Object.keys(module).join(", ")}`
|
|
2000
|
+
);
|
|
2001
|
+
}
|
|
2002
|
+
return module[handlerName];
|
|
2003
|
+
}
|
|
2004
|
+
}
|
|
1149
2005
|
export {
|
|
1150
2006
|
ActionRegistry,
|
|
1151
2007
|
DevSlowlyChangingPhase,
|
|
@@ -1159,8 +2015,12 @@ export {
|
|
|
1159
2015
|
discoverAndRegisterActions,
|
|
1160
2016
|
discoverPluginActions,
|
|
1161
2017
|
discoverPluginsWithInit,
|
|
2018
|
+
discoverPluginsWithReferences,
|
|
2019
|
+
discoverPluginsWithSetup,
|
|
1162
2020
|
executeAction,
|
|
2021
|
+
executePluginReferences,
|
|
1163
2022
|
executePluginServerInits,
|
|
2023
|
+
executePluginSetup,
|
|
1164
2024
|
generateClientScript,
|
|
1165
2025
|
getActionCacheHeaders,
|
|
1166
2026
|
getClientInitData,
|
|
@@ -1168,21 +2028,29 @@ export {
|
|
|
1168
2028
|
getRegisteredAction,
|
|
1169
2029
|
getRegisteredActionNames,
|
|
1170
2030
|
getService,
|
|
2031
|
+
getServiceRegistry,
|
|
1171
2032
|
hasAction,
|
|
1172
2033
|
hasService,
|
|
2034
|
+
listContracts,
|
|
2035
|
+
loadActionMetadata,
|
|
1173
2036
|
loadPageParts,
|
|
2037
|
+
materializeContracts,
|
|
1174
2038
|
onInit,
|
|
1175
2039
|
onShutdown,
|
|
2040
|
+
parseActionMetadata,
|
|
1176
2041
|
preparePluginClientInits,
|
|
1177
2042
|
registerAction,
|
|
1178
2043
|
registerService,
|
|
1179
2044
|
renderFastChangingData,
|
|
2045
|
+
resolveActionMetadataPath,
|
|
1180
2046
|
resolveServices,
|
|
1181
|
-
runAction,
|
|
1182
2047
|
runInitCallbacks,
|
|
1183
2048
|
runLoadParams,
|
|
1184
2049
|
runShutdownCallbacks,
|
|
1185
2050
|
runSlowlyChangingRender,
|
|
2051
|
+
scanPlugins,
|
|
1186
2052
|
setClientInitData,
|
|
1187
|
-
|
|
2053
|
+
slowRenderInstances,
|
|
2054
|
+
sortPluginsByDependencies,
|
|
2055
|
+
validateForEachInstances
|
|
1188
2056
|
};
|