@jay-framework/compiler-shared 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.
Files changed (3) hide show
  1. package/dist/index.d.ts +109 -21
  2. package/dist/index.js +297 -78
  3. package/package.json +6 -6
package/dist/index.d.ts CHANGED
@@ -69,6 +69,8 @@ declare const Import: {
69
69
  mimicJayElement: ImportName;
70
70
  jayContract: ImportName;
71
71
  injectHeadLinks: ImportName;
72
+ makeJayComponent: ImportName;
73
+ makeHeadlessInstanceComponent: ImportName;
72
74
  };
73
75
  declare class Imports {
74
76
  private readonly imports;
@@ -85,14 +87,17 @@ declare class Imports {
85
87
  declare const JAY_EXTENSION = ".jay-html";
86
88
  declare const CSS_EXTENSION = ".css";
87
89
  declare const JAY_CONTRACT_EXTENSION = ".jay-contract";
90
+ declare const JAY_ACTION_EXTENSION = ".jay-action";
88
91
  declare const JAY_TS_EXTENSION = ".jay-html.ts";
89
92
  declare const JAY_DTS_EXTENSION = ".jay-html.d.ts";
90
93
  declare const JAY_CONTRACT_DTS_EXTENSION = ".jay-contract.d.ts";
94
+ declare const JAY_ACTION_DTS_EXTENSION = ".jay-action.d.ts";
91
95
  declare const JAY_COMPONENT = "@jay-framework/component";
92
96
  declare const JAY_SECURE = "@jay-framework/secure";
93
97
  declare const JAY_RUNTIME = "@jay-framework/runtime";
94
98
  declare const JAY_4_REACT = "@jay-framework/4-react";
95
99
  declare const JAY_FULLSTACK_COMPONENTS = "@jay-framework/fullstack-component";
100
+ declare const JAY_STACK_CLIENT_RUNTIME = "@jay-framework/stack-client-runtime";
96
101
  declare const REACT = "react";
97
102
  declare const MAKE_JAY_COMPONENT = "makeJayComponent";
98
103
  declare const MAKE_JAY_TSX_COMPONENT = "makeJayTsxComponent";
@@ -111,7 +116,8 @@ declare enum JayTypeKind {
111
116
  array = 9,
112
117
  union = 10,
113
118
  promise = 11,
114
- recursive = 12
119
+ recursive = 12,
120
+ optional = 13
115
121
  }
116
122
  interface JayType {
117
123
  name: string;
@@ -209,7 +215,14 @@ declare class JayRecursiveType implements JayType {
209
215
  readonly kind = JayTypeKind.recursive;
210
216
  get name(): string;
211
217
  }
218
+ declare class JayOptionalType implements JayType {
219
+ readonly innerType: JayType;
220
+ constructor(innerType: JayType);
221
+ readonly kind = JayTypeKind.optional;
222
+ get name(): string;
223
+ }
212
224
  declare const JayErrorType: JayObjectType;
225
+ declare function isOptionalType(aType: JayType): aType is JayOptionalType;
213
226
  declare function isAtomicType(aType: JayType): aType is JayAtomicType;
214
227
  declare function isTypeAliasType(aType: JayType): aType is JayTypeAlias;
215
228
  declare function isEnumType(aType: JayType): aType is JayEnumType;
@@ -227,6 +240,29 @@ declare function isCurrencyType(aType: JayType): aType is JayAtomicType;
227
240
  declare function isDateWithTimezoneType(aType: JayType): aType is JayAtomicType;
228
241
  declare function equalJayTypes(a: JayType, b: JayType): any;
229
242
 
243
+ /**
244
+ * Converts JayType trees to JSON Schema.
245
+ *
246
+ * Used by the runtime to convert parsed .jay-action files into JSON Schema
247
+ * for AI agent tool definitions (e.g., Gemini function declarations).
248
+ */
249
+
250
+ /**
251
+ * JSON Schema property definition.
252
+ */
253
+ interface JsonSchemaProperty {
254
+ type: string;
255
+ description?: string;
256
+ enum?: string[];
257
+ items?: JsonSchemaProperty;
258
+ properties?: Record<string, JsonSchemaProperty>;
259
+ required?: string[];
260
+ }
261
+ /**
262
+ * Converts a JayType to a JSON Schema property.
263
+ */
264
+ declare function jayTypeToJsonSchema(type: JayType): JsonSchemaProperty | null;
265
+
230
266
  interface JayImportName {
231
267
  name: string;
232
268
  as?: string;
@@ -386,6 +422,20 @@ declare class WithValidations<Value> {
386
422
  flatMap<R>(func: (v: Value) => WithValidations<R>): WithValidations<R>;
387
423
  flatMapAsync<R>(func: (v: Value) => Promise<WithValidations<R>>): Promise<WithValidations<R>>;
388
424
  merge(other: WithValidations<Value>, merge: (t1: Value, t2: Value) => Value): WithValidations<Value>;
425
+ /**
426
+ * Append validations from another WithValidations without changing the value.
427
+ * Useful for collecting validations from side-effect operations.
428
+ */
429
+ withValidationsFrom<T>(other: WithValidations<T>): WithValidations<Value>;
430
+ /**
431
+ * Merge an array of WithValidations into a single WithValidations containing an array of values.
432
+ * All validations are collected.
433
+ */
434
+ static all<T>(items: WithValidations<T>[]): WithValidations<T[]>;
435
+ /**
436
+ * Create a WithValidations with no validations (pure value).
437
+ */
438
+ static pure<T>(value: T): WithValidations<T>;
389
439
  }
390
440
  declare function checkValidationErrors<T>(withValidations: WithValidations<T>): T;
391
441
 
@@ -460,6 +510,7 @@ declare function prettify(code: string, options?: prettier.Options): Promise<str
460
510
  declare function prettifyHtml(html: string): string;
461
511
  declare function removeComments(code: string): string;
462
512
 
513
+ declare const LOCAL_PLUGIN_PATH = "src/plugins";
463
514
  /**
464
515
  * Plugin initialization configuration.
465
516
  *
@@ -475,6 +526,17 @@ declare function removeComments(code: string): string;
475
526
  * ```
476
527
  */
477
528
  type PluginInitConfig = string;
529
+ /**
530
+ * Dynamic contract generator configuration.
531
+ */
532
+ interface DynamicContractConfig {
533
+ /** Path to the generator module (relative to plugin root) */
534
+ generator: string;
535
+ /** Path to the headless component (relative to plugin root) */
536
+ component: string;
537
+ /** Prefix for generated contract names (e.g., "cms" -> "cms/blog-posts") */
538
+ prefix: string;
539
+ }
478
540
  /**
479
541
  * Plugin manifest structure from plugin.yaml
480
542
  */
@@ -482,22 +544,49 @@ interface PluginManifest {
482
544
  name: string;
483
545
  version?: string;
484
546
  module?: string;
547
+ /** When true, this plugin is loaded on every page regardless of usage in jay-html.
548
+ * Useful for global tools like WebMCP, analytics, or dev tools. */
549
+ global?: boolean;
485
550
  contracts?: Array<{
486
551
  name: string;
487
552
  contract: string;
488
553
  component: string;
489
554
  description?: string;
490
555
  }>;
491
- dynamic_contracts?: {
492
- generator: string;
493
- component: string;
494
- prefix: string;
495
- };
496
- /** Named exports from plugin backend bundle that are JayAction instances */
497
- actions?: string[];
556
+ dynamic_contracts?: DynamicContractConfig | DynamicContractConfig[];
557
+ /** Named exports from plugin backend bundle that are JayAction instances.
558
+ * Can be a string (export name, no metadata) or an object with a .jay-action file reference.
559
+ * Actions with .jay-action metadata are exposed to AI agents; those without are not. */
560
+ actions?: ActionManifestEntry[];
498
561
  /** Plugin initialization configuration */
499
562
  init?: PluginInitConfig;
563
+ /** Plugin setup configuration (Design Log #87) */
564
+ setup?: {
565
+ /** Export name (NPM) or relative path (local) to setup handler function */
566
+ handler: string;
567
+ /** Export name for reference data generation (called by jay-stack agent-kit) */
568
+ references?: string;
569
+ /** Human-readable description of what setup does */
570
+ description?: string;
571
+ };
500
572
  }
573
+ /**
574
+ * Action entry in plugin.yaml.
575
+ * - `string`: export name only, no metadata (not exposed to AI agents)
576
+ * - `{ name, action }`: export name + path to .jay-action metadata file
577
+ */
578
+ type ActionManifestEntry = string | {
579
+ name: string;
580
+ action: string;
581
+ };
582
+ /**
583
+ * Normalizes an action manifest entry to { name, action? }.
584
+ * Strings become { name: string, action: undefined }.
585
+ */
586
+ declare function normalizeActionEntry(entry: ActionManifestEntry): {
587
+ name: string;
588
+ action?: string;
589
+ };
501
590
  /**
502
591
  * Result of resolving a plugin component
503
592
  */
@@ -521,31 +610,30 @@ interface PluginComponentResolution {
521
610
  */
522
611
  declare function loadPluginManifest(pluginDir: string): PluginManifest | null;
523
612
  /**
524
- * Resolves a plugin component from a local plugin directory (src/plugins/)
613
+ * Finds a dynamic contract config that matches the given contract name.
614
+ * Dynamic contracts use a prefix format: "prefix/name" (e.g., "list/recipes-list")
525
615
  *
526
- * @param projectRoot - Project root directory
527
- * @param pluginName - Name of the plugin
528
- * @param contractName - Name of the contract to resolve
529
- * @returns Resolution result with validation messages
616
+ * @param manifest - The plugin manifest
617
+ * @param contractName - The contract name to match (e.g., "list/recipes-list")
618
+ * @returns The matching DynamicContractConfig or null if not found
530
619
  */
531
- declare function resolveLocalPlugin(projectRoot: string, pluginName: string, contractName: string): WithValidations<PluginComponentResolution> | null;
620
+ declare function findDynamicContract(manifest: PluginManifest, contractName: string): DynamicContractConfig | null;
532
621
  /**
533
- * Resolves a plugin component from an NPM package (node_modules/)
622
+ * Resolves a plugin component, trying local plugins first, then NPM packages
534
623
  *
535
624
  * @param projectRoot - Project root directory
536
- * @param pluginName - Name of the NPM package
625
+ * @param pluginName - Name of the plugin
537
626
  * @param contractName - Name of the contract to resolve
538
627
  * @returns Resolution result with validation messages
539
628
  */
540
- declare function resolveNpmPlugin(projectRoot: string, pluginName: string, contractName: string): WithValidations<PluginComponentResolution> | null;
629
+ declare function resolvePluginComponent(projectRoot: string, pluginName: string, contractName: string): WithValidations<PluginComponentResolution>;
541
630
  /**
542
- * Resolves a plugin component, trying local plugins first, then NPM packages
631
+ * Resolves a plugin manifest from a local plugin or NPM package
543
632
  *
544
633
  * @param projectRoot - Project root directory
545
634
  * @param pluginName - Name of the plugin
546
- * @param contractName - Name of the contract to resolve
547
635
  * @returns Resolution result with validation messages
548
636
  */
549
- declare function resolvePluginComponent(projectRoot: string, pluginName: string, contractName: string): WithValidations<PluginComponentResolution>;
637
+ declare function resolvePluginManifest(projectRoot: string, pluginName: string): WithValidations<PluginManifest>;
550
638
 
551
- export { CSS_EXTENSION, type CompilerSourceFile, GenerateTarget, type GenericTypescriptSourceFile, Import, type ImportName, type ImportedRefsTree, Imports, ImportsFor, JAY_4_REACT, JAY_COMPONENT, JAY_CONTRACT_DTS_EXTENSION, JAY_CONTRACT_EXTENSION, JAY_DTS_EXTENSION, JAY_EXTENSION, JAY_FULLSTACK_COMPONENTS, JAY_QUERY_CLIENT, JAY_QUERY_MAIN_SANDBOX, JAY_QUERY_MAIN_SANDBOX_TS, JAY_QUERY_PREFIX, JAY_QUERY_SERVER, JAY_QUERY_WORKER_SANDBOX, JAY_QUERY_WORKER_SANDBOX_TS, JAY_QUERY_WORKER_TRUSTED, JAY_QUERY_WORKER_TRUSTED_TS, JAY_RUNTIME, JAY_SECURE, JAY_TS_EXTENSION, JayArrayType, JayAtomicType, JayBoolean, JayBuildEnvironment, JayComponentApiMember, JayComponentType, JayDate, JayElementConstructorType, JayElementType, JayEnumType, type JayEnvironment, JayErrorType, JayHTMLType, type JayImportLink, type JayImportName, JayImportedType, JayNumber, JayObjectType, JayPromiseType, JayRecursiveType, JayString, type JayType, JayTypeAlias, JayTypeKind, JayUnionType, JayUnknown, type JayValidations, MAKE_JAY_4_REACT_COMPONENT, MAKE_JAY_COMPONENT, MAKE_JAY_TSX_COMPONENT, type MainRuntimeModes, type ParsedJayModuleSpecifier, type PluginComponentResolution, type PluginInitConfig, type PluginManifest, REACT, type RecursiveRegion, type Ref, type RefsTree, RenderFragment, RuntimeMode, SourceFileFormat, TSX_EXTENSION, TS_EXTENSION, WithValidations, addBuildEnvironment, checkValidationErrors, equalJayTypes, getBasePath, getBuildEnvironment, getJayTsFileSourcePath, getMode, getModeFileExtension, getModeFromExtension, hasBuildEnvironment, hasExtension, hasJayExtension, hasJayModeExtension, hasRefs, isArrayType, isAtomicType, isComponentType, isCurrencyType, isDateWithTimezoneType, isElementConstructorType, isElementType, isEnumType, isHTMLType, isImportedType, isLocalModule, isObjectType, isPromiseType, isRecursiveType, isTypeAliasType, isUnionType, loadPluginManifest, mergeRefsTrees, mkRef, mkRefsTree, nestRefs, parseJayModuleSpecifier, prettify, prettifyHtml, removeComments, resolveLocalPlugin, resolveNpmPlugin, resolvePluginComponent, resolvePrimitiveType, withOriginalTrace, withoutExtension };
639
+ export { type ActionManifestEntry, CSS_EXTENSION, type CompilerSourceFile, type DynamicContractConfig, GenerateTarget, type GenericTypescriptSourceFile, Import, type ImportName, type ImportedRefsTree, Imports, ImportsFor, JAY_4_REACT, JAY_ACTION_DTS_EXTENSION, JAY_ACTION_EXTENSION, JAY_COMPONENT, JAY_CONTRACT_DTS_EXTENSION, JAY_CONTRACT_EXTENSION, JAY_DTS_EXTENSION, JAY_EXTENSION, JAY_FULLSTACK_COMPONENTS, JAY_QUERY_CLIENT, JAY_QUERY_MAIN_SANDBOX, JAY_QUERY_MAIN_SANDBOX_TS, JAY_QUERY_PREFIX, JAY_QUERY_SERVER, JAY_QUERY_WORKER_SANDBOX, JAY_QUERY_WORKER_SANDBOX_TS, JAY_QUERY_WORKER_TRUSTED, JAY_QUERY_WORKER_TRUSTED_TS, JAY_RUNTIME, JAY_SECURE, JAY_STACK_CLIENT_RUNTIME, JAY_TS_EXTENSION, JayArrayType, JayAtomicType, JayBoolean, JayBuildEnvironment, JayComponentApiMember, JayComponentType, JayDate, JayElementConstructorType, JayElementType, JayEnumType, type JayEnvironment, JayErrorType, JayHTMLType, type JayImportLink, type JayImportName, JayImportedType, JayNumber, JayObjectType, JayOptionalType, JayPromiseType, JayRecursiveType, JayString, type JayType, JayTypeAlias, JayTypeKind, JayUnionType, JayUnknown, type JayValidations, type JsonSchemaProperty, LOCAL_PLUGIN_PATH, MAKE_JAY_4_REACT_COMPONENT, MAKE_JAY_COMPONENT, MAKE_JAY_TSX_COMPONENT, type MainRuntimeModes, type ParsedJayModuleSpecifier, type PluginComponentResolution, type PluginInitConfig, type PluginManifest, REACT, type RecursiveRegion, type Ref, type RefsTree, RenderFragment, RuntimeMode, SourceFileFormat, TSX_EXTENSION, TS_EXTENSION, WithValidations, addBuildEnvironment, checkValidationErrors, equalJayTypes, findDynamicContract, getBasePath, getBuildEnvironment, getJayTsFileSourcePath, getMode, getModeFileExtension, getModeFromExtension, hasBuildEnvironment, hasExtension, hasJayExtension, hasJayModeExtension, hasRefs, isArrayType, isAtomicType, isComponentType, isCurrencyType, isDateWithTimezoneType, isElementConstructorType, isElementType, isEnumType, isHTMLType, isImportedType, isLocalModule, isObjectType, isOptionalType, isPromiseType, isRecursiveType, isTypeAliasType, isUnionType, jayTypeToJsonSchema, loadPluginManifest, mergeRefsTrees, mkRef, mkRefsTree, nestRefs, normalizeActionEntry, parseJayModuleSpecifier, prettify, prettifyHtml, removeComments, resolvePluginComponent, resolvePluginManifest, resolvePrimitiveType, withOriginalTrace, withoutExtension };
package/dist/index.js CHANGED
@@ -13,14 +13,17 @@ import { createRequire } from "module";
13
13
  const JAY_EXTENSION = ".jay-html";
14
14
  const CSS_EXTENSION = ".css";
15
15
  const JAY_CONTRACT_EXTENSION = ".jay-contract";
16
+ const JAY_ACTION_EXTENSION = ".jay-action";
16
17
  const JAY_TS_EXTENSION = ".jay-html.ts";
17
18
  const JAY_DTS_EXTENSION = ".jay-html.d.ts";
18
19
  const JAY_CONTRACT_DTS_EXTENSION = ".jay-contract.d.ts";
20
+ const JAY_ACTION_DTS_EXTENSION = ".jay-action.d.ts";
19
21
  const JAY_COMPONENT = "@jay-framework/component";
20
22
  const JAY_SECURE = "@jay-framework/secure";
21
23
  const JAY_RUNTIME = "@jay-framework/runtime";
22
24
  const JAY_4_REACT = "@jay-framework/4-react";
23
25
  const JAY_FULLSTACK_COMPONENTS = "@jay-framework/fullstack-component";
26
+ const JAY_STACK_CLIENT_RUNTIME = "@jay-framework/stack-client-runtime";
24
27
  const REACT = "react";
25
28
  const MAKE_JAY_COMPONENT = "makeJayComponent";
26
29
  const MAKE_JAY_TSX_COMPONENT = "makeJayTsxComponent";
@@ -400,6 +403,18 @@ const Import = {
400
403
  "injectHeadLinks",
401
404
  1
402
405
  /* implementation */
406
+ ),
407
+ makeJayComponent: importStatementFragment(
408
+ JAY_COMPONENT,
409
+ "makeJayComponent",
410
+ 1
411
+ /* implementation */
412
+ ),
413
+ makeHeadlessInstanceComponent: importStatementFragment(
414
+ JAY_STACK_CLIENT_RUNTIME,
415
+ "makeHeadlessInstanceComponent",
416
+ 1
417
+ /* implementation */
403
418
  )
404
419
  };
405
420
  class Imports {
@@ -480,6 +495,7 @@ var JayTypeKind = /* @__PURE__ */ ((JayTypeKind2) => {
480
495
  JayTypeKind2[JayTypeKind2["union"] = 10] = "union";
481
496
  JayTypeKind2[JayTypeKind2["promise"] = 11] = "promise";
482
497
  JayTypeKind2[JayTypeKind2["recursive"] = 12] = "recursive";
498
+ JayTypeKind2[JayTypeKind2["optional"] = 13] = "optional";
483
499
  return JayTypeKind2;
484
500
  })(JayTypeKind || {});
485
501
  class JayAtomicType {
@@ -602,11 +618,23 @@ class JayRecursiveType {
602
618
  return this.resolvedType?.name || `Recursive<${this.referencePath}>`;
603
619
  }
604
620
  }
621
+ class JayOptionalType {
622
+ constructor(innerType) {
623
+ __publicField(this, "kind", 13);
624
+ this.innerType = innerType;
625
+ }
626
+ get name() {
627
+ return `${this.innerType.name}?`;
628
+ }
629
+ }
605
630
  const JayErrorType = new JayObjectType("Error", {
606
631
  message: new JayAtomicType("string"),
607
632
  name: new JayAtomicType("string"),
608
633
  stack: new JayAtomicType("string")
609
634
  });
635
+ function isOptionalType(aType) {
636
+ return aType.kind === 13;
637
+ }
610
638
  function isAtomicType(aType) {
611
639
  return aType.kind === 0;
612
640
  }
@@ -692,6 +720,51 @@ function equalJayTypes(a, b) {
692
720
  } else
693
721
  ;
694
722
  }
723
+ function jayTypeToJsonSchema(type) {
724
+ if (isOptionalType(type)) {
725
+ return jayTypeToJsonSchema(type.innerType);
726
+ }
727
+ if (isAtomicType(type)) {
728
+ const name = type.name.toLowerCase();
729
+ if (name === "string" || name === "number" || name === "boolean") {
730
+ return { type: name };
731
+ }
732
+ return { type: "string" };
733
+ }
734
+ if (isEnumType(type)) {
735
+ return { type: "string", enum: type.values };
736
+ }
737
+ if (isImportedType(type)) {
738
+ return { type: "object", description: `Contract: ${type.name}` };
739
+ }
740
+ if (isArrayType(type)) {
741
+ const itemSchema = jayTypeToJsonSchema(type.itemType);
742
+ if (itemSchema) {
743
+ return { type: "array", items: itemSchema };
744
+ }
745
+ return { type: "array" };
746
+ }
747
+ if (isObjectType(type)) {
748
+ const properties = {};
749
+ const required = [];
750
+ for (const [key, propType] of Object.entries(type.props)) {
751
+ const isOpt = isOptionalType(propType);
752
+ const schema = jayTypeToJsonSchema(propType);
753
+ if (schema) {
754
+ properties[key] = schema;
755
+ if (!isOpt) {
756
+ required.push(key);
757
+ }
758
+ }
759
+ }
760
+ return {
761
+ type: "object",
762
+ properties,
763
+ ...required.length > 0 && { required }
764
+ };
765
+ }
766
+ return null;
767
+ }
695
768
  var RuntimeMode = /* @__PURE__ */ ((RuntimeMode2) => {
696
769
  RuntimeMode2["MainTrusted"] = "mainTrusted";
697
770
  RuntimeMode2["MainSandbox"] = "mainSandbox";
@@ -894,13 +967,13 @@ class WithValidations {
894
967
  this.validations = validations;
895
968
  }
896
969
  map(func) {
897
- if (this.val)
970
+ if (this.val !== void 0)
898
971
  return new WithValidations(func(this.val), this.validations);
899
972
  else
900
973
  return new WithValidations(void 0, this.validations);
901
974
  }
902
975
  async mapAsync(func) {
903
- if (this.val) {
976
+ if (this.val !== void 0) {
904
977
  const result = await func(this.val);
905
978
  return new WithValidations(result, this.validations);
906
979
  } else {
@@ -908,14 +981,14 @@ class WithValidations {
908
981
  }
909
982
  }
910
983
  flatMap(func) {
911
- if (this.val) {
984
+ if (this.val !== void 0) {
912
985
  let that = func(this.val);
913
986
  return new WithValidations(that.val, [...this.validations, ...that.validations]);
914
987
  } else
915
988
  return new WithValidations(void 0, this.validations);
916
989
  }
917
990
  async flatMapAsync(func) {
918
- if (this.val) {
991
+ if (this.val !== void 0) {
919
992
  const result = await func(this.val);
920
993
  return new WithValidations(result.val, [...this.validations, ...result.validations]);
921
994
  } else {
@@ -928,6 +1001,28 @@ class WithValidations {
928
1001
  ...other.validations
929
1002
  ]);
930
1003
  }
1004
+ /**
1005
+ * Append validations from another WithValidations without changing the value.
1006
+ * Useful for collecting validations from side-effect operations.
1007
+ */
1008
+ withValidationsFrom(other) {
1009
+ return new WithValidations(this.val, [...this.validations, ...other.validations]);
1010
+ }
1011
+ /**
1012
+ * Merge an array of WithValidations into a single WithValidations containing an array of values.
1013
+ * All validations are collected.
1014
+ */
1015
+ static all(items) {
1016
+ const values = items.map((item) => item.val).filter((v) => v !== void 0);
1017
+ const validations = items.flatMap((item) => item.validations);
1018
+ return new WithValidations(values, validations);
1019
+ }
1020
+ /**
1021
+ * Create a WithValidations with no validations (pure value).
1022
+ */
1023
+ static pure(value) {
1024
+ return new WithValidations(value, []);
1025
+ }
931
1026
  }
932
1027
  function checkValidationErrors(withValidations) {
933
1028
  const { validations } = withValidations;
@@ -1090,6 +1185,13 @@ function removeComments(code) {
1090
1185
  ).join("\n");
1091
1186
  }
1092
1187
  const require2 = createRequire(import.meta.url);
1188
+ const LOCAL_PLUGIN_PATH = "src/plugins";
1189
+ function normalizeActionEntry(entry) {
1190
+ if (typeof entry === "string") {
1191
+ return { name: entry };
1192
+ }
1193
+ return { name: entry.name, action: entry.action };
1194
+ }
1093
1195
  function loadPluginManifest(pluginDir) {
1094
1196
  const pluginYamlPath = path.join(pluginDir, "plugin.yaml");
1095
1197
  if (!fs.existsSync(pluginYamlPath)) {
@@ -1102,8 +1204,20 @@ function loadPluginManifest(pluginDir) {
1102
1204
  return null;
1103
1205
  }
1104
1206
  }
1105
- function resolveLocalPlugin(projectRoot, pluginName, contractName) {
1106
- const localPluginPath = path.join(projectRoot, "src/plugins", pluginName);
1207
+ function findDynamicContract(manifest, contractName) {
1208
+ if (!manifest.dynamic_contracts) {
1209
+ return null;
1210
+ }
1211
+ const slashIndex = contractName.indexOf("/");
1212
+ if (slashIndex === -1) {
1213
+ return null;
1214
+ }
1215
+ const prefix = contractName.substring(0, slashIndex);
1216
+ const dynamicConfigs = Array.isArray(manifest.dynamic_contracts) ? manifest.dynamic_contracts : [manifest.dynamic_contracts];
1217
+ return dynamicConfigs.find((config) => config.prefix === prefix) || null;
1218
+ }
1219
+ function resolveLocalPluginManifest(projectRoot, pluginName) {
1220
+ const localPluginPath = path.join(projectRoot, LOCAL_PLUGIN_PATH, pluginName);
1107
1221
  const pluginYamlPath = path.join(localPluginPath, "plugin.yaml");
1108
1222
  if (!fs.existsSync(localPluginPath)) {
1109
1223
  return null;
@@ -1119,32 +1233,59 @@ function resolveLocalPlugin(projectRoot, pluginName, contractName) {
1119
1233
  `Failed to parse plugin.yaml for local plugin "${pluginName}" at ${pluginYamlPath}`
1120
1234
  ]);
1121
1235
  }
1122
- if (!manifest.contracts || manifest.contracts.length === 0) {
1236
+ if (!manifest.contracts && !manifest.dynamic_contracts) {
1123
1237
  return new WithValidations(null, [
1124
- `Local plugin "${pluginName}" has no contracts defined in plugin.yaml`
1238
+ `Local plugin "${pluginName}" has no contracts or dynamic_contracts defined in plugin.yaml`
1125
1239
  ]);
1126
1240
  }
1127
- const contract = manifest.contracts.find((c2) => c2.name === contractName);
1128
- if (!contract) {
1129
- const availableContracts = manifest.contracts.map((c2) => c2.name).join(", ");
1130
- return new WithValidations(null, [
1131
- `Contract "${contractName}" not found in local plugin "${pluginName}". Available contracts: ${availableContracts}`
1132
- ]);
1241
+ return new WithValidations(manifest, []);
1242
+ }
1243
+ function resolveLocalPlugin(projectRoot, pluginName, contractName) {
1244
+ const manifestWithValidations = resolveLocalPluginManifest(projectRoot, pluginName);
1245
+ if (!manifestWithValidations) {
1246
+ return null;
1133
1247
  }
1248
+ if (!manifestWithValidations.val || manifestWithValidations.validations.length > 0)
1249
+ return new WithValidations(null, manifestWithValidations.validations);
1250
+ const manifest = manifestWithValidations.val;
1134
1251
  const componentModule = manifest.module || "index.js";
1252
+ const localPluginPath = path.join(projectRoot, LOCAL_PLUGIN_PATH, pluginName);
1135
1253
  const componentPath = path.join(localPluginPath, componentModule);
1136
- return new WithValidations(
1137
- {
1138
- contractPath: path.join(localPluginPath, contract.contract),
1139
- componentPath,
1140
- componentName: contract.component,
1141
- // This is the exported member name
1142
- isNpmPackage: false
1143
- },
1144
- []
1145
- );
1254
+ if (manifest.contracts && manifest.contracts.length > 0) {
1255
+ const contract = manifest.contracts.find((c2) => c2.name === contractName);
1256
+ if (contract) {
1257
+ return new WithValidations(
1258
+ {
1259
+ contractPath: path.join(localPluginPath, contract.contract),
1260
+ componentPath,
1261
+ componentName: contract.component,
1262
+ isNpmPackage: false
1263
+ },
1264
+ []
1265
+ );
1266
+ }
1267
+ }
1268
+ const dynamicConfig = findDynamicContract(manifest, contractName);
1269
+ if (dynamicConfig) {
1270
+ return new WithValidations(
1271
+ {
1272
+ contractPath: "",
1273
+ // Dynamic contracts don't have a static path
1274
+ componentPath,
1275
+ componentName: dynamicConfig.component,
1276
+ isNpmPackage: false
1277
+ },
1278
+ []
1279
+ );
1280
+ }
1281
+ const availableContracts = manifest.contracts?.map((c2) => c2.name) || [];
1282
+ const dynamicPrefixes = manifest.dynamic_contracts ? (Array.isArray(manifest.dynamic_contracts) ? manifest.dynamic_contracts : [manifest.dynamic_contracts]).map((c2) => `${c2.prefix}/*`) : [];
1283
+ const allAvailable = [...availableContracts, ...dynamicPrefixes].join(", ");
1284
+ return new WithValidations(null, [
1285
+ `Contract "${contractName}" not found in local plugin "${pluginName}". Available: ${allAvailable}`
1286
+ ]);
1146
1287
  }
1147
- function resolveNpmPlugin(projectRoot, pluginName, contractName) {
1288
+ function resolveNpmPluginManifest(projectRoot, pluginName) {
1148
1289
  let pluginYamlPath;
1149
1290
  try {
1150
1291
  pluginYamlPath = require2.resolve(`${pluginName}/plugin.yaml`, {
@@ -1167,75 +1308,145 @@ function resolveNpmPlugin(projectRoot, pluginName, contractName) {
1167
1308
  `Failed to parse plugin.yaml for NPM package "${pluginName}" at ${pluginYamlPath}`
1168
1309
  ]);
1169
1310
  }
1170
- if (!manifest.contracts || manifest.contracts.length === 0) {
1311
+ if (!manifest.contracts && !manifest.dynamic_contracts) {
1171
1312
  return new WithValidations(null, [
1172
- `NPM package "${pluginName}" has no contracts defined in plugin.yaml`
1313
+ `NPM package "${pluginName}" has no contracts or dynamic_contracts defined in plugin.yaml`
1173
1314
  ]);
1174
1315
  }
1175
- const contract = manifest.contracts.find((c2) => c2.name === contractName);
1176
- if (!contract) {
1177
- const availableContracts = manifest.contracts.map((c2) => c2.name).join(", ");
1178
- return new WithValidations(null, [
1179
- `Contract "${contractName}" not found in NPM package "${pluginName}". Available contracts: ${availableContracts}`
1180
- ]);
1316
+ return new WithValidations(manifest, []);
1317
+ }
1318
+ function resolveNpmPlugin(projectRoot, pluginName, contractName) {
1319
+ const manifestWithValidations = resolveNpmPluginManifest(projectRoot, pluginName);
1320
+ if (!manifestWithValidations) {
1321
+ return null;
1181
1322
  }
1323
+ if (!manifestWithValidations.val || manifestWithValidations.validations.length > 0)
1324
+ return new WithValidations(null, manifestWithValidations.validations);
1325
+ const manifest = manifestWithValidations.val;
1326
+ const pluginYamlPath = require2.resolve(`${pluginName}/plugin.yaml`, {
1327
+ paths: [projectRoot]
1328
+ });
1329
+ const npmPluginPath = path.dirname(pluginYamlPath);
1182
1330
  const packageJsonPath = path.join(npmPluginPath, "package.json");
1183
- let componentPath;
1184
- let contractPath;
1185
- if (fs.existsSync(packageJsonPath)) {
1186
- try {
1187
- const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
1188
- const packageName = packageJson.name;
1189
- const moduleName = manifest.module || packageName;
1190
- if ((moduleName === packageName || !manifest.module) && packageJson.exports && packageJson.exports["."]) {
1191
- const mainExport = packageJson.exports["."];
1192
- const mainPath = typeof mainExport === "string" ? mainExport : mainExport.default || mainExport.import;
1193
- componentPath = path.join(npmPluginPath, mainPath);
1194
- } else {
1195
- componentPath = path.join(npmPluginPath, "dist/index.js");
1331
+ const getComponentPath = () => {
1332
+ if (fs.existsSync(packageJsonPath)) {
1333
+ try {
1334
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
1335
+ const packageName = packageJson.name;
1336
+ const moduleName = manifest.module || packageName;
1337
+ if ((moduleName === packageName || !manifest.module) && packageJson.exports && packageJson.exports["."]) {
1338
+ const mainExport = packageJson.exports["."];
1339
+ const mainPath = typeof mainExport === "string" ? mainExport : mainExport.default || mainExport.import;
1340
+ return path.join(npmPluginPath, mainPath);
1341
+ }
1342
+ } catch {
1196
1343
  }
1197
- const contractSpec = contract.contract;
1198
- const contractExportKey = "./" + contractSpec;
1199
- if (packageJson.exports && packageJson.exports[contractExportKey]) {
1200
- const exportPath = packageJson.exports[contractExportKey];
1201
- contractPath = path.join(npmPluginPath, exportPath);
1344
+ }
1345
+ return path.join(npmPluginPath, "dist/index.js");
1346
+ };
1347
+ if (manifest.contracts && manifest.contracts.length > 0) {
1348
+ const contract = manifest.contracts.find((c2) => c2.name === contractName);
1349
+ if (contract) {
1350
+ const componentPath = getComponentPath();
1351
+ let contractPath;
1352
+ if (fs.existsSync(packageJsonPath)) {
1353
+ try {
1354
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
1355
+ const contractSpec = contract.contract;
1356
+ const contractExportKey = "./" + contractSpec;
1357
+ if (packageJson.exports && packageJson.exports[contractExportKey]) {
1358
+ const exportPath = packageJson.exports[contractExportKey];
1359
+ contractPath = path.join(npmPluginPath, exportPath);
1360
+ } else {
1361
+ const possiblePaths = [
1362
+ path.join(npmPluginPath, "dist", contractSpec),
1363
+ path.join(npmPluginPath, "lib", contractSpec),
1364
+ path.join(npmPluginPath, contractSpec)
1365
+ ];
1366
+ contractPath = possiblePaths.find((p) => fs.existsSync(p)) || possiblePaths[0];
1367
+ }
1368
+ } catch {
1369
+ contractPath = path.join(npmPluginPath, "dist", contract.contract);
1370
+ }
1202
1371
  } else {
1203
- const possiblePaths = [
1204
- path.join(npmPluginPath, "dist", contractSpec),
1205
- path.join(npmPluginPath, "lib", contractSpec),
1206
- path.join(npmPluginPath, contractSpec)
1207
- ];
1208
- contractPath = possiblePaths.find((p) => fs.existsSync(p)) || possiblePaths[0];
1372
+ contractPath = path.join(npmPluginPath, "dist", contract.contract);
1209
1373
  }
1210
- } catch (error) {
1211
- componentPath = path.join(npmPluginPath, "dist/index.js");
1212
- contractPath = path.join(npmPluginPath, "dist", contract.contract);
1374
+ return new WithValidations(
1375
+ {
1376
+ contractPath,
1377
+ componentPath,
1378
+ componentName: contract.component,
1379
+ isNpmPackage: true,
1380
+ packageName: pluginName
1381
+ },
1382
+ []
1383
+ );
1213
1384
  }
1214
- } else {
1215
- componentPath = path.join(npmPluginPath, "dist/index.js");
1216
- contractPath = path.join(npmPluginPath, "dist", contract.contract);
1217
1385
  }
1218
- return new WithValidations(
1219
- {
1220
- contractPath,
1221
- componentPath,
1222
- componentName: contract.component,
1223
- // This is the exported member name
1224
- isNpmPackage: true,
1225
- packageName: pluginName
1226
- },
1227
- []
1228
- );
1386
+ const dynamicConfig = findDynamicContract(manifest, contractName);
1387
+ if (dynamicConfig) {
1388
+ const componentPath = getComponentPath();
1389
+ return new WithValidations(
1390
+ {
1391
+ contractPath: "",
1392
+ // Dynamic contracts don't have a static path
1393
+ componentPath,
1394
+ componentName: dynamicConfig.component,
1395
+ isNpmPackage: true,
1396
+ packageName: pluginName
1397
+ },
1398
+ []
1399
+ );
1400
+ }
1401
+ const availableContracts = manifest.contracts?.map((c2) => c2.name) || [];
1402
+ const dynamicPrefixes = manifest.dynamic_contracts ? (Array.isArray(manifest.dynamic_contracts) ? manifest.dynamic_contracts : [manifest.dynamic_contracts]).map((c2) => `${c2.prefix}/*`) : [];
1403
+ const allAvailable = [...availableContracts, ...dynamicPrefixes].join(", ");
1404
+ return new WithValidations(null, [
1405
+ `Contract "${contractName}" not found in NPM package "${pluginName}". Available: ${allAvailable}`
1406
+ ]);
1229
1407
  }
1230
1408
  function resolvePluginComponent(projectRoot, pluginName, contractName) {
1231
1409
  const localResult = resolveLocalPlugin(projectRoot, pluginName, contractName);
1232
- if (localResult !== null) {
1410
+ if (localResult && localResult.val !== null && localResult.validations.length === 0) {
1233
1411
  return localResult;
1234
1412
  }
1235
1413
  const npmResult = resolveNpmPlugin(projectRoot, pluginName, contractName);
1236
- if (npmResult !== null) {
1414
+ if (npmResult && npmResult.val !== null && npmResult.validations.length === 0) {
1415
+ return npmResult;
1416
+ }
1417
+ if (localResult && localResult.validations.length > 0) {
1418
+ return localResult;
1419
+ }
1420
+ if (npmResult && npmResult.validations.length > 0 && localResult === null) {
1421
+ const npmError = npmResult.validations[0];
1422
+ const isGenericPackageNotFound = npmError.startsWith("NPM package") && npmError.includes("not found") || npmError.startsWith("Plugin") && npmError.includes("not found");
1423
+ if (!isGenericPackageNotFound) {
1424
+ return npmResult;
1425
+ }
1426
+ }
1427
+ return new WithValidations(null, [
1428
+ `Plugin "${pluginName}" not found. Searched in src/plugins/${pluginName}/ and node_modules/${pluginName}/. Ensure the plugin is installed or exists in your project.`
1429
+ ]);
1430
+ }
1431
+ function resolvePluginManifest(projectRoot, pluginName) {
1432
+ const localResult = resolveLocalPluginManifest(projectRoot, pluginName);
1433
+ if (localResult && localResult.val !== null && localResult.validations.length === 0) {
1434
+ return localResult;
1435
+ }
1436
+ const npmResult = resolveNpmPluginManifest(projectRoot, pluginName);
1437
+ if (npmResult && npmResult.val !== null && npmResult.validations.length === 0) {
1237
1438
  return npmResult;
1238
1439
  }
1440
+ if (localResult && localResult.validations.length > 0) {
1441
+ return localResult;
1442
+ }
1443
+ if (npmResult && npmResult.validations.length > 0 && localResult === null) {
1444
+ const npmError = npmResult.validations[0];
1445
+ const isGenericPackageNotFound = npmError.startsWith("NPM package") && npmError.includes("not found") || npmError.startsWith("Plugin") && npmError.includes("not found");
1446
+ if (!isGenericPackageNotFound) {
1447
+ return npmResult;
1448
+ }
1449
+ }
1239
1450
  return new WithValidations(null, [
1240
1451
  `Plugin "${pluginName}" not found. Searched in src/plugins/${pluginName}/ and node_modules/${pluginName}/. Ensure the plugin is installed or exists in your project.`
1241
1452
  ]);
@@ -1255,6 +1466,8 @@ export {
1255
1466
  Imports,
1256
1467
  ImportsFor,
1257
1468
  JAY_4_REACT,
1469
+ JAY_ACTION_DTS_EXTENSION,
1470
+ JAY_ACTION_EXTENSION,
1258
1471
  JAY_COMPONENT,
1259
1472
  JAY_CONTRACT_DTS_EXTENSION,
1260
1473
  JAY_CONTRACT_EXTENSION,
@@ -1272,6 +1485,7 @@ export {
1272
1485
  JAY_QUERY_WORKER_TRUSTED_TS,
1273
1486
  JAY_RUNTIME,
1274
1487
  JAY_SECURE,
1488
+ JAY_STACK_CLIENT_RUNTIME,
1275
1489
  JAY_TS_EXTENSION,
1276
1490
  JayArrayType,
1277
1491
  JayAtomicType,
@@ -1288,6 +1502,7 @@ export {
1288
1502
  JayImportedType,
1289
1503
  JayNumber,
1290
1504
  JayObjectType,
1505
+ JayOptionalType,
1291
1506
  JayPromiseType,
1292
1507
  JayRecursiveType,
1293
1508
  JayString,
@@ -1295,6 +1510,7 @@ export {
1295
1510
  JayTypeKind,
1296
1511
  JayUnionType,
1297
1512
  JayUnknown,
1513
+ LOCAL_PLUGIN_PATH,
1298
1514
  MAKE_JAY_4_REACT_COMPONENT,
1299
1515
  MAKE_JAY_COMPONENT,
1300
1516
  MAKE_JAY_TSX_COMPONENT,
@@ -1308,6 +1524,7 @@ export {
1308
1524
  addBuildEnvironment,
1309
1525
  checkValidationErrors,
1310
1526
  equalJayTypes,
1527
+ findDynamicContract,
1311
1528
  getBasePath,
1312
1529
  getBuildEnvironment,
1313
1530
  getJayTsFileSourcePath,
@@ -1332,22 +1549,24 @@ export {
1332
1549
  isImportedType,
1333
1550
  isLocalModule,
1334
1551
  isObjectType,
1552
+ isOptionalType,
1335
1553
  isPromiseType,
1336
1554
  isRecursiveType,
1337
1555
  isTypeAliasType,
1338
1556
  isUnionType,
1557
+ jayTypeToJsonSchema,
1339
1558
  loadPluginManifest,
1340
1559
  mergeRefsTrees,
1341
1560
  mkRef,
1342
1561
  mkRefsTree,
1343
1562
  nestRefs,
1563
+ normalizeActionEntry,
1344
1564
  parseJayModuleSpecifier,
1345
1565
  prettify,
1346
1566
  prettifyHtml,
1347
1567
  removeComments,
1348
- resolveLocalPlugin,
1349
- resolveNpmPlugin,
1350
1568
  resolvePluginComponent,
1569
+ resolvePluginManifest,
1351
1570
  resolvePrimitiveType,
1352
1571
  u as ts,
1353
1572
  c as tsBridge,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jay-framework/compiler-shared",
3
- "version": "0.11.0",
3
+ "version": "0.13.0",
4
4
  "type": "module",
5
5
  "description": "",
6
6
  "license": "Apache-2.0",
@@ -25,10 +25,10 @@
25
25
  },
26
26
  "author": "",
27
27
  "dependencies": {
28
- "@jay-framework/component": "^0.11.0",
29
- "@jay-framework/runtime": "^0.11.0",
30
- "@jay-framework/secure": "^0.11.0",
31
- "@jay-framework/typescript-bridge": "^0.6.0",
28
+ "@jay-framework/component": "^0.13.0",
29
+ "@jay-framework/runtime": "^0.13.0",
30
+ "@jay-framework/secure": "^0.13.0",
31
+ "@jay-framework/typescript-bridge": "^0.8.0",
32
32
  "@types/js-yaml": "^4.0.9",
33
33
  "change-case": "^4.1.2",
34
34
  "js-beautify": "^1.14.11",
@@ -41,7 +41,7 @@
41
41
  },
42
42
  "devDependencies": {
43
43
  "@caiogondim/strip-margin": "^1.0.0",
44
- "@jay-framework/dev-environment": "^0.11.0",
44
+ "@jay-framework/dev-environment": "^0.13.0",
45
45
  "@testing-library/jest-dom": "^6.2.0",
46
46
  "@types/js-beautify": "^1",
47
47
  "@types/node": "^20.11.5",