@reventlessdev/reventless-core 3.0.0-alpha.162 → 3.0.0-alpha.164
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.
- package/CHANGELOG.md +15 -0
- package/package.json +5 -5
- package/src/plugin/component/Plugin_SubscriptionSchema.res +10 -2
- package/src/plugin/component/Plugin_SubscriptionSchema.res.mjs +10 -6
- package/src/admin/ApiFragmentRegistry/StateChangeSlice/ApiFragmentRegistry.res +0 -65
- package/src/admin/ApiFragmentRegistry/StateChangeSlice/ApiFragmentRegistry.res.mjs +0 -87
- package/src/admin/ApiFragmentRegistry/StateChangeSlice/ApiFragmentRegistry_Behavior.res +0 -58
- package/src/admin/ApiFragmentRegistry/StateChangeSlice/ApiFragmentRegistry_Behavior.res.mjs +0 -135
- package/src/admin/ApiFragmentRegistry/StateViewSlice/ApiFragments.res +0 -44
- package/src/admin/ApiFragmentRegistry/StateViewSlice/ApiFragments.res.mjs +0 -74
- package/src/admin/ApiFragmentRegistry/StateViewSlice/ApiFragments_Projection.res +0 -50
- package/src/admin/ApiFragmentRegistry/StateViewSlice/ApiFragments_Projection.res.mjs +0 -80
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,21 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
# 3.0.0-alpha.164 (2026-07-13)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @reventlessdev/reventless-core
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
# 3.0.0-alpha.163 (2026-07-13)
|
|
15
|
+
|
|
16
|
+
### Bug Fixes
|
|
17
|
+
|
|
18
|
+
* **admin:** skip over-long Source-C subscriptions on the ApiFragmentRegistry aggregate (deploy [#6](https://github.com/ReventlessDev/reventless-core/issues/6)) ([0977120](https://github.com/ReventlessDev/reventless-core/commit/0977120d5c6cb2331d9384747d136fe99855690e))
|
|
19
|
+
|
|
20
|
+
|
|
6
21
|
# 3.0.0-alpha.162 (2026-07-13)
|
|
7
22
|
|
|
8
23
|
### Bug Fixes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reventlessdev/reventless-core",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.164",
|
|
4
4
|
"description": "Core package for Reventless framework",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"jest": {
|
|
@@ -29,16 +29,16 @@
|
|
|
29
29
|
"sury": "11.0.0-alpha.4",
|
|
30
30
|
"uuid": "^13.0.0",
|
|
31
31
|
"@reventlessdev/rescript-effect": "0.1.0-alpha.27",
|
|
32
|
-
"@reventlessdev/rescript-hash-object": "1.2.0-alpha.11",
|
|
33
32
|
"@reventlessdev/rescript-jest": "1.0.0-alpha.7",
|
|
34
|
-
"@reventlessdev/rescript-node-streams": "1.1.0-alpha.11",
|
|
35
33
|
"@reventlessdev/rescript-fast-csv": "1.2.0-alpha.12",
|
|
34
|
+
"@reventlessdev/rescript-hash-object": "1.2.0-alpha.11",
|
|
35
|
+
"@reventlessdev/rescript-node-streams": "1.1.0-alpha.11",
|
|
36
36
|
"@reventlessdev/rescript-pulumi-pulumi": "2.3.0-alpha.15",
|
|
37
37
|
"@reventlessdev/rescript-uuid": "1.1.0-alpha.15",
|
|
38
38
|
"@reventlessdev/reventless-infra": "3.0.0-alpha.98",
|
|
39
|
+
"@reventlessdev/rescript-ssh2": "1.1.0-alpha.12",
|
|
39
40
|
"@reventlessdev/reventless-interop": "3.0.0-alpha.26",
|
|
40
|
-
"@reventlessdev/reventless-spec": "3.0.0-alpha.76"
|
|
41
|
-
"@reventlessdev/rescript-ssh2": "1.1.0-alpha.12"
|
|
41
|
+
"@reventlessdev/reventless-spec": "3.0.0-alpha.76"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"rescript": "^12.3.0",
|
|
@@ -30,8 +30,16 @@ let sourceCFields = (
|
|
|
30
30
|
let fields: array<string> = []
|
|
31
31
|
let sources: array<GraphQL_Stitcher.subscriptionSource> = []
|
|
32
32
|
let pushField = (fieldName: string) => {
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
// AppSync caps subscription field names at 50 chars. A mutation whose `on<field>`
|
|
34
|
+
// Source-C subscription would exceed that (e.g. the admin-aggregate-convention
|
|
35
|
+
// `Platform_ApiFragmentRegistry_DeregisterApiFragment` → 52) simply gets NO
|
|
36
|
+
// mutation-triggered subscription — the field is dropped here so the pushed SDL stays
|
|
37
|
+
// valid, and the resolver side (CommandSubscriptionResolvers) applies the same gate so
|
|
38
|
+
// no orphan resolver is created. Plugin mutations are far under the cap and unaffected.
|
|
39
|
+
if `on${fieldName}`->String.length <= Api_Naming.appSyncSubscriptionMaxLen {
|
|
40
|
+
fields->Array.push(` on${fieldName}(id: ID): CommandResult`)
|
|
41
|
+
sources->Array.push({GraphQL_Stitcher.field: `on${fieldName}`, mutations: [fieldName]})
|
|
42
|
+
}
|
|
35
43
|
}
|
|
36
44
|
mutationEntries->Array.forEach(entry => {
|
|
37
45
|
let schema = entry.commandSchema
|
|
@@ -1,16 +1,20 @@
|
|
|
1
1
|
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
2
|
|
|
3
3
|
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
4
|
+
import * as Api_Naming$ReventlessCore from "../../components/Api/Api_Naming.res.mjs";
|
|
4
5
|
|
|
5
6
|
function sourceCFields(mutationEntries) {
|
|
6
7
|
let fields = [];
|
|
7
8
|
let sources = [];
|
|
8
9
|
let pushField = fieldName => {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
if ((`on` + fieldName).length <= Api_Naming$ReventlessCore.appSyncSubscriptionMaxLen) {
|
|
11
|
+
fields.push(` on` + fieldName + `(id: ID): CommandResult`);
|
|
12
|
+
sources.push({
|
|
13
|
+
field: `on` + fieldName,
|
|
14
|
+
mutations: [fieldName]
|
|
15
|
+
});
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
14
18
|
};
|
|
15
19
|
mutationEntries.forEach(entry => {
|
|
16
20
|
let schema = entry.commandSchema;
|
|
@@ -77,4 +81,4 @@ export {
|
|
|
77
81
|
sourceAFieldsAndTypes,
|
|
78
82
|
generate,
|
|
79
83
|
}
|
|
80
|
-
/*
|
|
84
|
+
/* Api_Naming-ReventlessCore Not a pure module */
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
// ApiFragmentRegistry StateChangeSlice — the write side of the platform API-schema
|
|
2
|
-
// fragment registry, replacing the raw `deploy-schema:*` keyspace (see
|
|
3
|
-
// docs/plans/event-sourced-fragment-registries.md).
|
|
4
|
-
//
|
|
5
|
-
// Unlike the UiFragmentRegistry (connect/disconnect-driven), this registry's transitions
|
|
6
|
-
// are driven by the DEPLOY / DESTROY of a plugin stack: the deploy registers its fragment
|
|
7
|
-
// as a SigV4 system caller against the Platform API, and only final retirement
|
|
8
|
-
// (`pulumi destroy`, resolvers gone) deregisters. Version supersession must NOT
|
|
9
|
-
// deregister — the registry is keyed by plugin NAME, so a successor's deploy overwrites
|
|
10
|
-
// its predecessor's fragment in place.
|
|
11
|
-
//
|
|
12
|
-
// The registry is idempotent: re-registering an identical fragment is a no-op,
|
|
13
|
-
// deregistering an absent fragment is a no-op — it never rejects a command.
|
|
14
|
-
//
|
|
15
|
-
// `RecordApiFragmentPush` is the write-back of the single-writer schema-push automation:
|
|
16
|
-
// after stitching and pushing the composed schema it records the outcome (ok / error +
|
|
17
|
-
// message) on the row of the plugin whose fragment change triggered the push, so a
|
|
18
|
-
// deploy waiter can poll the push status instead of timing out on introspection.
|
|
19
|
-
@@reventless.spec
|
|
20
|
-
|
|
21
|
-
open Reventless.Plugin
|
|
22
|
-
|
|
23
|
-
// `at` is the registration timestamp, stamped from the incoming command meta by the
|
|
24
|
-
// dispatching mapping — the StateViewSlice projection has no event meta, so time must
|
|
25
|
-
// ride the payload. Inline records let the ppx auto-tag `pluginId` (scoping the decision
|
|
26
|
-
// read to one plugin name). `message` is a plain string ("" = none) — option fields in
|
|
27
|
-
// variant payloads don't survive the T|null wire contract cleanly.
|
|
28
|
-
//
|
|
29
|
-
// `apiTarget` is the API this plugin's fields belong to — Domain (the default) or Platform.
|
|
30
|
-
// A plugin assigned to the Platform API (e.g. a platform inspector) stitches into the
|
|
31
|
-
// Platform-API schema, not the Domain-API one; the single-writer push automation groups
|
|
32
|
-
// fragments by this target and maintains one cumulative schema per API.
|
|
33
|
-
// `RegisterApiFragment` / `DeregisterApiFragment` ARE the GraphQL surface — the deploy calls them
|
|
34
|
-
// as a SigV4 system caller against the Platform API (exposed as `Platform_RegisterApiFragment` /
|
|
35
|
-
// `Platform_DeregisterApiFragment`). `RecordApiFragmentPush` is `@noApi`: it is the internal
|
|
36
|
-
// write-back of the single-writer schema-push automation, dispatched platform-side, never by a
|
|
37
|
-
// GraphQL caller.
|
|
38
|
-
@schema
|
|
39
|
-
type command =
|
|
40
|
-
| RegisterApiFragment({pluginId: string, fragment: apiSchemaFragment, apiTarget: apiTarget, at: string})
|
|
41
|
-
| DeregisterApiFragment({pluginId: string})
|
|
42
|
-
| @noApi RecordApiFragmentPush({pluginId: string, ok: bool, message: string, at: string})
|
|
43
|
-
|
|
44
|
-
// The registry never rejects (idempotent register/deregister/record); this variant is
|
|
45
|
-
// never returned.
|
|
46
|
-
@schema
|
|
47
|
-
type error = | RegistryError
|
|
48
|
-
|
|
49
|
-
@schema
|
|
50
|
-
type event =
|
|
51
|
-
| ApiFragmentRegistered({pluginId: string, fragment: apiSchemaFragment, apiTarget: apiTarget, at: string})
|
|
52
|
-
| ApiFragmentUpdated({
|
|
53
|
-
pluginId: string,
|
|
54
|
-
previousFragment: apiSchemaFragment,
|
|
55
|
-
newFragment: apiSchemaFragment,
|
|
56
|
-
apiTarget: apiTarget,
|
|
57
|
-
at: string,
|
|
58
|
-
})
|
|
59
|
-
| ApiFragmentDeregistered({pluginId: string})
|
|
60
|
-
| ApiFragmentPushRecorded({pluginId: string, ok: bool, message: string, at: string})
|
|
61
|
-
|
|
62
|
-
// This slice reads exactly the events it writes, so consumedEvent IS event — one inline
|
|
63
|
-
// event type, no duplicate-constructor collision, ppx auto-tags `pluginId` on both roles.
|
|
64
|
-
@schema
|
|
65
|
-
type consumedEvent = event
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
-
|
|
3
|
-
import * as S from "sury/src/S.res.mjs";
|
|
4
|
-
import * as DcbTag$Reventless from "@reventlessdev/reventless-spec/src/components/DcbTag.res.mjs";
|
|
5
|
-
import * as Plugin$Reventless from "@reventlessdev/reventless-spec/src/components/Plugin.res.mjs";
|
|
6
|
-
import * as Api$ReventlessInfra from "@reventlessdev/reventless-infra/src/components/Api.res.mjs";
|
|
7
|
-
|
|
8
|
-
let commandSchema = S.union([
|
|
9
|
-
S.schema(s => ({
|
|
10
|
-
TAG: "RegisterApiFragment",
|
|
11
|
-
pluginId: s.m(DcbTag$Reventless.string),
|
|
12
|
-
fragment: s.m(Plugin$Reventless.apiSchemaFragmentSchema),
|
|
13
|
-
apiTarget: s.m(Plugin$Reventless.apiTargetSchema),
|
|
14
|
-
at: s.m(S.string)
|
|
15
|
-
})),
|
|
16
|
-
S.schema(s => ({
|
|
17
|
-
TAG: "DeregisterApiFragment",
|
|
18
|
-
pluginId: s.m(DcbTag$Reventless.string)
|
|
19
|
-
})),
|
|
20
|
-
S.schema(s => ({
|
|
21
|
-
TAG: "RecordApiFragmentPush",
|
|
22
|
-
pluginId: s.m(DcbTag$Reventless.string),
|
|
23
|
-
ok: s.m(S.bool),
|
|
24
|
-
message: s.m(S.string),
|
|
25
|
-
at: s.m(S.string)
|
|
26
|
-
}))
|
|
27
|
-
]);
|
|
28
|
-
|
|
29
|
-
let errorSchema = S.literal("RegistryError");
|
|
30
|
-
|
|
31
|
-
let eventSchema = S.union([
|
|
32
|
-
S.schema(s => ({
|
|
33
|
-
TAG: "ApiFragmentRegistered",
|
|
34
|
-
pluginId: s.m(DcbTag$Reventless.string),
|
|
35
|
-
fragment: s.m(Plugin$Reventless.apiSchemaFragmentSchema),
|
|
36
|
-
apiTarget: s.m(Plugin$Reventless.apiTargetSchema),
|
|
37
|
-
at: s.m(S.string)
|
|
38
|
-
})),
|
|
39
|
-
S.schema(s => ({
|
|
40
|
-
TAG: "ApiFragmentUpdated",
|
|
41
|
-
pluginId: s.m(DcbTag$Reventless.string),
|
|
42
|
-
previousFragment: s.m(Plugin$Reventless.apiSchemaFragmentSchema),
|
|
43
|
-
newFragment: s.m(Plugin$Reventless.apiSchemaFragmentSchema),
|
|
44
|
-
apiTarget: s.m(Plugin$Reventless.apiTargetSchema),
|
|
45
|
-
at: s.m(S.string)
|
|
46
|
-
})),
|
|
47
|
-
S.schema(s => ({
|
|
48
|
-
TAG: "ApiFragmentDeregistered",
|
|
49
|
-
pluginId: s.m(DcbTag$Reventless.string)
|
|
50
|
-
})),
|
|
51
|
-
S.schema(s => ({
|
|
52
|
-
TAG: "ApiFragmentPushRecorded",
|
|
53
|
-
pluginId: s.m(DcbTag$Reventless.string),
|
|
54
|
-
ok: s.m(S.bool),
|
|
55
|
-
message: s.m(S.string),
|
|
56
|
-
at: s.m(S.string)
|
|
57
|
-
}))
|
|
58
|
-
]);
|
|
59
|
-
|
|
60
|
-
let commandSchema$1 = Api$ReventlessInfra.markNoApiVariants(commandSchema, ["RecordApiFragmentPush"]);
|
|
61
|
-
|
|
62
|
-
function commandAuthorization(param) {
|
|
63
|
-
return "AllowAuthenticated";
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
let name = "ApiFragmentRegistry";
|
|
67
|
-
|
|
68
|
-
let Id;
|
|
69
|
-
|
|
70
|
-
let consumedEventSchema = eventSchema;
|
|
71
|
-
|
|
72
|
-
let moduleUrl = "@reventlessdev/reventless-core/src/admin/ApiFragmentRegistry/StateChangeSlice/ApiFragmentRegistry.res.mjs";
|
|
73
|
-
|
|
74
|
-
let readConsistency = "EscalateOnRetry";
|
|
75
|
-
|
|
76
|
-
export {
|
|
77
|
-
name,
|
|
78
|
-
Id,
|
|
79
|
-
errorSchema,
|
|
80
|
-
eventSchema,
|
|
81
|
-
consumedEventSchema,
|
|
82
|
-
commandSchema$1 as commandSchema,
|
|
83
|
-
moduleUrl,
|
|
84
|
-
commandAuthorization,
|
|
85
|
-
readConsistency,
|
|
86
|
-
}
|
|
87
|
-
/* commandSchema Not a pure module */
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
@@reventless.behavior
|
|
2
|
-
|
|
3
|
-
open Reventless.Plugin
|
|
4
|
-
|
|
5
|
-
// The current fragment for this plugin name plus its target API and the last recorded push
|
|
6
|
-
// outcome (kept only to dedupe at-least-once redelivery of RecordApiFragmentPush), or None
|
|
7
|
-
// when no fragment is registered.
|
|
8
|
-
type registryEntry = {
|
|
9
|
-
fragment: apiSchemaFragment,
|
|
10
|
-
apiTarget: apiTarget,
|
|
11
|
-
lastPush: option<(bool, string, string)>, // (ok, message, at)
|
|
12
|
-
}
|
|
13
|
-
type state = option<registryEntry>
|
|
14
|
-
|
|
15
|
-
let initialState = None
|
|
16
|
-
|
|
17
|
-
let evolve = (state, event) =>
|
|
18
|
-
switch event {
|
|
19
|
-
| ApiFragmentRegistered({fragment, apiTarget}) => Some({fragment, apiTarget, lastPush: None})
|
|
20
|
-
| ApiFragmentUpdated({newFragment, apiTarget}) =>
|
|
21
|
-
Some({fragment: newFragment, apiTarget, lastPush: None})
|
|
22
|
-
| ApiFragmentDeregistered(_) => None
|
|
23
|
-
| ApiFragmentPushRecorded({ok, message, at}) =>
|
|
24
|
-
state->Option.map(entry => {...entry, lastPush: Some((ok, message, at))})
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
let decide = (state, command) =>
|
|
28
|
-
switch command {
|
|
29
|
-
| RegisterApiFragment({pluginId, fragment, apiTarget, at}) =>
|
|
30
|
-
switch state {
|
|
31
|
-
| None => Ok([ApiFragmentRegistered({pluginId, fragment, apiTarget, at})])
|
|
32
|
-
// Idempotent: an unchanged re-registration (same fragment AND same target — e.g. a
|
|
33
|
-
// redeploy carrying the same schema, or a version supersession that didn't change the
|
|
34
|
-
// SDL) emits nothing. A target change with an identical fragment IS meaningful (the
|
|
35
|
-
// fields move between the Domain and Platform APIs), so it is not a no-op.
|
|
36
|
-
| Some({fragment: current, apiTarget: currentTarget})
|
|
37
|
-
if current == fragment && currentTarget == apiTarget =>
|
|
38
|
-
Ok([])
|
|
39
|
-
| Some({fragment: current}) =>
|
|
40
|
-
Ok([
|
|
41
|
-
ApiFragmentUpdated({pluginId, previousFragment: current, newFragment: fragment, apiTarget, at}),
|
|
42
|
-
])
|
|
43
|
-
}
|
|
44
|
-
| DeregisterApiFragment({pluginId}) =>
|
|
45
|
-
switch state {
|
|
46
|
-
| None => Ok([]) // idempotent — nothing registered
|
|
47
|
-
| Some(_) => Ok([ApiFragmentDeregistered({pluginId: pluginId})])
|
|
48
|
-
}
|
|
49
|
-
| RecordApiFragmentPush({pluginId, ok, message, at}) =>
|
|
50
|
-
switch state {
|
|
51
|
-
| None => Ok([]) // fragment deregistered in the meantime — nowhere to record
|
|
52
|
-
// Idempotent: an at-least-once redelivery carries the identical payload.
|
|
53
|
-
| Some({lastPush: Some((lastOk, lastMessage, lastAt))})
|
|
54
|
-
if lastOk == ok && lastMessage == message && lastAt == at =>
|
|
55
|
-
Ok([])
|
|
56
|
-
| Some(_) => Ok([ApiFragmentPushRecorded({pluginId, ok, message, at})])
|
|
57
|
-
}
|
|
58
|
-
}
|
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
-
|
|
3
|
-
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
4
|
-
import * as Primitive_object from "@rescript/runtime/lib/es6/Primitive_object.js";
|
|
5
|
-
|
|
6
|
-
function evolve(state, event) {
|
|
7
|
-
switch (event.TAG) {
|
|
8
|
-
case "ApiFragmentRegistered" :
|
|
9
|
-
return {
|
|
10
|
-
fragment: event.fragment,
|
|
11
|
-
apiTarget: event.apiTarget,
|
|
12
|
-
lastPush: undefined
|
|
13
|
-
};
|
|
14
|
-
case "ApiFragmentUpdated" :
|
|
15
|
-
return {
|
|
16
|
-
fragment: event.newFragment,
|
|
17
|
-
apiTarget: event.apiTarget,
|
|
18
|
-
lastPush: undefined
|
|
19
|
-
};
|
|
20
|
-
case "ApiFragmentDeregistered" :
|
|
21
|
-
return;
|
|
22
|
-
case "ApiFragmentPushRecorded" :
|
|
23
|
-
let at = event.at;
|
|
24
|
-
let message = event.message;
|
|
25
|
-
let ok = event.ok;
|
|
26
|
-
return Stdlib_Option.map(state, entry => ({
|
|
27
|
-
fragment: entry.fragment,
|
|
28
|
-
apiTarget: entry.apiTarget,
|
|
29
|
-
lastPush: [
|
|
30
|
-
ok,
|
|
31
|
-
message,
|
|
32
|
-
at
|
|
33
|
-
]
|
|
34
|
-
}));
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
function decide(state, command) {
|
|
39
|
-
switch (command.TAG) {
|
|
40
|
-
case "RegisterApiFragment" :
|
|
41
|
-
let at = command.at;
|
|
42
|
-
let apiTarget = command.apiTarget;
|
|
43
|
-
let fragment = command.fragment;
|
|
44
|
-
let pluginId = command.pluginId;
|
|
45
|
-
if (state === undefined) {
|
|
46
|
-
return {
|
|
47
|
-
TAG: "Ok",
|
|
48
|
-
_0: [{
|
|
49
|
-
TAG: "ApiFragmentRegistered",
|
|
50
|
-
pluginId: pluginId,
|
|
51
|
-
fragment: fragment,
|
|
52
|
-
apiTarget: apiTarget,
|
|
53
|
-
at: at
|
|
54
|
-
}]
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
|
-
let current = state.fragment;
|
|
58
|
-
if (Primitive_object.equal(current, fragment) && state.apiTarget === apiTarget) {
|
|
59
|
-
return {
|
|
60
|
-
TAG: "Ok",
|
|
61
|
-
_0: []
|
|
62
|
-
};
|
|
63
|
-
} else {
|
|
64
|
-
return {
|
|
65
|
-
TAG: "Ok",
|
|
66
|
-
_0: [{
|
|
67
|
-
TAG: "ApiFragmentUpdated",
|
|
68
|
-
pluginId: pluginId,
|
|
69
|
-
previousFragment: current,
|
|
70
|
-
newFragment: fragment,
|
|
71
|
-
apiTarget: apiTarget,
|
|
72
|
-
at: at
|
|
73
|
-
}]
|
|
74
|
-
};
|
|
75
|
-
}
|
|
76
|
-
case "DeregisterApiFragment" :
|
|
77
|
-
if (state !== undefined) {
|
|
78
|
-
return {
|
|
79
|
-
TAG: "Ok",
|
|
80
|
-
_0: [{
|
|
81
|
-
TAG: "ApiFragmentDeregistered",
|
|
82
|
-
pluginId: command.pluginId
|
|
83
|
-
}]
|
|
84
|
-
};
|
|
85
|
-
} else {
|
|
86
|
-
return {
|
|
87
|
-
TAG: "Ok",
|
|
88
|
-
_0: []
|
|
89
|
-
};
|
|
90
|
-
}
|
|
91
|
-
case "RecordApiFragmentPush" :
|
|
92
|
-
if (state === undefined) {
|
|
93
|
-
return {
|
|
94
|
-
TAG: "Ok",
|
|
95
|
-
_0: []
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
|
-
let match = state.lastPush;
|
|
99
|
-
let at$1 = command.at;
|
|
100
|
-
let message = command.message;
|
|
101
|
-
let ok = command.ok;
|
|
102
|
-
if (match !== undefined && match[0] === ok && match[1] === message && match[2] === at$1) {
|
|
103
|
-
return {
|
|
104
|
-
TAG: "Ok",
|
|
105
|
-
_0: []
|
|
106
|
-
};
|
|
107
|
-
}
|
|
108
|
-
return {
|
|
109
|
-
TAG: "Ok",
|
|
110
|
-
_0: [{
|
|
111
|
-
TAG: "ApiFragmentPushRecorded",
|
|
112
|
-
pluginId: command.pluginId,
|
|
113
|
-
ok: ok,
|
|
114
|
-
message: message,
|
|
115
|
-
at: at$1
|
|
116
|
-
}]
|
|
117
|
-
};
|
|
118
|
-
break;
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
let Spec;
|
|
123
|
-
|
|
124
|
-
let initialState;
|
|
125
|
-
|
|
126
|
-
let moduleUrl = "@reventlessdev/reventless-core/src/admin/ApiFragmentRegistry/StateChangeSlice/ApiFragmentRegistry_Behavior.res.mjs";
|
|
127
|
-
|
|
128
|
-
export {
|
|
129
|
-
Spec,
|
|
130
|
-
initialState,
|
|
131
|
-
evolve,
|
|
132
|
-
decide,
|
|
133
|
-
moduleUrl,
|
|
134
|
-
}
|
|
135
|
-
/* No side effect */
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
// ApiFragments StateViewSlice — the read side of the platform API-schema fragment
|
|
2
|
-
// registry: the current fragment per plugin name plus the outcome of the last schema
|
|
3
|
-
// push that included it. Replaces the raw `deploy-schema:*` rows as the durable source
|
|
4
|
-
// the single-writer stitch automation and the runtime re-stitcher read, and backs the
|
|
5
|
-
// push-status poll of the deploy waiter.
|
|
6
|
-
//
|
|
7
|
-
// `pushStatus` is "pending" from registration/update until the automation records the
|
|
8
|
-
// push outcome ("ok" / "error"); `pushMessage`/`pushedAt` are "" until then (plain
|
|
9
|
-
// strings, no option fields — see the producer spec).
|
|
10
|
-
@@reventless.spec
|
|
11
|
-
|
|
12
|
-
@schema
|
|
13
|
-
type state = {
|
|
14
|
-
pluginId: string,
|
|
15
|
-
encoded: string,
|
|
16
|
-
protocol: string,
|
|
17
|
-
apiTarget: Reventless.Plugin.apiTarget,
|
|
18
|
-
registeredAt: string,
|
|
19
|
-
updatedAt: string,
|
|
20
|
-
pushStatus: string,
|
|
21
|
-
pushMessage: string,
|
|
22
|
-
pushedAt: string,
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
// Consumes the ApiFragmentRegistry slice's events (from the shared admin DcbEventLog).
|
|
26
|
-
// Inline records with the same constructors/fields as the producer's `event` — decodes
|
|
27
|
-
// byte-identically and the ppx auto-tags `pluginId`.
|
|
28
|
-
@schema
|
|
29
|
-
type consumedEvent =
|
|
30
|
-
| ApiFragmentRegistered({
|
|
31
|
-
pluginId: string,
|
|
32
|
-
fragment: Reventless.Plugin.apiSchemaFragment,
|
|
33
|
-
apiTarget: Reventless.Plugin.apiTarget,
|
|
34
|
-
at: string,
|
|
35
|
-
})
|
|
36
|
-
| ApiFragmentUpdated({
|
|
37
|
-
pluginId: string,
|
|
38
|
-
previousFragment: Reventless.Plugin.apiSchemaFragment,
|
|
39
|
-
newFragment: Reventless.Plugin.apiSchemaFragment,
|
|
40
|
-
apiTarget: Reventless.Plugin.apiTarget,
|
|
41
|
-
at: string,
|
|
42
|
-
})
|
|
43
|
-
| ApiFragmentDeregistered({pluginId: string})
|
|
44
|
-
| ApiFragmentPushRecorded({pluginId: string, ok: bool, message: string, at: string})
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
-
|
|
3
|
-
import * as S from "sury/src/S.res.mjs";
|
|
4
|
-
import * as DcbTag$Reventless from "@reventlessdev/reventless-spec/src/components/DcbTag.res.mjs";
|
|
5
|
-
import * as Plugin$Reventless from "@reventlessdev/reventless-spec/src/components/Plugin.res.mjs";
|
|
6
|
-
import * as ReadModel$Reventless from "@reventlessdev/reventless-spec/src/components/ReadModel.res.mjs";
|
|
7
|
-
|
|
8
|
-
let stateSchema = S.schema(s => ({
|
|
9
|
-
pluginId: s.m(S.string),
|
|
10
|
-
encoded: s.m(S.string),
|
|
11
|
-
protocol: s.m(S.string),
|
|
12
|
-
apiTarget: s.m(Plugin$Reventless.apiTargetSchema),
|
|
13
|
-
registeredAt: s.m(S.string),
|
|
14
|
-
updatedAt: s.m(S.string),
|
|
15
|
-
pushStatus: s.m(S.string),
|
|
16
|
-
pushMessage: s.m(S.string),
|
|
17
|
-
pushedAt: s.m(S.string)
|
|
18
|
-
}));
|
|
19
|
-
|
|
20
|
-
let consumedEventSchema = S.union([
|
|
21
|
-
S.schema(s => ({
|
|
22
|
-
TAG: "ApiFragmentRegistered",
|
|
23
|
-
pluginId: s.m(DcbTag$Reventless.string),
|
|
24
|
-
fragment: s.m(Plugin$Reventless.apiSchemaFragmentSchema),
|
|
25
|
-
apiTarget: s.m(Plugin$Reventless.apiTargetSchema),
|
|
26
|
-
at: s.m(S.string)
|
|
27
|
-
})),
|
|
28
|
-
S.schema(s => ({
|
|
29
|
-
TAG: "ApiFragmentUpdated",
|
|
30
|
-
pluginId: s.m(DcbTag$Reventless.string),
|
|
31
|
-
previousFragment: s.m(Plugin$Reventless.apiSchemaFragmentSchema),
|
|
32
|
-
newFragment: s.m(Plugin$Reventless.apiSchemaFragmentSchema),
|
|
33
|
-
apiTarget: s.m(Plugin$Reventless.apiTargetSchema),
|
|
34
|
-
at: s.m(S.string)
|
|
35
|
-
})),
|
|
36
|
-
S.schema(s => ({
|
|
37
|
-
TAG: "ApiFragmentDeregistered",
|
|
38
|
-
pluginId: s.m(DcbTag$Reventless.string)
|
|
39
|
-
})),
|
|
40
|
-
S.schema(s => ({
|
|
41
|
-
TAG: "ApiFragmentPushRecorded",
|
|
42
|
-
pluginId: s.m(DcbTag$Reventless.string),
|
|
43
|
-
ok: s.m(S.bool),
|
|
44
|
-
message: s.m(S.string),
|
|
45
|
-
at: s.m(S.string)
|
|
46
|
-
}))
|
|
47
|
-
]);
|
|
48
|
-
|
|
49
|
-
let config = ReadModel$Reventless.config(undefined, undefined, undefined);
|
|
50
|
-
|
|
51
|
-
let name = "ApiFragments";
|
|
52
|
-
|
|
53
|
-
let Id;
|
|
54
|
-
|
|
55
|
-
let subIdConfig;
|
|
56
|
-
|
|
57
|
-
let moduleUrl = "@reventlessdev/reventless-core/src/admin/ApiFragmentRegistry/StateViewSlice/ApiFragments.res.mjs";
|
|
58
|
-
|
|
59
|
-
let authorization = "AllowAuthenticated";
|
|
60
|
-
|
|
61
|
-
let visibility = "Public";
|
|
62
|
-
|
|
63
|
-
export {
|
|
64
|
-
name,
|
|
65
|
-
Id,
|
|
66
|
-
stateSchema,
|
|
67
|
-
consumedEventSchema,
|
|
68
|
-
config,
|
|
69
|
-
subIdConfig,
|
|
70
|
-
moduleUrl,
|
|
71
|
-
authorization,
|
|
72
|
-
visibility,
|
|
73
|
-
}
|
|
74
|
-
/* stateSchema Not a pure module */
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
@@reventless.projection
|
|
2
|
-
|
|
3
|
-
// A fragment change resets the row to "pending" — the automation's push outcome for the
|
|
4
|
-
// new fragment arrives as a subsequent ApiFragmentPushRecorded. The Update on a deleted
|
|
5
|
-
// row (a push recorded after deregistration) is a no-op by Update semantics.
|
|
6
|
-
let project = event =>
|
|
7
|
-
switch event {
|
|
8
|
-
| ApiFragmentRegistered({pluginId, fragment, apiTarget, at}) => [
|
|
9
|
-
Set(
|
|
10
|
-
pluginId,
|
|
11
|
-
{
|
|
12
|
-
pluginId,
|
|
13
|
-
encoded: fragment.encoded,
|
|
14
|
-
protocol: fragment.protocol,
|
|
15
|
-
apiTarget,
|
|
16
|
-
registeredAt: at,
|
|
17
|
-
updatedAt: at,
|
|
18
|
-
pushStatus: "pending",
|
|
19
|
-
pushMessage: "",
|
|
20
|
-
pushedAt: "",
|
|
21
|
-
},
|
|
22
|
-
),
|
|
23
|
-
]
|
|
24
|
-
| ApiFragmentUpdated({pluginId, newFragment, apiTarget, at}) => [
|
|
25
|
-
Update(
|
|
26
|
-
pluginId,
|
|
27
|
-
state => {
|
|
28
|
-
...state,
|
|
29
|
-
encoded: newFragment.encoded,
|
|
30
|
-
protocol: newFragment.protocol,
|
|
31
|
-
apiTarget,
|
|
32
|
-
updatedAt: at,
|
|
33
|
-
pushStatus: "pending",
|
|
34
|
-
pushMessage: "",
|
|
35
|
-
},
|
|
36
|
-
),
|
|
37
|
-
]
|
|
38
|
-
| ApiFragmentDeregistered({pluginId}) => [Delete(pluginId)]
|
|
39
|
-
| ApiFragmentPushRecorded({pluginId, ok, message, at}) => [
|
|
40
|
-
Update(
|
|
41
|
-
pluginId,
|
|
42
|
-
state => {
|
|
43
|
-
...state,
|
|
44
|
-
pushStatus: ok ? "ok" : "error",
|
|
45
|
-
pushMessage: message,
|
|
46
|
-
pushedAt: at,
|
|
47
|
-
},
|
|
48
|
-
),
|
|
49
|
-
]
|
|
50
|
-
}
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
function project(event) {
|
|
5
|
-
switch (event.TAG) {
|
|
6
|
-
case "ApiFragmentRegistered" :
|
|
7
|
-
let at = event.at;
|
|
8
|
-
let fragment = event.fragment;
|
|
9
|
-
let pluginId = event.pluginId;
|
|
10
|
-
return [{
|
|
11
|
-
TAG: "Set",
|
|
12
|
-
_0: pluginId,
|
|
13
|
-
_1: {
|
|
14
|
-
pluginId: pluginId,
|
|
15
|
-
encoded: fragment.encoded,
|
|
16
|
-
protocol: fragment.protocol,
|
|
17
|
-
apiTarget: event.apiTarget,
|
|
18
|
-
registeredAt: at,
|
|
19
|
-
updatedAt: at,
|
|
20
|
-
pushStatus: "pending",
|
|
21
|
-
pushMessage: "",
|
|
22
|
-
pushedAt: ""
|
|
23
|
-
}
|
|
24
|
-
}];
|
|
25
|
-
case "ApiFragmentUpdated" :
|
|
26
|
-
let at$1 = event.at;
|
|
27
|
-
let apiTarget = event.apiTarget;
|
|
28
|
-
let newFragment = event.newFragment;
|
|
29
|
-
return [{
|
|
30
|
-
TAG: "Update",
|
|
31
|
-
_0: event.pluginId,
|
|
32
|
-
_1: state => ({
|
|
33
|
-
pluginId: state.pluginId,
|
|
34
|
-
encoded: newFragment.encoded,
|
|
35
|
-
protocol: newFragment.protocol,
|
|
36
|
-
apiTarget: apiTarget,
|
|
37
|
-
registeredAt: state.registeredAt,
|
|
38
|
-
updatedAt: at$1,
|
|
39
|
-
pushStatus: "pending",
|
|
40
|
-
pushMessage: "",
|
|
41
|
-
pushedAt: state.pushedAt
|
|
42
|
-
})
|
|
43
|
-
}];
|
|
44
|
-
case "ApiFragmentDeregistered" :
|
|
45
|
-
return [{
|
|
46
|
-
TAG: "Delete",
|
|
47
|
-
_0: event.pluginId
|
|
48
|
-
}];
|
|
49
|
-
case "ApiFragmentPushRecorded" :
|
|
50
|
-
let at$2 = event.at;
|
|
51
|
-
let message = event.message;
|
|
52
|
-
let ok = event.ok;
|
|
53
|
-
return [{
|
|
54
|
-
TAG: "Update",
|
|
55
|
-
_0: event.pluginId,
|
|
56
|
-
_1: state => ({
|
|
57
|
-
pluginId: state.pluginId,
|
|
58
|
-
encoded: state.encoded,
|
|
59
|
-
protocol: state.protocol,
|
|
60
|
-
apiTarget: state.apiTarget,
|
|
61
|
-
registeredAt: state.registeredAt,
|
|
62
|
-
updatedAt: state.updatedAt,
|
|
63
|
-
pushStatus: ok ? "ok" : "error",
|
|
64
|
-
pushMessage: message,
|
|
65
|
-
pushedAt: at$2
|
|
66
|
-
})
|
|
67
|
-
}];
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
let Spec;
|
|
72
|
-
|
|
73
|
-
let moduleUrl = "@reventlessdev/reventless-core/src/admin/ApiFragmentRegistry/StateViewSlice/ApiFragments_Projection.res.mjs";
|
|
74
|
-
|
|
75
|
-
export {
|
|
76
|
-
Spec,
|
|
77
|
-
project,
|
|
78
|
-
moduleUrl,
|
|
79
|
-
}
|
|
80
|
-
/* No side effect */
|