@reventlessdev/reventless-core 3.0.0-alpha.201 → 3.0.0-alpha.202
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 +8 -0
- package/package.json +6 -6
- package/src/plugin/component/Plugin_Builder.res +27 -2
- package/src/plugin/component/Plugin_Builder.res.mjs +19 -2
- package/src/plugin/component/Plugin_Helpers.res +21 -0
- package/src/plugin/component/Plugin_Helpers.res.mjs +15 -0
- package/src/plugin/lifecycle/PluginsReadModelSpec.res +6 -4
- package/src/plugin/lifecycle/PluginsReadModelSpec.res.mjs +2 -2
- package/tests/message/MessageTest.res +4 -3
- package/tests/message/MessageTest.res.mjs +25 -21
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,14 @@
|
|
|
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.202 (2026-08-02)
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
* **core:** deploy-time offload hook seam for plugin payloads ([7f970eb](https://github.com/ReventlessDev/reventless-core/commit/7f970eb449765e781559c6596ee49dd74b9451bc))
|
|
11
|
+
* **spec:** make plugin structure/apiSchemaFragment offloadable payloads ([a0391bf](https://github.com/ReventlessDev/reventless-core/commit/a0391bf26f91035460cbf90f52d105a1003414c3))
|
|
12
|
+
|
|
13
|
+
|
|
6
14
|
# 3.0.0-alpha.201 (2026-08-02)
|
|
7
15
|
|
|
8
16
|
### Features
|
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.202",
|
|
4
4
|
"description": "Core package for Reventless framework",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"jest": {
|
|
@@ -28,17 +28,17 @@
|
|
|
28
28
|
"dependencies": {
|
|
29
29
|
"sury": "11.0.0-alpha.4",
|
|
30
30
|
"uuid": "^13.0.0",
|
|
31
|
-
"@reventlessdev/rescript-fast-csv": "2.0.0-alpha.0",
|
|
32
31
|
"@reventlessdev/rescript-effect": "0.1.0-alpha.32",
|
|
33
32
|
"@reventlessdev/rescript-hash-object": "1.2.0-alpha.14",
|
|
33
|
+
"@reventlessdev/rescript-fast-csv": "2.0.0-alpha.0",
|
|
34
34
|
"@reventlessdev/rescript-jest": "1.0.0-alpha.10",
|
|
35
35
|
"@reventlessdev/rescript-node": "2.0.0-alpha.0",
|
|
36
36
|
"@reventlessdev/rescript-pulumi-pulumi": "2.3.0-alpha.18",
|
|
37
|
-
"@reventlessdev/rescript-ssh2": "2.0.0-alpha.0",
|
|
38
|
-
"@reventlessdev/reventless-infra": "3.0.0-alpha.118",
|
|
39
37
|
"@reventlessdev/rescript-uuid": "2.0.0-alpha.0",
|
|
40
|
-
"@reventlessdev/
|
|
41
|
-
"@reventlessdev/reventless-
|
|
38
|
+
"@reventlessdev/rescript-ssh2": "2.0.0-alpha.0",
|
|
39
|
+
"@reventlessdev/reventless-infra": "3.0.0-alpha.119",
|
|
40
|
+
"@reventlessdev/reventless-spec": "3.0.0-alpha.94",
|
|
41
|
+
"@reventlessdev/reventless-interop": "3.0.0-alpha.30"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"rescript": "12.3.0",
|
|
@@ -738,6 +738,31 @@ module Make = (
|
|
|
738
738
|
// so reading it inside the async callback would always yield "Domain".
|
|
739
739
|
let capturedDeployTarget = Spec.hooks.deployTarget.contents
|
|
740
740
|
|
|
741
|
+
// Offload the two large pluginDefinition fields at deploy time when a
|
|
742
|
+
// provider offers an object store (AWS writes a content-addressed object
|
|
743
|
+
// and returns a reference); unset locally, so they stay Inline. Both
|
|
744
|
+
// values are concrete here, so the hook — and the object write it does —
|
|
745
|
+
// runs at graph-construction time, before the Pulumi.Output.apply below
|
|
746
|
+
// (a resource cannot be created inside .apply). Unconditional: these
|
|
747
|
+
// fields are always large enough to be worth offloading.
|
|
748
|
+
let toPayload = (value, ~schema, ~store) =>
|
|
749
|
+
switch Plugin_Helpers.offloadHook.contents {
|
|
750
|
+
| Some(hook) =>
|
|
751
|
+
Reventless.Offload.Offloaded(
|
|
752
|
+
hook(~store, ~bytes=value->S.reverseConvertToJsonStringOrThrow(schema)),
|
|
753
|
+
)
|
|
754
|
+
| None => Reventless.Offload.Inline(value)
|
|
755
|
+
}
|
|
756
|
+
let apiSchemaFragmentPayload = toPayload(
|
|
757
|
+
apiSchemaFragment,
|
|
758
|
+
~schema=Reventless.Plugin.apiSchemaFragmentSchema,
|
|
759
|
+
~store="pluginApiFragments",
|
|
760
|
+
)
|
|
761
|
+
let structurePayload =
|
|
762
|
+
pluginStructure->Option.map(s =>
|
|
763
|
+
toPayload(s, ~schema=Reventless.Plugin.pluginStructureSchema, ~store="pluginStructures")
|
|
764
|
+
)
|
|
765
|
+
|
|
741
766
|
// DCB EventLog definition — Some when this plugin has a DcbEventLog
|
|
742
767
|
// component, None otherwise. Admin's manageSubscriptions reads this to
|
|
743
768
|
// provision cross-plugin SNS subscriptions from peer plugins' DCB
|
|
@@ -769,9 +794,9 @@ module Make = (
|
|
|
769
794
|
extensions: extensionsDefinitions,
|
|
770
795
|
eventCollector: eventCollectorUrn,
|
|
771
796
|
extensionProtocols: [],
|
|
772
|
-
apiSchemaFragment: Some(
|
|
797
|
+
apiSchemaFragment: Some(apiSchemaFragmentPayload),
|
|
773
798
|
apiTarget: Some(capturedDeployTarget),
|
|
774
|
-
structure:
|
|
799
|
+
structure: structurePayload,
|
|
775
800
|
dcbEventLog: dcbEventLogDef,
|
|
776
801
|
// Business role from the deploy-time metadata registry (set via
|
|
777
802
|
// registerPluginMetadata). Unset → Domain. Rides the handshake to the
|
|
@@ -8,6 +8,7 @@ import * as Belt_SetString from "@rescript/runtime/lib/es6/Belt_SetString.js";
|
|
|
8
8
|
import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
|
|
9
9
|
import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
|
|
10
10
|
import * as DcbTag$Reventless from "@reventlessdev/reventless-spec/src/components/DcbTag.res.mjs";
|
|
11
|
+
import * as Plugin$Reventless from "@reventlessdev/reventless-spec/src/components/Plugin.res.mjs";
|
|
11
12
|
import * as Logger$ReventlessCore from "../../util/Logger.res.mjs";
|
|
12
13
|
import * as Plugin$ReventlessCore from "./Plugin.res.mjs";
|
|
13
14
|
import * as StackReference$Pulumi from "@reventlessdev/rescript-pulumi-pulumi/src/StackReference.res.mjs";
|
|
@@ -486,6 +487,22 @@ function Make(Spec) {
|
|
|
486
487
|
let match$3 = EventCollectorHelper.make(childName, eventTopics, opts);
|
|
487
488
|
let eventCollector = match$3[0];
|
|
488
489
|
let capturedDeployTarget = Spec.hooks.deployTarget.contents;
|
|
490
|
+
let toPayload = (value, schema, store) => {
|
|
491
|
+
let hook = Plugin_Helpers$ReventlessCore.offloadHook.contents;
|
|
492
|
+
if (hook !== undefined) {
|
|
493
|
+
return {
|
|
494
|
+
TAG: "Offloaded",
|
|
495
|
+
_0: hook(store, S.reverseConvertToJsonStringOrThrow(value, schema, undefined))
|
|
496
|
+
};
|
|
497
|
+
} else {
|
|
498
|
+
return {
|
|
499
|
+
TAG: "Inline",
|
|
500
|
+
_0: value
|
|
501
|
+
};
|
|
502
|
+
}
|
|
503
|
+
};
|
|
504
|
+
let apiSchemaFragmentPayload = toPayload(apiSchemaFragment, Plugin$Reventless.apiSchemaFragmentSchema, "pluginApiFragments");
|
|
505
|
+
let structurePayload = Stdlib_Option.map(pluginStructure, s => toPayload(s, Plugin$Reventless.pluginStructureSchema, "pluginStructures"));
|
|
489
506
|
let dcbOutputs$1 = dcbResult.dcbEventLogOutputs;
|
|
490
507
|
let dcbEventLogDef;
|
|
491
508
|
if (dcbOutputs$1 !== undefined) {
|
|
@@ -509,9 +526,9 @@ function Make(Spec) {
|
|
|
509
526
|
extensions: extensionsDefinitions,
|
|
510
527
|
eventCollector: param[1],
|
|
511
528
|
extensionProtocols: [],
|
|
512
|
-
apiSchemaFragment:
|
|
529
|
+
apiSchemaFragment: apiSchemaFragmentPayload,
|
|
513
530
|
apiTarget: capturedDeployTarget,
|
|
514
|
-
structure:
|
|
531
|
+
structure: structurePayload,
|
|
515
532
|
dcbEventLog: param[2],
|
|
516
533
|
kind: Stdlib_Option.getOr(Stdlib_Option.flatMap(Plugin_Helpers$ReventlessCore.pluginMetadataRegistry.contents, m => m.kind), "Domain")
|
|
517
534
|
}));
|
|
@@ -785,6 +785,27 @@ let clearOnPluginDeployed = () => {
|
|
|
785
785
|
onPluginDeployedHook.contents = None
|
|
786
786
|
}
|
|
787
787
|
|
|
788
|
+
// ---------------------------------------------------------------------------
|
|
789
|
+
// Deploy-time offload hook — content-addresses a large pluginDefinition field
|
|
790
|
+
// to an object store and returns the reference. Set by a provider that can
|
|
791
|
+
// write objects (AWS creates a BucketObject); unset on the local platform, so
|
|
792
|
+
// the fields stay Inline. `bytes` is the already-serialized JSON of the value;
|
|
793
|
+
// the provider hashes it, stores it at `sha256/<hash>`, and returns the ref.
|
|
794
|
+
// Fired synchronously at graph-construction time (the value is concrete and a
|
|
795
|
+
// resource cannot be created inside a Pulumi.Output.apply).
|
|
796
|
+
// ---------------------------------------------------------------------------
|
|
797
|
+
let offloadHook: ref<option<(~store: string, ~bytes: string) => Reventless.Offload.offloadedRef>> = ref(
|
|
798
|
+
None,
|
|
799
|
+
)
|
|
800
|
+
|
|
801
|
+
let registerOffload = (hook: (~store: string, ~bytes: string) => Reventless.Offload.offloadedRef) => {
|
|
802
|
+
offloadHook.contents = Some(hook)
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
let clearOffload = () => {
|
|
806
|
+
offloadHook.contents = None
|
|
807
|
+
}
|
|
808
|
+
|
|
788
809
|
// ---------------------------------------------------------------------------
|
|
789
810
|
// Platform-deployed hook — fires after deployPlatform / makePlatform
|
|
790
811
|
// completes, providing platform-level metadata with resolved values.
|
|
@@ -418,6 +418,18 @@ function clearOnPluginDeployed() {
|
|
|
418
418
|
onPluginDeployedHook.contents = undefined;
|
|
419
419
|
}
|
|
420
420
|
|
|
421
|
+
let offloadHook = {
|
|
422
|
+
contents: undefined
|
|
423
|
+
};
|
|
424
|
+
|
|
425
|
+
function registerOffload(hook) {
|
|
426
|
+
offloadHook.contents = hook;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
function clearOffload() {
|
|
430
|
+
offloadHook.contents = undefined;
|
|
431
|
+
}
|
|
432
|
+
|
|
421
433
|
let onPlatformDeployedHook = {
|
|
422
434
|
contents: undefined
|
|
423
435
|
};
|
|
@@ -1015,6 +1027,9 @@ export {
|
|
|
1015
1027
|
onPluginDeployedHook,
|
|
1016
1028
|
registerOnPluginDeployed,
|
|
1017
1029
|
clearOnPluginDeployed,
|
|
1030
|
+
offloadHook,
|
|
1031
|
+
registerOffload,
|
|
1032
|
+
clearOffload,
|
|
1018
1033
|
onPlatformDeployedHook,
|
|
1019
1034
|
lastPlatformDeployedInfo,
|
|
1020
1035
|
registerOnPlatformDeployed,
|
|
@@ -24,13 +24,15 @@ type state = {
|
|
|
24
24
|
extensions: array<Reventless.Plugin.extensionDefinition>,
|
|
25
25
|
status: status,
|
|
26
26
|
statusChange: Message.statusChange,
|
|
27
|
-
apiSchemaFragment: @s.matches(Reventless.Plugin.
|
|
27
|
+
apiSchemaFragment: @s.matches(Reventless.Plugin.apiSchemaFragmentOffloadSchema)
|
|
28
|
+
option<Reventless.Offload.payload<Reventless.Plugin.apiSchemaFragment>>,
|
|
28
29
|
// API target for split-API schema routing. Absent/None means "Domain" (backward compat).
|
|
29
30
|
// "Platform" → excluded from DomainApi runtime schema stitching in updateApiSchema.
|
|
30
31
|
apiTarget?: string,
|
|
31
32
|
// Plugin structure (component metadata) — surfaced via Platform_ComponentDefinitions.
|
|
32
33
|
// None for older plugins whose protocol version did not carry the field.
|
|
33
|
-
structure: @s.matches(Reventless.Plugin.
|
|
34
|
+
structure: @s.matches(Reventless.Plugin.pluginStructureOffloadSchema)
|
|
35
|
+
option<Reventless.Offload.payload<Reventless.Plugin.pluginStructure>>,
|
|
34
36
|
// DCB EventLog definition for plugins that bundle a DcbEventLog component.
|
|
35
37
|
// Admin's manageSubscriptions uses this to wire cross-plugin SNS subscriptions
|
|
36
38
|
// from this plugin's DCB topic → peer EventCollectors (and vice-versa). None
|
|
@@ -72,9 +74,9 @@ type queryResult = {
|
|
|
72
74
|
extensionNames: array<string>,
|
|
73
75
|
extensions: array<Reventless.Plugin.extensionDefinition>,
|
|
74
76
|
status: status,
|
|
75
|
-
apiSchemaFragment: option<Reventless.Plugin.apiSchemaFragment
|
|
77
|
+
apiSchemaFragment: option<Reventless.Offload.payload<Reventless.Plugin.apiSchemaFragment>>,
|
|
76
78
|
apiTarget?: string,
|
|
77
|
-
structure: option<Reventless.Plugin.pluginStructure
|
|
79
|
+
structure: option<Reventless.Offload.payload<Reventless.Plugin.pluginStructure>>,
|
|
78
80
|
dcbEventLog: option<Reventless.Plugin.dcbEventLogDefinition>,
|
|
79
81
|
kind: option<Reventless.Plugin.pluginKind>,
|
|
80
82
|
}
|
|
@@ -23,9 +23,9 @@ let stateSchema = S.schema(s => ({
|
|
|
23
23
|
extensions: s.m(S.array(Plugin$Reventless.extensionDefinitionSchema)),
|
|
24
24
|
status: s.m(statusSchema),
|
|
25
25
|
statusChange: s.m(Message$ReventlessCore.statusChangeSchema),
|
|
26
|
-
apiSchemaFragment: s.m(Plugin$Reventless.
|
|
26
|
+
apiSchemaFragment: s.m(Plugin$Reventless.apiSchemaFragmentOffloadSchema),
|
|
27
27
|
apiTarget: s.m(S.option(S.string)),
|
|
28
|
-
structure: s.m(Plugin$Reventless.
|
|
28
|
+
structure: s.m(Plugin$Reventless.pluginStructureOffloadSchema),
|
|
29
29
|
dcbEventLog: s.m(Plugin$Reventless.dcbEventLogOptionSchema),
|
|
30
30
|
kind: s.m(S.option(Plugin$Reventless.pluginKindSchema)),
|
|
31
31
|
otherConnectedVersions: s.m(S.array(Plugin$Reventless.versionSchema))
|
|
@@ -109,7 +109,7 @@ describe("Message should", () => {
|
|
|
109
109
|
extensionProtocols: [],
|
|
110
110
|
apiSchemaFragment: None,
|
|
111
111
|
apiTarget: None,
|
|
112
|
-
structure: Some({
|
|
112
|
+
structure: Some(Reventless.Offload.Inline({
|
|
113
113
|
readModels: [],
|
|
114
114
|
stateViewSlices: [],
|
|
115
115
|
stateChangeSlices: [],
|
|
@@ -132,7 +132,7 @@ describe("Message should", () => {
|
|
|
132
132
|
extensionPoints: None,
|
|
133
133
|
requiredStores: None,
|
|
134
134
|
requiredStoreDeclarations: None,
|
|
135
|
-
}),
|
|
135
|
+
})),
|
|
136
136
|
dcbEventLog: None,
|
|
137
137
|
kind: Domain,
|
|
138
138
|
}
|
|
@@ -186,7 +186,8 @@ describe("Message should", () => {
|
|
|
186
186
|
},
|
|
187
187
|
)->toBe("Domain")
|
|
188
188
|
expect(d.apiSchemaFragment->Option.isNone)->toBe(true)
|
|
189
|
-
let structure: Reventless.Plugin.pluginStructure =
|
|
189
|
+
let structure: Reventless.Plugin.pluginStructure =
|
|
190
|
+
d.structure->Option.flatMap(Reventless.Offload.getInline)->Option.getOrThrow
|
|
190
191
|
let agg = structure.aggregates->Array.getUnsafe(0)
|
|
191
192
|
expect(agg.events->Array.length)->toBe(0)
|
|
192
193
|
expect(agg.chapter->Option.isNone)->toBe(true)
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import * as S from "sury/src/S.res.mjs";
|
|
4
4
|
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
5
|
+
import * as Offload$Reventless from "@reventlessdev/reventless-spec/src/semantic/Offload.res.mjs";
|
|
5
6
|
import * as Message$ReventlessCore from "../../src/Message.res.mjs";
|
|
6
7
|
import * as PluginSpec$ReventlessCore from "../../src/plugin/lifecycle/PluginSpec.res.mjs";
|
|
7
8
|
|
|
@@ -100,26 +101,29 @@ globalThis.describe("Message should", () => {
|
|
|
100
101
|
apiSchemaFragment: undefined,
|
|
101
102
|
apiTarget: undefined,
|
|
102
103
|
structure: {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
104
|
+
TAG: "Inline",
|
|
105
|
+
_0: {
|
|
106
|
+
readModels: [],
|
|
107
|
+
stateViewSlices: [],
|
|
108
|
+
stateChangeSlices: [],
|
|
109
|
+
aggregates: [{
|
|
110
|
+
name: "Order",
|
|
111
|
+
commands: [],
|
|
112
|
+
producedEventTypes: [],
|
|
113
|
+
consumedEventTypes: [],
|
|
114
|
+
linkedViews: [],
|
|
115
|
+
consistencyRead: undefined,
|
|
116
|
+
events: [],
|
|
117
|
+
chapter: undefined
|
|
118
|
+
}],
|
|
119
|
+
automationSlices: [],
|
|
120
|
+
outboundTranslationSlices: [],
|
|
121
|
+
inboundTranslationSlices: [],
|
|
122
|
+
extensions: [],
|
|
123
|
+
extensionPoints: undefined,
|
|
124
|
+
requiredStores: undefined,
|
|
125
|
+
requiredStoreDeclarations: undefined
|
|
126
|
+
}
|
|
123
127
|
},
|
|
124
128
|
dcbEventLog: undefined,
|
|
125
129
|
kind: "Domain"
|
|
@@ -169,7 +173,7 @@ globalThis.describe("Message should", () => {
|
|
|
169
173
|
tmp = match === "Domain" ? "Domain" : "other";
|
|
170
174
|
globalThis.expect(tmp).toBe("Domain");
|
|
171
175
|
globalThis.expect(Stdlib_Option.isNone(d$1.apiSchemaFragment)).toBe(true);
|
|
172
|
-
let structure = Stdlib_Option.getOrThrow(d$1.structure, undefined);
|
|
176
|
+
let structure = Stdlib_Option.getOrThrow(Stdlib_Option.flatMap(d$1.structure, Offload$Reventless.getInline), undefined);
|
|
173
177
|
let agg = structure.aggregates[0];
|
|
174
178
|
globalThis.expect(agg.events.length).toBe(0);
|
|
175
179
|
globalThis.expect(Stdlib_Option.isNone(agg.chapter)).toBe(true);
|