@reventlessdev/reventless-core 3.0.0-alpha.166 → 3.0.0-alpha.168

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 (44) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/package.json +3 -3
  3. package/src/Projection.res +11 -6
  4. package/src/Projection.res.mjs +27 -25
  5. package/src/admin/AdminApi.res +9 -62
  6. package/src/admin/AdminApi.res.mjs +6 -28
  7. package/src/components/Api/GraphQL_Stitcher.res +4 -112
  8. package/src/components/Api/GraphQL_Stitcher.res.mjs +0 -90
  9. package/src/components/Dcb/Dcb_Builder.res +38 -21
  10. package/src/components/Dcb/Dcb_Builder.res.mjs +13 -4
  11. package/src/components/ReadModel/ReadModel_Callback.res +1 -1
  12. package/src/components/ReadModel/ReadModel_Callback.res.mjs +1 -1
  13. package/src/components/StateViewSlice/StateViewSlice_Builder.res +1 -1
  14. package/src/components/StateViewSlice/StateViewSlice_Builder.res.mjs +1 -1
  15. package/src/components/StateViewSlice/StateViewSlice_Callback.res +1 -1
  16. package/src/components/StateViewSlice/StateViewSlice_Callback.res.mjs +1 -1
  17. package/src/plugin/component/Plugin_Builder.res +5 -7
  18. package/src/plugin/component/Plugin_Builder.res.mjs +3 -6
  19. package/src/util/EffectLogger.res +5 -3
  20. package/src/util/EffectLogger.res.mjs +3 -10
  21. package/src/util/Logger.res +41 -11
  22. package/src/util/Logger.res.mjs +36 -10
  23. package/tests/api/GraphQL_StitcherTest.res +0 -198
  24. package/tests/api/GraphQL_StitcherTest.res.mjs +0 -168
  25. package/src/admin/ApiFragmentRegistry/ApiFragmentRegistryBehavior.res +0 -108
  26. package/src/admin/ApiFragmentRegistry/ApiFragmentRegistryBehavior.res.mjs +0 -190
  27. package/src/admin/ApiFragmentRegistry/ApiFragmentRegistrySpec.res +0 -71
  28. package/src/admin/ApiFragmentRegistry/ApiFragmentRegistrySpec.res.mjs +0 -92
  29. package/src/admin/ApiFragmentRegistry/ApiFragmentsProjection.res +0 -63
  30. package/src/admin/ApiFragmentRegistry/ApiFragmentsProjection.res.mjs +0 -108
  31. package/src/admin/ApiFragmentRegistry/ApiFragmentsReadModelSpec.res +0 -23
  32. package/src/admin/ApiFragmentRegistry/ApiFragmentsReadModelSpec.res.mjs +0 -43
  33. package/src/admin/Platform_ApiFragmentsApi.res +0 -32
  34. package/src/admin/Platform_ApiFragmentsApi.res.mjs +0 -52
  35. package/src/components/Api/Api_Builder.res +0 -40
  36. package/src/components/Api/Api_Builder.res.mjs +0 -33
  37. package/src/components/Api/Api_Operations.res +0 -13
  38. package/src/components/Api/Api_Operations.res.mjs +0 -12
  39. package/src/components/Api/GraphQL_PushPlanner.res +0 -65
  40. package/src/components/Api/GraphQL_PushPlanner.res.mjs +0 -46
  41. package/tests/admin/Platform_ApiFragmentsApiTest.res +0 -66
  42. package/tests/admin/Platform_ApiFragmentsApiTest.res.mjs +0 -68
  43. package/tests/api/GraphQL_PushPlannerTest.res +0 -62
  44. package/tests/api/GraphQL_PushPlannerTest.res.mjs +0 -80
@@ -1,46 +0,0 @@
1
- // Generated by ReScript, PLEASE EDIT WITH CARE
2
-
3
- import * as S from "sury/src/S.res.mjs";
4
- import * as GraphQL_Stitcher$ReventlessCore from "./GraphQL_Stitcher.res.mjs";
5
-
6
- let planTargetSchema = S.union([
7
- S.literal("DomainApi"),
8
- S.literal("PlatformApi")
9
- ]);
10
-
11
- let emptyBase = GraphQL_Stitcher$ReventlessCore.encode({
12
- types: [],
13
- mutations: [],
14
- queries: [],
15
- subscriptions: [],
16
- subscriptionSources: []
17
- });
18
-
19
- function planPushes(adminBase, fragments, splitApi) {
20
- if (splitApi) {
21
- let platformFrags = fragments.filter(f => f.target === "Platform").map(f => f.fragment);
22
- let domainFrags = fragments.filter(f => f.target === "Domain").map(f => f.fragment);
23
- return [
24
- {
25
- api: "PlatformApi",
26
- sdl: GraphQL_Stitcher$ReventlessCore.stitch(adminBase, platformFrags)
27
- },
28
- {
29
- api: "DomainApi",
30
- sdl: GraphQL_Stitcher$ReventlessCore.stitch(emptyBase, domainFrags)
31
- }
32
- ];
33
- }
34
- let allFrags = fragments.map(f => f.fragment);
35
- return [{
36
- api: "DomainApi",
37
- sdl: GraphQL_Stitcher$ReventlessCore.stitch(adminBase, allFrags)
38
- }];
39
- }
40
-
41
- export {
42
- planTargetSchema,
43
- emptyBase,
44
- planPushes,
45
- }
46
- /* planTargetSchema Not a pure module */
@@ -1,66 +0,0 @@
1
- // Asserts the canonical JSON shape produced by encodeApiFragmentEntry — the
2
- // deploy-facing status surface of the API-schema fragment registry, shared by
3
- // the in-memory and AWS adapters. Status only (no encoded SDL). If this test
4
- // changes, any deploy waiter parsing Platform_ApiFragments is affected.
5
-
6
- open JestGlobals
7
-
8
- let state: ApiFragmentsReadModelSpec.state = {
9
- pluginId: "Catalog",
10
- encoded: `{"types":[],"mutations":[],"queries":[],"subscriptions":[],"subscriptionSources":[]}`,
11
- protocol: "graphql",
12
- apiTarget: Reventless.Plugin.Domain,
13
- registeredAt: "2026-05-14T00:00:00.000Z",
14
- updatedAt: "2026-05-14T00:00:00.000Z",
15
- pushStatus: "ok",
16
- pushMessage: "",
17
- pushedAt: "2026-05-14T00:00:01.000Z",
18
- }
19
-
20
- let encoded = Platform_ApiFragmentsApi.encodeApiFragmentEntry(state)
21
- let json = encoded->JSON.stringify
22
-
23
- describe("encodeApiFragmentEntry", () => {
24
- testSync("produces a JSON object with the expected top-level keys (status only, no SDL)", () => {
25
- let dict = encoded->JSON.Decode.object->Option.getOr(Dict.make())
26
- let keys = dict->Dict.keysToArray->Array.toSorted(String.compare)
27
- expect(keys)->toEqual([
28
- "apiTarget",
29
- "pluginId",
30
- "pushMessage",
31
- "pushStatus",
32
- "pushedAt",
33
- "registeredAt",
34
- "updatedAt",
35
- ])
36
- })
37
-
38
- testSync("encodes pluginId", () =>
39
- expect(json->String.includes("\"pluginId\":\"Catalog\""))->toEqual(true)
40
- )
41
-
42
- testSync("encodes the apiTarget variant as its bare string", () =>
43
- expect(json->String.includes("\"apiTarget\":\"Domain\""))->toEqual(true)
44
- )
45
-
46
- testSync("encodes pushStatus", () =>
47
- expect(json->String.includes("\"pushStatus\":\"ok\""))->toEqual(true)
48
- )
49
-
50
- testSync("does not leak the encoded SDL into the status shape", () =>
51
- expect(json->String.includes("subscriptionSources"))->toEqual(false)
52
- )
53
- })
54
-
55
- describe("Platform_ApiFragmentsApi.sdl", () => {
56
- testSync("query field declares the list type", () =>
57
- expect(Platform_ApiFragmentsApi.sdlQueryField->String.includes("[Platform_ApiFragmentEntry!]!"))
58
- ->toEqual(true)
59
- )
60
-
61
- testSync("sdlTypes includes Platform_ApiFragmentEntry with pushStatus field", () => {
62
- let allTypes = Platform_ApiFragmentsApi.sdlTypes->Array.join("\n")
63
- expect(allTypes->String.includes("Platform_ApiFragmentEntry"))->toEqual(true)
64
- expect(allTypes->String.includes("pushStatus: String!"))->toEqual(true)
65
- })
66
- })
@@ -1,68 +0,0 @@
1
- // Generated by ReScript, PLEASE EDIT WITH CARE
2
-
3
- import * as Stdlib_JSON from "@rescript/runtime/lib/es6/Stdlib_JSON.js";
4
- import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
5
- import * as Primitive_string from "@rescript/runtime/lib/es6/Primitive_string.js";
6
- import * as Platform_ApiFragmentsApi$ReventlessCore from "../../src/admin/Platform_ApiFragmentsApi.res.mjs";
7
-
8
- let state = {
9
- pluginId: "Catalog",
10
- encoded: `{"types":[],"mutations":[],"queries":[],"subscriptions":[],"subscriptionSources":[]}`,
11
- protocol: "graphql",
12
- apiTarget: "Domain",
13
- registeredAt: "2026-05-14T00:00:00.000Z",
14
- updatedAt: "2026-05-14T00:00:00.000Z",
15
- pushStatus: "ok",
16
- pushMessage: "",
17
- pushedAt: "2026-05-14T00:00:01.000Z"
18
- };
19
-
20
- let encoded = Platform_ApiFragmentsApi$ReventlessCore.encodeApiFragmentEntry(state);
21
-
22
- let json = JSON.stringify(encoded);
23
-
24
- globalThis.describe("encodeApiFragmentEntry", () => {
25
- globalThis.test("produces a JSON object with the expected top-level keys (status only, no SDL)", () => {
26
- let dict = Stdlib_Option.getOr(Stdlib_JSON.Decode.object(encoded), {});
27
- let keys = Object.keys(dict).toSorted(Primitive_string.compare);
28
- globalThis.expect(keys).toEqual([
29
- "apiTarget",
30
- "pluginId",
31
- "pushMessage",
32
- "pushStatus",
33
- "pushedAt",
34
- "registeredAt",
35
- "updatedAt"
36
- ]);
37
- });
38
- globalThis.test("encodes pluginId", () => {
39
- globalThis.expect(json.includes("\"pluginId\":\"Catalog\"")).toEqual(true);
40
- });
41
- globalThis.test("encodes the apiTarget variant as its bare string", () => {
42
- globalThis.expect(json.includes("\"apiTarget\":\"Domain\"")).toEqual(true);
43
- });
44
- globalThis.test("encodes pushStatus", () => {
45
- globalThis.expect(json.includes("\"pushStatus\":\"ok\"")).toEqual(true);
46
- });
47
- globalThis.test("does not leak the encoded SDL into the status shape", () => {
48
- globalThis.expect(json.includes("subscriptionSources")).toEqual(false);
49
- });
50
- });
51
-
52
- globalThis.describe("Platform_ApiFragmentsApi.sdl", () => {
53
- globalThis.test("query field declares the list type", () => {
54
- globalThis.expect(Platform_ApiFragmentsApi$ReventlessCore.sdlQueryField.includes("[Platform_ApiFragmentEntry!]!")).toEqual(true);
55
- });
56
- globalThis.test("sdlTypes includes Platform_ApiFragmentEntry with pushStatus field", () => {
57
- let allTypes = Platform_ApiFragmentsApi$ReventlessCore.sdlTypes.join("\n");
58
- globalThis.expect(allTypes.includes("Platform_ApiFragmentEntry")).toEqual(true);
59
- globalThis.expect(allTypes.includes("pushStatus: String!")).toEqual(true);
60
- });
61
- });
62
-
63
- export {
64
- state,
65
- encoded,
66
- json,
67
- }
68
- /* encoded Not a pure module */
@@ -1,62 +0,0 @@
1
- open JestGlobals
2
- open GraphQL_PushPlanner
3
-
4
- // Minimal neutral fragments. `stitch` always adds Relay base types + `node`, so we assert on the
5
- // distinctive field names to know which base/fragments landed in each plan.
6
- let mkFragment = (~query: string): Reventless.Plugin.apiSchemaFragment =>
7
- GraphQL_Stitcher.encode({
8
- types: [],
9
- queries: [query],
10
- mutations: [],
11
- subscriptions: [],
12
- subscriptionSources: [],
13
- })
14
-
15
- let adminBase = mkFragment(~query=" Admin_Q: String")
16
- let domainFrag = mkFragment(~query=" Domain_Q: String")
17
- let platformFrag = mkFragment(~query=" Platform_Q: String")
18
-
19
- let fragments = [
20
- {fragment: domainFrag, target: Domain},
21
- {fragment: platformFrag, target: Platform},
22
- ]
23
-
24
- let planFor = (plans: array<pushPlan>, api: planTarget): option<pushPlan> =>
25
- plans->Array.find(p => p.api == api)
26
-
27
- describe("GraphQL_PushPlanner.planPushes", () => {
28
- testSync("split mode: admin base + Platform fragments on the Platform API only", () => {
29
- let plans = planPushes(~adminBase, ~fragments, ~splitApi=true)
30
- expect(plans->Array.length)->toBe(2)
31
- let platform = planFor(plans, PlatformApi)->Belt.Option.getExn
32
- expect(platform.sdl->String.includes("Admin_Q"))->toBe(true)
33
- expect(platform.sdl->String.includes("Platform_Q"))->toBe(true)
34
- expect(platform.sdl->String.includes("Domain_Q"))->toBe(false)
35
- })
36
-
37
- testSync("split mode: empty base + Domain fragments on the Domain API only (no admin)", () => {
38
- let plans = planPushes(~adminBase, ~fragments, ~splitApi=true)
39
- let domain = planFor(plans, DomainApi)->Belt.Option.getExn
40
- expect(domain.sdl->String.includes("Domain_Q"))->toBe(true)
41
- expect(domain.sdl->String.includes("Admin_Q"))->toBe(false)
42
- expect(domain.sdl->String.includes("Platform_Q"))->toBe(false)
43
- })
44
-
45
- testSync("unified mode: one Domain API push with admin base + ALL fragments", () => {
46
- let plans = planPushes(~adminBase, ~fragments, ~splitApi=false)
47
- expect(plans->Array.length)->toBe(1)
48
- let only = plans->Array.getUnsafe(0)
49
- expect(only.api == DomainApi)->toBe(true)
50
- expect(only.sdl->String.includes("Admin_Q"))->toBe(true)
51
- expect(only.sdl->String.includes("Domain_Q"))->toBe(true)
52
- expect(only.sdl->String.includes("Platform_Q"))->toBe(true)
53
- })
54
-
55
- testSync("empty registry still pushes the admin base (split → Platform API)", () => {
56
- let plans = planPushes(~adminBase, ~fragments=[], ~splitApi=true)
57
- let platform = planFor(plans, PlatformApi)->Belt.Option.getExn
58
- expect(platform.sdl->String.includes("Admin_Q"))->toBe(true)
59
- let domain = planFor(plans, DomainApi)->Belt.Option.getExn
60
- expect(domain.sdl->String.includes("Admin_Q"))->toBe(false)
61
- })
62
- })
@@ -1,80 +0,0 @@
1
- // Generated by ReScript, PLEASE EDIT WITH CARE
2
-
3
- import * as Belt_Option from "@rescript/runtime/lib/es6/Belt_Option.js";
4
- import * as GraphQL_Stitcher$ReventlessCore from "../../src/components/Api/GraphQL_Stitcher.res.mjs";
5
- import * as GraphQL_PushPlanner$ReventlessCore from "../../src/components/Api/GraphQL_PushPlanner.res.mjs";
6
-
7
- function mkFragment(query) {
8
- return GraphQL_Stitcher$ReventlessCore.encode({
9
- types: [],
10
- mutations: [],
11
- queries: [query],
12
- subscriptions: [],
13
- subscriptionSources: []
14
- });
15
- }
16
-
17
- let adminBase = mkFragment(" Admin_Q: String");
18
-
19
- let domainFrag = mkFragment(" Domain_Q: String");
20
-
21
- let platformFrag = mkFragment(" Platform_Q: String");
22
-
23
- let fragments = [
24
- {
25
- fragment: domainFrag,
26
- target: "Domain"
27
- },
28
- {
29
- fragment: platformFrag,
30
- target: "Platform"
31
- }
32
- ];
33
-
34
- function planFor(plans, api) {
35
- return plans.find(p => p.api === api);
36
- }
37
-
38
- globalThis.describe("GraphQL_PushPlanner.planPushes", () => {
39
- globalThis.test("split mode: admin base + Platform fragments on the Platform API only", () => {
40
- let plans = GraphQL_PushPlanner$ReventlessCore.planPushes(adminBase, fragments, true);
41
- globalThis.expect(plans.length).toBe(2);
42
- let platform = Belt_Option.getExn(planFor(plans, "PlatformApi"));
43
- globalThis.expect(platform.sdl.includes("Admin_Q")).toBe(true);
44
- globalThis.expect(platform.sdl.includes("Platform_Q")).toBe(true);
45
- globalThis.expect(platform.sdl.includes("Domain_Q")).toBe(false);
46
- });
47
- globalThis.test("split mode: empty base + Domain fragments on the Domain API only (no admin)", () => {
48
- let plans = GraphQL_PushPlanner$ReventlessCore.planPushes(adminBase, fragments, true);
49
- let domain = Belt_Option.getExn(planFor(plans, "DomainApi"));
50
- globalThis.expect(domain.sdl.includes("Domain_Q")).toBe(true);
51
- globalThis.expect(domain.sdl.includes("Admin_Q")).toBe(false);
52
- globalThis.expect(domain.sdl.includes("Platform_Q")).toBe(false);
53
- });
54
- globalThis.test("unified mode: one Domain API push with admin base + ALL fragments", () => {
55
- let plans = GraphQL_PushPlanner$ReventlessCore.planPushes(adminBase, fragments, false);
56
- globalThis.expect(plans.length).toBe(1);
57
- let only = plans[0];
58
- globalThis.expect(only.api === "DomainApi").toBe(true);
59
- globalThis.expect(only.sdl.includes("Admin_Q")).toBe(true);
60
- globalThis.expect(only.sdl.includes("Domain_Q")).toBe(true);
61
- globalThis.expect(only.sdl.includes("Platform_Q")).toBe(true);
62
- });
63
- globalThis.test("empty registry still pushes the admin base (split → Platform API)", () => {
64
- let plans = GraphQL_PushPlanner$ReventlessCore.planPushes(adminBase, [], true);
65
- let platform = Belt_Option.getExn(planFor(plans, "PlatformApi"));
66
- globalThis.expect(platform.sdl.includes("Admin_Q")).toBe(true);
67
- let domain = Belt_Option.getExn(planFor(plans, "DomainApi"));
68
- globalThis.expect(domain.sdl.includes("Admin_Q")).toBe(false);
69
- });
70
- });
71
-
72
- export {
73
- mkFragment,
74
- adminBase,
75
- domainFrag,
76
- platformFrag,
77
- fragments,
78
- planFor,
79
- }
80
- /* adminBase Not a pure module */