@reventlessdev/reventless-seed-aws 1.0.0-alpha.5 → 1.0.0-alpha.7

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 (42) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/lib/bs/.compiler.log +2 -2
  3. package/lib/bs/.sourcedirs.json +1 -1
  4. package/lib/bs/compiler-info.json +2 -2
  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 +9 -54
  10. package/lib/bs/src/ReventlessSeedAws.res.mjs +1 -30
  11. package/lib/bs/src/ReventlessSeedAws_Reset.ast +0 -0
  12. package/lib/bs/src/ReventlessSeedAws_Reset.cmi +0 -0
  13. package/lib/bs/src/ReventlessSeedAws_Reset.cmt +0 -0
  14. package/lib/bs/src/ReventlessSeedAws_Reset.res +8 -15
  15. package/lib/bs/tests/EndpointResolutionTest.ast +0 -0
  16. package/lib/bs/tests/EndpointResolutionTest.cmi +0 -0
  17. package/lib/bs/tests/EndpointResolutionTest.cmj +0 -0
  18. package/lib/bs/tests/EndpointResolutionTest.cmt +0 -0
  19. package/lib/bs/tests/EndpointResolutionTest.res +13 -111
  20. package/lib/bs/tests/EndpointResolutionTest.res.mjs +4 -97
  21. package/lib/ocaml/.compiler.log +2 -2
  22. package/lib/ocaml/EndpointResolutionTest.ast +0 -0
  23. package/lib/ocaml/EndpointResolutionTest.cmi +0 -0
  24. package/lib/ocaml/EndpointResolutionTest.cmj +0 -0
  25. package/lib/ocaml/EndpointResolutionTest.cmt +0 -0
  26. package/lib/ocaml/EndpointResolutionTest.res +13 -111
  27. package/lib/ocaml/ReventlessSeedAws.ast +0 -0
  28. package/lib/ocaml/ReventlessSeedAws.cmi +0 -0
  29. package/lib/ocaml/ReventlessSeedAws.cmj +0 -0
  30. package/lib/ocaml/ReventlessSeedAws.cmt +0 -0
  31. package/lib/ocaml/ReventlessSeedAws.res +9 -54
  32. package/lib/ocaml/ReventlessSeedAws_Reset.ast +0 -0
  33. package/lib/ocaml/ReventlessSeedAws_Reset.cmi +0 -0
  34. package/lib/ocaml/ReventlessSeedAws_Reset.cmt +0 -0
  35. package/lib/ocaml/ReventlessSeedAws_Reset.res +8 -15
  36. package/package.json +5 -4
  37. package/rescript.json +1 -0
  38. package/src/ReventlessSeedAws.res +9 -54
  39. package/src/ReventlessSeedAws.res.mjs +1 -30
  40. package/src/ReventlessSeedAws_Reset.res +8 -15
  41. package/tests/EndpointResolutionTest.res +13 -111
  42. package/tests/EndpointResolutionTest.res.mjs +4 -97
package/CHANGELOG.md CHANGED
@@ -3,6 +3,21 @@
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.7 (2026-08-01)
7
+
8
+ ### Features
9
+
10
+ * **upload:** add the release half of the upload contract via the domain API ([448f887](https://github.com/ReventlessDev/reventless-core/commit/448f88714a5875be420f794a08d482fcf4ba8404))
11
+
12
+
13
+ # 1.0.0-alpha.6 (2026-07-31)
14
+
15
+ **Note:** Version bump only for package @reventlessdev/reventless-seed-aws
16
+
17
+
18
+
19
+
20
+
6
21
  # 1.0.0-alpha.5 (2026-07-31)
7
22
 
8
23
  ### Bug Fixes
@@ -1,2 +1,2 @@
1
- #Start(1785495045190)
2
- #Done(1785495045219)
1
+ #Start(1785603404469)
2
+ #Done(1785603404495)
@@ -1 +1 @@
1
- {"cmt_scan":[{"also_scan_build_root":true,"build_root":"lib/bs","scan_dirs":["src","tests"]}],"dirs":["src","tests"],"generated":[],"pkgs":[["@reventlessdev/rescript-aws-sdk","/home/runner/work/reventless-core/reventless-core/rescript/aws-sdk"],["@reventlessdev/rescript-jest","/home/runner/work/reventless-core/reventless-core/rescript/jest"],["@reventlessdev/reventless-seed","/home/runner/work/reventless-core/reventless-core/reventless/seed"]],"version":2}
1
+ {"cmt_scan":[{"also_scan_build_root":true,"build_root":"lib/bs","scan_dirs":["src","tests"]}],"dirs":["src","tests"],"generated":[],"pkgs":[["@reventlessdev/rescript-aws-sdk","/home/runner/work/reventless-core/reventless-core/rescript/aws-sdk"],["@reventlessdev/rescript-jest","/home/runner/work/reventless-core/reventless-core/rescript/jest"],["@reventlessdev/rescript-node","/home/runner/work/reventless-core/reventless-core/rescript/node"],["@reventlessdev/reventless-seed","/home/runner/work/reventless-core/reventless-core/reventless/seed"]],"version":2}
@@ -2,7 +2,7 @@
2
2
  "version": "12.3.0",
3
3
  "bsc_path": "/home/runner/work/reventless-core/reventless-core/node_modules/@rescript/linux-x64/bin/bsc.exe",
4
4
  "bsc_hash": "75e3a59c95cc953608fd3dd6ea6ed68141bba4414a20a52f114261b8a48385fa",
5
- "rescript_config_hash": "80febfc1b083fe35268276ef15c3829eae3bbacfedb30515f97c99ea938ae1a4",
5
+ "rescript_config_hash": "c18a0067c363fd1290f6e7f6fe6212d2e16e201c1702fac667962047f88ed468",
6
6
  "runtime_path": "/home/runner/work/reventless-core/reventless-core/node_modules/@rescript/runtime",
7
- "generated_at": "1785495045225"
7
+ "generated_at": "1785603404501"
8
8
  }
Binary file
Binary file
Binary file
Binary file
@@ -14,11 +14,6 @@ open ReventlessSeed
14
14
 
15
15
  // ── Node bindings ─────────────────────────────────────────────────────────────
16
16
 
17
- @val @scope("process") external processEnv: dict<string> = "env"
18
-
19
- type execOptions = {cwd: string, encoding: string, env?: dict<string>}
20
- @module("node:child_process")
21
- external execFileSync: (string, array<string>, execOptions) => string = "execFileSync"
22
17
 
23
18
  type fetchInit = {method: string, headers: dict<string>, body?: string}
24
19
  type response
@@ -41,18 +36,6 @@ let asString = (json: JSON.t): option<string> =>
41
36
  | _ => None
42
37
  }
43
38
 
44
- // Non-string members are dropped rather than failing the whole map: one
45
- // malformed entry should not cost a run every endpoint it could have used.
46
- let asStringDict = (json: JSON.t): dict<string> =>
47
- switch json {
48
- | Object(obj) =>
49
- obj
50
- ->Dict.toArray
51
- ->Array.filterMap(((k, v)) => v->asString->Option.map(s => (k, s)))
52
- ->Dict.fromArray
53
- | _ => Dict.make()
54
- }
55
-
56
39
  // ── Stack discovery ───────────────────────────────────────────────────────────
57
40
 
58
41
  // Which Pulumi backend the `pulumi` subprocess reads from. When `backend` is
@@ -65,13 +48,17 @@ let envForBackend = (backend: option<string>): option<dict<string>> =>
65
48
  switch backend {
66
49
  | None => None
67
50
  | Some(url) =>
68
- let copy = processEnv->Dict.toArray->Dict.fromArray
51
+ let copy = NodeProcess.env->Dict.toArray->Dict.fromArray
69
52
  copy->Dict.set("PULUMI_BACKEND_URL", url)
70
53
  Some(copy)
71
54
  }
72
55
 
73
56
  let pulumi = (~projectDir: string, ~backend: option<string>, args: array<string>): string =>
74
- execFileSync("pulumi", args, {cwd: projectDir, encoding: "utf8", env: ?envForBackend(backend)})
57
+ NodeChildProcess.execFileSync(
58
+ "pulumi",
59
+ args,
60
+ {cwd: projectDir, encoding: "utf8", env: ?envForBackend(backend)},
61
+ )
75
62
 
76
63
  // Stacks that actually exist in the Pulumi backend for this project — the names
77
64
  // `pulumi stack output --stack <name>` accepts. A `Pulumi.<stack>.yaml` config
@@ -159,16 +146,6 @@ let resolveField = (~envKey: string, ~fromSource: option<string>, ~human: string
159
146
  }
160
147
  }
161
148
 
162
- // Same precedence, for a value whose absence is a legitimate answer rather than
163
- // a broken deployment: a stack that declares no store publishes no upload
164
- // endpoint, and that must stay a no-op at the data set instead of failing the
165
- // run before a single command is sent.
166
- let optionalField = (~envKey: string, ~fromSource: option<string>): string =>
167
- switch Seed.Prompt.envValue(envKey) {
168
- | Some(v) => v
169
- | None => fromSource->Option.getOr("")
170
- }
171
-
172
149
  // Which document publishes the deployment's endpoints. A stack that serves a
173
150
  // host shell publishes them in the shell's `config.json` under the client's key
174
151
  // names; one that does not publishes them as stack outputs under Pulumi's. The
@@ -178,11 +155,6 @@ type source = HostShellConfig(JSON.t) | StackOutputs(JSON.t)
178
155
 
179
156
  type endpoints = {
180
157
  graphql: string,
181
- // The legacy single presign service; "" when the deployment publishes none.
182
- uploadEndpoint: string,
183
- // Qualified `{plugin}.{store}` → that store's presign endpoint. Empty when the
184
- // deployment declares no store.
185
- uploadEndpoints: dict<string>,
186
158
  cognitoRegion: string,
187
159
  cognitoClientId: string,
188
160
  }
@@ -191,15 +163,9 @@ type endpoints = {
191
163
  * The endpoints a source document publishes — pure, so the branch selection and
192
164
  * every key it reads can be exercised with synthetic documents.
193
165
  *
194
- * `uploadEndpoints` is read on **both** arms. It was read on neither: the
195
- * host-shell arm looked only at the singular `uploadEndpoint`, and the
196
- * stack-output arm had no upload lookup at all, so a platform that publishes its
197
- * stores and no host shell resolved "" and reported itself as serving no
198
- * uploads.
199
- *
200
- * `REVENTLESS_UPLOAD_ENDPOINT` still overrides the singular endpoint and does
201
- * not touch the map: one string cannot express a map, so it could only ever
202
- * override one store and would need a naming convention to say which.
166
+ * Upload endpoints are no longer resolved here: under route B the seed mints through
167
+ * the domain API's `Upload_Presign` mutation on `graphql`, passing the store per asset,
168
+ * so there is no per-store URL to discover.
203
169
  */
204
170
  let endpointsFrom = (~stack: string, source: source): endpoints =>
205
171
  switch source {
@@ -211,11 +177,6 @@ let endpointsFrom = (~stack: string, source: source): endpoints =>
211
177
  ~fromSource=fromCfg("apiEndpoint"),
212
178
  ~human="apiEndpoint",
213
179
  ),
214
- uploadEndpoint: optionalField(
215
- ~envKey="REVENTLESS_UPLOAD_ENDPOINT",
216
- ~fromSource=fromCfg("uploadEndpoint"),
217
- ),
218
- uploadEndpoints: cfg->field("uploadEndpoints")->Option.mapOr(Dict.make(), asStringDict),
219
180
  cognitoRegion: resolveField(
220
181
  ~envKey="AWS_REGION",
221
182
  ~fromSource=fromCfg("region"),
@@ -243,10 +204,6 @@ let endpointsFrom = (~stack: string, source: source): endpoints =>
243
204
  ),
244
205
  )
245
206
  },
246
- // No stack output carries the legacy single service — it exists only in a
247
- // host shell's config.json — so here the env override is its only source.
248
- uploadEndpoint: optionalField(~envKey="REVENTLESS_UPLOAD_ENDPOINT", ~fromSource=None),
249
- uploadEndpoints: outputs->field("uploadEndpoints")->Option.mapOr(Dict.make(), asStringDict),
250
207
  cognitoRegion: resolveField(
251
208
  ~envKey="AWS_REGION",
252
209
  ~fromSource=out("cognitoRegion"),
@@ -366,8 +323,6 @@ let connect = (~projectDir: string=".", ~stack=?, ~backend=?, ()): (
366
323
  await Seed.Connect.make(
367
324
  ~label=stackName,
368
325
  ~endpoint=eps.graphql,
369
- ~uploadEndpoint=eps.uploadEndpoint,
370
- ~uploadEndpoints=eps.uploadEndpoints,
371
326
  ~login=cognito(~region=eps.cognitoRegion, ~clientId=eps.cognitoClientId),
372
327
  )
373
328
  }
@@ -19,20 +19,6 @@ function asString(json) {
19
19
  }
20
20
  }
21
21
 
22
- function asStringDict(json) {
23
- if (typeof json === "object" && json !== null && !Array.isArray(json)) {
24
- return Object.fromEntries(Stdlib_Array.filterMap(Object.entries(json), param => {
25
- let k = param[0];
26
- return Stdlib_Option.map(asString(param[1]), s => [
27
- k,
28
- s
29
- ]);
30
- }));
31
- } else {
32
- return {};
33
- }
34
- }
35
-
36
22
  function envForBackend(backend) {
37
23
  if (backend === undefined) {
38
24
  return;
@@ -166,23 +152,12 @@ function resolveField(envKey, fromSource, human) {
166
152
  };
167
153
  }
168
154
 
169
- function optionalField(envKey, fromSource) {
170
- let v = Seed_Prompt$ReventlessSeed.envValue(envKey);
171
- if (v !== undefined) {
172
- return v;
173
- } else {
174
- return Stdlib_Option.getOr(fromSource, "");
175
- }
176
- }
177
-
178
155
  function endpointsFrom(stack, source) {
179
156
  if (source.TAG === "HostShellConfig") {
180
157
  let cfg = source._0;
181
158
  let fromCfg = key => Stdlib_Option.flatMap(field(cfg, key), asString);
182
159
  return {
183
160
  graphql: resolveField("REVENTLESS_GRAPHQL_ENDPOINT", fromCfg("apiEndpoint"), "apiEndpoint"),
184
- uploadEndpoint: optionalField("REVENTLESS_UPLOAD_ENDPOINT", fromCfg("uploadEndpoint")),
185
- uploadEndpoints: Stdlib_Option.mapOr(field(cfg, "uploadEndpoints"), {}, asStringDict),
186
161
  cognitoRegion: resolveField("AWS_REGION", fromCfg("region"), "region"),
187
162
  cognitoClientId: resolveField("COGNITO_CLIENT_ID", fromCfg("cognitoClientId"), "cognitoClientId")
188
163
  };
@@ -208,8 +183,6 @@ function endpointsFrom(stack, source) {
208
183
  }
209
184
  return {
210
185
  graphql: tmp,
211
- uploadEndpoint: optionalField("REVENTLESS_UPLOAD_ENDPOINT", undefined),
212
- uploadEndpoints: Stdlib_Option.mapOr(field(outputs, "uploadEndpoints"), {}, asStringDict),
213
186
  cognitoRegion: resolveField("AWS_REGION", out("cognitoRegion"), "cognitoRegion"),
214
187
  cognitoClientId: resolveField("COGNITO_CLIENT_ID", out("cognitoUserPoolClientId"), "cognitoUserPoolClientId")
215
188
  };
@@ -313,14 +286,13 @@ function connect($staropt$star, stack, backend, param) {
313
286
  let backend$1 = url !== undefined ? url : backend;
314
287
  let stackName = await resolveStack(projectDir, backend$1, stack);
315
288
  let eps = await resolveEndpoints(projectDir, backend$1, stackName);
316
- return await Seed_Connect$ReventlessSeed.make(stackName, eps.graphql, eps.uploadEndpoint, eps.uploadEndpoints, cognito(eps.cognitoRegion, eps.cognitoClientId), undefined);
289
+ return await Seed_Connect$ReventlessSeed.make(stackName, eps.graphql, cognito(eps.cognitoRegion, eps.cognitoClientId), undefined);
317
290
  };
318
291
  }
319
292
 
320
293
  export {
321
294
  field,
322
295
  asString,
323
- asStringDict,
324
296
  envForBackend,
325
297
  pulumi,
326
298
  deployedStacks,
@@ -329,7 +301,6 @@ export {
329
301
  resolveStack,
330
302
  fetchConfig,
331
303
  resolveField,
332
- optionalField,
333
304
  endpointsFrom,
334
305
  resolveEndpoints,
335
306
  cognito,
@@ -48,14 +48,7 @@ module Ddb = AwsSdk.DynamoDb
48
48
  module Rgt = AwsSdk.ResourceGroupsTaggingApi
49
49
  module S3 = AwsSdk.S3
50
50
 
51
- @scope("process") @val external exit: int => unit = "exit"
52
- @scope("process") @val external processEnv: dict<string> = "env"
53
- @module("node:fs") external readFileSync: (string, string) => string = "readFileSync"
54
51
 
55
- type stream
56
- @scope("process") @val external stdin: stream = "stdin"
57
- // `process.stdin.isTTY` is `true` interactively and `undefined` under a pipe/CI.
58
- @get external isTTY: stream => option<bool> = "isTTY"
59
52
 
60
53
  // The Pulumi project name, which the framework stamps as `reventless:platform` on
61
54
  // every resource (`Plugin.res`: `platformName = getProjectName()`). Discovery
@@ -66,7 +59,7 @@ type stream
66
59
  // the target project's Pulumi.yaml — the same dir the pulumi subprocess uses.
67
60
  let projectName = (~projectDir: string): string => {
68
61
  let path = `${projectDir}/Pulumi.yaml`
69
- let raw = try readFileSync(path, "utf8") catch {
62
+ let raw = try NodeFs.readFileSync(path) catch {
70
63
  | _ => throw(Seed.Failed(`could not read ${path} to scope the wipe to this Pulumi project.`))
71
64
  }
72
65
  switch raw
@@ -561,7 +554,7 @@ let run = (~stack=?, ~backend=?, ~targets: array<target>, ()): unit => {
561
554
  ),
562
555
  )
563
556
  }
564
- processEnv->Dict.set("AWS_REGION", region)
557
+ NodeProcess.env->Dict.set("AWS_REGION", region)
565
558
 
566
559
  // Discover + count each target, scoped to its own project via the platform
567
560
  // tag so a same-named stack from another project is never touched.
@@ -597,7 +590,7 @@ let run = (~stack=?, ~backend=?, ~targets: array<target>, ()): unit => {
597
590
  Seed.Prompt.close()
598
591
  Console.log("")
599
592
  Console.log(`Nothing to reset — the selected scope already reads empty in ${region}.`)
600
- exit(0)
593
+ NodeProcess.exit(0)
601
594
  }
602
595
 
603
596
  // Confirmation. Interactively, re-typing the exact stack name IS the
@@ -606,7 +599,7 @@ let run = (~stack=?, ~backend=?, ~targets: array<target>, ()): unit => {
606
599
  // TTY (CI/scripts) there is nothing to type into, so
607
600
  // REVENTLESS_WIPE_CONFIRM=<stack> is the equivalent opt-in. Dry-run is the
608
601
  // default either way.
609
- let interactive = stdin->isTTY->Option.getOr(false)
602
+ let interactive = NodeProcess.stdin->NodeProcess.isTTY->Option.getOr(false)
610
603
  let confirmed = if interactive {
611
604
  let typed = await Seed.Prompt.ask(
612
605
  `About to permanently empty ${total->Int.toString} item(s)/object(s) across the selected scope of "${stack}". ` ++
@@ -624,7 +617,7 @@ let run = (~stack=?, ~backend=?, ~targets: array<target>, ()): unit => {
624
617
  ? "Dry run — nothing was deleted."
625
618
  : `Dry run — nothing was deleted. Set REVENTLESS_WIPE_CONFIRM=${stack} to empty this scope non-interactively.`,
626
619
  )
627
- exit(0)
620
+ NodeProcess.exit(0)
628
621
  }
629
622
 
630
623
  for i in 0 to resolvedList->Array.length - 1 {
@@ -681,19 +674,19 @@ let run = (~stack=?, ~backend=?, ~targets: array<target>, ()): unit => {
681
674
 
682
675
  Console.log("")
683
676
  Console.log(`Reset complete — the selected scope of "${stack}" reads empty and is re-seedable.`)
684
- exit(0)
677
+ NodeProcess.exit(0)
685
678
  } catch {
686
679
  | Seed.Failed(message) =>
687
680
  Seed.Prompt.close()
688
681
  Console.error("")
689
682
  Console.error(`Reset aborted — ${message}`)
690
- exit(1)
683
+ NodeProcess.exit(1)
691
684
  | exn =>
692
685
  Seed.Prompt.close()
693
686
  Console.error("")
694
687
  Console.error("Reset aborted with an unexpected error:")
695
688
  Console.error(exn->JsExn.fromException->Option.flatMap(JsExn.message)->Option.getOr("unknown"))
696
- exit(1)
689
+ NodeProcess.exit(1)
697
690
  }
698
691
  }
699
692
  go()->ignore
@@ -1,37 +1,30 @@
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
- @val @scope("process") external processEnv: dict<string> = "env"
16
-
17
14
  // Every value read here has an env override, and an ambient one in the runner's
18
- // environment (AWS_REGION is routinely set) would silently stand in for the
19
- // 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.
20
17
  let clearOverrides = () =>
21
18
  [
22
19
  "REVENTLESS_GRAPHQL_ENDPOINT",
23
- "REVENTLESS_UPLOAD_ENDPOINT",
24
20
  "AWS_REGION",
25
21
  "COGNITO_CLIENT_ID",
26
22
  "SEED_SKIP_UPLOADS",
27
- ]->Array.forEach(k => processEnv->Dict.set(k, ""))
23
+ ]->Array.forEach(k => NodeProcess.env->Dict.set(k, ""))
28
24
 
29
25
  let obj = entries => JSON.Encode.object(entries->Dict.fromArray)
30
26
  let str = JSON.Encode.string
31
27
 
32
- // A host shell's config.json and the stack outputs of a platform that serves no
33
- // shell — the two documents the two arms read, minus the upload keys each test
34
- // supplies.
35
28
  let config = (~extra: array<(string, JSON.t)>) =>
36
29
  obj(
37
30
  Array.concat(
@@ -56,84 +49,18 @@ let outputs = (~extra: array<(string, JSON.t)>) =>
56
49
  ),
57
50
  )
58
51
 
59
- let storeEndpoints = obj([("Catalog.productImages", str("https://presign.example/"))])
60
-
61
52
  describe("endpointsFrom — host shell arm", () => {
62
53
  beforeEach(clearOverrides)
63
54
 
64
- testSync("reads the legacy single service and the per-store map together", () => {
65
- let eps = ReventlessSeedAws.endpointsFrom(
66
- ~stack="alpha",
67
- HostShellConfig(
68
- config(
69
- ~extra=[
70
- ("uploadEndpoint", str("https://legacy.example/")),
71
- ("uploadEndpoints", storeEndpoints),
72
- ],
73
- ),
74
- ),
75
- )
76
- expect(eps.uploadEndpoint)->toBe("https://legacy.example/")
77
- expect(eps.uploadEndpoints)->toEqual(
78
- Dict.fromArray([("Catalog.productImages", "https://presign.example/")]),
79
- )
80
- })
81
-
82
- // A shell fronting only declared stores writes no singular key. That used to
83
- // fail the whole run before a command was sent ("deployment is missing
84
- // uploadEndpoint"), which is a harder failure than the one this plan fixes.
85
- testSync("a shell publishing only per-store endpoints resolves an empty legacy service", () => {
86
- let eps = ReventlessSeedAws.endpointsFrom(
87
- ~stack="alpha",
88
- HostShellConfig(config(~extra=[("uploadEndpoints", storeEndpoints)])),
89
- )
90
- expect(eps.uploadEndpoint)->toBe("")
91
- expect(eps.uploadEndpoints->Dict.keysToArray)->toEqual(["Catalog.productImages"])
92
- })
93
-
94
- testSync("REVENTLESS_UPLOAD_ENDPOINT overrides the legacy service and leaves the map alone", () => {
95
- processEnv->Dict.set("REVENTLESS_UPLOAD_ENDPOINT", "https://override.example/")
96
- let eps = ReventlessSeedAws.endpointsFrom(
97
- ~stack="alpha",
98
- HostShellConfig(
99
- config(
100
- ~extra=[
101
- ("uploadEndpoint", str("https://legacy.example/")),
102
- ("uploadEndpoints", storeEndpoints),
103
- ],
104
- ),
105
- ),
106
- )
107
- expect(eps.uploadEndpoint)->toBe("https://override.example/")
108
- expect(eps.uploadEndpoints->Dict.get("Catalog.productImages"))->toEqual(
109
- Some("https://presign.example/"),
110
- )
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")
111
58
  })
112
59
  })
113
60
 
114
61
  describe("endpointsFrom — stack outputs arm", () => {
115
62
  beforeEach(clearOverrides)
116
63
 
117
- // The lookup that was missing entirely: this arm had no upload source but the
118
- // env var, so a `PlatformOwned` deployment resolved "" whatever it published.
119
- testSync("reads the uploadEndpoints stack output", () => {
120
- let eps = ReventlessSeedAws.endpointsFrom(
121
- ~stack="pr-verify",
122
- StackOutputs(outputs(~extra=[("uploadEndpoints", storeEndpoints)])),
123
- )
124
- expect(eps.uploadEndpoints)->toEqual(
125
- Dict.fromArray([("Catalog.productImages", "https://presign.example/")]),
126
- )
127
- })
128
-
129
- // Declaring no store is a legitimate deployment, not a broken one — it stays a
130
- // no-op at the data set rather than failing the run.
131
- testSync("a deployment declaring no store resolves an empty map without failing", () => {
132
- let eps = ReventlessSeedAws.endpointsFrom(~stack="pr-verify", StackOutputs(outputs(~extra=[])))
133
- expect(eps.uploadEndpoint)->toBe("")
134
- expect(eps.uploadEndpoints->Dict.keysToArray)->toEqual([])
135
- })
136
-
137
64
  testSync("prefers the merged API endpoint over the per-plugin one", () => {
138
65
  let eps = ReventlessSeedAws.endpointsFrom(
139
66
  ~stack="pr-verify",
@@ -154,28 +81,3 @@ describe("endpointsFrom — stack outputs arm", () => {
154
81
  }
155
82
  )
156
83
  })
157
-
158
- describe("endpointsFrom — malformed uploadEndpoints", () => {
159
- beforeEach(clearOverrides)
160
-
161
- // One bad member should not cost the run every endpoint it could have used.
162
- testSync("drops a non-string member rather than the whole map", () => {
163
- let eps = ReventlessSeedAws.endpointsFrom(
164
- ~stack="pr-verify",
165
- StackOutputs(
166
- outputs(
167
- ~extra=[
168
- (
169
- "uploadEndpoints",
170
- obj([
171
- ("Catalog.productImages", str("https://presign.example/")),
172
- ("Catalog.broken", JSON.Encode.int(7)),
173
- ]),
174
- ),
175
- ],
176
- ),
177
- ),
178
- )
179
- expect(eps.uploadEndpoints->Dict.keysToArray)->toEqual(["Catalog.productImages"])
180
- })
181
- })
@@ -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 */
@@ -1,2 +1,2 @@
1
- #Start(1785495045190)
2
- #Done(1785495045219)
1
+ #Start(1785603404469)
2
+ #Done(1785603404495)