@living-architecture/riviere-cli 0.9.3 → 0.9.5

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/bin.js +167 -81
  2. package/dist/index.js +166 -80
  3. package/package.json +6 -6
package/dist/bin.js CHANGED
@@ -6886,6 +6886,10 @@ var BuildValidationError = class extends Error {
6886
6886
  }
6887
6887
  };
6888
6888
 
6889
+ // ../riviere-schema/dist/schema.js
6890
+ var EVENT_NAME_FIELD = "eventName";
6891
+ var SUBSCRIBED_EVENTS_FIELD = "subscribedEvents";
6892
+
6889
6893
  // ../riviere-schema/dist/validation.js
6890
6894
  var import_ajv = __toESM(require_ajv(), 1);
6891
6895
  var import_ajv_formats = __toESM(require_dist(), 1);
@@ -25532,7 +25536,6 @@ var COMPONENT_TYPES = [
25532
25536
  "domainOp",
25533
25537
  "event",
25534
25538
  "eventHandler",
25535
- "eventPublisher",
25536
25539
  "ui"
25537
25540
  ];
25538
25541
  function extractComponents(project, sourceFilePaths, config2, globMatcher, configDir) {
@@ -25691,7 +25694,6 @@ function resolveModule(moduleConfig, loader) {
25691
25694
  domainOp: requireRule(moduleConfig.domainOp, "domainOp", moduleConfig.name),
25692
25695
  event: requireRule(moduleConfig.event, "event", moduleConfig.name),
25693
25696
  eventHandler: requireRule(moduleConfig.eventHandler, "eventHandler", moduleConfig.name),
25694
- eventPublisher: requireRule(moduleConfig.eventPublisher, "eventPublisher", moduleConfig.name),
25695
25697
  ui: requireRule(moduleConfig.ui, "ui", moduleConfig.name),
25696
25698
  ...moduleConfig.customTypes !== void 0 && { customTypes: moduleConfig.customTypes }
25697
25699
  };
@@ -25711,7 +25713,6 @@ function resolveModuleWithExtends(moduleConfig, extendsSource, loader) {
25711
25713
  domainOp: moduleConfig.domainOp ?? baseModule.domainOp,
25712
25714
  event: moduleConfig.event ?? baseModule.event,
25713
25715
  eventHandler: moduleConfig.eventHandler ?? baseModule.eventHandler,
25714
- eventPublisher: moduleConfig.eventPublisher ?? baseModule.eventPublisher,
25715
25716
  ui: moduleConfig.ui ?? baseModule.ui,
25716
25717
  ...mergedCustomTypes !== void 0 && { customTypes: mergedCustomTypes }
25717
25718
  };
@@ -28171,90 +28172,104 @@ function traceNonComponent(project, componentIndex, source, typeName, calledMeth
28171
28172
  }
28172
28173
  }
28173
28174
 
28174
- // ../riviere-extract-ts/dist/features/extraction/domain/connection-detection/async-detection/detect-publish-connections.js
28175
- function detectPublishConnections(components, options) {
28176
- const publishers = components.filter((c) => c.type === "eventPublisher");
28175
+ // ../riviere-extract-ts/dist/features/extraction/domain/connection-detection/async-detection/async-detection-types.js
28176
+ function toSourceLocation(component, repository) {
28177
+ return {
28178
+ repository,
28179
+ filePath: component.location.file,
28180
+ lineNumber: component.location.line
28181
+ };
28182
+ }
28183
+
28184
+ // ../riviere-extract-ts/dist/features/extraction/domain/connection-detection/async-detection/detect-event-publisher-connections.js
28185
+ function detectEventPublisherConnections(components, eventPublishers, options) {
28186
+ if (eventPublishers.length === 0) {
28187
+ return [];
28188
+ }
28177
28189
  const events = components.filter((c) => c.type === "event");
28178
- const repository = options.repository;
28179
- return publishers.flatMap((publisher) => {
28180
- const publishedEventType = publisher.metadata["publishedEventType"];
28181
- const sourceLocation = {
28182
- repository,
28183
- filePath: publisher.location.file,
28184
- lineNumber: publisher.location.line
28185
- };
28186
- if (typeof publishedEventType !== "string") {
28187
- return [handleMissingMetadata(publisher, options, sourceLocation)];
28188
- }
28189
- return resolvePublishTarget(publisher, publishedEventType, events, options, sourceLocation);
28190
+ return eventPublishers.flatMap((publisherConfig) => {
28191
+ const { fromType, metadataKey } = publisherConfig;
28192
+ const publishers = components.filter((c) => c.type === fromType);
28193
+ return publishers.flatMap((publisher) => {
28194
+ const publishedEventType = publisher.metadata[metadataKey];
28195
+ if (Array.isArray(publishedEventType)) {
28196
+ const validTypes = publishedEventType.filter((t) => typeof t === "string" && t.trim() !== "");
28197
+ if (validTypes.length === 0) {
28198
+ return [handleMissingMetadata(publisher, metadataKey, options)];
28199
+ }
28200
+ return validTypes.flatMap((t) => resolvePublishTarget(publisher, t, events, options));
28201
+ }
28202
+ if (typeof publishedEventType !== "string" || publishedEventType.trim() === "") {
28203
+ return [handleMissingMetadata(publisher, metadataKey, options)];
28204
+ }
28205
+ return resolvePublishTarget(publisher, publishedEventType, events, options);
28206
+ });
28190
28207
  });
28191
28208
  }
28192
- function handleMissingMetadata(publisher, options, sourceLocation) {
28209
+ function handleMissingMetadata(publisher, metadataKey, options) {
28193
28210
  if (options.strict) {
28194
28211
  throw new ConnectionDetectionError({
28195
- file: sourceLocation.filePath,
28196
- line: sourceLocation.lineNumber,
28212
+ file: publisher.location.file,
28213
+ line: publisher.location.line,
28197
28214
  typeName: publisher.name,
28198
- reason: 'eventPublisher is missing required "publishedEventType" metadata'
28215
+ reason: `published event type in "${metadataKey}" metadata is missing or invalid`
28199
28216
  });
28200
28217
  }
28201
28218
  return {
28202
28219
  source: componentIdentity(publisher),
28203
28220
  target: "_unresolved",
28204
28221
  type: "async",
28205
- sourceLocation,
28206
- _uncertain: `eventPublisher "${publisher.name}" is missing required "publishedEventType" metadata`
28222
+ sourceLocation: toSourceLocation(publisher, options.repository),
28223
+ _uncertain: `event publisher "${publisher.name}" is missing required "${metadataKey}" metadata`
28207
28224
  };
28208
28225
  }
28209
- function resolvePublishTarget(publisher, publishedEventType, events, options, sourceLocation) {
28210
- const matchingEvents = events.filter((e) => e.metadata["eventName"] === publishedEventType);
28226
+ function resolvePublishTarget(publisher, publishedEventType, events, options) {
28227
+ const matchingEvents = events.filter((e) => e.metadata[EVENT_NAME_FIELD] === publishedEventType);
28211
28228
  if (matchingEvents.length === 0) {
28212
- return [handleNoMatch(publisher, publishedEventType, options, sourceLocation)];
28229
+ return [handleNoMatch(publisher, publishedEventType, options)];
28213
28230
  }
28214
28231
  if (matchingEvents.length > 1) {
28215
- return [
28216
- handleAmbiguousMatch(publisher, publishedEventType, matchingEvents.length, options, sourceLocation)
28217
- ];
28232
+ return [handleAmbiguousMatch(publisher, publishedEventType, matchingEvents.length, options)];
28218
28233
  }
28219
28234
  return matchingEvents.map((event) => ({
28220
28235
  source: componentIdentity(publisher),
28221
28236
  target: componentIdentity(event),
28222
28237
  type: "async",
28223
- sourceLocation
28238
+ sourceLocation: toSourceLocation(publisher, options.repository)
28224
28239
  }));
28225
28240
  }
28226
- function handleAmbiguousMatch(publisher, publishedEventType, matchCount, options, sourceLocation) {
28241
+ function handleAmbiguousMatch(publisher, publishedEventType, matchCount, options) {
28227
28242
  if (options.strict) {
28228
28243
  throw new ConnectionDetectionError({
28229
- file: sourceLocation.filePath,
28230
- line: sourceLocation.lineNumber,
28244
+ file: publisher.location.file,
28245
+ line: publisher.location.line,
28231
28246
  typeName: publisher.name,
28232
- reason: `publishedEventType "${publishedEventType}" matches ${matchCount} Event components (ambiguous)`
28247
+ reason: `published event "${publishedEventType}" matches ${matchCount} Event components (ambiguous)`
28233
28248
  });
28234
28249
  }
28235
28250
  return {
28236
28251
  source: componentIdentity(publisher),
28237
28252
  target: "_unresolved",
28238
28253
  type: "async",
28239
- sourceLocation,
28240
- _uncertain: `ambiguous: ${matchCount} events match publishedEventType: ${publishedEventType}`
28254
+ sourceLocation: toSourceLocation(publisher, options.repository),
28255
+ _uncertain: `ambiguous: ${matchCount} events match published event type: ${publishedEventType}`
28241
28256
  };
28242
28257
  }
28243
- function handleNoMatch(publisher, publishedEventType, options, sourceLocation) {
28258
+ function handleNoMatch(publisher, publishedEventType, options) {
28244
28259
  if (options.strict) {
28245
28260
  throw new ConnectionDetectionError({
28246
- file: sourceLocation.filePath,
28247
- line: sourceLocation.lineNumber,
28261
+ file: publisher.location.file,
28262
+ line: publisher.location.line,
28248
28263
  typeName: publisher.name,
28249
- reason: `publishedEventType "${publishedEventType}" does not match any Event component`
28264
+ reason: `published event "${publishedEventType}" does not match any Event component`
28250
28265
  });
28251
28266
  }
28252
28267
  return {
28253
28268
  source: componentIdentity(publisher),
28254
28269
  target: "_unresolved",
28255
28270
  type: "async",
28256
- sourceLocation,
28257
- _uncertain: `no event found for publishedEventType: ${publishedEventType}`
28271
+ sourceLocation: toSourceLocation(publisher, options.repository),
28272
+ _uncertain: `no event found for published event type: ${publishedEventType}`
28258
28273
  };
28259
28274
  }
28260
28275
 
@@ -28265,15 +28280,8 @@ function detectSubscribeConnections(components, options) {
28265
28280
  const repository = options.repository;
28266
28281
  return eventHandlers.flatMap((handler) => getSubscribedEvents(handler).flatMap((eventName) => resolveSubscription(handler, eventName, events, options, repository)));
28267
28282
  }
28268
- function toSourceLocation(component, repository) {
28269
- return {
28270
- repository,
28271
- filePath: component.location.file,
28272
- lineNumber: component.location.line
28273
- };
28274
- }
28275
28283
  function resolveSubscription(handler, eventName, events, options, repository) {
28276
- const matchingEvents = events.filter((e) => e.metadata["eventName"] === eventName);
28284
+ const matchingEvents = events.filter((e) => e.metadata[EVENT_NAME_FIELD] === eventName);
28277
28285
  if (matchingEvents.length === 0) {
28278
28286
  return [handleNoMatch2(handler, eventName, options, repository)];
28279
28287
  }
@@ -28322,7 +28330,7 @@ function handleNoMatch2(handler, eventName, options, repository) {
28322
28330
  };
28323
28331
  }
28324
28332
  function getSubscribedEvents(handler) {
28325
- const raw = handler.metadata["subscribedEvents"];
28333
+ const raw = handler.metadata[SUBSCRIBED_EVENTS_FIELD];
28326
28334
  if (!Array.isArray(raw)) {
28327
28335
  return [];
28328
28336
  }
@@ -28591,15 +28599,13 @@ function detectPerModuleConnections(project, components, options, globMatcher) {
28591
28599
  function detectCrossModuleConnections(allComponents, options) {
28592
28600
  const strict = options.allowIncomplete !== true;
28593
28601
  const repository = options.repository;
28594
- const asyncStart = performance.now();
28595
- const publishLinks = detectPublishConnections(allComponents, {
28596
- strict,
28597
- repository
28598
- });
28599
- const subscribeLinks = detectSubscribeConnections(allComponents, {
28602
+ const asyncOptions = {
28600
28603
  strict,
28601
28604
  repository
28602
- });
28605
+ };
28606
+ const asyncStart = performance.now();
28607
+ const publishLinks = detectEventPublisherConnections(allComponents, options.eventPublishers ?? [], asyncOptions);
28608
+ const subscribeLinks = detectSubscribeConnections(allComponents, asyncOptions);
28603
28609
  const asyncDetectionMs = performance.now() - asyncStart;
28604
28610
  return {
28605
28611
  links: [...publishLinks, ...subscribeLinks],
@@ -28638,7 +28644,6 @@ function getBuiltInRule(module, componentType) {
28638
28644
  domainOp: module.domainOp,
28639
28645
  event: module.event,
28640
28646
  eventHandler: module.eventHandler,
28641
- eventPublisher: module.eventPublisher,
28642
28647
  ui: module.ui
28643
28648
  };
28644
28649
  const rule = ruleMap[componentType];
@@ -28654,7 +28659,6 @@ function findDetectionRule(module, componentType) {
28654
28659
  "domainOp",
28655
28660
  "event",
28656
28661
  "eventHandler",
28657
- "eventPublisher",
28658
28662
  "ui"
28659
28663
  ];
28660
28664
  if (builtInTypes.includes(componentType)) {
@@ -28705,10 +28709,7 @@ function evaluateClassRule(rule, classDecl) {
28705
28709
  if ("fromClassName" in rule) {
28706
28710
  return evaluateFromClassNameRule(rule, classDecl);
28707
28711
  }
28708
- if (!("fromProperty" in rule)) {
28709
- throw new ExtractionError("Unsupported extraction rule type for class-based component", classDecl.getSourceFile().getFilePath(), classDecl.getStartLineNumber());
28710
- }
28711
- return evaluateFromPropertyRule(rule, classDecl);
28712
+ throw new ExtractionError("Unsupported extraction rule type for class-based component", classDecl.getSourceFile().getFilePath(), classDecl.getStartLineNumber());
28712
28713
  }
28713
28714
  function evaluateRule2(rule, draft, project) {
28714
28715
  if ("literal" in rule) {
@@ -28725,6 +28726,10 @@ function evaluateRule2(rule, draft, project) {
28725
28726
  const classDecl2 = findContainingClass(project, draft);
28726
28727
  return evaluateFromGenericArgRule(rule, classDecl2);
28727
28728
  }
28729
+ if ("fromProperty" in rule) {
28730
+ const classDecl2 = findContainingClass(project, draft);
28731
+ return evaluateFromPropertyRule(rule, classDecl2);
28732
+ }
28728
28733
  if ("fromParameterType" in rule) {
28729
28734
  const methodDecl = findMethodAtLine(project, draft);
28730
28735
  const params = methodDecl.getParameters();
@@ -28905,10 +28910,6 @@ var extraction_config_schema_default = {
28905
28910
  $ref: "#/$defs/componentRule",
28906
28911
  description: "Detection rule for EventHandler components"
28907
28912
  },
28908
- eventPublisher: {
28909
- $ref: "#/$defs/componentRule",
28910
- description: "Detection rule for EventPublisher components"
28911
- },
28912
28913
  ui: {
28913
28914
  $ref: "#/$defs/componentRule",
28914
28915
  description: "Detection rule for UI components"
@@ -28921,7 +28922,7 @@ var extraction_config_schema_default = {
28921
28922
  }
28922
28923
  },
28923
28924
  connections: {
28924
- $ref: "#/$defs/connectionsConfig",
28925
+ $ref: "#/$defs/moduleConnectionsConfig",
28925
28926
  description: "Module-level connection detection patterns additive to global"
28926
28927
  }
28927
28928
  },
@@ -28931,7 +28932,7 @@ var extraction_config_schema_default = {
28931
28932
  }
28932
28933
  },
28933
28934
  then: {
28934
- required: ["api", "useCase", "domainOp", "event", "eventHandler", "eventPublisher", "ui"]
28935
+ required: ["api", "useCase", "domainOp", "event", "eventHandler", "ui"]
28935
28936
  }
28936
28937
  },
28937
28938
  componentRule: {
@@ -29425,7 +29426,6 @@ var extraction_config_schema_default = {
29425
29426
  connectionsConfig: {
29426
29427
  type: "object",
29427
29428
  description: "Connection detection configuration with pattern definitions",
29428
- required: ["patterns"],
29429
29429
  additionalProperties: false,
29430
29430
  properties: {
29431
29431
  patterns: {
@@ -29435,6 +29435,47 @@ var extraction_config_schema_default = {
29435
29435
  items: {
29436
29436
  $ref: "#/$defs/connectionPattern"
29437
29437
  }
29438
+ },
29439
+ eventPublishers: {
29440
+ type: "array",
29441
+ description: "Declares which custom component types publish events and how to detect the connections",
29442
+ minItems: 1,
29443
+ items: {
29444
+ $ref: "#/$defs/eventPublisherConfig"
29445
+ }
29446
+ }
29447
+ }
29448
+ },
29449
+ moduleConnectionsConfig: {
29450
+ type: "object",
29451
+ description: "Module-level connection detection configuration (patterns only \u2014 eventPublishers is top-level only)",
29452
+ additionalProperties: false,
29453
+ properties: {
29454
+ patterns: {
29455
+ type: "array",
29456
+ description: "Connection detection patterns",
29457
+ minItems: 1,
29458
+ items: {
29459
+ $ref: "#/$defs/connectionPattern"
29460
+ }
29461
+ }
29462
+ }
29463
+ },
29464
+ eventPublisherConfig: {
29465
+ type: "object",
29466
+ description: "Declares a custom component type as an event publisher",
29467
+ required: ["fromType", "metadataKey"],
29468
+ additionalProperties: false,
29469
+ properties: {
29470
+ fromType: {
29471
+ type: "string",
29472
+ description: "The custom component type name \u2014 must be defined in customTypes in at least one module",
29473
+ minLength: 1
29474
+ },
29475
+ metadataKey: {
29476
+ type: "string",
29477
+ description: "The metadata key on this component type that holds the published event type name",
29478
+ minLength: 1
29438
29479
  }
29439
29480
  }
29440
29481
  },
@@ -29570,7 +29611,6 @@ var REQUIRED_FIELDS = {
29570
29611
  api: ["apiType"],
29571
29612
  event: ["eventName"],
29572
29613
  eventHandler: ["subscribedEvents"],
29573
- eventPublisher: [],
29574
29614
  domainOp: ["operationName"],
29575
29615
  ui: ["route"],
29576
29616
  useCase: []
@@ -29581,7 +29621,6 @@ var COMPONENT_TYPES2 = [
29581
29621
  "domainOp",
29582
29622
  "event",
29583
29623
  "eventHandler",
29584
- "eventPublisher",
29585
29624
  "ui"
29586
29625
  ];
29587
29626
  var ajv2 = new import_ajv2.default({ allErrors: true });
@@ -29660,6 +29699,54 @@ function validateAllExtractionRules(config2) {
29660
29699
  return validateModuleExtractionRules(module, index);
29661
29700
  });
29662
29701
  }
29702
+ function collectCustomTypeExtractedFields(config2) {
29703
+ const fieldsByType = /* @__PURE__ */ new Map();
29704
+ for (const module of config2.modules) {
29705
+ if ("$ref" in module || module.customTypes === void 0) {
29706
+ continue;
29707
+ }
29708
+ for (const [typeName, rule] of Object.entries(module.customTypes)) {
29709
+ const existing = fieldsByType.get(typeName) ?? /* @__PURE__ */ new Set();
29710
+ for (const key of Object.keys(rule.extract ?? {})) {
29711
+ existing.add(key);
29712
+ }
29713
+ fieldsByType.set(typeName, existing);
29714
+ }
29715
+ }
29716
+ return fieldsByType;
29717
+ }
29718
+ function validateEventPublishers(connections, customTypeFields) {
29719
+ if (connections.eventPublishers === void 0) {
29720
+ return [];
29721
+ }
29722
+ return connections.eventPublishers.flatMap((publisher, index) => {
29723
+ const extractedFields = customTypeFields.get(publisher.fromType);
29724
+ if (extractedFields === void 0) {
29725
+ return [
29726
+ {
29727
+ path: `/connections/eventPublishers/${index}/fromType`,
29728
+ message: `"${publisher.fromType}" is not defined as a customType in any module. Add a customType named "${publisher.fromType}" to at least one module.`
29729
+ }
29730
+ ];
29731
+ }
29732
+ if (!extractedFields.has(publisher.metadataKey)) {
29733
+ return [
29734
+ {
29735
+ path: `/connections/eventPublishers/${index}/fromType`,
29736
+ message: `customType "${publisher.fromType}" does not extract "${publisher.metadataKey}". Add extract["${publisher.metadataKey}"] to that custom type.`
29737
+ }
29738
+ ];
29739
+ }
29740
+ return [];
29741
+ });
29742
+ }
29743
+ function validateConnectionsConfig(config2) {
29744
+ if (config2.connections === void 0) {
29745
+ return [];
29746
+ }
29747
+ const customTypeFields = collectCustomTypeExtractedFields(config2);
29748
+ return validateEventPublishers(config2.connections, customTypeFields);
29749
+ }
29663
29750
  function validateExtractionConfigSchema(data) {
29664
29751
  const schemaValid = validate2(data) === true;
29665
29752
  if (!schemaValid) {
@@ -29677,7 +29764,7 @@ function validateExtractionConfig(data) {
29677
29764
  if (!isValidExtractionConfig(data)) {
29678
29765
  return validateExtractionConfigSchema(data);
29679
29766
  }
29680
- const semanticErrors = validateAllExtractionRules(data);
29767
+ const semanticErrors = [...validateAllExtractionRules(data), ...validateConnectionsConfig(data)];
29681
29768
  if (semanticErrors.length > 0) {
29682
29769
  return {
29683
29770
  valid: false,
@@ -29693,10 +29780,10 @@ function formatValidationErrors2(errors) {
29693
29780
  return formatValidationErrorsInternal2(errors);
29694
29781
  }
29695
29782
  function parseExtractionConfig(data) {
29696
- if (isValidExtractionConfig(data)) {
29783
+ const result = validateExtractionConfig(data);
29784
+ if (result.valid && isValidExtractionConfig(data)) {
29697
29785
  return data;
29698
29786
  }
29699
- const result = validateExtractionConfig(data);
29700
29787
  throw new ExtractionConfigValidationError(result.errors);
29701
29788
  }
29702
29789
 
@@ -30049,7 +30136,8 @@ var ExtractionProject = class {
30049
30136
  }
30050
30137
  const crossResult = detectCrossModuleConnections(enrichedComponents, {
30051
30138
  allowIncomplete,
30052
- repository: this.repositoryName
30139
+ repository: this.repositoryName,
30140
+ eventPublishers: this.resolvedConfig.connections?.eventPublishers
30053
30141
  });
30054
30142
  links.push(...crossResult.links);
30055
30143
  timings.push({
@@ -30355,7 +30443,6 @@ ${formatValidationErrors2(validationResult.errors)}`
30355
30443
  domainOp: parsed.domainOp ?? NOT_USED,
30356
30444
  event: parsed.event ?? NOT_USED,
30357
30445
  eventHandler: parsed.eventHandler ?? NOT_USED,
30358
- eventPublisher: parsed.eventPublisher ?? NOT_USED,
30359
30446
  ui: parsed.ui ?? NOT_USED
30360
30447
  };
30361
30448
  }
@@ -31120,7 +31207,7 @@ function parsePackageJson(pkg) {
31120
31207
  }
31121
31208
  function loadPackageJson() {
31122
31209
  if (true) {
31123
- return { version: "0.9.2" };
31210
+ return { version: "0.9.4" };
31124
31211
  }
31125
31212
  const require2 = createRequire2(import.meta.url);
31126
31213
  return parsePackageJson(require2("../../package.json"));
@@ -31214,7 +31301,6 @@ program.parseAsync().catch(handleGlobalError);
31214
31301
  /* istanbul ignore else -- @preserve: false branch is unreachable; FindTarget is exhaustive */
31215
31302
  /* istanbul ignore next -- @preserve: unreachable with valid FindTarget type; defensive fallback */
31216
31303
  /* v8 ignore next -- @preserve: getExtends() !== undefined guarantees getBaseClass() returns a value */
31217
- /* istanbul ignore next -- @preserve: only fromProperty reaches here; defensive guard */
31218
31304
  /* istanbul ignore next -- @preserve: catch always receives Error instances from ExtractionError */
31219
31305
  /* v8 ignore start -- @preserve: default executor delegates to execFileSync; tested via CLI integration */
31220
31306
  /* v8 ignore next -- @preserve: defensive optional chain; property existence guaranteed by hasOwn check above */
package/dist/index.js CHANGED
@@ -6885,6 +6885,10 @@ var BuildValidationError = class extends Error {
6885
6885
  }
6886
6886
  };
6887
6887
 
6888
+ // ../riviere-schema/dist/schema.js
6889
+ var EVENT_NAME_FIELD = "eventName";
6890
+ var SUBSCRIBED_EVENTS_FIELD = "subscribedEvents";
6891
+
6888
6892
  // ../riviere-schema/dist/validation.js
6889
6893
  var import_ajv = __toESM(require_ajv(), 1);
6890
6894
  var import_ajv_formats = __toESM(require_dist(), 1);
@@ -25556,7 +25560,6 @@ var COMPONENT_TYPES = [
25556
25560
  "domainOp",
25557
25561
  "event",
25558
25562
  "eventHandler",
25559
- "eventPublisher",
25560
25563
  "ui"
25561
25564
  ];
25562
25565
  function extractComponents(project, sourceFilePaths, config2, globMatcher, configDir) {
@@ -25715,7 +25718,6 @@ function resolveModule(moduleConfig, loader) {
25715
25718
  domainOp: requireRule(moduleConfig.domainOp, "domainOp", moduleConfig.name),
25716
25719
  event: requireRule(moduleConfig.event, "event", moduleConfig.name),
25717
25720
  eventHandler: requireRule(moduleConfig.eventHandler, "eventHandler", moduleConfig.name),
25718
- eventPublisher: requireRule(moduleConfig.eventPublisher, "eventPublisher", moduleConfig.name),
25719
25721
  ui: requireRule(moduleConfig.ui, "ui", moduleConfig.name),
25720
25722
  ...moduleConfig.customTypes !== void 0 && { customTypes: moduleConfig.customTypes }
25721
25723
  };
@@ -25735,7 +25737,6 @@ function resolveModuleWithExtends(moduleConfig, extendsSource, loader) {
25735
25737
  domainOp: moduleConfig.domainOp ?? baseModule.domainOp,
25736
25738
  event: moduleConfig.event ?? baseModule.event,
25737
25739
  eventHandler: moduleConfig.eventHandler ?? baseModule.eventHandler,
25738
- eventPublisher: moduleConfig.eventPublisher ?? baseModule.eventPublisher,
25739
25740
  ui: moduleConfig.ui ?? baseModule.ui,
25740
25741
  ...mergedCustomTypes !== void 0 && { customTypes: mergedCustomTypes }
25741
25742
  };
@@ -28195,90 +28196,104 @@ function traceNonComponent(project, componentIndex, source, typeName, calledMeth
28195
28196
  }
28196
28197
  }
28197
28198
 
28198
- // ../riviere-extract-ts/dist/features/extraction/domain/connection-detection/async-detection/detect-publish-connections.js
28199
- function detectPublishConnections(components, options) {
28200
- const publishers = components.filter((c) => c.type === "eventPublisher");
28199
+ // ../riviere-extract-ts/dist/features/extraction/domain/connection-detection/async-detection/async-detection-types.js
28200
+ function toSourceLocation(component, repository) {
28201
+ return {
28202
+ repository,
28203
+ filePath: component.location.file,
28204
+ lineNumber: component.location.line
28205
+ };
28206
+ }
28207
+
28208
+ // ../riviere-extract-ts/dist/features/extraction/domain/connection-detection/async-detection/detect-event-publisher-connections.js
28209
+ function detectEventPublisherConnections(components, eventPublishers, options) {
28210
+ if (eventPublishers.length === 0) {
28211
+ return [];
28212
+ }
28201
28213
  const events = components.filter((c) => c.type === "event");
28202
- const repository = options.repository;
28203
- return publishers.flatMap((publisher) => {
28204
- const publishedEventType = publisher.metadata["publishedEventType"];
28205
- const sourceLocation = {
28206
- repository,
28207
- filePath: publisher.location.file,
28208
- lineNumber: publisher.location.line
28209
- };
28210
- if (typeof publishedEventType !== "string") {
28211
- return [handleMissingMetadata(publisher, options, sourceLocation)];
28212
- }
28213
- return resolvePublishTarget(publisher, publishedEventType, events, options, sourceLocation);
28214
+ return eventPublishers.flatMap((publisherConfig) => {
28215
+ const { fromType, metadataKey } = publisherConfig;
28216
+ const publishers = components.filter((c) => c.type === fromType);
28217
+ return publishers.flatMap((publisher) => {
28218
+ const publishedEventType = publisher.metadata[metadataKey];
28219
+ if (Array.isArray(publishedEventType)) {
28220
+ const validTypes = publishedEventType.filter((t) => typeof t === "string" && t.trim() !== "");
28221
+ if (validTypes.length === 0) {
28222
+ return [handleMissingMetadata(publisher, metadataKey, options)];
28223
+ }
28224
+ return validTypes.flatMap((t) => resolvePublishTarget(publisher, t, events, options));
28225
+ }
28226
+ if (typeof publishedEventType !== "string" || publishedEventType.trim() === "") {
28227
+ return [handleMissingMetadata(publisher, metadataKey, options)];
28228
+ }
28229
+ return resolvePublishTarget(publisher, publishedEventType, events, options);
28230
+ });
28214
28231
  });
28215
28232
  }
28216
- function handleMissingMetadata(publisher, options, sourceLocation) {
28233
+ function handleMissingMetadata(publisher, metadataKey, options) {
28217
28234
  if (options.strict) {
28218
28235
  throw new ConnectionDetectionError({
28219
- file: sourceLocation.filePath,
28220
- line: sourceLocation.lineNumber,
28236
+ file: publisher.location.file,
28237
+ line: publisher.location.line,
28221
28238
  typeName: publisher.name,
28222
- reason: 'eventPublisher is missing required "publishedEventType" metadata'
28239
+ reason: `published event type in "${metadataKey}" metadata is missing or invalid`
28223
28240
  });
28224
28241
  }
28225
28242
  return {
28226
28243
  source: componentIdentity(publisher),
28227
28244
  target: "_unresolved",
28228
28245
  type: "async",
28229
- sourceLocation,
28230
- _uncertain: `eventPublisher "${publisher.name}" is missing required "publishedEventType" metadata`
28246
+ sourceLocation: toSourceLocation(publisher, options.repository),
28247
+ _uncertain: `event publisher "${publisher.name}" is missing required "${metadataKey}" metadata`
28231
28248
  };
28232
28249
  }
28233
- function resolvePublishTarget(publisher, publishedEventType, events, options, sourceLocation) {
28234
- const matchingEvents = events.filter((e) => e.metadata["eventName"] === publishedEventType);
28250
+ function resolvePublishTarget(publisher, publishedEventType, events, options) {
28251
+ const matchingEvents = events.filter((e) => e.metadata[EVENT_NAME_FIELD] === publishedEventType);
28235
28252
  if (matchingEvents.length === 0) {
28236
- return [handleNoMatch(publisher, publishedEventType, options, sourceLocation)];
28253
+ return [handleNoMatch(publisher, publishedEventType, options)];
28237
28254
  }
28238
28255
  if (matchingEvents.length > 1) {
28239
- return [
28240
- handleAmbiguousMatch(publisher, publishedEventType, matchingEvents.length, options, sourceLocation)
28241
- ];
28256
+ return [handleAmbiguousMatch(publisher, publishedEventType, matchingEvents.length, options)];
28242
28257
  }
28243
28258
  return matchingEvents.map((event) => ({
28244
28259
  source: componentIdentity(publisher),
28245
28260
  target: componentIdentity(event),
28246
28261
  type: "async",
28247
- sourceLocation
28262
+ sourceLocation: toSourceLocation(publisher, options.repository)
28248
28263
  }));
28249
28264
  }
28250
- function handleAmbiguousMatch(publisher, publishedEventType, matchCount, options, sourceLocation) {
28265
+ function handleAmbiguousMatch(publisher, publishedEventType, matchCount, options) {
28251
28266
  if (options.strict) {
28252
28267
  throw new ConnectionDetectionError({
28253
- file: sourceLocation.filePath,
28254
- line: sourceLocation.lineNumber,
28268
+ file: publisher.location.file,
28269
+ line: publisher.location.line,
28255
28270
  typeName: publisher.name,
28256
- reason: `publishedEventType "${publishedEventType}" matches ${matchCount} Event components (ambiguous)`
28271
+ reason: `published event "${publishedEventType}" matches ${matchCount} Event components (ambiguous)`
28257
28272
  });
28258
28273
  }
28259
28274
  return {
28260
28275
  source: componentIdentity(publisher),
28261
28276
  target: "_unresolved",
28262
28277
  type: "async",
28263
- sourceLocation,
28264
- _uncertain: `ambiguous: ${matchCount} events match publishedEventType: ${publishedEventType}`
28278
+ sourceLocation: toSourceLocation(publisher, options.repository),
28279
+ _uncertain: `ambiguous: ${matchCount} events match published event type: ${publishedEventType}`
28265
28280
  };
28266
28281
  }
28267
- function handleNoMatch(publisher, publishedEventType, options, sourceLocation) {
28282
+ function handleNoMatch(publisher, publishedEventType, options) {
28268
28283
  if (options.strict) {
28269
28284
  throw new ConnectionDetectionError({
28270
- file: sourceLocation.filePath,
28271
- line: sourceLocation.lineNumber,
28285
+ file: publisher.location.file,
28286
+ line: publisher.location.line,
28272
28287
  typeName: publisher.name,
28273
- reason: `publishedEventType "${publishedEventType}" does not match any Event component`
28288
+ reason: `published event "${publishedEventType}" does not match any Event component`
28274
28289
  });
28275
28290
  }
28276
28291
  return {
28277
28292
  source: componentIdentity(publisher),
28278
28293
  target: "_unresolved",
28279
28294
  type: "async",
28280
- sourceLocation,
28281
- _uncertain: `no event found for publishedEventType: ${publishedEventType}`
28295
+ sourceLocation: toSourceLocation(publisher, options.repository),
28296
+ _uncertain: `no event found for published event type: ${publishedEventType}`
28282
28297
  };
28283
28298
  }
28284
28299
 
@@ -28289,15 +28304,8 @@ function detectSubscribeConnections(components, options) {
28289
28304
  const repository = options.repository;
28290
28305
  return eventHandlers.flatMap((handler) => getSubscribedEvents(handler).flatMap((eventName) => resolveSubscription(handler, eventName, events, options, repository)));
28291
28306
  }
28292
- function toSourceLocation(component, repository) {
28293
- return {
28294
- repository,
28295
- filePath: component.location.file,
28296
- lineNumber: component.location.line
28297
- };
28298
- }
28299
28307
  function resolveSubscription(handler, eventName, events, options, repository) {
28300
- const matchingEvents = events.filter((e) => e.metadata["eventName"] === eventName);
28308
+ const matchingEvents = events.filter((e) => e.metadata[EVENT_NAME_FIELD] === eventName);
28301
28309
  if (matchingEvents.length === 0) {
28302
28310
  return [handleNoMatch2(handler, eventName, options, repository)];
28303
28311
  }
@@ -28346,7 +28354,7 @@ function handleNoMatch2(handler, eventName, options, repository) {
28346
28354
  };
28347
28355
  }
28348
28356
  function getSubscribedEvents(handler) {
28349
- const raw = handler.metadata["subscribedEvents"];
28357
+ const raw = handler.metadata[SUBSCRIBED_EVENTS_FIELD];
28350
28358
  if (!Array.isArray(raw)) {
28351
28359
  return [];
28352
28360
  }
@@ -28615,15 +28623,13 @@ function detectPerModuleConnections(project, components, options, globMatcher) {
28615
28623
  function detectCrossModuleConnections(allComponents, options) {
28616
28624
  const strict = options.allowIncomplete !== true;
28617
28625
  const repository = options.repository;
28618
- const asyncStart = performance.now();
28619
- const publishLinks = detectPublishConnections(allComponents, {
28620
- strict,
28621
- repository
28622
- });
28623
- const subscribeLinks = detectSubscribeConnections(allComponents, {
28626
+ const asyncOptions = {
28624
28627
  strict,
28625
28628
  repository
28626
- });
28629
+ };
28630
+ const asyncStart = performance.now();
28631
+ const publishLinks = detectEventPublisherConnections(allComponents, options.eventPublishers ?? [], asyncOptions);
28632
+ const subscribeLinks = detectSubscribeConnections(allComponents, asyncOptions);
28627
28633
  const asyncDetectionMs = performance.now() - asyncStart;
28628
28634
  return {
28629
28635
  links: [...publishLinks, ...subscribeLinks],
@@ -28662,7 +28668,6 @@ function getBuiltInRule(module, componentType) {
28662
28668
  domainOp: module.domainOp,
28663
28669
  event: module.event,
28664
28670
  eventHandler: module.eventHandler,
28665
- eventPublisher: module.eventPublisher,
28666
28671
  ui: module.ui
28667
28672
  };
28668
28673
  const rule = ruleMap[componentType];
@@ -28678,7 +28683,6 @@ function findDetectionRule(module, componentType) {
28678
28683
  "domainOp",
28679
28684
  "event",
28680
28685
  "eventHandler",
28681
- "eventPublisher",
28682
28686
  "ui"
28683
28687
  ];
28684
28688
  if (builtInTypes.includes(componentType)) {
@@ -28729,10 +28733,7 @@ function evaluateClassRule(rule, classDecl) {
28729
28733
  if ("fromClassName" in rule) {
28730
28734
  return evaluateFromClassNameRule(rule, classDecl);
28731
28735
  }
28732
- if (!("fromProperty" in rule)) {
28733
- throw new ExtractionError("Unsupported extraction rule type for class-based component", classDecl.getSourceFile().getFilePath(), classDecl.getStartLineNumber());
28734
- }
28735
- return evaluateFromPropertyRule(rule, classDecl);
28736
+ throw new ExtractionError("Unsupported extraction rule type for class-based component", classDecl.getSourceFile().getFilePath(), classDecl.getStartLineNumber());
28736
28737
  }
28737
28738
  function evaluateRule2(rule, draft, project) {
28738
28739
  if ("literal" in rule) {
@@ -28749,6 +28750,10 @@ function evaluateRule2(rule, draft, project) {
28749
28750
  const classDecl2 = findContainingClass(project, draft);
28750
28751
  return evaluateFromGenericArgRule(rule, classDecl2);
28751
28752
  }
28753
+ if ("fromProperty" in rule) {
28754
+ const classDecl2 = findContainingClass(project, draft);
28755
+ return evaluateFromPropertyRule(rule, classDecl2);
28756
+ }
28752
28757
  if ("fromParameterType" in rule) {
28753
28758
  const methodDecl = findMethodAtLine(project, draft);
28754
28759
  const params = methodDecl.getParameters();
@@ -28929,10 +28934,6 @@ var extraction_config_schema_default = {
28929
28934
  $ref: "#/$defs/componentRule",
28930
28935
  description: "Detection rule for EventHandler components"
28931
28936
  },
28932
- eventPublisher: {
28933
- $ref: "#/$defs/componentRule",
28934
- description: "Detection rule for EventPublisher components"
28935
- },
28936
28937
  ui: {
28937
28938
  $ref: "#/$defs/componentRule",
28938
28939
  description: "Detection rule for UI components"
@@ -28945,7 +28946,7 @@ var extraction_config_schema_default = {
28945
28946
  }
28946
28947
  },
28947
28948
  connections: {
28948
- $ref: "#/$defs/connectionsConfig",
28949
+ $ref: "#/$defs/moduleConnectionsConfig",
28949
28950
  description: "Module-level connection detection patterns additive to global"
28950
28951
  }
28951
28952
  },
@@ -28955,7 +28956,7 @@ var extraction_config_schema_default = {
28955
28956
  }
28956
28957
  },
28957
28958
  then: {
28958
- required: ["api", "useCase", "domainOp", "event", "eventHandler", "eventPublisher", "ui"]
28959
+ required: ["api", "useCase", "domainOp", "event", "eventHandler", "ui"]
28959
28960
  }
28960
28961
  },
28961
28962
  componentRule: {
@@ -29449,7 +29450,6 @@ var extraction_config_schema_default = {
29449
29450
  connectionsConfig: {
29450
29451
  type: "object",
29451
29452
  description: "Connection detection configuration with pattern definitions",
29452
- required: ["patterns"],
29453
29453
  additionalProperties: false,
29454
29454
  properties: {
29455
29455
  patterns: {
@@ -29459,6 +29459,47 @@ var extraction_config_schema_default = {
29459
29459
  items: {
29460
29460
  $ref: "#/$defs/connectionPattern"
29461
29461
  }
29462
+ },
29463
+ eventPublishers: {
29464
+ type: "array",
29465
+ description: "Declares which custom component types publish events and how to detect the connections",
29466
+ minItems: 1,
29467
+ items: {
29468
+ $ref: "#/$defs/eventPublisherConfig"
29469
+ }
29470
+ }
29471
+ }
29472
+ },
29473
+ moduleConnectionsConfig: {
29474
+ type: "object",
29475
+ description: "Module-level connection detection configuration (patterns only \u2014 eventPublishers is top-level only)",
29476
+ additionalProperties: false,
29477
+ properties: {
29478
+ patterns: {
29479
+ type: "array",
29480
+ description: "Connection detection patterns",
29481
+ minItems: 1,
29482
+ items: {
29483
+ $ref: "#/$defs/connectionPattern"
29484
+ }
29485
+ }
29486
+ }
29487
+ },
29488
+ eventPublisherConfig: {
29489
+ type: "object",
29490
+ description: "Declares a custom component type as an event publisher",
29491
+ required: ["fromType", "metadataKey"],
29492
+ additionalProperties: false,
29493
+ properties: {
29494
+ fromType: {
29495
+ type: "string",
29496
+ description: "The custom component type name \u2014 must be defined in customTypes in at least one module",
29497
+ minLength: 1
29498
+ },
29499
+ metadataKey: {
29500
+ type: "string",
29501
+ description: "The metadata key on this component type that holds the published event type name",
29502
+ minLength: 1
29462
29503
  }
29463
29504
  }
29464
29505
  },
@@ -29594,7 +29635,6 @@ var REQUIRED_FIELDS = {
29594
29635
  api: ["apiType"],
29595
29636
  event: ["eventName"],
29596
29637
  eventHandler: ["subscribedEvents"],
29597
- eventPublisher: [],
29598
29638
  domainOp: ["operationName"],
29599
29639
  ui: ["route"],
29600
29640
  useCase: []
@@ -29605,7 +29645,6 @@ var COMPONENT_TYPES2 = [
29605
29645
  "domainOp",
29606
29646
  "event",
29607
29647
  "eventHandler",
29608
- "eventPublisher",
29609
29648
  "ui"
29610
29649
  ];
29611
29650
  var ajv2 = new import_ajv2.default({ allErrors: true });
@@ -29684,6 +29723,54 @@ function validateAllExtractionRules(config2) {
29684
29723
  return validateModuleExtractionRules(module, index);
29685
29724
  });
29686
29725
  }
29726
+ function collectCustomTypeExtractedFields(config2) {
29727
+ const fieldsByType = /* @__PURE__ */ new Map();
29728
+ for (const module of config2.modules) {
29729
+ if ("$ref" in module || module.customTypes === void 0) {
29730
+ continue;
29731
+ }
29732
+ for (const [typeName, rule] of Object.entries(module.customTypes)) {
29733
+ const existing = fieldsByType.get(typeName) ?? /* @__PURE__ */ new Set();
29734
+ for (const key of Object.keys(rule.extract ?? {})) {
29735
+ existing.add(key);
29736
+ }
29737
+ fieldsByType.set(typeName, existing);
29738
+ }
29739
+ }
29740
+ return fieldsByType;
29741
+ }
29742
+ function validateEventPublishers(connections, customTypeFields) {
29743
+ if (connections.eventPublishers === void 0) {
29744
+ return [];
29745
+ }
29746
+ return connections.eventPublishers.flatMap((publisher, index) => {
29747
+ const extractedFields = customTypeFields.get(publisher.fromType);
29748
+ if (extractedFields === void 0) {
29749
+ return [
29750
+ {
29751
+ path: `/connections/eventPublishers/${index}/fromType`,
29752
+ message: `"${publisher.fromType}" is not defined as a customType in any module. Add a customType named "${publisher.fromType}" to at least one module.`
29753
+ }
29754
+ ];
29755
+ }
29756
+ if (!extractedFields.has(publisher.metadataKey)) {
29757
+ return [
29758
+ {
29759
+ path: `/connections/eventPublishers/${index}/fromType`,
29760
+ message: `customType "${publisher.fromType}" does not extract "${publisher.metadataKey}". Add extract["${publisher.metadataKey}"] to that custom type.`
29761
+ }
29762
+ ];
29763
+ }
29764
+ return [];
29765
+ });
29766
+ }
29767
+ function validateConnectionsConfig(config2) {
29768
+ if (config2.connections === void 0) {
29769
+ return [];
29770
+ }
29771
+ const customTypeFields = collectCustomTypeExtractedFields(config2);
29772
+ return validateEventPublishers(config2.connections, customTypeFields);
29773
+ }
29687
29774
  function validateExtractionConfigSchema(data) {
29688
29775
  const schemaValid = validate2(data) === true;
29689
29776
  if (!schemaValid) {
@@ -29701,7 +29788,7 @@ function validateExtractionConfig(data) {
29701
29788
  if (!isValidExtractionConfig(data)) {
29702
29789
  return validateExtractionConfigSchema(data);
29703
29790
  }
29704
- const semanticErrors = validateAllExtractionRules(data);
29791
+ const semanticErrors = [...validateAllExtractionRules(data), ...validateConnectionsConfig(data)];
29705
29792
  if (semanticErrors.length > 0) {
29706
29793
  return {
29707
29794
  valid: false,
@@ -29717,10 +29804,10 @@ function formatValidationErrors2(errors) {
29717
29804
  return formatValidationErrorsInternal2(errors);
29718
29805
  }
29719
29806
  function parseExtractionConfig(data) {
29720
- if (isValidExtractionConfig(data)) {
29807
+ const result = validateExtractionConfig(data);
29808
+ if (result.valid && isValidExtractionConfig(data)) {
29721
29809
  return data;
29722
29810
  }
29723
- const result = validateExtractionConfig(data);
29724
29811
  throw new ExtractionConfigValidationError(result.errors);
29725
29812
  }
29726
29813
 
@@ -30073,7 +30160,8 @@ var ExtractionProject = class {
30073
30160
  }
30074
30161
  const crossResult = detectCrossModuleConnections(enrichedComponents, {
30075
30162
  allowIncomplete,
30076
- repository: this.repositoryName
30163
+ repository: this.repositoryName,
30164
+ eventPublishers: this.resolvedConfig.connections?.eventPublishers
30077
30165
  });
30078
30166
  links.push(...crossResult.links);
30079
30167
  timings.push({
@@ -30379,7 +30467,6 @@ ${formatValidationErrors2(validationResult.errors)}`
30379
30467
  domainOp: parsed.domainOp ?? NOT_USED,
30380
30468
  event: parsed.event ?? NOT_USED,
30381
30469
  eventHandler: parsed.eventHandler ?? NOT_USED,
30382
- eventPublisher: parsed.eventPublisher ?? NOT_USED,
30383
30470
  ui: parsed.ui ?? NOT_USED
30384
30471
  };
30385
30472
  }
@@ -31202,7 +31289,6 @@ export {
31202
31289
  /* istanbul ignore else -- @preserve: false branch is unreachable; FindTarget is exhaustive */
31203
31290
  /* istanbul ignore next -- @preserve: unreachable with valid FindTarget type; defensive fallback */
31204
31291
  /* v8 ignore next -- @preserve: getExtends() !== undefined guarantees getBaseClass() returns a value */
31205
- /* istanbul ignore next -- @preserve: only fromProperty reaches here; defensive guard */
31206
31292
  /* istanbul ignore next -- @preserve: catch always receives Error instances from ExtractionError */
31207
31293
  /* v8 ignore start -- @preserve: default executor delegates to execFileSync; tested via CLI integration */
31208
31294
  /* v8 ignore next -- @preserve: defensive optional chain; property existence guaranteed by hasOwn check above */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@living-architecture/riviere-cli",
3
- "version": "0.9.3",
3
+ "version": "0.9.5",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -32,10 +32,10 @@
32
32
  "glob": "^11.0.2",
33
33
  "ts-morph": "^24.0.0",
34
34
  "yaml": "^2.7.0",
35
- "@living-architecture/riviere-builder": "0.7.3",
36
- "@living-architecture/riviere-extract-ts": "0.4.2",
37
- "@living-architecture/riviere-extract-config": "0.5.3",
38
- "@living-architecture/riviere-schema": "0.6.3",
39
- "@living-architecture/riviere-query": "0.6.3"
35
+ "@living-architecture/riviere-builder": "0.7.4",
36
+ "@living-architecture/riviere-extract-ts": "0.4.4",
37
+ "@living-architecture/riviere-query": "0.6.4",
38
+ "@living-architecture/riviere-schema": "0.6.4",
39
+ "@living-architecture/riviere-extract-config": "0.5.4"
40
40
  }
41
41
  }