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

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.
@@ -0,0 +1,675 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+ import * as Nodefs from "node:fs";
4
+ import * as S3$AwsSdk from "@reventlessdev/rescript-aws-sdk/src/S3.res.mjs";
5
+ import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
6
+ import * as Stdlib_JsExn from "@rescript/runtime/lib/es6/Stdlib_JsExn.js";
7
+ import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
8
+ import * as Primitive_object from "@rescript/runtime/lib/es6/Primitive_object.js";
9
+ import * as Primitive_string from "@rescript/runtime/lib/es6/Primitive_string.js";
10
+ import * as ReventlessSeedAws from "./ReventlessSeedAws.res.mjs";
11
+ import * as ClientS3 from "@aws-sdk/client-s3";
12
+ import * as Seed$ReventlessSeed from "@reventlessdev/reventless-seed/src/Seed.res.mjs";
13
+ import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
14
+ import * as LibDynamodb from "@aws-sdk/lib-dynamodb";
15
+ import * as ClientDynamodb from "@aws-sdk/client-dynamodb";
16
+ import * as DynamoDb_DynamoDb$AwsSdk from "@reventlessdev/rescript-aws-sdk/src/DynamoDb_DynamoDb.res.mjs";
17
+ import * as Seed_Prompt$ReventlessSeed from "@reventlessdev/reventless-seed/src/Seed_Prompt.res.mjs";
18
+ import * as Seed_Runner$ReventlessSeed from "@reventlessdev/reventless-seed/src/Seed_Runner.res.mjs";
19
+ import * as DynamoDb_DocumentClient$AwsSdk from "@reventlessdev/rescript-aws-sdk/src/DynamoDb_DocumentClient.res.mjs";
20
+ import * as ResourceGroupsTaggingApi$AwsSdk from "@reventlessdev/rescript-aws-sdk/src/ResourceGroupsTaggingApi.res.mjs";
21
+ import * as ClientResourceGroupsTaggingApi from "@aws-sdk/client-resource-groups-tagging-api";
22
+
23
+ function projectName(projectDir) {
24
+ let path = projectDir + `/Pulumi.yaml`;
25
+ let raw;
26
+ try {
27
+ raw = Nodefs.readFileSync(path, "utf8");
28
+ } catch (exn) {
29
+ throw {
30
+ RE_EXN_ID: Seed$ReventlessSeed.Failed,
31
+ _1: `could not read ` + path + ` to scope the wipe to this Pulumi project.`,
32
+ Error: new Error()
33
+ };
34
+ }
35
+ let line = raw.split("\n").find(line => line.trim().startsWith("name:"));
36
+ if (line !== undefined) {
37
+ let trimmed = line.trim();
38
+ return trimmed.slice("name:".length, trimmed.length).trim().replace(/^[\"']|[\"']$/g, "");
39
+ }
40
+ throw {
41
+ RE_EXN_ID: Seed$ReventlessSeed.Failed,
42
+ _1: `could not find a \`name:\` field in ` + path + `.`,
43
+ Error: new Error()
44
+ };
45
+ }
46
+
47
+ function field(json, key) {
48
+ if (typeof json === "object" && json !== null && !Array.isArray(json)) {
49
+ return json[key];
50
+ }
51
+ }
52
+
53
+ function asString(json) {
54
+ if (typeof json === "string") {
55
+ return json;
56
+ }
57
+ }
58
+
59
+ function chunk(arr, size) {
60
+ let out = [];
61
+ let i = 0;
62
+ while (i < arr.length) {
63
+ out.push(arr.slice(i, i + size | 0));
64
+ i = i + size | 0;
65
+ };
66
+ return out;
67
+ }
68
+
69
+ let nameAllowlist = /^(alpha|dev|pr-.+)$/;
70
+
71
+ function readStackConfig(projectDir, backend, stack) {
72
+ let raw;
73
+ try {
74
+ raw = ReventlessSeedAws.pulumi(projectDir, backend, [
75
+ "config",
76
+ "--json",
77
+ "--stack",
78
+ stack
79
+ ]);
80
+ } catch (exn) {
81
+ raw = undefined;
82
+ }
83
+ if (raw === undefined) {
84
+ return {
85
+ TAG: "Error",
86
+ _0: `could not read the Pulumi config for stack "` + stack + `" — is pulumi logged in to the right backend, and is the stack deployed?`
87
+ };
88
+ }
89
+ let match;
90
+ try {
91
+ match = JSON.parse(raw);
92
+ } catch (exn$1) {
93
+ match = undefined;
94
+ }
95
+ if (typeof match === "object" && match !== null && !Array.isArray(match)) {
96
+ return {
97
+ TAG: "Ok",
98
+ _0: match
99
+ };
100
+ }
101
+ return {
102
+ TAG: "Error",
103
+ _0: `could not parse \`pulumi config --json\` output for stack "` + stack + `".`
104
+ };
105
+ }
106
+
107
+ function configValue(cfg, key) {
108
+ return Stdlib_Option.flatMap(Stdlib_Option.flatMap(cfg[key], v => field(v, "value")), asString);
109
+ }
110
+
111
+ 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 {
119
+ return "Other";
120
+ }
121
+ }
122
+ let match = arn.split(":table/");
123
+ if (match.length !== 2) {
124
+ return "Other";
125
+ }
126
+ let name = match[1];
127
+ return {
128
+ TAG: "Table",
129
+ _0: name
130
+ };
131
+ }
132
+
133
+ function tagValue(tags, key) {
134
+ return Stdlib_Array.findMap(tags, t => {
135
+ if (t.Key === key) {
136
+ return t.Value;
137
+ }
138
+ });
139
+ }
140
+
141
+ async function discover(region, stack, platform) {
142
+ let client = ResourceGroupsTaggingApi$AwsSdk.client(region, undefined);
143
+ let tables = [];
144
+ let buckets = [];
145
+ let loop = async token => {
146
+ let out = await client.send(new ClientResourceGroupsTaggingApi.GetResourcesCommand({
147
+ TagFilters: [
148
+ {
149
+ Key: "reventless:platform",
150
+ Values: [platform]
151
+ },
152
+ {
153
+ Key: "reventless:environment",
154
+ Values: [stack]
155
+ }
156
+ ],
157
+ ResourceTypeFilters: [
158
+ "dynamodb:table",
159
+ "s3"
160
+ ],
161
+ ResourcesPerPage: 100,
162
+ PaginationToken: token
163
+ }));
164
+ Stdlib_Option.getOr(out.ResourceTagMappingList, []).forEach(m => {
165
+ let tags = Stdlib_Option.getOr(m.Tags, []);
166
+ let assertTag = (key, expected) => {
167
+ let v = tagValue(tags, key);
168
+ if (v !== undefined && v === expected) {
169
+ return;
170
+ }
171
+ throw {
172
+ RE_EXN_ID: Seed$ReventlessSeed.Failed,
173
+ _1: `refusing: discovered resource ` + m.ResourceARN + ` carries ` + key + `=` + Stdlib_Option.getOr(v, "<none>") + `, not "` + expected + `".`,
174
+ Error: new Error()
175
+ };
176
+ };
177
+ assertTag("reventless:platform", platform);
178
+ assertTag("reventless:environment", stack);
179
+ let name = classify(m.ResourceARN);
180
+ if (typeof name !== "object") {
181
+ return;
182
+ }
183
+ if (name.TAG === "Table") {
184
+ tables.push(name._0);
185
+ return;
186
+ }
187
+ buckets.push(name._0);
188
+ });
189
+ let t = out.PaginationToken;
190
+ if (t !== undefined && t !== "") {
191
+ return await loop(t);
192
+ }
193
+ };
194
+ await loop(undefined);
195
+ return [
196
+ tables,
197
+ buckets
198
+ ];
199
+ }
200
+
201
+ async function countTable(table) {
202
+ let loop = async (start, acc) => {
203
+ let out = await DynamoDb_DocumentClient$AwsSdk.ScanCommand.send(new LibDynamodb.ScanCommand({
204
+ TableName: table,
205
+ ExclusiveStartKey: start,
206
+ Select: "COUNT"
207
+ }));
208
+ let acc$1 = acc + Stdlib_Option.getOr(out.Count, 0) | 0;
209
+ let k = out.LastEvaluatedKey;
210
+ if (k !== undefined) {
211
+ return await loop(k, acc$1);
212
+ } else {
213
+ return acc$1;
214
+ }
215
+ };
216
+ return await loop(undefined, 0);
217
+ }
218
+
219
+ async function countBucket(bucket) {
220
+ let loop = async (keyMarker, versionMarker, acc) => {
221
+ let out = await S3$AwsSdk.ListObjectVersionsCommand.send(new ClientS3.ListObjectVersionsCommand({
222
+ Bucket: bucket,
223
+ KeyMarker: keyMarker,
224
+ VersionIdMarker: versionMarker
225
+ }));
226
+ let n = Stdlib_Option.getOr(out.Versions, []).length + Stdlib_Option.getOr(out.DeleteMarkers, []).length | 0;
227
+ if (Stdlib_Option.getOr(out.IsTruncated, false)) {
228
+ return await loop(out.NextKeyMarker, out.NextVersionIdMarker, acc + n | 0);
229
+ } else {
230
+ return acc + n | 0;
231
+ }
232
+ };
233
+ return await loop(undefined, undefined, 0);
234
+ }
235
+
236
+ async function sendBatch(table, requests, attempt) {
237
+ if (requests.length === 0) {
238
+ return;
239
+ }
240
+ if (attempt > 8) {
241
+ throw {
242
+ RE_EXN_ID: Seed$ReventlessSeed.Failed,
243
+ _1: `table ` + table + `: ` + requests.length.toString() + ` item(s) still unprocessed after 8 retries.`,
244
+ Error: new Error()
245
+ };
246
+ }
247
+ let out = await DynamoDb_DocumentClient$AwsSdk.BatchWriteCommand.send(new LibDynamodb.BatchWriteCommand({
248
+ RequestItems: Object.fromEntries([[
249
+ table,
250
+ requests
251
+ ]])
252
+ }));
253
+ let unprocessed = Stdlib_Option.getOr(Stdlib_Option.flatMap(out.UnprocessedItems, d => d[table]), []);
254
+ if (unprocessed.length !== 0) {
255
+ return await sendBatch(table, unprocessed, attempt + 1 | 0);
256
+ }
257
+ }
258
+
259
+ async function truncateTable(table) {
260
+ let desc = await DynamoDb_DynamoDb$AwsSdk.DescribeTableCommand.send(new ClientDynamodb.DescribeTableCommand({
261
+ TableName: table
262
+ }));
263
+ let keyAttrs = Stdlib_Option.getOr(Stdlib_Option.flatMap(desc.Table, t => t.KeySchema), []).map(k => k.AttributeName);
264
+ if (keyAttrs.length === 0) {
265
+ throw {
266
+ RE_EXN_ID: Seed$ReventlessSeed.Failed,
267
+ _1: `could not read a key schema for table ` + table + `.`,
268
+ Error: new Error()
269
+ };
270
+ }
271
+ let names = keyAttrs.map((name, i) => [
272
+ `#k` + i.toString(),
273
+ name
274
+ ]);
275
+ let projection = names.map(param => param[0]).join(", ");
276
+ let loop = async start => {
277
+ let out = await DynamoDb_DocumentClient$AwsSdk.ScanCommand.send(new LibDynamodb.ScanCommand({
278
+ TableName: table,
279
+ ExclusiveStartKey: start,
280
+ ExpressionAttributeNames: Object.fromEntries(names),
281
+ ProjectionExpression: projection
282
+ }));
283
+ let requests = Stdlib_Option.getOr(out.Items, []).map(item => {
284
+ let key = Object.fromEntries(Stdlib_Array.filterMap(keyAttrs, attr => Stdlib_Option.map(field(item, attr), v => [
285
+ attr,
286
+ v
287
+ ])));
288
+ return {
289
+ DeleteRequest: {
290
+ Key: key
291
+ }
292
+ };
293
+ });
294
+ let batches = chunk(requests, DynamoDb_DocumentClient$AwsSdk.BatchWriteCommand.maxBatchSize);
295
+ for (let i = 0, i_finish = batches.length; i < i_finish; ++i) {
296
+ let b = batches[i];
297
+ if (b !== undefined) {
298
+ await sendBatch(table, b, 1);
299
+ }
300
+ }
301
+ let k = out.LastEvaluatedKey;
302
+ if (k !== undefined) {
303
+ return await loop(k);
304
+ }
305
+ };
306
+ return await loop(undefined);
307
+ }
308
+
309
+ async function emptyBucket(bucket) {
310
+ let loop = async (keyMarker, versionMarker) => {
311
+ let out = await S3$AwsSdk.ListObjectVersionsCommand.send(new ClientS3.ListObjectVersionsCommand({
312
+ Bucket: bucket,
313
+ KeyMarker: keyMarker,
314
+ VersionIdMarker: versionMarker
315
+ }));
316
+ let ids = Stdlib_Option.getOr(out.Versions, []).concat(Stdlib_Option.getOr(out.DeleteMarkers, [])).map(v => ({
317
+ Key: v.Key,
318
+ VersionId: v.VersionId
319
+ }));
320
+ if (ids.length !== 0) {
321
+ let res = await S3$AwsSdk.DeleteObjectsCommand.send(new ClientS3.DeleteObjectsCommand({
322
+ Bucket: bucket,
323
+ Delete: {
324
+ Objects: ids,
325
+ Quiet: true
326
+ }
327
+ }));
328
+ let errs = res.Errors;
329
+ if (errs !== undefined && errs.length !== 0) {
330
+ throw {
331
+ RE_EXN_ID: Seed$ReventlessSeed.Failed,
332
+ _1: `failed to delete ` + errs.length.toString() + ` object(s) from ` + bucket + `: ` + Stdlib_Option.getOr(Stdlib_Option.flatMap(errs[0], e => e.Message), "unknown"),
333
+ Error: new Error()
334
+ };
335
+ }
336
+ }
337
+ if (Stdlib_Option.getOr(out.IsTruncated, false)) {
338
+ return await loop(out.NextKeyMarker, out.NextVersionIdMarker);
339
+ }
340
+ };
341
+ return await loop(undefined, undefined);
342
+ }
343
+
344
+ async function chooseScope(targets) {
345
+ let domain = targets.filter(t => t.group === "Domain");
346
+ let platform = targets.filter(t => t.group === "Platform");
347
+ let labelsOf = ts => ts.map(t => t.label).join(", ");
348
+ let other = Stdlib_Option.map(Seed_Prompt$ReventlessSeed.envValue("SEED_RESET_SCOPE"), prim => prim.toLowerCase());
349
+ if (other !== undefined) {
350
+ switch (other) {
351
+ case "domain" :
352
+ return domain;
353
+ case "all" :
354
+ case "both" :
355
+ case "everything" :
356
+ return targets;
357
+ case "platform" :
358
+ return platform;
359
+ default:
360
+ let t = targets.find(t => t.label.toLowerCase() === other);
361
+ if (t !== undefined) {
362
+ return [t];
363
+ }
364
+ throw {
365
+ RE_EXN_ID: Seed$ReventlessSeed.Failed,
366
+ _1: `SEED_RESET_SCOPE="` + other + `" is not a scope — use domain, platform, everything, or a plugin label (` + labelsOf(domain) + `).`,
367
+ Error: new Error()
368
+ };
369
+ }
370
+ } else {
371
+ let options = [];
372
+ if (domain.length !== 0) {
373
+ options.push([
374
+ `domain — ` + labelsOf(domain),
375
+ domain
376
+ ]);
377
+ if (domain.length > 1) {
378
+ domain.forEach(t => {
379
+ options.push([
380
+ t.label,
381
+ [t]
382
+ ]);
383
+ });
384
+ }
385
+ }
386
+ if (platform.length !== 0) {
387
+ options.push([
388
+ `platform — ` + labelsOf(platform),
389
+ platform
390
+ ]);
391
+ }
392
+ if (domain.length !== 0 && platform.length !== 0) {
393
+ options.push([
394
+ `everything — ` + labelsOf(targets),
395
+ targets
396
+ ]);
397
+ }
398
+ return await Seed_Prompt$ReventlessSeed.select("Reset scope:", options, undefined);
399
+ }
400
+ }
401
+
402
+ function gateTarget(target, backend, stack) {
403
+ let c = readStackConfig(target.projectDir, backend, stack);
404
+ let cfg;
405
+ if (c.TAG === "Ok") {
406
+ cfg = c._0;
407
+ } else {
408
+ throw {
409
+ RE_EXN_ID: Seed$ReventlessSeed.Failed,
410
+ _1: c._0,
411
+ Error: new Error()
412
+ };
413
+ }
414
+ let match = Stdlib_Option.map(configValue(cfg, "reventless:wipeable"), v => v.trim().toLowerCase());
415
+ let exit = 0;
416
+ if (match !== "true") {
417
+ exit = 1;
418
+ }
419
+ if (exit === 1) {
420
+ throw {
421
+ RE_EXN_ID: Seed$ReventlessSeed.Failed,
422
+ _1: target.label + `: stack "` + stack + `" does not declare \`reventless:wipeable: "true"\` in its Pulumi.` + stack + `.yaml — refusing. Add that line only on disposable dev stacks (see the alpha example configs).`,
423
+ Error: new Error()
424
+ };
425
+ }
426
+ let r = Seed_Prompt$ReventlessSeed.envValue("AWS_REGION");
427
+ let exit$1 = 0;
428
+ if (r !== undefined) {
429
+ if (r !== "") {
430
+ return r;
431
+ }
432
+ exit$1 = 1;
433
+ } else {
434
+ exit$1 = 1;
435
+ }
436
+ if (exit$1 === 1) {
437
+ let r$1 = configValue(cfg, "aws:region");
438
+ let exit$2 = 0;
439
+ if (r$1 !== undefined) {
440
+ if (r$1 !== "") {
441
+ return r$1;
442
+ }
443
+ exit$2 = 2;
444
+ } else {
445
+ exit$2 = 2;
446
+ }
447
+ if (exit$2 === 2) {
448
+ throw {
449
+ RE_EXN_ID: Seed$ReventlessSeed.Failed,
450
+ _1: target.label + `: could not resolve the AWS region — set AWS_REGION or \`aws:region\` in the stack config.`,
451
+ Error: new Error()
452
+ };
453
+ }
454
+ }
455
+ }
456
+
457
+ function reportAll(resolvedList, stack, region) {
458
+ Seed_Runner$ReventlessSeed.heading(`Reset target: stack "` + stack + `" in ` + region);
459
+ let total = {
460
+ contents: 0
461
+ };
462
+ resolvedList.forEach(r => {
463
+ console.log("");
464
+ console.log(` ` + r.target.label + ` (` + r.platform + `)`);
465
+ console.log(" DynamoDB tables:");
466
+ r.tables.forEach((t, i) => {
467
+ let c = Stdlib_Option.getOr(r.tableCounts[i], 0);
468
+ total.contents = total.contents + c | 0;
469
+ console.log(` ` + c.toString().padStart(8, " ") + ` ` + t);
470
+ });
471
+ if (r.tables.length === 0) {
472
+ console.log(" (none)");
473
+ }
474
+ console.log(" S3 buckets:");
475
+ r.bucketCounts.forEach(param => {
476
+ let c = param[1];
477
+ total.contents = total.contents + c | 0;
478
+ console.log(` ` + c.toString().padStart(8, " ") + ` ` + param[0]);
479
+ });
480
+ if (r.bucketCounts.length === 0) {
481
+ console.log(" (none)");
482
+ return;
483
+ }
484
+ });
485
+ return total.contents;
486
+ }
487
+
488
+ function run(stack, backend, targets, param) {
489
+ let go = async () => {
490
+ try {
491
+ if (targets.length === 0) {
492
+ throw {
493
+ RE_EXN_ID: Seed$ReventlessSeed.Failed,
494
+ _1: "no targets were declared — nothing to reset.",
495
+ Error: new Error()
496
+ };
497
+ }
498
+ let url = Seed_Prompt$ReventlessSeed.envValue("SEED_PULUMI_BACKEND");
499
+ let backend$1 = url !== undefined ? url : backend;
500
+ let baseTarget = Stdlib_Option.getOr(targets.find(t => t.group === "Platform"), targets[0]);
501
+ let stack$1 = await ReventlessSeedAws.resolveStack(baseTarget.projectDir, backend$1, stack);
502
+ if (!nameAllowlist.test(stack$1)) {
503
+ throw {
504
+ RE_EXN_ID: Seed$ReventlessSeed.Failed,
505
+ _1: `stack "` + stack$1 + `" is not on the wipe name-allowlist (alpha, dev, pr-*) — refusing.`,
506
+ Error: new Error()
507
+ };
508
+ }
509
+ let selected = await chooseScope(targets);
510
+ let regions = selected.map(t => gateTarget(t, backend$1, stack$1));
511
+ let region = regions[0];
512
+ if (regions.some(r => r !== region)) {
513
+ throw {
514
+ RE_EXN_ID: Seed$ReventlessSeed.Failed,
515
+ _1: `selected targets span more than one region (` + regions.join(", ") + `) — reset them one region at a time.`,
516
+ Error: new Error()
517
+ };
518
+ }
519
+ process.env["AWS_REGION"] = region;
520
+ let resolvedList = [];
521
+ for (let i = 0, i_finish = selected.length; i < i_finish; ++i) {
522
+ let target = selected[i];
523
+ if (target !== undefined) {
524
+ 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);
528
+ let tableCounts = [];
529
+ for (let j = 0, j_finish = tables.length; j < j_finish; ++j) {
530
+ let t = tables[j];
531
+ if (t !== undefined) {
532
+ tableCounts.push(await countTable(t));
533
+ }
534
+ }
535
+ let bucketCounts = [];
536
+ for (let j$1 = 0, j_finish$1 = buckets.length; j$1 < j_finish$1; ++j$1) {
537
+ let b = buckets[j$1];
538
+ if (b !== undefined) {
539
+ bucketCounts.push([
540
+ b,
541
+ await countBucket(b)
542
+ ]);
543
+ }
544
+ }
545
+ resolvedList.push({
546
+ target: target,
547
+ platform: platform,
548
+ tables: tables,
549
+ tableCounts: tableCounts,
550
+ bucketCounts: bucketCounts
551
+ });
552
+ }
553
+ }
554
+ let total = reportAll(resolvedList, stack$1, region);
555
+ if (total === 0) {
556
+ Seed_Prompt$ReventlessSeed.close();
557
+ console.log("");
558
+ console.log(`Nothing to reset — the selected scope already reads empty in ` + region + `.`);
559
+ process.exit(0);
560
+ }
561
+ let interactive = Stdlib_Option.getOr(process.stdin.isTTY, false);
562
+ let confirmed;
563
+ if (interactive) {
564
+ let typed = await Seed_Prompt$ReventlessSeed.ask(`About to permanently empty ` + total.toString() + ` item(s)/object(s) across the selected scope of "` + stack$1 + `". Type the stack name to confirm, or press Enter to keep this a dry run: `);
565
+ confirmed = typed.trim() === stack$1;
566
+ } else {
567
+ confirmed = Primitive_object.equal(Seed_Prompt$ReventlessSeed.envValue("REVENTLESS_WIPE_CONFIRM"), stack$1);
568
+ }
569
+ Seed_Prompt$ReventlessSeed.close();
570
+ if (!confirmed) {
571
+ console.log("");
572
+ 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
+ process.exit(0);
574
+ }
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);
584
+ }
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);
592
+ }
593
+ }
594
+ }
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;
604
+ }
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;
610
+ }
611
+ }
612
+ }
613
+ }
614
+ if (remaining !== 0) {
615
+ throw {
616
+ RE_EXN_ID: Seed$ReventlessSeed.Failed,
617
+ _1: remaining.toString() + ` item(s)/object(s) remain after the wipe — re-run to finish.`,
618
+ Error: new Error()
619
+ };
620
+ }
621
+ console.log("");
622
+ console.log(`Reset complete — the selected scope of "` + stack$1 + `" reads empty and is re-seedable.`);
623
+ process.exit(0);
624
+ return;
625
+ } catch (raw_message) {
626
+ let message = Primitive_exceptions.internalToException(raw_message);
627
+ if (message.RE_EXN_ID === Seed$ReventlessSeed.Failed) {
628
+ Seed_Prompt$ReventlessSeed.close();
629
+ console.error("");
630
+ console.error(`Reset aborted — ` + message._1);
631
+ process.exit(1);
632
+ } else {
633
+ Seed_Prompt$ReventlessSeed.close();
634
+ console.error("");
635
+ 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"));
637
+ process.exit(1);
638
+ }
639
+ return;
640
+ }
641
+ };
642
+ go();
643
+ }
644
+
645
+ let Ddb;
646
+
647
+ let Rgt;
648
+
649
+ let S3;
650
+
651
+ export {
652
+ Ddb,
653
+ Rgt,
654
+ S3,
655
+ projectName,
656
+ field,
657
+ asString,
658
+ chunk,
659
+ nameAllowlist,
660
+ readStackConfig,
661
+ configValue,
662
+ classify,
663
+ tagValue,
664
+ discover,
665
+ countTable,
666
+ countBucket,
667
+ sendBatch,
668
+ truncateTable,
669
+ emptyBucket,
670
+ chooseScope,
671
+ gateTarget,
672
+ reportAll,
673
+ run,
674
+ }
675
+ /* node:fs Not a pure module */
@@ -1,2 +1,2 @@
1
- #Start(1785139469141)
2
- #Done(1785139473591)
1
+ #Start(1785181007711)
2
+ #Done(1785181012329)
Binary file
Binary file