@reventlessdev/reventless-core 3.0.0-alpha.152 → 3.0.0-alpha.154

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.
@@ -86,7 +86,15 @@ let make = (
86
86
  ~inboundTranslationSlices: array<module(ReventlessInfra.InboundTranslationSlice.T)>=[],
87
87
  ~extensions: array<module(ReventlessInfra.Extension.Blueprint)>=[],
88
88
  ~extensionPoints: array<module(ReventlessInfra.ExtensionPointMapping.Mapping)>=[],
89
+ // Component name → chapter (intra-plugin grouping band), captured at build time
90
+ // from each component's source folder by the plugin generator. A component whose
91
+ // spec name has no entry (or lives directly under a kind-folder) carries no chapter
92
+ // and renders flat. Keyed by `Spec.name`, which equals the source filename stem for
93
+ // every graph-node kind, so the generator can build this map from the discovered
94
+ // file paths. See `Codegen.chapterOf` and docs/plans/deployed-chapter-grouping.md.
95
+ ~componentChapters: dict<string>=Dict.make(),
89
96
  ): Reventless.Plugin.pluginStructure => {
97
+ let chapterOf = (compName: string): option<string> => componentChapters->Dict.get(compName)
90
98
  // Event schemas: filter out payload-less variants — DCB event-type lookups
91
99
  // can't WHERE-clause on bare-string events, so the plugin graph mustn't
92
100
  // claim cross-component edges that the runtime can't honour.
@@ -405,6 +413,7 @@ let make = (
405
413
  searchableFields,
406
414
  statusField: statusFieldFromStateSchema(stateSchema),
407
415
  visibility: visibilityTag(R.Spec.visibility),
416
+ chapter: chapterOf(R.Spec.name),
408
417
  }: Reventless.Plugin.queryableDef)
409
418
  })
410
419
 
@@ -427,6 +436,7 @@ let make = (
427
436
  searchableFields,
428
437
  statusField: statusFieldFromStateSchema(stateSchema),
429
438
  visibility: visibilityTag(SVS.Spec.visibility),
439
+ chapter: chapterOf(SVS.Spec.name),
430
440
  }: Reventless.Plugin.queryableDef)
431
441
  })
432
442
 
@@ -454,6 +464,7 @@ let make = (
454
464
  linkedViews: linkedSvsFor(produced),
455
465
  consistencyRead: consistencyReadFor(consumed),
456
466
  events: extractEventDefs(SCS.Spec.eventSchema->S.castToUnknown),
467
+ chapter: chapterOf(SCS.Spec.name),
457
468
  }: Reventless.Plugin.writableDef)
458
469
  })
459
470
 
@@ -475,6 +486,7 @@ let make = (
475
486
  linkedViews: Array.concat(linkedSvsFor(produced), linkedReadModelsFor(A.Spec.name)),
476
487
  consistencyRead: None,
477
488
  events: extractEventDefs(A.Spec.eventSchema->S.castToUnknown),
489
+ chapter: chapterOf(A.Spec.name),
478
490
  }: Reventless.Plugin.writableDef)
479
491
  })
480
492
 
@@ -497,6 +509,7 @@ let make = (
497
509
  consumedEventTypes: qualify(~prefix=name, allConsumedVariants),
498
510
  producedCommandTypes: qualify(~prefix=name, commandVariantNames(AS.Spec.commandSchema)),
499
511
  targetName: AS.Spec.targetName,
512
+ chapter: chapterOf(AS.Spec.name),
500
513
  }: Reventless.Plugin.automationSliceDef)
501
514
  })
502
515
 
@@ -509,6 +522,7 @@ let make = (
509
522
  inboundCommandTypes: qualify(~prefix=name, commandVariantNames(OTS.Spec.inboundCommandSchema)),
510
523
  targetName: OTS.Spec.targetName,
511
524
  externalSystem: OTS.Spec.externalSystem,
525
+ chapter: chapterOf(OTS.Spec.name),
512
526
  }: Reventless.Plugin.outboundTranslationSliceDef))
513
527
 
514
528
  // ── Inbound translation slices ────────────────────────────────────────────
@@ -519,6 +533,7 @@ let make = (
519
533
  commandTypes: qualify(~prefix=name, commandVariantNames(ITS.Spec.commandSchema)),
520
534
  targetName: ITS.Spec.targetName,
521
535
  externalSystem: ITS.Spec.externalSystem,
536
+ chapter: chapterOf(ITS.Spec.name),
522
537
  }: Reventless.Plugin.inboundTranslationSliceDef))
523
538
 
524
539
  // ── Extensions ───────────────────────────────────────────────────────────
@@ -67,7 +67,7 @@ function labelFieldsFromStateSchema(entityName, stateSchema) {
67
67
  }
68
68
  }
69
69
 
70
- function make(name, aggregatesOpt, readModelsOpt, stateViewSlicesOpt, stateChangeSlicesOpt, automationSlicesOpt, outboundTranslationSlicesOpt, inboundTranslationSlicesOpt, extensionsOpt, extensionPointsOpt) {
70
+ function make(name, aggregatesOpt, readModelsOpt, stateViewSlicesOpt, stateChangeSlicesOpt, automationSlicesOpt, outboundTranslationSlicesOpt, inboundTranslationSlicesOpt, extensionsOpt, extensionPointsOpt, componentChaptersOpt) {
71
71
  let aggregates = aggregatesOpt !== undefined ? aggregatesOpt : [];
72
72
  let readModels = readModelsOpt !== undefined ? readModelsOpt : [];
73
73
  let stateViewSlices = stateViewSlicesOpt !== undefined ? stateViewSlicesOpt : [];
@@ -77,6 +77,7 @@ function make(name, aggregatesOpt, readModelsOpt, stateViewSlicesOpt, stateChang
77
77
  let inboundTranslationSlices = inboundTranslationSlicesOpt !== undefined ? inboundTranslationSlicesOpt : [];
78
78
  let extensions = extensionsOpt !== undefined ? extensionsOpt : [];
79
79
  let extensionPoints = extensionPointsOpt !== undefined ? extensionPointsOpt : [];
80
+ let componentChapters = componentChaptersOpt !== undefined ? componentChaptersOpt : ({});
80
81
  let qualify = (prefix, names) => names.map(n => prefix + "." + n);
81
82
  let isCreateCommandName = name => [
82
83
  "Add",
@@ -333,7 +334,8 @@ function make(name, aggregatesOpt, readModelsOpt, stateViewSlicesOpt, stateChang
333
334
  labelField: match[0],
334
335
  searchableFields: match[1],
335
336
  statusField: statusFieldFromStateSchema(stateSchema),
336
- visibility: visibilityTag(R.Spec.visibility)
337
+ visibility: visibilityTag(R.Spec.visibility),
338
+ chapter: componentChapters[R.Spec.name]
337
339
  };
338
340
  });
339
341
  let stateViewDefs = stateViewSlices.map((SVS, i) => {
@@ -351,7 +353,8 @@ function make(name, aggregatesOpt, readModelsOpt, stateViewSlicesOpt, stateChang
351
353
  labelField: match$1[0],
352
354
  searchableFields: match$1[1],
353
355
  statusField: statusFieldFromStateSchema(stateSchema),
354
- visibility: visibilityTag(SVS.Spec.visibility)
356
+ visibility: visibilityTag(SVS.Spec.visibility),
357
+ chapter: componentChapters[SVS.Spec.name]
355
358
  };
356
359
  });
357
360
  let stateChangeDefs = stateChangeSlices.map((SCS, i) => {
@@ -366,7 +369,8 @@ function make(name, aggregatesOpt, readModelsOpt, stateViewSlicesOpt, stateChang
366
369
  consumedEventTypes: consumed,
367
370
  linkedViews: linkedSvsFor(produced),
368
371
  consistencyRead: consistencyReadFor(consumed),
369
- events: extractEventDefs(SCS.Spec.eventSchema)
372
+ events: extractEventDefs(SCS.Spec.eventSchema),
373
+ chapter: componentChapters[SCS.Spec.name]
370
374
  };
371
375
  });
372
376
  let aggregateDefs = aggregates.map((A, i) => {
@@ -379,7 +383,8 @@ function make(name, aggregatesOpt, readModelsOpt, stateViewSlicesOpt, stateChang
379
383
  consumedEventTypes: [],
380
384
  linkedViews: linkedSvsFor(produced).concat(linkedReadModelsFor(A.Spec.name)),
381
385
  consistencyRead: undefined,
382
- events: extractEventDefs(A.Spec.eventSchema)
386
+ events: extractEventDefs(A.Spec.eventSchema),
387
+ chapter: componentChapters[A.Spec.name]
383
388
  };
384
389
  });
385
390
  let automationSliceDefs = automationSlices.map(AS => {
@@ -388,7 +393,8 @@ function make(name, aggregatesOpt, readModelsOpt, stateViewSlicesOpt, stateChang
388
393
  name: AS.Spec.name,
389
394
  consumedEventTypes: qualify(name, allConsumedVariants),
390
395
  producedCommandTypes: qualify(name, DcbTag$Reventless.extractAllVariantNames(AS.Spec.commandSchema)),
391
- targetName: AS.Spec.targetName
396
+ targetName: AS.Spec.targetName,
397
+ chapter: componentChapters[AS.Spec.name]
392
398
  };
393
399
  });
394
400
  let outboundTranslationSliceDefs = outboundTranslationSlices.map(OTS => ({
@@ -396,13 +402,15 @@ function make(name, aggregatesOpt, readModelsOpt, stateViewSlicesOpt, stateChang
396
402
  consumedEventTypes: qualify(name, DcbTag$Reventless.extractVariantNames(OTS.Spec.consumedEventSchema)),
397
403
  inboundCommandTypes: qualify(name, DcbTag$Reventless.extractAllVariantNames(OTS.Spec.inboundCommandSchema)),
398
404
  targetName: OTS.Spec.targetName,
399
- externalSystem: OTS.Spec.externalSystem
405
+ externalSystem: OTS.Spec.externalSystem,
406
+ chapter: componentChapters[OTS.Spec.name]
400
407
  }));
401
408
  let inboundTranslationSliceDefs = inboundTranslationSlices.map(ITS => ({
402
409
  name: ITS.Spec.name,
403
410
  commandTypes: qualify(name, DcbTag$Reventless.extractAllVariantNames(ITS.Spec.commandSchema)),
404
411
  targetName: ITS.Spec.targetName,
405
- externalSystem: ITS.Spec.externalSystem
412
+ externalSystem: ITS.Spec.externalSystem,
413
+ chapter: componentChapters[ITS.Spec.name]
406
414
  }));
407
415
  let extensionDefs = extensions.map(E => {
408
416
  let delegateNames = E.mappings.map(M => M.delegateName);
@@ -0,0 +1,53 @@
1
+ open JestGlobals
2
+
3
+ // The registry only forwards `~component`; it never reads its fields. A
4
+ // structural stand-in keeps @pulumi/pulumi (whose Output.make would build a real
5
+ // resource) out of the Jest run — its ESM entry can't be imported under Jest.
6
+ let stubResource: ReventlessInfra.Adapter.resource = %raw(`{}`)
7
+
8
+ describe("Monitoring", () => {
9
+ testSync("Noop default: notify is silent and does not throw", () => {
10
+ // No backend registered — the default Noop backend swallows the call.
11
+ Monitoring.notify(~kind=CommandHandler, ~name="before", ~component=stubResource)
12
+ expect(true)->toBe(true)
13
+ })
14
+
15
+ testSync("use registers a backend that receives every notify, role and name", () => {
16
+ let recorded: array<(Monitoring.unitKind, string)> = []
17
+ module Recorder: Monitoring.Backend = {
18
+ let onProvisioned = (~kind, ~name, ~component as _) => recorded->Array.push((kind, name))
19
+ }
20
+ Monitoring.use(module(Recorder: Monitoring.Backend))
21
+
22
+ Monitoring.notify(~kind=CommandHandler, ~name="AllAggregatesCmdHandler", ~component=stubResource)
23
+ Monitoring.notify(~kind=Projection, ~name="AllStateViewSlices", ~component=stubResource)
24
+ Monitoring.notify(~kind=DeadLetterSink, ~name="DeadLetterQueue", ~component=stubResource)
25
+ Monitoring.notify(~kind=Other("Counter"), ~name="ProductCounter", ~component=stubResource)
26
+
27
+ expect(recorded)->toEqual([
28
+ (Monitoring.CommandHandler, "AllAggregatesCmdHandler"),
29
+ (Monitoring.Projection, "AllStateViewSlices"),
30
+ (Monitoring.DeadLetterSink, "DeadLetterQueue"),
31
+ (Monitoring.Other("Counter"), "ProductCounter"),
32
+ ])
33
+
34
+ // Restore the default so registry state doesn't leak to other cases.
35
+ Monitoring.use(module(Monitoring.Noop))
36
+ })
37
+
38
+ testSync("notify forwards the static name and component resource to the backend", () => {
39
+ let seen: ref<option<(string, ReventlessInfra.Adapter.resource)>> = ref(None)
40
+ module Capture: Monitoring.Backend = {
41
+ let onProvisioned = (~kind as _, ~name, ~component) => seen := Some((name, component))
42
+ }
43
+ Monitoring.use(module(Capture: Monitoring.Backend))
44
+
45
+ Monitoring.notify(~kind=Scheduler, ~name="HeartbeatUnit", ~component=stubResource)
46
+ switch seen.contents {
47
+ | Some((name, _component)) => expect(name)->toBe("HeartbeatUnit")
48
+ | None => expect("no notify received")->toBe("a notify")
49
+ }
50
+
51
+ Monitoring.use(module(Monitoring.Noop))
52
+ })
53
+ })
@@ -0,0 +1,82 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+ import * as Monitoring$ReventlessCore from "../../src/adapter/Monitoring/Monitoring.res.mjs";
4
+
5
+ let stubResource = {};
6
+
7
+ globalThis.describe("Monitoring", () => {
8
+ globalThis.test("Noop default: notify is silent and does not throw", () => {
9
+ Monitoring$ReventlessCore.notify("CommandHandler", "before", stubResource);
10
+ globalThis.expect(true).toBe(true);
11
+ });
12
+ globalThis.test("use registers a backend that receives every notify, role and name", () => {
13
+ let recorded = [];
14
+ let onProvisioned = (kind, name, param) => {
15
+ recorded.push([
16
+ kind,
17
+ name
18
+ ]);
19
+ };
20
+ let Recorder = {
21
+ onProvisioned: onProvisioned
22
+ };
23
+ Monitoring$ReventlessCore.use(Recorder);
24
+ Monitoring$ReventlessCore.notify("CommandHandler", "AllAggregatesCmdHandler", stubResource);
25
+ Monitoring$ReventlessCore.notify("Projection", "AllStateViewSlices", stubResource);
26
+ Monitoring$ReventlessCore.notify("DeadLetterSink", "DeadLetterQueue", stubResource);
27
+ Monitoring$ReventlessCore.notify({
28
+ TAG: "Other",
29
+ _0: "Counter"
30
+ }, "ProductCounter", stubResource);
31
+ globalThis.expect(recorded).toEqual([
32
+ [
33
+ "CommandHandler",
34
+ "AllAggregatesCmdHandler"
35
+ ],
36
+ [
37
+ "Projection",
38
+ "AllStateViewSlices"
39
+ ],
40
+ [
41
+ "DeadLetterSink",
42
+ "DeadLetterQueue"
43
+ ],
44
+ [
45
+ {
46
+ TAG: "Other",
47
+ _0: "Counter"
48
+ },
49
+ "ProductCounter"
50
+ ]
51
+ ]);
52
+ Monitoring$ReventlessCore.use(Monitoring$ReventlessCore.Noop);
53
+ });
54
+ globalThis.test("notify forwards the static name and component resource to the backend", () => {
55
+ let seen = {
56
+ contents: undefined
57
+ };
58
+ let onProvisioned = (param, name, component) => {
59
+ seen.contents = [
60
+ name,
61
+ component
62
+ ];
63
+ };
64
+ let Capture = {
65
+ onProvisioned: onProvisioned
66
+ };
67
+ Monitoring$ReventlessCore.use(Capture);
68
+ Monitoring$ReventlessCore.notify("Scheduler", "HeartbeatUnit", stubResource);
69
+ let match = seen.contents;
70
+ if (match !== undefined) {
71
+ globalThis.expect(match[0]).toBe("HeartbeatUnit");
72
+ } else {
73
+ globalThis.expect("no notify received").toBe("a notify");
74
+ }
75
+ Monitoring$ReventlessCore.use(Monitoring$ReventlessCore.Noop);
76
+ });
77
+ });
78
+
79
+ export {
80
+ stubResource,
81
+ }
82
+ /* Not a pure module */
@@ -28,6 +28,7 @@ let qbl: queryableDef = {
28
28
  searchableFields: ["displayName"],
29
29
  statusField: None,
30
30
  visibility: None,
31
+ chapter: None,
31
32
  }
32
33
 
33
34
  let wbl: writableDef = {
@@ -38,6 +39,7 @@ let wbl: writableDef = {
38
39
  producedEventTypes: ["ProductAdded"],
39
40
  consumedEventTypes: [],
40
41
  events: [{name: "ProductAdded", schema: "{}", references: []}],
42
+ chapter: None,
41
43
  }
42
44
 
43
45
  let structure: pluginStructure = {
@@ -51,6 +53,7 @@ let structure: pluginStructure = {
51
53
  consumedEventTypes: ["StockLow"],
52
54
  producedCommandTypes: ["Restock"],
53
55
  targetName: "Product",
56
+ chapter: None,
54
57
  },
55
58
  ],
56
59
  outboundTranslationSlices: [
@@ -60,10 +63,17 @@ let structure: pluginStructure = {
60
63
  inboundCommandTypes: ["Ship"],
61
64
  targetName: None,
62
65
  externalSystem: None,
66
+ chapter: None,
63
67
  },
64
68
  ],
65
69
  inboundTranslationSlices: [
66
- {name: "FromBilling", commandTypes: ["RecordPayment"], targetName: "Order", externalSystem: None},
70
+ {
71
+ name: "FromBilling",
72
+ commandTypes: ["RecordPayment"],
73
+ targetName: "Order",
74
+ externalSystem: None,
75
+ chapter: None,
76
+ },
67
77
  ],
68
78
  extensions: [
69
79
  {
@@ -143,6 +153,61 @@ describe("encodePluginStructureEntry", () => {
143
153
  testSync("encodes writableDef events", () =>
144
154
  expect(json->String.includes("\"events\":[{\"name\":\"ProductAdded\""))->toEqual(true)
145
155
  )
156
+
157
+ // Translation-slice externalSystem: absent on the fixture above (both None), so it
158
+ // must serialize as null — the "no external box" case.
159
+ testSync("encodes None outbound externalSystem as null", () =>
160
+ expect(json->String.includes("\"inboundCommandTypes\":[\"Ship\"],\"externalSystem\":null"))->toEqual(
161
+ true,
162
+ )
163
+ )
164
+
165
+ testSync("encodes None inbound externalSystem as null", () =>
166
+ expect(json->String.includes("\"commandTypes\":[\"RecordPayment\"],\"externalSystem\":null"))->toEqual(
167
+ true,
168
+ )
169
+ )
170
+ })
171
+
172
+ // A deployed-graph consumer draws the external-system boundary box off this field, so
173
+ // a slice whose spec sets `externalSystem = Some("X")` must surface "X" on the wire for
174
+ // both directions — the round-trip the plan pins.
175
+ describe("translation-slice externalSystem round-trip", () => {
176
+ let externalStructure: pluginStructure = {
177
+ ...structure,
178
+ outboundTranslationSlices: [
179
+ {
180
+ name: "ToShipper",
181
+ consumedEventTypes: ["OrderPlaced"],
182
+ inboundCommandTypes: ["Ship"],
183
+ targetName: None,
184
+ externalSystem: Some("ShipperGateway"),
185
+ chapter: None,
186
+ },
187
+ ],
188
+ inboundTranslationSlices: [
189
+ {
190
+ name: "FromBilling",
191
+ commandTypes: ["RecordPayment"],
192
+ targetName: "Order",
193
+ externalSystem: Some("BillingProvider"),
194
+ chapter: None,
195
+ },
196
+ ],
197
+ }
198
+ let externalJson =
199
+ Platform_ComponentDefinitionsApi.encodePluginStructureEntry(
200
+ ~pluginId="Catalog",
201
+ externalStructure,
202
+ )->JSON.stringify
203
+
204
+ testSync("surfaces Some outbound externalSystem as its inner string", () =>
205
+ expect(externalJson->String.includes("\"externalSystem\":\"ShipperGateway\""))->toEqual(true)
206
+ )
207
+
208
+ testSync("surfaces Some inbound externalSystem as its inner string", () =>
209
+ expect(externalJson->String.includes("\"externalSystem\":\"BillingProvider\""))->toEqual(true)
210
+ )
146
211
  })
147
212
 
148
213
  describe("visibility filtering (deployed AutoUI hides Internal)", () => {
@@ -159,6 +224,7 @@ describe("visibility filtering (deployed AutoUI hides Internal)", () => {
159
224
  searchableFields: ["name"],
160
225
  statusField: None,
161
226
  visibility: Some("Internal"),
227
+ chapter: None,
162
228
  }
163
229
  let mixed: pluginStructure = {
164
230
  ...structure,
@@ -199,6 +265,7 @@ describe("allowedStates + statusField populated", () => {
199
265
  searchableFields: ["name"],
200
266
  statusField: Some("status"),
201
267
  visibility: None,
268
+ chapter: None,
202
269
  }
203
270
 
204
271
  let wblWithStates: writableDef = {
@@ -209,6 +276,7 @@ describe("allowedStates + statusField populated", () => {
209
276
  producedEventTypes: [],
210
277
  consumedEventTypes: [],
211
278
  events: [],
279
+ chapter: None,
212
280
  }
213
281
 
214
282
  let structureWithStates: pluginStructure = {
@@ -39,7 +39,8 @@ let qbl = {
39
39
  labelField: "displayName",
40
40
  searchableFields: qbl_searchableFields,
41
41
  statusField: undefined,
42
- visibility: undefined
42
+ visibility: undefined,
43
+ chapter: undefined
43
44
  };
44
45
 
45
46
  let wbl_commands = [cmd];
@@ -63,7 +64,8 @@ let wbl = {
63
64
  consumedEventTypes: wbl_consumedEventTypes,
64
65
  linkedViews: wbl_linkedViews,
65
66
  consistencyRead: undefined,
66
- events: wbl_events
67
+ events: wbl_events,
68
+ chapter: undefined
67
69
  };
68
70
 
69
71
  let structure_readModels = [qbl];
@@ -78,7 +80,8 @@ let structure_automationSlices = [{
78
80
  name: "Restocker",
79
81
  consumedEventTypes: ["StockLow"],
80
82
  producedCommandTypes: ["Restock"],
81
- targetName: "Product"
83
+ targetName: "Product",
84
+ chapter: undefined
82
85
  }];
83
86
 
84
87
  let structure_outboundTranslationSlices = [{
@@ -86,14 +89,16 @@ let structure_outboundTranslationSlices = [{
86
89
  consumedEventTypes: ["OrderPlaced"],
87
90
  inboundCommandTypes: ["Ship"],
88
91
  targetName: undefined,
89
- externalSystem: undefined
92
+ externalSystem: undefined,
93
+ chapter: undefined
90
94
  }];
91
95
 
92
96
  let structure_inboundTranslationSlices = [{
93
97
  name: "FromBilling",
94
98
  commandTypes: ["RecordPayment"],
95
99
  targetName: "Order",
96
- externalSystem: undefined
100
+ externalSystem: undefined,
101
+ chapter: undefined
97
102
  }];
98
103
 
99
104
  let structure_extensions = [{
@@ -168,6 +173,54 @@ globalThis.describe("encodePluginStructureEntry", () => {
168
173
  globalThis.test("encodes writableDef events", () => {
169
174
  globalThis.expect(json.includes("\"events\":[{\"name\":\"ProductAdded\"")).toEqual(true);
170
175
  });
176
+ globalThis.test("encodes None outbound externalSystem as null", () => {
177
+ globalThis.expect(json.includes("\"inboundCommandTypes\":[\"Ship\"],\"externalSystem\":null")).toEqual(true);
178
+ });
179
+ globalThis.test("encodes None inbound externalSystem as null", () => {
180
+ globalThis.expect(json.includes("\"commandTypes\":[\"RecordPayment\"],\"externalSystem\":null")).toEqual(true);
181
+ });
182
+ });
183
+
184
+ globalThis.describe("translation-slice externalSystem round-trip", () => {
185
+ let externalStructure_readModels = structure_readModels;
186
+ let externalStructure_stateViewSlices = structure_stateViewSlices;
187
+ let externalStructure_stateChangeSlices = structure_stateChangeSlices;
188
+ let externalStructure_aggregates = structure_aggregates;
189
+ let externalStructure_automationSlices = structure_automationSlices;
190
+ let externalStructure_outboundTranslationSlices = [{
191
+ name: "ToShipper",
192
+ consumedEventTypes: ["OrderPlaced"],
193
+ inboundCommandTypes: ["Ship"],
194
+ targetName: undefined,
195
+ externalSystem: "ShipperGateway",
196
+ chapter: undefined
197
+ }];
198
+ let externalStructure_inboundTranslationSlices = [{
199
+ name: "FromBilling",
200
+ commandTypes: ["RecordPayment"],
201
+ targetName: "Order",
202
+ externalSystem: "BillingProvider",
203
+ chapter: undefined
204
+ }];
205
+ let externalStructure_extensions = structure_extensions;
206
+ let externalStructure = {
207
+ readModels: externalStructure_readModels,
208
+ stateViewSlices: externalStructure_stateViewSlices,
209
+ stateChangeSlices: externalStructure_stateChangeSlices,
210
+ aggregates: externalStructure_aggregates,
211
+ automationSlices: externalStructure_automationSlices,
212
+ outboundTranslationSlices: externalStructure_outboundTranslationSlices,
213
+ inboundTranslationSlices: externalStructure_inboundTranslationSlices,
214
+ extensions: externalStructure_extensions,
215
+ extensionPoints: undefined
216
+ };
217
+ let externalJson = JSON.stringify(Platform_ComponentDefinitionsApi$ReventlessCore.encodePluginStructureEntry("Catalog", externalStructure));
218
+ globalThis.test("surfaces Some outbound externalSystem as its inner string", () => {
219
+ globalThis.expect(externalJson.includes("\"externalSystem\":\"ShipperGateway\"")).toEqual(true);
220
+ });
221
+ globalThis.test("surfaces Some inbound externalSystem as its inner string", () => {
222
+ globalThis.expect(externalJson.includes("\"externalSystem\":\"BillingProvider\"")).toEqual(true);
223
+ });
171
224
  });
172
225
 
173
226
  globalThis.describe("visibility filtering (deployed AutoUI hides Internal)", () => {
@@ -184,7 +237,8 @@ globalThis.describe("visibility filtering (deployed AutoUI hides Internal)", ()
184
237
  labelField: "name",
185
238
  searchableFields: internalQbl_searchableFields,
186
239
  statusField: undefined,
187
- visibility: internalQbl_visibility
240
+ visibility: internalQbl_visibility,
241
+ chapter: undefined
188
242
  };
189
243
  let mixed_readModels = [
190
244
  qbl,
@@ -245,7 +299,8 @@ globalThis.describe("allowedStates + statusField populated", () => {
245
299
  labelField: "name",
246
300
  searchableFields: qblWithStatus_searchableFields,
247
301
  statusField: qblWithStatus_statusField,
248
- visibility: undefined
302
+ visibility: undefined,
303
+ chapter: undefined
249
304
  };
250
305
  let wblWithStates_commands = [cmdWithStates];
251
306
  let wblWithStates_producedEventTypes = [];
@@ -259,7 +314,8 @@ globalThis.describe("allowedStates + statusField populated", () => {
259
314
  consumedEventTypes: wblWithStates_consumedEventTypes,
260
315
  linkedViews: wblWithStates_linkedViews,
261
316
  consistencyRead: undefined,
262
- events: wblWithStates_events
317
+ events: wblWithStates_events,
318
+ chapter: undefined
263
319
  };
264
320
  let structureWithStates_readModels = [qblWithStatus];
265
321
  let structureWithStates_stateViewSlices = [];