@jay-framework/stack-server-runtime 0.17.3 → 0.18.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.
Files changed (3) hide show
  1. package/dist/index.d.ts +56 -11
  2. package/dist/index.js +207 -26
  3. package/package.json +13 -13
package/dist/index.d.ts CHANGED
@@ -129,17 +129,8 @@ interface InstanceSlowRenderResult {
129
129
  * Shared between preRenderJayHtml (pre-render path) and handleDirectRequest (direct path).
130
130
  */
131
131
  declare function slowRenderInstances(discovered: DiscoveredHeadlessInstance[], headlessInstanceComponents: HeadlessInstanceComponent[]): Promise<InstanceSlowRenderResult | undefined>;
132
- /**
133
- * Validate that forEach headless instances do not have a slow phase.
134
- *
135
- * Components with slowlyRender cannot be used inside forEach because
136
- * forEach items are only known at request time, after slow rendering completes.
137
- *
138
- * @returns Array of validation error messages (empty if all valid)
139
- */
140
- declare function validateForEachInstances(forEachInstances: ForEachHeadlessInstance[], headlessInstanceComponents: HeadlessInstanceComponent[]): string[];
141
132
 
142
- declare function renderFastChangingData(pageParams: object, pageProps: PageProps, carryForward: object, parts: Array<DevServerPagePart>, instancePhaseData?: InstancePhaseData, forEachInstances?: ForEachHeadlessInstance[], headlessInstanceComponents?: HeadlessInstanceComponent[], mergedSlowViewState?: object, query?: Record<string, string>): Promise<AnyFastRenderResult>;
133
+ declare function renderFastChangingData(pageParams: object, pageProps: PageProps, carryForward: object, parts: Array<DevServerPagePart>, instancePhaseData?: InstancePhaseData, forEachInstances?: ForEachHeadlessInstance[], headlessInstanceComponents?: HeadlessInstanceComponent[], mergedSlowViewState?: object, query?: Record<string, string>, cookies?: Record<string, string>): Promise<AnyFastRenderResult>;
143
134
 
144
135
  /**
145
136
  * Action metadata loaded from .jay-action files.
@@ -992,6 +983,11 @@ interface RouteIndexEntry {
992
983
  path: string;
993
984
  description?: string;
994
985
  }
986
+ /** CLI command entry in plugins-index.yaml (DL#142) */
987
+ interface CommandIndexEntry {
988
+ name: string;
989
+ description?: string;
990
+ }
995
991
  /** Entry for plugins-index.yaml (Design Log #85) */
996
992
  interface PluginsIndexEntry {
997
993
  name: string;
@@ -1005,6 +1001,8 @@ interface PluginsIndexEntry {
1005
1001
  contexts?: ContextIndexEntry[];
1006
1002
  /** Plugin-provided routes (DL#130) */
1007
1003
  routes?: RouteIndexEntry[];
1004
+ /** CLI commands (DL#142) */
1005
+ commands?: CommandIndexEntry[];
1008
1006
  }
1009
1007
  interface PluginsIndex {
1010
1008
  plugins: PluginsIndexEntry[];
@@ -1261,4 +1259,51 @@ declare function mergeHeadTags(sources: HeadTag[][]): HeadTag[];
1261
1259
  */
1262
1260
  declare function serializeHeadTags(tags: HeadTag[]): string;
1263
1261
 
1264
- export { type ActionDiscoveryOptions, type ActionDiscoveryResult, type ActionErrorResponse, type ActionExecutionResult, type ActionIndexEntry, type ActionMetadata, ActionRegistry, type ActionSchema, type ContextIndexEntry, type DevServerPagePart, DevSlowlyChangingPhase, type GenerateClientScriptOptions, type HeadlessInstanceComponent, type InstancePhaseData, type InstanceSlowRenderResult, type LoadedPageParts, type MaterializeContractsOptions, type MaterializeResult, type PluginActionDiscoveryOptions, type PluginClientInitInfo, type PluginContractEntry, type PluginInitDiscoveryOptions, type PluginReferencesContext, type PluginReferencesHandler, type PluginReferencesResult, type PluginScanOptions, type PluginSetupContext, type PluginSetupHandler, type PluginSetupResult, type PluginWithInit, type PluginWithReferences, type PluginWithSetup, type PluginsIndex, type PluginsIndexEntry, type ProjectClientInitInfo, type RegisteredAction, type RegisteredActionBase, type RegisteredActionEntry, type RegisteredStreamAction, type RouteIndexEntry, type ScannedPlugin, type ScriptFragments, type ServiceIndexEntry, SlowRenderCache, type SlowRenderCacheEntry, type SlowlyChangingPhase, type ViteSSRLoader, actionRegistry, buildAutomationWrap, buildScriptFragments, clearActionRegistry, clearClientInitData, clearLifecycleCallbacks, clearServerElementCache, clearServiceRegistry, discoverAllPluginActions, discoverAndRegisterActions, discoverPluginActions, discoverPluginsWithInit, discoverPluginsWithReferences, discoverPluginsWithSetup, executeAction, executePluginReferences, executePluginServerInits, executePluginSetup, generateClientScript, generateFrozenPageHtml, generatePromiseReconstruction, generateSSRPageHtml, getActionCacheHeaders, getClientInitData, getClientInitDataForKey, getRegisteredAction, getRegisteredActionNames, getService, getServiceRegistry, hasAction, hasService, invalidateServerElementCache, listContracts, loadActionMetadata, loadPageParts, materializeContracts, mergeHeadTags, onInit, onShutdown, parseActionMetadata, preparePluginClientInits, registerAction, registerService, renderFastChangingData, resolveActionMetadataPath, resolveServices, resolveViewStatePromises, runInitCallbacks, runLoadParams, runShutdownCallbacks, scanPlugins, serializeHeadTags, setClientInitData, slowRenderInstances, sortPluginsByDependencies, tagIdentityKey, validateForEachInstances };
1262
+ /**
1263
+ * Parse a Cookie header string into a key-value record.
1264
+ * Handles standard cookie format: "name1=value1; name2=value2".
1265
+ */
1266
+ declare function parseCookies(cookieHeader: string | null | undefined): Record<string, string>;
1267
+
1268
+ /**
1269
+ * Plugin CLI Commands (Design Log #142)
1270
+ *
1271
+ * Plugins expose CLI commands via `commands` in plugin.yaml.
1272
+ * Each command has a `makeCliCommand` handler and an optional `.jay-command` metadata file.
1273
+ * Run via `jay-stack run <plugin>/<command>`.
1274
+ */
1275
+
1276
+ interface CommandMetadata {
1277
+ name: string;
1278
+ description?: string;
1279
+ inputSchema?: Record<string, string>;
1280
+ }
1281
+ interface DiscoveredCommand {
1282
+ pluginName: string;
1283
+ pluginPath: string;
1284
+ packageName: string;
1285
+ isLocal: boolean;
1286
+ commandName: string;
1287
+ handlerExport: string;
1288
+ pluginModule?: string;
1289
+ metadata?: CommandMetadata;
1290
+ metadataPath?: string;
1291
+ }
1292
+ interface CommandFlag {
1293
+ flag: string;
1294
+ description: string;
1295
+ required: boolean;
1296
+ type: 'string' | 'boolean' | 'number';
1297
+ }
1298
+ declare function discoverPluginCommands(options: {
1299
+ projectRoot: string;
1300
+ verbose?: boolean;
1301
+ pluginFilter?: string;
1302
+ }): Promise<DiscoveredCommand[]>;
1303
+ declare function commandSchemaToFlags(inputSchema: Record<string, string>): CommandFlag[];
1304
+ declare function parseInputFromFlags(rawOptions: Record<string, any>, schema: Record<string, string>): Record<string, any>;
1305
+ declare function executePluginCommand(command: DiscoveredCommand, input: Record<string, any>, viteServer?: ViteSSRLoader): Promise<{
1306
+ success: boolean;
1307
+ }>;
1308
+
1309
+ export { type ActionDiscoveryOptions, type ActionDiscoveryResult, type ActionErrorResponse, type ActionExecutionResult, type ActionIndexEntry, type ActionMetadata, ActionRegistry, type ActionSchema, type CommandFlag, type CommandIndexEntry, type CommandMetadata, type ContextIndexEntry, type DevServerPagePart, DevSlowlyChangingPhase, type DiscoveredCommand, type GenerateClientScriptOptions, type HeadlessInstanceComponent, type InstancePhaseData, type InstanceSlowRenderResult, type LoadedPageParts, type MaterializeContractsOptions, type MaterializeResult, type PluginActionDiscoveryOptions, type PluginClientInitInfo, type PluginContractEntry, type PluginInitDiscoveryOptions, type PluginReferencesContext, type PluginReferencesHandler, type PluginReferencesResult, type PluginScanOptions, type PluginSetupContext, type PluginSetupHandler, type PluginSetupResult, type PluginWithInit, type PluginWithReferences, type PluginWithSetup, type PluginsIndex, type PluginsIndexEntry, type ProjectClientInitInfo, type RegisteredAction, type RegisteredActionBase, type RegisteredActionEntry, type RegisteredStreamAction, type RouteIndexEntry, type ScannedPlugin, type ScriptFragments, type ServiceIndexEntry, SlowRenderCache, type SlowRenderCacheEntry, type SlowlyChangingPhase, type ViteSSRLoader, actionRegistry, buildAutomationWrap, buildScriptFragments, clearActionRegistry, clearClientInitData, clearLifecycleCallbacks, clearServerElementCache, clearServiceRegistry, commandSchemaToFlags, discoverAllPluginActions, discoverAndRegisterActions, discoverPluginActions, discoverPluginCommands, discoverPluginsWithInit, discoverPluginsWithReferences, discoverPluginsWithSetup, executeAction, executePluginCommand, executePluginReferences, executePluginServerInits, executePluginSetup, generateClientScript, generateFrozenPageHtml, generatePromiseReconstruction, generateSSRPageHtml, getActionCacheHeaders, getClientInitData, getClientInitDataForKey, getRegisteredAction, getRegisteredActionNames, getService, getServiceRegistry, hasAction, hasService, invalidateServerElementCache, listContracts, loadActionMetadata, loadPageParts, materializeContracts, mergeHeadTags, onInit, onShutdown, parseActionMetadata, parseCookies, parseInputFromFlags, preparePluginClientInits, registerAction, registerService, renderFastChangingData, resolveActionMetadataPath, resolveServices, resolveViewStatePromises, runInitCallbacks, runLoadParams, runShutdownCallbacks, scanPlugins, serializeHeadTags, setClientInitData, slowRenderInstances, sortPluginsByDependencies, tagIdentityKey };
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@ var __publicField = (obj, key, value) => {
4
4
  __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
5
5
  return value;
6
6
  };
7
- import { phaseOutput, isJayAction, isJayStreamAction } from "@jay-framework/fullstack-component";
7
+ import { phaseOutput, isJayAction, isJayStreamAction, isJayCliCommand } from "@jay-framework/fullstack-component";
8
8
  import "prettier";
9
9
  import "js-beautify";
10
10
  import fs$1 from "fs";
@@ -395,10 +395,11 @@ function resolveBinding(binding, item) {
395
395
  }
396
396
  return binding;
397
397
  }
398
- async function renderFastChangingData(pageParams, pageProps, carryForward, parts, instancePhaseData, forEachInstances, headlessInstanceComponents, mergedSlowViewState, query = {}) {
398
+ async function renderFastChangingData(pageParams, pageProps, carryForward, parts, instancePhaseData, forEachInstances, headlessInstanceComponents, mergedSlowViewState, query = {}, cookies = {}) {
399
399
  let fastViewState = {};
400
400
  let fastCarryForward = {};
401
401
  const fastHeadTagSources = [];
402
+ const responseHeaderSources = [];
402
403
  for (const part of parts) {
403
404
  const { compDefinition, key, contractInfo } = part;
404
405
  if (compDefinition.fastRender) {
@@ -408,6 +409,7 @@ async function renderFastChangingData(pageParams, pageProps, carryForward, parts
408
409
  ...pageProps,
409
410
  ...pageParams,
410
411
  query,
412
+ cookies,
411
413
  ...contractInfo && {
412
414
  contractName: contractInfo.contractName,
413
415
  metadata: contractInfo.metadata
@@ -425,6 +427,9 @@ async function renderFastChangingData(pageParams, pageProps, carryForward, parts
425
427
  if (fastRenderedPart.headTags) {
426
428
  fastHeadTagSources.push(fastRenderedPart.headTags);
427
429
  }
430
+ if (fastRenderedPart.responseHeaders) {
431
+ responseHeaderSources.push(fastRenderedPart.responseHeaders);
432
+ }
428
433
  } else
429
434
  return fastRenderedPart;
430
435
  }
@@ -445,7 +450,7 @@ async function renderFastChangingData(pageParams, pageProps, carryForward, parts
445
450
  if (comp.compDefinition.fastRender) {
446
451
  const services = resolveServices(comp.compDefinition.services);
447
452
  const cf = instancePhaseData.carryForwards[coordKey];
448
- const instanceProps = { ...instance.props, query };
453
+ const instanceProps = { ...instance.props, query, cookies };
449
454
  const fastResult = comp.compDefinition.slowlyRender ? await comp.compDefinition.fastRender(instanceProps, cf, ...services) : await comp.compDefinition.fastRender(instanceProps, ...services);
450
455
  if (fastResult.kind === "PhaseOutput") {
451
456
  instanceViewStates[coordKey] = instanceSlowVS ? { ...instanceSlowVS, ...fastResult.rendered } : fastResult.rendered;
@@ -455,6 +460,9 @@ async function renderFastChangingData(pageParams, pageProps, carryForward, parts
455
460
  if (fastResult.headTags) {
456
461
  fastHeadTagSources.push(fastResult.headTags);
457
462
  }
463
+ if (fastResult.responseHeaders) {
464
+ responseHeaderSources.push(fastResult.responseHeaders);
465
+ }
458
466
  }
459
467
  } else {
460
468
  instanceViewStates[coordKey] = instanceSlowVS ?? {};
@@ -496,7 +504,7 @@ async function renderFastChangingData(pageParams, pageProps, carryForward, parts
496
504
  cf = slowResult.carryForward;
497
505
  }
498
506
  }
499
- const forEachProps = { ...props, query };
507
+ const forEachProps = { ...props, query, cookies };
500
508
  const fastResult = comp.compDefinition.slowlyRender ? await comp.compDefinition.fastRender(forEachProps, cf, ...services) : await comp.compDefinition.fastRender(forEachProps, ...services);
501
509
  if (fastResult.kind === "PhaseOutput") {
502
510
  const coord = computeForEachInstanceKey(
@@ -522,6 +530,9 @@ async function renderFastChangingData(pageParams, pageProps, carryForward, parts
522
530
  if (fastHeadTagSources.length > 0) {
523
531
  result.headTags = fastHeadTagSources.flat();
524
532
  }
533
+ if (responseHeaderSources.length > 0) {
534
+ result.responseHeaders = Object.assign({}, ...responseHeaderSources);
535
+ }
525
536
  return Promise.resolve(result);
526
537
  }
527
538
  function generatePromiseReconstruction(outcomes) {
@@ -1282,22 +1293,6 @@ async function slowRenderInstances(discovered, headlessInstanceComponents) {
1282
1293
  instancePhaseData: { discovered: discoveredForFast, carryForwards, slowViewStates }
1283
1294
  };
1284
1295
  }
1285
- function validateForEachInstances(forEachInstances, headlessInstanceComponents) {
1286
- const componentByContractName = /* @__PURE__ */ new Map();
1287
- for (const comp of headlessInstanceComponents) {
1288
- componentByContractName.set(comp.contractName, comp);
1289
- }
1290
- const validations = [];
1291
- for (const instance of forEachInstances) {
1292
- const comp = componentByContractName.get(instance.contractName);
1293
- if (comp?.compDefinition.slowlyRender) {
1294
- validations.push(
1295
- `<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.`
1296
- );
1297
- }
1298
- }
1299
- return validations;
1300
- }
1301
1296
  class ActionRegistry {
1302
1297
  constructor() {
1303
1298
  __publicField(this, "actions", /* @__PURE__ */ new Map());
@@ -1314,7 +1309,9 @@ class ActionRegistry {
1314
1309
  cacheOptions: action.cacheOptions,
1315
1310
  services: action.services,
1316
1311
  handler: action.handler,
1317
- ...action.acceptsFiles && { acceptsFiles: true }
1312
+ ...action.acceptsFiles && {
1313
+ acceptsFiles: true
1314
+ }
1318
1315
  };
1319
1316
  this.actions.set(action.actionName, entry);
1320
1317
  }
@@ -1472,7 +1469,9 @@ class ActionRegistry {
1472
1469
  isStreaming: true,
1473
1470
  services: action.services,
1474
1471
  handler: action.handler,
1475
- ...action.acceptsFiles && { acceptsFiles: true }
1472
+ ...action.acceptsFiles && {
1473
+ acceptsFiles: true
1474
+ }
1476
1475
  };
1477
1476
  this.actions.set(action.actionName, entry);
1478
1477
  }
@@ -2572,6 +2571,24 @@ async function materializeContracts(options, services = /* @__PURE__ */ new Map(
2572
2571
  ...r.description && { description: r.description }
2573
2572
  }));
2574
2573
  }
2574
+ if (manifest.commands?.length) {
2575
+ entry.commands = manifest.commands.map((c) => {
2576
+ let description;
2577
+ if (c.command) {
2578
+ try {
2579
+ const cmdPath = path.resolve(plugin.pluginPath, c.command);
2580
+ const cmdContent = fs.readFileSync(cmdPath, "utf-8");
2581
+ const parsed = YAML.parse(cmdContent);
2582
+ description = parsed?.description;
2583
+ } catch {
2584
+ }
2585
+ }
2586
+ return {
2587
+ name: c.name,
2588
+ ...description && { description }
2589
+ };
2590
+ });
2591
+ }
2575
2592
  pluginsIndexMap.set(plugin.name, entry);
2576
2593
  }
2577
2594
  if (!dynamicOnly && manifest.contracts) {
@@ -2707,7 +2724,8 @@ async function materializeContracts(options, services = /* @__PURE__ */ new Map(
2707
2724
  ...data.actions && data.actions.length > 0 && { actions: data.actions },
2708
2725
  ...data.services?.length && { services: data.services },
2709
2726
  ...data.contexts?.length && { contexts: data.contexts },
2710
- ...data.routes?.length && { routes: data.routes }
2727
+ ...data.routes?.length && { routes: data.routes },
2728
+ ...data.commands?.length && { commands: data.commands }
2711
2729
  }))
2712
2730
  };
2713
2731
  fs.mkdirSync(outputDir, { recursive: true });
@@ -2770,6 +2788,24 @@ async function listContracts(options) {
2770
2788
  ...r.description && { description: r.description }
2771
2789
  }));
2772
2790
  }
2791
+ if (manifest.commands?.length) {
2792
+ entry.commands = manifest.commands.map((c) => {
2793
+ let description;
2794
+ if (c.command) {
2795
+ try {
2796
+ const cmdPath = path.resolve(plugin.pluginPath, c.command);
2797
+ const cmdContent = fs.readFileSync(cmdPath, "utf-8");
2798
+ const parsed = YAML.parse(cmdContent);
2799
+ description = parsed?.description;
2800
+ } catch {
2801
+ }
2802
+ }
2803
+ return {
2804
+ name: c.name,
2805
+ ...description && { description }
2806
+ };
2807
+ });
2808
+ }
2773
2809
  pluginsMap.set(plugin.name, entry);
2774
2810
  }
2775
2811
  if (!dynamicOnly && manifest.contracts) {
@@ -2817,7 +2853,8 @@ async function listContracts(options) {
2817
2853
  contracts: data.contracts,
2818
2854
  ...data.services?.length && { services: data.services },
2819
2855
  ...data.contexts?.length && { contexts: data.contexts },
2820
- ...data.routes?.length && { routes: data.routes }
2856
+ ...data.routes?.length && { routes: data.routes },
2857
+ ...data.commands?.length && { commands: data.commands }
2821
2858
  }))
2822
2859
  };
2823
2860
  }
@@ -2948,6 +2985,146 @@ async function loadHandler(plugin, handlerName, viteServer) {
2948
2985
  return module[handlerName];
2949
2986
  }
2950
2987
  }
2988
+ function parseCookies(cookieHeader) {
2989
+ const cookies = {};
2990
+ if (!cookieHeader)
2991
+ return cookies;
2992
+ for (const pair of cookieHeader.split(";")) {
2993
+ const [name, ...rest] = pair.trim().split("=");
2994
+ if (name)
2995
+ cookies[name] = decodeURIComponent(rest.join("="));
2996
+ }
2997
+ return cookies;
2998
+ }
2999
+ async function discoverPluginCommands(options) {
3000
+ const { projectRoot, verbose, pluginFilter } = options;
3001
+ const allPlugins = await scanPlugins({
3002
+ projectRoot,
3003
+ verbose,
3004
+ discoverTransitive: true
3005
+ });
3006
+ const commands = [];
3007
+ for (const [packageName, plugin] of allPlugins) {
3008
+ if (!plugin.manifest.commands || plugin.manifest.commands.length === 0)
3009
+ continue;
3010
+ if (pluginFilter && plugin.name !== pluginFilter && packageName !== pluginFilter) {
3011
+ continue;
3012
+ }
3013
+ for (const cmd of plugin.manifest.commands) {
3014
+ let metadata;
3015
+ let metadataPath;
3016
+ if (cmd.command) {
3017
+ metadataPath = path.resolve(plugin.pluginPath, cmd.command);
3018
+ metadata = loadCommandMetadata(metadataPath);
3019
+ }
3020
+ commands.push({
3021
+ pluginName: plugin.name,
3022
+ pluginPath: plugin.pluginPath,
3023
+ packageName: plugin.packageName,
3024
+ isLocal: plugin.isLocal,
3025
+ commandName: cmd.name,
3026
+ handlerExport: cmd.name,
3027
+ pluginModule: plugin.manifest.module,
3028
+ metadata,
3029
+ metadataPath
3030
+ });
3031
+ if (verbose) {
3032
+ getLogger().info(`[Commands] Found ${plugin.name}/${cmd.name}`);
3033
+ }
3034
+ }
3035
+ }
3036
+ return commands;
3037
+ }
3038
+ function loadCommandMetadata(filePath) {
3039
+ try {
3040
+ const content = fs.readFileSync(filePath, "utf-8");
3041
+ return YAML.parse(content);
3042
+ } catch {
3043
+ return void 0;
3044
+ }
3045
+ }
3046
+ function commandSchemaToFlags(inputSchema) {
3047
+ const flags = [];
3048
+ for (const [field, type] of Object.entries(inputSchema)) {
3049
+ const isOptional = field.endsWith("?");
3050
+ const cleanName = isOptional ? field.slice(0, -1) : field;
3051
+ const kebabName = camelToKebab(cleanName);
3052
+ const cleanType = type.toLowerCase().trim();
3053
+ const isBoolean = cleanType === "boolean";
3054
+ flags.push({
3055
+ flag: isBoolean ? `--${kebabName}` : `--${kebabName} <value>`,
3056
+ description: "",
3057
+ required: !isOptional,
3058
+ type: cleanType === "number" ? "number" : isBoolean ? "boolean" : "string"
3059
+ });
3060
+ }
3061
+ return flags;
3062
+ }
3063
+ function camelToKebab(str) {
3064
+ return str.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
3065
+ }
3066
+ function parseInputFromFlags(rawOptions, schema) {
3067
+ const input = {};
3068
+ for (const [field, type] of Object.entries(schema)) {
3069
+ const isOptional = field.endsWith("?");
3070
+ const cleanName = isOptional ? field.slice(0, -1) : field;
3071
+ const kebabName = camelToKebab(cleanName);
3072
+ const value = rawOptions[kebabName];
3073
+ if (value === void 0) {
3074
+ if (!isOptional) {
3075
+ throw new Error(`Missing required flag: --${kebabName}`);
3076
+ }
3077
+ continue;
3078
+ }
3079
+ const cleanType = type.toLowerCase().trim();
3080
+ if (cleanType === "number") {
3081
+ const parsed = Number(value);
3082
+ if (isNaN(parsed))
3083
+ throw new Error(`Flag --${kebabName} must be a number`);
3084
+ input[cleanName] = parsed;
3085
+ } else if (cleanType === "boolean") {
3086
+ input[cleanName] = value === true || value === "true";
3087
+ } else {
3088
+ input[cleanName] = String(value);
3089
+ }
3090
+ }
3091
+ return input;
3092
+ }
3093
+ async function executePluginCommand(command, input, viteServer) {
3094
+ const cliCommand = await loadCommandHandler(command, viteServer);
3095
+ const services = resolveServices(cliCommand.services);
3096
+ return cliCommand.handler(input, ...services);
3097
+ }
3098
+ async function loadCommandHandler(command, viteServer) {
3099
+ let module;
3100
+ if (command.isLocal) {
3101
+ const moduleFile = command.pluginModule || "index";
3102
+ const modulePath = path.resolve(command.pluginPath, moduleFile);
3103
+ if (viteServer) {
3104
+ module = await viteServer.ssrLoadModule(modulePath);
3105
+ } else {
3106
+ module = await import(modulePath);
3107
+ }
3108
+ } else {
3109
+ if (viteServer) {
3110
+ module = await viteServer.ssrLoadModule(command.packageName);
3111
+ } else {
3112
+ module = await import(command.packageName);
3113
+ }
3114
+ }
3115
+ for (const [, exported] of Object.entries(module)) {
3116
+ if (isJayCliCommand(exported) && exported.commandName === command.commandName) {
3117
+ return exported;
3118
+ }
3119
+ }
3120
+ const byName = module[command.handlerExport];
3121
+ if (byName && isJayCliCommand(byName)) {
3122
+ return byName;
3123
+ }
3124
+ throw new Error(
3125
+ `CLI command "${command.commandName}" not found as export in "${command.isLocal ? command.pluginPath : command.packageName}". Available exports: ${Object.keys(module).join(", ")}`
3126
+ );
3127
+ }
2951
3128
  export {
2952
3129
  ActionRegistry,
2953
3130
  DevSlowlyChangingPhase,
@@ -2960,13 +3137,16 @@ export {
2960
3137
  clearLifecycleCallbacks,
2961
3138
  clearServerElementCache,
2962
3139
  clearServiceRegistry,
3140
+ commandSchemaToFlags,
2963
3141
  discoverAllPluginActions,
2964
3142
  discoverAndRegisterActions,
2965
3143
  discoverPluginActions,
3144
+ discoverPluginCommands,
2966
3145
  discoverPluginsWithInit,
2967
3146
  discoverPluginsWithReferences,
2968
3147
  discoverPluginsWithSetup,
2969
3148
  executeAction,
3149
+ executePluginCommand,
2970
3150
  executePluginReferences,
2971
3151
  executePluginServerInits,
2972
3152
  executePluginSetup,
@@ -2992,6 +3172,8 @@ export {
2992
3172
  onInit,
2993
3173
  onShutdown,
2994
3174
  parseActionMetadata,
3175
+ parseCookies,
3176
+ parseInputFromFlags,
2995
3177
  preparePluginClientInits,
2996
3178
  registerAction,
2997
3179
  registerService,
@@ -3007,6 +3189,5 @@ export {
3007
3189
  setClientInitData,
3008
3190
  slowRenderInstances,
3009
3191
  sortPluginsByDependencies,
3010
- tagIdentityKey,
3011
- validateForEachInstances
3192
+ tagIdentityKey
3012
3193
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jay-framework/stack-server-runtime",
3
- "version": "0.17.3",
3
+ "version": "0.18.0",
4
4
  "license": "Apache-2.0",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.mts",
@@ -26,21 +26,21 @@
26
26
  "test:watch": "vitest"
27
27
  },
28
28
  "dependencies": {
29
- "@jay-framework/compiler-jay-html": "^0.17.3",
30
- "@jay-framework/compiler-shared": "^0.17.3",
31
- "@jay-framework/component": "^0.17.3",
32
- "@jay-framework/fullstack-component": "^0.17.3",
33
- "@jay-framework/logger": "^0.17.3",
34
- "@jay-framework/runtime": "^0.17.3",
35
- "@jay-framework/ssr-runtime": "^0.17.3",
36
- "@jay-framework/stack-route-scanner": "^0.17.3",
37
- "@jay-framework/view-state-merge": "^0.17.3",
29
+ "@jay-framework/compiler-jay-html": "^0.18.0",
30
+ "@jay-framework/compiler-shared": "^0.18.0",
31
+ "@jay-framework/component": "^0.18.0",
32
+ "@jay-framework/fullstack-component": "^0.18.0",
33
+ "@jay-framework/logger": "^0.18.0",
34
+ "@jay-framework/runtime": "^0.18.0",
35
+ "@jay-framework/ssr-runtime": "^0.18.0",
36
+ "@jay-framework/stack-route-scanner": "^0.18.0",
37
+ "@jay-framework/view-state-merge": "^0.18.0",
38
38
  "yaml": "^2.3.4"
39
39
  },
40
40
  "devDependencies": {
41
- "@jay-framework/dev-environment": "^0.17.3",
42
- "@jay-framework/jay-cli": "^0.17.3",
43
- "@jay-framework/stack-client-runtime": "^0.17.3",
41
+ "@jay-framework/dev-environment": "^0.18.0",
42
+ "@jay-framework/jay-cli": "^0.18.0",
43
+ "@jay-framework/stack-client-runtime": "^0.18.0",
44
44
  "@types/express": "^5.0.2",
45
45
  "@types/node": "^22.15.21",
46
46
  "nodemon": "^3.0.3",