@reventlessdev/reventless-aws 3.0.0-alpha.386 → 3.0.0-alpha.388
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 +21 -0
- package/README.md +1 -1
- package/package.json +12 -12
- package/scripts/ProvisionIdentity.res +1 -1
- package/src/Platform.res +20 -13
- package/src/Platform.res.mjs +34 -30
- package/src/Platform_Stack.res +3 -3
- package/src/adapter/AWS_Tags.res +1 -1
- package/src/adapter/Auth/Auth_ActiveRolePoolAttachment.res +1 -1
- package/src/adapter/Auth/Auth_ActiveRoleStore_Ops.res +2 -2
- package/src/adapter/Auth/Auth_ActiveRoleStore_Schema.res +1 -1
- package/src/adapter/Auth/Auth_Cognito.res +1 -1
- package/src/adapter/Auth/Auth_LoginIdentifier.res +1 -1
- package/src/adapter/Auth/Auth_SignUpMode.res +1 -1
- package/src/adapter/DcbEventLog/DcbEventLogStorage_DynamoDb_Runtime.res +2 -2
- package/src/adapter/EventLog/EventLogBackend.res +1 -1
- package/src/adapter/QueryDb/PgQueryResolver_Lambda.res +2 -2
- package/src/adapter/Runtime/AggregateEntryPoint.mjs +6 -6
- package/src/adapter/Runtime/AggregateEntryPoint_Ops.res +1 -1
- package/src/adapter/Runtime/AggregateRuntime_Builder_Micro.res +8 -8
- package/src/adapter/Runtime/AggregateRuntime_Builder_Micro.res.mjs +7 -7
- package/src/adapter/Runtime/AggregateRuntime_Builder_Micro_Async.res +8 -8
- package/src/adapter/Runtime/AggregateRuntime_Builder_Micro_Async.res.mjs +7 -7
- package/src/adapter/Runtime/AggregateRuntime_Builder_PerAggregate.res +7 -7
- package/src/adapter/Runtime/AggregateRuntime_Builder_PerAggregate.res.mjs +6 -6
- package/src/adapter/Runtime/AggregateRuntime_Builder_PerAggregate_Async.res +7 -7
- package/src/adapter/Runtime/AggregateRuntime_Builder_PerAggregate_Async.res.mjs +6 -6
- package/src/adapter/Runtime/AggregateRuntime_Builder_Single.res +7 -7
- package/src/adapter/Runtime/AggregateRuntime_Builder_Single.res.mjs +6 -6
- package/src/adapter/Runtime/AggregateRuntime_Builder_Single_Async.res +7 -7
- package/src/adapter/Runtime/AggregateRuntime_Builder_Single_Async.res.mjs +6 -6
- package/src/adapter/Runtime/AutomationSliceEntryPoint_Ops.res +1 -1
- package/src/adapter/Runtime/AutomationSliceRuntime_Builder_Single.res +2 -2
- package/src/adapter/Runtime/DcbCommandTopicEntryPoint.mjs +7 -7
- package/src/adapter/Runtime/DcbCommandTopicEntryPoint_Ops.res +7 -7
- package/src/adapter/Runtime/DcbCommandTopicEntryPoint_Ops.res.mjs +2 -2
- package/src/adapter/Runtime/EventCollectorEntryPoint.mjs +1 -1
- package/src/adapter/Runtime/RuntimeEnvironment_Lambda.res +2 -2
- package/src/adapter/Runtime/RuntimeExtensionEntryPoint_Ops.res +2 -2
- package/src/adapter/Runtime/StateChangeSliceRuntime_Builder_Single.res +10 -10
- package/src/adapter/Runtime/StateChangeSliceRuntime_Builder_Single.res.mjs +3 -3
- package/src/adapter/StateTopic/StateTopic_AppSync.res +1 -1
- package/src/capability/Capability_Messaging.res +2 -2
- package/src/components/Aggregate_Builder_Micro.res +3 -3
- package/src/components/Aggregate_Builder_Micro.res.mjs +3 -3
- package/src/components/Aggregate_Builder_NoResolver.res +3 -3
- package/src/components/Aggregate_Builder_NoResolver.res.mjs +3 -3
- package/src/components/Aggregate_Builder_PerAggregate.res +3 -3
- package/src/components/Aggregate_Builder_PerAggregate.res.mjs +3 -3
- package/src/components/Aggregate_Builder_Single.res +3 -3
- package/src/components/Aggregate_Builder_Single.res.mjs +3 -3
- package/src/components/Aggregate_Builder_Single_Async.res +3 -3
- package/src/components/Aggregate_Builder_Single_Async.res.mjs +3 -3
- package/src/components/Api/AppSync_Adapter.res +3 -3
- package/src/components/Api/AppSync_SdlDecorate.res +3 -3
- package/src/components/SideEffectHandler_PerSideEffectHandler.res +1 -1
- package/src/components/StateChangeSlice_Builder.res +4 -4
- package/src/components/StateChangeSlice_Builder.res.mjs +4 -4
- package/src/plugin/runtime/PluginRuntime_Builder.res +4 -4
- package/src/plugin/runtime/PluginRuntime_Builder.res.mjs +3 -3
- package/src/plugin/stack/Plugin_Stack.res +1 -1
- package/src/util/Util_Bundle.res +1 -1
- package/src/util/Util_ShellConfig.res +7 -1
- package/src/util/Util_ShellConfig.res.mjs +8 -2
- package/tests/AppSync_AdapterTest.res +1 -1
- package/tests/AppSync_RetirementNarrowingTest.res +1 -1
- package/tests/AppSync_SdlDecorateTest.res +1 -1
- package/tests/Auth_LoginIdentifierTest.res +1 -1
- package/tests/Auth_SignUpModeTest.res +1 -1
- package/tests/BakeConvergenceTest.res +11 -11
- package/tests/BakeConvergenceTest.res.mjs +13 -13
- package/tests/QueryDbResolvers_AppSyncTest.res +1 -1
- package/tests/Upload_ClaimTest.res +1 -1
- package/tests/Util_AwsErrorTest.res +1 -1
- package/tests/Util_ShellConfigTest.res +40 -0
- package/tests/Util_ShellConfigTest.res.mjs +76 -21
- package/tests/Util_StoreLayoutTest.res +1 -1
- package/tests/dcbColdStartPartition.mjs +3 -3
- package/tests/integration/{AggTestAggregateBehavior.res → AggTestAggregateDecision.res} +2 -2
- package/tests/integration/{AggTestAggregateBehavior.res.mjs → AggTestAggregateDecision.res.mjs} +1 -1
- package/tests/integration/AggregateEntryPoint_IntegrationTest.res +3 -3
- package/tests/integration/AggregateEntryPoint_IntegrationTest.res.mjs +2 -2
- package/tests/integration/DcbCommandTopicEntryPoint_IntegrationTest.res +5 -5
- package/tests/integration/DcbCommandTopicEntryPoint_IntegrationTest.res.mjs +4 -4
- package/tests/integration/DcbEventLogStorage_DynamoDb_IntegrationTest.res +1 -1
- package/tests/integration/{EpCompositeSliceBehavior.res → EpCompositeSliceDecision.res} +2 -2
- package/tests/integration/{EpCompositeSliceBehavior.res.mjs → EpCompositeSliceDecision.res.mjs} +1 -1
- package/tests/integration/{EpTestSliceBehavior.res → EpTestSliceDecision.res} +2 -2
- package/tests/integration/{EpTestSliceBehavior.res.mjs → EpTestSliceDecision.res.mjs} +1 -1
|
@@ -101,10 +101,10 @@ let dcbConfigRef = {
|
|
|
101
101
|
|
|
102
102
|
let registeredSliceModulePaths = [];
|
|
103
103
|
|
|
104
|
-
function registerStateChangeSliceSpec(specPath,
|
|
104
|
+
function registerStateChangeSliceSpec(specPath, decisionPath) {
|
|
105
105
|
registeredSliceModulePaths.push({
|
|
106
106
|
specPath: specPath,
|
|
107
|
-
|
|
107
|
+
decisionPath: decisionPath
|
|
108
108
|
});
|
|
109
109
|
}
|
|
110
110
|
|
|
@@ -547,7 +547,7 @@ function Make(EventCollectorChannel) {
|
|
|
547
547
|
let dcbConfig = dcbConfigRef.contents;
|
|
548
548
|
let slicePaths = registeredSliceModulePaths.concat(dcbConfig.stateChangeSliceModulePaths).map(param => [
|
|
549
549
|
param.specPath,
|
|
550
|
-
param.
|
|
550
|
+
param.decisionPath
|
|
551
551
|
]);
|
|
552
552
|
let inboundSlices = Stdlib_Array.filterMap(Object.values(registeredInboundSlices), reg => {
|
|
553
553
|
if (reg.specPath === "") {
|
|
@@ -524,7 +524,7 @@ let makeUiBundleDistribution = (
|
|
|
524
524
|
|
|
525
525
|
// Auto-invalidate CloudFront once every object is (re)uploaded. Stable-named
|
|
526
526
|
// entry files (index.html, the module-federation mf-entry-bootstrap-*.js)
|
|
527
|
-
// are served by the long-TTL default cache
|
|
527
|
+
// are served by the long-TTL default cache behavior, so without this a
|
|
528
528
|
// `pulumi up` lands the new bundle in S3 while CloudFront keeps serving the
|
|
529
529
|
// prior build until its TTL expires. Chained on the upload etags so it runs
|
|
530
530
|
// AFTER the new content is in S3; `/*` is a single invalidation path (well
|
package/src/util/Util_Bundle.res
CHANGED
|
@@ -254,7 +254,7 @@ type codeArchive = {
|
|
|
254
254
|
*
|
|
255
255
|
* `ReventlessCore.RuntimeExtension` carries `import.meta.url`s because that is
|
|
256
256
|
* what an extension module can state about itself; the npm specifier a Lambda
|
|
257
|
-
* resolves is derived here, the same conversion spec and
|
|
257
|
+
* resolves is derived here, the same conversion spec and decision modules go
|
|
258
258
|
* through.
|
|
259
259
|
*/
|
|
260
260
|
let runtimeExtensionSpecifiers = (): array<string> =>
|
|
@@ -81,7 +81,8 @@ let subscriptionEndpoint = (httpsEndpoint: string): string =>
|
|
|
81
81
|
/**
|
|
82
82
|
The config.json field set.
|
|
83
83
|
|
|
84
|
-
`computed` arrives in wire order and keeps it
|
|
84
|
+
`computed` arrives in wire order and keeps it; `environment` follows it, its
|
|
85
|
+
purpose key only when the purpose is known. `viewModes` unset ⇒ no
|
|
85
86
|
`viewModes` key and no per-mode key, so a deployment that wants no optional mode
|
|
86
87
|
gets byte-identical output to before this input existed. `bakedManifest` unset ⇒
|
|
87
88
|
no `manifestUrl`, and every caller keeps the admin discovery path. `shellConfig`
|
|
@@ -91,6 +92,7 @@ somewhere unintended with nothing in the diff to say so.
|
|
|
91
92
|
*/
|
|
92
93
|
let fields = (
|
|
93
94
|
~computed: array<(string, JSON.t)>,
|
|
95
|
+
~environment: option<Reventless.ShellEnvironment.t>=?,
|
|
94
96
|
~viewModes: option<array<Platform.viewMode>>=?,
|
|
95
97
|
~bakedManifest: option<Platform.bakedManifest>=?,
|
|
96
98
|
~uiSlotsFile: option<string>=?,
|
|
@@ -98,6 +100,10 @@ let fields = (
|
|
|
98
100
|
): dict<JSON.t> => {
|
|
99
101
|
let out = computed->Dict.fromArray
|
|
100
102
|
|
|
103
|
+
environment->Option.forEach(env =>
|
|
104
|
+
env->Reventless.ShellEnvironment.configFields->Array.forEach(((k, v)) => out->Dict.set(k, v))
|
|
105
|
+
)
|
|
106
|
+
|
|
101
107
|
// Computed, like the endpoints: the group the admin API is gated on, from the
|
|
102
108
|
// deploy's own role mapping.
|
|
103
109
|
ReventlessCore.Platform_AdminGroup.configEntry()->Option.forEach(((k, v)) => out->Dict.set(k, v))
|
|
@@ -4,6 +4,7 @@ import * as Pervasives from "@rescript/runtime/lib/es6/Pervasives.js";
|
|
|
4
4
|
import * as Stdlib_Dict from "@rescript/runtime/lib/es6/Stdlib_Dict.js";
|
|
5
5
|
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
6
6
|
import * as Platform$ReventlessInfra from "@reventlessdev/reventless-infra/src/types/Platform.res.mjs";
|
|
7
|
+
import * as ShellEnvironment$Reventless from "@reventlessdev/reventless-spec/src/types/ShellEnvironment.res.mjs";
|
|
7
8
|
import * as Platform_UiSlots$ReventlessCore from "@reventlessdev/reventless-core/src/admin/Platform_UiSlots.res.mjs";
|
|
8
9
|
import * as Platform_AdminGroup$ReventlessCore from "@reventlessdev/reventless-core/src/admin/Platform_AdminGroup.res.mjs";
|
|
9
10
|
import * as Platform_BakedManifest$ReventlessCore from "@reventlessdev/reventless-core/src/admin/Platform_BakedManifest.res.mjs";
|
|
@@ -58,8 +59,13 @@ function subscriptionEndpoint(httpsEndpoint) {
|
|
|
58
59
|
return httpsEndpoint.replace("https://", "wss://").replace(".appsync-api.", ".appsync-realtime-api.");
|
|
59
60
|
}
|
|
60
61
|
|
|
61
|
-
function fields(computed, viewModes, bakedManifest, uiSlotsFile, shellConfig) {
|
|
62
|
+
function fields(computed, environment, viewModes, bakedManifest, uiSlotsFile, shellConfig) {
|
|
62
63
|
let out = Object.fromEntries(computed);
|
|
64
|
+
Stdlib_Option.forEach(environment, env => {
|
|
65
|
+
ShellEnvironment$Reventless.configFields(env).forEach(param => {
|
|
66
|
+
out[param[0]] = param[1];
|
|
67
|
+
});
|
|
68
|
+
});
|
|
63
69
|
Stdlib_Option.forEach(Platform_AdminGroup$ReventlessCore.configEntry(), param => {
|
|
64
70
|
out[param[0]] = param[1];
|
|
65
71
|
});
|
|
@@ -107,4 +113,4 @@ export {
|
|
|
107
113
|
subscriptionEndpoint,
|
|
108
114
|
fields,
|
|
109
115
|
}
|
|
110
|
-
/*
|
|
116
|
+
/* ShellEnvironment-Reventless Not a pure module */
|
|
@@ -330,7 +330,7 @@ describe("AppSync_Adapter.injectAwsAuth — Stage E2 permission lifting", () =>
|
|
|
330
330
|
// and emitted the same group-less directive, which on this Cognito-primary
|
|
331
331
|
// API means *any authenticated caller* — the inverse of the declaration. It
|
|
332
332
|
// deployed green, passed `assertGateable`, and worked on the local platform,
|
|
333
|
-
// whose resolvers call `Authorization.isAllowed` and
|
|
333
|
+
// whose resolvers call `Authorization.isAllowed` and honor the rule. It
|
|
334
334
|
// failed closed, so no deployment ever reported it.
|
|
335
335
|
|
|
336
336
|
let refuses = (run: unit => 'a): bool =>
|
|
@@ -192,7 +192,7 @@ describe("the by-index door's owner scoping", () => {
|
|
|
192
192
|
)->Expect.toBe(true)
|
|
193
193
|
)
|
|
194
194
|
|
|
195
|
-
// The generic argument loop turns an
|
|
195
|
+
// The generic argument loop turns an unrecognized arg into a `contains` filter.
|
|
196
196
|
// `includeRetired` is a request to lift a restriction, and filtering on it
|
|
197
197
|
// would match no row at all.
|
|
198
198
|
testSync("never treats includeRetired as a column to match on", () =>
|
|
@@ -270,7 +270,7 @@ describe("AppSync_SdlDecorate.assertGateable", () => {
|
|
|
270
270
|
|
|
271
271
|
// The original outage, exactly. A "does it have a directive?" check passes
|
|
272
272
|
// this — @aws_auth was present on all 18 admin fields the whole time it was
|
|
273
|
-
// inert. Only knowing WHICH directive the service
|
|
273
|
+
// inert. Only knowing WHICH directive the service honors catches it.
|
|
274
274
|
testSync("refuses @aws_auth, the directive AppSync ignores here", () => {
|
|
275
275
|
let sdl = `type Query @aws_cognito_user_pools {\n Admin_Thing: String @aws_auth(cognito_groups: ["Admin"])\n}`
|
|
276
276
|
expect(refuses(sdl))->toBe(true)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
open JestGlobals
|
|
2
2
|
|
|
3
3
|
// The sign-in attribute is the one pool setting no later deploy can correct, so
|
|
4
|
-
// what these cover is the parse: absent must mean today's
|
|
4
|
+
// what these cover is the parse: absent must mean today's behavior, and a
|
|
5
5
|
// spelling this build does not know must refuse rather than default.
|
|
6
6
|
|
|
7
7
|
module LoginIdentifier = Auth_LoginIdentifier
|
|
@@ -2,7 +2,7 @@ open JestGlobals
|
|
|
2
2
|
|
|
3
3
|
// Sign-up mode is correctable on a live pool, unlike the sign-in attribute, so
|
|
4
4
|
// what these cover is not permanence but silence: absent must mean today's
|
|
5
|
-
//
|
|
5
|
+
// behavior, an unknown spelling must refuse rather than quietly close the pool,
|
|
6
6
|
// and the mapping onto Cognito's inverted field must not be readable backwards.
|
|
7
7
|
|
|
8
8
|
module SignUpMode = Auth_SignUpMode
|
|
@@ -94,10 +94,10 @@ let row = (def: Reventless.Plugin.pluginDefinition, ~at: string): dict<JSON.t> =
|
|
|
94
94
|
->JSON.Decode.object
|
|
95
95
|
->Option.getOr(Dict.make())
|
|
96
96
|
|
|
97
|
-
let apply = (state, events) => events->Array.reduce(state, ReventlessCore.
|
|
97
|
+
let apply = (state, events) => events->Array.reduce(state, ReventlessCore.PluginDecision.evolve)
|
|
98
98
|
|
|
99
99
|
let connect = (state, def) =>
|
|
100
|
-
switch ReventlessCore.
|
|
100
|
+
switch ReventlessCore.PluginDecision.decide(state, ReventlessCore.PluginSpec.Connect(def)) {
|
|
101
101
|
| Ok(events) => events
|
|
102
102
|
| Error(_) => []
|
|
103
103
|
}
|
|
@@ -153,16 +153,16 @@ describe("the bake converges when a plugin's structure changes", () => {
|
|
|
153
153
|
// unchanged one, so this is the step a broken chain silently skips.
|
|
154
154
|
testSync("a redeploy with a changed structure re-emits VersionConnected", () => {
|
|
155
155
|
let connected =
|
|
156
|
-
ReventlessCore.
|
|
157
|
-
connect(ReventlessCore.
|
|
156
|
+
ReventlessCore.PluginDecision.initialState->apply(
|
|
157
|
+
connect(ReventlessCore.PluginDecision.initialState, shipped(defA)),
|
|
158
158
|
)
|
|
159
159
|
expect(connect(connected, shipped(defB))->Array.length)->toBe(1)
|
|
160
160
|
})
|
|
161
161
|
|
|
162
162
|
testSync("once it lands, the plugin reads as registered by this deploy", () => {
|
|
163
163
|
let connected =
|
|
164
|
-
ReventlessCore.
|
|
165
|
-
connect(ReventlessCore.
|
|
164
|
+
ReventlessCore.PluginDecision.initialState->apply(
|
|
165
|
+
connect(ReventlessCore.PluginDecision.initialState, shipped(defA)),
|
|
166
166
|
)
|
|
167
167
|
let redeployed = connected->apply(connect(connected, shipped(defB)))
|
|
168
168
|
let def = switch redeployed.known->Dict.get("1.0.0") {
|
|
@@ -180,8 +180,8 @@ describe("the bake converges when a plugin's structure changes", () => {
|
|
|
180
180
|
// counts it apart from a plugin that did register.
|
|
181
181
|
testSync("an unchanged structure passes without re-registering", () => {
|
|
182
182
|
let connected =
|
|
183
|
-
ReventlessCore.
|
|
184
|
-
connect(ReventlessCore.
|
|
183
|
+
ReventlessCore.PluginDecision.initialState->apply(
|
|
184
|
+
connect(ReventlessCore.PluginDecision.initialState, shipped(defA)),
|
|
185
185
|
)
|
|
186
186
|
expect(connect(connected, shipped(defA)))->toEqual([])
|
|
187
187
|
expect(
|
|
@@ -198,11 +198,11 @@ describe("the bake converges when a plugin's structure changes", () => {
|
|
|
198
198
|
// and the changed structure never reaches the read model.
|
|
199
199
|
testSync("a redeploy re-detects an already-connected version", () => {
|
|
200
200
|
let connected =
|
|
201
|
-
ReventlessCore.
|
|
202
|
-
connect(ReventlessCore.
|
|
201
|
+
ReventlessCore.PluginDecision.initialState->apply(
|
|
202
|
+
connect(ReventlessCore.PluginDecision.initialState, shipped(defA)),
|
|
203
203
|
)
|
|
204
204
|
expect(
|
|
205
|
-
ReventlessCore.
|
|
205
|
+
ReventlessCore.PluginDecision.decide(connected, ReventlessCore.PluginSpec.Redetect("1.0.0")),
|
|
206
206
|
)->toEqual(Ok([ReventlessCore.PluginSpec.VersionDetected("1.0.0")]))
|
|
207
207
|
})
|
|
208
208
|
})
|
|
@@ -6,7 +6,7 @@ import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
|
|
|
6
6
|
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
7
7
|
import * as Plugin$Reventless from "@reventlessdev/reventless-spec/src/components/Plugin.res.mjs";
|
|
8
8
|
import * as Util_Sury$Reventless from "@reventlessdev/reventless-spec/src/util/Util_Sury.res.mjs";
|
|
9
|
-
import * as
|
|
9
|
+
import * as PluginDecision$ReventlessCore from "@reventlessdev/reventless-core/src/plugin/lifecycle/PluginDecision.res.mjs";
|
|
10
10
|
import * as Plugin_Helpers$ReventlessCore from "@reventlessdev/reventless-core/src/plugin/component/Plugin_Helpers.res.mjs";
|
|
11
11
|
import * as PluginsProjection$ReventlessCore from "@reventlessdev/reventless-core/src/plugin/lifecycle/PluginsProjection.res.mjs";
|
|
12
12
|
import * as Platform_ComponentDefinitions_Lambda_Ops$ReventlessAws from "../src/adapter/Api/Platform_ComponentDefinitions_Lambda_Ops.res.mjs";
|
|
@@ -97,11 +97,11 @@ function row(def, at) {
|
|
|
97
97
|
}
|
|
98
98
|
|
|
99
99
|
function apply(state, events) {
|
|
100
|
-
return Stdlib_Array.reduce(events, state,
|
|
100
|
+
return Stdlib_Array.reduce(events, state, PluginDecision$ReventlessCore.evolve);
|
|
101
101
|
}
|
|
102
102
|
|
|
103
103
|
function connect(state, def) {
|
|
104
|
-
let events =
|
|
104
|
+
let events = PluginDecision$ReventlessCore.decide(state, {
|
|
105
105
|
TAG: "Connect",
|
|
106
106
|
_0: def
|
|
107
107
|
});
|
|
@@ -156,15 +156,15 @@ globalThis.describe("the bake converges when a plugin's structure changes", () =
|
|
|
156
156
|
]], deployedAt)).toEqual("behind");
|
|
157
157
|
});
|
|
158
158
|
globalThis.test("a redeploy with a changed structure re-emits VersionConnected", () => {
|
|
159
|
-
let events = connect(
|
|
160
|
-
let connected = Stdlib_Array.reduce(events,
|
|
159
|
+
let events = connect(PluginDecision$ReventlessCore.initialState, shipped(defA));
|
|
160
|
+
let connected = Stdlib_Array.reduce(events, PluginDecision$ReventlessCore.initialState, PluginDecision$ReventlessCore.evolve);
|
|
161
161
|
globalThis.expect(connect(connected, shipped(defB)).length).toBe(1);
|
|
162
162
|
});
|
|
163
163
|
globalThis.test("once it lands, the plugin reads as registered by this deploy", () => {
|
|
164
|
-
let events = connect(
|
|
165
|
-
let connected = Stdlib_Array.reduce(events,
|
|
164
|
+
let events = connect(PluginDecision$ReventlessCore.initialState, shipped(defA));
|
|
165
|
+
let connected = Stdlib_Array.reduce(events, PluginDecision$ReventlessCore.initialState, PluginDecision$ReventlessCore.evolve);
|
|
166
166
|
let events$1 = connect(connected, shipped(defB));
|
|
167
|
-
let redeployed = Stdlib_Array.reduce(events$1, connected,
|
|
167
|
+
let redeployed = Stdlib_Array.reduce(events$1, connected, PluginDecision$ReventlessCore.evolve);
|
|
168
168
|
let match = redeployed.known["1.0.0"];
|
|
169
169
|
let def = match !== undefined ? match.definition : shipped(defA);
|
|
170
170
|
globalThis.expect(stateOf([row(def, afterDeploy)], [[
|
|
@@ -173,8 +173,8 @@ globalThis.describe("the bake converges when a plugin's structure changes", () =
|
|
|
173
173
|
]], deployedAt)).toEqual("registered");
|
|
174
174
|
});
|
|
175
175
|
globalThis.test("an unchanged structure passes without re-registering", () => {
|
|
176
|
-
let events = connect(
|
|
177
|
-
let connected = Stdlib_Array.reduce(events,
|
|
176
|
+
let events = connect(PluginDecision$ReventlessCore.initialState, shipped(defA));
|
|
177
|
+
let connected = Stdlib_Array.reduce(events, PluginDecision$ReventlessCore.initialState, PluginDecision$ReventlessCore.evolve);
|
|
178
178
|
globalThis.expect(connect(connected, shipped(defA))).toEqual([]);
|
|
179
179
|
globalThis.expect(stateOf([row(shipped(defA), beforeDeploy)], [[
|
|
180
180
|
"Ordering",
|
|
@@ -182,9 +182,9 @@ globalThis.describe("the bake converges when a plugin's structure changes", () =
|
|
|
182
182
|
]], deployedAt)).toEqual("unchanged");
|
|
183
183
|
});
|
|
184
184
|
globalThis.test("a redeploy re-detects an already-connected version", () => {
|
|
185
|
-
let events = connect(
|
|
186
|
-
let connected = Stdlib_Array.reduce(events,
|
|
187
|
-
globalThis.expect(
|
|
185
|
+
let events = connect(PluginDecision$ReventlessCore.initialState, shipped(defA));
|
|
186
|
+
let connected = Stdlib_Array.reduce(events, PluginDecision$ReventlessCore.initialState, PluginDecision$ReventlessCore.evolve);
|
|
187
|
+
globalThis.expect(PluginDecision$ReventlessCore.decide(connected, {
|
|
188
188
|
TAG: "Redetect",
|
|
189
189
|
_0: "1.0.0"
|
|
190
190
|
})).toEqual({
|
|
@@ -43,7 +43,7 @@ describe("AppSync_Resolver_Retrying.Functions.listAllItemsConnection", () => {
|
|
|
43
43
|
)
|
|
44
44
|
})
|
|
45
45
|
|
|
46
|
-
// Tripwires for the Scan connection's paging. The
|
|
46
|
+
// Tripwires for the Scan connection's paging. The behavior itself is exercised
|
|
47
47
|
// against the evaluated resolver in `rescript/pulumi-aws`; these guard the wiring
|
|
48
48
|
// this package is responsible for emitting.
|
|
49
49
|
describe("listAllItemsConnection — paging", () => {
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// decided by three functions in `Upload_Claim_S3_Ops`: which table a record came
|
|
5
5
|
// from, which refs a declared field holds, and whether a ref resolves to an
|
|
6
6
|
// object this claimer may touch. The untag itself has no branching left in it,
|
|
7
|
-
// so pinning these pins the
|
|
7
|
+
// so pinning these pins the behavior that matters.
|
|
8
8
|
//
|
|
9
9
|
// The direction under test throughout is refusal. An untag this component
|
|
10
10
|
// wrongly *skips* costs a delayed cleanup; one it wrongly *performs* removes the
|
|
@@ -18,7 +18,7 @@ external throwAwsError: (string, string) => unit = "throwAwsError"
|
|
|
18
18
|
|
|
19
19
|
🚨 **Thrown and caught, not constructed.** ReScript's `exn` for a JS error is
|
|
20
20
|
the wrapper its own `catch` builds — a bare `Error` value is a different thing
|
|
21
|
-
and `JsExn.fromException` does not
|
|
21
|
+
and `JsExn.fromException` does not recognize it. A fixture that returned one
|
|
22
22
|
would make every predicate here look broken while the code was fine, which is
|
|
23
23
|
exactly the wrong way round for a regression test. */
|
|
24
24
|
let awsError = (~name: string, ~message: string): exn =>
|
|
@@ -226,6 +226,46 @@ describe("Util_ShellConfig.fields — journeys", () => {
|
|
|
226
226
|
})
|
|
227
227
|
})
|
|
228
228
|
|
|
229
|
+
// The shell badges every environment that is not production, so a purpose that
|
|
230
|
+
// went missing shows as a badge rather than as nothing.
|
|
231
|
+
describe("Util_ShellConfig.fields — environment", () => {
|
|
232
|
+
testSync("the name and the purpose follow the computed keys", () => {
|
|
233
|
+
let out = Util_ShellConfig.fields(~computed, ~environment={name: "test", purpose: Some("test")})
|
|
234
|
+
expect(out->Dict.keysToArray)->toEqual([
|
|
235
|
+
"apiEndpoint",
|
|
236
|
+
"region",
|
|
237
|
+
"environment",
|
|
238
|
+
"environmentPurpose",
|
|
239
|
+
])
|
|
240
|
+
expect((out->get("environment"), out->get("environmentPurpose")))->toEqual((
|
|
241
|
+
JSON.Encode.string("test"),
|
|
242
|
+
JSON.Encode.string("test"),
|
|
243
|
+
))
|
|
244
|
+
})
|
|
245
|
+
|
|
246
|
+
testSync("an unknown purpose leaves its key out", () => {
|
|
247
|
+
let out = Util_ShellConfig.fields(~computed, ~environment={name: "alpha", purpose: None})
|
|
248
|
+
expect(out->Dict.get("environmentPurpose")->Option.isNone)->toBe(true)
|
|
249
|
+
})
|
|
250
|
+
|
|
251
|
+
testSync("a shellConfig environment fails the deploy rather than renaming it", () => {
|
|
252
|
+
let failure = try {
|
|
253
|
+
let _ = Util_ShellConfig.fields(
|
|
254
|
+
~computed,
|
|
255
|
+
~environment={name: "prod", purpose: Some("production")},
|
|
256
|
+
~shellConfig=Dict.fromArray([("environment", JSON.Encode.string("staging"))]),
|
|
257
|
+
)
|
|
258
|
+
None
|
|
259
|
+
} catch {
|
|
260
|
+
| Failure(message) => Some(message)
|
|
261
|
+
}
|
|
262
|
+
switch failure {
|
|
263
|
+
| Some(message) => expect(message->String.includes("environment"))->toBe(true)
|
|
264
|
+
| None => fail("a shellConfig key renaming the computed environment must fail the deploy")
|
|
265
|
+
}
|
|
266
|
+
})
|
|
267
|
+
})
|
|
268
|
+
|
|
229
269
|
describe("Util_ShellConfig.fields — shellConfig passthrough", () => {
|
|
230
270
|
testSync("shell-owned keys land verbatim, under the computed ones", () => {
|
|
231
271
|
let out = Util_ShellConfig.fields(
|
|
@@ -28,7 +28,7 @@ function get(out, key) {
|
|
|
28
28
|
|
|
29
29
|
globalThis.describe("Util_ShellConfig.fields — viewModes", () => {
|
|
30
30
|
globalThis.test("unset ⇒ no viewModes key and the computed set is untouched", () => {
|
|
31
|
-
let out = Util_ShellConfig$ReventlessAws.fields(computed, undefined, undefined, undefined, undefined);
|
|
31
|
+
let out = Util_ShellConfig$ReventlessAws.fields(computed, undefined, undefined, undefined, undefined, undefined);
|
|
32
32
|
globalThis.expect(Object.keys(out)).toEqual([
|
|
33
33
|
"apiEndpoint",
|
|
34
34
|
"region"
|
|
@@ -36,7 +36,7 @@ globalThis.describe("Util_ShellConfig.fields — viewModes", () => {
|
|
|
36
36
|
globalThis.expect(Stdlib_Option.isNone(out["viewModes"])).toBe(true);
|
|
37
37
|
});
|
|
38
38
|
globalThis.test("Map with defaults ⇒ the mode, and no mapStyle key", () => {
|
|
39
|
-
let out = Util_ShellConfig$ReventlessAws.fields(computed, [{
|
|
39
|
+
let out = Util_ShellConfig$ReventlessAws.fields(computed, undefined, [{
|
|
40
40
|
TAG: "Map",
|
|
41
41
|
_0: {}
|
|
42
42
|
}], undefined, undefined, undefined);
|
|
@@ -44,7 +44,7 @@ globalThis.describe("Util_ShellConfig.fields — viewModes", () => {
|
|
|
44
44
|
globalThis.expect(Stdlib_Option.isNone(out["mapStyle"])).toBe(true);
|
|
45
45
|
});
|
|
46
46
|
globalThis.test("per-mode options flatten beside the mode", () => {
|
|
47
|
-
let out = Util_ShellConfig$ReventlessAws.fields(computed, [
|
|
47
|
+
let out = Util_ShellConfig$ReventlessAws.fields(computed, undefined, [
|
|
48
48
|
{
|
|
49
49
|
TAG: "Map",
|
|
50
50
|
_0: {
|
|
@@ -77,21 +77,21 @@ globalThis.describe("Util_ShellConfig.fields — bakedManifest", () => {
|
|
|
77
77
|
key: key
|
|
78
78
|
});
|
|
79
79
|
globalThis.test("unset ⇒ no manifestUrl, so every caller keeps the admin path", () => {
|
|
80
|
-
let out = Util_ShellConfig$ReventlessAws.fields(computed, undefined, undefined, undefined, undefined);
|
|
80
|
+
let out = Util_ShellConfig$ReventlessAws.fields(computed, undefined, undefined, undefined, undefined, undefined);
|
|
81
81
|
globalThis.expect(Stdlib_Option.isNone(out["manifestUrl"])).toBe(true);
|
|
82
82
|
});
|
|
83
83
|
globalThis.test("declared ⇒ the URL the deploy writes the file to", () => {
|
|
84
|
-
let out = Util_ShellConfig$ReventlessAws.fields(computed, undefined, bake(undefined), undefined, undefined);
|
|
84
|
+
let out = Util_ShellConfig$ReventlessAws.fields(computed, undefined, undefined, bake(undefined), undefined, undefined);
|
|
85
85
|
globalThis.expect(get(out, "manifestUrl")).toEqual("/component-manifest.json");
|
|
86
86
|
});
|
|
87
87
|
globalThis.test("follows a renamed bake", () => {
|
|
88
|
-
let out = Util_ShellConfig$ReventlessAws.fields(computed, undefined, bake("storefront.json"), undefined, undefined);
|
|
88
|
+
let out = Util_ShellConfig$ReventlessAws.fields(computed, undefined, undefined, bake("storefront.json"), undefined, undefined);
|
|
89
89
|
globalThis.expect(get(out, "manifestUrl")).toEqual("/storefront.json");
|
|
90
90
|
});
|
|
91
91
|
globalThis.test("a shellConfig manifestUrl fails the deploy rather than redirecting it", () => {
|
|
92
92
|
let failure;
|
|
93
93
|
try {
|
|
94
|
-
Util_ShellConfig$ReventlessAws.fields(computed, undefined, bake(undefined), undefined, Object.fromEntries([[
|
|
94
|
+
Util_ShellConfig$ReventlessAws.fields(computed, undefined, undefined, bake(undefined), undefined, Object.fromEntries([[
|
|
95
95
|
"manifestUrl",
|
|
96
96
|
"/elsewhere.json"
|
|
97
97
|
]]));
|
|
@@ -115,21 +115,21 @@ globalThis.describe("Util_ShellConfig.fields — bakedManifest", () => {
|
|
|
115
115
|
|
|
116
116
|
globalThis.describe("Util_ShellConfig.fields — uiSlotsFile", () => {
|
|
117
117
|
globalThis.test("unset ⇒ no uiSlotsUrl, and the shell imports nothing", () => {
|
|
118
|
-
let out = Util_ShellConfig$ReventlessAws.fields(computed, undefined, undefined, undefined, undefined);
|
|
118
|
+
let out = Util_ShellConfig$ReventlessAws.fields(computed, undefined, undefined, undefined, undefined, undefined);
|
|
119
119
|
globalThis.expect(Stdlib_Option.isNone(out["uiSlotsUrl"])).toBe(true);
|
|
120
120
|
});
|
|
121
121
|
globalThis.test("declared ⇒ the URL the deploy writes the module to", () => {
|
|
122
|
-
let out = Util_ShellConfig$ReventlessAws.fields(computed, undefined, undefined, "/src/storefront-slots.js", undefined);
|
|
122
|
+
let out = Util_ShellConfig$ReventlessAws.fields(computed, undefined, undefined, undefined, "/src/storefront-slots.js", undefined);
|
|
123
123
|
globalThis.expect(get(out, "uiSlotsUrl")).toEqual("/ui-slots.js");
|
|
124
124
|
});
|
|
125
125
|
globalThis.test("names where the file is served, never where it was authored", () => {
|
|
126
|
-
let out = Util_ShellConfig$ReventlessAws.fields(computed, undefined, undefined, "/home/me/prj/slots.js", undefined);
|
|
126
|
+
let out = Util_ShellConfig$ReventlessAws.fields(computed, undefined, undefined, undefined, "/home/me/prj/slots.js", undefined);
|
|
127
127
|
globalThis.expect(get(out, "uiSlotsUrl")).toEqual("/ui-slots.js");
|
|
128
128
|
});
|
|
129
129
|
globalThis.test("a shellConfig uiSlotsUrl fails the deploy rather than redirecting it", () => {
|
|
130
130
|
let failure;
|
|
131
131
|
try {
|
|
132
|
-
Util_ShellConfig$ReventlessAws.fields(computed, undefined, undefined, "/src/storefront-slots.js", Object.fromEntries([[
|
|
132
|
+
Util_ShellConfig$ReventlessAws.fields(computed, undefined, undefined, undefined, "/src/storefront-slots.js", Object.fromEntries([[
|
|
133
133
|
"uiSlotsUrl",
|
|
134
134
|
"/elsewhere.js"
|
|
135
135
|
]]));
|
|
@@ -181,7 +181,7 @@ globalThis.describe("Util_ShellConfig.fields — journeys", () => {
|
|
|
181
181
|
key: fulfilment_key
|
|
182
182
|
};
|
|
183
183
|
globalThis.test("a bake declaring no journeys writes no map", () => {
|
|
184
|
-
let out = Util_ShellConfig$ReventlessAws.fields(computed, undefined, {
|
|
184
|
+
let out = Util_ShellConfig$ReventlessAws.fields(computed, undefined, undefined, {
|
|
185
185
|
components: [{
|
|
186
186
|
plugin: "Catalog",
|
|
187
187
|
views: ["Products"],
|
|
@@ -191,15 +191,15 @@ globalThis.describe("Util_ShellConfig.fields — journeys", () => {
|
|
|
191
191
|
globalThis.expect(Stdlib_Option.isNone(out["journeyManifestUrls"])).toBe(true);
|
|
192
192
|
});
|
|
193
193
|
globalThis.test("an empty journeys array is the same as none", () => {
|
|
194
|
-
let out = Util_ShellConfig$ReventlessAws.fields(computed, undefined, withJourneys([]), undefined, undefined);
|
|
194
|
+
let out = Util_ShellConfig$ReventlessAws.fields(computed, undefined, undefined, withJourneys([]), undefined, undefined);
|
|
195
195
|
globalThis.expect(Stdlib_Option.isNone(out["journeyManifestUrls"])).toBe(true);
|
|
196
196
|
});
|
|
197
197
|
globalThis.test("keeps manifestUrl as the default journey", () => {
|
|
198
|
-
let out = Util_ShellConfig$ReventlessAws.fields(computed, undefined, withJourneys([shopper]), undefined, undefined);
|
|
198
|
+
let out = Util_ShellConfig$ReventlessAws.fields(computed, undefined, undefined, withJourneys([shopper]), undefined, undefined);
|
|
199
199
|
globalThis.expect(get(out, "manifestUrl")).toEqual("/component-manifest.json");
|
|
200
200
|
});
|
|
201
201
|
globalThis.test("maps each declared group to its own file", () => {
|
|
202
|
-
let out = Util_ShellConfig$ReventlessAws.fields(computed, undefined, withJourneys([
|
|
202
|
+
let out = Util_ShellConfig$ReventlessAws.fields(computed, undefined, undefined, withJourneys([
|
|
203
203
|
shopper,
|
|
204
204
|
fulfilment
|
|
205
205
|
]), undefined, undefined);
|
|
@@ -219,14 +219,14 @@ globalThis.describe("Util_ShellConfig.fields — journeys", () => {
|
|
|
219
219
|
shopper,
|
|
220
220
|
fulfilment
|
|
221
221
|
]);
|
|
222
|
-
let out = Util_ShellConfig$ReventlessAws.fields(computed, undefined, bake, undefined, undefined);
|
|
222
|
+
let out = Util_ShellConfig$ReventlessAws.fields(computed, undefined, undefined, bake, undefined, undefined);
|
|
223
223
|
let published = Stdlib_Option.mapOr(Stdlib_JSON.Decode.string(get(out, "manifestUrl")), [], url => [url]).concat(Stdlib_Array.filterMap(Object.values(Stdlib_Option.getOr(Stdlib_JSON.Decode.object(get(out, "journeyManifestUrls")), {})), Stdlib_JSON.Decode.string));
|
|
224
224
|
globalThis.expect(published).toEqual(Platform_BakedManifest$ReventlessCore.files(bake).map(param => "/" + param[0]));
|
|
225
225
|
});
|
|
226
226
|
globalThis.test("a shellConfig journey map fails the deploy rather than redirecting it", () => {
|
|
227
227
|
let failure;
|
|
228
228
|
try {
|
|
229
|
-
Util_ShellConfig$ReventlessAws.fields(computed, undefined, withJourneys([shopper]), undefined, Object.fromEntries([[
|
|
229
|
+
Util_ShellConfig$ReventlessAws.fields(computed, undefined, undefined, withJourneys([shopper]), undefined, Object.fromEntries([[
|
|
230
230
|
"journeyManifestUrls",
|
|
231
231
|
{}
|
|
232
232
|
]]));
|
|
@@ -248,9 +248,64 @@ globalThis.describe("Util_ShellConfig.fields — journeys", () => {
|
|
|
248
248
|
});
|
|
249
249
|
});
|
|
250
250
|
|
|
251
|
+
globalThis.describe("Util_ShellConfig.fields — environment", () => {
|
|
252
|
+
globalThis.test("the name and the purpose follow the computed keys", () => {
|
|
253
|
+
let out = Util_ShellConfig$ReventlessAws.fields(computed, {
|
|
254
|
+
name: "test",
|
|
255
|
+
purpose: "test"
|
|
256
|
+
}, undefined, undefined, undefined, undefined);
|
|
257
|
+
globalThis.expect(Object.keys(out)).toEqual([
|
|
258
|
+
"apiEndpoint",
|
|
259
|
+
"region",
|
|
260
|
+
"environment",
|
|
261
|
+
"environmentPurpose"
|
|
262
|
+
]);
|
|
263
|
+
globalThis.expect([
|
|
264
|
+
get(out, "environment"),
|
|
265
|
+
get(out, "environmentPurpose")
|
|
266
|
+
]).toEqual([
|
|
267
|
+
"test",
|
|
268
|
+
"test"
|
|
269
|
+
]);
|
|
270
|
+
});
|
|
271
|
+
globalThis.test("an unknown purpose leaves its key out", () => {
|
|
272
|
+
let out = Util_ShellConfig$ReventlessAws.fields(computed, {
|
|
273
|
+
name: "alpha",
|
|
274
|
+
purpose: undefined
|
|
275
|
+
}, undefined, undefined, undefined, undefined);
|
|
276
|
+
globalThis.expect(Stdlib_Option.isNone(out["environmentPurpose"])).toBe(true);
|
|
277
|
+
});
|
|
278
|
+
globalThis.test("a shellConfig environment fails the deploy rather than renaming it", () => {
|
|
279
|
+
let failure;
|
|
280
|
+
try {
|
|
281
|
+
Util_ShellConfig$ReventlessAws.fields(computed, {
|
|
282
|
+
name: "prod",
|
|
283
|
+
purpose: "production"
|
|
284
|
+
}, undefined, undefined, undefined, Object.fromEntries([[
|
|
285
|
+
"environment",
|
|
286
|
+
"staging"
|
|
287
|
+
]]));
|
|
288
|
+
failure = undefined;
|
|
289
|
+
} catch (raw_message) {
|
|
290
|
+
let message = Primitive_exceptions.internalToException(raw_message);
|
|
291
|
+
if (message.RE_EXN_ID === "Failure") {
|
|
292
|
+
failure = message._1;
|
|
293
|
+
} else {
|
|
294
|
+
throw message;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
if (failure !== undefined) {
|
|
298
|
+
globalThis.expect(failure.includes("environment")).toBe(true);
|
|
299
|
+
return;
|
|
300
|
+
} else {
|
|
301
|
+
return JestGlobals.fail("a shellConfig key renaming the computed environment must fail the deploy");
|
|
302
|
+
}
|
|
303
|
+
});
|
|
304
|
+
});
|
|
305
|
+
|
|
251
306
|
globalThis.describe("Util_ShellConfig.fields — shellConfig passthrough", () => {
|
|
252
307
|
globalThis.test("shell-owned keys land verbatim, under the computed ones", () => {
|
|
253
|
-
let out = Util_ShellConfig$ReventlessAws.fields(computed, undefined, undefined, undefined, Object.fromEntries([
|
|
308
|
+
let out = Util_ShellConfig$ReventlessAws.fields(computed, undefined, undefined, undefined, undefined, Object.fromEntries([
|
|
254
309
|
[
|
|
255
310
|
"platformName",
|
|
256
311
|
"Online Shop"
|
|
@@ -271,7 +326,7 @@ globalThis.describe("Util_ShellConfig.fields — shellConfig passthrough", () =>
|
|
|
271
326
|
globalThis.test("a key the deploy computes fails the deploy, naming it", () => {
|
|
272
327
|
let failure;
|
|
273
328
|
try {
|
|
274
|
-
Util_ShellConfig$ReventlessAws.fields(computed, undefined, undefined, undefined, Object.fromEntries([[
|
|
329
|
+
Util_ShellConfig$ReventlessAws.fields(computed, undefined, undefined, undefined, undefined, Object.fromEntries([[
|
|
275
330
|
"apiEndpoint",
|
|
276
331
|
"https://wrong.example/graphql"
|
|
277
332
|
]]));
|
|
@@ -345,7 +400,7 @@ globalThis.describe("the subscription endpoint", () => {
|
|
|
345
400
|
globalThis.describe("Util_ShellConfig.fields — adminGroup", () => {
|
|
346
401
|
globalThis.test("is absent while the administrator role keeps its own name", () => {
|
|
347
402
|
Role$Reventless.clearGroups();
|
|
348
|
-
globalThis.expect(Stdlib_Option.isNone(Util_ShellConfig$ReventlessAws.fields(computed, undefined, undefined, undefined, undefined)["adminGroup"])).toBe(true);
|
|
403
|
+
globalThis.expect(Stdlib_Option.isNone(Util_ShellConfig$ReventlessAws.fields(computed, undefined, undefined, undefined, undefined, undefined)["adminGroup"])).toBe(true);
|
|
349
404
|
});
|
|
350
405
|
globalThis.test("carries the group a renamed administrator role maps to", () => {
|
|
351
406
|
Role$Reventless.clearGroups();
|
|
@@ -353,7 +408,7 @@ globalThis.describe("Util_ShellConfig.fields — adminGroup", () => {
|
|
|
353
408
|
Role$Reventless.admin,
|
|
354
409
|
"shop-admins"
|
|
355
410
|
]]);
|
|
356
|
-
let out = Util_ShellConfig$ReventlessAws.fields(computed, undefined, undefined, undefined, undefined);
|
|
411
|
+
let out = Util_ShellConfig$ReventlessAws.fields(computed, undefined, undefined, undefined, undefined, undefined);
|
|
357
412
|
Role$Reventless.clearGroups();
|
|
358
413
|
globalThis.expect(get(out, "adminGroup")).toEqual("shop-admins");
|
|
359
414
|
});
|
|
@@ -28,7 +28,7 @@ describe("Util_StoreLayout.layoutFor", () => {
|
|
|
28
28
|
)
|
|
29
29
|
|
|
30
30
|
// The accepted fail-open: a production stack whose name is not on the list
|
|
31
|
-
// gets the weaker layout silently. Asserted so the
|
|
31
|
+
// gets the weaker layout silently. Asserted so the behavior is a decision on
|
|
32
32
|
// record rather than a surprise, and so the config override is the documented
|
|
33
33
|
// fix rather than a code change.
|
|
34
34
|
testSync("an unlisted production name falls open to the shared layout", () =>
|
|
@@ -23,7 +23,7 @@ export async function invokeAfterFailedStartup() {
|
|
|
23
23
|
process.on("unhandledRejection", onUnhandled);
|
|
24
24
|
process.env.HANDLER_CONFIG = JSON.stringify({
|
|
25
25
|
...baseConfig,
|
|
26
|
-
stateChangeSliceModules: [{ spec: "cold-start-test/missing-spec.mjs",
|
|
26
|
+
stateChangeSliceModules: [{ spec: "cold-start-test/missing-spec.mjs", decision: "cold-start-test/missing-decision.mjs" }],
|
|
27
27
|
});
|
|
28
28
|
try {
|
|
29
29
|
const { handler } = await import(ENTRY);
|
|
@@ -51,12 +51,12 @@ export async function startWithUnresolvedSlice() {
|
|
|
51
51
|
const { buildHandlersForConfig } = await import(ENTRY);
|
|
52
52
|
const loadModule = async (specifier) => {
|
|
53
53
|
if (specifier === "cold-start-test://spec") return await import("./DcbUnresolvedPartitionSlice.res.mjs");
|
|
54
|
-
if (specifier === "cold-start-test://
|
|
54
|
+
if (specifier === "cold-start-test://decision") return {};
|
|
55
55
|
throw new Error("unknown test specifier: " + specifier);
|
|
56
56
|
};
|
|
57
57
|
try {
|
|
58
58
|
await buildHandlersForConfig(
|
|
59
|
-
{ ...baseConfig, stateChangeSliceModules: [{ spec: "cold-start-test://spec",
|
|
59
|
+
{ ...baseConfig, stateChangeSliceModules: [{ spec: "cold-start-test://spec", decision: "cold-start-test://decision" }] },
|
|
60
60
|
{ loadModule },
|
|
61
61
|
);
|
|
62
62
|
return "started";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
//
|
|
1
|
+
// Decision pair for `AggTestAggregate`. Create-once / reject-on-seen.
|
|
2
2
|
|
|
3
3
|
type state = NotCreated | Active
|
|
4
4
|
|
|
@@ -15,4 +15,4 @@ let decide = (state, command: AggTestAggregate.command): result<
|
|
|
15
15
|
| (NotCreated, Add({name})) => Ok([Added({name: name})])
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
let moduleUrl = "agg-test://
|
|
18
|
+
let moduleUrl = "agg-test://AggTestAggregateDecision"
|