@reventlessdev/reventless-seed-aws 1.0.0-alpha.28 → 1.0.0-alpha.29
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 +7 -0
- package/lib/bs/.compiler.log +2 -2
- package/lib/bs/compiler-info.json +1 -1
- package/lib/bs/src/ReventlessSeedAws.ast +0 -0
- package/lib/bs/src/ReventlessSeedAws.cmi +0 -0
- package/lib/bs/src/ReventlessSeedAws.cmj +0 -0
- package/lib/bs/src/ReventlessSeedAws.cmt +0 -0
- package/lib/bs/src/ReventlessSeedAws.res +111 -59
- package/lib/bs/src/ReventlessSeedAws.res.mjs +23 -1
- package/lib/bs/src/ReventlessSeedAws_Quiesce.ast +0 -0
- package/lib/bs/src/ReventlessSeedAws_Quiesce.cmi +0 -0
- package/lib/bs/src/ReventlessSeedAws_Quiesce.cmt +0 -0
- package/lib/bs/src/ReventlessSeedAws_Quiesce.res +11 -9
- package/lib/bs/src/ReventlessSeedAws_Reconcile.ast +0 -0
- package/lib/bs/src/ReventlessSeedAws_Reconcile.cmi +0 -0
- package/lib/bs/src/ReventlessSeedAws_Reconcile.cmt +0 -0
- package/lib/bs/src/ReventlessSeedAws_Reconcile.res +26 -20
- package/lib/bs/src/ReventlessSeedAws_Reset.ast +0 -0
- package/lib/bs/src/ReventlessSeedAws_Reset.cmi +0 -0
- package/lib/bs/src/ReventlessSeedAws_Reset.cmt +0 -0
- package/lib/bs/src/ReventlessSeedAws_Reset.res +51 -46
- package/lib/bs/tests/EndpointResolutionTest.cmi +0 -0
- package/lib/bs/tests/EndpointResolutionTest.cmt +0 -0
- package/lib/bs/tests/ObjectStoreReconcileTest.ast +0 -0
- package/lib/bs/tests/ObjectStoreReconcileTest.cmi +0 -0
- package/lib/bs/tests/ObjectStoreReconcileTest.cmt +0 -0
- package/lib/bs/tests/ObjectStoreReconcileTest.res +4 -5
- package/lib/bs/tests/ObjectStoreResetTest.ast +0 -0
- package/lib/bs/tests/ObjectStoreResetTest.cmi +0 -0
- package/lib/bs/tests/ObjectStoreResetTest.cmt +0 -0
- package/lib/bs/tests/ObjectStoreResetTest.res +27 -6
- package/lib/bs/tests/QuiesceResetTest.ast +0 -0
- package/lib/bs/tests/QuiesceResetTest.cmi +0 -0
- package/lib/bs/tests/QuiesceResetTest.cmt +0 -0
- package/lib/bs/tests/QuiesceResetTest.res +34 -22
- package/lib/ocaml/.compiler.log +2 -2
- package/lib/ocaml/EndpointResolutionTest.cmi +0 -0
- package/lib/ocaml/EndpointResolutionTest.cmt +0 -0
- package/lib/ocaml/ObjectStoreReconcileTest.ast +0 -0
- package/lib/ocaml/ObjectStoreReconcileTest.cmi +0 -0
- package/lib/ocaml/ObjectStoreReconcileTest.cmt +0 -0
- package/lib/ocaml/ObjectStoreReconcileTest.res +4 -5
- package/lib/ocaml/ObjectStoreResetTest.ast +0 -0
- package/lib/ocaml/ObjectStoreResetTest.cmi +0 -0
- package/lib/ocaml/ObjectStoreResetTest.cmt +0 -0
- package/lib/ocaml/ObjectStoreResetTest.res +27 -6
- package/lib/ocaml/QuiesceResetTest.ast +0 -0
- package/lib/ocaml/QuiesceResetTest.cmi +0 -0
- package/lib/ocaml/QuiesceResetTest.cmt +0 -0
- package/lib/ocaml/QuiesceResetTest.res +34 -22
- package/lib/ocaml/ReventlessSeedAws.ast +0 -0
- package/lib/ocaml/ReventlessSeedAws.cmi +0 -0
- package/lib/ocaml/ReventlessSeedAws.cmj +0 -0
- package/lib/ocaml/ReventlessSeedAws.cmt +0 -0
- package/lib/ocaml/ReventlessSeedAws.res +111 -59
- package/lib/ocaml/ReventlessSeedAws_Quiesce.ast +0 -0
- package/lib/ocaml/ReventlessSeedAws_Quiesce.cmi +0 -0
- package/lib/ocaml/ReventlessSeedAws_Quiesce.cmt +0 -0
- package/lib/ocaml/ReventlessSeedAws_Quiesce.res +11 -9
- package/lib/ocaml/ReventlessSeedAws_Reconcile.ast +0 -0
- package/lib/ocaml/ReventlessSeedAws_Reconcile.cmi +0 -0
- package/lib/ocaml/ReventlessSeedAws_Reconcile.cmt +0 -0
- package/lib/ocaml/ReventlessSeedAws_Reconcile.res +26 -20
- package/lib/ocaml/ReventlessSeedAws_Reset.ast +0 -0
- package/lib/ocaml/ReventlessSeedAws_Reset.cmi +0 -0
- package/lib/ocaml/ReventlessSeedAws_Reset.cmt +0 -0
- package/lib/ocaml/ReventlessSeedAws_Reset.res +51 -46
- package/package.json +4 -4
- package/src/ReventlessSeedAws.res +111 -59
- package/src/ReventlessSeedAws.res.mjs +23 -1
- package/src/ReventlessSeedAws_Quiesce.res +11 -9
- package/src/ReventlessSeedAws_Reconcile.res +26 -20
- package/src/ReventlessSeedAws_Reset.res +51 -46
- package/tests/ObjectStoreReconcileTest.res +4 -5
- package/tests/ObjectStoreResetTest.res +27 -6
- package/tests/QuiesceResetTest.res +34 -22
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,13 @@
|
|
|
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
|
+
# 1.0.0-alpha.29 (2026-09-09)
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
* **seed:** choose the role a run acts as, instead of inheriting a stored one ([edf41ca](https://github.com/ReventlessDev/reventless-core/commit/edf41ca80f84bf340679f200ebfeeeb4a590ae03))
|
|
11
|
+
|
|
12
|
+
|
|
6
13
|
# 1.0.0-alpha.28 (2026-09-08)
|
|
7
14
|
|
|
8
15
|
**Note:** Version bump only for package @reventlessdev/reventless-seed-aws
|
package/lib/bs/.compiler.log
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
#Start(
|
|
2
|
-
#Done(
|
|
1
|
+
#Start(1788992686668)
|
|
2
|
+
#Done(1788992686721)
|
|
@@ -4,5 +4,5 @@
|
|
|
4
4
|
"bsc_hash": "75e3a59c95cc953608fd3dd6ea6ed68141bba4414a20a52f114261b8a48385fa",
|
|
5
5
|
"rescript_config_hash": "c18a0067c363fd1290f6e7f6fe6212d2e16e201c1702fac667962047f88ed468",
|
|
6
6
|
"runtime_path": "/home/runner/work/reventless-core/reventless-core/node_modules/@rescript/runtime",
|
|
7
|
-
"generated_at": "
|
|
7
|
+
"generated_at": "1788992686726"
|
|
8
8
|
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -14,7 +14,6 @@ open ReventlessSeed
|
|
|
14
14
|
|
|
15
15
|
// ── Node bindings ─────────────────────────────────────────────────────────────
|
|
16
16
|
|
|
17
|
-
|
|
18
17
|
type fetchInit = {method: string, headers: dict<string>, body?: string}
|
|
19
18
|
type response
|
|
20
19
|
@val external fetch: (string, fetchInit) => promise<response> = "fetch"
|
|
@@ -77,12 +76,15 @@ let deployedStacks = (~projectDir: string, ~backend: option<string>): array<stri
|
|
|
77
76
|
}
|
|
78
77
|
|
|
79
78
|
let stackOutputs = (~projectDir: string, ~backend: option<string>, stack: string): JSON.t => {
|
|
80
|
-
let raw = try pulumi(
|
|
79
|
+
let raw = try pulumi(
|
|
80
|
+
~projectDir,
|
|
81
|
+
~backend,
|
|
82
|
+
["stack", "output", "--stack", stack, "--json"],
|
|
83
|
+
) catch {
|
|
81
84
|
| _ =>
|
|
82
85
|
throw(
|
|
83
86
|
Seed.Failed(
|
|
84
|
-
`pulumi stack output --stack ${stack} failed — is pulumi installed, logged in, ` ++
|
|
85
|
-
"and the stack deployed?",
|
|
87
|
+
`pulumi stack output --stack ${stack} failed — is pulumi installed, logged in, ` ++ "and the stack deployed?",
|
|
86
88
|
),
|
|
87
89
|
)
|
|
88
90
|
}
|
|
@@ -97,7 +99,11 @@ let backendNote = (~backend: option<string>): string =>
|
|
|
97
99
|
| None => ""
|
|
98
100
|
}
|
|
99
101
|
|
|
100
|
-
let resolveStack = async (
|
|
102
|
+
let resolveStack = async (
|
|
103
|
+
~projectDir: string,
|
|
104
|
+
~backend: option<string>,
|
|
105
|
+
~stack: option<string>,
|
|
106
|
+
): string =>
|
|
101
107
|
switch stack {
|
|
102
108
|
| Some(s) => s
|
|
103
109
|
| None =>
|
|
@@ -111,8 +117,7 @@ let resolveStack = async (~projectDir: string, ~backend: option<string>, ~stack:
|
|
|
111
117
|
`no deployed Pulumi stacks for this project (\`pulumi stack ls\` is empty in ${projectDir})${backendNote(
|
|
112
118
|
~backend,
|
|
113
119
|
)}. ` ++
|
|
114
|
-
"A Pulumi.<stack>.yaml config file alone is not a deployed stack — run `pulumi up` " ++
|
|
115
|
-
"first, log in to the backend that holds the stack, or set SEED_STACK to target one.",
|
|
120
|
+
"A Pulumi.<stack>.yaml config file alone is not a deployed stack — run `pulumi up` " ++ "first, log in to the backend that holds the stack, or set SEED_STACK to target one.",
|
|
116
121
|
),
|
|
117
122
|
)
|
|
118
123
|
}
|
|
@@ -123,13 +128,13 @@ let resolveStack = async (~projectDir: string, ~backend: option<string>, ~stack:
|
|
|
123
128
|
// ── Endpoints ─────────────────────────────────────────────────────────────────
|
|
124
129
|
|
|
125
130
|
let fetchConfig = async (hostShellUrl: string): JSON.t => {
|
|
126
|
-
let base = hostShellUrl->String.replaceRegExp(
|
|
131
|
+
let base = hostShellUrl->String.replaceRegExp(/\/+$/g, "")
|
|
127
132
|
let url = `${base}/config.json`
|
|
128
133
|
let res = try await fetch(url, {method: "GET", headers: Dict.make()}) catch {
|
|
129
134
|
| _ => throw(Seed.Failed(`cannot reach ${url}`))
|
|
130
135
|
}
|
|
131
136
|
if !(res->responseOk) {
|
|
132
|
-
throw(Seed.Failed(`GET ${url} → HTTP ${
|
|
137
|
+
throw(Seed.Failed(`GET ${url} → HTTP ${res->responseStatus->Int.toString}`))
|
|
133
138
|
}
|
|
134
139
|
await res->responseJson
|
|
135
140
|
}
|
|
@@ -232,64 +237,110 @@ let resolveEndpoints = async (
|
|
|
232
237
|
|
|
233
238
|
// ── Cognito login ─────────────────────────────────────────────────────────────
|
|
234
239
|
|
|
235
|
-
let cognito = (~region: string, ~clientId: string) =>
|
|
236
|
-
~username: string,
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
]),
|
|
240
|
+
let cognito = (~region: string, ~clientId: string) =>
|
|
241
|
+
async (~username: string, ~password: string): string => {
|
|
242
|
+
let body = JSON.stringify(
|
|
243
|
+
JSON.Encode.object(
|
|
244
|
+
Dict.fromArray([
|
|
245
|
+
("AuthFlow", JSON.Encode.string("USER_PASSWORD_AUTH")),
|
|
246
|
+
("ClientId", JSON.Encode.string(clientId)),
|
|
247
|
+
(
|
|
248
|
+
"AuthParameters",
|
|
249
|
+
JSON.Encode.object(
|
|
250
|
+
Dict.fromArray([
|
|
251
|
+
("USERNAME", JSON.Encode.string(username)),
|
|
252
|
+
("PASSWORD", JSON.Encode.string(password)),
|
|
253
|
+
]),
|
|
254
|
+
),
|
|
251
255
|
),
|
|
252
|
-
),
|
|
253
|
-
]),
|
|
254
|
-
),
|
|
255
|
-
)
|
|
256
|
-
let headers = Dict.fromArray([
|
|
257
|
-
("content-type", "application/x-amz-json-1.1"),
|
|
258
|
-
("x-amz-target", "AWSCognitoIdentityProviderService.InitiateAuth"),
|
|
259
|
-
])
|
|
260
|
-
let res = try await fetch(`https://cognito-idp.${region}.amazonaws.com/`, {
|
|
261
|
-
method: "POST",
|
|
262
|
-
headers,
|
|
263
|
-
body,
|
|
264
|
-
}) catch {
|
|
265
|
-
| _ => throw(Seed.Failed(`cannot reach Cognito in ${region}`))
|
|
266
|
-
}
|
|
267
|
-
let json = await res->responseJson
|
|
268
|
-
if !(res->responseOk) {
|
|
269
|
-
let detail =
|
|
270
|
-
json->field("message")->Option.flatMap(asString)->Option.getOr(JSON.stringify(json))
|
|
271
|
-
throw(
|
|
272
|
-
Seed.Failed(
|
|
273
|
-
`Cognito InitiateAuth failed (HTTP ${(res->responseStatus)->Int.toString}): ${detail}`,
|
|
256
|
+
]),
|
|
274
257
|
),
|
|
275
258
|
)
|
|
259
|
+
let headers = Dict.fromArray([
|
|
260
|
+
("content-type", "application/x-amz-json-1.1"),
|
|
261
|
+
("x-amz-target", "AWSCognitoIdentityProviderService.InitiateAuth"),
|
|
262
|
+
])
|
|
263
|
+
let res = try await fetch(
|
|
264
|
+
`https://cognito-idp.${region}.amazonaws.com/`,
|
|
265
|
+
{
|
|
266
|
+
method: "POST",
|
|
267
|
+
headers,
|
|
268
|
+
body,
|
|
269
|
+
},
|
|
270
|
+
) catch {
|
|
271
|
+
| _ => throw(Seed.Failed(`cannot reach Cognito in ${region}`))
|
|
272
|
+
}
|
|
273
|
+
let json = await res->responseJson
|
|
274
|
+
if !(res->responseOk) {
|
|
275
|
+
let detail =
|
|
276
|
+
json->field("message")->Option.flatMap(asString)->Option.getOr(JSON.stringify(json))
|
|
277
|
+
throw(
|
|
278
|
+
Seed.Failed(
|
|
279
|
+
`Cognito InitiateAuth failed (HTTP ${res->responseStatus->Int.toString}): ${detail}`,
|
|
280
|
+
),
|
|
281
|
+
)
|
|
282
|
+
}
|
|
283
|
+
switch json->field("ChallengeName")->Option.flatMap(asString) {
|
|
284
|
+
| Some(challenge) =>
|
|
285
|
+
throw(
|
|
286
|
+
Seed.Failed(
|
|
287
|
+
`Cognito returned challenge ${challenge} — set a permanent password first ` ++ "(aws cognito-idp admin-set-user-password … --permanent).",
|
|
288
|
+
),
|
|
289
|
+
)
|
|
290
|
+
| None => ()
|
|
291
|
+
}
|
|
292
|
+
switch json
|
|
293
|
+
->field("AuthenticationResult")
|
|
294
|
+
->Option.flatMap(ar => ar->field("IdToken"))
|
|
295
|
+
->Option.flatMap(asString) {
|
|
296
|
+
| Some(token) => token
|
|
297
|
+
| None => throw(Seed.Failed(`Cognito response carried no IdToken: ${JSON.stringify(json)}`))
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// ── Active role ───────────────────────────────────────────────────────────────
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* The Cognito path's active-role door: `Platform_SetActiveRole` on the domain
|
|
305
|
+
* API, which is where the seed already sends everything else.
|
|
306
|
+
*
|
|
307
|
+
* It sits on the domain base document at `AllowAuthenticated`, deliberately not
|
|
308
|
+
* behind the Admin gate — the whole point is that a caller can drop into a
|
|
309
|
+
* narrower role — so a token already narrowed to `Shopper` can still call this
|
|
310
|
+
* to widen back out. There is no chicken-and-egg, and no `sub` argument: the
|
|
311
|
+
* mutation addresses the authorizer-verified caller's own row and nobody else's.
|
|
312
|
+
*
|
|
313
|
+
* Returns `None` always: the choice is a stored row, read by the pool's
|
|
314
|
+
* pre-token-generation trigger on the NEXT login, so the current bearer is
|
|
315
|
+
* unchanged by it and the caller must re-authenticate to see any effect.
|
|
316
|
+
*
|
|
317
|
+
* Split-API only. A unified-mode deployment's single API does not carry the
|
|
318
|
+
* field, so a refusal naming it is reported as "this deployment offers no role
|
|
319
|
+
* switch" rather than as a seeding failure.
|
|
320
|
+
*/
|
|
321
|
+
let setActiveRole: Seed.Connect.roleSwitch = async (~client, ~role) => {
|
|
322
|
+
let argument = switch role {
|
|
323
|
+
| None => "null"
|
|
324
|
+
| Some(r) => JSON.stringify(JSON.Encode.string(r))
|
|
276
325
|
}
|
|
277
|
-
|
|
278
|
-
|
|
326
|
+
try {
|
|
327
|
+
let _ = await Seed.Client.gql(
|
|
328
|
+
client,
|
|
329
|
+
~query=`mutation { Platform_SetActiveRole(activeRole: ${argument}) { activeRole availableRoles } }`,
|
|
330
|
+
~label="Platform_SetActiveRole",
|
|
331
|
+
)
|
|
332
|
+
None
|
|
333
|
+
} catch {
|
|
334
|
+
| Seed.Failed(message) =>
|
|
279
335
|
throw(
|
|
280
336
|
Seed.Failed(
|
|
281
|
-
|
|
282
|
-
|
|
337
|
+
message->String.includes("Platform_SetActiveRole")
|
|
338
|
+
? `this deployment offers no role switch — \`Platform_SetActiveRole\` is a split-API ` ++
|
|
339
|
+
`field, and a unified-mode API does not carry it. Change the role in the host shell ` ++
|
|
340
|
+
`instead.\n ${message}`
|
|
341
|
+
: message,
|
|
283
342
|
),
|
|
284
343
|
)
|
|
285
|
-
| None => ()
|
|
286
|
-
}
|
|
287
|
-
switch json
|
|
288
|
-
->field("AuthenticationResult")
|
|
289
|
-
->Option.flatMap(ar => ar->field("IdToken"))
|
|
290
|
-
->Option.flatMap(asString) {
|
|
291
|
-
| Some(token) => token
|
|
292
|
-
| None => throw(Seed.Failed(`Cognito response carried no IdToken: ${JSON.stringify(json)}`))
|
|
293
344
|
}
|
|
294
345
|
}
|
|
295
346
|
|
|
@@ -324,5 +375,6 @@ let connect = (~projectDir: string=".", ~stack=?, ~backend=?, ()): (
|
|
|
324
375
|
~label=stackName,
|
|
325
376
|
~endpoint=eps.graphql,
|
|
326
377
|
~login=cognito(~region=eps.cognitoRegion, ~clientId=eps.cognitoClientId),
|
|
378
|
+
~roleSwitch=setActiveRole,
|
|
327
379
|
)
|
|
328
380
|
}
|
|
@@ -4,6 +4,8 @@ import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
|
|
|
4
4
|
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
5
5
|
import * as Nodechild_process from "node:child_process";
|
|
6
6
|
import * as Seed$ReventlessSeed from "@reventlessdev/reventless-seed/src/Seed.res.mjs";
|
|
7
|
+
import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
|
|
8
|
+
import * as Seed_Client$ReventlessSeed from "@reventlessdev/reventless-seed/src/Seed_Client.res.mjs";
|
|
7
9
|
import * as Seed_Prompt$ReventlessSeed from "@reventlessdev/reventless-seed/src/Seed_Prompt.res.mjs";
|
|
8
10
|
import * as Seed_Connect$ReventlessSeed from "@reventlessdev/reventless-seed/src/Seed_Connect.res.mjs";
|
|
9
11
|
|
|
@@ -279,6 +281,25 @@ function cognito(region, clientId) {
|
|
|
279
281
|
};
|
|
280
282
|
}
|
|
281
283
|
|
|
284
|
+
async function setActiveRole(client, role) {
|
|
285
|
+
let argument = role !== undefined ? JSON.stringify(role) : "null";
|
|
286
|
+
try {
|
|
287
|
+
await Seed_Client$ReventlessSeed.gql(client, `mutation { Platform_SetActiveRole(activeRole: ` + argument + `) { activeRole availableRoles } }`, "Platform_SetActiveRole");
|
|
288
|
+
return;
|
|
289
|
+
} catch (raw_message) {
|
|
290
|
+
let message = Primitive_exceptions.internalToException(raw_message);
|
|
291
|
+
if (message.RE_EXN_ID === Seed$ReventlessSeed.Failed) {
|
|
292
|
+
let message$1 = message._1;
|
|
293
|
+
throw {
|
|
294
|
+
RE_EXN_ID: Seed$ReventlessSeed.Failed,
|
|
295
|
+
_1: message$1.includes("Platform_SetActiveRole") ? `this deployment offers no role switch — \`Platform_SetActiveRole\` is a split-API field, and a unified-mode API does not carry it. Change the role in the host shell instead.\n ` + message$1 : message$1,
|
|
296
|
+
Error: new Error()
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
throw message;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
282
303
|
function connect($staropt$star, stack, backend, param) {
|
|
283
304
|
return async () => {
|
|
284
305
|
let projectDir = $staropt$star !== undefined ? $staropt$star : ".";
|
|
@@ -286,7 +307,7 @@ function connect($staropt$star, stack, backend, param) {
|
|
|
286
307
|
let backend$1 = url !== undefined ? url : backend;
|
|
287
308
|
let stackName = await resolveStack(projectDir, backend$1, stack);
|
|
288
309
|
let eps = await resolveEndpoints(projectDir, backend$1, stackName);
|
|
289
|
-
return await Seed_Connect$ReventlessSeed.make(stackName, eps.graphql, cognito(eps.cognitoRegion, eps.cognitoClientId), undefined);
|
|
310
|
+
return await Seed_Connect$ReventlessSeed.make(stackName, eps.graphql, cognito(eps.cognitoRegion, eps.cognitoClientId), setActiveRole, undefined);
|
|
290
311
|
};
|
|
291
312
|
}
|
|
292
313
|
|
|
@@ -304,6 +325,7 @@ export {
|
|
|
304
325
|
endpointsFrom,
|
|
305
326
|
resolveEndpoints,
|
|
306
327
|
cognito,
|
|
328
|
+
setActiveRole,
|
|
307
329
|
connect,
|
|
308
330
|
}
|
|
309
331
|
/* node:child_process Not a pure module */
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -153,8 +153,9 @@ let restoreConcurrency = async (~client, ~h: held): option<string> =>
|
|
|
153
153
|
| () => None
|
|
154
154
|
| exception exn =>
|
|
155
155
|
Some(
|
|
156
|
-
`LEFT SWITCHED OFF: could not restore concurrency on ${h.functionName} (${errorText(
|
|
157
|
-
|
|
156
|
+
`LEFT SWITCHED OFF: could not restore concurrency on ${h.functionName} (${errorText(
|
|
157
|
+
exn,
|
|
158
|
+
)}). ` ++ `It is still reserved at 0 and will not run until that is undone.`,
|
|
158
159
|
)
|
|
159
160
|
}
|
|
160
161
|
|
|
@@ -181,7 +182,9 @@ let release = async (~client, ~held: array<held>): array<string> => {
|
|
|
181
182
|
| () => None
|
|
182
183
|
| exception exn =>
|
|
183
184
|
Some(
|
|
184
|
-
`could not restore the environment of ${h.functionName} (${errorText(
|
|
185
|
+
`could not restore the environment of ${h.functionName} (${errorText(
|
|
186
|
+
exn,
|
|
187
|
+
)}) — it may still ` ++
|
|
185
188
|
`carry ${markerKey}, which is inert and is removed by the next deploy.`,
|
|
186
189
|
)
|
|
187
190
|
}
|
|
@@ -207,8 +210,9 @@ let recycle = async (~client, ~held: array<held>): array<string> => {
|
|
|
207
210
|
| () => None
|
|
208
211
|
| exception exn =>
|
|
209
212
|
Some(
|
|
210
|
-
`could not recycle ${h.functionName} (${errorText(
|
|
211
|
-
|
|
213
|
+
`could not recycle ${h.functionName} (${errorText(
|
|
214
|
+
exn,
|
|
215
|
+
)}) — a warm container may still hold ` ++ `pre-wipe state and write it back. Redeploy or update that function to clear it.`,
|
|
212
216
|
)
|
|
213
217
|
}
|
|
214
218
|
})
|
|
@@ -283,12 +287,10 @@ let hold = async (~client, ~functionNames: array<string>): array<held> => {
|
|
|
283
287
|
let advice = if reason->isThrottle {
|
|
284
288
|
`The Lambda control plane throttled the hold. That budget is per account and region and is ` ++
|
|
285
289
|
`shared with anything else using it — a deploy, an inspector sync, another stack in the same ` ++
|
|
286
|
-
`region — so this is transient and nothing is wrong with the credentials. Wait for whatever ` ++
|
|
287
|
-
`else is running to finish and re-run.`
|
|
290
|
+
`region — so this is transient and nothing is wrong with the credentials. Wait for whatever ` ++ `else is running to finish and re-run.`
|
|
288
291
|
} else {
|
|
289
292
|
`The reset holds every runtime in scope for the length of the wipe, which needs ` ++
|
|
290
|
-
`lambda:GetFunctionConcurrency, lambda:GetFunctionConfiguration, lambda:PutFunctionConcurrency, ` ++
|
|
291
|
-
`lambda:DeleteFunctionConcurrency and lambda:UpdateFunctionConfiguration.`
|
|
293
|
+
`lambda:GetFunctionConcurrency, lambda:GetFunctionConfiguration, lambda:PutFunctionConcurrency, ` ++ `lambda:DeleteFunctionConcurrency and lambda:UpdateFunctionConfiguration.`
|
|
292
294
|
}
|
|
293
295
|
throw(
|
|
294
296
|
ReventlessSeed.Seed.Failed(
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -123,7 +123,7 @@ let listObjects = async (~bucket: string, ~prefix: string): array<object> => {
|
|
|
123
123
|
S3.ListObjectVersionsCommand.make({
|
|
124
124
|
bucket,
|
|
125
125
|
prefix: `${prefix}/`,
|
|
126
|
-
|
|
126
|
+
?keyMarker,
|
|
127
127
|
versionIdMarker: ?versionMarker,
|
|
128
128
|
}),
|
|
129
129
|
)
|
|
@@ -153,8 +153,7 @@ let listObjects = async (~bucket: string, ~prefix: string): array<object> => {
|
|
|
153
153
|
let tagging = await S3.GetObjectTaggingCommand.send(
|
|
154
154
|
S3.GetObjectTaggingCommand.make({bucket, key}),
|
|
155
155
|
)
|
|
156
|
-
let pending =
|
|
157
|
-
tagging.tagSet->Option.getOr([])->Array.some(t => t.key == pendingTagKey)
|
|
156
|
+
let pending = tagging.tagSet->Option.getOr([])->Array.some(t => t.key == pendingTagKey)
|
|
158
157
|
objects->Array.push({key, ref: `/${key}`, pending})
|
|
159
158
|
})
|
|
160
159
|
)
|
|
@@ -224,10 +223,17 @@ let print = (r: report): bool => {
|
|
|
224
223
|
Console.log("")
|
|
225
224
|
Console.log(` ${r.store} ${r.bucket}/${r.prefix}/`)
|
|
226
225
|
Console.log(` event rows scanned: ${r.eventRows->Int.toString}`)
|
|
227
|
-
let line = (label, n) =>
|
|
226
|
+
let line = (label, n) =>
|
|
227
|
+
Console.log(` ${n->Int.toString->String.padStart(8, " ")} ${label}`)
|
|
228
228
|
line("referenced, still tagged pending ← must be 0", r.referencedButPending->Array.length)
|
|
229
|
-
line(
|
|
230
|
-
|
|
229
|
+
line(
|
|
230
|
+
"unreferenced, tagged pending ← what expiry would delete",
|
|
231
|
+
r.unreferencedPending->Array.length,
|
|
232
|
+
)
|
|
233
|
+
line(
|
|
234
|
+
"unreferenced, untagged ← outside the rule",
|
|
235
|
+
r.unreferencedUntagged->Array.length,
|
|
236
|
+
)
|
|
231
237
|
line("referenced but missing ← dangling refs", r.danglingRefs->Array.length)
|
|
232
238
|
|
|
233
239
|
// Every object untagged reads as "the claimer has caught up with everything",
|
|
@@ -238,13 +244,16 @@ let print = (r: report): bool => {
|
|
|
238
244
|
r.referencedButPending->Array.length +
|
|
239
245
|
r.unreferencedPending->Array.length +
|
|
240
246
|
r.unreferencedUntagged->Array.length
|
|
241
|
-
if
|
|
247
|
+
if (
|
|
248
|
+
objectCount > 0 &&
|
|
249
|
+
r.referencedButPending->Array.length == 0 &&
|
|
250
|
+
r.unreferencedPending->Array.length == 0
|
|
251
|
+
) {
|
|
242
252
|
Console.log("")
|
|
243
253
|
Console.log(
|
|
244
254
|
` Note: none of the ${objectCount->Int.toString} objects carry "${pendingTagKey}". That is ` ++
|
|
245
255
|
"what a fully-claimed store looks like — and also what it looks like if the mint side " ++
|
|
246
|
-
"never wrote the tag (a store whose objects all predate it) or if this tool's tag key has " ++
|
|
247
|
-
"drifted from the deploy's.",
|
|
256
|
+
"never wrote the tag (a store whose objects all predate it) or if this tool's tag key has " ++ "drifted from the deploy's.",
|
|
248
257
|
)
|
|
249
258
|
}
|
|
250
259
|
|
|
@@ -258,8 +267,7 @@ let print = (r: report): bool => {
|
|
|
258
267
|
Console.log("")
|
|
259
268
|
Console.log(
|
|
260
269
|
" Do NOT enable this store's expiry rule. Either the claim component is behind or " ++
|
|
261
|
-
"stopped (check its IteratorAge alarm), or a field holding these refs is missing its " ++
|
|
262
|
-
"`@storageRef` annotation — in which case the claimer never sees it and never will.",
|
|
270
|
+
"stopped (check its IteratorAge alarm), or a field holding these refs is missing its " ++ "`@storageRef` annotation — in which case the claimer never sees it and never will.",
|
|
263
271
|
)
|
|
264
272
|
}
|
|
265
273
|
r.referencedButPending->Array.length == 0
|
|
@@ -293,8 +301,7 @@ let run = (~stack=?, ~backend=?, ~targets: array<ReventlessSeedAws_Reset.target>
|
|
|
293
301
|
| None =>
|
|
294
302
|
throw(
|
|
295
303
|
Seed.Failed(
|
|
296
|
-
"no `platform` target is declared — declared object stores live in the platform " ++
|
|
297
|
-
"project's stack output and cannot be resolved without it.",
|
|
304
|
+
"no `platform` target is declared — declared object stores live in the platform " ++ "project's stack output and cannot be resolved without it.",
|
|
298
305
|
),
|
|
299
306
|
)
|
|
300
307
|
}
|
|
@@ -320,8 +327,7 @@ let run = (~stack=?, ~backend=?, ~targets: array<ReventlessSeedAws_Reset.target>
|
|
|
320
327
|
} else {
|
|
321
328
|
let region = switch Seed.Prompt.envValue("AWS_REGION") {
|
|
322
329
|
| Some(r) if r != "" => r
|
|
323
|
-
| _ =>
|
|
324
|
-
throw(Seed.Failed("could not resolve the AWS region — set AWS_REGION."))
|
|
330
|
+
| _ => throw(Seed.Failed("could not resolve the AWS region — set AWS_REGION."))
|
|
325
331
|
}
|
|
326
332
|
Seed.Runner.heading(`Reconcile: stack "${stack}" in ${region}`)
|
|
327
333
|
|
|
@@ -356,14 +362,12 @@ let run = (~stack=?, ~backend=?, ~targets: array<ReventlessSeedAws_Reset.target>
|
|
|
356
362
|
if allClear.contents {
|
|
357
363
|
Console.log(
|
|
358
364
|
"Every referenced object has been claimed. Enabling a store's expiry rule " ++
|
|
359
|
-
"(`pendingUploadExpiryDays: \"<plugin>.<store>=<days>\"`) would delete only " ++
|
|
360
|
-
"objects nothing references.",
|
|
365
|
+
"(`pendingUploadExpiryDays: \"<plugin>.<store>=<days>\"`) would delete only " ++ "objects nothing references.",
|
|
361
366
|
)
|
|
362
367
|
} else {
|
|
363
368
|
throw(
|
|
364
369
|
Seed.Failed(
|
|
365
|
-
"at least one referenced object is still tagged pending — see above. No store's " ++
|
|
366
|
-
"expiry rule should be enabled while this is true.",
|
|
370
|
+
"at least one referenced object is still tagged pending — see above. No store's " ++ "expiry rule should be enabled while this is true.",
|
|
367
371
|
),
|
|
368
372
|
)
|
|
369
373
|
}
|
|
@@ -377,7 +381,9 @@ let run = (~stack=?, ~backend=?, ~targets: array<ReventlessSeedAws_Reset.target>
|
|
|
377
381
|
| exn =>
|
|
378
382
|
Console.error("")
|
|
379
383
|
Console.error("Reconcile failed with an unexpected error:")
|
|
380
|
-
Console.error(
|
|
384
|
+
Console.error(
|
|
385
|
+
exn->JsExn.fromException->Option.flatMap(JsExn.message)->Option.getOr("unknown"),
|
|
386
|
+
)
|
|
381
387
|
NodeProcess.exit(1)
|
|
382
388
|
}
|
|
383
389
|
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|