@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.
Files changed (76) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/lib/bs/.compiler.log +2 -2
  3. package/lib/bs/compiler-info.json +1 -1
  4. package/lib/bs/src/ReventlessSeedAws.ast +0 -0
  5. package/lib/bs/src/ReventlessSeedAws.cmi +0 -0
  6. package/lib/bs/src/ReventlessSeedAws.cmj +0 -0
  7. package/lib/bs/src/ReventlessSeedAws.cmt +0 -0
  8. package/lib/bs/src/ReventlessSeedAws.res +111 -59
  9. package/lib/bs/src/ReventlessSeedAws.res.mjs +23 -1
  10. package/lib/bs/src/ReventlessSeedAws_Quiesce.ast +0 -0
  11. package/lib/bs/src/ReventlessSeedAws_Quiesce.cmi +0 -0
  12. package/lib/bs/src/ReventlessSeedAws_Quiesce.cmt +0 -0
  13. package/lib/bs/src/ReventlessSeedAws_Quiesce.res +11 -9
  14. package/lib/bs/src/ReventlessSeedAws_Reconcile.ast +0 -0
  15. package/lib/bs/src/ReventlessSeedAws_Reconcile.cmi +0 -0
  16. package/lib/bs/src/ReventlessSeedAws_Reconcile.cmt +0 -0
  17. package/lib/bs/src/ReventlessSeedAws_Reconcile.res +26 -20
  18. package/lib/bs/src/ReventlessSeedAws_Reset.ast +0 -0
  19. package/lib/bs/src/ReventlessSeedAws_Reset.cmi +0 -0
  20. package/lib/bs/src/ReventlessSeedAws_Reset.cmt +0 -0
  21. package/lib/bs/src/ReventlessSeedAws_Reset.res +51 -46
  22. package/lib/bs/tests/EndpointResolutionTest.cmi +0 -0
  23. package/lib/bs/tests/EndpointResolutionTest.cmt +0 -0
  24. package/lib/bs/tests/ObjectStoreReconcileTest.ast +0 -0
  25. package/lib/bs/tests/ObjectStoreReconcileTest.cmi +0 -0
  26. package/lib/bs/tests/ObjectStoreReconcileTest.cmt +0 -0
  27. package/lib/bs/tests/ObjectStoreReconcileTest.res +4 -5
  28. package/lib/bs/tests/ObjectStoreResetTest.ast +0 -0
  29. package/lib/bs/tests/ObjectStoreResetTest.cmi +0 -0
  30. package/lib/bs/tests/ObjectStoreResetTest.cmt +0 -0
  31. package/lib/bs/tests/ObjectStoreResetTest.res +27 -6
  32. package/lib/bs/tests/QuiesceResetTest.ast +0 -0
  33. package/lib/bs/tests/QuiesceResetTest.cmi +0 -0
  34. package/lib/bs/tests/QuiesceResetTest.cmt +0 -0
  35. package/lib/bs/tests/QuiesceResetTest.res +34 -22
  36. package/lib/ocaml/.compiler.log +2 -2
  37. package/lib/ocaml/EndpointResolutionTest.cmi +0 -0
  38. package/lib/ocaml/EndpointResolutionTest.cmt +0 -0
  39. package/lib/ocaml/ObjectStoreReconcileTest.ast +0 -0
  40. package/lib/ocaml/ObjectStoreReconcileTest.cmi +0 -0
  41. package/lib/ocaml/ObjectStoreReconcileTest.cmt +0 -0
  42. package/lib/ocaml/ObjectStoreReconcileTest.res +4 -5
  43. package/lib/ocaml/ObjectStoreResetTest.ast +0 -0
  44. package/lib/ocaml/ObjectStoreResetTest.cmi +0 -0
  45. package/lib/ocaml/ObjectStoreResetTest.cmt +0 -0
  46. package/lib/ocaml/ObjectStoreResetTest.res +27 -6
  47. package/lib/ocaml/QuiesceResetTest.ast +0 -0
  48. package/lib/ocaml/QuiesceResetTest.cmi +0 -0
  49. package/lib/ocaml/QuiesceResetTest.cmt +0 -0
  50. package/lib/ocaml/QuiesceResetTest.res +34 -22
  51. package/lib/ocaml/ReventlessSeedAws.ast +0 -0
  52. package/lib/ocaml/ReventlessSeedAws.cmi +0 -0
  53. package/lib/ocaml/ReventlessSeedAws.cmj +0 -0
  54. package/lib/ocaml/ReventlessSeedAws.cmt +0 -0
  55. package/lib/ocaml/ReventlessSeedAws.res +111 -59
  56. package/lib/ocaml/ReventlessSeedAws_Quiesce.ast +0 -0
  57. package/lib/ocaml/ReventlessSeedAws_Quiesce.cmi +0 -0
  58. package/lib/ocaml/ReventlessSeedAws_Quiesce.cmt +0 -0
  59. package/lib/ocaml/ReventlessSeedAws_Quiesce.res +11 -9
  60. package/lib/ocaml/ReventlessSeedAws_Reconcile.ast +0 -0
  61. package/lib/ocaml/ReventlessSeedAws_Reconcile.cmi +0 -0
  62. package/lib/ocaml/ReventlessSeedAws_Reconcile.cmt +0 -0
  63. package/lib/ocaml/ReventlessSeedAws_Reconcile.res +26 -20
  64. package/lib/ocaml/ReventlessSeedAws_Reset.ast +0 -0
  65. package/lib/ocaml/ReventlessSeedAws_Reset.cmi +0 -0
  66. package/lib/ocaml/ReventlessSeedAws_Reset.cmt +0 -0
  67. package/lib/ocaml/ReventlessSeedAws_Reset.res +51 -46
  68. package/package.json +4 -4
  69. package/src/ReventlessSeedAws.res +111 -59
  70. package/src/ReventlessSeedAws.res.mjs +23 -1
  71. package/src/ReventlessSeedAws_Quiesce.res +11 -9
  72. package/src/ReventlessSeedAws_Reconcile.res +26 -20
  73. package/src/ReventlessSeedAws_Reset.res +51 -46
  74. package/tests/ObjectStoreReconcileTest.res +4 -5
  75. package/tests/ObjectStoreResetTest.res +27 -6
  76. 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
@@ -1,2 +1,2 @@
1
- #Start(1788869322743)
2
- #Done(1788869322782)
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": "1788869322788"
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(~projectDir, ~backend, ["stack", "output", "--stack", stack, "--json"]) catch {
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 (~projectDir: string, ~backend: option<string>, ~stack: option<string>): string =>
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(%re("/\/+$/g"), "")
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 ${(res->responseStatus)->Int.toString}`))
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) => async (
236
- ~username: string,
237
- ~password: string,
238
- ): string => {
239
- let body = JSON.stringify(
240
- JSON.Encode.object(
241
- Dict.fromArray([
242
- ("AuthFlow", JSON.Encode.string("USER_PASSWORD_AUTH")),
243
- ("ClientId", JSON.Encode.string(clientId)),
244
- (
245
- "AuthParameters",
246
- JSON.Encode.object(
247
- Dict.fromArray([
248
- ("USERNAME", JSON.Encode.string(username)),
249
- ("PASSWORD", JSON.Encode.string(password)),
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
- switch json->field("ChallengeName")->Option.flatMap(asString) {
278
- | Some(challenge) =>
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
- `Cognito returned challenge ${challenge} — set a permanent password first ` ++
282
- "(aws cognito-idp admin-set-user-password --permanent).",
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 */
@@ -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(exn)}). ` ++
157
- `It is still reserved at 0 and will not run until that is undone.`,
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(exn)}) — it may still ` ++
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(exn)}) — a warm container may still hold ` ++
211
- `pre-wipe state and write it back. Redeploy or update that function to clear it.`,
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(
@@ -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
- keyMarker: ?keyMarker,
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) => Console.log(` ${n->Int.toString->String.padStart(8, " ")} ${label}`)
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("unreferenced, tagged pending ← what expiry would delete", r.unreferencedPending->Array.length)
230
- line("unreferenced, untagged outside the rule", r.unreferencedUntagged->Array.length)
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 objectCount > 0 && r.referencedButPending->Array.length == 0 && r.unreferencedPending->Array.length == 0 {
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(exn->JsExn.fromException->Option.flatMap(JsExn.message)->Option.getOr("unknown"))
384
+ Console.error(
385
+ exn->JsExn.fromException->Option.flatMap(JsExn.message)->Option.getOr("unknown"),
386
+ )
381
387
  NodeProcess.exit(1)
382
388
  }
383
389
  }