@pattern-stack/codegen 0.6.7 → 0.7.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 (42) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/src/cli/index.js +516 -73
  3. package/dist/src/cli/index.js.map +1 -1
  4. package/dist/src/index.d.ts +208 -1
  5. package/dist/src/index.js +147 -0
  6. package/dist/src/index.js.map +1 -1
  7. package/package.json +1 -1
  8. package/src/patterns/library/base-junction-fields.ts +32 -0
  9. package/src/patterns/library/index.ts +7 -0
  10. package/src/patterns/library/junction.pattern.ts +41 -0
  11. package/templates/entity/new/backend/application/queries/get-by-id.ejs.t +3 -3
  12. package/templates/entity/new/backend/application/queries/grouped-index.ejs.t +5 -5
  13. package/templates/entity/new/backend/application/queries/index.ejs.t +3 -0
  14. package/templates/entity/new/backend/application/queries/list.ejs.t +3 -3
  15. package/templates/entity/new/backend/application/queries/relationships.queries.ejs.t +147 -0
  16. package/templates/entity/new/backend/database/repository.ejs.t +36 -176
  17. package/templates/entity/new/backend/domain/entity.ejs.t +0 -44
  18. package/templates/entity/new/backend/domain/grouped-index.ejs.t +4 -60
  19. package/templates/entity/new/backend/domain/index.ejs.t +2 -2
  20. package/templates/entity/new/backend/domain/repository-interface.ejs.t +16 -17
  21. package/templates/entity/new/backend/modules/core/module.ejs.t +10 -0
  22. package/templates/entity/new/backend/presentation/controller.ejs.t +2 -34
  23. package/templates/entity/new/clean-lite-ps/entity.ejs.t +21 -2
  24. package/templates/entity/new/clean-lite-ps/module.ejs.t +27 -2
  25. package/templates/entity/new/clean-lite-ps/prompt-extension.js +108 -9
  26. package/templates/entity/new/clean-lite-ps/repository.ejs.t +33 -1
  27. package/templates/entity/new/clean-lite-ps/service.ejs.t +79 -0
  28. package/templates/entity/new/prompt.js +1 -0
  29. package/templates/junction/new/_inject-parent-module-clp-left.ejs.t +8 -0
  30. package/templates/junction/new/_inject-parent-module-clp-right.ejs.t +8 -0
  31. package/templates/junction/new/_inject-parent-module-import-clp-left.ejs.t +9 -0
  32. package/templates/junction/new/_inject-parent-module-import-clp-right.ejs.t +9 -0
  33. package/templates/junction/new/_inject-parent-service-clp-left.ejs.t +51 -0
  34. package/templates/junction/new/_inject-parent-service-clp-right.ejs.t +48 -0
  35. package/templates/junction/new/_inject-parent-service-import-clp-left.ejs.t +11 -0
  36. package/templates/junction/new/_inject-parent-service-import-clp-right.ejs.t +11 -0
  37. package/templates/junction/new/entity.ejs.t +111 -0
  38. package/templates/junction/new/index.ejs.t +15 -0
  39. package/templates/junction/new/module.ejs.t +37 -0
  40. package/templates/junction/new/prompt.js +492 -0
  41. package/templates/junction/new/repository.ejs.t +67 -0
  42. package/templates/junction/new/service.ejs.t +174 -0
@@ -3453,6 +3453,149 @@ declare const RelationshipDefinitionSchema: z.ZodEffects<z.ZodEffects<z.ZodObjec
3453
3453
  }>;
3454
3454
  type RelationshipDefinition = z.infer<typeof RelationshipDefinitionSchema>;
3455
3455
 
3456
+ /**
3457
+ * Top-level junction YAML shape.
3458
+ *
3459
+ * pattern: Junction
3460
+ * between: [opportunity, contact]
3461
+ * temporal: true # optional, default true
3462
+ * sourced: true # optional, default true
3463
+ * fields:
3464
+ * role:
3465
+ * type: enum
3466
+ * values: [champion, decision_maker, influencer]
3467
+ * queries:
3468
+ * - by: [opportunity_id]
3469
+ *
3470
+ * Fields use the same shape as entity fields — validated downstream by the
3471
+ * template / codegen layer using the existing `FieldDefinitionSchema`.
3472
+ * This schema accepts the shape loosely (`z.any()`) and applies only the
3473
+ * reserved-column collision check; matches the relationship-schema
3474
+ * precedent (`relationship-definition.schema.ts` line ~250).
3475
+ */
3476
+ declare const JunctionDefinitionSchema: z.ZodEffects<z.ZodEffects<z.ZodObject<{
3477
+ /** Discriminator literal — `pattern: Junction`. */
3478
+ pattern: z.ZodLiteral<"Junction">;
3479
+ /**
3480
+ * Exactly two endpoint entity names. Both intra- and cross-domain
3481
+ * pairings are accepted; entity existence is validated by the
3482
+ * analyzer in a later leaf.
3483
+ */
3484
+ between: z.ZodTuple<[z.ZodString, z.ZodString], null>;
3485
+ /**
3486
+ * Emit BaseJunctionFields temporal columns (`started_at`, `ended_at`,
3487
+ * `matched_at`). Default true. Matches Relationship's `temporal` toggle.
3488
+ */
3489
+ temporal: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
3490
+ /**
3491
+ * Emit BaseJunctionFields sourcing columns (`sourced_from`,
3492
+ * `confidence`). Default true. Matches Relationship's `sourced` toggle.
3493
+ */
3494
+ sourced: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
3495
+ /**
3496
+ * Junction-specific fields beyond `BaseJunctionFields`. Includes the
3497
+ * per-pairing role enum (declared inline; never shared across
3498
+ * pairings). Shape is validated downstream by the codegen layer
3499
+ * using the existing entity FieldDefinitionSchema.
3500
+ */
3501
+ fields: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
3502
+ /**
3503
+ * Declarative queries — same syntax as entity queries. Shape is
3504
+ * validated downstream by the codegen layer.
3505
+ */
3506
+ queries: z.ZodOptional<z.ZodArray<z.ZodAny, "many">>;
3507
+ /**
3508
+ * Per-side opt-out for parent-service fan-out (CGP-60). When a side
3509
+ * is `false`, the `_inject-parent-service-*` templates emit nothing
3510
+ * on that side (and the corresponding module wiring is skipped).
3511
+ * The junction service body is always emitted regardless. Defaults
3512
+ * to `{ left: true, right: true }`.
3513
+ */
3514
+ expose_on_parent: z.ZodDefault<z.ZodOptional<z.ZodObject<{
3515
+ left: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
3516
+ right: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
3517
+ }, "strip", z.ZodTypeAny, {
3518
+ left: boolean;
3519
+ right: boolean;
3520
+ }, {
3521
+ left?: boolean | undefined;
3522
+ right?: boolean | undefined;
3523
+ }>>>;
3524
+ }, "strict", z.ZodTypeAny, {
3525
+ pattern: "Junction";
3526
+ temporal: boolean;
3527
+ sourced: boolean;
3528
+ between: [string, string];
3529
+ expose_on_parent: {
3530
+ left: boolean;
3531
+ right: boolean;
3532
+ };
3533
+ fields?: Record<string, any> | undefined;
3534
+ queries?: any[] | undefined;
3535
+ }, {
3536
+ pattern: "Junction";
3537
+ between: [string, string];
3538
+ fields?: Record<string, any> | undefined;
3539
+ queries?: any[] | undefined;
3540
+ temporal?: boolean | undefined;
3541
+ sourced?: boolean | undefined;
3542
+ expose_on_parent?: {
3543
+ left?: boolean | undefined;
3544
+ right?: boolean | undefined;
3545
+ } | undefined;
3546
+ }>, {
3547
+ pattern: "Junction";
3548
+ temporal: boolean;
3549
+ sourced: boolean;
3550
+ between: [string, string];
3551
+ expose_on_parent: {
3552
+ left: boolean;
3553
+ right: boolean;
3554
+ };
3555
+ fields?: Record<string, any> | undefined;
3556
+ queries?: any[] | undefined;
3557
+ }, {
3558
+ pattern: "Junction";
3559
+ between: [string, string];
3560
+ fields?: Record<string, any> | undefined;
3561
+ queries?: any[] | undefined;
3562
+ temporal?: boolean | undefined;
3563
+ sourced?: boolean | undefined;
3564
+ expose_on_parent?: {
3565
+ left?: boolean | undefined;
3566
+ right?: boolean | undefined;
3567
+ } | undefined;
3568
+ }>, {
3569
+ pattern: "Junction";
3570
+ temporal: boolean;
3571
+ sourced: boolean;
3572
+ between: [string, string];
3573
+ expose_on_parent: {
3574
+ left: boolean;
3575
+ right: boolean;
3576
+ };
3577
+ fields?: Record<string, any> | undefined;
3578
+ queries?: any[] | undefined;
3579
+ }, {
3580
+ pattern: "Junction";
3581
+ between: [string, string];
3582
+ fields?: Record<string, any> | undefined;
3583
+ queries?: any[] | undefined;
3584
+ temporal?: boolean | undefined;
3585
+ sourced?: boolean | undefined;
3586
+ expose_on_parent?: {
3587
+ left?: boolean | undefined;
3588
+ right?: boolean | undefined;
3589
+ } | undefined;
3590
+ }>;
3591
+ type JunctionDefinition = z.infer<typeof JunctionDefinitionSchema>;
3592
+ declare function validateJunctionDefinition(data: unknown): JunctionDefinition;
3593
+ declare function safeValidateJunctionDefinition(data: unknown): {
3594
+ success: boolean;
3595
+ data?: JunctionDefinition;
3596
+ error?: z.ZodError;
3597
+ };
3598
+
3456
3599
  interface LoadResult {
3457
3600
  success: true;
3458
3601
  definition: EntityDefinition;
@@ -3485,6 +3628,27 @@ type LoadRelationshipResult = RelationshipLoadResult | RelationshipLoadError;
3485
3628
  * Load and validate a relationship definition from a YAML file
3486
3629
  */
3487
3630
  declare function loadRelationshipFromYaml(filePath: string): LoadRelationshipResult;
3631
+ interface JunctionLoadResult {
3632
+ success: true;
3633
+ definition: JunctionDefinition;
3634
+ filePath: string;
3635
+ }
3636
+ interface JunctionLoadError {
3637
+ success: false;
3638
+ error: string;
3639
+ details?: string[];
3640
+ filePath: string;
3641
+ }
3642
+ type LoadJunctionResult = JunctionLoadResult | JunctionLoadError;
3643
+ /**
3644
+ * Load and validate a junction definition from a YAML file.
3645
+ *
3646
+ * Mirrors {@link loadRelationshipFromYaml}: existence check → readFileSync →
3647
+ * parseYaml → `JunctionDefinitionSchema.safeParse`. Returns a discriminated
3648
+ * result; callers are expected to aggregate into `AnalysisIssue`s rather
3649
+ * than throw.
3650
+ */
3651
+ declare function loadJunctionFromYaml(filePath: string): LoadJunctionResult;
3488
3652
 
3489
3653
  /**
3490
3654
  * Entity Loader
@@ -3860,6 +4024,28 @@ declare const ActivityPattern: PatternDefinition<unknown>;
3860
4024
  */
3861
4025
  declare const BasePattern: PatternDefinition<unknown>;
3862
4026
 
4027
+ /**
4028
+ * JunctionPattern — top-level discriminator for explicit many-to-many
4029
+ * junction YAML files.
4030
+ *
4031
+ * Unlike `Activity` / `Synced` / `Metadata` (which attach to an entity via
4032
+ * `pattern:` / `patterns:`), `Junction` IS the top-level YAML shape — a
4033
+ * junction file's discriminator is `pattern: Junction`, not `entity:`.
4034
+ * It therefore does not declare `repositoryClass` / `serviceClass`: the
4035
+ * downstream Hygen-template leaf emits a dedicated junction repo/service
4036
+ * per pairing.
4037
+ *
4038
+ * `columns` is set to `BaseJunctionFields` for two reasons:
4039
+ * 1. Registry-side declaration of the shared shape — discoverable through
4040
+ * `getPattern('Junction').columns` by the downstream template leaf.
4041
+ * 2. Satisfies the registry's `assertHasContribution()` check, which
4042
+ * insists every pattern contribute at least one of columns / repo /
4043
+ * service class. (See spec §"Open Questions Q3"; recommendation (a).)
4044
+ *
4045
+ * See `.ai-docs/stacks/codegen-app-patterns/specs/58.md`.
4046
+ */
4047
+ declare const JunctionPattern: PatternDefinition<{}>;
4048
+
3863
4049
  /**
3864
4050
  * KnowledgePattern — replaces `family: knowledge`.
3865
4051
  *
@@ -3900,6 +4086,27 @@ declare const MetadataPattern: PatternDefinition<unknown>;
3900
4086
  */
3901
4087
  declare const SyncedPattern: PatternDefinition<unknown>;
3902
4088
 
4089
+ /**
4090
+ * BaseJunctionFields — shared column shape every junction table carries.
4091
+ *
4092
+ * Per-pairing role columns and pairing-specific fields are declared in the
4093
+ * consumer YAML's `fields:` block and are NOT part of this shape.
4094
+ *
4095
+ * Exposed as a TS const so two consumers can import it:
4096
+ * - `junction.pattern.ts` — registers it as the pattern's
4097
+ * column contribution so the
4098
+ * registry's `assertHasContribution()`
4099
+ * check passes structurally.
4100
+ * - `junction-definition.schema.ts` — uses the name set for the
4101
+ * reserved-column collision check
4102
+ * on the consumer's `fields:` block.
4103
+ *
4104
+ * See ADR-031 and `.ai-docs/stacks/codegen-app-patterns/specs/58.md`.
4105
+ */
4106
+
4107
+ declare const BaseJunctionFields: readonly PatternColumnContribution[];
4108
+ declare const BASE_JUNCTION_FIELD_NAMES: ReadonlySet<string>;
4109
+
3903
4110
  /**
3904
4111
  * Pattern Registry — library + app pattern storage and discovery.
3905
4112
  *
@@ -4137,4 +4344,4 @@ declare function validateEntities(entitiesDir: string): {
4137
4344
  errors: string[];
4138
4345
  };
4139
4346
 
4140
- export { ActivityPattern, type AnalysisIssue, type AnalysisResult, type AnalyzeDomainOptions, type AnyPatternDefinition, BasePattern, type CodegenManifest, type DomainGraph, type DomainStatistics, type EntityNode, KnowledgePattern, type LoadAppPatternsResult, type ManifestEntity, type ManifestField, type ManifestRelationship, type ManifestSuggestion, MetadataPattern, type OrchestrationPatternDefinition, type OrchestrationProjectContext, type OrchestrationRegistrySpec, type OutputFormat, type ParsedEntity, type ParsedEvent, type ParsedField, type ParsedProviderSync, type ParsedQuery, type ParsedRelationship, type ParsedRelationshipDefinition, type ParsedSync, type ParsedTypeDirection, type PathHop, type PatternColumnContribution, type PatternDefinition, type PatternKind, type PatternProjectContext, type RelationshipEdge, type Severity, SyncedPattern, type TransitivePath, type TransitiveSuggestion, analyzeDomain, buildDomainGraph, checkConsistency, computeStatistics, defineOrchestrationPattern, definePattern, findCircularDependencies, findOrphanEntities, formatConsole, formatJson, formatMarkdown, formatMermaidGraph, getAllOrchestrationPatterns, getAllPatternNames, getAppPatternNames, getLibraryPatternNames, getOrchestrationPattern, getOrchestrationPatternNames, getPattern, getRelatedEntities, isDomainPattern, isOrchestrationPattern, isPatternDefinition, loadAppPatterns, loadEntities, loadEntityFromYaml, loadRelationshipFromYaml, loadRelationships, registerLibraryPattern, validateEntities, validateOrchestrationProject, validatePatternComposition, validatePatternProject };
4347
+ export { ActivityPattern, type AnalysisIssue, type AnalysisResult, type AnalyzeDomainOptions, type AnyPatternDefinition, BASE_JUNCTION_FIELD_NAMES, BaseJunctionFields, BasePattern, type CodegenManifest, type DomainGraph, type DomainStatistics, type EntityNode, type JunctionDefinition, JunctionDefinitionSchema, JunctionPattern, KnowledgePattern, type LoadAppPatternsResult, type ManifestEntity, type ManifestField, type ManifestRelationship, type ManifestSuggestion, MetadataPattern, type OrchestrationPatternDefinition, type OrchestrationProjectContext, type OrchestrationRegistrySpec, type OutputFormat, type ParsedEntity, type ParsedEvent, type ParsedField, type ParsedProviderSync, type ParsedQuery, type ParsedRelationship, type ParsedRelationshipDefinition, type ParsedSync, type ParsedTypeDirection, type PathHop, type PatternColumnContribution, type PatternDefinition, type PatternKind, type PatternProjectContext, type RelationshipEdge, type Severity, SyncedPattern, type TransitivePath, type TransitiveSuggestion, analyzeDomain, buildDomainGraph, checkConsistency, computeStatistics, defineOrchestrationPattern, definePattern, findCircularDependencies, findOrphanEntities, formatConsole, formatJson, formatMarkdown, formatMermaidGraph, getAllOrchestrationPatterns, getAllPatternNames, getAppPatternNames, getLibraryPatternNames, getOrchestrationPattern, getOrchestrationPatternNames, getPattern, getRelatedEntities, isDomainPattern, isOrchestrationPattern, isPatternDefinition, loadAppPatterns, loadEntities, loadEntityFromYaml, loadJunctionFromYaml, loadRelationshipFromYaml, loadRelationships, registerLibraryPattern, safeValidateJunctionDefinition, validateEntities, validateJunctionDefinition, validateOrchestrationProject, validatePatternComposition, validatePatternProject };
package/dist/src/index.js CHANGED
@@ -1754,6 +1754,90 @@ function deriveUniqueConstraint(config) {
1754
1754
  return columns;
1755
1755
  }
1756
1756
 
1757
+ // src/schema/junction-definition.schema.ts
1758
+ import { z as z6 } from "zod";
1759
+
1760
+ // src/patterns/library/base-junction-fields.ts
1761
+ var BaseJunctionFields = [
1762
+ { name: "is_primary", type: "boolean" },
1763
+ { name: "started_at", type: "timestamp" },
1764
+ { name: "ended_at", type: "timestamp" },
1765
+ { name: "sourced_from", type: "text" },
1766
+ { name: "confidence", type: "numeric(5,4)" },
1767
+ { name: "matched_at", type: "timestamp" }
1768
+ ];
1769
+ var BASE_JUNCTION_FIELD_NAMES = new Set(
1770
+ BaseJunctionFields.map((c) => c.name)
1771
+ );
1772
+
1773
+ // src/schema/junction-definition.schema.ts
1774
+ var EntityNameSchema = z6.string().regex(/^[a-z][a-z0-9_]*$/, "Entity reference must be snake_case");
1775
+ var JunctionDefinitionSchema = z6.object({
1776
+ /** Discriminator literal — `pattern: Junction`. */
1777
+ pattern: z6.literal("Junction"),
1778
+ /**
1779
+ * Exactly two endpoint entity names. Both intra- and cross-domain
1780
+ * pairings are accepted; entity existence is validated by the
1781
+ * analyzer in a later leaf.
1782
+ */
1783
+ between: z6.tuple([EntityNameSchema, EntityNameSchema]),
1784
+ /**
1785
+ * Emit BaseJunctionFields temporal columns (`started_at`, `ended_at`,
1786
+ * `matched_at`). Default true. Matches Relationship's `temporal` toggle.
1787
+ */
1788
+ temporal: z6.boolean().optional().default(true),
1789
+ /**
1790
+ * Emit BaseJunctionFields sourcing columns (`sourced_from`,
1791
+ * `confidence`). Default true. Matches Relationship's `sourced` toggle.
1792
+ */
1793
+ sourced: z6.boolean().optional().default(true),
1794
+ /**
1795
+ * Junction-specific fields beyond `BaseJunctionFields`. Includes the
1796
+ * per-pairing role enum (declared inline; never shared across
1797
+ * pairings). Shape is validated downstream by the codegen layer
1798
+ * using the existing entity FieldDefinitionSchema.
1799
+ */
1800
+ fields: z6.record(z6.string(), z6.any()).optional(),
1801
+ /**
1802
+ * Declarative queries — same syntax as entity queries. Shape is
1803
+ * validated downstream by the codegen layer.
1804
+ */
1805
+ queries: z6.array(z6.any()).optional(),
1806
+ /**
1807
+ * Per-side opt-out for parent-service fan-out (CGP-60). When a side
1808
+ * is `false`, the `_inject-parent-service-*` templates emit nothing
1809
+ * on that side (and the corresponding module wiring is skipped).
1810
+ * The junction service body is always emitted regardless. Defaults
1811
+ * to `{ left: true, right: true }`.
1812
+ */
1813
+ expose_on_parent: z6.object({
1814
+ left: z6.boolean().optional().default(true),
1815
+ right: z6.boolean().optional().default(true)
1816
+ }).optional().default({ left: true, right: true })
1817
+ }).strict().refine((d) => d.between[0] !== d.between[1], {
1818
+ message: "`between` endpoints must be distinct",
1819
+ path: ["between"]
1820
+ }).refine(
1821
+ (d) => {
1822
+ const fieldNames = Object.keys(d.fields ?? {});
1823
+ return !fieldNames.some((n) => BASE_JUNCTION_FIELD_NAMES.has(n));
1824
+ },
1825
+ {
1826
+ message: "`fields:` block redeclares a reserved BaseJunctionFields column (is_primary, started_at, ended_at, sourced_from, confidence, matched_at)",
1827
+ path: ["fields"]
1828
+ }
1829
+ );
1830
+ function validateJunctionDefinition(data) {
1831
+ return JunctionDefinitionSchema.parse(data);
1832
+ }
1833
+ function safeValidateJunctionDefinition(data) {
1834
+ const result = JunctionDefinitionSchema.safeParse(data);
1835
+ if (result.success) {
1836
+ return { success: true, data: result.data };
1837
+ }
1838
+ return { success: false, error: result.error };
1839
+ }
1840
+
1757
1841
  // src/utils/yaml-loader.ts
1758
1842
  function loadEntityFromYaml(filePath) {
1759
1843
  if (!existsSync(filePath)) {
@@ -1852,6 +1936,51 @@ function loadRelationshipFromYaml(filePath) {
1852
1936
  filePath
1853
1937
  };
1854
1938
  }
1939
+ function loadJunctionFromYaml(filePath) {
1940
+ if (!existsSync(filePath)) {
1941
+ return {
1942
+ success: false,
1943
+ error: `File not found: ${filePath}`,
1944
+ filePath
1945
+ };
1946
+ }
1947
+ let content;
1948
+ try {
1949
+ content = readFileSync(filePath, "utf-8");
1950
+ } catch (err) {
1951
+ return {
1952
+ success: false,
1953
+ error: `Failed to read file: ${filePath}`,
1954
+ details: [err instanceof Error ? err.message : String(err)],
1955
+ filePath
1956
+ };
1957
+ }
1958
+ let parsed;
1959
+ try {
1960
+ parsed = parseYaml(content);
1961
+ } catch (err) {
1962
+ return {
1963
+ success: false,
1964
+ error: `Invalid YAML syntax in ${filePath}`,
1965
+ details: [err instanceof Error ? err.message : String(err)],
1966
+ filePath
1967
+ };
1968
+ }
1969
+ const result = JunctionDefinitionSchema.safeParse(parsed);
1970
+ if (!result.success) {
1971
+ return {
1972
+ success: false,
1973
+ error: `Validation failed for ${filePath}`,
1974
+ details: formatZodErrors(result.error),
1975
+ filePath
1976
+ };
1977
+ }
1978
+ return {
1979
+ success: true,
1980
+ definition: result.data,
1981
+ filePath
1982
+ };
1983
+ }
1855
1984
 
1856
1985
  // src/parser/load-entities.ts
1857
1986
  function transformToEntity(result) {
@@ -3754,6 +3883,16 @@ var BasePattern = definePattern({
3754
3883
  description: "Identity pattern \u2014 base CRUD, no extra columns or methods"
3755
3884
  });
3756
3885
 
3886
+ // src/patterns/library/junction.pattern.ts
3887
+ import { z as z7 } from "zod";
3888
+ var JunctionPatternConfigSchema = z7.object({}).strict();
3889
+ var JunctionPattern = definePattern({
3890
+ name: "Junction",
3891
+ description: "Explicit many-to-many junction with role + temporal + sourcing metadata",
3892
+ columns: [...BaseJunctionFields],
3893
+ configSchema: JunctionPatternConfigSchema
3894
+ });
3895
+
3757
3896
  // src/patterns/library/knowledge.pattern.ts
3758
3897
  var KnowledgePattern = definePattern({
3759
3898
  name: "Knowledge",
@@ -3818,6 +3957,7 @@ registerLibraryPattern(SyncedPattern);
3818
3957
  registerLibraryPattern(ActivityPattern);
3819
3958
  registerLibraryPattern(KnowledgePattern);
3820
3959
  registerLibraryPattern(MetadataPattern);
3960
+ registerLibraryPattern(JunctionPattern);
3821
3961
 
3822
3962
  // src/index.ts
3823
3963
  async function analyzeDomain(entitiesDir, relationshipsOrOptions) {
@@ -3872,7 +4012,11 @@ function validateEntities(entitiesDir) {
3872
4012
  }
3873
4013
  export {
3874
4014
  ActivityPattern,
4015
+ BASE_JUNCTION_FIELD_NAMES,
4016
+ BaseJunctionFields,
3875
4017
  BasePattern,
4018
+ JunctionDefinitionSchema,
4019
+ JunctionPattern,
3876
4020
  KnowledgePattern,
3877
4021
  MetadataPattern,
3878
4022
  SyncedPattern,
@@ -3902,10 +4046,13 @@ export {
3902
4046
  loadAppPatterns,
3903
4047
  loadEntities,
3904
4048
  loadEntityFromYaml,
4049
+ loadJunctionFromYaml,
3905
4050
  loadRelationshipFromYaml,
3906
4051
  loadRelationships,
3907
4052
  registerLibraryPattern,
4053
+ safeValidateJunctionDefinition,
3908
4054
  validateEntities,
4055
+ validateJunctionDefinition,
3909
4056
  validateOrchestrationProject,
3910
4057
  validatePatternComposition,
3911
4058
  validatePatternProject