@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
@@ -102,7 +102,7 @@ let pageInfoString = (response: JSON.t, key: string): option<string> =>
102
102
  // Per-test fixture — fresh Bus + storage + registry + resolver
103
103
  // ─────────────────────────────────────────────────────────────
104
104
 
105
- let buildFixture = async (~name: string) => {
105
+ let buildFixture = async (~name: string, ~indexes: array<Reventless.ReadModel.indexConfig>=[]) => {
106
106
  module Bus = LocalBus.Make()
107
107
  module Storage = LocalQueryDbStorage.Make(Bus)
108
108
  module Resolvers = QueryDbResolvers_GraphQL.Make(Bus)
@@ -151,7 +151,7 @@ let buildFixture = async (~name: string) => {
151
151
  ~api=(),
152
152
  ~apiRole=(),
153
153
  ~dataSourceName=""->Pulumi.Output.make,
154
- ~indexes=[],
154
+ ~indexes,
155
155
  ~subIdField=None,
156
156
  ~idResolverConfigs=[],
157
157
  ~idsResolverConfigs=[],
@@ -440,3 +440,83 @@ describe("QueryDb list resolver — SQLite push-down path", () => {
440
440
  })
441
441
  )
442
442
  })
443
+
444
+ // The by-index door answers a Relay connection, keyed on the index's column.
445
+ // Both halves used to be wrong here and in the opposite direction on AppSync:
446
+ // this backend promised `[String]` and returned whole rows, so every call failed
447
+ // to serialise before a caller could reach the rows at all.
448
+ describe("QueryDb by-index resolver", () => {
449
+ let statusIndex: array<Reventless.ReadModel.indexConfig> = [
450
+ {index: "status", type_: "S", projectionType: ALL},
451
+ ]
452
+
453
+ let indexResolver = async (~name) => {
454
+ let _ = await buildFixture(~name, ~indexes=statusIndex)
455
+ switch DomainGraphQL_Server.getQueryResolver(name ++ "ByStatus") {
456
+ | Some(r) => r
457
+ | None => JsError.throwWithMessage("index resolver not registered: " ++ name ++ "ByStatus")
458
+ }
459
+ }
460
+
461
+ beforeEach(() => {
462
+ DomainGraphQL_Server.reset()
463
+ })
464
+
465
+ testPromise("answers the rows carrying the index value, as edges", async () => {
466
+ let resolver = await indexResolver(~name="IdxA")
467
+ let response = await resolver(JSON.Encode.null, argsOf([("status", strJson("active"))]), emptyCtx)
468
+ let edges = getEdges(response)
469
+ expect(edges->Array.length)->toBe(3)
470
+ expect(edgeNodeField(edges->Array.getUnsafe(0), "productId"))->toBe("p-1")
471
+ })
472
+
473
+ testPromise("pages forward on first/after like every other connection", async () => {
474
+ let resolver = await indexResolver(~name="IdxB")
475
+ let page1 =
476
+ await resolver(
477
+ JSON.Encode.null,
478
+ argsOf([("status", strJson("active")), ("first", numJson(2))]),
479
+ emptyCtx,
480
+ )
481
+ expect(getEdges(page1)->Array.length)->toBe(2)
482
+ expect(pageInfoBool(page1, "hasNextPage"))->toBe(true)
483
+
484
+ let page2 =
485
+ await resolver(
486
+ JSON.Encode.null,
487
+ argsOf([
488
+ ("status", strJson("active")),
489
+ ("first", numJson(2)),
490
+ ("after", strJson(pageInfoString(page1, "endCursor")->Option.getOr(""))),
491
+ ]),
492
+ emptyCtx,
493
+ )
494
+ let edges2 = getEdges(page2)
495
+ expect(edges2->Array.length)->toBe(1)
496
+ expect(edgeNodeField(edges2->Array.getUnsafe(0), "productId"))->toBe("p-4")
497
+ expect(pageInfoBool(page2, "hasNextPage"))->toBe(false)
498
+ })
499
+
500
+ // Refused rather than ignored, and refused here because AppSync cannot do it:
501
+ // a door that paged backward on one backend and quietly returned the forward
502
+ // page on the other is the divergence this whole field was rebuilt to remove.
503
+ testPromise("refuses backward paging instead of answering forward", async () => {
504
+ let resolver = await indexResolver(~name="IdxC")
505
+ let outcome = try {
506
+ let _ =
507
+ await resolver(
508
+ JSON.Encode.null,
509
+ argsOf([("status", strJson("active")), ("last", numJson(2))]),
510
+ emptyCtx,
511
+ )
512
+ Ok()
513
+ } catch {
514
+ | e => Error(e->JsExn.fromException->Option.flatMap(JsExn.message)->Option.getOr(""))
515
+ }
516
+ switch outcome {
517
+ | Ok() => expect("no error")->toBe("a BAD_USER_INPUT refusal")
518
+ | Error(message) =>
519
+ expect(message->String.includes("Backward pagination (last/before) is not supported"))->toBe(true)
520
+ }
521
+ })
522
+ })
@@ -1,13 +1,15 @@
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
+ import * as Stdlib_JsExn from "@rescript/runtime/lib/es6/Stdlib_JsExn.js";
5
6
  import * as Id$Reventless from "@reventlessdev/reventless-spec/src/types/Id.res.mjs";
6
7
  import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
7
8
  import * as Pulumi from "@pulumi/pulumi";
8
9
  import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
9
10
  import * as DcbTag$Reventless from "@reventlessdev/reventless-spec/src/components/DcbTag.res.mjs";
10
11
  import * as Identity$Reventless from "@reventlessdev/reventless-spec/src/types/Identity.res.mjs";
12
+ import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
11
13
  import * as ReadModel$Reventless from "@reventlessdev/reventless-spec/src/components/ReadModel.res.mjs";
12
14
  import * as Component$ReventlessCore from "@reventlessdev/reventless-core/src/components/Component.res.mjs";
13
15
  import * as LocalBus$ReventlessLocal from "../../src/adapter/LocalBus.res.mjs";
@@ -24,13 +26,13 @@ import * as QueryDbResolvers_GraphQL$ReventlessLocal from "../../src/adapter/Que
24
26
 
25
27
  TestRunner$ReventlessLocal.setup();
26
28
 
27
- let rowStateSchema = S.schema(s => ({
29
+ let rowStateSchema = Sury.$schema(s => ({
28
30
  productId: s.m(DcbTag$Reventless.string),
29
- status: s.m(S.string),
30
- name: s.m(S.string)
31
+ status: s.m(Sury.string),
32
+ name: s.m(Sury.string)
31
33
  }));
32
34
 
33
- let rowStateSchemaWithAnnotations = S.Metadata.set(rowStateSchema, StateAnnotations$Reventless.stateAnnotationsId, {
35
+ let rowStateSchemaWithAnnotations = Sury.$Metadata_set(rowStateSchema, StateAnnotations$Reventless.stateAnnotationsId, {
34
36
  ids: ["productId"],
35
37
  compositeIds: [],
36
38
  subIds: [],
@@ -112,7 +114,8 @@ function pageInfoString(response, key) {
112
114
  return getString(pageInfo(response), key);
113
115
  }
114
116
 
115
- async function buildFixture(name) {
117
+ async function buildFixture(name, indexesOpt) {
118
+ let indexes = indexesOpt !== undefined ? indexesOpt : [];
116
119
  let Bus = LocalBus$ReventlessLocal.Make({});
117
120
  let Storage = LocalQueryDbStorage$ReventlessLocal.Make(Bus);
118
121
  let Resolvers = QueryDbResolvers_GraphQL$ReventlessLocal.Make(Bus);
@@ -151,7 +154,7 @@ async function buildFixture(name) {
151
154
  Plugin_Helpers$ReventlessCore.stateSchemaRegistry[name] = rowStateSchemaWithAnnotations;
152
155
  let queryDb = Maker.make(undefined, undefined, undefined, undefined, undefined);
153
156
  let ops = await TestRunner$ReventlessLocal.resolve(Component$ReventlessCore.operations(queryDb));
154
- Resolvers.make(name, undefined, undefined, Pulumi.output(""), [], undefined, [], [], "AllowAuthenticated", {});
157
+ Resolvers.make(name, undefined, undefined, Pulumi.output(""), indexes, undefined, [], [], "AllowAuthenticated", {});
155
158
  let r = DomainGraphQL_Server$ReventlessLocal.getQueryResolver(listFieldName);
156
159
  let resolver = r !== undefined ? r : Stdlib_JsError.throwWithMessage("resolver not registered: " + listFieldName);
157
160
  let rows = [
@@ -199,7 +202,7 @@ async function buildFixture(name) {
199
202
  globalThis.describe("QueryDb list resolver — keyset pagination", () => {
200
203
  globalThis.beforeEach(() => DomainGraphQL_Server$ReventlessLocal.reset());
201
204
  globalThis.test("first: 2 over a 5-row fixture returns 2 edges and hasNextPage = true", async () => {
202
- let match = await buildFixture("PageA");
205
+ let match = await buildFixture("PageA", undefined);
203
206
  let response = await match[0](null, Object.fromEntries([[
204
207
  "first",
205
208
  2
@@ -212,7 +215,7 @@ globalThis.describe("QueryDb list resolver — keyset pagination", () => {
212
215
  globalThis.expect(edgeNodeField(edges[1], "productId")).toBe("p-2");
213
216
  });
214
217
  globalThis.test("after: <endCursor> walks forward without overlap", async () => {
215
- let match = await buildFixture("PageB");
218
+ let match = await buildFixture("PageB", undefined);
216
219
  let resolver = match[0];
217
220
  let page1 = await resolver(null, Object.fromEntries([[
218
221
  "first",
@@ -251,7 +254,7 @@ globalThis.describe("QueryDb list resolver — keyset pagination", () => {
251
254
  globalThis.expect(pageInfoBool(page3, "hasNextPage")).toBe(false);
252
255
  });
253
256
  globalThis.test("last + before walks backward and flips hasPreviousPage", async () => {
254
- let match = await buildFixture("PageC");
257
+ let match = await buildFixture("PageC", undefined);
255
258
  let resolver = match[0];
256
259
  let page1 = await resolver(null, Object.fromEntries([[
257
260
  "first",
@@ -314,7 +317,7 @@ globalThis.describe("QueryDb list resolver — keyset pagination", () => {
314
317
  globalThis.expect(pageInfoBool(firstPage, "hasPreviousPage")).toBe(false);
315
318
  });
316
319
  globalThis.test("filter.<field>Eq + first / after paginates only the narrowed subset", async () => {
317
- let match = await buildFixture("PageD");
320
+ let match = await buildFixture("PageD", undefined);
318
321
  let resolver = match[0];
319
322
  let activeFilter = Object.fromEntries([[
320
323
  "statusEq",
@@ -356,7 +359,7 @@ globalThis.describe("QueryDb list resolver — keyset pagination", () => {
356
359
  globalThis.expect(pageInfoBool(page2, "hasNextPage")).toBe(false);
357
360
  });
358
361
  globalThis.test("orderBy DESC + first / after paginates the reverse-sorted view", async () => {
359
- let match = await buildFixture("PageE");
362
+ let match = await buildFixture("PageE", undefined);
360
363
  let resolver = match[0];
361
364
  let orderBy = Object.fromEntries([
362
365
  [
@@ -404,7 +407,7 @@ globalThis.describe("QueryDb list resolver — keyset pagination", () => {
404
407
  globalThis.expect(edgeNodeField(edges2[1], "name")).toBe("Bravo");
405
408
  });
406
409
  globalThis.test("bare request (no first / after) returns a single bounded page", async () => {
407
- let match = await buildFixture("PageF");
410
+ let match = await buildFixture("PageF", undefined);
408
411
  let response = await match[0](null, Object.fromEntries([]), emptyCtx);
409
412
  let edges = getEdges(response);
410
413
  globalThis.expect(edges.length).toBe(5);
@@ -424,7 +427,7 @@ globalThis.describe("QueryDb list resolver — SQLite push-down path", () => {
424
427
  return r;
425
428
  };
426
429
  globalThis.test("first:2 then after walks forward without overlap", () => withSqlite(async () => {
427
- let match = await buildFixture("SqlPageA");
430
+ let match = await buildFixture("SqlPageA", undefined);
428
431
  let resolver = match[0];
429
432
  let page1 = await resolver(null, Object.fromEntries([[
430
433
  "first",
@@ -452,7 +455,7 @@ globalThis.describe("QueryDb list resolver — SQLite push-down path", () => {
452
455
  globalThis.expect(edgeNodeField(edges2[1], "productId")).toBe("p-4");
453
456
  }));
454
457
  globalThis.test("orderBy name DESC + first:2 returns the reverse-sorted head", () => withSqlite(async () => {
455
- let match = await buildFixture("SqlPageB");
458
+ let match = await buildFixture("SqlPageB", undefined);
456
459
  let orderBy = Object.fromEntries([
457
460
  [
458
461
  "field",
@@ -479,7 +482,7 @@ globalThis.describe("QueryDb list resolver — SQLite push-down path", () => {
479
482
  globalThis.expect(edgeNodeField(edges1[1], "name")).toBe("Delta");
480
483
  }));
481
484
  globalThis.test("statusEq active narrows the pushed page", () => withSqlite(async () => {
482
- let match = await buildFixture("SqlPageC");
485
+ let match = await buildFixture("SqlPageC", undefined);
483
486
  let activeFilter = Object.fromEntries([[
484
487
  "statusEq",
485
488
  "active"
@@ -495,6 +498,98 @@ globalThis.describe("QueryDb list resolver — SQLite push-down path", () => {
495
498
  }));
496
499
  });
497
500
 
501
+ globalThis.describe("QueryDb by-index resolver", () => {
502
+ let statusIndex = [{
503
+ index: "status",
504
+ type_: "S",
505
+ projectionType: "ALL"
506
+ }];
507
+ let indexResolver = async name => {
508
+ await buildFixture(name, statusIndex);
509
+ let r = DomainGraphQL_Server$ReventlessLocal.getQueryResolver(name + "ByStatus");
510
+ if (r !== undefined) {
511
+ return r;
512
+ } else {
513
+ return Stdlib_JsError.throwWithMessage("index resolver not registered: " + name + "ByStatus");
514
+ }
515
+ };
516
+ globalThis.beforeEach(() => DomainGraphQL_Server$ReventlessLocal.reset());
517
+ globalThis.test("answers the rows carrying the index value, as edges", async () => {
518
+ let resolver = await indexResolver("IdxA");
519
+ let response = await resolver(null, Object.fromEntries([[
520
+ "status",
521
+ "active"
522
+ ]]), emptyCtx);
523
+ let edges = getEdges(response);
524
+ globalThis.expect(edges.length).toBe(3);
525
+ globalThis.expect(edgeNodeField(edges[0], "productId")).toBe("p-1");
526
+ });
527
+ globalThis.test("pages forward on first/after like every other connection", async () => {
528
+ let resolver = await indexResolver("IdxB");
529
+ let page1 = await resolver(null, Object.fromEntries([
530
+ [
531
+ "status",
532
+ "active"
533
+ ],
534
+ [
535
+ "first",
536
+ 2
537
+ ]
538
+ ]), emptyCtx);
539
+ globalThis.expect(getEdges(page1).length).toBe(2);
540
+ globalThis.expect(pageInfoBool(page1, "hasNextPage")).toBe(true);
541
+ let page2 = await resolver(null, Object.fromEntries([
542
+ [
543
+ "status",
544
+ "active"
545
+ ],
546
+ [
547
+ "first",
548
+ 2
549
+ ],
550
+ [
551
+ "after",
552
+ Stdlib_Option.getOr(getString(pageInfo(page1), "endCursor"), "")
553
+ ]
554
+ ]), emptyCtx);
555
+ let edges2 = getEdges(page2);
556
+ globalThis.expect(edges2.length).toBe(1);
557
+ globalThis.expect(edgeNodeField(edges2[0], "productId")).toBe("p-4");
558
+ globalThis.expect(pageInfoBool(page2, "hasNextPage")).toBe(false);
559
+ });
560
+ globalThis.test("refuses backward paging instead of answering forward", async () => {
561
+ let resolver = await indexResolver("IdxC");
562
+ let outcome;
563
+ try {
564
+ await resolver(null, Object.fromEntries([
565
+ [
566
+ "status",
567
+ "active"
568
+ ],
569
+ [
570
+ "last",
571
+ 2
572
+ ]
573
+ ]), emptyCtx);
574
+ outcome = {
575
+ TAG: "Ok",
576
+ _0: undefined
577
+ };
578
+ } catch (raw_e) {
579
+ let e = Primitive_exceptions.internalToException(raw_e);
580
+ outcome = {
581
+ TAG: "Error",
582
+ _0: Stdlib_Option.getOr(Stdlib_Option.flatMap(Stdlib_JsExn.fromException(e), Stdlib_JsExn.message), "")
583
+ };
584
+ }
585
+ if (outcome.TAG === "Ok") {
586
+ globalThis.expect("no error").toBe("a BAD_USER_INPUT refusal");
587
+ return;
588
+ }
589
+ globalThis.expect(outcome._0.includes("Backward pagination (last/before) is not supported")).toBe(true);
590
+ });
591
+ });
592
+
498
593
  export {
499
594
  rowStateSchema,
500
595
  rowStateSchemaWithAnnotations,
@@ -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 Id$Reventless from "@reventlessdev/reventless-spec/src/types/Id.res.mjs";
5
5
  import * as LocalBus$ReventlessLocal from "../../../src/adapter/LocalBus.res.mjs";
6
6
  import * as TestRunner$ReventlessLocal from "../../../src/test/TestRunner.res.mjs";
@@ -9,17 +9,17 @@ import * as Aggregate_Builder$ReventlessLocal from "../../../src/components/Aggr
9
9
 
10
10
  let name = "TestItem";
11
11
 
12
- let commandSchema = S.schema(s => ({
12
+ let commandSchema = Sury.$schema(s => ({
13
13
  TAG: "CreateItem",
14
- name: s.m(S.string)
14
+ name: s.m(Sury.string)
15
15
  }));
16
16
 
17
- let eventSchema = S.schema(s => ({
17
+ let eventSchema = Sury.$schema(s => ({
18
18
  TAG: "ItemCreated",
19
- name: s.m(S.string)
19
+ name: s.m(Sury.string)
20
20
  }));
21
21
 
22
- let errorSchema = S.literal("AlreadyExists");
22
+ let errorSchema = Sury.literal("AlreadyExists");
23
23
 
24
24
  let moduleUrl = import.meta.url;
25
25
 
@@ -138,7 +138,7 @@ let testContext: Reventless.AutomationSlice.context = {
138
138
  // the event payload with a `meta.service` matching the source name so the
139
139
  // callback's per-source dispatch picks the right mapping.
140
140
  let encodeShipOrderEvent = (event: ShipOrderSource.event): JSON.t => {
141
- let payloadJson = event->S.reverseConvertToJsonOrThrow(ShipOrderSource.eventSchema)
141
+ let payloadJson = event->Reventless.Util_Sury.toJson(ShipOrderSource.eventSchema)
142
142
  let dict = switch payloadJson->JSON.Decode.object {
143
143
  | Some(d) => d->Dict.copy
144
144
  | None =>
@@ -158,13 +158,13 @@ let encodeShipOrderEvent = (event: ShipOrderSource.event): JSON.t => {
158
158
  msgId: "msg-1",
159
159
  correlationId: "",
160
160
  }
161
- dict->Dict.set("meta", meta->S.reverseConvertToJsonOrThrow(Reventless.Message.metaSchema))
161
+ dict->Dict.set("meta", meta->Reventless.Util_Sury.toJson(Reventless.Message.metaSchema))
162
162
  dict->Dict.set("id", JSON.Encode.string("env-id"))
163
163
  JSON.Encode.object(dict)
164
164
  }
165
165
 
166
166
  let encodeSkipProcessEvent = (event: SkipProcessSource.event): JSON.t => {
167
- let payloadJson = event->S.reverseConvertToJsonOrThrow(SkipProcessSource.eventSchema)
167
+ let payloadJson = event->Reventless.Util_Sury.toJson(SkipProcessSource.eventSchema)
168
168
  let dict = switch payloadJson->JSON.Decode.object {
169
169
  | Some(d) => d->Dict.copy
170
170
  | None =>
@@ -183,7 +183,7 @@ let encodeSkipProcessEvent = (event: SkipProcessSource.event): JSON.t => {
183
183
  msgId: "msg-1",
184
184
  correlationId: "",
185
185
  }
186
- dict->Dict.set("meta", meta->S.reverseConvertToJsonOrThrow(Reventless.Message.metaSchema))
186
+ dict->Dict.set("meta", meta->Reventless.Util_Sury.toJson(Reventless.Message.metaSchema))
187
187
  dict->Dict.set("id", JSON.Encode.string("env-id"))
188
188
  JSON.Encode.object(dict)
189
189
  }
@@ -1,21 +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_JSON from "@rescript/runtime/lib/es6/Stdlib_JSON.js";
5
5
  import * as Id$Reventless from "@reventlessdev/reventless-spec/src/types/Id.res.mjs";
6
6
  import * as DcbTag$Reventless from "@reventlessdev/reventless-spec/src/components/DcbTag.res.mjs";
7
7
  import * as Message$Reventless from "@reventlessdev/reventless-spec/src/types/Message.res.mjs";
8
+ import * as Util_Sury$Reventless from "@reventlessdev/reventless-spec/src/util/Util_Sury.res.mjs";
8
9
  import * as AutomationSlice$Reventless from "@reventlessdev/reventless-spec/src/components/AutomationSlice.res.mjs";
9
10
 
10
11
  let name = "ShipOrderDcbEventLog";
11
12
 
12
- let eventSchema = S.union([
13
- S.schema(s => ({
13
+ let eventSchema = Sury.union([
14
+ Sury.$schema(s => ({
14
15
  TAG: "OrderPlaced",
15
16
  orderId: s.m(DcbTag$Reventless.string),
16
- address: s.m(S.string)
17
+ address: s.m(Sury.string)
17
18
  })),
18
- S.schema(s => ({
19
+ Sury.$schema(s => ({
19
20
  TAG: "ShipmentCreated",
20
21
  orderId: s.m(DcbTag$Reventless.string)
21
22
  }))
@@ -29,12 +30,12 @@ let ShipOrderSource = {
29
30
 
30
31
  let name$1 = "SkipProcessDcbEventLog";
31
32
 
32
- let eventSchema$1 = S.union([
33
- S.schema(s => ({
33
+ let eventSchema$1 = Sury.union([
34
+ Sury.$schema(s => ({
34
35
  TAG: "OrderPlaced",
35
36
  orderId: s.m(DcbTag$Reventless.string)
36
37
  })),
37
- S.schema(s => ({
38
+ Sury.$schema(s => ({
38
39
  TAG: "ShipmentCreated",
39
40
  orderId: s.m(DcbTag$Reventless.string)
40
41
  }))
@@ -48,12 +49,12 @@ let SkipProcessSource = {
48
49
 
49
50
  let moduleUrl = import.meta.url;
50
51
 
51
- let todoItemSchema = S.schema(s => ({
52
- orderId: s.m(S.string),
53
- address: s.m(S.string)
52
+ let todoItemSchema = Sury.$schema(s => ({
53
+ orderId: s.m(Sury.string),
54
+ address: s.m(Sury.string)
54
55
  }));
55
56
 
56
- let commandSchema = S.schema(s => ({
57
+ let commandSchema = Sury.$schema(s => ({
57
58
  TAG: "CreateShipment",
58
59
  orderId: s.m(DcbTag$Reventless.string)
59
60
  }));
@@ -75,11 +76,11 @@ let ShipOrderSpec = {
75
76
 
76
77
  let moduleUrl$1 = import.meta.url;
77
78
 
78
- let todoItemSchema$1 = S.schema(s => ({
79
- orderId: s.m(S.string)
79
+ let todoItemSchema$1 = Sury.$schema(s => ({
80
+ orderId: s.m(Sury.string)
80
81
  }));
81
82
 
82
- let commandSchema$1 = S.literal("Noop");
83
+ let commandSchema$1 = Sury.literal("Noop");
83
84
 
84
85
  function commandAuthorization$1(param) {
85
86
  return "AllowAuthenticated";
@@ -196,7 +197,7 @@ let SkipProcessAutomation = {
196
197
  };
197
198
 
198
199
  function encodeShipOrderEvent(event) {
199
- let payloadJson = S.reverseConvertToJsonOrThrow(event, eventSchema);
200
+ let payloadJson = Util_Sury$Reventless.toJson(event, eventSchema);
200
201
  let d = Stdlib_JSON.Decode.object(payloadJson);
201
202
  let dict;
202
203
  if (d !== undefined) {
@@ -219,13 +220,13 @@ function encodeShipOrderEvent(event) {
219
220
  msgId: "msg-1",
220
221
  correlationId: ""
221
222
  };
222
- dict["meta"] = S.reverseConvertToJsonOrThrow(meta, Message$Reventless.metaSchema);
223
+ dict["meta"] = Util_Sury$Reventless.toJson(meta, Message$Reventless.metaSchema);
223
224
  dict["id"] = "env-id";
224
225
  return dict;
225
226
  }
226
227
 
227
228
  function encodeSkipProcessEvent(event) {
228
- let payloadJson = S.reverseConvertToJsonOrThrow(event, eventSchema$1);
229
+ let payloadJson = Util_Sury$Reventless.toJson(event, eventSchema$1);
229
230
  let d = Stdlib_JSON.Decode.object(payloadJson);
230
231
  let dict;
231
232
  if (d !== undefined) {
@@ -248,7 +249,7 @@ function encodeSkipProcessEvent(event) {
248
249
  msgId: "msg-1",
249
250
  correlationId: ""
250
251
  };
251
- dict["meta"] = S.reverseConvertToJsonOrThrow(meta, Message$Reventless.metaSchema);
252
+ dict["meta"] = Util_Sury$Reventless.toJson(meta, Message$Reventless.metaSchema);
252
253
  dict["id"] = "env-id";
253
254
  return dict;
254
255
  }
@@ -207,7 +207,7 @@ let publishJsons: ReventlessInfra.CommandTopic.publishJsons = async cmdJsons =>
207
207
  let fullBody = JSON.Encode.object(
208
208
  Dict.fromArray([
209
209
  ("id", JSON.Encode.string(cmdJson.id)),
210
- ("meta", cmdJson.meta->S.reverseConvertToJsonOrThrow(Reventless.Message.metaSchema)),
210
+ ("meta", cmdJson.meta->Reventless.Util_Sury.toJson(Reventless.Message.metaSchema)),
211
211
  ("command", cmdJson.commandJson),
212
212
  ]),
213
213
  )
@@ -266,7 +266,7 @@ let placeCmdJson = (orderId: string): Reventless.Message.commandJson => {
266
266
  id: orderId,
267
267
  meta: testMeta,
268
268
  commandJson: PlaceSpec.Place({orderId: orderId})
269
- ->S.reverseConvertToJsonOrThrow(PlaceSpec.commandSchema),
269
+ ->Reventless.Util_Sury.toJson(PlaceSpec.commandSchema),
270
270
  }
271
271
 
272
272
  // Promise-based timeout used to fail fast if the chain self-deadlocks.
@@ -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 Id$Reventless from "@reventlessdev/reventless-spec/src/types/Id.res.mjs";
5
5
  import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
6
6
  import * as Effect from "effect/Effect";
@@ -8,6 +8,7 @@ import * as Stream from "effect/Stream";
8
8
  import * as Pulumi from "@pulumi/pulumi";
9
9
  import * as DcbTag$Reventless from "@reventlessdev/reventless-spec/src/components/DcbTag.res.mjs";
10
10
  import * as Message$Reventless from "@reventlessdev/reventless-spec/src/types/Message.res.mjs";
11
+ import * as Util_Sury$Reventless from "@reventlessdev/reventless-spec/src/util/Util_Sury.res.mjs";
11
12
  import * as LocalBus$ReventlessLocal from "../../../src/adapter/LocalBus.res.mjs";
12
13
  import * as Component$ReventlessInfra from "@reventlessdev/reventless-infra/src/components/Component.res.mjs";
13
14
  import * as AutomationSlice$Reventless from "@reventlessdev/reventless-spec/src/components/AutomationSlice.res.mjs";
@@ -22,19 +23,19 @@ let name = "Place";
22
23
 
23
24
  let moduleUrl = import.meta.url;
24
25
 
25
- let eventSchema = S.schema(s => ({
26
+ let eventSchema = Sury.$schema(s => ({
26
27
  TAG: "Placed",
27
28
  orderId: s.m(DcbTag$Reventless.string)
28
29
  }));
29
30
 
30
- let consumedEventSchema = S.literal("Placed");
31
+ let consumedEventSchema = Sury.literal("Placed");
31
32
 
32
- let commandSchema = S.schema(s => ({
33
+ let commandSchema = Sury.$schema(s => ({
33
34
  TAG: "Place",
34
35
  orderId: s.m(DcbTag$Reventless.string)
35
36
  }));
36
37
 
37
- let errorSchema = S.literal("AlreadyPlaced");
38
+ let errorSchema = Sury.literal("AlreadyPlaced");
38
39
 
39
40
  function commandAuthorization(param) {
40
41
  return "AllowAuthenticated";
@@ -87,25 +88,25 @@ let name$1 = "Ship";
87
88
 
88
89
  let moduleUrl$2 = import.meta.url;
89
90
 
90
- let eventSchema$1 = S.schema(s => ({
91
+ let eventSchema$1 = Sury.$schema(s => ({
91
92
  TAG: "Shipped",
92
93
  orderId: s.m(DcbTag$Reventless.string)
93
94
  }));
94
95
 
95
- let consumedEventSchema$1 = S.union([
96
- S.schema(s => ({
96
+ let consumedEventSchema$1 = Sury.union([
97
+ Sury.$schema(s => ({
97
98
  TAG: "Placed",
98
- orderId: s.m(S.string)
99
+ orderId: s.m(Sury.string)
99
100
  })),
100
- S.literal("Shipped")
101
+ Sury.literal("Shipped")
101
102
  ]);
102
103
 
103
- let commandSchema$1 = S.schema(s => ({
104
+ let commandSchema$1 = Sury.$schema(s => ({
104
105
  TAG: "Ship",
105
106
  orderId: s.m(DcbTag$Reventless.string)
106
107
  }));
107
108
 
108
- let errorSchema$1 = S.literal("NotPlaced");
109
+ let errorSchema$1 = Sury.literal("NotPlaced");
109
110
 
110
111
  function commandAuthorization$1(param) {
111
112
  return "AllowAuthenticated";
@@ -178,14 +179,14 @@ let ShipBehavior = {
178
179
 
179
180
  let name$2 = "TestLogDcbEventLog";
180
181
 
181
- let eventSchema$2 = S.union([
182
- S.schema(s => ({
182
+ let eventSchema$2 = Sury.union([
183
+ Sury.$schema(s => ({
183
184
  TAG: "Placed",
184
- orderId: s.m(S.string)
185
+ orderId: s.m(Sury.string)
185
186
  })),
186
- S.schema(s => ({
187
+ Sury.$schema(s => ({
187
188
  TAG: "Shipped",
188
- orderId: s.m(S.string)
189
+ orderId: s.m(Sury.string)
189
190
  }))
190
191
  ]);
191
192
 
@@ -199,11 +200,11 @@ let name$3 = "AutoShip";
199
200
 
200
201
  let moduleUrl$4 = import.meta.url;
201
202
 
202
- let todoItemSchema = S.schema(s => ({
203
- orderId: s.m(S.string)
203
+ let todoItemSchema = Sury.$schema(s => ({
204
+ orderId: s.m(Sury.string)
204
205
  }));
205
206
 
206
- let commandSchema$2 = S.schema(s => ({
207
+ let commandSchema$2 = Sury.$schema(s => ({
207
208
  TAG: "Ship",
208
209
  orderId: s.m(DcbTag$Reventless.string)
209
210
  }));
@@ -304,7 +305,7 @@ async function publishJsons(cmdJsons) {
304
305
  ],
305
306
  [
306
307
  "meta",
307
- S.reverseConvertToJsonOrThrow(cmdJson.meta, Message$Reventless.metaSchema)
308
+ Util_Sury$Reventless.toJson(cmdJson.meta, Message$Reventless.metaSchema)
308
309
  ],
309
310
  [
310
311
  "command",
@@ -387,7 +388,7 @@ function placeCmdJson(orderId) {
387
388
  return {
388
389
  id: orderId,
389
390
  meta: TestFixtures$ReventlessLocal.testMeta,
390
- commandJson: S.reverseConvertToJsonOrThrow({
391
+ commandJson: Util_Sury$Reventless.toJson({
391
392
  TAG: "Place",
392
393
  orderId: orderId
393
394
  }, commandSchema)
@@ -193,8 +193,8 @@ let publishAggregateEvent = async (id, event: OrderAggregateSource.event) => {
193
193
  let eventJson = JSON.Encode.object(
194
194
  Dict.fromArray([
195
195
  ("id", id->JSON.Encode.string),
196
- ("meta", meta->S.reverseConvertToJsonOrThrow(Message.metaSchema)),
197
- ("event", event->S.reverseConvertToJsonOrThrow(OrderAggregateSource.eventSchema)),
196
+ ("meta", meta->Reventless.Util_Sury.toJson(Message.metaSchema)),
197
+ ("event", event->Reventless.Util_Sury.toJson(OrderAggregateSource.eventSchema)),
198
198
  ]),
199
199
  )
200
200
  await Bus.publishEvent(OrderAggregateSource.name, "test", meta, eventJson)
@@ -205,8 +205,8 @@ let publishDcbEvent = async (id, event: InventoryDcbSource.event) => {
205
205
  let eventJson = JSON.Encode.object(
206
206
  Dict.fromArray([
207
207
  ("id", id->JSON.Encode.string),
208
- ("meta", meta->S.reverseConvertToJsonOrThrow(Message.metaSchema)),
209
- ("event", event->S.reverseConvertToJsonOrThrow(InventoryDcbSource.eventSchema)),
208
+ ("meta", meta->Reventless.Util_Sury.toJson(Message.metaSchema)),
209
+ ("event", event->Reventless.Util_Sury.toJson(InventoryDcbSource.eventSchema)),
210
210
  ]),
211
211
  )
212
212
  await Bus.publishEvent(InventoryDcbSource.name, "test", meta, eventJson)