@reventlessdev/reventless-seed-aws 1.0.0-alpha.6 → 1.0.0-alpha.8

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 (57) hide show
  1. package/CHANGELOG.md +14 -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 +3 -47
  9. package/lib/bs/src/ReventlessSeedAws.res.mjs +1 -30
  10. package/lib/bs/src/ReventlessSeedAws_Reset.ast +0 -0
  11. package/lib/bs/src/ReventlessSeedAws_Reset.cmi +0 -0
  12. package/lib/bs/src/ReventlessSeedAws_Reset.cmj +0 -0
  13. package/lib/bs/src/ReventlessSeedAws_Reset.cmt +0 -0
  14. package/lib/bs/src/ReventlessSeedAws_Reset.res +261 -6
  15. package/lib/bs/src/ReventlessSeedAws_Reset.res.mjs +211 -25
  16. package/lib/bs/tests/EndpointResolutionTest.ast +0 -0
  17. package/lib/bs/tests/EndpointResolutionTest.cmi +0 -0
  18. package/lib/bs/tests/EndpointResolutionTest.cmj +0 -0
  19. package/lib/bs/tests/EndpointResolutionTest.cmt +0 -0
  20. package/lib/bs/tests/EndpointResolutionTest.res +12 -109
  21. package/lib/bs/tests/EndpointResolutionTest.res.mjs +4 -97
  22. package/lib/bs/tests/ObjectStoreResetTest.ast +0 -0
  23. package/lib/bs/tests/ObjectStoreResetTest.cmi +0 -0
  24. package/lib/bs/tests/ObjectStoreResetTest.cmj +0 -0
  25. package/lib/bs/tests/ObjectStoreResetTest.cmt +0 -0
  26. package/lib/bs/tests/ObjectStoreResetTest.res +170 -0
  27. package/lib/bs/tests/ObjectStoreResetTest.res.mjs +211 -0
  28. package/lib/ocaml/.compiler.log +2 -2
  29. package/lib/ocaml/EndpointResolutionTest.ast +0 -0
  30. package/lib/ocaml/EndpointResolutionTest.cmi +0 -0
  31. package/lib/ocaml/EndpointResolutionTest.cmj +0 -0
  32. package/lib/ocaml/EndpointResolutionTest.cmt +0 -0
  33. package/lib/ocaml/EndpointResolutionTest.res +12 -109
  34. package/lib/ocaml/ObjectStoreResetTest.ast +0 -0
  35. package/lib/ocaml/ObjectStoreResetTest.cmi +0 -0
  36. package/lib/ocaml/ObjectStoreResetTest.cmj +0 -0
  37. package/lib/ocaml/ObjectStoreResetTest.cmt +0 -0
  38. package/lib/ocaml/ObjectStoreResetTest.res +170 -0
  39. package/lib/ocaml/ReventlessSeedAws.ast +0 -0
  40. package/lib/ocaml/ReventlessSeedAws.cmi +0 -0
  41. package/lib/ocaml/ReventlessSeedAws.cmj +0 -0
  42. package/lib/ocaml/ReventlessSeedAws.cmt +0 -0
  43. package/lib/ocaml/ReventlessSeedAws.res +3 -47
  44. package/lib/ocaml/ReventlessSeedAws_Reset.ast +0 -0
  45. package/lib/ocaml/ReventlessSeedAws_Reset.cmi +0 -0
  46. package/lib/ocaml/ReventlessSeedAws_Reset.cmj +0 -0
  47. package/lib/ocaml/ReventlessSeedAws_Reset.cmt +0 -0
  48. package/lib/ocaml/ReventlessSeedAws_Reset.res +261 -6
  49. package/package.json +2 -2
  50. package/src/ReventlessSeedAws.res +3 -47
  51. package/src/ReventlessSeedAws.res.mjs +1 -30
  52. package/src/ReventlessSeedAws_Reset.res +261 -6
  53. package/src/ReventlessSeedAws_Reset.res.mjs +211 -25
  54. package/tests/EndpointResolutionTest.res +12 -109
  55. package/tests/EndpointResolutionTest.res.mjs +4 -97
  56. package/tests/ObjectStoreResetTest.res +170 -0
  57. package/tests/ObjectStoreResetTest.res.mjs +211 -0
@@ -5,6 +5,7 @@ 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
7
  import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
8
+ import * as Stdlib_String from "@rescript/runtime/lib/es6/Stdlib_String.js";
8
9
  import * as Primitive_object from "@rescript/runtime/lib/es6/Primitive_object.js";
9
10
  import * as Primitive_string from "@rescript/runtime/lib/es6/Primitive_string.js";
10
11
  import * as ReventlessSeedAws from "./ReventlessSeedAws.res.mjs";
@@ -198,6 +199,97 @@ async function discover(region, stack, platform) {
198
199
  ];
199
200
  }
200
201
 
202
+ function splitQualified(key) {
203
+ return Stdlib_Option.map(Stdlib_String.indexOfOpt(key, "."), i => [
204
+ key.slice(0, i),
205
+ key.slice(i + 1 | 0, key.length)
206
+ ]);
207
+ }
208
+
209
+ function parseObjectStores(json) {
210
+ if (json !== undefined) {
211
+ if (typeof json === "object" && json !== null && !Array.isArray(json)) {
212
+ return Stdlib_Array.reduce(Object.entries(json), {
213
+ TAG: "Ok",
214
+ _0: []
215
+ }, (acc, param) => {
216
+ let entry = param[1];
217
+ let qualified = param[0];
218
+ if (acc.TAG !== "Ok") {
219
+ return acc;
220
+ }
221
+ let match = splitQualified(qualified);
222
+ let match$1 = Stdlib_Option.flatMap(field(entry, "bucketName"), asString);
223
+ let match$2 = Stdlib_Option.flatMap(field(entry, "keyPrefix"), asString);
224
+ if (match !== undefined && match$1 !== undefined && match$2 !== undefined) {
225
+ return {
226
+ TAG: "Ok",
227
+ _0: acc._0.concat([{
228
+ qualified: qualified,
229
+ plugin: match[0],
230
+ store: match[1],
231
+ bucketName: match$1,
232
+ keyPrefix: match$2
233
+ }])
234
+ };
235
+ }
236
+ return {
237
+ TAG: "Error",
238
+ _0: `the platform stack's \`objectStores\` output has a malformed entry for "` + qualified + `" — expected a {plugin}.{store} key carrying bucketName and keyPrefix.`
239
+ };
240
+ });
241
+ } else {
242
+ return {
243
+ TAG: "Error",
244
+ _0: "the platform stack's `objectStores` output is not an object."
245
+ };
246
+ }
247
+ } else {
248
+ return {
249
+ TAG: "Ok",
250
+ _0: []
251
+ };
252
+ }
253
+ }
254
+
255
+ function validateStores(stores) {
256
+ let s = stores.find(s => {
257
+ if (s.keyPrefix === "") {
258
+ return true;
259
+ } else {
260
+ return s.store.includes("/");
261
+ }
262
+ });
263
+ if (s !== undefined) {
264
+ return {
265
+ TAG: "Error",
266
+ _0: `store "` + s.qualified + `" has an unusable key prefix ("` + s.keyPrefix + `") — a store name may not be empty or contain "/".`
267
+ };
268
+ }
269
+ let message = Stdlib_Array.findMap(stores, a => Stdlib_Array.findMap(stores, b => {
270
+ if (a.qualified === b.qualified || a.bucketName !== b.bucketName) {
271
+ return;
272
+ } else if (a.keyPrefix === b.keyPrefix) {
273
+ 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.`;
274
+ } else if (b.keyPrefix.startsWith(a.keyPrefix + "/")) {
275
+ return `store "` + a.qualified + `" (` + a.bucketName + `/` + a.keyPrefix + `/) encloses "` + b.qualified + `" ` + (`(` + b.keyPrefix + `/) — wiping the first would delete the second's objects. Rename one.`);
276
+ } else {
277
+ return;
278
+ }
279
+ }));
280
+ if (message !== undefined) {
281
+ return {
282
+ TAG: "Error",
283
+ _0: message
284
+ };
285
+ } else {
286
+ return {
287
+ TAG: "Ok",
288
+ _0: undefined
289
+ };
290
+ }
291
+ }
292
+
201
293
  async function countTable(table) {
202
294
  let loop = async (start, acc) => {
203
295
  let out = await DynamoDb_DocumentClient$AwsSdk.ScanCommand.send(new LibDynamodb.ScanCommand({
@@ -216,10 +308,11 @@ async function countTable(table) {
216
308
  return await loop(undefined, 0);
217
309
  }
218
310
 
219
- async function countBucket(bucket) {
311
+ async function countBucket(bucket, prefix) {
220
312
  let loop = async (keyMarker, versionMarker, acc) => {
221
313
  let out = await S3$AwsSdk.ListObjectVersionsCommand.send(new ClientS3.ListObjectVersionsCommand({
222
314
  Bucket: bucket,
315
+ Prefix: prefix,
223
316
  KeyMarker: keyMarker,
224
317
  VersionIdMarker: versionMarker
225
318
  }));
@@ -306,10 +399,11 @@ async function truncateTable(table) {
306
399
  return await loop(undefined);
307
400
  }
308
401
 
309
- async function emptyBucket(bucket) {
402
+ async function emptyBucket(bucket, prefix) {
310
403
  let loop = async (keyMarker, versionMarker) => {
311
404
  let out = await S3$AwsSdk.ListObjectVersionsCommand.send(new ClientS3.ListObjectVersionsCommand({
312
405
  Bucket: bucket,
406
+ Prefix: prefix,
313
407
  KeyMarker: keyMarker,
314
408
  VersionIdMarker: versionMarker
315
409
  }));
@@ -341,6 +435,10 @@ async function emptyBucket(bucket) {
341
435
  return await loop(undefined, undefined);
342
436
  }
343
437
 
438
+ function pluginOf(t) {
439
+ return Stdlib_Option.getOr(t.plugin, t.label);
440
+ }
441
+
344
442
  async function chooseScope(targets) {
345
443
  let domain = targets.filter(t => t.group === "Domain");
346
444
  let platform = targets.filter(t => t.group === "Platform");
@@ -479,6 +577,15 @@ function reportAll(resolvedList, stack, region) {
479
577
  });
480
578
  if (r.bucketCounts.length === 0) {
481
579
  console.log(" (none)");
580
+ }
581
+ if (r.storeCounts.length !== 0) {
582
+ console.log(" Object stores:");
583
+ r.storeCounts.forEach(param => {
584
+ let c = param[1];
585
+ let s = param[0];
586
+ total.contents = total.contents + c | 0;
587
+ console.log(` ` + c.toString().padStart(8, " ") + ` ` + s.qualified + ` ` + (s.bucketName + `/` + s.keyPrefix + `/`));
588
+ });
482
589
  return;
483
590
  }
484
591
  });
@@ -507,7 +614,38 @@ function run(stack, backend, targets, param) {
507
614
  };
508
615
  }
509
616
  let selected = await chooseScope(targets);
510
- let regions = selected.map(t => gateTarget(t, backend$1, stack$1));
617
+ let platformTarget = targets.find(t => t.group === "Platform");
618
+ let allStores;
619
+ if (platformTarget !== undefined) {
620
+ let output = ReventlessSeedAws.stackOutputs(platformTarget.projectDir, backend$1, stack$1);
621
+ let stores = parseObjectStores(field(output, "objectStores"));
622
+ if (stores.TAG === "Ok") {
623
+ allStores = stores._0;
624
+ } else {
625
+ throw {
626
+ RE_EXN_ID: Seed$ReventlessSeed.Failed,
627
+ _1: stores._0,
628
+ Error: new Error()
629
+ };
630
+ }
631
+ } else {
632
+ console.log("");
633
+ console.log("Note: no `platform` target is declared, so declared object stores could not be resolved — any uploaded objects will be left in place.");
634
+ allStores = [];
635
+ }
636
+ let message = validateStores(allStores);
637
+ if (message.TAG !== "Ok") {
638
+ throw {
639
+ RE_EXN_ID: Seed$ReventlessSeed.Failed,
640
+ _1: `refusing: ` + message._0,
641
+ Error: new Error()
642
+ };
643
+ }
644
+ let storeBucketNames = allStores.map(s => s.bucketName);
645
+ let selectedStores = allStores.filter(s => selected.some(t => pluginOf(t) === s.plugin));
646
+ let match = selectedStores.length !== 0;
647
+ let gated = match && platformTarget !== undefined && !selected.some(t => t.projectDir === platformTarget.projectDir) ? selected.concat([platformTarget]) : selected;
648
+ let regions = gated.map(t => gateTarget(t, backend$1, stack$1));
511
649
  let region = regions[0];
512
650
  if (regions.some(r => r !== region)) {
513
651
  throw {
@@ -517,14 +655,29 @@ function run(stack, backend, targets, param) {
517
655
  };
518
656
  }
519
657
  process.env["AWS_REGION"] = region;
658
+ if (selectedStores.length !== 0 && platformTarget !== undefined) {
659
+ let platformProject = projectName(platformTarget.projectDir);
660
+ let match$1 = await discover(region, stack$1, platformProject);
661
+ let platformBuckets = match$1[1];
662
+ selectedStores.forEach(s => {
663
+ if (platformBuckets.includes(s.bucketName)) {
664
+ return;
665
+ }
666
+ throw {
667
+ RE_EXN_ID: Seed$ReventlessSeed.Failed,
668
+ _1: `refusing: store "` + s.qualified + `" names bucket ` + s.bucketName + `, which does not ` + (`carry reventless:platform=` + platformProject + ` + reventless:environment=` + stack$1 + `.`),
669
+ Error: new Error()
670
+ };
671
+ });
672
+ }
520
673
  let resolvedList = [];
521
674
  for (let i = 0, i_finish = selected.length; i < i_finish; ++i) {
522
675
  let target = selected[i];
523
676
  if (target !== undefined) {
524
677
  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);
678
+ let match$2 = await discover(region, stack$1, platform);
679
+ let tables = match$2[0].toSorted(Primitive_string.compare);
680
+ let buckets = match$2[1].filter(b => !storeBucketNames.includes(b)).toSorted(Primitive_string.compare);
528
681
  let tableCounts = [];
529
682
  for (let j = 0, j_finish = tables.length; j < j_finish; ++j) {
530
683
  let t = tables[j];
@@ -538,7 +691,18 @@ function run(stack, backend, targets, param) {
538
691
  if (b !== undefined) {
539
692
  bucketCounts.push([
540
693
  b,
541
- await countBucket(b)
694
+ await countBucket(b, undefined)
695
+ ]);
696
+ }
697
+ }
698
+ let stores$1 = selectedStores.filter(s => s.plugin === pluginOf(target));
699
+ let storeCounts = [];
700
+ for (let j$2 = 0, j_finish$2 = stores$1.length; j$2 < j_finish$2; ++j$2) {
701
+ let s = stores$1[j$2];
702
+ if (s !== undefined) {
703
+ storeCounts.push([
704
+ s,
705
+ await countBucket(s.bucketName, s.keyPrefix + `/`)
542
706
  ]);
543
707
  }
544
708
  }
@@ -547,7 +711,8 @@ function run(stack, backend, targets, param) {
547
711
  platform: platform,
548
712
  tables: tables,
549
713
  tableCounts: tableCounts,
550
- bucketCounts: bucketCounts
714
+ bucketCounts: bucketCounts,
715
+ storeCounts: storeCounts
551
716
  });
552
717
  }
553
718
  }
@@ -576,37 +741,54 @@ function run(stack, backend, targets, param) {
576
741
  let r = resolvedList[i$1];
577
742
  if (r !== undefined) {
578
743
  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];
744
+ for (let j$3 = 0, j_finish$3 = r.tables.length; j$3 < j_finish$3; ++j$3) {
745
+ let t$1 = r.tables[j$3];
581
746
  if (t$1 !== undefined) {
582
747
  await truncateTable(t$1);
583
748
  console.log(` truncated ` + t$1);
584
749
  }
585
750
  }
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);
751
+ for (let j$4 = 0, j_finish$4 = r.bucketCounts.length; j$4 < j_finish$4; ++j$4) {
752
+ let match$3 = r.bucketCounts[j$4];
753
+ if (match$3 !== undefined) {
754
+ let b$1 = match$3[0];
755
+ await emptyBucket(b$1, undefined);
591
756
  console.log(` emptied ` + b$1);
592
757
  }
593
758
  }
759
+ for (let j$5 = 0, j_finish$5 = r.storeCounts.length; j$5 < j_finish$5; ++j$5) {
760
+ let match$4 = r.storeCounts[j$5];
761
+ if (match$4 !== undefined) {
762
+ let s$1 = match$4[0];
763
+ await emptyBucket(s$1.bucketName, s$1.keyPrefix + `/`);
764
+ console.log(` emptied ` + s$1.qualified + ` — ` + match$4[1].toString() + ` object(s) removed from ` + (s$1.bucketName + `/` + s$1.keyPrefix + `/`));
765
+ }
766
+ }
594
767
  }
595
768
  }
596
769
  let remaining = 0;
597
770
  for (let i$2 = 0, i_finish$2 = resolvedList.length; i$2 < i_finish$2; ++i$2) {
598
771
  let r$1 = resolvedList[i$2];
599
772
  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];
773
+ for (let j$6 = 0, j_finish$6 = r$1.tables.length; j$6 < j_finish$6; ++j$6) {
774
+ let t$2 = r$1.tables[j$6];
602
775
  if (t$2 !== undefined) {
603
776
  remaining = remaining + await countTable(t$2) | 0;
604
777
  }
605
778
  }
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;
779
+ for (let j$7 = 0, j_finish$7 = r$1.bucketCounts.length; j$7 < j_finish$7; ++j$7) {
780
+ let match$5 = r$1.bucketCounts[j$7];
781
+ if (match$5 !== undefined) {
782
+ remaining = remaining + await countBucket(match$5[0], undefined) | 0;
783
+ }
784
+ }
785
+ for (let j$8 = 0, j_finish$8 = r$1.storeCounts.length; j$8 < j_finish$8; ++j$8) {
786
+ let match$6 = r$1.storeCounts[j$8];
787
+ if (match$6 !== undefined) {
788
+ let s$2 = match$6[0];
789
+ let left = await countBucket(s$2.bucketName, s$2.keyPrefix + `/`);
790
+ remaining = remaining + left | 0;
791
+ console.log(` verified empty: ` + s$2.qualified + ` — ` + left.toString() + ` object(s) remain under ` + (s$2.bucketName + `/` + s$2.keyPrefix + `/`));
610
792
  }
611
793
  }
612
794
  }
@@ -623,17 +805,17 @@ function run(stack, backend, targets, param) {
623
805
  process.exit(0);
624
806
  return;
625
807
  } catch (raw_message) {
626
- let message = Primitive_exceptions.internalToException(raw_message);
627
- if (message.RE_EXN_ID === Seed$ReventlessSeed.Failed) {
808
+ let message$1 = Primitive_exceptions.internalToException(raw_message);
809
+ if (message$1.RE_EXN_ID === Seed$ReventlessSeed.Failed) {
628
810
  Seed_Prompt$ReventlessSeed.close();
629
811
  console.error("");
630
- console.error(`Reset aborted — ` + message._1);
812
+ console.error(`Reset aborted — ` + message$1._1);
631
813
  process.exit(1);
632
814
  } else {
633
815
  Seed_Prompt$ReventlessSeed.close();
634
816
  console.error("");
635
817
  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"));
818
+ console.error(Stdlib_Option.getOr(Stdlib_Option.flatMap(Stdlib_JsExn.fromException(message$1), Stdlib_JsExn.message), "unknown"));
637
819
  process.exit(1);
638
820
  }
639
821
  return;
@@ -662,11 +844,15 @@ export {
662
844
  classify,
663
845
  tagValue,
664
846
  discover,
847
+ splitQualified,
848
+ parseObjectStores,
849
+ validateStores,
665
850
  countTable,
666
851
  countBucket,
667
852
  sendBatch,
668
853
  truncateTable,
669
854
  emptyBucket,
855
+ pluginOf,
670
856
  chooseScope,
671
857
  gateTarget,
672
858
  reportAll,
@@ -1,25 +1,22 @@
1
- // Which document `resolveEndpoints` reads, and what each arm takes from it.
1
+ // Which document `resolveEndpoints` reads, and which GraphQL endpoint each arm takes
2
+ // from it.
2
3
  //
3
4
  // `endpointsFrom` is the pure half of `resolveEndpoints`; the impure half is a
4
- // `pulumi stack output` subprocess and a `config.json` fetch, and the decision
5
- // these tests pin is in neither. The defect they lock out: **neither arm read
6
- // `uploadEndpoints`**, so a platform that publishes a presign endpoint per
7
- // declared store resolved "" and the seeder reported it as serving no uploads.
8
- // The stack-outputs arm is the one that matters a platform deploying no host
9
- // shell publishes no `hostShellUrl` by construction, so it takes that arm, and
10
- // the per-store endpoint is its only way to reach the store.
5
+ // `pulumi stack output` subprocess and a `config.json` fetch, and the decision these
6
+ // tests pin is in neither. Upload endpoints are no longer resolved here — under route B
7
+ // the seed mints through the domain API's `Upload_Presign` mutation on the GraphQL
8
+ // endpoint below so the only decision left is which GraphQL endpoint each source
9
+ // publishes, and the merged-over-per-plugin precedence within the stack-outputs arm.
11
10
 
12
11
  open JestGlobals
13
12
  open ReventlessSeed
14
13
 
15
-
16
14
  // Every value read here has an env override, and an ambient one in the runner's
17
- // environment (AWS_REGION is routinely set) would silently stand in for the
18
- // document under test. An empty string reads as unset.
15
+ // environment (AWS_REGION is routinely set) would silently stand in for the document
16
+ // under test. An empty string reads as unset.
19
17
  let clearOverrides = () =>
20
18
  [
21
19
  "REVENTLESS_GRAPHQL_ENDPOINT",
22
- "REVENTLESS_UPLOAD_ENDPOINT",
23
20
  "AWS_REGION",
24
21
  "COGNITO_CLIENT_ID",
25
22
  "SEED_SKIP_UPLOADS",
@@ -28,9 +25,6 @@ let clearOverrides = () =>
28
25
  let obj = entries => JSON.Encode.object(entries->Dict.fromArray)
29
26
  let str = JSON.Encode.string
30
27
 
31
- // A host shell's config.json and the stack outputs of a platform that serves no
32
- // shell — the two documents the two arms read, minus the upload keys each test
33
- // supplies.
34
28
  let config = (~extra: array<(string, JSON.t)>) =>
35
29
  obj(
36
30
  Array.concat(
@@ -55,84 +49,18 @@ let outputs = (~extra: array<(string, JSON.t)>) =>
55
49
  ),
56
50
  )
57
51
 
58
- let storeEndpoints = obj([("Catalog.productImages", str("https://presign.example/"))])
59
-
60
52
  describe("endpointsFrom — host shell arm", () => {
61
53
  beforeEach(clearOverrides)
62
54
 
63
- testSync("reads the legacy single service and the per-store map together", () => {
64
- let eps = ReventlessSeedAws.endpointsFrom(
65
- ~stack="alpha",
66
- HostShellConfig(
67
- config(
68
- ~extra=[
69
- ("uploadEndpoint", str("https://legacy.example/")),
70
- ("uploadEndpoints", storeEndpoints),
71
- ],
72
- ),
73
- ),
74
- )
75
- expect(eps.uploadEndpoint)->toBe("https://legacy.example/")
76
- expect(eps.uploadEndpoints)->toEqual(
77
- Dict.fromArray([("Catalog.productImages", "https://presign.example/")]),
78
- )
79
- })
80
-
81
- // A shell fronting only declared stores writes no singular key. That used to
82
- // fail the whole run before a command was sent ("deployment is missing
83
- // uploadEndpoint"), which is a harder failure than the one this plan fixes.
84
- testSync("a shell publishing only per-store endpoints resolves an empty legacy service", () => {
85
- let eps = ReventlessSeedAws.endpointsFrom(
86
- ~stack="alpha",
87
- HostShellConfig(config(~extra=[("uploadEndpoints", storeEndpoints)])),
88
- )
89
- expect(eps.uploadEndpoint)->toBe("")
90
- expect(eps.uploadEndpoints->Dict.keysToArray)->toEqual(["Catalog.productImages"])
91
- })
92
-
93
- testSync("REVENTLESS_UPLOAD_ENDPOINT overrides the legacy service and leaves the map alone", () => {
94
- NodeProcess.env->Dict.set("REVENTLESS_UPLOAD_ENDPOINT", "https://override.example/")
95
- let eps = ReventlessSeedAws.endpointsFrom(
96
- ~stack="alpha",
97
- HostShellConfig(
98
- config(
99
- ~extra=[
100
- ("uploadEndpoint", str("https://legacy.example/")),
101
- ("uploadEndpoints", storeEndpoints),
102
- ],
103
- ),
104
- ),
105
- )
106
- expect(eps.uploadEndpoint)->toBe("https://override.example/")
107
- expect(eps.uploadEndpoints->Dict.get("Catalog.productImages"))->toEqual(
108
- Some("https://presign.example/"),
109
- )
55
+ testSync("reads the GraphQL endpoint from the shell config", () => {
56
+ let eps = ReventlessSeedAws.endpointsFrom(~stack="alpha", HostShellConfig(config(~extra=[])))
57
+ expect(eps.graphql)->toBe("https://api.example/graphql")
110
58
  })
111
59
  })
112
60
 
113
61
  describe("endpointsFrom — stack outputs arm", () => {
114
62
  beforeEach(clearOverrides)
115
63
 
116
- // The lookup that was missing entirely: this arm had no upload source but the
117
- // env var, so a `PlatformOwned` deployment resolved "" whatever it published.
118
- testSync("reads the uploadEndpoints stack output", () => {
119
- let eps = ReventlessSeedAws.endpointsFrom(
120
- ~stack="pr-verify",
121
- StackOutputs(outputs(~extra=[("uploadEndpoints", storeEndpoints)])),
122
- )
123
- expect(eps.uploadEndpoints)->toEqual(
124
- Dict.fromArray([("Catalog.productImages", "https://presign.example/")]),
125
- )
126
- })
127
-
128
- // Declaring no store is a legitimate deployment, not a broken one — it stays a
129
- // no-op at the data set rather than failing the run.
130
- testSync("a deployment declaring no store resolves an empty map without failing", () => {
131
- let eps = ReventlessSeedAws.endpointsFrom(~stack="pr-verify", StackOutputs(outputs(~extra=[])))
132
- expect(eps.uploadEndpoint)->toBe("")
133
- expect(eps.uploadEndpoints->Dict.keysToArray)->toEqual([])
134
- })
135
-
136
64
  testSync("prefers the merged API endpoint over the per-plugin one", () => {
137
65
  let eps = ReventlessSeedAws.endpointsFrom(
138
66
  ~stack="pr-verify",
@@ -153,28 +81,3 @@ describe("endpointsFrom — stack outputs arm", () => {
153
81
  }
154
82
  )
155
83
  })
156
-
157
- describe("endpointsFrom — malformed uploadEndpoints", () => {
158
- beforeEach(clearOverrides)
159
-
160
- // One bad member should not cost the run every endpoint it could have used.
161
- testSync("drops a non-string member rather than the whole map", () => {
162
- let eps = ReventlessSeedAws.endpointsFrom(
163
- ~stack="pr-verify",
164
- StackOutputs(
165
- outputs(
166
- ~extra=[
167
- (
168
- "uploadEndpoints",
169
- obj([
170
- ("Catalog.productImages", str("https://presign.example/")),
171
- ("Catalog.broken", JSON.Encode.int(7)),
172
- ]),
173
- ),
174
- ],
175
- ),
176
- ),
177
- )
178
- expect(eps.uploadEndpoints->Dict.keysToArray)->toEqual(["Catalog.productImages"])
179
- })
180
- })
@@ -8,7 +8,6 @@ import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_excep
8
8
  function clearOverrides() {
9
9
  [
10
10
  "REVENTLESS_GRAPHQL_ENDPOINT",
11
- "REVENTLESS_UPLOAD_ENDPOINT",
12
11
  "AWS_REGION",
13
12
  "COGNITO_CLIENT_ID",
14
13
  "SEED_SKIP_UPLOADS"
@@ -59,87 +58,19 @@ function outputs(extra) {
59
58
  ].concat(extra));
60
59
  }
61
60
 
62
- let storeEndpoints = Object.fromEntries([[
63
- "Catalog.productImages",
64
- "https://presign.example/"
65
- ]]);
66
-
67
61
  globalThis.describe("endpointsFrom — host shell arm", () => {
68
62
  globalThis.beforeEach(clearOverrides);
69
- globalThis.test("reads the legacy single service and the per-store map together", () => {
70
- let eps = ReventlessSeedAws.endpointsFrom("alpha", {
71
- TAG: "HostShellConfig",
72
- _0: config([
73
- [
74
- "uploadEndpoint",
75
- "https://legacy.example/"
76
- ],
77
- [
78
- "uploadEndpoints",
79
- storeEndpoints
80
- ]
81
- ])
82
- });
83
- globalThis.expect(eps.uploadEndpoint).toBe("https://legacy.example/");
84
- globalThis.expect(eps.uploadEndpoints).toEqual(Object.fromEntries([[
85
- "Catalog.productImages",
86
- "https://presign.example/"
87
- ]]));
88
- });
89
- globalThis.test("a shell publishing only per-store endpoints resolves an empty legacy service", () => {
63
+ globalThis.test("reads the GraphQL endpoint from the shell config", () => {
90
64
  let eps = ReventlessSeedAws.endpointsFrom("alpha", {
91
65
  TAG: "HostShellConfig",
92
- _0: config([[
93
- "uploadEndpoints",
94
- storeEndpoints
95
- ]])
66
+ _0: config([])
96
67
  });
97
- globalThis.expect(eps.uploadEndpoint).toBe("");
98
- globalThis.expect(Object.keys(eps.uploadEndpoints)).toEqual(["Catalog.productImages"]);
99
- });
100
- globalThis.test("REVENTLESS_UPLOAD_ENDPOINT overrides the legacy service and leaves the map alone", () => {
101
- process.env["REVENTLESS_UPLOAD_ENDPOINT"] = "https://override.example/";
102
- let eps = ReventlessSeedAws.endpointsFrom("alpha", {
103
- TAG: "HostShellConfig",
104
- _0: config([
105
- [
106
- "uploadEndpoint",
107
- "https://legacy.example/"
108
- ],
109
- [
110
- "uploadEndpoints",
111
- storeEndpoints
112
- ]
113
- ])
114
- });
115
- globalThis.expect(eps.uploadEndpoint).toBe("https://override.example/");
116
- globalThis.expect(eps.uploadEndpoints["Catalog.productImages"]).toEqual("https://presign.example/");
68
+ globalThis.expect(eps.graphql).toBe("https://api.example/graphql");
117
69
  });
118
70
  });
119
71
 
120
72
  globalThis.describe("endpointsFrom — stack outputs arm", () => {
121
73
  globalThis.beforeEach(clearOverrides);
122
- globalThis.test("reads the uploadEndpoints stack output", () => {
123
- let eps = ReventlessSeedAws.endpointsFrom("pr-verify", {
124
- TAG: "StackOutputs",
125
- _0: outputs([[
126
- "uploadEndpoints",
127
- storeEndpoints
128
- ]])
129
- });
130
- globalThis.expect(eps.uploadEndpoints).toEqual(Object.fromEntries([[
131
- "Catalog.productImages",
132
- "https://presign.example/"
133
- ]]));
134
- });
135
- globalThis.test("a deployment declaring no store resolves an empty map without failing", () => {
136
- let eps = ReventlessSeedAws.endpointsFrom("pr-verify", {
137
- TAG: "StackOutputs",
138
- _0: outputs([])
139
- });
140
- globalThis.expect(eps.uploadEndpoint).toBe("");
141
- globalThis.expect(Object.keys(eps.uploadEndpoints)).toEqual([]);
142
- });
143
74
  globalThis.test("prefers the merged API endpoint over the per-plugin one", () => {
144
75
  let eps = ReventlessSeedAws.endpointsFrom("pr-verify", {
145
76
  TAG: "StackOutputs",
@@ -174,35 +105,11 @@ globalThis.describe("endpointsFrom — stack outputs arm", () => {
174
105
  });
175
106
  });
176
107
 
177
- globalThis.describe("endpointsFrom — malformed uploadEndpoints", () => {
178
- globalThis.beforeEach(clearOverrides);
179
- globalThis.test("drops a non-string member rather than the whole map", () => {
180
- let eps = ReventlessSeedAws.endpointsFrom("pr-verify", {
181
- TAG: "StackOutputs",
182
- _0: outputs([[
183
- "uploadEndpoints",
184
- Object.fromEntries([
185
- [
186
- "Catalog.productImages",
187
- "https://presign.example/"
188
- ],
189
- [
190
- "Catalog.broken",
191
- 7
192
- ]
193
- ])
194
- ]])
195
- });
196
- globalThis.expect(Object.keys(eps.uploadEndpoints)).toEqual(["Catalog.productImages"]);
197
- });
198
- });
199
-
200
108
  export {
201
109
  clearOverrides,
202
110
  obj,
203
111
  str,
204
112
  config,
205
113
  outputs,
206
- storeEndpoints,
207
114
  }
208
- /* storeEndpoints Not a pure module */
115
+ /* Not a pure module */