@reventlessdev/reventless-seed 1.0.0-alpha.2 → 1.0.0-alpha.21
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 +149 -0
- package/lib/bs/.compiler.log +2 -2
- package/lib/bs/.sourcedirs.json +1 -0
- package/lib/bs/ReventlessSeed.cmi +0 -0
- package/lib/bs/ReventlessSeed.cmt +0 -0
- package/lib/bs/ReventlessSeed.mlmap +6 -0
- package/lib/bs/compiler-info.json +2 -2
- package/lib/bs/src/Seed-ReventlessSeed.cmi +0 -0
- package/lib/bs/src/Seed-ReventlessSeed.cmt +0 -0
- package/lib/bs/src/Seed.ast +0 -0
- package/lib/bs/src/Seed.res +12 -3
- package/lib/bs/src/Seed.res.mjs +3 -0
- package/lib/bs/src/Seed_Client-ReventlessSeed.cmi +0 -0
- package/lib/bs/src/Seed_Client-ReventlessSeed.cmj +0 -0
- package/lib/bs/src/Seed_Client-ReventlessSeed.cmt +0 -0
- package/lib/bs/src/Seed_Client.ast +0 -0
- package/lib/bs/src/Seed_Client.res +382 -21
- package/lib/bs/src/Seed_Client.res.mjs +332 -24
- package/lib/bs/src/Seed_Connect-ReventlessSeed.cmi +0 -0
- package/lib/bs/src/Seed_Connect-ReventlessSeed.cmj +0 -0
- package/lib/bs/src/Seed_Connect-ReventlessSeed.cmt +0 -0
- package/lib/bs/src/Seed_Connect.ast +0 -0
- package/lib/bs/src/Seed_Connect.res +281 -33
- package/lib/bs/src/Seed_Connect.res.mjs +162 -8
- package/lib/bs/src/Seed_Prompt-ReventlessSeed.cmi +0 -0
- package/lib/bs/src/Seed_Prompt-ReventlessSeed.cmj +0 -0
- package/lib/bs/src/Seed_Prompt-ReventlessSeed.cmt +0 -0
- package/lib/bs/src/Seed_Prompt.ast +0 -0
- package/lib/bs/src/Seed_Prompt.res +140 -41
- package/lib/bs/src/Seed_Prompt.res.mjs +88 -13
- package/lib/bs/src/Seed_Random-ReventlessSeed.cmi +0 -0
- package/lib/bs/src/Seed_Random-ReventlessSeed.cmt +0 -0
- package/lib/bs/src/Seed_Random.ast +0 -0
- package/lib/bs/src/Seed_Random.res +4 -2
- package/lib/bs/src/Seed_Runner-ReventlessSeed.cmi +0 -0
- package/lib/bs/src/Seed_Runner-ReventlessSeed.cmj +0 -0
- package/lib/bs/src/Seed_Runner-ReventlessSeed.cmt +0 -0
- package/lib/bs/src/Seed_Runner.ast +0 -0
- package/lib/bs/src/Seed_Runner.res +45 -19
- package/lib/bs/src/Seed_Runner.res.mjs +19 -1
- package/lib/bs/src/Seed_Types-ReventlessSeed.cmt +0 -0
- package/lib/bs/src/Seed_Upload-ReventlessSeed.cmi +0 -0
- package/lib/bs/src/Seed_Upload-ReventlessSeed.cmj +0 -0
- package/lib/bs/src/Seed_Upload-ReventlessSeed.cmt +0 -0
- package/lib/bs/src/Seed_Upload.ast +0 -0
- package/lib/bs/src/Seed_Upload.res +43 -43
- package/lib/bs/src/Seed_Upload.res.mjs +65 -69
- package/lib/bs/src/Seed_Users-ReventlessSeed.cmi +0 -0
- package/lib/bs/src/Seed_Users-ReventlessSeed.cmj +0 -0
- package/lib/bs/src/Seed_Users-ReventlessSeed.cmt +0 -0
- package/lib/bs/src/Seed_Users.ast +0 -0
- package/lib/bs/src/Seed_Users.res +92 -0
- package/lib/bs/src/Seed_Users.res.mjs +91 -0
- package/lib/bs/tests/Seed_ClientTest-ReventlessSeed.cmi +0 -0
- package/lib/bs/tests/Seed_ClientTest-ReventlessSeed.cmj +0 -0
- package/lib/bs/tests/Seed_ClientTest-ReventlessSeed.cmt +0 -0
- package/lib/bs/tests/Seed_ClientTest.ast +0 -0
- package/lib/bs/tests/Seed_ClientTest.res +287 -0
- package/lib/bs/tests/Seed_ClientTest.res.mjs +268 -0
- package/lib/bs/tests/Seed_ConnectTest-ReventlessSeed.cmi +0 -0
- package/lib/bs/tests/Seed_ConnectTest-ReventlessSeed.cmj +0 -0
- package/lib/bs/tests/Seed_ConnectTest-ReventlessSeed.cmt +0 -0
- package/lib/bs/tests/Seed_ConnectTest.ast +0 -0
- package/lib/bs/tests/Seed_ConnectTest.res +64 -0
- package/lib/bs/tests/Seed_ConnectTest.res.mjs +56 -0
- package/lib/bs/tests/Seed_PromptTest-ReventlessSeed.cmi +0 -0
- package/lib/bs/tests/Seed_PromptTest-ReventlessSeed.cmj +0 -0
- package/lib/bs/tests/Seed_PromptTest-ReventlessSeed.cmt +0 -0
- package/lib/bs/tests/Seed_PromptTest.ast +0 -0
- package/lib/bs/tests/Seed_PromptTest.res +55 -0
- package/lib/bs/tests/Seed_PromptTest.res.mjs +63 -0
- package/lib/bs/tests/Seed_RandomTest-ReventlessSeed.cmi +0 -0
- package/lib/bs/tests/Seed_RandomTest-ReventlessSeed.cmj +0 -0
- package/lib/bs/tests/Seed_RandomTest-ReventlessSeed.cmt +0 -0
- package/lib/bs/tests/Seed_RandomTest.ast +0 -0
- package/lib/bs/tests/Seed_RandomTest.res +200 -0
- package/lib/bs/tests/Seed_RandomTest.res.mjs +208 -0
- package/lib/bs/tests/Seed_UsersTest-ReventlessSeed.cmi +0 -0
- package/lib/bs/tests/Seed_UsersTest-ReventlessSeed.cmj +0 -0
- package/lib/bs/tests/Seed_UsersTest-ReventlessSeed.cmt +0 -0
- package/lib/bs/tests/Seed_UsersTest.ast +0 -0
- package/lib/bs/tests/Seed_UsersTest.res +129 -0
- package/lib/bs/tests/Seed_UsersTest.res.mjs +113 -0
- package/lib/ocaml/.compiler.log +2 -2
- package/lib/ocaml/ReventlessSeed.cmi +0 -0
- package/lib/ocaml/ReventlessSeed.cmt +0 -0
- package/lib/ocaml/ReventlessSeed.mlmap +6 -0
- package/lib/ocaml/Seed-ReventlessSeed.cmi +0 -0
- package/lib/ocaml/Seed-ReventlessSeed.cmt +0 -0
- package/lib/ocaml/Seed.ast +0 -0
- package/lib/ocaml/Seed.res +12 -3
- package/lib/ocaml/Seed_Client-ReventlessSeed.cmi +0 -0
- package/lib/ocaml/Seed_Client-ReventlessSeed.cmj +0 -0
- package/lib/ocaml/Seed_Client-ReventlessSeed.cmt +0 -0
- package/lib/ocaml/Seed_Client.ast +0 -0
- package/lib/ocaml/Seed_Client.res +382 -21
- package/lib/ocaml/Seed_ClientTest-ReventlessSeed.cmi +0 -0
- package/lib/ocaml/Seed_ClientTest-ReventlessSeed.cmj +0 -0
- package/lib/ocaml/Seed_ClientTest-ReventlessSeed.cmt +0 -0
- package/lib/ocaml/Seed_ClientTest.ast +0 -0
- package/lib/ocaml/Seed_ClientTest.res +287 -0
- package/lib/ocaml/Seed_Connect-ReventlessSeed.cmi +0 -0
- package/lib/ocaml/Seed_Connect-ReventlessSeed.cmj +0 -0
- package/lib/ocaml/Seed_Connect-ReventlessSeed.cmt +0 -0
- package/lib/ocaml/Seed_Connect.ast +0 -0
- package/lib/ocaml/Seed_Connect.res +281 -33
- package/lib/ocaml/Seed_ConnectTest-ReventlessSeed.cmi +0 -0
- package/lib/ocaml/Seed_ConnectTest-ReventlessSeed.cmj +0 -0
- package/lib/ocaml/Seed_ConnectTest-ReventlessSeed.cmt +0 -0
- package/lib/ocaml/Seed_ConnectTest.ast +0 -0
- package/lib/ocaml/Seed_ConnectTest.res +64 -0
- package/lib/ocaml/Seed_Prompt-ReventlessSeed.cmi +0 -0
- package/lib/ocaml/Seed_Prompt-ReventlessSeed.cmj +0 -0
- package/lib/ocaml/Seed_Prompt-ReventlessSeed.cmt +0 -0
- package/lib/ocaml/Seed_Prompt.ast +0 -0
- package/lib/ocaml/Seed_Prompt.res +140 -41
- package/lib/ocaml/Seed_PromptTest-ReventlessSeed.cmi +0 -0
- package/lib/ocaml/Seed_PromptTest-ReventlessSeed.cmj +0 -0
- package/lib/ocaml/Seed_PromptTest-ReventlessSeed.cmt +0 -0
- package/lib/ocaml/Seed_PromptTest.ast +0 -0
- package/lib/ocaml/Seed_PromptTest.res +55 -0
- package/lib/ocaml/Seed_Random-ReventlessSeed.cmi +0 -0
- package/lib/ocaml/Seed_Random-ReventlessSeed.cmt +0 -0
- package/lib/ocaml/Seed_Random.ast +0 -0
- package/lib/ocaml/Seed_Random.res +4 -2
- package/lib/ocaml/Seed_RandomTest-ReventlessSeed.cmi +0 -0
- package/lib/ocaml/Seed_RandomTest-ReventlessSeed.cmj +0 -0
- package/lib/ocaml/Seed_RandomTest-ReventlessSeed.cmt +0 -0
- package/lib/ocaml/Seed_RandomTest.ast +0 -0
- package/lib/ocaml/Seed_RandomTest.res +200 -0
- package/lib/ocaml/Seed_Runner-ReventlessSeed.cmi +0 -0
- package/lib/ocaml/Seed_Runner-ReventlessSeed.cmj +0 -0
- package/lib/ocaml/Seed_Runner-ReventlessSeed.cmt +0 -0
- package/lib/ocaml/Seed_Runner.ast +0 -0
- package/lib/ocaml/Seed_Runner.res +45 -19
- package/lib/ocaml/Seed_Types-ReventlessSeed.cmt +0 -0
- package/lib/ocaml/Seed_Upload-ReventlessSeed.cmi +0 -0
- package/lib/ocaml/Seed_Upload-ReventlessSeed.cmj +0 -0
- package/lib/ocaml/Seed_Upload-ReventlessSeed.cmt +0 -0
- package/lib/ocaml/Seed_Upload.ast +0 -0
- package/lib/ocaml/Seed_Upload.res +43 -43
- package/lib/ocaml/Seed_Users-ReventlessSeed.cmi +0 -0
- package/lib/ocaml/Seed_Users-ReventlessSeed.cmj +0 -0
- package/lib/ocaml/Seed_Users-ReventlessSeed.cmt +0 -0
- package/lib/ocaml/Seed_Users.ast +0 -0
- package/lib/ocaml/Seed_Users.res +92 -0
- package/lib/ocaml/Seed_UsersTest-ReventlessSeed.cmi +0 -0
- package/lib/ocaml/Seed_UsersTest-ReventlessSeed.cmj +0 -0
- package/lib/ocaml/Seed_UsersTest-ReventlessSeed.cmt +0 -0
- package/lib/ocaml/Seed_UsersTest.ast +0 -0
- package/lib/ocaml/Seed_UsersTest.res +129 -0
- package/package.json +7 -2
- package/rescript.json +9 -1
- package/src/Seed.res +12 -3
- package/src/Seed.res.mjs +3 -0
- package/src/Seed_Client.res +382 -21
- package/src/Seed_Client.res.mjs +332 -24
- package/src/Seed_Connect.res +281 -33
- package/src/Seed_Connect.res.mjs +162 -8
- package/src/Seed_Prompt.res +140 -41
- package/src/Seed_Prompt.res.mjs +88 -13
- package/src/Seed_Random.res +4 -2
- package/src/Seed_Runner.res +45 -19
- package/src/Seed_Runner.res.mjs +19 -1
- package/src/Seed_Upload.res +43 -43
- package/src/Seed_Upload.res.mjs +65 -69
- package/src/Seed_Users.res +92 -0
- package/src/Seed_Users.res.mjs +91 -0
- package/tests/Seed_ClientTest.res +287 -0
- package/tests/Seed_ClientTest.res.mjs +268 -0
- package/tests/Seed_ConnectTest.res +64 -0
- package/tests/Seed_ConnectTest.res.mjs +56 -0
- package/tests/Seed_PromptTest.res +55 -0
- package/tests/Seed_PromptTest.res.mjs +63 -0
- package/tests/Seed_RandomTest.res +200 -0
- package/tests/Seed_RandomTest.res.mjs +208 -0
- package/tests/Seed_UsersTest.res +129 -0
- package/tests/Seed_UsersTest.res.mjs +113 -0
package/src/Seed_Upload.res
CHANGED
|
@@ -1,27 +1,26 @@
|
|
|
1
|
-
// Seed-time asset upload against the framework's
|
|
1
|
+
// Seed-time asset upload against the framework's upload contract (route B).
|
|
2
2
|
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
// stores and the UI renders.
|
|
3
|
+
// Minting is a GraphQL mutation on the domain API — `Upload_Presign(store, fileName,
|
|
4
|
+
// contentType)` — authenticated by the same bearer the seed already uses for commands
|
|
5
|
+
// (no separate endpoint, no anonymous surface). `uploadAsset` issues it through the
|
|
6
|
+
// shared `Seed_Client`, then PUTs the bytes to the returned `uploadUrl` and resolves
|
|
7
|
+
// `Ok(storageRef)` — the same `/{prefix}/{key}` ref a command stores and the UI renders.
|
|
8
8
|
//
|
|
9
|
-
// The seed runs under Node, so
|
|
10
|
-
// absolute URL against the
|
|
11
|
-
//
|
|
12
|
-
//
|
|
9
|
+
// The seed runs under Node, so a relative `uploadUrl` (the local dev server returns a
|
|
10
|
+
// same-origin `/{prefix}/{key}`) is resolved to an absolute URL against the client's
|
|
11
|
+
// endpoint origin before the PUT; AWS returns an absolute presigned S3 URL (used as-is).
|
|
12
|
+
// The PUT itself is unauthenticated — presigned on AWS, open on the local route.
|
|
13
13
|
|
|
14
14
|
type fetchInit = {method: string, headers: dict<string>, body: string}
|
|
15
15
|
type response
|
|
16
16
|
|
|
17
17
|
@val external fetch: (string, fetchInit) => promise<response> = "fetch"
|
|
18
|
-
@send external responseJson: response => promise<JSON.t> = "json"
|
|
19
18
|
@send external responseText: response => promise<string> = "text"
|
|
20
19
|
@get external responseOk: response => bool = "ok"
|
|
21
20
|
@get external responseStatus: response => int = "status"
|
|
22
21
|
|
|
23
|
-
// Resolve a possibly-relative URL against a base (WHATWG URL semantics: an
|
|
24
|
-
//
|
|
22
|
+
// Resolve a possibly-relative URL against a base (WHATWG URL semantics: an absolute
|
|
23
|
+
// `input` ignores `base`, a relative one is resolved against it).
|
|
25
24
|
type url
|
|
26
25
|
@new external makeUrl: (string, string) => url = "URL"
|
|
27
26
|
@get external urlHref: url => string = "href"
|
|
@@ -38,51 +37,52 @@ let asString = (json: JSON.t): option<string> =>
|
|
|
38
37
|
| _ => None
|
|
39
38
|
}
|
|
40
39
|
|
|
41
|
-
//
|
|
42
|
-
//
|
|
40
|
+
// Whether this run should skip uploads entirely. `SEED_SKIP_UPLOADS` seeds domain data
|
|
41
|
+
// fast, or skips a broken/absent upload path without editing the data set.
|
|
42
|
+
let uploadsSkipped = (): bool => Seed_Prompt.envValue("SEED_SKIP_UPLOADS")->Option.isSome
|
|
43
|
+
|
|
44
|
+
// A `fetch` that reports an unreachable endpoint as `Error` instead of throwing.
|
|
43
45
|
let tryFetch = async (url: string, init: fetchInit): result<response, string> =>
|
|
44
46
|
try Ok(await fetch(url, init)) catch {
|
|
45
47
|
| _ => Error(`cannot reach ${url}`)
|
|
46
48
|
}
|
|
47
49
|
|
|
48
50
|
/**
|
|
49
|
-
* Uploads `bytes` under `fileName`/`contentType`
|
|
51
|
+
* Uploads `bytes` under `fileName`/`contentType` into `store` (the qualified
|
|
52
|
+
* `{plugin}.{store}` the asset's field declares, e.g. `"Catalog.productImages"`) and
|
|
50
53
|
* resolves `Ok(storageRef)` (the stored `/{prefix}/{key}` ref), or `Error(msg)`
|
|
51
|
-
* describing the step that failed.
|
|
52
|
-
*
|
|
53
|
-
* the PUT itself is unauthenticated — presigned on AWS, open locally).
|
|
54
|
+
* describing the step that failed. Mints through the domain API's `Upload_Presign`
|
|
55
|
+
* mutation on `client`, then PUTs the bytes to the returned `uploadUrl`.
|
|
54
56
|
*/
|
|
55
57
|
let uploadAsset = async (
|
|
56
|
-
~
|
|
58
|
+
~client: Seed_Client.t,
|
|
59
|
+
~store: string,
|
|
57
60
|
~bytes: string,
|
|
58
61
|
~fileName: string,
|
|
59
62
|
~contentType: string,
|
|
60
|
-
~authToken: option<string>=?,
|
|
61
63
|
): result<string, string> => {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
let
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
)
|
|
64
|
+
// GraphQL string literals: JSON-quote the argument values (JSON string escaping is a
|
|
65
|
+
// superset-safe subset of GraphQL's for these ASCII-ish inputs).
|
|
66
|
+
let q = s => JSON.stringify(JSON.Encode.string(s))
|
|
67
|
+
let query = `mutation { r: Upload_Presign(store: ${q(store)}, fileName: ${q(
|
|
68
|
+
fileName,
|
|
69
|
+
)}, contentType: ${q(contentType)}) { uploadUrl storageRef } }`
|
|
70
|
+
|
|
71
|
+
let presign = try Ok(await Seed_Client.gql(client, ~query, ~label="Upload_Presign")) catch {
|
|
72
|
+
| Seed_Types.Failed(m) => Error(m)
|
|
73
|
+
| _ => Error("Upload_Presign: unexpected error")
|
|
74
|
+
}
|
|
72
75
|
|
|
73
|
-
switch
|
|
74
|
-
| Error(m) => Error(`presign: ${m}
|
|
75
|
-
| Ok(
|
|
76
|
-
let
|
|
77
|
-
Error(`presign failed with HTTP ${(presignRes->responseStatus)->Int.toString}: ${detail}`)
|
|
78
|
-
| Ok(presignRes) =>
|
|
79
|
-
let json = await presignRes->responseJson
|
|
76
|
+
switch presign {
|
|
77
|
+
| Error(m) => Error(`presign: ${m}`)
|
|
78
|
+
| Ok(data) =>
|
|
79
|
+
let r = data->field("r")->Option.getOr(JSON.Encode.null)
|
|
80
80
|
switch (
|
|
81
|
-
|
|
82
|
-
|
|
81
|
+
r->field("uploadUrl")->Option.flatMap(asString),
|
|
82
|
+
r->field("storageRef")->Option.flatMap(asString),
|
|
83
83
|
) {
|
|
84
84
|
| (Some(uploadUrl), Some(storageRef)) =>
|
|
85
|
-
let putUrl = urlHref(makeUrl(uploadUrl,
|
|
85
|
+
let putUrl = urlHref(makeUrl(uploadUrl, Seed_Client.endpoint(client)))
|
|
86
86
|
switch await tryFetch(
|
|
87
87
|
putUrl,
|
|
88
88
|
{method: "PUT", headers: Dict.fromArray([("content-type", contentType)]), body: bytes},
|
|
@@ -91,9 +91,9 @@ let uploadAsset = async (
|
|
|
91
91
|
| Ok(putRes) if putRes->responseOk => Ok(storageRef)
|
|
92
92
|
| Ok(putRes) =>
|
|
93
93
|
let detail = await putRes->responseText
|
|
94
|
-
Error(`upload PUT failed with HTTP ${
|
|
94
|
+
Error(`upload PUT failed with HTTP ${putRes->responseStatus->Int.toString}: ${detail}`)
|
|
95
95
|
}
|
|
96
|
-
| _ => Error("
|
|
96
|
+
| _ => Error("Upload_Presign response missing uploadUrl/storageRef")
|
|
97
97
|
}
|
|
98
98
|
}
|
|
99
99
|
}
|
package/src/Seed_Upload.res.mjs
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
2
|
|
|
3
3
|
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
4
|
+
import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
|
|
5
|
+
import * as Seed_Types$ReventlessSeed from "./Seed_Types.res.mjs";
|
|
6
|
+
import * as Seed_Client$ReventlessSeed from "./Seed_Client.res.mjs";
|
|
7
|
+
import * as Seed_Prompt$ReventlessSeed from "./Seed_Prompt.res.mjs";
|
|
4
8
|
|
|
5
9
|
function field(json, key) {
|
|
6
10
|
if (typeof json === "object" && json !== null && !Array.isArray(json)) {
|
|
@@ -14,6 +18,10 @@ function asString(json) {
|
|
|
14
18
|
}
|
|
15
19
|
}
|
|
16
20
|
|
|
21
|
+
function uploadsSkipped() {
|
|
22
|
+
return Stdlib_Option.isSome(Seed_Prompt$ReventlessSeed.envValue("SEED_SKIP_UPLOADS"));
|
|
23
|
+
}
|
|
24
|
+
|
|
17
25
|
async function tryFetch(url, init) {
|
|
18
26
|
try {
|
|
19
27
|
return {
|
|
@@ -28,91 +36,79 @@ async function tryFetch(url, init) {
|
|
|
28
36
|
}
|
|
29
37
|
}
|
|
30
38
|
|
|
31
|
-
async function uploadAsset(
|
|
32
|
-
let
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
method: "POST",
|
|
51
|
-
headers: presignHeaders,
|
|
52
|
-
body: presignBody
|
|
53
|
-
});
|
|
54
|
-
if (m.TAG !== "Ok") {
|
|
39
|
+
async function uploadAsset(client, store, bytes, fileName, contentType) {
|
|
40
|
+
let query = `mutation { r: Upload_Presign(store: ` + JSON.stringify(store) + `, fileName: ` + JSON.stringify(fileName) + `, contentType: ` + JSON.stringify(contentType) + `) { uploadUrl storageRef } }`;
|
|
41
|
+
let presign;
|
|
42
|
+
try {
|
|
43
|
+
presign = {
|
|
44
|
+
TAG: "Ok",
|
|
45
|
+
_0: await Seed_Client$ReventlessSeed.gql(client, query, "Upload_Presign")
|
|
46
|
+
};
|
|
47
|
+
} catch (raw_m) {
|
|
48
|
+
let m = Primitive_exceptions.internalToException(raw_m);
|
|
49
|
+
presign = m.RE_EXN_ID === Seed_Types$ReventlessSeed.Failed ? ({
|
|
50
|
+
TAG: "Error",
|
|
51
|
+
_0: m._1
|
|
52
|
+
}) : ({
|
|
53
|
+
TAG: "Error",
|
|
54
|
+
_0: "Upload_Presign: unexpected error"
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
if (presign.TAG !== "Ok") {
|
|
55
58
|
return {
|
|
56
59
|
TAG: "Error",
|
|
57
|
-
_0: `presign: ` +
|
|
60
|
+
_0: `presign: ` + presign._0
|
|
58
61
|
};
|
|
59
62
|
}
|
|
60
|
-
let
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
let match$1 = Stdlib_Option.flatMap(field(json, "storageRef"), asString);
|
|
65
|
-
if (match === undefined) {
|
|
66
|
-
return {
|
|
67
|
-
TAG: "Error",
|
|
68
|
-
_0: "presign response missing uploadUrl/storageRef"
|
|
69
|
-
};
|
|
70
|
-
}
|
|
71
|
-
if (match$1 === undefined) {
|
|
72
|
-
return {
|
|
73
|
-
TAG: "Error",
|
|
74
|
-
_0: "presign response missing uploadUrl/storageRef"
|
|
75
|
-
};
|
|
76
|
-
}
|
|
77
|
-
let putUrl = new URL(match, uploadEndpoint).href;
|
|
78
|
-
let m$1 = await tryFetch(putUrl, {
|
|
79
|
-
method: "PUT",
|
|
80
|
-
headers: Object.fromEntries([[
|
|
81
|
-
"content-type",
|
|
82
|
-
contentType
|
|
83
|
-
]]),
|
|
84
|
-
body: bytes
|
|
85
|
-
});
|
|
86
|
-
if (m$1.TAG !== "Ok") {
|
|
87
|
-
return {
|
|
88
|
-
TAG: "Error",
|
|
89
|
-
_0: `upload PUT: ` + m$1._0
|
|
90
|
-
};
|
|
91
|
-
}
|
|
92
|
-
let putRes = m$1._0;
|
|
93
|
-
if (putRes.ok) {
|
|
94
|
-
return {
|
|
95
|
-
TAG: "Ok",
|
|
96
|
-
_0: match$1
|
|
97
|
-
};
|
|
98
|
-
}
|
|
99
|
-
let detail = await putRes.text();
|
|
63
|
+
let r = Stdlib_Option.getOr(field(presign._0, "r"), null);
|
|
64
|
+
let match = Stdlib_Option.flatMap(field(r, "uploadUrl"), asString);
|
|
65
|
+
let match$1 = Stdlib_Option.flatMap(field(r, "storageRef"), asString);
|
|
66
|
+
if (match === undefined) {
|
|
100
67
|
return {
|
|
101
68
|
TAG: "Error",
|
|
102
|
-
_0:
|
|
69
|
+
_0: "Upload_Presign response missing uploadUrl/storageRef"
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
if (match$1 === undefined) {
|
|
73
|
+
return {
|
|
74
|
+
TAG: "Error",
|
|
75
|
+
_0: "Upload_Presign response missing uploadUrl/storageRef"
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
let putUrl = new URL(match, Seed_Client$ReventlessSeed.endpoint(client)).href;
|
|
79
|
+
let m$1 = await tryFetch(putUrl, {
|
|
80
|
+
method: "PUT",
|
|
81
|
+
headers: Object.fromEntries([[
|
|
82
|
+
"content-type",
|
|
83
|
+
contentType
|
|
84
|
+
]]),
|
|
85
|
+
body: bytes
|
|
86
|
+
});
|
|
87
|
+
if (m$1.TAG !== "Ok") {
|
|
88
|
+
return {
|
|
89
|
+
TAG: "Error",
|
|
90
|
+
_0: `upload PUT: ` + m$1._0
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
let putRes = m$1._0;
|
|
94
|
+
if (putRes.ok) {
|
|
95
|
+
return {
|
|
96
|
+
TAG: "Ok",
|
|
97
|
+
_0: match$1
|
|
103
98
|
};
|
|
104
99
|
}
|
|
105
|
-
let detail
|
|
100
|
+
let detail = await putRes.text();
|
|
106
101
|
return {
|
|
107
102
|
TAG: "Error",
|
|
108
|
-
_0: `
|
|
103
|
+
_0: `upload PUT failed with HTTP ` + putRes.status.toString() + `: ` + detail
|
|
109
104
|
};
|
|
110
105
|
}
|
|
111
106
|
|
|
112
107
|
export {
|
|
113
108
|
field,
|
|
114
109
|
asString,
|
|
110
|
+
uploadsSkipped,
|
|
115
111
|
tryFetch,
|
|
116
112
|
uploadAsset,
|
|
117
113
|
}
|
|
118
|
-
/*
|
|
114
|
+
/* Seed_Prompt-ReventlessSeed Not a pure module */
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
// The dev accounts a seed run can log in as, read from `.reventless/users.yaml`.
|
|
2
|
+
//
|
|
3
|
+
// Both platforms keep that file beside the package the seed runs from: locally
|
|
4
|
+
// the in-memory auth adapter loads it at startup, and on AWS it is the record of
|
|
5
|
+
// what was created in the Cognito pool. Either way it already holds the
|
|
6
|
+
// credentials an operator would otherwise retype, so the credential prompt
|
|
7
|
+
// offers its entries instead of asking for a password nobody remembers.
|
|
8
|
+
//
|
|
9
|
+
// Absence is normal and silent — the caller falls back to asking. Nothing here
|
|
10
|
+
// throws: a missing, unreadable or malformed file yields no accounts.
|
|
11
|
+
|
|
12
|
+
@module("yaml") external parseYaml: string => JSON.t = "parse"
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* One account: what to log in as, what to send with it, and — when the file
|
|
16
|
+
* records one — the id the platform stamps on rows this account writes.
|
|
17
|
+
*
|
|
18
|
+
* `userId` is optional because absence is normal on both platforms: a local file
|
|
19
|
+
* may omit it and let the auth adapter default it to the username, and a
|
|
20
|
+
* hand-maintained AWS file records subs the pool minted, so it can lag.
|
|
21
|
+
*/
|
|
22
|
+
type user = {
|
|
23
|
+
username: string,
|
|
24
|
+
password: string,
|
|
25
|
+
groups: array<string>,
|
|
26
|
+
userId: option<string>,
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
let asString = (json: JSON.t): option<string> =>
|
|
30
|
+
switch json {
|
|
31
|
+
| String(s) => Some(s)
|
|
32
|
+
| _ => None
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
let userOf = (json: JSON.t): option<user> =>
|
|
36
|
+
switch json {
|
|
37
|
+
| Object(obj) =>
|
|
38
|
+
switch (
|
|
39
|
+
obj->Dict.get("username")->Option.flatMap(asString),
|
|
40
|
+
obj->Dict.get("password")->Option.flatMap(asString),
|
|
41
|
+
) {
|
|
42
|
+
| (Some(username), Some(password)) =>
|
|
43
|
+
let groups = switch obj->Dict.get("groups") {
|
|
44
|
+
| Some(JSON.Array(items)) => items->Array.filterMap(asString)
|
|
45
|
+
| _ => []
|
|
46
|
+
}
|
|
47
|
+
Some({username, password, groups, userId: obj->Dict.get("userId")->Option.flatMap(asString)})
|
|
48
|
+
| _ => None
|
|
49
|
+
}
|
|
50
|
+
| _ => None
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* The accounts a users.yaml document defines, in the order it defines them —
|
|
55
|
+
* the order is what makes "the first one" a stable default.
|
|
56
|
+
*
|
|
57
|
+
* An entry without both a username and a password is skipped rather than
|
|
58
|
+
* rejected: the file is hand-maintained, and one incomplete entry should not
|
|
59
|
+
* cost the operator the rest of the list.
|
|
60
|
+
*/
|
|
61
|
+
let parseString = (yamlText: string): array<user> => {
|
|
62
|
+
let doc = try parseYaml(yamlText) catch {
|
|
63
|
+
| _ => JSON.Null
|
|
64
|
+
}
|
|
65
|
+
switch doc {
|
|
66
|
+
| Array(items) => items->Array.filterMap(userOf)
|
|
67
|
+
| _ => []
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** Where the file lives for the platform being seeded — the seed runs from that
|
|
72
|
+
package's directory, which is the same cwd the local auth adapter reads. */
|
|
73
|
+
let defaultPath = (): string => NodePath.join([NodeProcess.cwd(), ".reventless", "users.yaml"])
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* The accounts on disk, with the path they came from. `None` when there is no
|
|
77
|
+
* readable file with at least one usable account, which the caller reads as
|
|
78
|
+
* "ask for credentials instead".
|
|
79
|
+
*/
|
|
80
|
+
let load = (~path: option<string>=?): option<(string, array<user>)> => {
|
|
81
|
+
let file = path->Option.getOr(defaultPath())
|
|
82
|
+
let users = try {
|
|
83
|
+
NodeFs.existsSync(file) ? parseString(NodeFs.readFileSync(file)) : []
|
|
84
|
+
} catch {
|
|
85
|
+
| _ => []
|
|
86
|
+
}
|
|
87
|
+
users->Array.length == 0 ? None : Some((file, users))
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/** Menu label: the username, plus whatever groups the file records for it. */
|
|
91
|
+
let label = (u: user): string =>
|
|
92
|
+
u.groups->Array.length == 0 ? u.username : `${u.username} [${u.groups->Array.join(", ")}]`
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as Yaml from "yaml";
|
|
4
|
+
import * as Nodefs from "node:fs";
|
|
5
|
+
import * as Nodepath from "node:path";
|
|
6
|
+
import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
|
|
7
|
+
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
8
|
+
|
|
9
|
+
function asString(json) {
|
|
10
|
+
if (typeof json === "string") {
|
|
11
|
+
return json;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function userOf(json) {
|
|
16
|
+
if (typeof json !== "object" || json === null || Array.isArray(json)) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
let match = Stdlib_Option.flatMap(json["username"], asString);
|
|
20
|
+
let match$1 = Stdlib_Option.flatMap(json["password"], asString);
|
|
21
|
+
if (match === undefined) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
if (match$1 === undefined) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
let match$2 = json["groups"];
|
|
28
|
+
let groups = match$2 !== undefined ? (
|
|
29
|
+
Array.isArray(match$2) ? Stdlib_Array.filterMap(match$2, asString) : []
|
|
30
|
+
) : [];
|
|
31
|
+
return {
|
|
32
|
+
username: match,
|
|
33
|
+
password: match$1,
|
|
34
|
+
groups: groups,
|
|
35
|
+
userId: Stdlib_Option.flatMap(json["userId"], asString)
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function parseString(yamlText) {
|
|
40
|
+
let doc;
|
|
41
|
+
try {
|
|
42
|
+
doc = Yaml.parse(yamlText);
|
|
43
|
+
} catch (exn) {
|
|
44
|
+
doc = null;
|
|
45
|
+
}
|
|
46
|
+
if (Array.isArray(doc)) {
|
|
47
|
+
return Stdlib_Array.filterMap(doc, userOf);
|
|
48
|
+
} else {
|
|
49
|
+
return [];
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function defaultPath() {
|
|
54
|
+
return Nodepath.join(process.cwd(), ".reventless", "users.yaml");
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function load(path) {
|
|
58
|
+
let file = Stdlib_Option.getOr(path, defaultPath());
|
|
59
|
+
let users;
|
|
60
|
+
try {
|
|
61
|
+
users = Nodefs.existsSync(file) ? parseString(Nodefs.readFileSync(file, "utf8")) : [];
|
|
62
|
+
} catch (exn) {
|
|
63
|
+
users = [];
|
|
64
|
+
}
|
|
65
|
+
if (users.length === 0) {
|
|
66
|
+
return;
|
|
67
|
+
} else {
|
|
68
|
+
return [
|
|
69
|
+
file,
|
|
70
|
+
users
|
|
71
|
+
];
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function label(u) {
|
|
76
|
+
if (u.groups.length === 0) {
|
|
77
|
+
return u.username;
|
|
78
|
+
} else {
|
|
79
|
+
return u.username + ` [` + u.groups.join(", ") + `]`;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export {
|
|
84
|
+
asString,
|
|
85
|
+
userOf,
|
|
86
|
+
parseString,
|
|
87
|
+
defaultPath,
|
|
88
|
+
load,
|
|
89
|
+
label,
|
|
90
|
+
}
|
|
91
|
+
/* yaml Not a pure module */
|