@reventlessdev/reventless-core 3.0.0-alpha.239 → 3.0.0-alpha.241

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 (172) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/package.json +11 -11
  3. package/src/Message.res +11 -11
  4. package/src/Message.res.mjs +15 -14
  5. package/src/Projection.res +2 -2
  6. package/src/Projection.res.mjs +5 -4
  7. package/src/adapter/Monitoring/Monitoring.res +24 -2
  8. package/src/adapter/Monitoring/Monitoring.res.mjs +3 -3
  9. package/src/admin/Platform_Admin.res +1 -16
  10. package/src/admin/Platform_Admin.res.mjs +2 -30
  11. package/src/admin/Platform_AdminApi.res.mjs +3 -3
  12. package/src/admin/Platform_Admin_Structure.res +58 -113
  13. package/src/admin/Platform_Admin_Structure.res.mjs +24 -139
  14. package/src/admin/UiFragmentRegistry/StateChangeSlice/UiFragmentRegistry.res.mjs +12 -12
  15. package/src/admin/UiFragmentRegistry/StateViewSlice/UiFragments.res.mjs +14 -14
  16. package/src/components/Aggregate/Aggregate_Callback.res +2 -2
  17. package/src/components/Aggregate/Aggregate_Callback.res.mjs +4 -4
  18. package/src/components/Api/ApiAllowedStatesHelpers.res.mjs +3 -3
  19. package/src/components/Api/ApiNoApiHelpers.res.mjs +5 -5
  20. package/src/components/Api/ApiTargetStateHelpers.res.mjs +3 -3
  21. package/src/components/Api/GraphQL_FragmentGenerator.res +18 -12
  22. package/src/components/Api/GraphQL_FragmentGenerator.res.mjs +7 -13
  23. package/src/components/Api/GraphQL_SchemaInspector.res +1 -1
  24. package/src/components/Api/GraphQL_SchemaInspector.res.mjs +1 -1
  25. package/src/components/Api/MCP_SchemaGenerator.res +1 -1
  26. package/src/components/Api/MCP_SchemaGenerator.res.mjs +1 -1
  27. package/src/components/Api/SchemaType.res +6 -10
  28. package/src/components/Api/SchemaType.res.mjs +4 -4
  29. package/src/components/Api/StorageRefFields.res +1 -1
  30. package/src/components/Api/StorageRefFields.res.mjs +1 -1
  31. package/src/components/Api/SuryToJsonSchema.res +11 -0
  32. package/src/components/Api/SuryToJsonSchema.res.mjs +2 -1
  33. package/src/components/AutomationSlice/AutomationSlice_Callback.res +3 -4
  34. package/src/components/AutomationSlice/AutomationSlice_Callback.res.mjs +22 -23
  35. package/src/components/CommandTopic/CommandTopic_Callback.res +1 -2
  36. package/src/components/CommandTopic/CommandTopic_Callback.res.mjs +3 -4
  37. package/src/components/CommandTopic/CommandTopic_Helpers.res +1 -1
  38. package/src/components/CommandTopic/CommandTopic_Helpers.res.mjs +3 -3
  39. package/src/components/Counter/Counter.res.mjs +2 -2
  40. package/src/components/Counter/Counter_Callback.res.mjs +4 -4
  41. package/src/components/Counter/Counter_Operations.res.mjs +4 -4
  42. package/src/components/Dcb/Dcb_Builder.res +1 -1
  43. package/src/components/Dcb/Dcb_Builder.res.mjs +8 -6
  44. package/src/components/DcbEventLog/DcbEventLog_Builder.res.mjs +4 -3
  45. package/src/components/EventCollector/EventCollector_Builder.res +1 -1
  46. package/src/components/InboundTranslationSlice/InboundTranslationSlice_Callback.res +1 -2
  47. package/src/components/InboundTranslationSlice/InboundTranslationSlice_Callback.res.mjs +11 -12
  48. package/src/components/OutboundTranslationSlice/OutboundTranslationSlice_Callback.res +3 -4
  49. package/src/components/OutboundTranslationSlice/OutboundTranslationSlice_Callback.res.mjs +24 -25
  50. package/src/components/SideEffectHandler/SideEffectHandler_Callback.res +1 -1
  51. package/src/components/SideEffectHandler/SideEffectHandler_Callback.res.mjs +3 -3
  52. package/src/components/StateChangeSlice/StateChangeSlice_Callback.res +2 -2
  53. package/src/components/StateChangeSlice/StateChangeSlice_Callback.res.mjs +4 -4
  54. package/src/components/StateViewSlice/StateViewSlice_Builder.res +1 -1
  55. package/src/components/StateViewSlice/StateViewSlice_Builder.res.mjs +3 -3
  56. package/src/plugin/api/PluginBaseFragment.res +12 -29
  57. package/src/plugin/api/PluginBaseFragment.res.mjs +3 -22
  58. package/src/plugin/component/Capability_Inference.res +118 -1
  59. package/src/plugin/component/Capability_Inference.res.mjs +128 -1
  60. package/src/plugin/component/Plugin_Builder.res +2 -2
  61. package/src/plugin/component/Plugin_Builder.res.mjs +2 -1
  62. package/src/plugin/component/Plugin_Helpers.res +11 -11
  63. package/src/plugin/component/Plugin_Helpers.res.mjs +11 -10
  64. package/src/plugin/component/Plugin_Structure.res +349 -274
  65. package/src/plugin/component/Plugin_Structure.res.mjs +212 -175
  66. package/src/plugin/component/Plugin_SubscriptionSchema.res +1 -1
  67. package/src/plugin/component/Plugin_SubscriptionSchema.res.mjs +1 -1
  68. package/src/plugin/component/SchemaWalker.res +11 -11
  69. package/src/plugin/component/SchemaWalker.res.mjs +8 -9
  70. package/src/plugin/connect/PluginExtensionPoint_Plugin.res.mjs +15 -15
  71. package/src/plugin/lifecycle/PluginBehavior.res.mjs +55 -55
  72. package/src/plugin/lifecycle/PluginSpec.res +22 -7
  73. package/src/plugin/lifecycle/PluginSpec.res.mjs +91 -36
  74. package/src/plugin/lifecycle/PluginsReadModelSpec.res +36 -9
  75. package/src/plugin/lifecycle/PluginsReadModelSpec.res.mjs +33 -22
  76. package/src/util/Interstack.res +3 -3
  77. package/src/util/LogFormat.res +1 -2
  78. package/src/util/LogFormat.res.mjs +2 -2
  79. package/tests/IdentityTest.res +6 -7
  80. package/tests/IdentityTest.res.mjs +7 -9
  81. package/tests/adapter/MonitoringTest.res +30 -3
  82. package/tests/adapter/MonitoringTest.res.mjs +31 -12
  83. package/tests/adapter/RuntimeExtensionHookReachTest.res +0 -1
  84. package/tests/adapter/RuntimeExtensionHookReachTest.res.mjs +5 -7
  85. package/tests/admin/Platform_Admin_StructureTest.res +254 -0
  86. package/tests/admin/Platform_Admin_StructureTest.res.mjs +219 -0
  87. package/tests/aggregate/AggregateCacheTest.res +0 -1
  88. package/tests/aggregate/AggregateCacheTest.res.mjs +13 -15
  89. package/tests/aggregate/AggregateConflictTest.res +0 -1
  90. package/tests/aggregate/AggregateConflictTest.res.mjs +7 -9
  91. package/tests/aggregate/AggregateFixtures.res +0 -1
  92. package/tests/aggregate/AggregateFixtures.res.mjs +19 -21
  93. package/tests/aggregate/AggregateSnapshotTest.res +1 -2
  94. package/tests/aggregate/AggregateSnapshotTest.res.mjs +15 -16
  95. package/tests/api/ApiNoApiTest.res.mjs +17 -9
  96. package/tests/api/GraphQL_FragmentGeneratorTest.res +62 -1
  97. package/tests/api/GraphQL_FragmentGeneratorTest.res.mjs +102 -58
  98. package/tests/api/PsInternalFieldsReadModel.res +21 -0
  99. package/tests/api/PsInternalFieldsReadModel.res.mjs +74 -0
  100. package/tests/api/StorageRefFieldsTest.res.mjs +13 -13
  101. package/tests/api/SuryToJsonSchemaTest.res +43 -0
  102. package/tests/api/SuryToJsonSchemaTest.res.mjs +352 -849
  103. package/tests/commandgenerator/CommandGeneratorFixtures.res +0 -1
  104. package/tests/commandgenerator/CommandGeneratorFixtures.res.mjs +19 -21
  105. package/tests/commandgenerator/OwnerStampingTest.res +0 -1
  106. package/tests/commandgenerator/OwnerStampingTest.res.mjs +9 -11
  107. package/tests/commandtopic/CommandTopicCallbackFixtures.res +0 -1
  108. package/tests/commandtopic/CommandTopicCallbackFixtures.res.mjs +7 -9
  109. package/tests/counter/CounterFixtures.res +0 -1
  110. package/tests/counter/CounterFixtures.res.mjs +1 -4
  111. package/tests/dcb/DcbDecodeTest.res.mjs +24 -24
  112. package/tests/dcb/DcbEventLogOperationsTest.res +2 -2
  113. package/tests/dcb/DcbEventLogOperationsTest.res.mjs +3 -3
  114. package/tests/dcb/DcbEventLogSchemaTest.res.mjs +7 -7
  115. package/tests/dcb/DcbFixtures.res +0 -1
  116. package/tests/dcb/DcbFixtures.res.mjs +87 -89
  117. package/tests/dcb/DcbTagTest.res.mjs +6 -6
  118. package/tests/dcb/DcbValidationTest.res.mjs +52 -52
  119. package/tests/eventlog/EventLogFixtures.res +0 -1
  120. package/tests/eventlog/EventLogFixtures.res.mjs +7 -9
  121. package/tests/eventmapper/EventMapperFixtures.res +0 -1
  122. package/tests/eventmapper/EventMapperFixtures.res.mjs +24 -26
  123. package/tests/eventtopic/EventTopicFixtures.res +0 -1
  124. package/tests/eventtopic/EventTopicFixtures.res.mjs +7 -9
  125. package/tests/extensionpoint/ExtensionPointFixtures.res +0 -1
  126. package/tests/extensionpoint/ExtensionPointFixtures.res.mjs +10 -12
  127. package/tests/extensionpoint/ExtensionPointOperationsTest.res +1 -2
  128. package/tests/extensionpoint/ExtensionPointOperationsTest.res.mjs +9 -10
  129. package/tests/logger/LogFormatTest.res +3 -2
  130. package/tests/logger/LogFormatTest.res.mjs +7 -9
  131. package/tests/message/MessageTest.res +2 -2
  132. package/tests/message/MessageTest.res.mjs +8 -7
  133. package/tests/message/MetaEnvelopeTest.res +5 -5
  134. package/tests/message/MetaEnvelopeTest.res.mjs +12 -11
  135. package/tests/plugin/ManifestVisibilityTest.res.mjs +7 -7
  136. package/tests/plugin/PluginDefinitionScalars.res +5 -3
  137. package/tests/plugin/PluginDefinitionScalars.res.mjs +2 -2
  138. package/tests/plugin/PluginLifecycleCorpusTest.res +4 -3
  139. package/tests/plugin/PluginLifecycleCorpusTest.res.mjs +3 -6
  140. package/tests/plugin/PluginSpecExperiment.res +0 -1
  141. package/tests/plugin/PluginSpecExperiment.res.mjs +12 -14
  142. package/tests/plugin/PluginStructureTest.res +188 -1
  143. package/tests/plugin/PluginStructureTest.res.mjs +293 -102
  144. package/tests/plugin/Plugin_EventQuerySchemaTest.res.mjs +3 -3
  145. package/tests/plugin/SchemaWalkerTest.res +0 -1
  146. package/tests/plugin/SchemaWalkerTest.res.mjs +17 -19
  147. package/tests/plugin/StateChangeSlice/PsAttachInvoice.res.mjs +5 -5
  148. package/tests/plugin/StateChangeSlice/PsChangePhoto.res.mjs +8 -8
  149. package/tests/plugin/StateChangeSlice/PsDispatchShipment.res.mjs +5 -5
  150. package/tests/plugin/StateChangeSlice/PsGatedCommands.res.mjs +9 -9
  151. package/tests/plugin/StateChangeSlice/PsPlaceOrder.res.mjs +5 -5
  152. package/tests/plugin/StateChangeSlice/PsReserveStock.res.mjs +8 -8
  153. package/tests/plugin/StateChangeSlice/PsShipOrder.res.mjs +15 -15
  154. package/tests/plugin/StateChangeSlice/PsTypoStore.res +31 -0
  155. package/tests/plugin/StateChangeSlice/PsTypoStore.res.mjs +62 -0
  156. package/tests/plugin/StateChangeSlice/PsUploadAvatar.res.mjs +8 -8
  157. package/tests/plugin/StateChangeSlice/PsUploadImages.res +40 -0
  158. package/tests/plugin/StateChangeSlice/PsUploadImages.res.mjs +66 -0
  159. package/tests/plugin/StateViewSlice/PsAnnotatedView.res.mjs +13 -12
  160. package/tests/plugin/StateViewSlice/PsAvailableProductsView.res.mjs +8 -8
  161. package/tests/plugin/StateViewSlice/PsCategoriesView.res.mjs +6 -6
  162. package/tests/plugin/StateViewSlice/PsCustomersView.res.mjs +10 -10
  163. package/tests/plugin/StateViewSlice/PsGatedView.res.mjs +6 -6
  164. package/tests/plugin/StateViewSlice/PsOrdersView.res.mjs +9 -9
  165. package/tests/plugin/StateViewSlice/PsShipmentsView.res.mjs +11 -10
  166. package/tests/plugin/pluginDefinitionRequiredScalars.txt +15 -0
  167. package/tests/querydb/QueryDbFixtures.res +0 -1
  168. package/tests/querydb/QueryDbFixtures.res.mjs +5 -7
  169. package/tests/sideeffecthandler/SideEffectHandlerFixtures.res +0 -1
  170. package/tests/sideeffecthandler/SideEffectHandlerFixtures.res.mjs +4 -6
  171. package/tests/util/CommandPublisherTest.res +0 -1
  172. package/tests/util/CommandPublisherTest.res.mjs +4 -6
@@ -368,7 +368,6 @@ let refDoorFragment = (~subIdField=?) =>
368
368
  // What a caller holding a pointer to a withheld row may learn about it, and what
369
369
  // the two doors that could never answer for one can now be asked.
370
370
  describe("the reference door and the archive argument", () => {
371
- open Expect
372
371
 
373
372
  // The narrowness is the type's, not a rule each backend re-implements: a caller
374
373
  // cannot ask this door for a price, because there is no price on it.
@@ -511,3 +510,65 @@ describe("the by-index door", () => {
511
510
  ))->toEqual(("XByOwner", "XByOwnerId", "XByBy"))
512
511
  )
513
512
  })
513
+
514
+ // ── @internal: a field that is not on the GraphQL surface ────────────────────
515
+ //
516
+ // A read model's `@schema type state` is otherwise simultaneously the storage
517
+ // shape and the API shape. `@internal` separates them: the field stays in the
518
+ // record and in storage, and every generated object type drops it.
519
+ //
520
+ // The declaration is read off the schema rather than passed in, which is the
521
+ // point — the alternative is a hand-written exclude list beside the query entry,
522
+ // kept in step with the record by whoever next edits it. That is exactly what
523
+ // `PluginBaseFragment` maintained and what this replaces.
524
+ //
525
+ // The fixture is `PsInternalFieldsReadModel`, a spec file: the annotation machinery
526
+ // runs under `@@reventless.spec`.
527
+
528
+ describe("@internal keeps a field off the generated type", () => {
529
+ let stateSchema = PsInternalFieldsReadModel.stateSchema->S.castToUnknown
530
+
531
+ let types = (~excludeFields=?) =>
532
+ GraphQL_FragmentGenerator.deriveObjectTypeWithNested(
533
+ ~typeName="Platform_Widget",
534
+ ~excludeFields?,
535
+ stateSchema,
536
+ )->Array.join("\n")
537
+
538
+ testSync("the declared fields are absent", () =>
539
+ expect((
540
+ types()->String.includes("eventCollector"),
541
+ types()->String.includes("extensionNames"),
542
+ ))->toEqual((false, false))
543
+ )
544
+
545
+ testSync("and everything else is untouched", () =>
546
+ expect((types()->String.includes("name"), types()->String.includes("itemId")))->toEqual((
547
+ true,
548
+ true,
549
+ ))
550
+ )
551
+
552
+ // The caller's own exclusions still apply. The two lists answer different
553
+ // questions — one is a decision made where the entry is assembled, the other a
554
+ // declaration on the field — so the marker joins the list rather than
555
+ // replacing it.
556
+ testSync("a caller's excludeFields still applies alongside", () => {
557
+ let sdl = types(~excludeFields=["name"])
558
+ expect((sdl->String.includes("name"), sdl->String.includes("eventCollector")))->toEqual((
559
+ false,
560
+ false,
561
+ ))
562
+ })
563
+
564
+ // The published state schema and the SDL have to agree, because AutoUI builds
565
+ // its list query from the former and sends it against the latter. This is the
566
+ // pairing that used to need two hand-maintained lists to hold.
567
+ testSync("the published state schema drops them too", () => {
568
+ let json = SuryToJsonSchema.deriveObjectSchema(stateSchema)->JSON.stringify
569
+ expect((json->String.includes("eventCollector"), json->String.includes("name")))->toEqual((
570
+ false,
571
+ true,
572
+ ))
573
+ })
574
+ })
@@ -1,20 +1,22 @@
1
1
  // Generated by ReScript, PLEASE EDIT WITH CARE
2
2
 
3
- import * as S from "sury/src/S.res.mjs";
3
+ import * as Sury from "sury";
4
4
  import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
5
5
  import * as Money$Reventless from "@reventlessdev/reventless-spec/src/semantic/Money.res.mjs";
6
6
  import * as GraphQL_Stitcher$ReventlessCore from "../../src/components/Api/GraphQL_Stitcher.res.mjs";
7
+ import * as SuryToJsonSchema$ReventlessCore from "../../src/components/Api/SuryToJsonSchema.res.mjs";
7
8
  import * as GraphQL_FragmentGenerator$ReventlessCore from "../../src/components/Api/GraphQL_FragmentGenerator.res.mjs";
9
+ import * as PsInternalFieldsReadModel$ReventlessCore from "./PsInternalFieldsReadModel.res.mjs";
8
10
  import * as OutboundTranslationSlice_Callback$ReventlessCore from "../../src/components/OutboundTranslationSlice/OutboundTranslationSlice_Callback.res.mjs";
9
11
 
10
- let commandSchema = S.union([
11
- S.schema(s => ({
12
+ let commandSchema = Sury.union([
13
+ Sury.$schema(s => ({
12
14
  TAG: "CancelOrder",
13
- orderId: s.m(S.string)
15
+ orderId: s.m(Sury.string)
14
16
  })),
15
- S.schema(s => ({
17
+ Sury.$schema(s => ({
16
18
  TAG: "ReopenOrder",
17
- orderId: s.m(S.string)
19
+ orderId: s.m(Sury.string)
18
20
  }))
19
21
  ]);
20
22
 
@@ -52,9 +54,9 @@ globalThis.describe("GraphQL_FragmentGenerator.generate mutation id injection",
52
54
  });
53
55
  });
54
56
 
55
- let outboundItemSchema = S.schema(s => ({
56
- customerId: s.m(S.string),
57
- address: s.m(S.string)
57
+ let outboundItemSchema = Sury.$schema(s => ({
58
+ customerId: s.m(Sury.string),
59
+ address: s.m(Sury.string)
58
60
  }));
59
61
 
60
62
  let GeocodeItem = {
@@ -86,9 +88,9 @@ globalThis.describe("GraphQL_FragmentGenerator slice TODO rows", () => {
86
88
 
87
89
  globalThis.describe("resolveKeyField — the ladder", () => {
88
90
  globalThis.test("a lone `*Id` field is the only thing the key could be", () => {
89
- let schema = S.schema(s => ({
90
- productId: s.m(S.string),
91
- name: s.m(S.string)
91
+ let schema = Sury.$schema(s => ({
92
+ productId: s.m(Sury.string),
93
+ name: s.m(Sury.string)
92
94
  }));
93
95
  globalThis.expect(GraphQL_FragmentGenerator$ReventlessCore.resolveKeyField("AvailableProducts", schema)).toEqual([
94
96
  "productId",
@@ -96,9 +98,9 @@ globalThis.describe("resolveKeyField — the ladder", () => {
96
98
  ]);
97
99
  });
98
100
  globalThis.test("several `*Id` fields are disambiguated by the component name", () => {
99
- let schema = S.schema(s => ({
100
- productId: s.m(S.string),
101
- categoryId: s.m(S.string)
101
+ let schema = Sury.$schema(s => ({
102
+ productId: s.m(Sury.string),
103
+ categoryId: s.m(Sury.string)
102
104
  }));
103
105
  globalThis.expect(GraphQL_FragmentGenerator$ReventlessCore.resolveKeyField("Products", schema)).toEqual([
104
106
  "productId",
@@ -106,9 +108,9 @@ globalThis.describe("resolveKeyField — the ladder", () => {
106
108
  ]);
107
109
  });
108
110
  globalThis.test("the convention rung singularises the way Api_Naming does", () => {
109
- let schema = S.schema(s => ({
110
- categoryId: s.m(S.string),
111
- ownerId: s.m(S.string)
111
+ let schema = Sury.$schema(s => ({
112
+ categoryId: s.m(Sury.string),
113
+ ownerId: s.m(Sury.string)
112
114
  }));
113
115
  globalThis.expect(GraphQL_FragmentGenerator$ReventlessCore.resolveKeyField("Categories", schema)).toEqual([
114
116
  "categoryId",
@@ -116,23 +118,23 @@ globalThis.describe("resolveKeyField — the ladder", () => {
116
118
  ]);
117
119
  });
118
120
  globalThis.test("several `*Id` fields with no name match declines", () => {
119
- let schema = S.schema(s => ({
120
- productId: s.m(S.string),
121
- categoryId: s.m(S.string)
121
+ let schema = Sury.$schema(s => ({
122
+ productId: s.m(Sury.string),
123
+ categoryId: s.m(Sury.string)
122
124
  }));
123
125
  globalThis.expect(GraphQL_FragmentGenerator$ReventlessCore.resolveKeyField("ProductDemand", schema)).toEqual(undefined);
124
126
  });
125
127
  globalThis.test("no `*Id` field at all declines", () => {
126
- let schema = S.schema(s => ({
127
- email: s.m(S.string),
128
- address: s.m(S.string)
128
+ let schema = Sury.$schema(s => ({
129
+ email: s.m(Sury.string),
130
+ address: s.m(Sury.string)
129
131
  }));
130
132
  globalThis.expect(GraphQL_FragmentGenerator$ReventlessCore.resolveKeyField("Customers", schema)).toEqual(undefined);
131
133
  });
132
134
  globalThis.test("a word merely ending in `id` is not a key", () => {
133
- let schema = S.schema(s => ({
134
- paid: s.m(S.string),
135
- valid: s.m(S.string)
135
+ let schema = Sury.$schema(s => ({
136
+ paid: s.m(Sury.string),
137
+ valid: s.m(Sury.string)
136
138
  }));
137
139
  globalThis.expect(GraphQL_FragmentGenerator$ReventlessCore.resolveKeyField("Invoices", schema)).toEqual(undefined);
138
140
  });
@@ -140,17 +142,17 @@ globalThis.describe("resolveKeyField — the ladder", () => {
140
142
 
141
143
  globalThis.describe("deriveServerCapability — inferred keys reach the SDL surface", () => {
142
144
  globalThis.test("an inferred key yields an eq filter and a sort field", () => {
143
- let schema = S.schema(s => ({
144
- orderId: s.m(S.string),
145
- total: s.m(S.float)
145
+ let schema = Sury.$schema(s => ({
146
+ orderId: s.m(Sury.string),
147
+ total: s.m(Sury.float)
146
148
  }));
147
149
  let c = GraphQL_FragmentGenerator$ReventlessCore.deriveServerCapability("Orders", schema);
148
150
  globalThis.expect(c.filterFields.map(f => f.name)).toEqual(["orderId"]);
149
151
  globalThis.expect(c.sortFields).toEqual(["orderId"]);
150
152
  });
151
153
  globalThis.test("an unresolvable key still yields nothing — the old behaviour, now narrowed", () => {
152
- let schema = S.schema(s => ({
153
- email: s.m(S.string)
154
+ let schema = Sury.$schema(s => ({
155
+ email: s.m(Sury.string)
154
156
  }));
155
157
  let c = GraphQL_FragmentGenerator$ReventlessCore.deriveServerCapability("Customers", schema);
156
158
  globalThis.expect([
@@ -162,15 +164,15 @@ globalThis.describe("deriveServerCapability — inferred keys reach the SDL surf
162
164
  ]);
163
165
  });
164
166
  globalThis.test("the filter input carries the inferred key's eq field", () => {
165
- let schema = S.schema(s => ({
166
- orderId: s.m(S.string)
167
+ let schema = Sury.$schema(s => ({
168
+ orderId: s.m(Sury.string)
167
169
  }));
168
170
  let input = GraphQL_FragmentGenerator$ReventlessCore.deriveConnectionFilterType("Ordering_OrderFilter", GraphQL_FragmentGenerator$ReventlessCore.deriveServerCapability("Orders", schema));
169
171
  globalThis.expect(input.includes("orderIdEq: ID")).toBe(true);
170
172
  });
171
173
  globalThis.test("the order-by pair exists because of the inferred key", () => {
172
- let schema = S.schema(s => ({
173
- orderId: s.m(S.string)
174
+ let schema = Sury.$schema(s => ({
175
+ orderId: s.m(Sury.string)
174
176
  }));
175
177
  let types = GraphQL_FragmentGenerator$ReventlessCore.deriveConnectionOrderByType("Ordering_Order", GraphQL_FragmentGenerator$ReventlessCore.deriveServerCapability("Orders", schema));
176
178
  globalThis.expect(types.length).toBe(2);
@@ -178,15 +180,15 @@ globalThis.describe("deriveServerCapability — inferred keys reach the SDL surf
178
180
  });
179
181
  });
180
182
 
181
- let commandSchema$1 = S.union([
182
- S.schema(s => ({
183
+ let commandSchema$1 = Sury.union([
184
+ Sury.$schema(s => ({
183
185
  TAG: "AddProduct",
184
- productId: s.m(S.string),
186
+ productId: s.m(Sury.string),
185
187
  price: s.m(Money$Reventless.schema)
186
188
  })),
187
- S.schema(s => ({
189
+ Sury.$schema(s => ({
188
190
  TAG: "ArchiveProduct",
189
- productId: s.m(S.string)
191
+ productId: s.m(Sury.string)
190
192
  }))
191
193
  ]);
192
194
 
@@ -199,15 +201,15 @@ let AddProductCmd = {
199
201
  commandAuthorization: commandAuthorization$1
200
202
  };
201
203
 
202
- let commandSchema$2 = S.union([
203
- S.schema(s => ({
204
+ let commandSchema$2 = Sury.union([
205
+ Sury.$schema(s => ({
204
206
  TAG: "ChangeProductPrice",
205
- productId: s.m(S.string),
207
+ productId: s.m(Sury.string),
206
208
  price: s.m(Money$Reventless.schema)
207
209
  })),
208
- S.schema(s => ({
210
+ Sury.$schema(s => ({
209
211
  TAG: "ClearProductPrice",
210
- productId: s.m(S.string)
212
+ productId: s.m(Sury.string)
211
213
  }))
212
214
  ]);
213
215
 
@@ -244,8 +246,8 @@ globalThis.describe("semantic composites are named once, not once per field", ()
244
246
  globalThis.expect(fragmentTypes.some(t => t.includes("AddProductPrice"))).toBe(false);
245
247
  });
246
248
  globalThis.test("the output position keeps the bare name", () => {
247
- let types = GraphQL_FragmentGenerator$ReventlessCore.deriveObjectTypeWithNested("Catalog_Product", undefined, false, S.schema(s => ({
248
- productId: s.m(S.string),
249
+ let types = GraphQL_FragmentGenerator$ReventlessCore.deriveObjectTypeWithNested("Catalog_Product", undefined, false, Sury.$schema(s => ({
250
+ productId: s.m(Sury.string),
249
251
  price: s.m(Money$Reventless.schema)
250
252
  })));
251
253
  globalThis.expect([
@@ -260,17 +262,17 @@ globalThis.describe("semantic composites are named once, not once per field", ()
260
262
  });
261
263
  });
262
264
 
263
- let shippingMethodSchema = S.union([
264
- S.literal("Standard"),
265
- S.literal("Express")
265
+ let shippingMethodSchema = Sury.union([
266
+ Sury.literal("Standard"),
267
+ Sury.literal("Express")
266
268
  ]);
267
269
 
268
- let schema = S.schema(s => ({
269
- orderId: s.m(S.string),
270
+ let schema = Sury.$schema(s => ({
271
+ orderId: s.m(Sury.string),
270
272
  shippingMethod: s.m(shippingMethodSchema),
271
273
  total: s.m(Money$Reventless.schema),
272
- tip: s.m(S.option(Money$Reventless.schema)),
273
- itemCount: s.m(S.int)
274
+ tip: s.m(Sury.$option(Money$Reventless.schema)),
275
+ itemCount: s.m(Sury.int)
274
276
  }));
275
277
 
276
278
  let PlaceOrder = {
@@ -322,9 +324,9 @@ globalThis.describe("GraphQL_FragmentGenerator.mutationArgTypes", () => {
322
324
  });
323
325
  });
324
326
 
325
- let stateSchema = S.schema(s => ({
326
- id: s.m(S.string),
327
- name: s.m(S.string)
327
+ let stateSchema = Sury.$schema(s => ({
328
+ id: s.m(Sury.string),
329
+ name: s.m(Sury.string)
328
330
  }));
329
331
 
330
332
  let RefDoorRow = {
@@ -427,6 +429,48 @@ globalThis.describe("the by-index door", () => {
427
429
  });
428
430
  });
429
431
 
432
+ globalThis.describe("@internal keeps a field off the generated type", () => {
433
+ let types = excludeFields => GraphQL_FragmentGenerator$ReventlessCore.deriveObjectTypeWithNested("Platform_Widget", excludeFields, undefined, PsInternalFieldsReadModel$ReventlessCore.stateSchema).join("\n");
434
+ globalThis.test("the declared fields are absent", () => {
435
+ globalThis.expect([
436
+ types(undefined).includes("eventCollector"),
437
+ types(undefined).includes("extensionNames")
438
+ ]).toEqual([
439
+ false,
440
+ false
441
+ ]);
442
+ });
443
+ globalThis.test("and everything else is untouched", () => {
444
+ globalThis.expect([
445
+ types(undefined).includes("name"),
446
+ types(undefined).includes("itemId")
447
+ ]).toEqual([
448
+ true,
449
+ true
450
+ ]);
451
+ });
452
+ globalThis.test("a caller's excludeFields still applies alongside", () => {
453
+ let sdl = types(["name"]);
454
+ globalThis.expect([
455
+ sdl.includes("name"),
456
+ sdl.includes("eventCollector")
457
+ ]).toEqual([
458
+ false,
459
+ false
460
+ ]);
461
+ });
462
+ globalThis.test("the published state schema drops them too", () => {
463
+ let json = JSON.stringify(SuryToJsonSchema$ReventlessCore.deriveObjectSchema(PsInternalFieldsReadModel$ReventlessCore.stateSchema));
464
+ globalThis.expect([
465
+ json.includes("eventCollector"),
466
+ json.includes("name")
467
+ ]).toEqual([
468
+ false,
469
+ true
470
+ ]);
471
+ });
472
+ });
473
+
430
474
  export {
431
475
  OrderSliceCmd,
432
476
  mutationFor,
@@ -0,0 +1,21 @@
1
+ // Fixture for `@internal`: a state record whose storage shape and API shape
2
+ // differ. `eventCollector` and `extensionNames` are projected and stored and
3
+ // belong on no generated surface; everything else is ordinary.
4
+ //
5
+ // A spec file rather than a module inside the test, and named `*ReadModel*`
6
+ // deliberately: the annotation machinery runs under `@@reventless.spec` AND only
7
+ // for a file the PPX recognises as a read model or state view. That is also the
8
+ // honest scope for `@internal` — it describes a read model's state.
9
+
10
+ @@reventless.spec("InternalFieldsReadModel")
11
+
12
+ @schema
13
+ type consumedEvent = ItemRecorded({itemId: string, name: string})
14
+
15
+ @schema
16
+ type state = {
17
+ @id itemId: string,
18
+ name: string,
19
+ @internal eventCollector: string,
20
+ @internal extensionNames: array<string>,
21
+ }
@@ -0,0 +1,74 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+ import * as Sury from "sury";
4
+ import * as ReadModel$Reventless from "@reventlessdev/reventless-spec/src/components/ReadModel.res.mjs";
5
+ import * as StateAnnotations$Reventless from "@reventlessdev/reventless-spec/src/components/StateAnnotations.res.mjs";
6
+
7
+ let consumedEventSchema = Sury.$schema(s => ({
8
+ TAG: "ItemRecorded",
9
+ itemId: s.m(Sury.string),
10
+ name: s.m(Sury.string)
11
+ }));
12
+
13
+ let stateSchema = Sury.$schema(s => ({
14
+ itemId: s.m(Sury.string),
15
+ name: s.m(Sury.string),
16
+ eventCollector: s.m(Sury.string),
17
+ extensionNames: s.m(Sury.array(Sury.string))
18
+ }));
19
+
20
+ let config = ReadModel$Reventless.config(undefined, undefined, undefined);
21
+
22
+ let makeId = (state => state.itemId);
23
+
24
+ let stateSchema$1 = Sury.$Metadata_set(stateSchema, StateAnnotations$Reventless.stateAnnotationsId, {
25
+ ids: ["itemId"],
26
+ compositeIds: [],
27
+ subIds: [],
28
+ compositeSubIds: [],
29
+ indexes: [],
30
+ hidden: [],
31
+ summary: [],
32
+ internal: [
33
+ "eventCollector",
34
+ "extensionNames"
35
+ ],
36
+ drillTargets: [],
37
+ drillTargetKeys: [],
38
+ collapsed: [],
39
+ scan: [],
40
+ scanSort: [],
41
+ semantic: [],
42
+ metric: [],
43
+ lifecycle: undefined,
44
+ groupBy: undefined,
45
+ visibility: undefined,
46
+ live: undefined,
47
+ retired: undefined
48
+ });
49
+
50
+ let name = "InternalFieldsReadModel";
51
+
52
+ let Id;
53
+
54
+ let subIdConfig;
55
+
56
+ let moduleUrl = "@reventlessdev/reventless-core/tests/api/PsInternalFieldsReadModel.res.mjs";
57
+
58
+ let authorization = "AllowAuthenticated";
59
+
60
+ let visibility = "Public";
61
+
62
+ export {
63
+ name,
64
+ Id,
65
+ consumedEventSchema,
66
+ config,
67
+ subIdConfig,
68
+ makeId,
69
+ stateSchema$1 as stateSchema,
70
+ moduleUrl,
71
+ authorization,
72
+ visibility,
73
+ }
74
+ /* consumedEventSchema Not a pure module */
@@ -1,12 +1,12 @@
1
1
  // Generated by ReScript, PLEASE EDIT WITH CARE
2
2
 
3
- import * as S from "sury/src/S.res.mjs";
3
+ import * as Sury from "sury";
4
4
  import * as StorageRef$Reventless from "@reventlessdev/reventless-spec/src/semantic/StorageRef.res.mjs";
5
5
  import * as StorageRefFields$ReventlessCore from "../../src/components/Api/StorageRefFields.res.mjs";
6
6
 
7
7
  function variant(tag, fields) {
8
- return S.object(s => {
9
- s.f("TAG", S.literal(tag));
8
+ return Sury.object(s => {
9
+ s.f("TAG", Sury.literal(tag));
10
10
  fields.forEach(param => {
11
11
  s.f(param[0], param[1]);
12
12
  });
@@ -17,7 +17,7 @@ let ref_ = StorageRef$Reventless.forStore;
17
17
 
18
18
  globalThis.describe("StorageRefFields.fromEventSchema", () => {
19
19
  globalThis.test("finds a declared single-valued ref field and qualifies its store", () => {
20
- let schema = S.union([variant("ProductImageChanged", [[
20
+ let schema = Sury.union([variant("ProductImageChanged", [[
21
21
  "imageUrl",
22
22
  StorageRef$Reventless.forStore(undefined, "productImages")
23
23
  ]])]);
@@ -31,16 +31,16 @@ globalThis.describe("StorageRefFields.fromEventSchema", () => {
31
31
  }]);
32
32
  });
33
33
  globalThis.test("a qualified declaration keeps the store it names", () => {
34
- let schema = S.union([variant("OrderPhotoAttached", [[
34
+ let schema = Sury.union([variant("OrderPhotoAttached", [[
35
35
  "photo",
36
36
  StorageRef$Reventless.forStore("Catalog", "productImages")
37
37
  ]])]);
38
38
  globalThis.expect(StorageRefFields$ReventlessCore.fromEventSchema("Ordering", schema).flatMap(e => e.fields.map(f => f.store))).toEqual(["Catalog.productImages"]);
39
39
  });
40
40
  globalThis.test("finds a multi-valued ref field and records its arity", () => {
41
- let schema = S.union([variant("GalleryReplaced", [[
41
+ let schema = Sury.union([variant("GalleryReplaced", [[
42
42
  "imageUrls",
43
- S.array(StorageRef$Reventless.forStore(undefined, "productImages"))
43
+ Sury.array(StorageRef$Reventless.forStore(undefined, "productImages"))
44
44
  ]])]);
45
45
  globalThis.expect(StorageRefFields$ReventlessCore.fromEventSchema("Catalog", schema).flatMap(e => e.fields)).toEqual([{
46
46
  field: "imageUrls",
@@ -49,10 +49,10 @@ globalThis.describe("StorageRefFields.fromEventSchema", () => {
49
49
  }]);
50
50
  });
51
51
  globalThis.test("a variant with no declared field is omitted entirely", () => {
52
- let schema = S.union([
52
+ let schema = Sury.union([
53
53
  variant("ProductRenamed", [[
54
54
  "name",
55
- S.string
55
+ Sury.string
56
56
  ]]),
57
57
  variant("ProductImageChanged", [[
58
58
  "imageUrl",
@@ -62,16 +62,16 @@ globalThis.describe("StorageRefFields.fromEventSchema", () => {
62
62
  globalThis.expect(StorageRefFields$ReventlessCore.fromEventSchema("Catalog", schema).map(e => e.eventType)).toEqual(["ProductImageChanged"]);
63
63
  });
64
64
  globalThis.test("an event schema with no declaration anywhere yields nothing", () => {
65
- let schema = S.union([variant("ProductRenamed", [[
65
+ let schema = Sury.union([variant("ProductRenamed", [[
66
66
  "name",
67
- S.string
67
+ Sury.string
68
68
  ]])]);
69
69
  globalThis.expect(StorageRefFields$ReventlessCore.fromEventSchema("Catalog", schema)).toEqual([]);
70
70
  });
71
71
  globalThis.test("an unannotated string field is not treated as a ref", () => {
72
- let schema = S.union([variant("ProductImported", [[
72
+ let schema = Sury.union([variant("ProductImported", [[
73
73
  "imageUrl",
74
- S.string
74
+ Sury.string
75
75
  ]])]);
76
76
  globalThis.expect(StorageRefFields$ReventlessCore.fromEventSchema("Catalog", schema)).toEqual([]);
77
77
  });
@@ -256,6 +256,49 @@ describe("SuryToJsonSchema:", () => {
256
256
  ))->toEqual((Some(true), None))
257
257
  })
258
258
 
259
+ // `@internal` drops the property rather than marking it. A marker is the
260
+ // right answer for a field that is on the surface and merely unwanted — that
261
+ // is `@hidden`, above. This one is not on the surface at all, so an entry
262
+ // here would describe a field the SDL does not declare, which is the
263
+ // mismatch that makes a generated list query name fields the server rejects.
264
+ testSync("drops a field listed in internal rather than annotating it", () => {
265
+ let schema = S.schema(s =>
266
+ {
267
+ "id": s.matches(S.string),
268
+ "eventCollector": s.matches(S.string),
269
+ }
270
+ )->S.castToUnknown
271
+ let schema' = schema->withSpec({...emptySpec, internal: ["eventCollector"]})
272
+ let json = SuryToJsonSchema.deriveObjectSchema(schema')
273
+ expect((
274
+ getPropertyOf(json, "eventCollector")->Option.isNone,
275
+ getPropertyOf(json, "id")->Option.isSome,
276
+ ))->toEqual((true, true))
277
+ })
278
+
279
+ // A dropped property must not be left behind in `required`, or a consumer
280
+ // building a form from the schema asks for a field it was never given.
281
+ testSync("keeps a dropped field out of required", () => {
282
+ let schema = S.schema(s =>
283
+ {
284
+ "id": s.matches(S.string),
285
+ "eventCollector": s.matches(S.string),
286
+ }
287
+ )->S.castToUnknown
288
+ let json =
289
+ schema
290
+ ->withSpec({...emptySpec, internal: ["eventCollector"]})
291
+ ->SuryToJsonSchema.deriveObjectSchema
292
+ expect(
293
+ json
294
+ ->JSON.Decode.object
295
+ ->Option.flatMap(o => o->Dict.get("required"))
296
+ ->Option.flatMap(JSON.Decode.array)
297
+ ->Option.getOr([])
298
+ ->Array.filterMap(JSON.Decode.string),
299
+ )->toEqual(["id"])
300
+ })
301
+
259
302
  testSync("emits x-reventless-summary on field listed in summary", () => {
260
303
  let schema = S.schema(s =>
261
304
  {