@reventlessdev/reventless-seed-aws 1.0.0-alpha.4 → 1.0.0-alpha.40

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 (111) hide show
  1. package/CHANGELOG.md +279 -0
  2. package/lib/bs/.compiler.log +2 -2
  3. package/lib/bs/.sourcedirs.json +1 -0
  4. package/lib/bs/compiler-info.json +4 -4
  5. package/lib/bs/src/ReventlessSeedAws.ast +0 -0
  6. package/lib/bs/src/ReventlessSeedAws.cmi +0 -0
  7. package/lib/bs/src/ReventlessSeedAws.cmj +0 -0
  8. package/lib/bs/src/ReventlessSeedAws.cmt +0 -0
  9. package/lib/bs/src/ReventlessSeedAws.res +198 -134
  10. package/lib/bs/src/ReventlessSeedAws.res.mjs +59 -33
  11. package/lib/bs/src/ReventlessSeedAws_Quiesce.ast +0 -0
  12. package/lib/bs/src/ReventlessSeedAws_Quiesce.cmi +0 -0
  13. package/lib/bs/src/ReventlessSeedAws_Quiesce.cmj +0 -0
  14. package/lib/bs/src/ReventlessSeedAws_Quiesce.cmt +0 -0
  15. package/lib/bs/src/ReventlessSeedAws_Quiesce.res +307 -0
  16. package/lib/bs/src/ReventlessSeedAws_Quiesce.res.mjs +217 -0
  17. package/lib/bs/src/ReventlessSeedAws_Reconcile.ast +0 -0
  18. package/lib/bs/src/ReventlessSeedAws_Reconcile.cmi +0 -0
  19. package/lib/bs/src/ReventlessSeedAws_Reconcile.cmj +0 -0
  20. package/lib/bs/src/ReventlessSeedAws_Reconcile.cmt +0 -0
  21. package/lib/bs/src/ReventlessSeedAws_Reconcile.res +391 -0
  22. package/lib/bs/src/ReventlessSeedAws_Reconcile.res.mjs +318 -0
  23. package/lib/bs/src/ReventlessSeedAws_Reset.ast +0 -0
  24. package/lib/bs/src/ReventlessSeedAws_Reset.cmi +0 -0
  25. package/lib/bs/src/ReventlessSeedAws_Reset.cmj +0 -0
  26. package/lib/bs/src/ReventlessSeedAws_Reset.cmt +0 -0
  27. package/lib/bs/src/ReventlessSeedAws_Reset.res +497 -94
  28. package/lib/bs/src/ReventlessSeedAws_Reset.res.mjs +385 -69
  29. package/lib/bs/tests/EndpointResolutionTest.ast +0 -0
  30. package/lib/bs/tests/EndpointResolutionTest.cmi +0 -0
  31. package/lib/bs/tests/EndpointResolutionTest.cmj +0 -0
  32. package/lib/bs/tests/EndpointResolutionTest.cmt +0 -0
  33. package/lib/bs/tests/EndpointResolutionTest.res +83 -0
  34. package/lib/bs/tests/EndpointResolutionTest.res.mjs +115 -0
  35. package/lib/bs/tests/ObjectStoreReconcileTest.ast +0 -0
  36. package/lib/bs/tests/ObjectStoreReconcileTest.cmi +0 -0
  37. package/lib/bs/tests/ObjectStoreReconcileTest.cmj +0 -0
  38. package/lib/bs/tests/ObjectStoreReconcileTest.cmt +0 -0
  39. package/lib/bs/tests/ObjectStoreReconcileTest.res +83 -0
  40. package/lib/bs/tests/ObjectStoreReconcileTest.res.mjs +102 -0
  41. package/lib/bs/tests/ObjectStoreResetTest.ast +0 -0
  42. package/lib/bs/tests/ObjectStoreResetTest.cmi +0 -0
  43. package/lib/bs/tests/ObjectStoreResetTest.cmj +0 -0
  44. package/lib/bs/tests/ObjectStoreResetTest.cmt +0 -0
  45. package/lib/bs/tests/ObjectStoreResetTest.res +191 -0
  46. package/lib/bs/tests/ObjectStoreResetTest.res.mjs +211 -0
  47. package/lib/bs/tests/QuiesceResetTest.ast +0 -0
  48. package/lib/bs/tests/QuiesceResetTest.cmi +0 -0
  49. package/lib/bs/tests/QuiesceResetTest.cmj +0 -0
  50. package/lib/bs/tests/QuiesceResetTest.cmt +0 -0
  51. package/lib/bs/tests/QuiesceResetTest.res +169 -0
  52. package/lib/bs/tests/QuiesceResetTest.res.mjs +157 -0
  53. package/lib/ocaml/.compiler.log +2 -2
  54. package/lib/ocaml/EndpointResolutionTest.ast +0 -0
  55. package/lib/ocaml/EndpointResolutionTest.cmi +0 -0
  56. package/lib/ocaml/EndpointResolutionTest.cmj +0 -0
  57. package/lib/ocaml/EndpointResolutionTest.cmt +0 -0
  58. package/lib/ocaml/EndpointResolutionTest.res +83 -0
  59. package/lib/ocaml/ObjectStoreReconcileTest.ast +0 -0
  60. package/lib/ocaml/ObjectStoreReconcileTest.cmi +0 -0
  61. package/lib/ocaml/ObjectStoreReconcileTest.cmj +0 -0
  62. package/lib/ocaml/ObjectStoreReconcileTest.cmt +0 -0
  63. package/lib/ocaml/ObjectStoreReconcileTest.res +83 -0
  64. package/lib/ocaml/ObjectStoreResetTest.ast +0 -0
  65. package/lib/ocaml/ObjectStoreResetTest.cmi +0 -0
  66. package/lib/ocaml/ObjectStoreResetTest.cmj +0 -0
  67. package/lib/ocaml/ObjectStoreResetTest.cmt +0 -0
  68. package/lib/ocaml/ObjectStoreResetTest.res +191 -0
  69. package/lib/ocaml/QuiesceResetTest.ast +0 -0
  70. package/lib/ocaml/QuiesceResetTest.cmi +0 -0
  71. package/lib/ocaml/QuiesceResetTest.cmj +0 -0
  72. package/lib/ocaml/QuiesceResetTest.cmt +0 -0
  73. package/lib/ocaml/QuiesceResetTest.res +169 -0
  74. package/lib/ocaml/ReventlessSeedAws.ast +0 -0
  75. package/lib/ocaml/ReventlessSeedAws.cmi +0 -0
  76. package/lib/ocaml/ReventlessSeedAws.cmj +0 -0
  77. package/lib/ocaml/ReventlessSeedAws.cmt +0 -0
  78. package/lib/ocaml/ReventlessSeedAws.res +198 -134
  79. package/lib/ocaml/ReventlessSeedAws_Quiesce.ast +0 -0
  80. package/lib/ocaml/ReventlessSeedAws_Quiesce.cmi +0 -0
  81. package/lib/ocaml/ReventlessSeedAws_Quiesce.cmj +0 -0
  82. package/lib/ocaml/ReventlessSeedAws_Quiesce.cmt +0 -0
  83. package/lib/ocaml/ReventlessSeedAws_Quiesce.res +307 -0
  84. package/lib/ocaml/ReventlessSeedAws_Reconcile.ast +0 -0
  85. package/lib/ocaml/ReventlessSeedAws_Reconcile.cmi +0 -0
  86. package/lib/ocaml/ReventlessSeedAws_Reconcile.cmj +0 -0
  87. package/lib/ocaml/ReventlessSeedAws_Reconcile.cmt +0 -0
  88. package/lib/ocaml/ReventlessSeedAws_Reconcile.res +391 -0
  89. package/lib/ocaml/ReventlessSeedAws_Reset.ast +0 -0
  90. package/lib/ocaml/ReventlessSeedAws_Reset.cmi +0 -0
  91. package/lib/ocaml/ReventlessSeedAws_Reset.cmj +0 -0
  92. package/lib/ocaml/ReventlessSeedAws_Reset.cmt +0 -0
  93. package/lib/ocaml/ReventlessSeedAws_Reset.res +497 -94
  94. package/package.json +7 -5
  95. package/rescript.json +8 -1
  96. package/src/ReventlessSeedAws.res +198 -134
  97. package/src/ReventlessSeedAws.res.mjs +59 -33
  98. package/src/ReventlessSeedAws_Quiesce.res +307 -0
  99. package/src/ReventlessSeedAws_Quiesce.res.mjs +217 -0
  100. package/src/ReventlessSeedAws_Reconcile.res +391 -0
  101. package/src/ReventlessSeedAws_Reconcile.res.mjs +318 -0
  102. package/src/ReventlessSeedAws_Reset.res +497 -94
  103. package/src/ReventlessSeedAws_Reset.res.mjs +385 -69
  104. package/tests/EndpointResolutionTest.res +83 -0
  105. package/tests/EndpointResolutionTest.res.mjs +115 -0
  106. package/tests/ObjectStoreReconcileTest.res +83 -0
  107. package/tests/ObjectStoreReconcileTest.res.mjs +102 -0
  108. package/tests/ObjectStoreResetTest.res +191 -0
  109. package/tests/ObjectStoreResetTest.res.mjs +211 -0
  110. package/tests/QuiesceResetTest.res +169 -0
  111. package/tests/QuiesceResetTest.res.mjs +157 -0
@@ -4,7 +4,9 @@ import * as Nodefs from "node:fs";
4
4
  import * as S3$AwsSdk from "@reventlessdev/rescript-aws-sdk/src/S3.res.mjs";
5
5
  import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
6
6
  import * as Stdlib_JsExn from "@rescript/runtime/lib/es6/Stdlib_JsExn.js";
7
+ import * as Lambda$AwsSdk from "@reventlessdev/rescript-aws-sdk/src/Lambda.res.mjs";
7
8
  import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
9
+ import * as Stdlib_String from "@rescript/runtime/lib/es6/Stdlib_String.js";
8
10
  import * as Primitive_object from "@rescript/runtime/lib/es6/Primitive_object.js";
9
11
  import * as Primitive_string from "@rescript/runtime/lib/es6/Primitive_string.js";
10
12
  import * as ReventlessSeedAws from "./ReventlessSeedAws.res.mjs";
@@ -14,6 +16,7 @@ import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_excep
14
16
  import * as LibDynamodb from "@aws-sdk/lib-dynamodb";
15
17
  import * as ClientDynamodb from "@aws-sdk/client-dynamodb";
16
18
  import * as DynamoDb_DynamoDb$AwsSdk from "@reventlessdev/rescript-aws-sdk/src/DynamoDb_DynamoDb.res.mjs";
19
+ import * as ReventlessSeedAws_Quiesce from "./ReventlessSeedAws_Quiesce.res.mjs";
17
20
  import * as Seed_Prompt$ReventlessSeed from "@reventlessdev/reventless-seed/src/Seed_Prompt.res.mjs";
18
21
  import * as Seed_Runner$ReventlessSeed from "@reventlessdev/reventless-seed/src/Seed_Runner.res.mjs";
19
22
  import * as DynamoDb_DocumentClient$AwsSdk from "@reventlessdev/rescript-aws-sdk/src/DynamoDb_DocumentClient.res.mjs";
@@ -109,25 +112,52 @@ function configValue(cfg, key) {
109
112
  }
110
113
 
111
114
  function classify(arn) {
112
- if (!arn.startsWith("arn:aws:dynamodb:")) {
113
- if (arn.startsWith("arn:aws:s3:::")) {
114
- return {
115
- TAG: "Bucket",
116
- _0: arn.slice("arn:aws:s3:::".length, arn.length)
117
- };
118
- } else {
115
+ if (arn.startsWith("arn:aws:dynamodb:")) {
116
+ let match = arn.split(":table/");
117
+ if (match.length !== 2) {
119
118
  return "Other";
120
119
  }
120
+ let name = match[1];
121
+ return {
122
+ TAG: "Table",
123
+ _0: name
124
+ };
125
+ }
126
+ if (arn.startsWith("arn:aws:s3:::")) {
127
+ return {
128
+ TAG: "Bucket",
129
+ _0: arn.slice("arn:aws:s3:::".length, arn.length)
130
+ };
121
131
  }
122
- let match = arn.split(":table/");
123
- if (match.length !== 2) {
132
+ if (!arn.startsWith("arn:aws:lambda:")) {
124
133
  return "Other";
125
134
  }
126
- let name = match[1];
127
- return {
128
- TAG: "Table",
129
- _0: name
130
- };
135
+ let match$1 = arn.split(":function:");
136
+ if (match$1.length !== 2) {
137
+ return "Other";
138
+ }
139
+ let rest = match$1[1];
140
+ let match$2 = rest.split(":");
141
+ let len = match$2.length;
142
+ if (len >= 3) {
143
+ return "Other";
144
+ }
145
+ switch (len) {
146
+ case 0 :
147
+ return "Other";
148
+ case 1 :
149
+ let name$1 = match$2[0];
150
+ return {
151
+ TAG: "Function",
152
+ _0: name$1
153
+ };
154
+ case 2 :
155
+ let name$2 = match$2[0];
156
+ return {
157
+ TAG: "Function",
158
+ _0: name$2
159
+ };
160
+ }
131
161
  }
132
162
 
133
163
  function tagValue(tags, key) {
@@ -142,6 +172,7 @@ async function discover(region, stack, platform) {
142
172
  let client = ResourceGroupsTaggingApi$AwsSdk.client(region, undefined);
143
173
  let tables = [];
144
174
  let buckets = [];
175
+ let functions = [];
145
176
  let loop = async token => {
146
177
  let out = await client.send(new ClientResourceGroupsTaggingApi.GetResourcesCommand({
147
178
  TagFilters: [
@@ -156,7 +187,8 @@ async function discover(region, stack, platform) {
156
187
  ],
157
188
  ResourceTypeFilters: [
158
189
  "dynamodb:table",
159
- "s3"
190
+ "s3",
191
+ "lambda:function"
160
192
  ],
161
193
  ResourcesPerPage: 100,
162
194
  PaginationToken: token
@@ -180,11 +212,17 @@ async function discover(region, stack, platform) {
180
212
  if (typeof name !== "object") {
181
213
  return;
182
214
  }
183
- if (name.TAG === "Table") {
184
- tables.push(name._0);
185
- return;
215
+ switch (name.TAG) {
216
+ case "Table" :
217
+ tables.push(name._0);
218
+ return;
219
+ case "Bucket" :
220
+ buckets.push(name._0);
221
+ return;
222
+ case "Function" :
223
+ functions.push(name._0);
224
+ return;
186
225
  }
187
- buckets.push(name._0);
188
226
  });
189
227
  let t = out.PaginationToken;
190
228
  if (t !== undefined && t !== "") {
@@ -192,10 +230,102 @@ async function discover(region, stack, platform) {
192
230
  }
193
231
  };
194
232
  await loop(undefined);
195
- return [
196
- tables,
197
- buckets
198
- ];
233
+ return {
234
+ tables: tables,
235
+ buckets: buckets,
236
+ functions: functions
237
+ };
238
+ }
239
+
240
+ function splitQualified(key) {
241
+ return Stdlib_Option.map(Stdlib_String.indexOfOpt(key, "."), i => [
242
+ key.slice(0, i),
243
+ key.slice(i + 1 | 0, key.length)
244
+ ]);
245
+ }
246
+
247
+ function parseObjectStores(json) {
248
+ if (json !== undefined) {
249
+ if (typeof json === "object" && json !== null && !Array.isArray(json)) {
250
+ return Stdlib_Array.reduce(Object.entries(json), {
251
+ TAG: "Ok",
252
+ _0: []
253
+ }, (acc, param) => {
254
+ let entry = param[1];
255
+ let qualified = param[0];
256
+ if (acc.TAG !== "Ok") {
257
+ return acc;
258
+ }
259
+ let match = splitQualified(qualified);
260
+ let match$1 = Stdlib_Option.flatMap(field(entry, "bucketName"), asString);
261
+ let match$2 = Stdlib_Option.flatMap(field(entry, "keyPrefix"), asString);
262
+ if (match !== undefined && match$1 !== undefined && match$2 !== undefined) {
263
+ return {
264
+ TAG: "Ok",
265
+ _0: acc._0.concat([{
266
+ qualified: qualified,
267
+ plugin: match[0],
268
+ store: match[1],
269
+ bucketName: match$1,
270
+ keyPrefix: match$2
271
+ }])
272
+ };
273
+ }
274
+ return {
275
+ TAG: "Error",
276
+ _0: `the platform stack's \`objectStores\` output has a malformed entry for "` + qualified + `" — expected a {plugin}.{store} key carrying bucketName and keyPrefix.`
277
+ };
278
+ });
279
+ } else {
280
+ return {
281
+ TAG: "Error",
282
+ _0: "the platform stack's `objectStores` output is not an object."
283
+ };
284
+ }
285
+ } else {
286
+ return {
287
+ TAG: "Ok",
288
+ _0: []
289
+ };
290
+ }
291
+ }
292
+
293
+ function validateStores(stores) {
294
+ let s = stores.find(s => {
295
+ if (s.keyPrefix === "") {
296
+ return true;
297
+ } else {
298
+ return s.store.includes("/");
299
+ }
300
+ });
301
+ if (s !== undefined) {
302
+ return {
303
+ TAG: "Error",
304
+ _0: `store "` + s.qualified + `" has an unusable key prefix ("` + s.keyPrefix + `") — a store name may not be empty or contain "/".`
305
+ };
306
+ }
307
+ let message = Stdlib_Array.findMap(stores, a => Stdlib_Array.findMap(stores, b => {
308
+ if (a.qualified === b.qualified || a.bucketName !== b.bucketName) {
309
+ return;
310
+ } else if (a.keyPrefix === b.keyPrefix) {
311
+ return `stores "` + a.qualified + `" and "` + b.qualified + `" both live at ` + (a.bucketName + `/` + a.keyPrefix + `/ — a prefix-scoped wipe cannot tell their objects `) + `apart. Rename one store, or qualify the \`@storageRef\` annotation if they were meant to be one shared store.`;
312
+ } else if (b.keyPrefix.startsWith(a.keyPrefix + "/")) {
313
+ return `store "` + a.qualified + `" (` + a.bucketName + `/` + a.keyPrefix + `/) encloses "` + b.qualified + `" ` + (`(` + b.keyPrefix + `/) — wiping the first would delete the second's objects. Rename one.`);
314
+ } else {
315
+ return;
316
+ }
317
+ }));
318
+ if (message !== undefined) {
319
+ return {
320
+ TAG: "Error",
321
+ _0: message
322
+ };
323
+ } else {
324
+ return {
325
+ TAG: "Ok",
326
+ _0: undefined
327
+ };
328
+ }
199
329
  }
200
330
 
201
331
  async function countTable(table) {
@@ -216,10 +346,11 @@ async function countTable(table) {
216
346
  return await loop(undefined, 0);
217
347
  }
218
348
 
219
- async function countBucket(bucket) {
349
+ async function countBucket(bucket, prefix) {
220
350
  let loop = async (keyMarker, versionMarker, acc) => {
221
351
  let out = await S3$AwsSdk.ListObjectVersionsCommand.send(new ClientS3.ListObjectVersionsCommand({
222
352
  Bucket: bucket,
353
+ Prefix: prefix,
223
354
  KeyMarker: keyMarker,
224
355
  VersionIdMarker: versionMarker
225
356
  }));
@@ -306,10 +437,11 @@ async function truncateTable(table) {
306
437
  return await loop(undefined);
307
438
  }
308
439
 
309
- async function emptyBucket(bucket) {
440
+ async function emptyBucket(bucket, prefix) {
310
441
  let loop = async (keyMarker, versionMarker) => {
311
442
  let out = await S3$AwsSdk.ListObjectVersionsCommand.send(new ClientS3.ListObjectVersionsCommand({
312
443
  Bucket: bucket,
444
+ Prefix: prefix,
313
445
  KeyMarker: keyMarker,
314
446
  VersionIdMarker: versionMarker
315
447
  }));
@@ -341,6 +473,10 @@ async function emptyBucket(bucket) {
341
473
  return await loop(undefined, undefined);
342
474
  }
343
475
 
476
+ function pluginOf(t) {
477
+ return Stdlib_Option.getOr(t.plugin, t.label);
478
+ }
479
+
344
480
  async function chooseScope(targets) {
345
481
  let domain = targets.filter(t => t.group === "Domain");
346
482
  let platform = targets.filter(t => t.group === "Platform");
@@ -395,7 +531,7 @@ async function chooseScope(targets) {
395
531
  targets
396
532
  ]);
397
533
  }
398
- return await Seed_Prompt$ReventlessSeed.select("Reset scope:", options, undefined);
534
+ return await Seed_Prompt$ReventlessSeed.select("Reset scope:", options, undefined, undefined);
399
535
  }
400
536
  }
401
537
 
@@ -454,6 +590,28 @@ function gateTarget(target, backend, stack) {
454
590
  }
455
591
  }
456
592
 
593
+ function noQuiesce() {
594
+ let match = Stdlib_Option.map(Seed_Prompt$ReventlessSeed.envValue("SEED_RESET_NO_QUIESCE"), v => v.trim().toLowerCase());
595
+ if (match === undefined) {
596
+ return false;
597
+ }
598
+ switch (match) {
599
+ case "1" :
600
+ case "true" :
601
+ case "yes" :
602
+ return true;
603
+ default:
604
+ return false;
605
+ }
606
+ }
607
+
608
+ function refillMessage(refilled, heldCount) {
609
+ let total = Stdlib_Array.reduce(refilled, 0, (acc, param) => acc + param[1] | 0);
610
+ let lines = refilled.map(param => `\n ` + param[1].toString().padStart(8, " ") + ` ` + param[0]).join("");
611
+ let diagnosis = heldCount > 0 ? `\n\n The wipe deleted these and something wrote them back. All ` + heldCount.toString() + ` runtime(s) in scope were held at zero concurrency for the whole wipe, so the writer was an invocation already in flight when the hold took effect. Re-running clears it.` : `\n\n The wipe deleted these and a running runtime wrote them back. The stack was NOT held (SEED_RESET_NO_QUIESCE), so nothing stopped it, and re-running will not help: the writer keeps the state in memory and restores it on every invocation, identical each time. Re-run without SEED_RESET_NO_QUIESCE so the runtimes are held and recycled.`;
612
+ return total.toString() + ` item(s)/object(s) came back after the wipe:` + lines + diagnosis;
613
+ }
614
+
457
615
  function reportAll(resolvedList, stack, region) {
458
616
  Seed_Runner$ReventlessSeed.heading(`Reset target: stack "` + stack + `" in ` + region);
459
617
  let total = {
@@ -479,6 +637,15 @@ function reportAll(resolvedList, stack, region) {
479
637
  });
480
638
  if (r.bucketCounts.length === 0) {
481
639
  console.log(" (none)");
640
+ }
641
+ if (r.storeCounts.length !== 0) {
642
+ console.log(" Object stores:");
643
+ r.storeCounts.forEach(param => {
644
+ let c = param[1];
645
+ let s = param[0];
646
+ total.contents = total.contents + c | 0;
647
+ console.log(` ` + c.toString().padStart(8, " ") + ` ` + s.qualified + ` ` + (s.bucketName + `/` + s.keyPrefix + `/`));
648
+ });
482
649
  return;
483
650
  }
484
651
  });
@@ -507,7 +674,38 @@ function run(stack, backend, targets, param) {
507
674
  };
508
675
  }
509
676
  let selected = await chooseScope(targets);
510
- let regions = selected.map(t => gateTarget(t, backend$1, stack$1));
677
+ let platformTarget = targets.find(t => t.group === "Platform");
678
+ let allStores;
679
+ if (platformTarget !== undefined) {
680
+ let output = ReventlessSeedAws.stackOutputs(platformTarget.projectDir, backend$1, stack$1);
681
+ let stores = parseObjectStores(field(output, "objectStores"));
682
+ if (stores.TAG === "Ok") {
683
+ allStores = stores._0;
684
+ } else {
685
+ throw {
686
+ RE_EXN_ID: Seed$ReventlessSeed.Failed,
687
+ _1: stores._0,
688
+ Error: new Error()
689
+ };
690
+ }
691
+ } else {
692
+ console.log("");
693
+ console.log("Note: no `platform` target is declared, so declared object stores could not be resolved — any uploaded objects will be left in place.");
694
+ allStores = [];
695
+ }
696
+ let message = validateStores(allStores);
697
+ if (message.TAG !== "Ok") {
698
+ throw {
699
+ RE_EXN_ID: Seed$ReventlessSeed.Failed,
700
+ _1: `refusing: ` + message._0,
701
+ Error: new Error()
702
+ };
703
+ }
704
+ let storeBucketNames = allStores.map(s => s.bucketName);
705
+ let selectedStores = allStores.filter(s => selected.some(t => pluginOf(t) === s.plugin));
706
+ let match = selectedStores.length !== 0;
707
+ let gated = match && platformTarget !== undefined && !selected.some(t => t.projectDir === platformTarget.projectDir) ? selected.concat([platformTarget]) : selected;
708
+ let regions = gated.map(t => gateTarget(t, backend$1, stack$1));
511
709
  let region = regions[0];
512
710
  if (regions.some(r => r !== region)) {
513
711
  throw {
@@ -517,14 +715,28 @@ function run(stack, backend, targets, param) {
517
715
  };
518
716
  }
519
717
  process.env["AWS_REGION"] = region;
718
+ if (selectedStores.length !== 0 && platformTarget !== undefined) {
719
+ let platformProject = projectName(platformTarget.projectDir);
720
+ let platformFound = await discover(region, stack$1, platformProject);
721
+ selectedStores.forEach(s => {
722
+ if (platformFound.buckets.includes(s.bucketName)) {
723
+ return;
724
+ }
725
+ throw {
726
+ RE_EXN_ID: Seed$ReventlessSeed.Failed,
727
+ _1: `refusing: store "` + s.qualified + `" names bucket ` + s.bucketName + `, which does not ` + (`carry reventless:platform=` + platformProject + ` + reventless:environment=` + stack$1 + `.`),
728
+ Error: new Error()
729
+ };
730
+ });
731
+ }
520
732
  let resolvedList = [];
521
733
  for (let i = 0, i_finish = selected.length; i < i_finish; ++i) {
522
734
  let target = selected[i];
523
735
  if (target !== undefined) {
524
736
  let platform = projectName(target.projectDir);
525
- let match = await discover(region, stack$1, platform);
526
- let tables = match[0].toSorted(Primitive_string.compare);
527
- let buckets = match[1].toSorted(Primitive_string.compare);
737
+ let found = await discover(region, stack$1, platform);
738
+ let tables = found.tables.toSorted(Primitive_string.compare);
739
+ let buckets = found.buckets.filter(b => !storeBucketNames.includes(b)).toSorted(Primitive_string.compare);
528
740
  let tableCounts = [];
529
741
  for (let j = 0, j_finish = tables.length; j < j_finish; ++j) {
530
742
  let t = tables[j];
@@ -538,7 +750,18 @@ function run(stack, backend, targets, param) {
538
750
  if (b !== undefined) {
539
751
  bucketCounts.push([
540
752
  b,
541
- await countBucket(b)
753
+ await countBucket(b, undefined)
754
+ ]);
755
+ }
756
+ }
757
+ let stores$1 = selectedStores.filter(s => s.plugin === pluginOf(target));
758
+ let storeCounts = [];
759
+ for (let j$2 = 0, j_finish$2 = stores$1.length; j$2 < j_finish$2; ++j$2) {
760
+ let s = stores$1[j$2];
761
+ if (s !== undefined) {
762
+ storeCounts.push([
763
+ s,
764
+ await countBucket(s.bucketName, s.keyPrefix + `/`)
542
765
  ]);
543
766
  }
544
767
  }
@@ -547,7 +770,9 @@ function run(stack, backend, targets, param) {
547
770
  platform: platform,
548
771
  tables: tables,
549
772
  tableCounts: tableCounts,
550
- bucketCounts: bucketCounts
773
+ bucketCounts: bucketCounts,
774
+ storeCounts: storeCounts,
775
+ functions: found.functions.toSorted(Primitive_string.compare)
551
776
  });
552
777
  }
553
778
  }
@@ -572,49 +797,128 @@ function run(stack, backend, targets, param) {
572
797
  console.log(interactive ? "Dry run — nothing was deleted." : `Dry run — nothing was deleted. Set REVENTLESS_WIPE_CONFIRM=` + stack$1 + ` to empty this scope non-interactively.`);
573
798
  process.exit(0);
574
799
  }
575
- for (let i$1 = 0, i_finish$1 = resolvedList.length; i$1 < i_finish$1; ++i$1) {
576
- let r = resolvedList[i$1];
577
- if (r !== undefined) {
578
- Seed_Runner$ReventlessSeed.heading(`Emptying ` + r.target.label + ` …`);
579
- for (let j$2 = 0, j_finish$2 = r.tables.length; j$2 < j_finish$2; ++j$2) {
580
- let t$1 = r.tables[j$2];
581
- if (t$1 !== undefined) {
582
- await truncateTable(t$1);
583
- console.log(` truncated ` + t$1);
800
+ let functionNames = Stdlib_Array.reduce(resolvedList, [], (acc, r) => acc.concat(r.functions.filter(f => !acc.includes(f))));
801
+ let quiesce = !noQuiesce() && functionNames.length !== 0;
802
+ let lambdaClient = Lambda$AwsSdk.client(region, undefined);
803
+ let held = quiesce ? (Seed_Runner$ReventlessSeed.heading(`Holding ` + functionNames.length.toString() + ` runtime(s) at zero concurrency …`), await ReventlessSeedAws_Quiesce.hold(lambdaClient, functionNames)) : (functionNames.length !== 0 ? (console.log(""), console.log("Note: SEED_RESET_NO_QUIESCE is set — the stack's runtimes keep running through the wipe. A runtime that holds state across invocations can write it straight back over an emptied store."), undefined) : undefined, []);
804
+ let outcome;
805
+ try {
806
+ for (let i$1 = 0, i_finish$1 = resolvedList.length; i$1 < i_finish$1; ++i$1) {
807
+ let r = resolvedList[i$1];
808
+ if (r !== undefined) {
809
+ Seed_Runner$ReventlessSeed.heading(`Emptying ` + r.target.label + ` …`);
810
+ for (let j$3 = 0, j_finish$3 = r.tables.length; j$3 < j_finish$3; ++j$3) {
811
+ let t$1 = r.tables[j$3];
812
+ if (t$1 !== undefined) {
813
+ await truncateTable(t$1);
814
+ console.log(` truncated ` + t$1);
815
+ }
584
816
  }
585
- }
586
- for (let j$3 = 0, j_finish$3 = r.bucketCounts.length; j$3 < j_finish$3; ++j$3) {
587
- let match$1 = r.bucketCounts[j$3];
588
- if (match$1 !== undefined) {
589
- let b$1 = match$1[0];
590
- await emptyBucket(b$1);
591
- console.log(` emptied ` + b$1);
817
+ for (let j$4 = 0, j_finish$4 = r.bucketCounts.length; j$4 < j_finish$4; ++j$4) {
818
+ let match$1 = r.bucketCounts[j$4];
819
+ if (match$1 !== undefined) {
820
+ let b$1 = match$1[0];
821
+ await emptyBucket(b$1, undefined);
822
+ console.log(` emptied ` + b$1);
823
+ }
824
+ }
825
+ for (let j$5 = 0, j_finish$5 = r.storeCounts.length; j$5 < j_finish$5; ++j$5) {
826
+ let match$2 = r.storeCounts[j$5];
827
+ if (match$2 !== undefined) {
828
+ let s$1 = match$2[0];
829
+ await emptyBucket(s$1.bucketName, s$1.keyPrefix + `/`);
830
+ console.log(` emptied ` + s$1.qualified + ` — ` + match$2[1].toString() + ` object(s) removed from ` + (s$1.bucketName + `/` + s$1.keyPrefix + `/`));
831
+ }
592
832
  }
593
833
  }
594
834
  }
595
- }
596
- let remaining = 0;
597
- for (let i$2 = 0, i_finish$2 = resolvedList.length; i$2 < i_finish$2; ++i$2) {
598
- let r$1 = resolvedList[i$2];
599
- if (r$1 !== undefined) {
600
- for (let j$4 = 0, j_finish$4 = r$1.tables.length; j$4 < j_finish$4; ++j$4) {
601
- let t$2 = r$1.tables[j$4];
602
- if (t$2 !== undefined) {
603
- remaining = remaining + await countTable(t$2) | 0;
835
+ let refilled = [];
836
+ for (let i$2 = 0, i_finish$2 = resolvedList.length; i$2 < i_finish$2; ++i$2) {
837
+ let r$1 = resolvedList[i$2];
838
+ if (r$1 !== undefined) {
839
+ for (let j$6 = 0, j_finish$6 = r$1.tables.length; j$6 < j_finish$6; ++j$6) {
840
+ let t$2 = r$1.tables[j$6];
841
+ if (t$2 !== undefined) {
842
+ let left = await countTable(t$2);
843
+ if (left !== 0) {
844
+ refilled.push([
845
+ t$2,
846
+ left
847
+ ]);
848
+ }
849
+ }
604
850
  }
605
- }
606
- for (let j$5 = 0, j_finish$5 = r$1.bucketCounts.length; j$5 < j_finish$5; ++j$5) {
607
- let match$2 = r$1.bucketCounts[j$5];
608
- if (match$2 !== undefined) {
609
- remaining = remaining + await countBucket(match$2[0]) | 0;
851
+ for (let j$7 = 0, j_finish$7 = r$1.bucketCounts.length; j$7 < j_finish$7; ++j$7) {
852
+ let match$3 = r$1.bucketCounts[j$7];
853
+ if (match$3 !== undefined) {
854
+ let b$2 = match$3[0];
855
+ let left$1 = await countBucket(b$2, undefined);
856
+ if (left$1 !== 0) {
857
+ refilled.push([
858
+ b$2,
859
+ left$1
860
+ ]);
861
+ }
862
+ }
863
+ }
864
+ for (let j$8 = 0, j_finish$8 = r$1.storeCounts.length; j$8 < j_finish$8; ++j$8) {
865
+ let match$4 = r$1.storeCounts[j$8];
866
+ if (match$4 !== undefined) {
867
+ let s$2 = match$4[0];
868
+ let left$2 = await countBucket(s$2.bucketName, s$2.keyPrefix + `/`);
869
+ if (left$2 !== 0) {
870
+ refilled.push([
871
+ s$2.qualified + ` (` + s$2.bucketName + `/` + s$2.keyPrefix + `/)`,
872
+ left$2
873
+ ]);
874
+ }
875
+ console.log(` verified empty: ` + s$2.qualified + ` — ` + left$2.toString() + ` object(s) remain under ` + (s$2.bucketName + `/` + s$2.keyPrefix + `/`));
876
+ }
610
877
  }
611
878
  }
612
879
  }
880
+ outcome = {
881
+ TAG: "Ok",
882
+ _0: refilled
883
+ };
884
+ } catch (raw_message) {
885
+ let message$1 = Primitive_exceptions.internalToException(raw_message);
886
+ outcome = message$1.RE_EXN_ID === Seed$ReventlessSeed.Failed ? ({
887
+ TAG: "Error",
888
+ _0: message$1._1
889
+ }) : ({
890
+ TAG: "Error",
891
+ _0: `the wipe failed: ` + Stdlib_Option.getOr(Stdlib_Option.flatMap(Stdlib_JsExn.fromException(message$1), Stdlib_JsExn.message), "unknown error")
892
+ });
613
893
  }
614
- if (remaining !== 0) {
894
+ let warnings;
895
+ if (held.length !== 0) {
896
+ Seed_Runner$ReventlessSeed.heading(`Recycling ` + held.length.toString() + ` runtime(s) …`);
897
+ let recycled = await ReventlessSeedAws_Quiesce.recycle(lambdaClient, held);
898
+ let released = await ReventlessSeedAws_Quiesce.release(lambdaClient, held);
899
+ warnings = recycled.concat(released);
900
+ } else {
901
+ warnings = [];
902
+ }
903
+ if (warnings.length !== 0) {
904
+ console.error("");
905
+ warnings.forEach(w => {
906
+ console.error(` warning: ` + w);
907
+ });
908
+ }
909
+ if (outcome.TAG === "Ok") {
910
+ let refilled$1 = outcome._0;
911
+ if (refilled$1.length !== 0) {
912
+ throw {
913
+ RE_EXN_ID: Seed$ReventlessSeed.Failed,
914
+ _1: refillMessage(refilled$1, held.length),
915
+ Error: new Error()
916
+ };
917
+ }
918
+ } else {
615
919
  throw {
616
920
  RE_EXN_ID: Seed$ReventlessSeed.Failed,
617
- _1: remaining.toString() + ` item(s)/object(s) remain after the wipe — re-run to finish.`,
921
+ _1: outcome._0,
618
922
  Error: new Error()
619
923
  };
620
924
  }
@@ -622,18 +926,18 @@ function run(stack, backend, targets, param) {
622
926
  console.log(`Reset complete — the selected scope of "` + stack$1 + `" reads empty and is re-seedable.`);
623
927
  process.exit(0);
624
928
  return;
625
- } catch (raw_message) {
626
- let message = Primitive_exceptions.internalToException(raw_message);
627
- if (message.RE_EXN_ID === Seed$ReventlessSeed.Failed) {
929
+ } catch (raw_message$1) {
930
+ let message$2 = Primitive_exceptions.internalToException(raw_message$1);
931
+ if (message$2.RE_EXN_ID === Seed$ReventlessSeed.Failed) {
628
932
  Seed_Prompt$ReventlessSeed.close();
629
933
  console.error("");
630
- console.error(`Reset aborted — ` + message._1);
934
+ console.error(`Reset aborted — ` + message$2._1);
631
935
  process.exit(1);
632
936
  } else {
633
937
  Seed_Prompt$ReventlessSeed.close();
634
938
  console.error("");
635
939
  console.error("Reset aborted with an unexpected error:");
636
- console.error(Stdlib_Option.getOr(Stdlib_Option.flatMap(Stdlib_JsExn.fromException(message), Stdlib_JsExn.message), "unknown"));
940
+ console.error(Stdlib_Option.getOr(Stdlib_Option.flatMap(Stdlib_JsExn.fromException(message$2), Stdlib_JsExn.message), "unknown"));
637
941
  process.exit(1);
638
942
  }
639
943
  return;
@@ -648,10 +952,16 @@ let Rgt;
648
952
 
649
953
  let S3;
650
954
 
955
+ let Lambda;
956
+
957
+ let Quiesce;
958
+
651
959
  export {
652
960
  Ddb,
653
961
  Rgt,
654
962
  S3,
963
+ Lambda,
964
+ Quiesce,
655
965
  projectName,
656
966
  field,
657
967
  asString,
@@ -662,13 +972,19 @@ export {
662
972
  classify,
663
973
  tagValue,
664
974
  discover,
975
+ splitQualified,
976
+ parseObjectStores,
977
+ validateStores,
665
978
  countTable,
666
979
  countBucket,
667
980
  sendBatch,
668
981
  truncateTable,
669
982
  emptyBucket,
983
+ pluginOf,
670
984
  chooseScope,
671
985
  gateTarget,
986
+ noQuiesce,
987
+ refillMessage,
672
988
  reportAll,
673
989
  run,
674
990
  }