@reventlessdev/reventless-local 3.0.0-alpha.226 → 3.0.0-alpha.228

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 (84) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/package.json +14 -14
  3. package/src/LocalPlatformRegistry.res +2 -2
  4. package/src/LocalPlatformRegistry.res.mjs +14 -13
  5. package/src/Platform.res +14 -15
  6. package/src/Platform.res.mjs +20 -21
  7. package/src/adapter/Auth/LocalAuth.res +3 -3
  8. package/src/adapter/Auth/LocalAuth.res.mjs +3 -2
  9. package/src/adapter/Auth/UserStore.res +1 -1
  10. package/src/adapter/Auth/UserStore.res.mjs +7 -6
  11. package/src/adapter/CommandGenerator/CommandGeneratorResolvers_GraphQL.res +1 -1
  12. package/src/adapter/CommandGenerator/CommandGeneratorResolvers_GraphQL.res.mjs +1 -1
  13. package/src/adapter/CommandTopic/LocalCommandTopicRemoteChannel.res +1 -1
  14. package/src/adapter/CommandTopic/LocalCommandTopicRemoteChannel.res.mjs +3 -3
  15. package/src/adapter/DcbEventLog/DcbEventLogStorage_Sqlite.res +2 -2
  16. package/src/adapter/DcbEventLog/DcbEventLogStorage_Sqlite.res.mjs +4 -4
  17. package/src/adapter/DomainGraphQL_Server.res +2 -2
  18. package/src/adapter/DomainGraphQL_Server.res.mjs +3 -3
  19. package/src/adapter/DomainMCP_Server.res +1 -1
  20. package/src/adapter/MCP_ServerInstance.res +1 -1
  21. package/src/adapter/QueryDb/QueryDbResolvers_GraphQL.res +223 -22
  22. package/src/adapter/QueryDb/QueryDbResolvers_GraphQL.res.mjs +176 -18
  23. package/tests/BakedManifestFilesTest.res +0 -1
  24. package/tests/PluginEventDecodeTest.res +3 -3
  25. package/tests/PluginEventDecodeTest.res.mjs +4 -4
  26. package/tests/ShellConfigTest.res +0 -1
  27. package/tests/UiHintsTest.res +33 -6
  28. package/tests/UiHintsTest.res.mjs +15 -2
  29. package/tests/adapter/CommandAuthorizationTest.res.mjs +7 -7
  30. package/tests/adapter/GraphQL_SchemaInspectorTest.res +9 -7
  31. package/tests/adapter/GraphQL_SchemaInspectorTest.res.mjs +64 -64
  32. package/tests/adapter/LocalAuthHttpTest.res +1 -1
  33. package/tests/adapter/LocalAuthHttpTest.res.mjs +2 -2
  34. package/tests/adapter/QueryDbListResolverTest.res +82 -2
  35. package/tests/adapter/QueryDbListResolverTest.res.mjs +111 -16
  36. package/tests/components/aggregate/AggregateFixtures.res.mjs +6 -6
  37. package/tests/components/automationslice/AutomationSliceFixtures.res +4 -4
  38. package/tests/components/automationslice/AutomationSliceFixtures.res.mjs +20 -19
  39. package/tests/components/automationslice/AutomationSliceSelfDeadlockFixtures.res +2 -2
  40. package/tests/components/automationslice/AutomationSliceSelfDeadlockFixtures.res.mjs +23 -22
  41. package/tests/components/automationslice/MixedSourceAutomationSliceFixtures.res +4 -4
  42. package/tests/components/automationslice/MixedSourceAutomationSliceFixtures.res.mjs +21 -20
  43. package/tests/components/commandgenerator/CommandGeneratorFixtures.res +0 -1
  44. package/tests/components/commandgenerator/CommandGeneratorFixtures.res.mjs +6 -8
  45. package/tests/components/commandgenerator/CommandGeneratorTest.res +1 -1
  46. package/tests/components/commandgenerator/CommandGeneratorTest.res.mjs +2 -2
  47. package/tests/components/commandtopic/CommandTopicFixtures.res.mjs +9 -9
  48. package/tests/components/commandtopic/CommandTopicStreamFixtures.res.mjs +9 -9
  49. package/tests/components/dcb/DcbCrossPartitionFixtures.res +3 -3
  50. package/tests/components/dcb/DcbCrossPartitionFixtures.res.mjs +22 -21
  51. package/tests/components/dcb/DcbEventLogAppendStreamTest.res +1 -1
  52. package/tests/components/dcb/DcbEventLogAppendStreamTest.res.mjs +2 -2
  53. package/tests/components/dcb/DcbFixtures.res +2 -2
  54. package/tests/components/dcb/DcbFixtures.res.mjs +12 -11
  55. package/tests/components/eventlog/EventLogFixtures.res.mjs +6 -6
  56. package/tests/components/eventlog/EventLogProvisioningSeamTest.res.mjs +3 -3
  57. package/tests/components/eventtopic/EventTopicFixtures.res.mjs +6 -6
  58. package/tests/components/eventtopic/EventTopicStreamFixtures.res.mjs +6 -6
  59. package/tests/components/extensionpoint/ExtensionPointFixtures.res +0 -1
  60. package/tests/components/extensionpoint/ExtensionPointFixtures.res.mjs +11 -13
  61. package/tests/components/extensionpoint/ExtensionPointTest.res +3 -3
  62. package/tests/components/extensionpoint/ExtensionPointTest.res.mjs +4 -4
  63. package/tests/components/inboundtranslationslice/InboundTranslationSliceCallbackTest.res.mjs +10 -10
  64. package/tests/components/inboundtranslationslice/InboundTranslationSliceFixtures.res.mjs +9 -9
  65. package/tests/components/outboundtranslationslice/OutboundTranslationSliceFixtures.res.mjs +23 -21
  66. package/tests/components/outboundtranslationslice/OutboundTranslationSlicePlatformFixtures.res +2 -2
  67. package/tests/components/outboundtranslationslice/OutboundTranslationSlicePlatformFixtures.res.mjs +17 -14
  68. package/tests/components/querydb/QueryDbFixtures.res.mjs +4 -4
  69. package/tests/components/querydb/QueryDbSubIdFixtures.res.mjs +6 -6
  70. package/tests/components/readmodel/DcbReadModelE2EFixtures.res +3 -3
  71. package/tests/components/readmodel/DcbReadModelE2EFixtures.res.mjs +17 -16
  72. package/tests/components/readmodel/DcbReadModelTypoFailFastTest.res.mjs +7 -7
  73. package/tests/components/readmodel/MixedSourceReadModelFixtures.res +5 -5
  74. package/tests/components/readmodel/MixedSourceReadModelFixtures.res.mjs +20 -19
  75. package/tests/components/readmodel/ReadModelFixtures.res +3 -3
  76. package/tests/components/readmodel/ReadModelFixtures.res.mjs +9 -8
  77. package/tests/components/sideeffecthandler/SideEffectHandlerFixtures.res +2 -3
  78. package/tests/components/sideeffecthandler/SideEffectHandlerFixtures.res.mjs +7 -8
  79. package/tests/components/stateviewslice/StateViewSliceFixtures.res +2 -2
  80. package/tests/components/stateviewslice/StateViewSliceFixtures.res.mjs +22 -21
  81. package/tests/components/stateviewslice/StateViewSliceSubIdFixtures.res +2 -2
  82. package/tests/components/stateviewslice/StateViewSliceSubIdFixtures.res.mjs +27 -26
  83. package/tests/components/task/TaskFixtures.res +0 -1
  84. package/tests/components/task/TaskFixtures.res.mjs +0 -3
@@ -16,7 +16,6 @@ let keysOf = (config: ReventlessInfra.Platform.bakedManifest) =>
16
16
  BakedManifest.files(~config)->Array.map(((key, _)) => key)
17
17
 
18
18
  describe("BakedManifest.files", () => {
19
- open Expect
20
19
 
21
20
  // The regression line: one declaration, one file, under the name every
22
21
  // existing deployment's config.json already points at.
@@ -16,7 +16,7 @@ let envelopeOf = (event: ReventlessCore.PluginSpec.event) =>
16
16
  "Catalog",
17
17
  meta,
18
18
  ~recordedAt="2024-01-01T00:00:00Z",
19
- event->S.reverseConvertToJsonOrThrow(ReventlessCore.PluginSpec.eventSchema),
19
+ event->Reventless.Util_Sury.toJson(ReventlessCore.PluginSpec.eventSchema),
20
20
  )
21
21
 
22
22
  describe("Platform.decodePluginEventEnvelope", () => {
@@ -38,7 +38,7 @@ describe("Platform.decodePluginEventEnvelope", () => {
38
38
  testSync("returns None for a bare event JSON (no envelope) and malformed input", () => {
39
39
  // The old bug class: input that is not the {id, meta, event} envelope.
40
40
  let bare =
41
- ReventlessCore.PluginSpec.VersionDetected("2.0.0")->S.reverseConvertToJsonOrThrow(
41
+ ReventlessCore.PluginSpec.VersionDetected("2.0.0")->Reventless.Util_Sury.toJson(
42
42
  ReventlessCore.PluginSpec.eventSchema,
43
43
  )
44
44
  expect(Platform.decodePluginEventEnvelope(bare))->toEqual(None)
@@ -64,7 +64,7 @@ describe("Platform.decodeUiFragmentRegistryEventEnvelope", () => {
64
64
  }
65
65
 
66
66
  let dcbEnvelopeOf = (event: ReventlessCore.UiFragmentRegistry.event) => {
67
- let json = event->S.reverseConvertToJsonOrThrow(ReventlessCore.UiFragmentRegistry.eventSchema)
67
+ let json = event->Reventless.Util_Sury.toJson(ReventlessCore.UiFragmentRegistry.eventSchema)
68
68
  let (eventType, data) = json->ReventlessCore.Message.splitMessage
69
69
  ReventlessCore.Message.composeEventJson'(
70
70
  "Catalog",
@@ -1,6 +1,6 @@
1
1
  // Generated by ReScript, PLEASE EDIT WITH CARE
2
2
 
3
- import * as S from "sury/src/S.res.mjs";
3
+ import * as Util_Sury$Reventless from "@reventlessdev/reventless-spec/src/util/Util_Sury.res.mjs";
4
4
  import * as Message$ReventlessCore from "@reventlessdev/reventless-core/src/Message.res.mjs";
5
5
  import * as Platform$ReventlessLocal from "../src/Platform.res.mjs";
6
6
  import * as PluginSpec$ReventlessCore from "@reventlessdev/reventless-core/src/plugin/lifecycle/PluginSpec.res.mjs";
@@ -15,7 +15,7 @@ TestRunner$ReventlessLocal.setup();
15
15
  let meta = Message$ReventlessCore.generateMeta(PluginSpec$ReventlessCore.name, undefined, undefined, undefined, undefined, undefined, undefined, undefined);
16
16
 
17
17
  function envelopeOf(event) {
18
- return Message$ReventlessCore.composeEventJson$p("Catalog", meta, "2024-01-01T00:00:00Z", S.reverseConvertToJsonOrThrow(event, PluginSpec$ReventlessCore.eventSchema));
18
+ return Message$ReventlessCore.composeEventJson$p("Catalog", meta, "2024-01-01T00:00:00Z", Util_Sury$Reventless.toJson(event, PluginSpec$ReventlessCore.eventSchema));
19
19
  }
20
20
 
21
21
  globalThis.describe("Platform.decodePluginEventEnvelope", () => {
@@ -46,7 +46,7 @@ globalThis.describe("Platform.decodePluginEventEnvelope", () => {
46
46
  });
47
47
  });
48
48
  globalThis.test("returns None for a bare event JSON (no envelope) and malformed input", () => {
49
- let bare = S.reverseConvertToJsonOrThrow({
49
+ let bare = Util_Sury$Reventless.toJson({
50
50
  TAG: "VersionDetected",
51
51
  _0: "2.0.0"
52
52
  }, PluginSpec$ReventlessCore.eventSchema);
@@ -62,7 +62,7 @@ globalThis.describe("Platform.decodePluginEventEnvelope", () => {
62
62
  globalThis.describe("Platform.decodeUiFragmentRegistryEventEnvelope", () => {
63
63
  let dcbMeta = Message$ReventlessCore.generateMeta(ComponentType$ReventlessCore.name(Platform_Admin_Structure$ReventlessCore.pluginId, "DcbEventLog"), undefined, undefined, undefined, undefined, undefined, undefined, undefined);
64
64
  let dcbEnvelopeOf = event => {
65
- let json = S.reverseConvertToJsonOrThrow(event, UiFragmentRegistry$ReventlessCore.eventSchema);
65
+ let json = Util_Sury$Reventless.toJson(event, UiFragmentRegistry$ReventlessCore.eventSchema);
66
66
  let match = Message$ReventlessCore.splitMessage(json);
67
67
  return Message$ReventlessCore.composeEventJson$p("Catalog", dcbMeta, "2024-01-01T00:00:00Z", Message$ReventlessCore.combineMessage(match[0], match[1]));
68
68
  };
@@ -167,7 +167,6 @@ let fulfilment: ReventlessInfra.Platform.bakedJourney = {
167
167
  }
168
168
 
169
169
  describe("ShellConfig.overlay — journeys", () => {
170
- open Expect
171
170
 
172
171
  // The regression line. A shell that has never heard of journeys must not
173
172
  // suddenly find a key it does not know.
@@ -103,30 +103,54 @@ describe("UiHints.emit", () => {
103
103
  // point, while mid-session it is almost always an editor mid-save, and killing a
104
104
  // running dev server over a keystroke is worse than the restart this replaces.
105
105
 
106
- // Both exits close the watcher AND clear the deadline. A watcher is `unref`ed
106
+ // The edit is repeated, and that is not belt-and-braces.
107
+ //
108
+ // `fs.watch` does not promise that a write landing near the watcher's creation
109
+ // is reported. The FSEvents stream behind it on macOS is armed asynchronously,
110
+ // and a write that gets there first is not reported late — it is not reported at
111
+ // all. Measured against this very module: once the stream is up the edit is seen
112
+ // in about 10ms, and when it is not, the same edit produces no event in four
113
+ // seconds, with which of the two happens varying by how many watchers the
114
+ // process has already opened rather than by anything the test does.
115
+ //
116
+ // So a single edit tests the arming, not the reload. Repeating it on an interval
117
+ // far longer than a reload takes — 50ms of debounce plus a file copy — leaves the
118
+ // case where the first write lands identical to what it always was, and lets the
119
+ // case where it is dropped recover on the next one instead of reporting that hot
120
+ // reload is broken. Re-writing the same bytes is what a developer saving twice
121
+ // does, so nothing here asserts less than it did.
122
+ let retryEvery = 1000
123
+
124
+ // All three exits close the watcher AND clear both timers. A watcher is `unref`ed
107
125
  // and would not hold the run open on its own, but a live 4-second timer would —
108
126
  // and "Jest did not exit" on a suite that passed is exactly the noise that
109
127
  // teaches a reader to ignore it.
110
- let waitForReload = (~timeoutMs: int=4000, ~afterWatching: unit => unit, ~uiHintsFile, ~dir) =>
128
+ let waitForReload = (~timeoutMs: int=4000, ~edit: unit => unit, ~uiHintsFile, ~dir) =>
111
129
  Promise.make((resolve, _) => {
112
130
  let fired = ref(0)
113
131
  let watcher = ref(None)
114
132
  let deadline = ref(None)
133
+ let retry = ref(None)
115
134
  // Resolves with a count rather than rejecting on the deadline: "nothing was
116
135
  // re-served" is the expected answer in half these cases, and a rejection
117
136
  // would make the assertion read as an infrastructure failure.
118
137
  let finish = () => {
119
138
  watcher.contents->Option.forEach(NodeFs.watcherClose)
120
139
  deadline.contents->Option.forEach(clearTimeout)
140
+ retry.contents->Option.forEach(clearTimeout)
121
141
  resolve(fired.contents)
122
142
  }
143
+ let rec editUntilSeen = () => {
144
+ edit()
145
+ retry := Some(setTimeout(editUntilSeen, retryEvery))
146
+ }
123
147
  watcher :=
124
148
  UiHints.watch(~uiHintsFile, ~dir, ~onReload=() => {
125
149
  fired := fired.contents + 1
126
150
  finish()
127
151
  })
128
152
  deadline := Some(setTimeout(finish, timeoutMs))
129
- afterWatching()
153
+ editUntilSeen()
130
154
  })
131
155
 
132
156
  describe("UiHints.watch", () => {
@@ -147,7 +171,7 @@ describe("UiHints.watch", () => {
147
171
  let fired = await waitForReload(
148
172
  ~uiHintsFile=Some(path),
149
173
  ~dir,
150
- ~afterWatching=() => NodeFs.writeFileSync(path, edited),
174
+ ~edit=() => NodeFs.writeFileSync(path, edited),
151
175
  )
152
176
  expect((fired > 0, served(dir)))->toEqual((true, edited))
153
177
  })
@@ -163,7 +187,7 @@ describe("UiHints.watch", () => {
163
187
  ~timeoutMs=1500,
164
188
  ~uiHintsFile=Some(path),
165
189
  ~dir,
166
- ~afterWatching=() => NodeFs.writeFileSync(path, `{"Catalog": {"views":`),
190
+ ~edit=() => NodeFs.writeFileSync(path, `{"Catalog": {"views":`),
167
191
  )
168
192
  expect((fired, served(dir)))->toEqual((0, declared))
169
193
  })
@@ -178,7 +202,10 @@ describe("UiHints.watch", () => {
178
202
  let fired = await waitForReload(
179
203
  ~uiHintsFile=Some(path),
180
204
  ~dir,
181
- ~afterWatching=() => {
205
+ // Both halves of the save, so a repeat of this edit is the same story told
206
+ // again and still ends on the whole file — never a truncated write left
207
+ // standing after a complete one.
208
+ ~edit=() => {
182
209
  NodeFs.writeFileSync(path, `{"Catalog": {"views":`)
183
210
  let _ = setTimeout(() => NodeFs.writeFileSync(path, whole), 200)
184
211
  },
@@ -88,7 +88,7 @@ globalThis.describe("UiHints.emit", () => {
88
88
  });
89
89
  });
90
90
 
91
- function waitForReload(timeoutMsOpt, afterWatching, uiHintsFile, dir) {
91
+ function waitForReload(timeoutMsOpt, edit, uiHintsFile, dir) {
92
92
  let timeoutMs = timeoutMsOpt !== undefined ? timeoutMsOpt : 4000;
93
93
  return new Promise((resolve, param) => {
94
94
  let fired = {
@@ -100,6 +100,9 @@ function waitForReload(timeoutMsOpt, afterWatching, uiHintsFile, dir) {
100
100
  let deadline = {
101
101
  contents: undefined
102
102
  };
103
+ let retry = {
104
+ contents: undefined
105
+ };
103
106
  let finish = () => {
104
107
  Stdlib_Option.forEach(watcher.contents, prim => {
105
108
  prim.close();
@@ -107,14 +110,21 @@ function waitForReload(timeoutMsOpt, afterWatching, uiHintsFile, dir) {
107
110
  Stdlib_Option.forEach(deadline.contents, prim => {
108
111
  clearTimeout(prim);
109
112
  });
113
+ Stdlib_Option.forEach(retry.contents, prim => {
114
+ clearTimeout(prim);
115
+ });
110
116
  resolve(fired.contents);
111
117
  };
118
+ let editUntilSeen = () => {
119
+ edit();
120
+ retry.contents = Primitive_option.some(setTimeout(editUntilSeen, 1000));
121
+ };
112
122
  watcher.contents = UiHints$ReventlessLocal.watch(uiHintsFile, dir, () => {
113
123
  fired.contents = fired.contents + 1 | 0;
114
124
  finish();
115
125
  });
116
126
  deadline.contents = Primitive_option.some(setTimeout(finish, timeoutMs));
117
- afterWatching();
127
+ editUntilSeen();
118
128
  });
119
129
  }
120
130
 
@@ -178,6 +188,8 @@ globalThis.describe("UiHints.watch", () => {
178
188
  });
179
189
  });
180
190
 
191
+ let retryEvery = 1000;
192
+
181
193
  export {
182
194
  shipped,
183
195
  declared,
@@ -187,6 +199,7 @@ export {
187
199
  served,
188
200
  baselinePath,
189
201
  threw,
202
+ retryEvery,
190
203
  waitForReload,
191
204
  }
192
205
  /* Not a pure module */
@@ -1,6 +1,6 @@
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_JSON from "@rescript/runtime/lib/es6/Stdlib_JSON.js";
5
5
  import * as Stdlib_JsExn from "@rescript/runtime/lib/es6/Stdlib_JsExn.js";
6
6
  import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
@@ -15,16 +15,16 @@ import * as CommandGeneratorResolvers_GraphQL$ReventlessLocal from "../../src/ad
15
15
 
16
16
  TestRunner$ReventlessLocal.setup();
17
17
 
18
- let commandSchema = S.union([
19
- S.schema(s => ({
18
+ let commandSchema = Sury.union([
19
+ Sury.$schema(s => ({
20
20
  TAG: "Add",
21
- name: s.m(S.string)
21
+ name: s.m(Sury.string)
22
22
  })),
23
- S.schema(s => ({
23
+ Sury.$schema(s => ({
24
24
  TAG: "Rename",
25
- name: s.m(S.string)
25
+ name: s.m(Sury.string)
26
26
  })),
27
- S.literal("Archive")
27
+ Sury.literal("Archive")
28
28
  ]);
29
29
 
30
30
  function commandAuthorization(cmd) {
@@ -271,7 +271,7 @@ describe("GraphQL_SchemaInspector", () => {
271
271
  expect(result.typeDef->Option.isSome)->toBe(true)
272
272
  let typeDef = result.typeDef->Option.getOrThrow
273
273
  expect(typeDef->String.includes("type CatalogProduct"))->toBe(true)
274
- expect(result.singleQuery->String.includes("Catalog_Product(id: ID!)"))->toBe(true)
274
+ expect(result.singleQuery->String.includes("Catalog_Product(id: ID!, includeRetired: Boolean)"))->toBe(true)
275
275
  expect(result.singleQuery->String.includes("CatalogProduct"))->toBe(true)
276
276
  expect(result.listQuery->Option.isSome)->toBe(true)
277
277
  let listQ = result.listQuery->Option.getOrThrow
@@ -298,7 +298,7 @@ describe("GraphQL_SchemaInspector", () => {
298
298
  )
299
299
  let inspection = ReventlessCore.GraphQL_SchemaInspector.inspectFragment(fragment)
300
300
  let sdl = inspection.sdlPreview
301
- expect(sdl->String.includes("RM_Product(id: ID!): RMProduct"))->toBe(true)
301
+ expect(sdl->String.includes("RM_Product(id: ID!, includeRetired: Boolean): RMProduct"))->toBe(true)
302
302
  expect(sdl->String.includes("type RMProduct"))->toBe(true)
303
303
  // The type should have an injected id: ID! field (first field in the type)
304
304
  let typeLines = sdl->String.split("\n")
@@ -357,7 +357,7 @@ describe("GraphQL_SchemaInspector", () => {
357
357
  )
358
358
  let inspection = ReventlessCore.GraphQL_SchemaInspector.inspectFragment(fragment)
359
359
  let sdl = inspection.sdlPreview
360
- expect(sdl->String.includes("Default_Thing(id: ID!): DefaultThing"))->toBe(true)
360
+ expect(sdl->String.includes("Default_Thing(id: ID!, includeRetired: Boolean): DefaultThing"))->toBe(true)
361
361
  })
362
362
  })
363
363
 
@@ -542,13 +542,15 @@ describe("GraphQL_SchemaInspector", () => {
542
542
  ],
543
543
  )
544
544
  let inspection = ReventlessCore.GraphQL_SchemaInspector.inspectFragment(fragment)
545
- // TestState, TestStateEdge, TestStateConnection, TestStateFilter (Phase 4 connection filter)
545
+ // TestState, TestStateEdge, TestStateConnection, TestStateFilter (connection filter)
546
+ // + TestStateRef (the reference door's projection)
546
547
  // + CommandResult union + CommandAccepted + CommandRejected + CommandPending
547
548
  // (auto-injected whenever the fragment emits any mutation field).
548
- expect(inspection.types->Array.length)->toBe(8)
549
+ expect(inspection.types->Array.length)->toBe(9)
549
550
  expect(inspection.mutations->Array.length)->toBe(1)
550
- // single Test_State(id), list Test_States(...), and Test_StatesByIds(ids: [String!]!)
551
- expect(inspection.queries->Array.length)->toBe(3)
551
+ // single Test_State(id), list Test_States(...), Test_StatesByIds(ids: [String!]!)
552
+ // and Test_StatesRefs(ids: [ID!]!) — the by-ids read projected to a reference.
553
+ expect(inspection.queries->Array.length)->toBe(4)
552
554
  expect(inspection.sdlPreview->String.includes("type TestState"))->toBe(true)
553
555
  expect(inspection.sdlPreview->String.includes("type TestStateEdge"))->toBe(true)
554
556
  expect(inspection.sdlPreview->String.includes("type TestStateConnection"))->toBe(true)
@@ -1,6 +1,6 @@
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 DcbTag$Reventless from "@reventlessdev/reventless-spec/src/components/DcbTag.res.mjs";
6
6
  import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
@@ -16,87 +16,93 @@ import * as Plugin_SubscriptionSchema$ReventlessCore from "@reventlessdev/revent
16
16
 
17
17
  TestRunner$ReventlessLocal.setup();
18
18
 
19
- let testStateSchema = S.schema(s => ({
19
+ let stringSchema = Sury.string;
20
+
21
+ let numberSchema = Sury.float;
22
+
23
+ let boolSchema = Sury.bool;
24
+
25
+ let testStateSchema = Sury.$schema(s => ({
20
26
  id: s.m(DcbTag$Reventless.string),
21
- name: s.m(S.string),
22
- price: s.m(S.float),
23
- active: s.m(S.bool)
27
+ name: s.m(Sury.string),
28
+ price: s.m(Sury.float),
29
+ active: s.m(Sury.bool)
24
30
  }));
25
31
 
26
- let svStateSchema = S.schema(s => ({
32
+ let svStateSchema = Sury.$schema(s => ({
27
33
  productId: s.m(DcbTag$Reventless.string),
28
- name: s.m(S.string),
29
- price: s.m(S.float)
34
+ name: s.m(Sury.string),
35
+ price: s.m(Sury.float)
30
36
  }));
31
37
 
32
- let sourceKindSchema = S.union([
33
- S.literal("tagged"),
34
- S.literal("ancestry"),
35
- S.literal("substrate")
38
+ let sourceKindSchema = Sury.union([
39
+ Sury.literal("tagged"),
40
+ Sury.literal("ancestry"),
41
+ Sury.literal("substrate")
36
42
  ]);
37
43
 
38
- let enumStateSchema = S.schema(s => ({
44
+ let enumStateSchema = Sury.$schema(s => ({
39
45
  productId: s.m(DcbTag$Reventless.string),
40
46
  requiredSource: s.m(sourceKindSchema),
41
- optionalSource: s.m(S.option(sourceKindSchema))
47
+ optionalSource: s.m(Sury.$option(sourceKindSchema))
42
48
  }));
43
49
 
44
- let addCommandSchema = S.schema(s => ({
50
+ let addCommandSchema = Sury.$schema(s => ({
45
51
  productId: s.m(DcbTag$Reventless.string),
46
- name: s.m(S.string)
52
+ name: s.m(Sury.string)
47
53
  }));
48
54
 
49
- let unionCommandSchema = S.union([
50
- S.schema(s => ({
55
+ let unionCommandSchema = Sury.union([
56
+ Sury.$schema(s => ({
51
57
  TAG: "Create",
52
58
  itemId: s.m(DcbTag$Reventless.string),
53
- name: s.m(S.string)
59
+ name: s.m(Sury.string)
54
60
  })),
55
- S.schema(s => ({
61
+ Sury.$schema(s => ({
56
62
  TAG: "Rename",
57
63
  itemId: s.m(DcbTag$Reventless.string),
58
- newName: s.m(S.string)
64
+ newName: s.m(Sury.string)
59
65
  }))
60
66
  ]);
61
67
 
62
- let dcbSingleCommandSchema = S.schema(s => ({
68
+ let dcbSingleCommandSchema = Sury.$schema(s => ({
63
69
  TAG: "AddCategory",
64
70
  categoryId: s.m(DcbTag$Reventless.string),
65
- name: s.m(S.string)
71
+ name: s.m(Sury.string)
66
72
  }));
67
73
 
68
- let dcbMultiCommandSchema = S.union([
69
- S.schema(s => ({
74
+ let dcbMultiCommandSchema = Sury.union([
75
+ Sury.$schema(s => ({
70
76
  TAG: "SyncNewProduct",
71
77
  productId: s.m(DcbTag$Reventless.string),
72
- name: s.m(S.string),
73
- price: s.m(S.float)
78
+ name: s.m(Sury.string),
79
+ price: s.m(Sury.float)
74
80
  })),
75
- S.schema(s => ({
81
+ Sury.$schema(s => ({
76
82
  TAG: "ChangeSyncedPrice",
77
83
  productId: s.m(DcbTag$Reventless.string),
78
- price: s.m(S.float)
84
+ price: s.m(Sury.float)
79
85
  }))
80
86
  ]);
81
87
 
82
- let plainStateSchema = S.schema(s => ({
88
+ let plainStateSchema = Sury.$schema(s => ({
83
89
  productId: s.m(DcbTag$Reventless.string),
84
- name: s.m(S.string)
90
+ name: s.m(Sury.string)
85
91
  }));
86
92
 
87
- let keylessStateSchema = S.schema(s => ({
88
- name: s.m(S.string),
89
- note: s.m(S.string)
93
+ let keylessStateSchema = Sury.$schema(s => ({
94
+ name: s.m(Sury.string),
95
+ note: s.m(Sury.string)
90
96
  }));
91
97
 
92
- let indexedStateSchema = S.schema(s => ({
98
+ let indexedStateSchema = Sury.$schema(s => ({
93
99
  productId: s.m(DcbTag$Reventless.string),
94
- ownerId: s.m(S.string),
95
- status: s.m(S.string),
96
- name: s.m(S.string)
100
+ ownerId: s.m(Sury.string),
101
+ status: s.m(Sury.string),
102
+ name: s.m(Sury.string)
97
103
  }));
98
104
 
99
- let indexedStateSchemaWithAnnotations = S.Metadata.set(indexedStateSchema, StateAnnotations$Reventless.stateAnnotationsId, {
105
+ let indexedStateSchemaWithAnnotations = Sury.$Metadata_set(indexedStateSchema, StateAnnotations$Reventless.stateAnnotationsId, {
100
106
  ids: ["productId"],
101
107
  compositeIds: [],
102
108
  subIds: [],
@@ -121,13 +127,13 @@ let indexedStateSchemaWithAnnotations = S.Metadata.set(indexedStateSchema, State
121
127
  retired: undefined
122
128
  });
123
129
 
124
- let orderedStateSchema = S.schema(s => ({
130
+ let orderedStateSchema = Sury.$schema(s => ({
125
131
  productId: s.m(DcbTag$Reventless.string),
126
- createdAt: s.m(S.string),
127
- name: s.m(S.string)
132
+ createdAt: s.m(Sury.string),
133
+ name: s.m(Sury.string)
128
134
  }));
129
135
 
130
- let orderedStateSchemaWithAnnotations = S.Metadata.set(orderedStateSchema, StateAnnotations$Reventless.stateAnnotationsId, {
136
+ let orderedStateSchemaWithAnnotations = Sury.$Metadata_set(orderedStateSchema, StateAnnotations$Reventless.stateAnnotationsId, {
131
137
  ids: ["productId"],
132
138
  compositeIds: [],
133
139
  subIds: ["createdAt"],
@@ -149,14 +155,14 @@ let orderedStateSchemaWithAnnotations = S.Metadata.set(orderedStateSchema, State
149
155
  retired: undefined
150
156
  });
151
157
 
152
- let scanStateSchema = S.schema(s => ({
158
+ let scanStateSchema = Sury.$schema(s => ({
153
159
  productId: s.m(DcbTag$Reventless.string),
154
- status: s.m(S.string),
155
- name: s.m(S.string),
156
- description: s.m(S.string)
160
+ status: s.m(Sury.string),
161
+ name: s.m(Sury.string),
162
+ description: s.m(Sury.string)
157
163
  }));
158
164
 
159
- let scanStateSchemaWithAnnotations = S.Metadata.set(scanStateSchema, StateAnnotations$Reventless.stateAnnotationsId, {
165
+ let scanStateSchemaWithAnnotations = Sury.$Metadata_set(scanStateSchema, StateAnnotations$Reventless.stateAnnotationsId, {
160
166
  ids: ["productId"],
161
167
  compositeIds: [],
162
168
  subIds: [],
@@ -181,16 +187,16 @@ let scanStateSchemaWithAnnotations = S.Metadata.set(scanStateSchema, StateAnnota
181
187
  globalThis.describe("GraphQL_SchemaInspector", () => {
182
188
  globalThis.describe("inspectScalar", () => {
183
189
  globalThis.test("plain string derives to String", async () => {
184
- globalThis.expect(GraphQL_SchemaInspector$ReventlessCore.inspectScalar(S.string)).toBe("String");
190
+ globalThis.expect(GraphQL_SchemaInspector$ReventlessCore.inspectScalar(stringSchema)).toBe("String");
185
191
  });
186
192
  globalThis.test("tagged string derives to ID", async () => {
187
193
  globalThis.expect(GraphQL_SchemaInspector$ReventlessCore.inspectScalar(DcbTag$Reventless.string)).toBe("ID");
188
194
  });
189
195
  globalThis.test("float derives to Float", async () => {
190
- globalThis.expect(GraphQL_SchemaInspector$ReventlessCore.inspectScalar(S.float)).toBe("Float");
196
+ globalThis.expect(GraphQL_SchemaInspector$ReventlessCore.inspectScalar(numberSchema)).toBe("Float");
191
197
  });
192
198
  globalThis.test("bool derives to Boolean", async () => {
193
- globalThis.expect(GraphQL_SchemaInspector$ReventlessCore.inspectScalar(S.bool)).toBe("Boolean");
199
+ globalThis.expect(GraphQL_SchemaInspector$ReventlessCore.inspectScalar(boolSchema)).toBe("Boolean");
194
200
  });
195
201
  });
196
202
  globalThis.describe("inspectObjectType", () => {
@@ -205,7 +211,7 @@ globalThis.describe("GraphQL_SchemaInspector", () => {
205
211
  globalThis.expect(sdl.includes("active: Boolean")).toBe(true);
206
212
  });
207
213
  globalThis.test("returns None for non-object schema", async () => {
208
- let result = GraphQL_SchemaInspector$ReventlessCore.inspectObjectType("Foo", S.string);
214
+ let result = GraphQL_SchemaInspector$ReventlessCore.inspectObjectType("Foo", stringSchema);
209
215
  globalThis.expect(Stdlib_Option.isNone(result)).toBe(true);
210
216
  });
211
217
  });
@@ -229,7 +235,7 @@ globalThis.describe("GraphQL_SchemaInspector", () => {
229
235
  globalThis.expect(renameField.includes("newName: String")).toBe(true);
230
236
  });
231
237
  globalThis.test("returns empty for non-object/non-union schema", async () => {
232
- let fields = GraphQL_SchemaInspector$ReventlessCore.inspectMutationFields("Foo", S.string);
238
+ let fields = GraphQL_SchemaInspector$ReventlessCore.inspectMutationFields("Foo", stringSchema);
233
239
  globalThis.expect(fields.length).toBe(0);
234
240
  });
235
241
  });
@@ -239,7 +245,7 @@ globalThis.describe("GraphQL_SchemaInspector", () => {
239
245
  globalThis.expect(Stdlib_Option.isSome(result.typeDef)).toBe(true);
240
246
  let typeDef = Stdlib_Option.getOrThrow(result.typeDef, undefined);
241
247
  globalThis.expect(typeDef.includes("type CatalogProduct")).toBe(true);
242
- globalThis.expect(result.singleQuery.includes("Catalog_Product(id: ID!)")).toBe(true);
248
+ globalThis.expect(result.singleQuery.includes("Catalog_Product(id: ID!, includeRetired: Boolean)")).toBe(true);
243
249
  globalThis.expect(result.singleQuery.includes("CatalogProduct")).toBe(true);
244
250
  globalThis.expect(Stdlib_Option.isSome(result.listQuery)).toBe(true);
245
251
  let listQ = Stdlib_Option.getOrThrow(result.listQuery, undefined);
@@ -258,7 +264,7 @@ globalThis.describe("GraphQL_SchemaInspector", () => {
258
264
  }]);
259
265
  let inspection = GraphQL_SchemaInspector$ReventlessCore.inspectFragment(fragment);
260
266
  let sdl = inspection.sdlPreview;
261
- globalThis.expect(sdl.includes("RM_Product(id: ID!): RMProduct")).toBe(true);
267
+ globalThis.expect(sdl.includes("RM_Product(id: ID!, includeRetired: Boolean): RMProduct")).toBe(true);
262
268
  globalThis.expect(sdl.includes("type RMProduct")).toBe(true);
263
269
  let typeLines = sdl.split("\n");
264
270
  let idFieldInType = typeLines.some(line => {
@@ -302,7 +308,7 @@ globalThis.describe("GraphQL_SchemaInspector", () => {
302
308
  }]);
303
309
  let inspection = GraphQL_SchemaInspector$ReventlessCore.inspectFragment(fragment);
304
310
  let sdl = inspection.sdlPreview;
305
- globalThis.expect(sdl.includes("Default_Thing(id: ID!): DefaultThing")).toBe(true);
311
+ globalThis.expect(sdl.includes("Default_Thing(id: ID!, includeRetired: Boolean): DefaultThing")).toBe(true);
306
312
  });
307
313
  });
308
314
  globalThis.describe("Relay compliance", () => {
@@ -424,9 +430,9 @@ globalThis.describe("GraphQL_SchemaInspector", () => {
424
430
  authorization: undefined
425
431
  }]);
426
432
  let inspection = GraphQL_SchemaInspector$ReventlessCore.inspectFragment(fragment);
427
- globalThis.expect(inspection.types.length).toBe(8);
433
+ globalThis.expect(inspection.types.length).toBe(9);
428
434
  globalThis.expect(inspection.mutations.length).toBe(1);
429
- globalThis.expect(inspection.queries.length).toBe(3);
435
+ globalThis.expect(inspection.queries.length).toBe(4);
430
436
  globalThis.expect(inspection.sdlPreview.includes("type TestState")).toBe(true);
431
437
  globalThis.expect(inspection.sdlPreview.includes("type TestStateEdge")).toBe(true);
432
438
  globalThis.expect(inspection.sdlPreview.includes("type TestStateConnection")).toBe(true);
@@ -707,14 +713,8 @@ globalThis.describe("optional enum fields preserve GraphQL nullability", () => {
707
713
  });
708
714
  });
709
715
 
710
- let stringSchema = S.string;
711
-
712
716
  let taggedSchema = DcbTag$Reventless.string;
713
717
 
714
- let numberSchema = S.float;
715
-
716
- let boolSchema = S.bool;
717
-
718
718
  export {
719
719
  stringSchema,
720
720
  taggedSchema,
@@ -163,7 +163,7 @@ testPromise("POST /__inmemory/login returns {token, identity} for valid credenti
163
163
  // The echoed identity matches what LocalAuth.lookupUser returns.
164
164
  switch getJsonField(body, "identity") {
165
165
  | Some(idJson) =>
166
- let id = idJson->S.parseJsonOrThrow(Reventless.Identity.schema)
166
+ let id = idJson->Reventless.Util_Sury.fromJson(Reventless.Identity.schema)
167
167
  expect(id.username)->toEqual("alice")
168
168
  expect(id.groups)->toEqual(["Editor"])
169
169
  | None => JsError.throwWithMessage("response missing identity field")
@@ -1,11 +1,11 @@
1
1
  // Generated by ReScript, PLEASE EDIT WITH CARE
2
2
 
3
- import * as S from "sury/src/S.res.mjs";
4
3
  import * as Nodehttp from "node:http";
5
4
  import * as Stdlib_JSON from "@rescript/runtime/lib/es6/Stdlib_JSON.js";
6
5
  import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
7
6
  import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
8
7
  import * as Identity$Reventless from "@reventlessdev/reventless-spec/src/types/Identity.res.mjs";
8
+ import * as Util_Sury$Reventless from "@reventlessdev/reventless-spec/src/util/Util_Sury.res.mjs";
9
9
  import * as LocalAuth$ReventlessLocal from "../../src/adapter/Auth/LocalAuth.res.mjs";
10
10
  import * as TestRunner$ReventlessLocal from "../../src/test/TestRunner.res.mjs";
11
11
  import * as DomainGraphQL_Server$ReventlessLocal from "../../src/adapter/DomainGraphQL_Server.res.mjs";
@@ -151,7 +151,7 @@ globalThis.test("POST /__inmemory/login returns {token, identity} for valid cred
151
151
  if (idJson === undefined) {
152
152
  return Stdlib_JsError.throwWithMessage("response missing identity field");
153
153
  }
154
- let id = S.parseJsonOrThrow(idJson, Identity$Reventless.schema);
154
+ let id = Util_Sury$Reventless.fromJson(idJson, Identity$Reventless.schema);
155
155
  globalThis.expect(id.username).toEqual("alice");
156
156
  globalThis.expect(id.groups).toEqual(["Editor"]);
157
157
  });