@reventlessdev/reventless-seed-aws 1.0.0-alpha.3 → 1.0.0-alpha.30
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.
- package/CHANGELOG.md +207 -0
- package/lib/bs/.compiler.log +2 -2
- package/lib/bs/.sourcedirs.json +1 -0
- package/lib/bs/compiler-info.json +2 -2
- package/lib/bs/src/ReventlessSeedAws.ast +0 -0
- package/lib/bs/src/ReventlessSeedAws.cmi +0 -0
- package/lib/bs/src/ReventlessSeedAws.cmj +0 -0
- package/lib/bs/src/ReventlessSeedAws.cmt +0 -0
- package/lib/bs/src/ReventlessSeedAws.res +198 -134
- package/lib/bs/src/ReventlessSeedAws.res.mjs +57 -31
- package/lib/bs/src/ReventlessSeedAws_Quiesce.ast +0 -0
- package/lib/bs/src/ReventlessSeedAws_Quiesce.cmi +0 -0
- package/lib/bs/src/ReventlessSeedAws_Quiesce.cmj +0 -0
- package/lib/bs/src/ReventlessSeedAws_Quiesce.cmt +0 -0
- package/lib/bs/src/ReventlessSeedAws_Quiesce.res +307 -0
- package/lib/bs/src/ReventlessSeedAws_Quiesce.res.mjs +217 -0
- package/lib/bs/src/ReventlessSeedAws_Reconcile.ast +0 -0
- package/lib/bs/src/ReventlessSeedAws_Reconcile.cmi +0 -0
- package/lib/bs/src/ReventlessSeedAws_Reconcile.cmj +0 -0
- package/lib/bs/src/ReventlessSeedAws_Reconcile.cmt +0 -0
- package/lib/bs/src/ReventlessSeedAws_Reconcile.res +391 -0
- package/lib/bs/src/ReventlessSeedAws_Reconcile.res.mjs +318 -0
- package/lib/bs/src/ReventlessSeedAws_Reset.ast +0 -0
- package/lib/bs/src/ReventlessSeedAws_Reset.cmi +0 -0
- package/lib/bs/src/ReventlessSeedAws_Reset.cmj +0 -0
- package/lib/bs/src/ReventlessSeedAws_Reset.cmt +0 -0
- package/lib/bs/src/ReventlessSeedAws_Reset.res +1103 -0
- package/lib/bs/src/ReventlessSeedAws_Reset.res.mjs +991 -0
- package/lib/bs/tests/EndpointResolutionTest.ast +0 -0
- package/lib/bs/tests/EndpointResolutionTest.cmi +0 -0
- package/lib/bs/tests/EndpointResolutionTest.cmj +0 -0
- package/lib/bs/tests/EndpointResolutionTest.cmt +0 -0
- package/lib/bs/tests/EndpointResolutionTest.res +83 -0
- package/lib/bs/tests/EndpointResolutionTest.res.mjs +115 -0
- package/lib/bs/tests/ObjectStoreReconcileTest.ast +0 -0
- package/lib/bs/tests/ObjectStoreReconcileTest.cmi +0 -0
- package/lib/bs/tests/ObjectStoreReconcileTest.cmj +0 -0
- package/lib/bs/tests/ObjectStoreReconcileTest.cmt +0 -0
- package/lib/bs/tests/ObjectStoreReconcileTest.res +83 -0
- package/lib/bs/tests/ObjectStoreReconcileTest.res.mjs +102 -0
- package/lib/bs/tests/ObjectStoreResetTest.ast +0 -0
- package/lib/bs/tests/ObjectStoreResetTest.cmi +0 -0
- package/lib/bs/tests/ObjectStoreResetTest.cmj +0 -0
- package/lib/bs/tests/ObjectStoreResetTest.cmt +0 -0
- package/lib/bs/tests/ObjectStoreResetTest.res +191 -0
- package/lib/bs/tests/ObjectStoreResetTest.res.mjs +211 -0
- package/lib/bs/tests/QuiesceResetTest.ast +0 -0
- package/lib/bs/tests/QuiesceResetTest.cmi +0 -0
- package/lib/bs/tests/QuiesceResetTest.cmj +0 -0
- package/lib/bs/tests/QuiesceResetTest.cmt +0 -0
- package/lib/bs/tests/QuiesceResetTest.res +169 -0
- package/lib/bs/tests/QuiesceResetTest.res.mjs +157 -0
- package/lib/ocaml/.compiler.log +2 -2
- package/lib/ocaml/EndpointResolutionTest.ast +0 -0
- package/lib/ocaml/EndpointResolutionTest.cmi +0 -0
- package/lib/ocaml/EndpointResolutionTest.cmj +0 -0
- package/lib/ocaml/EndpointResolutionTest.cmt +0 -0
- package/lib/ocaml/EndpointResolutionTest.res +83 -0
- package/lib/ocaml/ObjectStoreReconcileTest.ast +0 -0
- package/lib/ocaml/ObjectStoreReconcileTest.cmi +0 -0
- package/lib/ocaml/ObjectStoreReconcileTest.cmj +0 -0
- package/lib/ocaml/ObjectStoreReconcileTest.cmt +0 -0
- package/lib/ocaml/ObjectStoreReconcileTest.res +83 -0
- package/lib/ocaml/ObjectStoreResetTest.ast +0 -0
- package/lib/ocaml/ObjectStoreResetTest.cmi +0 -0
- package/lib/ocaml/ObjectStoreResetTest.cmj +0 -0
- package/lib/ocaml/ObjectStoreResetTest.cmt +0 -0
- package/lib/ocaml/ObjectStoreResetTest.res +191 -0
- package/lib/ocaml/QuiesceResetTest.ast +0 -0
- package/lib/ocaml/QuiesceResetTest.cmi +0 -0
- package/lib/ocaml/QuiesceResetTest.cmj +0 -0
- package/lib/ocaml/QuiesceResetTest.cmt +0 -0
- package/lib/ocaml/QuiesceResetTest.res +169 -0
- package/lib/ocaml/ReventlessSeedAws.ast +0 -0
- package/lib/ocaml/ReventlessSeedAws.cmi +0 -0
- package/lib/ocaml/ReventlessSeedAws.cmj +0 -0
- package/lib/ocaml/ReventlessSeedAws.cmt +0 -0
- package/lib/ocaml/ReventlessSeedAws.res +198 -134
- package/lib/ocaml/ReventlessSeedAws_Quiesce.ast +0 -0
- package/lib/ocaml/ReventlessSeedAws_Quiesce.cmi +0 -0
- package/lib/ocaml/ReventlessSeedAws_Quiesce.cmj +0 -0
- package/lib/ocaml/ReventlessSeedAws_Quiesce.cmt +0 -0
- package/lib/ocaml/ReventlessSeedAws_Quiesce.res +307 -0
- package/lib/ocaml/ReventlessSeedAws_Reconcile.ast +0 -0
- package/lib/ocaml/ReventlessSeedAws_Reconcile.cmi +0 -0
- package/lib/ocaml/ReventlessSeedAws_Reconcile.cmj +0 -0
- package/lib/ocaml/ReventlessSeedAws_Reconcile.cmt +0 -0
- package/lib/ocaml/ReventlessSeedAws_Reconcile.res +391 -0
- package/lib/ocaml/ReventlessSeedAws_Reset.ast +0 -0
- package/lib/ocaml/ReventlessSeedAws_Reset.cmi +0 -0
- package/lib/ocaml/ReventlessSeedAws_Reset.cmj +0 -0
- package/lib/ocaml/ReventlessSeedAws_Reset.cmt +0 -0
- package/lib/ocaml/ReventlessSeedAws_Reset.res +1103 -0
- package/package.json +7 -4
- package/rescript.json +9 -1
- package/src/ReventlessSeedAws.res +198 -134
- package/src/ReventlessSeedAws.res.mjs +57 -31
- package/src/ReventlessSeedAws_Quiesce.res +307 -0
- package/src/ReventlessSeedAws_Quiesce.res.mjs +217 -0
- package/src/ReventlessSeedAws_Reconcile.res +391 -0
- package/src/ReventlessSeedAws_Reconcile.res.mjs +318 -0
- package/src/ReventlessSeedAws_Reset.res +1103 -0
- package/src/ReventlessSeedAws_Reset.res.mjs +991 -0
- package/tests/EndpointResolutionTest.res +83 -0
- package/tests/EndpointResolutionTest.res.mjs +115 -0
- package/tests/ObjectStoreReconcileTest.res +83 -0
- package/tests/ObjectStoreReconcileTest.res.mjs +102 -0
- package/tests/ObjectStoreResetTest.res +191 -0
- package/tests/ObjectStoreResetTest.res.mjs +211 -0
- package/tests/QuiesceResetTest.res +169 -0
- package/tests/QuiesceResetTest.res.mjs +157 -0
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,213 @@
|
|
|
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.30 (2026-09-11)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @reventlessdev/reventless-seed-aws
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
# 1.0.0-alpha.29 (2026-09-09)
|
|
15
|
+
|
|
16
|
+
### Features
|
|
17
|
+
|
|
18
|
+
* **seed:** choose the role a run acts as, instead of inheriting a stored one ([edf41ca](https://github.com/ReventlessDev/reventless-core/commit/edf41ca80f84bf340679f200ebfeeeb4a590ae03))
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
# 1.0.0-alpha.28 (2026-09-08)
|
|
22
|
+
|
|
23
|
+
**Note:** Version bump only for package @reventlessdev/reventless-seed-aws
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
# 1.0.0-alpha.27 (2026-09-04)
|
|
30
|
+
|
|
31
|
+
**Note:** Version bump only for package @reventlessdev/reventless-seed-aws
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
# 1.0.0-alpha.26 (2026-08-27)
|
|
38
|
+
|
|
39
|
+
**Note:** Version bump only for package @reventlessdev/reventless-seed-aws
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
# 1.0.0-alpha.25 (2026-08-27)
|
|
46
|
+
|
|
47
|
+
### Bug Fixes
|
|
48
|
+
|
|
49
|
+
* **seed-aws:** a throttled control plane aborts the reset hold and blames IAM ([95af263](https://github.com/ReventlessDev/reventless-core/commit/95af263afba7dfdfa9a7fc45f494b302dba4baf8))
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
# 1.0.0-alpha.24 (2026-08-23)
|
|
53
|
+
|
|
54
|
+
**Note:** Version bump only for package @reventlessdev/reventless-seed-aws
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
# 1.0.0-alpha.23 (2026-08-20)
|
|
61
|
+
|
|
62
|
+
### Features
|
|
63
|
+
|
|
64
|
+
* **seed:** choose the login from the platform's users.yaml ([74e61de](https://github.com/ReventlessDev/reventless-core/commit/74e61de8fba3ee4cc62b368ff12010f162d49db7))
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
# 1.0.0-alpha.22 (2026-08-18)
|
|
68
|
+
|
|
69
|
+
**Note:** Version bump only for package @reventlessdev/reventless-seed-aws
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
# 1.0.0-alpha.21 (2026-08-16)
|
|
76
|
+
|
|
77
|
+
**Note:** Version bump only for package @reventlessdev/reventless-seed-aws
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
# 1.0.0-alpha.20 (2026-08-16)
|
|
84
|
+
|
|
85
|
+
**Note:** Version bump only for package @reventlessdev/reventless-seed-aws
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
# 1.0.0-alpha.19 (2026-08-15)
|
|
92
|
+
|
|
93
|
+
**Note:** Version bump only for package @reventlessdev/reventless-seed-aws
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
# 1.0.0-alpha.18 (2026-08-14)
|
|
100
|
+
|
|
101
|
+
**Note:** Version bump only for package @reventlessdev/reventless-seed-aws
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
# 1.0.0-alpha.17 (2026-08-13)
|
|
108
|
+
|
|
109
|
+
**Note:** Version bump only for package @reventlessdev/reventless-seed-aws
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
# 1.0.0-alpha.16 (2026-08-13)
|
|
116
|
+
|
|
117
|
+
**Note:** Version bump only for package @reventlessdev/reventless-seed-aws
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
# 1.0.0-alpha.15 (2026-08-11)
|
|
124
|
+
|
|
125
|
+
**Note:** Version bump only for package @reventlessdev/reventless-seed-aws
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
# 1.0.0-alpha.14 (2026-08-09)
|
|
132
|
+
|
|
133
|
+
**Note:** Version bump only for package @reventlessdev/reventless-seed-aws
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
# 1.0.0-alpha.13 (2026-08-09)
|
|
140
|
+
|
|
141
|
+
### Bug Fixes
|
|
142
|
+
|
|
143
|
+
* **seed-aws:** hold and recycle a stack's runtimes so a reset stays empty ([4baaa38](https://github.com/ReventlessDev/reventless-core/commit/4baaa3827ef30a0adccdef5d2bccc688e7b6686f))
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
# 1.0.0-alpha.12 (2026-08-05)
|
|
147
|
+
|
|
148
|
+
**Note:** Version bump only for package @reventlessdev/reventless-seed-aws
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
# 1.0.0-alpha.11 (2026-08-03)
|
|
155
|
+
|
|
156
|
+
**Note:** Version bump only for package @reventlessdev/reventless-seed-aws
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
# 1.0.0-alpha.10 (2026-08-02)
|
|
163
|
+
|
|
164
|
+
**Note:** Version bump only for package @reventlessdev/reventless-seed-aws
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
# 1.0.0-alpha.9 (2026-08-02)
|
|
171
|
+
|
|
172
|
+
### Features
|
|
173
|
+
|
|
174
|
+
* **aws,core,spec,seed-aws:** expire uploads nobody committed a reference to ([f63e84c](https://github.com/ReventlessDev/reventless-core/commit/f63e84c1a11cc350b799a6f69a2e7427cf1ea6e9))
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
# 1.0.0-alpha.8 (2026-08-01)
|
|
178
|
+
|
|
179
|
+
### Features
|
|
180
|
+
|
|
181
|
+
* **seed-aws:** wipe a plugin's declared object stores in seed:reset ([2280c5f](https://github.com/ReventlessDev/reventless-core/commit/2280c5f14755d13fff0fe1ac11eb440cd0617f1d))
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
# 1.0.0-alpha.7 (2026-08-01)
|
|
185
|
+
|
|
186
|
+
### Features
|
|
187
|
+
|
|
188
|
+
* **upload:** add the release half of the upload contract via the domain API ([448f887](https://github.com/ReventlessDev/reventless-core/commit/448f88714a5875be420f794a08d482fcf4ba8404))
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
# 1.0.0-alpha.6 (2026-07-31)
|
|
192
|
+
|
|
193
|
+
**Note:** Version bump only for package @reventlessdev/reventless-seed-aws
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
# 1.0.0-alpha.5 (2026-07-31)
|
|
200
|
+
|
|
201
|
+
### Bug Fixes
|
|
202
|
+
|
|
203
|
+
* **seed:** address a deployment's per-store upload endpoints ([45b226e](https://github.com/ReventlessDev/reventless-core/commit/45b226e00604af9fd28b6fb0b75ba7d3414791f2))
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
# 1.0.0-alpha.4 (2026-07-27)
|
|
207
|
+
|
|
208
|
+
### Features
|
|
209
|
+
|
|
210
|
+
* **seed:** guarded AWS store reset (seed:reset) with per-project scope selection ([8446172](https://github.com/ReventlessDev/reventless-core/commit/8446172cbb53776a58f53220d19e96d96ce94508))
|
|
211
|
+
|
|
212
|
+
|
|
6
213
|
# 1.0.0-alpha.3 (2026-07-27)
|
|
7
214
|
|
|
8
215
|
**Note:** Version bump only for package @reventlessdev/reventless-seed-aws
|
package/lib/bs/.compiler.log
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
#Start(
|
|
2
|
-
#Done(
|
|
1
|
+
#Start(1789087760185)
|
|
2
|
+
#Done(1789087760226)
|
|
@@ -0,0 +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/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": "
|
|
5
|
+
"rescript_config_hash": "c18a0067c363fd1290f6e7f6fe6212d2e16e201c1702fac667962047f88ed468",
|
|
6
6
|
"runtime_path": "/home/runner/work/reventless-core/reventless-core/node_modules/@rescript/runtime",
|
|
7
|
-
"generated_at": "
|
|
7
|
+
"generated_at": "1789087760231"
|
|
8
8
|
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -14,12 +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
|
-
|
|
23
17
|
type fetchInit = {method: string, headers: dict<string>, body?: string}
|
|
24
18
|
type response
|
|
25
19
|
@val external fetch: (string, fetchInit) => promise<response> = "fetch"
|
|
@@ -53,13 +47,17 @@ let envForBackend = (backend: option<string>): option<dict<string>> =>
|
|
|
53
47
|
switch backend {
|
|
54
48
|
| None => None
|
|
55
49
|
| Some(url) =>
|
|
56
|
-
let copy =
|
|
50
|
+
let copy = NodeProcess.env->Dict.toArray->Dict.fromArray
|
|
57
51
|
copy->Dict.set("PULUMI_BACKEND_URL", url)
|
|
58
52
|
Some(copy)
|
|
59
53
|
}
|
|
60
54
|
|
|
61
55
|
let pulumi = (~projectDir: string, ~backend: option<string>, args: array<string>): string =>
|
|
62
|
-
execFileSync(
|
|
56
|
+
NodeChildProcess.execFileSync(
|
|
57
|
+
"pulumi",
|
|
58
|
+
args,
|
|
59
|
+
{cwd: projectDir, encoding: "utf8", env: ?envForBackend(backend)},
|
|
60
|
+
)
|
|
63
61
|
|
|
64
62
|
// Stacks that actually exist in the Pulumi backend for this project — the names
|
|
65
63
|
// `pulumi stack output --stack <name>` accepts. A `Pulumi.<stack>.yaml` config
|
|
@@ -78,12 +76,15 @@ let deployedStacks = (~projectDir: string, ~backend: option<string>): array<stri
|
|
|
78
76
|
}
|
|
79
77
|
|
|
80
78
|
let stackOutputs = (~projectDir: string, ~backend: option<string>, stack: string): JSON.t => {
|
|
81
|
-
let raw = try pulumi(
|
|
79
|
+
let raw = try pulumi(
|
|
80
|
+
~projectDir,
|
|
81
|
+
~backend,
|
|
82
|
+
["stack", "output", "--stack", stack, "--json"],
|
|
83
|
+
) catch {
|
|
82
84
|
| _ =>
|
|
83
85
|
throw(
|
|
84
86
|
Seed.Failed(
|
|
85
|
-
`pulumi stack output --stack ${stack} failed — is pulumi installed, logged in, ` ++
|
|
86
|
-
"and the stack deployed?",
|
|
87
|
+
`pulumi stack output --stack ${stack} failed — is pulumi installed, logged in, ` ++ "and the stack deployed?",
|
|
87
88
|
),
|
|
88
89
|
)
|
|
89
90
|
}
|
|
@@ -98,7 +99,11 @@ let backendNote = (~backend: option<string>): string =>
|
|
|
98
99
|
| None => ""
|
|
99
100
|
}
|
|
100
101
|
|
|
101
|
-
let resolveStack = async (
|
|
102
|
+
let resolveStack = async (
|
|
103
|
+
~projectDir: string,
|
|
104
|
+
~backend: option<string>,
|
|
105
|
+
~stack: option<string>,
|
|
106
|
+
): string =>
|
|
102
107
|
switch stack {
|
|
103
108
|
| Some(s) => s
|
|
104
109
|
| None =>
|
|
@@ -112,8 +117,7 @@ let resolveStack = async (~projectDir: string, ~backend: option<string>, ~stack:
|
|
|
112
117
|
`no deployed Pulumi stacks for this project (\`pulumi stack ls\` is empty in ${projectDir})${backendNote(
|
|
113
118
|
~backend,
|
|
114
119
|
)}. ` ++
|
|
115
|
-
"A Pulumi.<stack>.yaml config file alone is not a deployed stack — run `pulumi up` " ++
|
|
116
|
-
"first, log in to the backend that holds the stack, or set SEED_STACK to target one.",
|
|
120
|
+
"A Pulumi.<stack>.yaml config file alone is not a deployed stack — run `pulumi up` " ++ "first, log in to the backend that holds the stack, or set SEED_STACK to target one.",
|
|
117
121
|
),
|
|
118
122
|
)
|
|
119
123
|
}
|
|
@@ -124,13 +128,13 @@ let resolveStack = async (~projectDir: string, ~backend: option<string>, ~stack:
|
|
|
124
128
|
// ── Endpoints ─────────────────────────────────────────────────────────────────
|
|
125
129
|
|
|
126
130
|
let fetchConfig = async (hostShellUrl: string): JSON.t => {
|
|
127
|
-
let base = hostShellUrl->String.replaceRegExp(
|
|
131
|
+
let base = hostShellUrl->String.replaceRegExp(/\/+$/g, "")
|
|
128
132
|
let url = `${base}/config.json`
|
|
129
133
|
let res = try await fetch(url, {method: "GET", headers: Dict.make()}) catch {
|
|
130
134
|
| _ => throw(Seed.Failed(`cannot reach ${url}`))
|
|
131
135
|
}
|
|
132
136
|
if !(res->responseOk) {
|
|
133
|
-
throw(Seed.Failed(`GET ${url} → HTTP ${
|
|
137
|
+
throw(Seed.Failed(`GET ${url} → HTTP ${res->responseStatus->Int.toString}`))
|
|
134
138
|
}
|
|
135
139
|
await res->responseJson
|
|
136
140
|
}
|
|
@@ -147,132 +151,196 @@ let resolveField = (~envKey: string, ~fromSource: option<string>, ~human: string
|
|
|
147
151
|
}
|
|
148
152
|
}
|
|
149
153
|
|
|
150
|
-
//
|
|
151
|
-
//
|
|
152
|
-
//
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
154
|
+
// Which document publishes the deployment's endpoints. A stack that serves a
|
|
155
|
+
// host shell publishes them in the shell's `config.json` under the client's key
|
|
156
|
+
// names; one that does not publishes them as stack outputs under Pulumi's. The
|
|
157
|
+
// two arms name different keys for the same values, which is why this is a
|
|
158
|
+
// variant and not a merged lookup.
|
|
159
|
+
type source = HostShellConfig(JSON.t) | StackOutputs(JSON.t)
|
|
160
|
+
|
|
161
|
+
type endpoints = {
|
|
162
|
+
graphql: string,
|
|
163
|
+
cognitoRegion: string,
|
|
164
|
+
cognitoClientId: string,
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* The endpoints a source document publishes — pure, so the branch selection and
|
|
169
|
+
* every key it reads can be exercised with synthetic documents.
|
|
170
|
+
*
|
|
171
|
+
* Upload endpoints are no longer resolved here: under route B the seed mints through
|
|
172
|
+
* the domain API's `Upload_Presign` mutation on `graphql`, passing the store per asset,
|
|
173
|
+
* so there is no per-store URL to discover.
|
|
174
|
+
*/
|
|
175
|
+
let endpointsFrom = (~stack: string, source: source): endpoints =>
|
|
176
|
+
switch source {
|
|
177
|
+
| HostShellConfig(cfg) =>
|
|
163
178
|
let fromCfg = key => cfg->field(key)->Option.flatMap(asString)
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
~human="cognitoClientId",
|
|
183
|
-
)
|
|
184
|
-
(endpoint, uploadEndpoint, region, clientId)
|
|
185
|
-
| None =>
|
|
179
|
+
{
|
|
180
|
+
graphql: resolveField(
|
|
181
|
+
~envKey="REVENTLESS_GRAPHQL_ENDPOINT",
|
|
182
|
+
~fromSource=fromCfg("apiEndpoint"),
|
|
183
|
+
~human="apiEndpoint",
|
|
184
|
+
),
|
|
185
|
+
cognitoRegion: resolveField(
|
|
186
|
+
~envKey="AWS_REGION",
|
|
187
|
+
~fromSource=fromCfg("region"),
|
|
188
|
+
~human="region",
|
|
189
|
+
),
|
|
190
|
+
cognitoClientId: resolveField(
|
|
191
|
+
~envKey="COGNITO_CLIENT_ID",
|
|
192
|
+
~fromSource=fromCfg("cognitoClientId"),
|
|
193
|
+
~human="cognitoClientId",
|
|
194
|
+
),
|
|
195
|
+
}
|
|
196
|
+
| StackOutputs(outputs) =>
|
|
186
197
|
let out = key => outputs->field(key)->Option.flatMap(asString)
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
198
|
+
{
|
|
199
|
+
graphql: switch (
|
|
200
|
+
Seed.Prompt.envValue("REVENTLESS_GRAPHQL_ENDPOINT"),
|
|
201
|
+
out("domainMergedApiEndpoint"),
|
|
202
|
+
out("domainApiEndpoint"),
|
|
203
|
+
) {
|
|
204
|
+
| (Some(v), _, _) | (_, Some(v), _) | (_, _, Some(v)) => v
|
|
205
|
+
| _ =>
|
|
206
|
+
throw(
|
|
207
|
+
Seed.Failed(
|
|
208
|
+
`stack "${stack}" exports neither domainMergedApiEndpoint nor domainApiEndpoint`,
|
|
209
|
+
),
|
|
210
|
+
)
|
|
211
|
+
},
|
|
212
|
+
cognitoRegion: resolveField(
|
|
213
|
+
~envKey="AWS_REGION",
|
|
214
|
+
~fromSource=out("cognitoRegion"),
|
|
215
|
+
~human="cognitoRegion",
|
|
216
|
+
),
|
|
217
|
+
cognitoClientId: resolveField(
|
|
218
|
+
~envKey="COGNITO_CLIENT_ID",
|
|
219
|
+
~fromSource=out("cognitoUserPoolClientId"),
|
|
220
|
+
~human="cognitoUserPoolClientId",
|
|
221
|
+
),
|
|
199
222
|
}
|
|
200
|
-
let region = resolveField(
|
|
201
|
-
~envKey="AWS_REGION",
|
|
202
|
-
~fromSource=out("cognitoRegion"),
|
|
203
|
-
~human="cognitoRegion",
|
|
204
|
-
)
|
|
205
|
-
let clientId = resolveField(
|
|
206
|
-
~envKey="COGNITO_CLIENT_ID",
|
|
207
|
-
~fromSource=out("cognitoUserPoolClientId"),
|
|
208
|
-
~human="cognitoUserPoolClientId",
|
|
209
|
-
)
|
|
210
|
-
// Absent → "" → the data set skips its upload phase.
|
|
211
|
-
let uploadEndpoint = Seed.Prompt.envValue("REVENTLESS_UPLOAD_ENDPOINT")->Option.getOr("")
|
|
212
|
-
(endpoint, uploadEndpoint, region, clientId)
|
|
213
223
|
}
|
|
224
|
+
|
|
225
|
+
let resolveEndpoints = async (
|
|
226
|
+
~projectDir: string,
|
|
227
|
+
~backend: option<string>,
|
|
228
|
+
~stack: string,
|
|
229
|
+
): endpoints => {
|
|
230
|
+
let outputs = stackOutputs(~projectDir, ~backend, stack)
|
|
231
|
+
let source = switch outputs->field("hostShellUrl")->Option.flatMap(asString) {
|
|
232
|
+
| Some(hostShellUrl) => HostShellConfig(await fetchConfig(hostShellUrl))
|
|
233
|
+
| None => StackOutputs(outputs)
|
|
234
|
+
}
|
|
235
|
+
endpointsFrom(~stack, source)
|
|
214
236
|
}
|
|
215
237
|
|
|
216
238
|
// ── Cognito login ─────────────────────────────────────────────────────────────
|
|
217
239
|
|
|
218
|
-
let cognito = (~region: string, ~clientId: string) =>
|
|
219
|
-
~username: string,
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
]),
|
|
240
|
+
let cognito = (~region: string, ~clientId: string) =>
|
|
241
|
+
async (~username: string, ~password: string): string => {
|
|
242
|
+
let body = JSON.stringify(
|
|
243
|
+
JSON.Encode.object(
|
|
244
|
+
Dict.fromArray([
|
|
245
|
+
("AuthFlow", JSON.Encode.string("USER_PASSWORD_AUTH")),
|
|
246
|
+
("ClientId", JSON.Encode.string(clientId)),
|
|
247
|
+
(
|
|
248
|
+
"AuthParameters",
|
|
249
|
+
JSON.Encode.object(
|
|
250
|
+
Dict.fromArray([
|
|
251
|
+
("USERNAME", JSON.Encode.string(username)),
|
|
252
|
+
("PASSWORD", JSON.Encode.string(password)),
|
|
253
|
+
]),
|
|
254
|
+
),
|
|
234
255
|
),
|
|
235
|
-
),
|
|
236
|
-
]),
|
|
237
|
-
),
|
|
238
|
-
)
|
|
239
|
-
let headers = Dict.fromArray([
|
|
240
|
-
("content-type", "application/x-amz-json-1.1"),
|
|
241
|
-
("x-amz-target", "AWSCognitoIdentityProviderService.InitiateAuth"),
|
|
242
|
-
])
|
|
243
|
-
let res = try await fetch(`https://cognito-idp.${region}.amazonaws.com/`, {
|
|
244
|
-
method: "POST",
|
|
245
|
-
headers,
|
|
246
|
-
body,
|
|
247
|
-
}) catch {
|
|
248
|
-
| _ => throw(Seed.Failed(`cannot reach Cognito in ${region}`))
|
|
249
|
-
}
|
|
250
|
-
let json = await res->responseJson
|
|
251
|
-
if !(res->responseOk) {
|
|
252
|
-
let detail =
|
|
253
|
-
json->field("message")->Option.flatMap(asString)->Option.getOr(JSON.stringify(json))
|
|
254
|
-
throw(
|
|
255
|
-
Seed.Failed(
|
|
256
|
-
`Cognito InitiateAuth failed (HTTP ${(res->responseStatus)->Int.toString}): ${detail}`,
|
|
256
|
+
]),
|
|
257
257
|
),
|
|
258
258
|
)
|
|
259
|
+
let headers = Dict.fromArray([
|
|
260
|
+
("content-type", "application/x-amz-json-1.1"),
|
|
261
|
+
("x-amz-target", "AWSCognitoIdentityProviderService.InitiateAuth"),
|
|
262
|
+
])
|
|
263
|
+
let res = try await fetch(
|
|
264
|
+
`https://cognito-idp.${region}.amazonaws.com/`,
|
|
265
|
+
{
|
|
266
|
+
method: "POST",
|
|
267
|
+
headers,
|
|
268
|
+
body,
|
|
269
|
+
},
|
|
270
|
+
) catch {
|
|
271
|
+
| _ => throw(Seed.Failed(`cannot reach Cognito in ${region}`))
|
|
272
|
+
}
|
|
273
|
+
let json = await res->responseJson
|
|
274
|
+
if !(res->responseOk) {
|
|
275
|
+
let detail =
|
|
276
|
+
json->field("message")->Option.flatMap(asString)->Option.getOr(JSON.stringify(json))
|
|
277
|
+
throw(
|
|
278
|
+
Seed.Failed(
|
|
279
|
+
`Cognito InitiateAuth failed (HTTP ${res->responseStatus->Int.toString}): ${detail}`,
|
|
280
|
+
),
|
|
281
|
+
)
|
|
282
|
+
}
|
|
283
|
+
switch json->field("ChallengeName")->Option.flatMap(asString) {
|
|
284
|
+
| Some(challenge) =>
|
|
285
|
+
throw(
|
|
286
|
+
Seed.Failed(
|
|
287
|
+
`Cognito returned challenge ${challenge} — set a permanent password first ` ++ "(aws cognito-idp admin-set-user-password … --permanent).",
|
|
288
|
+
),
|
|
289
|
+
)
|
|
290
|
+
| None => ()
|
|
291
|
+
}
|
|
292
|
+
switch json
|
|
293
|
+
->field("AuthenticationResult")
|
|
294
|
+
->Option.flatMap(ar => ar->field("IdToken"))
|
|
295
|
+
->Option.flatMap(asString) {
|
|
296
|
+
| Some(token) => token
|
|
297
|
+
| None => throw(Seed.Failed(`Cognito response carried no IdToken: ${JSON.stringify(json)}`))
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// ── Active role ───────────────────────────────────────────────────────────────
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* The Cognito path's active-role door: `Platform_SetActiveRole` on the domain
|
|
305
|
+
* API, which is where the seed already sends everything else.
|
|
306
|
+
*
|
|
307
|
+
* It sits on the domain base document at `AllowAuthenticated`, deliberately not
|
|
308
|
+
* behind the Admin gate — the whole point is that a caller can drop into a
|
|
309
|
+
* narrower role — so a token already narrowed to `Shopper` can still call this
|
|
310
|
+
* to widen back out. There is no chicken-and-egg, and no `sub` argument: the
|
|
311
|
+
* mutation addresses the authorizer-verified caller's own row and nobody else's.
|
|
312
|
+
*
|
|
313
|
+
* Returns `None` always: the choice is a stored row, read by the pool's
|
|
314
|
+
* pre-token-generation trigger on the NEXT login, so the current bearer is
|
|
315
|
+
* unchanged by it and the caller must re-authenticate to see any effect.
|
|
316
|
+
*
|
|
317
|
+
* Split-API only. A unified-mode deployment's single API does not carry the
|
|
318
|
+
* field, so a refusal naming it is reported as "this deployment offers no role
|
|
319
|
+
* switch" rather than as a seeding failure.
|
|
320
|
+
*/
|
|
321
|
+
let setActiveRole: Seed.Connect.roleSwitch = async (~client, ~role) => {
|
|
322
|
+
let argument = switch role {
|
|
323
|
+
| None => "null"
|
|
324
|
+
| Some(r) => JSON.stringify(JSON.Encode.string(r))
|
|
259
325
|
}
|
|
260
|
-
|
|
261
|
-
|
|
326
|
+
try {
|
|
327
|
+
let _ = await Seed.Client.gql(
|
|
328
|
+
client,
|
|
329
|
+
~query=`mutation { Platform_SetActiveRole(activeRole: ${argument}) { activeRole availableRoles } }`,
|
|
330
|
+
~label="Platform_SetActiveRole",
|
|
331
|
+
)
|
|
332
|
+
None
|
|
333
|
+
} catch {
|
|
334
|
+
| Seed.Failed(message) =>
|
|
262
335
|
throw(
|
|
263
336
|
Seed.Failed(
|
|
264
|
-
|
|
265
|
-
|
|
337
|
+
message->String.includes("Platform_SetActiveRole")
|
|
338
|
+
? `this deployment offers no role switch — \`Platform_SetActiveRole\` is a split-API ` ++
|
|
339
|
+
`field, and a unified-mode API does not carry it. Change the role in the host shell ` ++
|
|
340
|
+
`instead.\n ${message}`
|
|
341
|
+
: message,
|
|
266
342
|
),
|
|
267
343
|
)
|
|
268
|
-
| None => ()
|
|
269
|
-
}
|
|
270
|
-
switch json
|
|
271
|
-
->field("AuthenticationResult")
|
|
272
|
-
->Option.flatMap(ar => ar->field("IdToken"))
|
|
273
|
-
->Option.flatMap(asString) {
|
|
274
|
-
| Some(token) => token
|
|
275
|
-
| None => throw(Seed.Failed(`Cognito response carried no IdToken: ${JSON.stringify(json)}`))
|
|
276
344
|
}
|
|
277
345
|
}
|
|
278
346
|
|
|
@@ -302,15 +370,11 @@ let connect = (~projectDir: string=".", ~stack=?, ~backend=?, ()): (
|
|
|
302
370
|
| None => backend
|
|
303
371
|
}
|
|
304
372
|
let stackName = await resolveStack(~projectDir, ~backend, ~stack)
|
|
305
|
-
let
|
|
306
|
-
~projectDir,
|
|
307
|
-
~backend,
|
|
308
|
-
~stack=stackName,
|
|
309
|
-
)
|
|
373
|
+
let eps = await resolveEndpoints(~projectDir, ~backend, ~stack=stackName)
|
|
310
374
|
await Seed.Connect.make(
|
|
311
375
|
~label=stackName,
|
|
312
|
-
~endpoint,
|
|
313
|
-
~
|
|
314
|
-
~
|
|
376
|
+
~endpoint=eps.graphql,
|
|
377
|
+
~login=cognito(~region=eps.cognitoRegion, ~clientId=eps.cognitoClientId),
|
|
378
|
+
~roleSwitch=setActiveRole,
|
|
315
379
|
)
|
|
316
380
|
}
|