@reventlessdev/reventless-core 3.0.0-alpha.219 → 3.0.0-alpha.221
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 +14 -0
- package/package.json +8 -8
- package/src/adapter/RuntimeExtension/RuntimeExtension.res +34 -0
- package/src/adapter/RuntimeExtension/RuntimeExtension.res.mjs +5 -0
- package/src/components/Api/SuryToJsonSchema.res +13 -4
- package/src/components/Api/SuryToJsonSchema.res.mjs +10 -3
- package/src/plugin/lifecycle/PluginsReadModelSpec.res.mjs +2 -1
- package/tests/adapter/RuntimeExtensionHookReachTest.res +1 -0
- package/tests/adapter/RuntimeExtensionHookReachTest.res.mjs +2 -0
- package/tests/adapter/RuntimeExtensionTest.res +31 -1
- package/tests/adapter/RuntimeExtensionTest.res.mjs +32 -8
- package/tests/api/SuryToJsonSchemaTest.res +36 -0
- package/tests/api/SuryToJsonSchemaTest.res.mjs +158 -23
- package/tests/commandtopic/CommandOutcomeHookTest.res +1 -0
- package/tests/commandtopic/CommandOutcomeHookTest.res.mjs +2 -0
- package/tests/plugin/PluginStructureTest.res +11 -0
- package/tests/plugin/PluginStructureTest.res.mjs +7 -0
- package/tests/plugin/StateViewSlice/PsAnnotatedView.res +1 -0
- package/tests/plugin/StateViewSlice/PsAnnotatedView.res.mjs +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,20 @@
|
|
|
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.221 (2026-08-09)
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
* **ppx,spec,core:** [@live](https://github.com/live) on state declarations → top-level x-reventless-live schema key ([0f38f38](https://github.com/ReventlessDev/reventless-core/commit/0f38f38dc83c38da2fde6615b89a98cd7fda6fed))
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
# 3.0.0-alpha.220 (2026-08-09)
|
|
14
|
+
|
|
15
|
+
### Features
|
|
16
|
+
|
|
17
|
+
* **core,aws:** bundle a runtime extension's companion packages, guard imports at deploy ([e975175](https://github.com/ReventlessDev/reventless-core/commit/e9751758f51582a8e46db362219f725bb5f1bcde))
|
|
18
|
+
|
|
19
|
+
|
|
6
20
|
# 3.0.0-alpha.219 (2026-08-09)
|
|
7
21
|
|
|
8
22
|
**Note:** Version bump only for package @reventlessdev/reventless-core
|
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.221",
|
|
4
4
|
"description": "Core package for Reventless framework",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"jest": {
|
|
@@ -29,21 +29,21 @@
|
|
|
29
29
|
"sury": "11.0.0-alpha.4",
|
|
30
30
|
"uuid": "^13.0.0",
|
|
31
31
|
"@reventlessdev/rescript-effect": "0.1.0-alpha.32",
|
|
32
|
-
"@reventlessdev/rescript-fast-csv": "2.0.0-alpha.2",
|
|
33
32
|
"@reventlessdev/rescript-hash-object": "1.2.0-alpha.14",
|
|
33
|
+
"@reventlessdev/rescript-node": "2.0.0-alpha.3",
|
|
34
34
|
"@reventlessdev/rescript-jest": "1.0.0-alpha.10",
|
|
35
|
-
"@reventlessdev/rescript-
|
|
36
|
-
"@reventlessdev/rescript-ssh2": "2.0.0-alpha.2",
|
|
35
|
+
"@reventlessdev/rescript-fast-csv": "2.0.0-alpha.3",
|
|
37
36
|
"@reventlessdev/rescript-pulumi-pulumi": "2.3.0-alpha.18",
|
|
38
|
-
"@reventlessdev/
|
|
39
|
-
"@reventlessdev/
|
|
37
|
+
"@reventlessdev/rescript-ssh2": "2.0.0-alpha.3",
|
|
38
|
+
"@reventlessdev/reventless-infra": "3.0.0-alpha.132",
|
|
40
39
|
"@reventlessdev/reventless-interop": "3.0.0-alpha.30",
|
|
41
|
-
"@reventlessdev/
|
|
40
|
+
"@reventlessdev/rescript-uuid": "2.0.0-alpha.0",
|
|
41
|
+
"@reventlessdev/reventless-spec": "3.0.0-alpha.106"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"rescript": "12.3.0",
|
|
45
45
|
"sury-ppx": "11.0.0-alpha.2",
|
|
46
|
-
"@reventlessdev/reventless-ppx": "1.0.0-alpha.
|
|
46
|
+
"@reventlessdev/reventless-ppx": "1.0.0-alpha.64"
|
|
47
47
|
},
|
|
48
48
|
"peerDependencies": {
|
|
49
49
|
"rescript": "12.3.0"
|
|
@@ -90,6 +90,28 @@ trade than a loud, skipped hook.
|
|
|
90
90
|
*/
|
|
91
91
|
module type Extension = {
|
|
92
92
|
let moduleUrl: string
|
|
93
|
+
/**
|
|
94
|
+
`import.meta.url` of one module per COMPANION package this extension imports at
|
|
95
|
+
runtime — packages that must ride into the code archive alongside the
|
|
96
|
+
extension's own. `[]` for an extension importing nothing outside the
|
|
97
|
+
framework-provided set.
|
|
98
|
+
|
|
99
|
+
Needed because a companion is invisible to every conventional lookup: the
|
|
100
|
+
ecosystem convention for split packages declares the neutral core as a
|
|
101
|
+
`peerDependency` (true in the deploy program's process, false in the Lambda),
|
|
102
|
+
so a `dependencies` walk finds nothing; and a companion named by bare package
|
|
103
|
+
name has no resolution root the framework could use — the one thing that
|
|
104
|
+
resolves robustly is a module URL the companion states about itself, exactly
|
|
105
|
+
like `moduleUrl`. A companion package exposes one by exporting
|
|
106
|
+
`let moduleUrl: string = %raw("import.meta.url")` from any module the
|
|
107
|
+
extension already imports (spec modules can lift the
|
|
108
|
+
`@@reventless.spec`-injected one).
|
|
109
|
+
|
|
110
|
+
Companions are bundle-only: the entry shell imports only the extension
|
|
111
|
+
modules, and Node resolves companions from the archive's `node_modules` like
|
|
112
|
+
any other import.
|
|
113
|
+
*/
|
|
114
|
+
let companionModuleUrls: array<string>
|
|
93
115
|
let onColdStart: coldStartHook
|
|
94
116
|
}
|
|
95
117
|
|
|
@@ -127,6 +149,18 @@ let moduleUrls = (): array<string> =>
|
|
|
127
149
|
E.moduleUrl
|
|
128
150
|
})
|
|
129
151
|
|
|
152
|
+
/**
|
|
153
|
+
Every registered extension's companion module URLs, flattened in registration
|
|
154
|
+
order. Read only by the provider's code-archive builder — unlike `moduleUrls`,
|
|
155
|
+
these never reach a runtime's config: companions are bundled so the extension's
|
|
156
|
+
own imports resolve, not imported by the entry shell.
|
|
157
|
+
*/
|
|
158
|
+
let companionModuleUrls = (): array<string> =>
|
|
159
|
+
extensions.contents->Array.flatMap(e => {
|
|
160
|
+
module E = unpack(e)
|
|
161
|
+
E.companionModuleUrls
|
|
162
|
+
})
|
|
163
|
+
|
|
130
164
|
let log = Logger.fromEnv()
|
|
131
165
|
|
|
132
166
|
/**
|
|
@@ -26,6 +26,10 @@ function moduleUrls() {
|
|
|
26
26
|
return extensions.contents.map(e => e.moduleUrl);
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
+
function companionModuleUrls() {
|
|
30
|
+
return extensions.contents.flatMap(e => e.companionModuleUrls);
|
|
31
|
+
}
|
|
32
|
+
|
|
29
33
|
let log = Logger$ReventlessCore.fromEnv();
|
|
30
34
|
|
|
31
35
|
function runHook(hook, index, runtimeKind, component, plugin, platform) {
|
|
@@ -52,6 +56,7 @@ export {
|
|
|
52
56
|
reset,
|
|
53
57
|
isEmpty,
|
|
54
58
|
moduleUrls,
|
|
59
|
+
companionModuleUrls,
|
|
55
60
|
log,
|
|
56
61
|
runHook,
|
|
57
62
|
notifyColdStartHooks,
|
|
@@ -229,13 +229,22 @@ let deriveObjectSchema = (schema: S.t<unknown>): JSON.t =>
|
|
|
229
229
|
~optional=SchemaType.optionalFieldNames(schema),
|
|
230
230
|
fields,
|
|
231
231
|
)
|
|
232
|
-
// Surface component-level
|
|
233
|
-
//
|
|
232
|
+
// Surface component-level hints on the top-level object schema.
|
|
233
|
+
// Visibility is omitted entirely for the default `Public` (None) so schemas
|
|
234
|
+
// stay compact; live is emitted only when declared — an absent key means
|
|
235
|
+
// the consumer's own default applies.
|
|
234
236
|
switch annotations {
|
|
235
|
-
| Some({visibility
|
|
237
|
+
| Some({visibility, live}) if visibility->Option.isSome || live->Option.isSome =>
|
|
236
238
|
switch objSchema->JSON.Decode.object {
|
|
237
239
|
| Some(obj) =>
|
|
238
|
-
|
|
240
|
+
switch visibility {
|
|
241
|
+
| Some(name) => obj->Dict.set("x-reventless-visibility", JSON.Encode.string(name))
|
|
242
|
+
| None => ()
|
|
243
|
+
}
|
|
244
|
+
switch live {
|
|
245
|
+
| Some(b) => obj->Dict.set("x-reventless-live", JSON.Encode.bool(b))
|
|
246
|
+
| None => ()
|
|
247
|
+
}
|
|
239
248
|
JSON.Encode.object(obj)
|
|
240
249
|
| None => objSchema
|
|
241
250
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
2
|
|
|
3
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";
|
|
4
5
|
import * as Logger$ReventlessCore from "../../util/Logger.res.mjs";
|
|
5
6
|
import * as SchemaType$ReventlessCore from "./SchemaType.res.mjs";
|
|
6
7
|
import * as StateAnnotations$Reventless from "@reventlessdev/reventless-spec/src/components/StateAnnotations.res.mjs";
|
|
@@ -267,13 +268,19 @@ function deriveObjectSchema(schema) {
|
|
|
267
268
|
if (annotations === undefined) {
|
|
268
269
|
return objSchema;
|
|
269
270
|
}
|
|
270
|
-
let
|
|
271
|
-
|
|
271
|
+
let live = annotations.live;
|
|
272
|
+
let visibility = annotations.visibility;
|
|
273
|
+
if (!(Stdlib_Option.isSome(visibility) || Stdlib_Option.isSome(live))) {
|
|
272
274
|
return objSchema;
|
|
273
275
|
}
|
|
274
276
|
let obj = Stdlib_JSON.Decode.object(objSchema);
|
|
275
277
|
if (obj !== undefined) {
|
|
276
|
-
|
|
278
|
+
if (visibility !== undefined) {
|
|
279
|
+
obj["x-reventless-visibility"] = visibility;
|
|
280
|
+
}
|
|
281
|
+
if (live !== undefined) {
|
|
282
|
+
obj["x-reventless-live"] = live;
|
|
283
|
+
}
|
|
277
284
|
return obj;
|
|
278
285
|
} else {
|
|
279
286
|
return objSchema;
|
|
@@ -47,6 +47,7 @@ describe("RuntimeExtension reaches the runtime callback hooks", () => {
|
|
|
47
47
|
let seenAtColdStart: array<string> = []
|
|
48
48
|
module Gatekeeper: RuntimeExtension.Extension = {
|
|
49
49
|
let moduleUrl = "file:///pkg/gatekeeper.res.mjs"
|
|
50
|
+
let companionModuleUrls = []
|
|
50
51
|
let onColdStart = (~runtimeKind as _, ~component, ~plugin as _, ~platform as _) => {
|
|
51
52
|
seenAtColdStart->Array.push(component)
|
|
52
53
|
CommandGenerator_Callback.registerCommandInterceptor(async (
|
|
@@ -53,6 +53,7 @@ globalThis.describe("RuntimeExtension reaches the runtime callback hooks", () =>
|
|
|
53
53
|
});
|
|
54
54
|
globalThis.test("an interceptor registered at cold start denies a later command", async () => {
|
|
55
55
|
let seenAtColdStart = [];
|
|
56
|
+
let companionModuleUrls = [];
|
|
56
57
|
let onColdStart = (param, component, param$1, param$2) => {
|
|
57
58
|
seenAtColdStart.push(component);
|
|
58
59
|
CommandGenerator_Callback$ReventlessCore.registerCommandInterceptor(async (param, componentName, param$1, tag, param$2) => ({
|
|
@@ -62,6 +63,7 @@ globalThis.describe("RuntimeExtension reaches the runtime callback hooks", () =>
|
|
|
62
63
|
};
|
|
63
64
|
let Gatekeeper = {
|
|
64
65
|
moduleUrl: "file:///pkg/gatekeeper.res.mjs",
|
|
66
|
+
companionModuleUrls: companionModuleUrls,
|
|
65
67
|
onColdStart: onColdStart
|
|
66
68
|
};
|
|
67
69
|
RuntimeExtension$ReventlessCore.use(Gatekeeper);
|
|
@@ -7,11 +7,12 @@ type call = {
|
|
|
7
7
|
platform: option<string>,
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
let recorderNamed = (label: string, into: array<(string, call)>): module(
|
|
10
|
+
let recorderNamed = (~companions: array<string>=[], label: string, into: array<(string, call)>): module(
|
|
11
11
|
RuntimeExtension.Extension
|
|
12
12
|
) => {
|
|
13
13
|
module R = {
|
|
14
14
|
let moduleUrl = `file:///pkg/${label}.res.mjs`
|
|
15
|
+
let companionModuleUrls = companions
|
|
15
16
|
let onColdStart = (~runtimeKind, ~component, ~plugin, ~platform) =>
|
|
16
17
|
into->Array.push((label, {runtimeKind, component, plugin, platform}))
|
|
17
18
|
}
|
|
@@ -32,6 +33,7 @@ describe("RuntimeExtension", () => {
|
|
|
32
33
|
testSync("empty registry is the default and notifyColdStart is silent", () => {
|
|
33
34
|
expect(RuntimeExtension.isEmpty())->toBe(true)
|
|
34
35
|
expect(RuntimeExtension.moduleUrls())->toEqual([])
|
|
36
|
+
expect(RuntimeExtension.companionModuleUrls())->toEqual([])
|
|
35
37
|
fireAggregate()
|
|
36
38
|
expect(true)->toBe(true)
|
|
37
39
|
})
|
|
@@ -77,10 +79,38 @@ describe("RuntimeExtension", () => {
|
|
|
77
79
|
])
|
|
78
80
|
})
|
|
79
81
|
|
|
82
|
+
testSync("companionModuleUrls flattens every registration's companions, in order", () => {
|
|
83
|
+
let calls: array<(string, call)> = []
|
|
84
|
+
RuntimeExtension.use(
|
|
85
|
+
recorderNamed(
|
|
86
|
+
~companions=["file:///pkg/companion-a.res.mjs", "file:///pkg/companion-b.res.mjs"],
|
|
87
|
+
"tracing",
|
|
88
|
+
calls,
|
|
89
|
+
),
|
|
90
|
+
)
|
|
91
|
+
RuntimeExtension.use(recorderNamed("accounting", calls))
|
|
92
|
+
RuntimeExtension.use(
|
|
93
|
+
recorderNamed(~companions=["file:///pkg/companion-c.res.mjs"], "quota", calls),
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
expect(RuntimeExtension.companionModuleUrls())->toEqual([
|
|
97
|
+
"file:///pkg/companion-a.res.mjs",
|
|
98
|
+
"file:///pkg/companion-b.res.mjs",
|
|
99
|
+
"file:///pkg/companion-c.res.mjs",
|
|
100
|
+
])
|
|
101
|
+
// Companions are bundle-only: the entry shell's import list is untouched.
|
|
102
|
+
expect(RuntimeExtension.moduleUrls())->toEqual([
|
|
103
|
+
"file:///pkg/tracing.res.mjs",
|
|
104
|
+
"file:///pkg/accounting.res.mjs",
|
|
105
|
+
"file:///pkg/quota.res.mjs",
|
|
106
|
+
])
|
|
107
|
+
})
|
|
108
|
+
|
|
80
109
|
testSync("a throwing extension is skipped; the runtime and its siblings survive", () => {
|
|
81
110
|
let calls: array<(string, call)> = []
|
|
82
111
|
module Broken: RuntimeExtension.Extension = {
|
|
83
112
|
let moduleUrl = "file:///pkg/broken.res.mjs"
|
|
113
|
+
let companionModuleUrls = []
|
|
84
114
|
let onColdStart = (~runtimeKind as _, ~component as _, ~plugin as _, ~platform as _) =>
|
|
85
115
|
JsError.throwWithMessage("extension blew up")
|
|
86
116
|
}
|
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
|
|
4
4
|
import * as RuntimeExtension$ReventlessCore from "../../src/adapter/RuntimeExtension/RuntimeExtension.res.mjs";
|
|
5
5
|
|
|
6
|
-
function recorderNamed(label, into) {
|
|
6
|
+
function recorderNamed(companionsOpt, label, into) {
|
|
7
|
+
let companions = companionsOpt !== undefined ? companionsOpt : [];
|
|
7
8
|
let moduleUrl = `file:///pkg/` + label + `.res.mjs`;
|
|
8
9
|
let onColdStart = (runtimeKind, component, plugin, platform) => {
|
|
9
10
|
into.push([
|
|
@@ -18,6 +19,7 @@ function recorderNamed(label, into) {
|
|
|
18
19
|
};
|
|
19
20
|
return {
|
|
20
21
|
moduleUrl: moduleUrl,
|
|
22
|
+
companionModuleUrls: companions,
|
|
21
23
|
onColdStart: onColdStart
|
|
22
24
|
};
|
|
23
25
|
}
|
|
@@ -31,12 +33,13 @@ globalThis.describe("RuntimeExtension", () => {
|
|
|
31
33
|
globalThis.test("empty registry is the default and notifyColdStart is silent", () => {
|
|
32
34
|
globalThis.expect(RuntimeExtension$ReventlessCore.isEmpty()).toBe(true);
|
|
33
35
|
globalThis.expect(RuntimeExtension$ReventlessCore.moduleUrls()).toEqual([]);
|
|
36
|
+
globalThis.expect(RuntimeExtension$ReventlessCore.companionModuleUrls()).toEqual([]);
|
|
34
37
|
fireAggregate();
|
|
35
38
|
globalThis.expect(true).toBe(true);
|
|
36
39
|
});
|
|
37
40
|
globalThis.test("a registered extension receives the runtime's full identity", () => {
|
|
38
41
|
let calls = [];
|
|
39
|
-
RuntimeExtension$ReventlessCore.use(recorderNamed("tracing", calls));
|
|
42
|
+
RuntimeExtension$ReventlessCore.use(recorderNamed(undefined, "tracing", calls));
|
|
40
43
|
fireAggregate();
|
|
41
44
|
globalThis.expect(calls).toEqual([[
|
|
42
45
|
"tracing",
|
|
@@ -50,8 +53,8 @@ globalThis.describe("RuntimeExtension", () => {
|
|
|
50
53
|
});
|
|
51
54
|
globalThis.test("several extensions compose, in registration order", () => {
|
|
52
55
|
let calls = [];
|
|
53
|
-
RuntimeExtension$ReventlessCore.use(recorderNamed("tracing", calls));
|
|
54
|
-
RuntimeExtension$ReventlessCore.use(recorderNamed("accounting", calls));
|
|
56
|
+
RuntimeExtension$ReventlessCore.use(recorderNamed(undefined, "tracing", calls));
|
|
57
|
+
RuntimeExtension$ReventlessCore.use(recorderNamed(undefined, "accounting", calls));
|
|
55
58
|
fireAggregate();
|
|
56
59
|
globalThis.expect(calls.map(param => param[0])).toEqual([
|
|
57
60
|
"tracing",
|
|
@@ -60,23 +63,44 @@ globalThis.describe("RuntimeExtension", () => {
|
|
|
60
63
|
});
|
|
61
64
|
globalThis.test("moduleUrls reports every registration, in order", () => {
|
|
62
65
|
let calls = [];
|
|
63
|
-
RuntimeExtension$ReventlessCore.use(recorderNamed("tracing", calls));
|
|
64
|
-
RuntimeExtension$ReventlessCore.use(recorderNamed("accounting", calls));
|
|
66
|
+
RuntimeExtension$ReventlessCore.use(recorderNamed(undefined, "tracing", calls));
|
|
67
|
+
RuntimeExtension$ReventlessCore.use(recorderNamed(undefined, "accounting", calls));
|
|
65
68
|
globalThis.expect(RuntimeExtension$ReventlessCore.isEmpty()).toBe(false);
|
|
66
69
|
globalThis.expect(RuntimeExtension$ReventlessCore.moduleUrls()).toEqual([
|
|
67
70
|
"file:///pkg/tracing.res.mjs",
|
|
68
71
|
"file:///pkg/accounting.res.mjs"
|
|
69
72
|
]);
|
|
70
73
|
});
|
|
74
|
+
globalThis.test("companionModuleUrls flattens every registration's companions, in order", () => {
|
|
75
|
+
let calls = [];
|
|
76
|
+
RuntimeExtension$ReventlessCore.use(recorderNamed([
|
|
77
|
+
"file:///pkg/companion-a.res.mjs",
|
|
78
|
+
"file:///pkg/companion-b.res.mjs"
|
|
79
|
+
], "tracing", calls));
|
|
80
|
+
RuntimeExtension$ReventlessCore.use(recorderNamed(undefined, "accounting", calls));
|
|
81
|
+
RuntimeExtension$ReventlessCore.use(recorderNamed(["file:///pkg/companion-c.res.mjs"], "quota", calls));
|
|
82
|
+
globalThis.expect(RuntimeExtension$ReventlessCore.companionModuleUrls()).toEqual([
|
|
83
|
+
"file:///pkg/companion-a.res.mjs",
|
|
84
|
+
"file:///pkg/companion-b.res.mjs",
|
|
85
|
+
"file:///pkg/companion-c.res.mjs"
|
|
86
|
+
]);
|
|
87
|
+
globalThis.expect(RuntimeExtension$ReventlessCore.moduleUrls()).toEqual([
|
|
88
|
+
"file:///pkg/tracing.res.mjs",
|
|
89
|
+
"file:///pkg/accounting.res.mjs",
|
|
90
|
+
"file:///pkg/quota.res.mjs"
|
|
91
|
+
]);
|
|
92
|
+
});
|
|
71
93
|
globalThis.test("a throwing extension is skipped; the runtime and its siblings survive", () => {
|
|
72
94
|
let calls = [];
|
|
95
|
+
let companionModuleUrls = [];
|
|
73
96
|
let onColdStart = (param, param$1, param$2, param$3) => Stdlib_JsError.throwWithMessage("extension blew up");
|
|
74
97
|
let Broken = {
|
|
75
98
|
moduleUrl: "file:///pkg/broken.res.mjs",
|
|
99
|
+
companionModuleUrls: companionModuleUrls,
|
|
76
100
|
onColdStart: onColdStart
|
|
77
101
|
};
|
|
78
102
|
RuntimeExtension$ReventlessCore.use(Broken);
|
|
79
|
-
RuntimeExtension$ReventlessCore.use(recorderNamed("accounting", calls));
|
|
103
|
+
RuntimeExtension$ReventlessCore.use(recorderNamed(undefined, "accounting", calls));
|
|
80
104
|
fireAggregate();
|
|
81
105
|
globalThis.expect(calls.map(param => param[0])).toEqual(["accounting"]);
|
|
82
106
|
});
|
|
@@ -96,7 +120,7 @@ globalThis.describe("RuntimeExtension", () => {
|
|
|
96
120
|
});
|
|
97
121
|
globalThis.test("reset clears the registry", () => {
|
|
98
122
|
let calls = [];
|
|
99
|
-
RuntimeExtension$ReventlessCore.use(recorderNamed("tracing", calls));
|
|
123
|
+
RuntimeExtension$ReventlessCore.use(recorderNamed(undefined, "tracing", calls));
|
|
100
124
|
RuntimeExtension$ReventlessCore.reset();
|
|
101
125
|
fireAggregate();
|
|
102
126
|
globalThis.expect(RuntimeExtension$ReventlessCore.isEmpty()).toBe(true);
|
|
@@ -34,6 +34,7 @@ let emptySpec: Reventless.StateAnnotations.stateAnnotationSpec = {
|
|
|
34
34
|
status: None,
|
|
35
35
|
groupBy: None,
|
|
36
36
|
visibility: None,
|
|
37
|
+
live: None,
|
|
37
38
|
}
|
|
38
39
|
|
|
39
40
|
describe("SuryToJsonSchema:", () => {
|
|
@@ -427,6 +428,41 @@ describe("SuryToJsonSchema:", () => {
|
|
|
427
428
|
let json = SuryToJsonSchema.deriveObjectSchema(schema')
|
|
428
429
|
expect(getProperty(json, "x-reventless-visibility"))->toBe(None)
|
|
429
430
|
})
|
|
431
|
+
|
|
432
|
+
testSync("emits x-reventless-live at top level when live is declared", () => {
|
|
433
|
+
let schema = S.schema(s => {"id": s.matches(S.string)})->S.castToUnknown
|
|
434
|
+
let offJson = SuryToJsonSchema.deriveObjectSchema(
|
|
435
|
+
schema->withSpec({...emptySpec, live: Some(false)}),
|
|
436
|
+
)
|
|
437
|
+
let onJson = SuryToJsonSchema.deriveObjectSchema(
|
|
438
|
+
schema->withSpec({...emptySpec, live: Some(true)}),
|
|
439
|
+
)
|
|
440
|
+
expect((
|
|
441
|
+
getProperty(offJson, "x-reventless-live")->Option.flatMap(JSON.Decode.bool),
|
|
442
|
+
getProperty(onJson, "x-reventless-live")->Option.flatMap(JSON.Decode.bool),
|
|
443
|
+
))->toEqual((Some(false), Some(true)))
|
|
444
|
+
})
|
|
445
|
+
|
|
446
|
+
testSync("omits x-reventless-live when live is None (no annotation)", () => {
|
|
447
|
+
let schema = S.schema(s => {"id": s.matches(S.string)})->S.castToUnknown
|
|
448
|
+
let schema' = schema->withSpec({...emptySpec, live: None})
|
|
449
|
+
let json = SuryToJsonSchema.deriveObjectSchema(schema')
|
|
450
|
+
expect(getProperty(json, "x-reventless-live"))->toBe(None)
|
|
451
|
+
})
|
|
452
|
+
|
|
453
|
+
testSync("emits x-reventless-live and x-reventless-visibility together", () => {
|
|
454
|
+
let schema = S.schema(s => {"id": s.matches(S.string)})->S.castToUnknown
|
|
455
|
+
let schema' = schema->withSpec({
|
|
456
|
+
...emptySpec,
|
|
457
|
+
visibility: Some("Internal"),
|
|
458
|
+
live: Some(false),
|
|
459
|
+
})
|
|
460
|
+
let json = SuryToJsonSchema.deriveObjectSchema(schema')
|
|
461
|
+
expect((
|
|
462
|
+
getProperty(json, "x-reventless-visibility")->Option.flatMap(JSON.Decode.string),
|
|
463
|
+
getProperty(json, "x-reventless-live")->Option.flatMap(JSON.Decode.bool),
|
|
464
|
+
))->toEqual((Some("Internal"), Some(false)))
|
|
465
|
+
})
|
|
430
466
|
})
|
|
431
467
|
|
|
432
468
|
// Parity sanity-check: deriveObjectSchema and the legacy S.toJSONSchema must
|
|
@@ -81,7 +81,8 @@ let emptySpec = {
|
|
|
81
81
|
metric: emptySpec_metric,
|
|
82
82
|
status: undefined,
|
|
83
83
|
groupBy: undefined,
|
|
84
|
-
visibility: undefined
|
|
84
|
+
visibility: undefined,
|
|
85
|
+
live: undefined
|
|
85
86
|
};
|
|
86
87
|
|
|
87
88
|
globalThis.describe("SuryToJsonSchema:", () => {
|
|
@@ -129,7 +130,8 @@ globalThis.describe("SuryToJsonSchema:", () => {
|
|
|
129
130
|
metric: emptySpec_metric,
|
|
130
131
|
status: undefined,
|
|
131
132
|
groupBy: undefined,
|
|
132
|
-
visibility: undefined
|
|
133
|
+
visibility: undefined,
|
|
134
|
+
live: undefined
|
|
133
135
|
});
|
|
134
136
|
let json = SuryToJsonSchema$ReventlessCore.deriveObjectSchema(schema$p);
|
|
135
137
|
let entityIdSchema = getPropertyOf(json, "entityId");
|
|
@@ -161,7 +163,8 @@ globalThis.describe("SuryToJsonSchema:", () => {
|
|
|
161
163
|
metric: emptySpec_metric,
|
|
162
164
|
status: undefined,
|
|
163
165
|
groupBy: undefined,
|
|
164
|
-
visibility: undefined
|
|
166
|
+
visibility: undefined,
|
|
167
|
+
live: undefined
|
|
165
168
|
});
|
|
166
169
|
let json = SuryToJsonSchema$ReventlessCore.deriveObjectSchema(schema$p);
|
|
167
170
|
let envSchema = getPropertyOf(json, "environment");
|
|
@@ -196,7 +199,8 @@ globalThis.describe("SuryToJsonSchema:", () => {
|
|
|
196
199
|
metric: emptySpec_metric,
|
|
197
200
|
status: undefined,
|
|
198
201
|
groupBy: undefined,
|
|
199
|
-
visibility: undefined
|
|
202
|
+
visibility: undefined,
|
|
203
|
+
live: undefined
|
|
200
204
|
});
|
|
201
205
|
let json = SuryToJsonSchema$ReventlessCore.deriveObjectSchema(schema$p);
|
|
202
206
|
let versionSchema = getPropertyOf(json, "version");
|
|
@@ -227,7 +231,8 @@ globalThis.describe("SuryToJsonSchema:", () => {
|
|
|
227
231
|
metric: emptySpec_metric,
|
|
228
232
|
status: undefined,
|
|
229
233
|
groupBy: undefined,
|
|
230
|
-
visibility: undefined
|
|
234
|
+
visibility: undefined,
|
|
235
|
+
live: undefined
|
|
231
236
|
});
|
|
232
237
|
let json = SuryToJsonSchema$ReventlessCore.deriveObjectSchema(schema$p);
|
|
233
238
|
let ownerIdSchema = getPropertyOf(json, "ownerId");
|
|
@@ -258,7 +263,8 @@ globalThis.describe("SuryToJsonSchema:", () => {
|
|
|
258
263
|
metric: emptySpec_metric,
|
|
259
264
|
status: undefined,
|
|
260
265
|
groupBy: undefined,
|
|
261
|
-
visibility: undefined
|
|
266
|
+
visibility: undefined,
|
|
267
|
+
live: undefined
|
|
262
268
|
});
|
|
263
269
|
let json = SuryToJsonSchema$ReventlessCore.deriveObjectSchema(schema$p);
|
|
264
270
|
let categorySchema = getPropertyOf(json, "category");
|
|
@@ -286,7 +292,8 @@ globalThis.describe("SuryToJsonSchema:", () => {
|
|
|
286
292
|
metric: emptySpec_metric,
|
|
287
293
|
status: undefined,
|
|
288
294
|
groupBy: undefined,
|
|
289
|
-
visibility: undefined
|
|
295
|
+
visibility: undefined,
|
|
296
|
+
live: undefined
|
|
290
297
|
});
|
|
291
298
|
let json = SuryToJsonSchema$ReventlessCore.deriveObjectSchema(schema$p);
|
|
292
299
|
let nameSchema = getPropertyOf(json, "name");
|
|
@@ -314,7 +321,8 @@ globalThis.describe("SuryToJsonSchema:", () => {
|
|
|
314
321
|
metric: emptySpec_metric,
|
|
315
322
|
status: undefined,
|
|
316
323
|
groupBy: undefined,
|
|
317
|
-
visibility: undefined
|
|
324
|
+
visibility: undefined,
|
|
325
|
+
live: undefined
|
|
318
326
|
});
|
|
319
327
|
let json = SuryToJsonSchema$ReventlessCore.deriveObjectSchema(schema$p);
|
|
320
328
|
let deploymentIdSchema = getPropertyOf(json, "deploymentId");
|
|
@@ -349,7 +357,8 @@ globalThis.describe("SuryToJsonSchema:", () => {
|
|
|
349
357
|
metric: emptySpec_metric,
|
|
350
358
|
status: undefined,
|
|
351
359
|
groupBy: undefined,
|
|
352
|
-
visibility: undefined
|
|
360
|
+
visibility: undefined,
|
|
361
|
+
live: undefined
|
|
353
362
|
});
|
|
354
363
|
let json = SuryToJsonSchema$ReventlessCore.deriveObjectSchema(schema$p);
|
|
355
364
|
let pluginNameSchema = getPropertyOf(json, "pluginName");
|
|
@@ -387,7 +396,8 @@ globalThis.describe("SuryToJsonSchema:", () => {
|
|
|
387
396
|
metric: emptySpec_metric,
|
|
388
397
|
status: undefined,
|
|
389
398
|
groupBy: undefined,
|
|
390
|
-
visibility: undefined
|
|
399
|
+
visibility: undefined,
|
|
400
|
+
live: undefined
|
|
391
401
|
});
|
|
392
402
|
let json = SuryToJsonSchema$ReventlessCore.deriveObjectSchema(schema$p);
|
|
393
403
|
let componentsSchema = getPropertyOf(json, "components");
|
|
@@ -428,7 +438,8 @@ globalThis.describe("SuryToJsonSchema:", () => {
|
|
|
428
438
|
metric: emptySpec_metric,
|
|
429
439
|
status: undefined,
|
|
430
440
|
groupBy: undefined,
|
|
431
|
-
visibility: undefined
|
|
441
|
+
visibility: undefined,
|
|
442
|
+
live: undefined
|
|
432
443
|
});
|
|
433
444
|
let json = SuryToJsonSchema$ReventlessCore.deriveObjectSchema(schema$p);
|
|
434
445
|
let componentsSchema = getPropertyOf(json, "components");
|
|
@@ -459,7 +470,8 @@ globalThis.describe("SuryToJsonSchema:", () => {
|
|
|
459
470
|
metric: emptySpec_metric,
|
|
460
471
|
status: undefined,
|
|
461
472
|
groupBy: undefined,
|
|
462
|
-
visibility: undefined
|
|
473
|
+
visibility: undefined,
|
|
474
|
+
live: undefined
|
|
463
475
|
});
|
|
464
476
|
let json = SuryToJsonSchema$ReventlessCore.deriveObjectSchema(schema$p);
|
|
465
477
|
let componentsSchema = getPropertyOf(json, "components");
|
|
@@ -487,7 +499,8 @@ globalThis.describe("SuryToJsonSchema:", () => {
|
|
|
487
499
|
metric: emptySpec_metric,
|
|
488
500
|
status: undefined,
|
|
489
501
|
groupBy: undefined,
|
|
490
|
-
visibility: undefined
|
|
502
|
+
visibility: undefined,
|
|
503
|
+
live: undefined
|
|
491
504
|
});
|
|
492
505
|
let json = SuryToJsonSchema$ReventlessCore.deriveObjectSchema(schema$p);
|
|
493
506
|
let statusSchema = getPropertyOf(json, "status");
|
|
@@ -522,7 +535,8 @@ globalThis.describe("SuryToJsonSchema:", () => {
|
|
|
522
535
|
metric: emptySpec_metric,
|
|
523
536
|
status: undefined,
|
|
524
537
|
groupBy: undefined,
|
|
525
|
-
visibility: undefined
|
|
538
|
+
visibility: undefined,
|
|
539
|
+
live: undefined
|
|
526
540
|
});
|
|
527
541
|
let json = SuryToJsonSchema$ReventlessCore.deriveObjectSchema(schema$p);
|
|
528
542
|
let nameSchema = getPropertyOf(json, "name");
|
|
@@ -560,7 +574,8 @@ globalThis.describe("SuryToJsonSchema:", () => {
|
|
|
560
574
|
metric: emptySpec_metric,
|
|
561
575
|
status: undefined,
|
|
562
576
|
groupBy: undefined,
|
|
563
|
-
visibility: undefined
|
|
577
|
+
visibility: undefined,
|
|
578
|
+
live: undefined
|
|
564
579
|
});
|
|
565
580
|
let json = SuryToJsonSchema$ReventlessCore.deriveObjectSchema(schema$p);
|
|
566
581
|
let totalSchema = getPropertyOf(json, "total");
|
|
@@ -601,7 +616,8 @@ globalThis.describe("SuryToJsonSchema:", () => {
|
|
|
601
616
|
]],
|
|
602
617
|
status: undefined,
|
|
603
618
|
groupBy: undefined,
|
|
604
|
-
visibility: undefined
|
|
619
|
+
visibility: undefined,
|
|
620
|
+
live: undefined
|
|
605
621
|
});
|
|
606
622
|
let json = SuryToJsonSchema$ReventlessCore.deriveObjectSchema(schema$p);
|
|
607
623
|
let metricObj = Stdlib_Option.flatMap(getPropertyOf(json, "total"), s => getProperty(s, "x-reventless-metric"));
|
|
@@ -640,7 +656,8 @@ globalThis.describe("SuryToJsonSchema:", () => {
|
|
|
640
656
|
]],
|
|
641
657
|
status: undefined,
|
|
642
658
|
groupBy: undefined,
|
|
643
|
-
visibility: undefined
|
|
659
|
+
visibility: undefined,
|
|
660
|
+
live: undefined
|
|
644
661
|
});
|
|
645
662
|
let json = SuryToJsonSchema$ReventlessCore.deriveObjectSchema(schema$p);
|
|
646
663
|
let metricObj = Stdlib_Option.flatMap(getPropertyOf(json, "total"), s => getProperty(s, "x-reventless-metric"));
|
|
@@ -674,7 +691,8 @@ globalThis.describe("SuryToJsonSchema:", () => {
|
|
|
674
691
|
metric: emptySpec_metric,
|
|
675
692
|
status: undefined,
|
|
676
693
|
groupBy: "kind",
|
|
677
|
-
visibility: undefined
|
|
694
|
+
visibility: undefined,
|
|
695
|
+
live: undefined
|
|
678
696
|
});
|
|
679
697
|
let json = SuryToJsonSchema$ReventlessCore.deriveObjectSchema(schema$p);
|
|
680
698
|
let kindSchema = getPropertyOf(json, "kind");
|
|
@@ -709,7 +727,8 @@ globalThis.describe("SuryToJsonSchema:", () => {
|
|
|
709
727
|
metric: emptySpec_metric,
|
|
710
728
|
status: undefined,
|
|
711
729
|
groupBy: undefined,
|
|
712
|
-
visibility: undefined
|
|
730
|
+
visibility: undefined,
|
|
731
|
+
live: undefined
|
|
713
732
|
});
|
|
714
733
|
let json = SuryToJsonSchema$ReventlessCore.deriveObjectSchema(schema$p);
|
|
715
734
|
let primarySchema = getPropertyOf(json, "primaryResource");
|
|
@@ -743,7 +762,8 @@ globalThis.describe("SuryToJsonSchema:", () => {
|
|
|
743
762
|
metric: emptySpec_metric,
|
|
744
763
|
status: undefined,
|
|
745
764
|
groupBy: undefined,
|
|
746
|
-
visibility: "Internal"
|
|
765
|
+
visibility: "Internal",
|
|
766
|
+
live: undefined
|
|
747
767
|
});
|
|
748
768
|
let json = SuryToJsonSchema$ReventlessCore.deriveObjectSchema(schema$p);
|
|
749
769
|
globalThis.expect(Stdlib_Option.flatMap(getProperty(json, "x-reventless-visibility"), Stdlib_JSON.Decode.string)).toBe("Internal");
|
|
@@ -769,11 +789,124 @@ globalThis.describe("SuryToJsonSchema:", () => {
|
|
|
769
789
|
metric: emptySpec_metric,
|
|
770
790
|
status: undefined,
|
|
771
791
|
groupBy: undefined,
|
|
772
|
-
visibility: undefined
|
|
792
|
+
visibility: undefined,
|
|
793
|
+
live: undefined
|
|
773
794
|
});
|
|
774
795
|
let json = SuryToJsonSchema$ReventlessCore.deriveObjectSchema(schema$p);
|
|
775
796
|
globalThis.expect(getProperty(json, "x-reventless-visibility")).toBe(undefined);
|
|
776
797
|
});
|
|
798
|
+
globalThis.test("emits x-reventless-live at top level when live is declared", () => {
|
|
799
|
+
let schema = S.schema(s => ({
|
|
800
|
+
id: s.m(S.string)
|
|
801
|
+
}));
|
|
802
|
+
let offJson = SuryToJsonSchema$ReventlessCore.deriveObjectSchema(withSpec(schema, {
|
|
803
|
+
ids: emptySpec_ids,
|
|
804
|
+
compositeIds: emptySpec_compositeIds,
|
|
805
|
+
subIds: emptySpec_subIds,
|
|
806
|
+
compositeSubIds: emptySpec_compositeSubIds,
|
|
807
|
+
indexes: emptySpec_indexes,
|
|
808
|
+
hidden: emptySpec_hidden,
|
|
809
|
+
summary: emptySpec_summary,
|
|
810
|
+
drillTargets: emptySpec_drillTargets,
|
|
811
|
+
drillTargetKeys: emptySpec_drillTargetKeys,
|
|
812
|
+
collapsed: emptySpec_collapsed,
|
|
813
|
+
scan: emptySpec_scan,
|
|
814
|
+
scanSort: emptySpec_scanSort,
|
|
815
|
+
semantic: emptySpec_semantic,
|
|
816
|
+
metric: emptySpec_metric,
|
|
817
|
+
status: undefined,
|
|
818
|
+
groupBy: undefined,
|
|
819
|
+
visibility: undefined,
|
|
820
|
+
live: false
|
|
821
|
+
}));
|
|
822
|
+
let onJson = SuryToJsonSchema$ReventlessCore.deriveObjectSchema(withSpec(schema, {
|
|
823
|
+
ids: emptySpec_ids,
|
|
824
|
+
compositeIds: emptySpec_compositeIds,
|
|
825
|
+
subIds: emptySpec_subIds,
|
|
826
|
+
compositeSubIds: emptySpec_compositeSubIds,
|
|
827
|
+
indexes: emptySpec_indexes,
|
|
828
|
+
hidden: emptySpec_hidden,
|
|
829
|
+
summary: emptySpec_summary,
|
|
830
|
+
drillTargets: emptySpec_drillTargets,
|
|
831
|
+
drillTargetKeys: emptySpec_drillTargetKeys,
|
|
832
|
+
collapsed: emptySpec_collapsed,
|
|
833
|
+
scan: emptySpec_scan,
|
|
834
|
+
scanSort: emptySpec_scanSort,
|
|
835
|
+
semantic: emptySpec_semantic,
|
|
836
|
+
metric: emptySpec_metric,
|
|
837
|
+
status: undefined,
|
|
838
|
+
groupBy: undefined,
|
|
839
|
+
visibility: undefined,
|
|
840
|
+
live: true
|
|
841
|
+
}));
|
|
842
|
+
globalThis.expect([
|
|
843
|
+
Stdlib_Option.flatMap(getProperty(offJson, "x-reventless-live"), Stdlib_JSON.Decode.bool),
|
|
844
|
+
Stdlib_Option.flatMap(getProperty(onJson, "x-reventless-live"), Stdlib_JSON.Decode.bool)
|
|
845
|
+
]).toEqual([
|
|
846
|
+
false,
|
|
847
|
+
true
|
|
848
|
+
]);
|
|
849
|
+
});
|
|
850
|
+
globalThis.test("omits x-reventless-live when live is None (no annotation)", () => {
|
|
851
|
+
let schema = S.schema(s => ({
|
|
852
|
+
id: s.m(S.string)
|
|
853
|
+
}));
|
|
854
|
+
let schema$p = withSpec(schema, {
|
|
855
|
+
ids: emptySpec_ids,
|
|
856
|
+
compositeIds: emptySpec_compositeIds,
|
|
857
|
+
subIds: emptySpec_subIds,
|
|
858
|
+
compositeSubIds: emptySpec_compositeSubIds,
|
|
859
|
+
indexes: emptySpec_indexes,
|
|
860
|
+
hidden: emptySpec_hidden,
|
|
861
|
+
summary: emptySpec_summary,
|
|
862
|
+
drillTargets: emptySpec_drillTargets,
|
|
863
|
+
drillTargetKeys: emptySpec_drillTargetKeys,
|
|
864
|
+
collapsed: emptySpec_collapsed,
|
|
865
|
+
scan: emptySpec_scan,
|
|
866
|
+
scanSort: emptySpec_scanSort,
|
|
867
|
+
semantic: emptySpec_semantic,
|
|
868
|
+
metric: emptySpec_metric,
|
|
869
|
+
status: undefined,
|
|
870
|
+
groupBy: undefined,
|
|
871
|
+
visibility: undefined,
|
|
872
|
+
live: undefined
|
|
873
|
+
});
|
|
874
|
+
let json = SuryToJsonSchema$ReventlessCore.deriveObjectSchema(schema$p);
|
|
875
|
+
globalThis.expect(getProperty(json, "x-reventless-live")).toBe(undefined);
|
|
876
|
+
});
|
|
877
|
+
globalThis.test("emits x-reventless-live and x-reventless-visibility together", () => {
|
|
878
|
+
let schema = S.schema(s => ({
|
|
879
|
+
id: s.m(S.string)
|
|
880
|
+
}));
|
|
881
|
+
let schema$p = withSpec(schema, {
|
|
882
|
+
ids: emptySpec_ids,
|
|
883
|
+
compositeIds: emptySpec_compositeIds,
|
|
884
|
+
subIds: emptySpec_subIds,
|
|
885
|
+
compositeSubIds: emptySpec_compositeSubIds,
|
|
886
|
+
indexes: emptySpec_indexes,
|
|
887
|
+
hidden: emptySpec_hidden,
|
|
888
|
+
summary: emptySpec_summary,
|
|
889
|
+
drillTargets: emptySpec_drillTargets,
|
|
890
|
+
drillTargetKeys: emptySpec_drillTargetKeys,
|
|
891
|
+
collapsed: emptySpec_collapsed,
|
|
892
|
+
scan: emptySpec_scan,
|
|
893
|
+
scanSort: emptySpec_scanSort,
|
|
894
|
+
semantic: emptySpec_semantic,
|
|
895
|
+
metric: emptySpec_metric,
|
|
896
|
+
status: undefined,
|
|
897
|
+
groupBy: undefined,
|
|
898
|
+
visibility: "Internal",
|
|
899
|
+
live: false
|
|
900
|
+
});
|
|
901
|
+
let json = SuryToJsonSchema$ReventlessCore.deriveObjectSchema(schema$p);
|
|
902
|
+
globalThis.expect([
|
|
903
|
+
Stdlib_Option.flatMap(getProperty(json, "x-reventless-visibility"), Stdlib_JSON.Decode.string),
|
|
904
|
+
Stdlib_Option.flatMap(getProperty(json, "x-reventless-live"), Stdlib_JSON.Decode.bool)
|
|
905
|
+
]).toEqual([
|
|
906
|
+
"Internal",
|
|
907
|
+
false
|
|
908
|
+
]);
|
|
909
|
+
});
|
|
777
910
|
});
|
|
778
911
|
globalThis.describe("parity with S.toJSONSchema for unannotated objects:", () => {
|
|
779
912
|
let getKeys = schema => {
|
|
@@ -835,7 +968,8 @@ globalThis.describe("SuryToJsonSchema:", () => {
|
|
|
835
968
|
metric: emptySpec_metric,
|
|
836
969
|
status: undefined,
|
|
837
970
|
groupBy: undefined,
|
|
838
|
-
visibility: undefined
|
|
971
|
+
visibility: undefined,
|
|
972
|
+
live: undefined
|
|
839
973
|
});
|
|
840
974
|
let native = S.toJSONSchema(schema$p);
|
|
841
975
|
let entityIdSchema = getPropertyOf(native, "entityId");
|
|
@@ -945,7 +1079,8 @@ globalThis.describe("SuryToJsonSchema:", () => {
|
|
|
945
1079
|
metric: emptySpec_metric,
|
|
946
1080
|
status: undefined,
|
|
947
1081
|
groupBy: undefined,
|
|
948
|
-
visibility: undefined
|
|
1082
|
+
visibility: undefined,
|
|
1083
|
+
live: undefined
|
|
949
1084
|
});
|
|
950
1085
|
let json = SuryToJsonSchema$ReventlessCore.deriveObjectSchema(schema);
|
|
951
1086
|
globalThis.expect(semanticOf(json, "imageUrl")).toEqual("storageRef");
|
|
@@ -228,6 +228,7 @@ describe("CommandTopic command-outcome hook:", () => {
|
|
|
228
228
|
// seam already reaches, so an extension picks it up alongside the other four.
|
|
229
229
|
module Accountant: RuntimeExtension.Extension = {
|
|
230
230
|
let moduleUrl = "file:///pkg/accountant.res.mjs"
|
|
231
|
+
let companionModuleUrls = []
|
|
231
232
|
let onColdStart = (~runtimeKind as _, ~component as _, ~plugin as _, ~platform as _) =>
|
|
232
233
|
record()
|
|
233
234
|
}
|
|
@@ -321,9 +321,11 @@ globalThis.describe("CommandTopic command-outcome hook:", () => {
|
|
|
321
321
|
globalThis.expect(observed.contents.length).toBe(0);
|
|
322
322
|
});
|
|
323
323
|
globalThis.test("an out-of-tree extension can register it from onColdStart", async () => {
|
|
324
|
+
let companionModuleUrls = [];
|
|
324
325
|
let onColdStart = (param, param$1, param$2, param$3) => record();
|
|
325
326
|
let Accountant = {
|
|
326
327
|
moduleUrl: "file:///pkg/accountant.res.mjs",
|
|
328
|
+
companionModuleUrls: companionModuleUrls,
|
|
327
329
|
onColdStart: onColdStart
|
|
328
330
|
};
|
|
329
331
|
RuntimeExtension$ReventlessCore.use(Accountant);
|
|
@@ -666,6 +666,17 @@ describe("Plugin_Structure.make — Phase 2 graph fields", () => {
|
|
|
666
666
|
orderIdField->Option.flatMap(s => getProperty(s, "x-reventless-id")),
|
|
667
667
|
)->toBe(None)
|
|
668
668
|
})
|
|
669
|
+
|
|
670
|
+
testSync("@live(false) flows through the PPX to top-level x-reventless-live", () => {
|
|
671
|
+
expect(
|
|
672
|
+
getProperty(annotatedSchema, "x-reventless-live")->Option.flatMap(JSON.Decode.bool),
|
|
673
|
+
)->toBe(Some(false))
|
|
674
|
+
})
|
|
675
|
+
|
|
676
|
+
testSync("unannotated state-view slice (Orders) has no top-level x-reventless-live", () => {
|
|
677
|
+
let ordersSchema = structure.stateViewSlices->Array.getUnsafe(0)->parseSchema
|
|
678
|
+
expect(getProperty(ordersSchema, "x-reventless-live"))->toBe(None)
|
|
679
|
+
})
|
|
669
680
|
})
|
|
670
681
|
|
|
671
682
|
// The generator captures each component's chapter (source-folder grouping band)
|
|
@@ -761,6 +761,13 @@ globalThis.describe("Plugin_Structure.make — Phase 2 graph fields", () => {
|
|
|
761
761
|
let orderIdField = getPropertyOf(ordersSchema, "orderId");
|
|
762
762
|
globalThis.expect(Stdlib_Option.flatMap(orderIdField, s => getProperty(s, "x-reventless-id"))).toBe(undefined);
|
|
763
763
|
});
|
|
764
|
+
globalThis.test("@live(false) flows through the PPX to top-level x-reventless-live", () => {
|
|
765
|
+
globalThis.expect(Stdlib_Option.flatMap(getProperty(annotatedSchema, "x-reventless-live"), Stdlib_JSON.Decode.bool)).toBe(false);
|
|
766
|
+
});
|
|
767
|
+
globalThis.test("unannotated state-view slice (Orders) has no top-level x-reventless-live", () => {
|
|
768
|
+
let ordersSchema = JSON.parse(structure.stateViewSlices[0].schema);
|
|
769
|
+
globalThis.expect(getProperty(ordersSchema, "x-reventless-live")).toBe(undefined);
|
|
770
|
+
});
|
|
764
771
|
});
|
|
765
772
|
globalThis.describe("componentChapters threading", () => {
|
|
766
773
|
let chaptered = Plugin_Structure$ReventlessCore.make("TestPlugin", undefined, undefined, [PsOrdersViewSlice], [
|