@reventlessdev/reventless-aws 3.0.0-alpha.248 → 3.0.0-alpha.249
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 +8 -0
- package/package.json +13 -12
- package/rescript.json +1 -0
- package/src/adapter/Api/AppSyncEventsSigner_Ops.res +11 -29
- package/src/adapter/Api/Platform_ComponentDefinitions_Lambda_Ops.res +2 -3
- package/src/adapter/Api/Platform_UIFragments_Lambda_Ops.res +1 -2
- package/src/adapter/EventLogSubscription/EventLogSubscription_AppSync_Ops.res +2 -3
- package/src/adapter/Geocoder/Geocoder_AwsLocation_Ops.res +1 -2
- package/src/adapter/Runtime/AutomationSliceEntryPoint_Ops.res +1 -2
- package/src/adapter/Runtime/EventCollectorEntryPoint_Ops.res +5 -7
- package/src/adapter/Runtime/ExtensionPointEntryPoint_Ops.res +1 -2
- package/src/adapter/Runtime/HeartbeatEntryPoint.res +3 -4
- package/src/adapter/Runtime/PgChangeFeedRelayEntryPoint.res +1 -2
- package/src/adapter/Runtime/PgMigrationEntryPoint.res +1 -2
- package/src/adapter/Runtime/PluginExtensionPointEntryPoint.res +3 -4
- package/src/adapter/Runtime/ProjectionEntryPoint_Ops.res +2 -3
- package/src/adapter/Runtime/TaskBucketEntryPoint_Ops.res +4 -5
- package/src/adapter/StateTopic/StateTopic_AppSync_Ops.res +2 -3
- package/src/adapter/Upload/Upload_Presign_S3_Ops.res +2 -5
- package/src/components/Api/AppSync_Adapter.res +1 -6
- package/src/util/Util_Bundle.res +24 -50
- package/src/util/Util_Bundle.res.mjs +20 -20
- package/src/util/Util_LocalConfig.res +7 -14
- package/src/util/Util_LocalConfig.res.mjs +8 -8
- package/src/util/Util_SQS_Runtime.res +1 -5
- package/src/util/Util_StaticBundle.res +12 -29
- package/src/util/Util_StaticBundle.res.mjs +11 -11
- package/tests/ExtensionPointEntryPoint_OpsTest.res +1 -2
- package/tests/PgChangeFeedRelay_IntegrationTest.res +1 -2
- package/tests/PgMigrationEntryPoint_IntegrationTest.res +1 -2
- package/tests/PgPipeline_IntegrationTest.res +1 -2
- package/tests/TaskBucketEntryPoint_OpsTest.res +2 -3
- package/tests/Util_BundleResolveTest.res +12 -18
- package/tests/Util_BundleResolveTest.res.mjs +8 -8
- package/tests/Util_StaticBundleTest.res +28 -35
- package/tests/Util_StaticBundleTest.res.mjs +31 -31
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,14 @@
|
|
|
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
|
+
# 3.0.0-alpha.249 (2026-07-31)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @reventlessdev/reventless-aws
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
6
14
|
# 3.0.0-alpha.248 (2026-07-30)
|
|
7
15
|
|
|
8
16
|
### Bug Fixes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reventlessdev/reventless-aws",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.249",
|
|
4
4
|
"description": "AWS adapters for Reventless",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"dependencies": {
|
|
@@ -11,17 +11,18 @@
|
|
|
11
11
|
"@aws-sdk/s3-request-presigner": "3.970.0",
|
|
12
12
|
"sury": "11.0.0-alpha.4",
|
|
13
13
|
"uuid": "^13.0.0",
|
|
14
|
-
"@reventlessdev/rescript-aws-sdk": "
|
|
15
|
-
"@reventlessdev/rescript-
|
|
16
|
-
"@reventlessdev/rescript-
|
|
17
|
-
"@reventlessdev/rescript-
|
|
18
|
-
"@reventlessdev/rescript-pulumi-aws": "2.4.0-alpha.
|
|
19
|
-
"@reventlessdev/rescript-uuid": "
|
|
20
|
-
"@reventlessdev/reventless-core": "3.0.0-alpha.
|
|
21
|
-
"@reventlessdev/reventless-
|
|
22
|
-
"@reventlessdev/reventless-
|
|
23
|
-
"@reventlessdev/
|
|
24
|
-
"@reventlessdev/reventless-
|
|
14
|
+
"@reventlessdev/rescript-aws-sdk": "3.0.0-alpha.0",
|
|
15
|
+
"@reventlessdev/rescript-effect": "0.1.0-alpha.32",
|
|
16
|
+
"@reventlessdev/rescript-node": "2.0.0-alpha.0",
|
|
17
|
+
"@reventlessdev/rescript-jest": "1.0.0-alpha.10",
|
|
18
|
+
"@reventlessdev/rescript-pulumi-aws": "2.4.0-alpha.62",
|
|
19
|
+
"@reventlessdev/rescript-uuid": "2.0.0-alpha.0",
|
|
20
|
+
"@reventlessdev/reventless-core": "3.0.0-alpha.196",
|
|
21
|
+
"@reventlessdev/reventless-interop": "3.0.0-alpha.30",
|
|
22
|
+
"@reventlessdev/reventless-infra": "3.0.0-alpha.114",
|
|
23
|
+
"@reventlessdev/rescript-pulumi-pulumi": "2.3.0-alpha.18",
|
|
24
|
+
"@reventlessdev/reventless-spec": "3.0.0-alpha.89",
|
|
25
|
+
"@reventlessdev/reventless-postgres": "3.0.0-alpha.60"
|
|
25
26
|
},
|
|
26
27
|
"devDependencies": {
|
|
27
28
|
"rescript": "12.3.0",
|
package/rescript.json
CHANGED
|
@@ -11,44 +11,26 @@
|
|
|
11
11
|
// AppSyncEventsSigner_ParityFixture.mjs pins that original as a golden reference
|
|
12
12
|
// and AppSyncEventsSigner_OpsTest asserts byte-for-byte equality.
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
let sha256hex = (data: string): string =>
|
|
15
|
+
NodeCrypto.createHash("sha256")->NodeCrypto.hashUpdate(data)->NodeCrypto.hashDigest("hex")
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
@module("node:crypto") external createHmacBuf: (string, buffer) => hmac = "createHmac"
|
|
22
|
-
@send external hmacUpdate: (hmac, string) => hmac = "update"
|
|
23
|
-
@send external hmacDigestBuf: hmac => buffer = "digest"
|
|
24
|
-
@send external hmacDigestHex: (hmac, string) => string = "digest"
|
|
25
|
-
|
|
26
|
-
type hash
|
|
27
|
-
@module("node:crypto") external createHash: string => hash = "createHash"
|
|
28
|
-
@send external hashUpdate: (hash, string) => hash = "update"
|
|
29
|
-
@send external hashDigestHex: (hash, string) => string = "digest"
|
|
30
|
-
|
|
31
|
-
let sha256hex = (data: string): string => createHash("sha256")->hashUpdate(data)->hashDigestHex("hex")
|
|
32
|
-
|
|
33
|
-
let hmacFromStr = (key: string, data: string): buffer =>
|
|
34
|
-
createHmacStr("sha256", key)->hmacUpdate(data)->hmacDigestBuf
|
|
35
|
-
let hmacFromBuf = (key: buffer, data: string): buffer =>
|
|
36
|
-
createHmacBuf("sha256", key)->hmacUpdate(data)->hmacDigestBuf
|
|
17
|
+
let hmacFromStr = (key: string, data: string): NodeCrypto.buffer =>
|
|
18
|
+
NodeCrypto.createHmac("sha256", key)->NodeCrypto.hmacUpdate(data)->NodeCrypto.hmacDigestBuffer
|
|
19
|
+
let hmacFromBuf = (key: NodeCrypto.buffer, data: string): NodeCrypto.buffer =>
|
|
20
|
+
NodeCrypto.createHmacFromBuffer("sha256", key)->NodeCrypto.hmacUpdate(data)->NodeCrypto.hmacDigestBuffer
|
|
37
21
|
|
|
38
22
|
// ── SigV4 ───────────────────────────────────────────────────────────────────
|
|
39
23
|
|
|
40
24
|
type creds = {accessKeyId: string, secretAccessKey: string, sessionToken: option<string>}
|
|
41
25
|
|
|
42
|
-
@val @scope("process") external processEnv: dict<string> = "env"
|
|
43
|
-
|
|
44
26
|
// Ambient Lambda execution-role credentials (the managed runtime injects these).
|
|
45
27
|
let envCreds = (): creds => {
|
|
46
|
-
accessKeyId:
|
|
47
|
-
secretAccessKey:
|
|
48
|
-
sessionToken:
|
|
28
|
+
accessKeyId: NodeProcess.env->Dict.get("AWS_ACCESS_KEY_ID")->Option.getOr(""),
|
|
29
|
+
secretAccessKey: NodeProcess.env->Dict.get("AWS_SECRET_ACCESS_KEY")->Option.getOr(""),
|
|
30
|
+
sessionToken: NodeProcess.env->Dict.get("AWS_SESSION_TOKEN"),
|
|
49
31
|
}
|
|
50
32
|
|
|
51
|
-
let region = (): string =>
|
|
33
|
+
let region = (): string => NodeProcess.env->Dict.get("AWS_REGION")->Option.getOr("eu-west-1")
|
|
52
34
|
|
|
53
35
|
// Sign a `POST <path>` for service `appsync`. `isoNow` is a Date().toISOString()
|
|
54
36
|
// string, taken as an argument so the signer is pure and parity-testable. The
|
|
@@ -89,7 +71,7 @@ let signedHeaders = (
|
|
|
89
71
|
let kRegion = hmacFromBuf(kDate, region)
|
|
90
72
|
let kService = hmacFromBuf(kRegion, "appsync")
|
|
91
73
|
let kSigning = hmacFromBuf(kService, "aws4_request")
|
|
92
|
-
let signature =
|
|
74
|
+
let signature = NodeCrypto.createHmacFromBuffer("sha256", kSigning)->NodeCrypto.hmacUpdate(stringToSign)->NodeCrypto.hmacDigest("hex")
|
|
93
75
|
|
|
94
76
|
let authorization = `AWS4-HMAC-SHA256 Credential=${creds.accessKeyId}/${scope}, SignedHeaders=${signedHeaderList}, Signature=${signature}`
|
|
95
77
|
let out = Dict.fromArray(sorted)
|
|
@@ -12,7 +12,6 @@
|
|
|
12
12
|
// sury-encoded with the same shape as the in-memory adapter's
|
|
13
13
|
// encodePluginStructureEntry, so it is wrapped with `pluginId` without decoding.
|
|
14
14
|
|
|
15
|
-
@val @scope("process") external processEnv: dict<string> = "env"
|
|
16
15
|
|
|
17
16
|
let str = (item: dict<JSON.t>, key: string): option<string> =>
|
|
18
17
|
item->Dict.get(key)->Option.flatMap(JSON.Decode.string)
|
|
@@ -61,14 +60,14 @@ let toEntry = (item: dict<JSON.t>, ~name: string): option<JSON.t> =>
|
|
|
61
60
|
// ADMIN_ENTRY_JSON env var (the admin never Connects to itself, so its structure
|
|
62
61
|
// never enters the Plugin read model).
|
|
63
62
|
let adminEntry: option<JSON.t> =
|
|
64
|
-
switch
|
|
63
|
+
switch NodeProcess.env->Dict.get("ADMIN_ENTRY_JSON") {
|
|
65
64
|
| Some(s) if s != "" => Some(JSON.parseOrThrow(s))
|
|
66
65
|
| _ => None
|
|
67
66
|
}
|
|
68
67
|
|
|
69
68
|
let handler = async (_event: JSON.t): array<JSON.t> => {
|
|
70
69
|
let admin = adminEntry->Option.mapOr([], e => [e])
|
|
71
|
-
switch
|
|
70
|
+
switch NodeProcess.env->Dict.get("PLUGIN_RM_TABLE") {
|
|
72
71
|
| None | Some("") =>
|
|
73
72
|
Console.error("Platform_ComponentDefinitions: PLUGIN_RM_TABLE env var not set")
|
|
74
73
|
admin
|
|
@@ -11,7 +11,6 @@
|
|
|
11
11
|
// adapter's Platform_UIFragmentsApi.encodeUIFragmentEntry produces, so rows are
|
|
12
12
|
// returned as-is (bar the name/version collapse).
|
|
13
13
|
|
|
14
|
-
@val @scope("process") external processEnv: dict<string> = "env"
|
|
15
14
|
|
|
16
15
|
let str = (item: dict<JSON.t>, key: string): option<string> =>
|
|
17
16
|
item->Dict.get(key)->Option.flatMap(JSON.Decode.string)
|
|
@@ -38,7 +37,7 @@ let toEntry = (item: dict<JSON.t>, ~name: string): option<JSON.t> =>
|
|
|
38
37
|
}
|
|
39
38
|
|
|
40
39
|
let handler = async (_event: JSON.t): array<JSON.t> =>
|
|
41
|
-
switch
|
|
40
|
+
switch NodeProcess.env->Dict.get("UI_FRAGMENT_RM_TABLE") {
|
|
42
41
|
| None | Some("") =>
|
|
43
42
|
Console.error("Platform_UIFragments: UI_FRAGMENT_RM_TABLE env var not set")
|
|
44
43
|
[]
|
|
@@ -7,11 +7,10 @@
|
|
|
7
7
|
// body, wraps it as a `{position, eventType, payload}` event, and publishes it
|
|
8
8
|
// to the fixed plugin event-log channel on the AppSync Events API.
|
|
9
9
|
|
|
10
|
-
@val @scope("process") external processEnv: dict<string> = "env"
|
|
11
10
|
|
|
12
11
|
// Baked at deploy time: the normalised channel segment for this event log.
|
|
13
|
-
let channel = "/default/" ++
|
|
14
|
-
let endpoint =
|
|
12
|
+
let channel = "/default/" ++ NodeProcess.env->Dict.get("EVENT_LOG_CHANNEL")->Option.getOr("")
|
|
13
|
+
let endpoint = NodeProcess.env->Dict.get("APPSYNC_ENDPOINT")->Option.getOr("")
|
|
15
14
|
|
|
16
15
|
// SQS Lambda event (only the fields this handler reads).
|
|
17
16
|
type sqsRecord = {body: string, messageId: string}
|
|
@@ -39,11 +39,10 @@ external makeSearchPlaceIndexForTextCommand: searchPlaceIndexForTextInput => sea
|
|
|
39
39
|
|
|
40
40
|
// ── Node bindings (replacing the former `%raw` env helper with a typed one) ──
|
|
41
41
|
|
|
42
|
-
@val @scope("process") external processEnv: dict<string> = "env"
|
|
43
42
|
|
|
44
43
|
// Read an env var, mapping "" / unset to None.
|
|
45
44
|
let getEnv = (k: string): option<string> =>
|
|
46
|
-
switch
|
|
45
|
+
switch NodeProcess.env->Dict.get(k) {
|
|
47
46
|
| Some("") | None => None
|
|
48
47
|
| Some(v) => Some(v)
|
|
49
48
|
}
|
|
@@ -20,7 +20,6 @@
|
|
|
20
20
|
// `callback.phase1`. The `bodyModule` and `context` HANDLER_CONFIG fields
|
|
21
21
|
// exist for this wiring (AutomationSliceRuntime_Builder_Single).
|
|
22
22
|
|
|
23
|
-
@val @scope("process") external processEnv: dict<string> = "env"
|
|
24
23
|
|
|
25
24
|
type handlerEntry = {
|
|
26
25
|
specModule: string,
|
|
@@ -81,7 +80,7 @@ let warnMissingBodyModule = (entry: handlerEntry) =>
|
|
|
81
80
|
// Fallback for automation entries from a config without `context` — sliceName
|
|
82
81
|
// is the only field the runtime can still recover.
|
|
83
82
|
let defaultContext = (sliceName: string): Reventless.AutomationSlice.context => {
|
|
84
|
-
environment:
|
|
83
|
+
environment: NodeProcess.env->Dict.get("Environment")->Option.getOr("unknown"),
|
|
85
84
|
platformName: "unknown",
|
|
86
85
|
pluginName: "unknown",
|
|
87
86
|
sliceName,
|
|
@@ -58,7 +58,6 @@ external scanByTableName: (
|
|
|
58
58
|
int,
|
|
59
59
|
) => promise<array<JSON.t>> = "scanByTableName"
|
|
60
60
|
|
|
61
|
-
@val @scope("process") external processEnv: dict<string> = "env"
|
|
62
61
|
|
|
63
62
|
let exnMessage = (exn: exn): string =>
|
|
64
63
|
exn->JsExn.fromException->Option.flatMap(JsExn.message)->Option.getOr("unknown error")
|
|
@@ -536,7 +535,7 @@ let reconcileSubscriptionsOnce = async (
|
|
|
536
535
|
// rule prefix must be stable across deploys and unique per stack;
|
|
537
536
|
// AWS_LAMBDA_FUNCTION_NAME carries a content hash. PluginExtensionPointEntryPoint
|
|
538
537
|
// instantiates the same admin EP module and must derive this identically.
|
|
539
|
-
let environment =
|
|
538
|
+
let environment = NodeProcess.env->Dict.get("Environment")->Option.getOr("unknown")
|
|
540
539
|
|
|
541
540
|
// Only what the admin EP mapping's callHandler needs: sendMessageToChannel for
|
|
542
541
|
// ForwardCommand.
|
|
@@ -613,7 +612,7 @@ let buildPublishToAggregates = (map: dict<string>): dict<ReventlessCore.CommandT
|
|
|
613
612
|
->Dict.toArray
|
|
614
613
|
->Array.map(((aggName, envVarName)) => (
|
|
615
614
|
aggName,
|
|
616
|
-
makePublishJsons(
|
|
615
|
+
makePublishJsons(NodeProcess.env->Dict.get(envVarName)->Option.getOr("")),
|
|
617
616
|
))
|
|
618
617
|
->Dict.fromArray
|
|
619
618
|
|
|
@@ -632,7 +631,7 @@ let extensionPublishDicts = (config: handlerConfig, ext: extensionConfig): exten
|
|
|
632
631
|
->Array.filterMap(name =>
|
|
633
632
|
envVarNames
|
|
634
633
|
->Dict.get(name)
|
|
635
|
-
->Option.flatMap(envVarName =>
|
|
634
|
+
->Option.flatMap(envVarName => NodeProcess.env->Dict.get(envVarName))
|
|
636
635
|
->Option.filter(queueUrl => queueUrl != "")
|
|
637
636
|
->Option.map(queueUrl => (name, makePublishJsons(queueUrl)))
|
|
638
637
|
)
|
|
@@ -666,7 +665,6 @@ let warnSkippedExtension = (ext: extensionConfig) =>
|
|
|
666
665
|
type url
|
|
667
666
|
@new external makeUrl: (string, string) => url = "URL"
|
|
668
667
|
@module("node:fs") external readFileSyncUrl: (url, string) => string = "readFileSync"
|
|
669
|
-
@val @scope("process") external cwd: unit => string = "cwd"
|
|
670
668
|
|
|
671
669
|
// pluginDefinition.json is written at deploy time as a stable JSON literal
|
|
672
670
|
// matching Reventless.Plugin.pluginDefinitionSchema (PluginRuntime_Builder), so
|
|
@@ -677,7 +675,7 @@ external asPluginDefinition: JSON.t => Reventless.Plugin.pluginDefinition = "%id
|
|
|
677
675
|
|
|
678
676
|
let loadPluginDefinition = (): Reventless.Plugin.pluginDefinition =>
|
|
679
677
|
try {
|
|
680
|
-
readFileSyncUrl(makeUrl("./pluginDefinition.json", `file://${cwd()}/`), "utf-8")
|
|
678
|
+
readFileSyncUrl(makeUrl("./pluginDefinition.json", `file://${NodeProcess.cwd()}/`), "utf-8")
|
|
681
679
|
->JSON.parseOrThrow
|
|
682
680
|
->asPluginDefinition
|
|
683
681
|
} catch {
|
|
@@ -693,7 +691,7 @@ let loadPluginDefinition = (): Reventless.Plugin.pluginDefinition =>
|
|
|
693
691
|
// both map to None.
|
|
694
692
|
let loadUiFragments = (): option<JSON.t> =>
|
|
695
693
|
try {
|
|
696
|
-
switch readFileSyncUrl(makeUrl("./uiFragments.json", `file://${cwd()}/`), "utf-8")->JSON.parseOrThrow {
|
|
694
|
+
switch readFileSyncUrl(makeUrl("./uiFragments.json", `file://${NodeProcess.cwd()}/`), "utf-8")->JSON.parseOrThrow {
|
|
697
695
|
| JSON.Null => None
|
|
698
696
|
| json => Some(json)
|
|
699
697
|
}
|
|
@@ -16,7 +16,6 @@
|
|
|
16
16
|
// records fix the shapes; scheduler/queryEngine still throw by design (not
|
|
17
17
|
// available in the bundled handler).
|
|
18
18
|
|
|
19
|
-
@val @scope("process") external processEnv: dict<string> = "env"
|
|
20
19
|
|
|
21
20
|
// ── Shim bindings (HandlerFactoryHelpers.mjs), typed for SQS records ────────
|
|
22
21
|
@module("./HandlerFactoryHelpers.mjs")
|
|
@@ -69,7 +68,7 @@ let makeCallbackSpec = (config: handlerConfig): callbackSpec => {
|
|
|
69
68
|
->Option.getOr(Dict.make())
|
|
70
69
|
->Dict.toArray
|
|
71
70
|
->Array.map(((aggName, envVarName)) => {
|
|
72
|
-
let queueUrl =
|
|
71
|
+
let queueUrl = NodeProcess.env->Dict.get(envVarName)->Option.getOr("")
|
|
73
72
|
let queue: Util_SQS_Runtime.resolvedQueue = {id: queueUrl, name: queueUrl, arn: ""}
|
|
74
73
|
(aggName, queue->CommandTopicChannel_SQS_Runtime.publishJsons(AWS.SQS_FIFO))
|
|
75
74
|
})
|
|
@@ -7,16 +7,15 @@
|
|
|
7
7
|
// Pulumi value reaches this module's import graph (deploy-time wiring lives in
|
|
8
8
|
// PluginRuntime_Builder.forPluginHeartbeat).
|
|
9
9
|
|
|
10
|
-
@val @scope("process") external processEnv: dict<string> = "env"
|
|
11
10
|
|
|
12
11
|
// === Initialize eagerly at module load (Lambda cold start) ===
|
|
13
12
|
|
|
14
|
-
let epQueueUrl =
|
|
15
|
-
let pluginId =
|
|
13
|
+
let epQueueUrl = NodeProcess.env->Dict.get("EP_QUEUE_URL")->Option.getOr("")
|
|
14
|
+
let pluginId = NodeProcess.env->Dict.get("PLUGIN_ID")->Option.getOr("")
|
|
16
15
|
// Mirrors the former shell's `parseInt(…) || 10`: unset, unparsable, and 0 all
|
|
17
16
|
// fall back to the 10-minute default.
|
|
18
17
|
let timeout =
|
|
19
|
-
|
|
18
|
+
NodeProcess.env
|
|
20
19
|
->Dict.get("HEARTBEAT_TIMEOUT")
|
|
21
20
|
->Option.flatMap(s => Int.fromString(s))
|
|
22
21
|
->Option.filter(n => n != 0)
|
|
@@ -23,7 +23,6 @@
|
|
|
23
23
|
// "kind"?: "classic", // absent → DCB
|
|
24
24
|
// "partitionTag"?: <derivedPartitionTag> } ] } // DCB only
|
|
25
25
|
|
|
26
|
-
@val @scope("process") external processEnv: dict<string> = "env"
|
|
27
26
|
|
|
28
27
|
// Structured JSON logging shared by every deployed entry point (HandlerFactoryHelpers).
|
|
29
28
|
type logExtra = {comp?: string}
|
|
@@ -89,7 +88,7 @@ let relayLog = async (l: relayLogConfig): unit => {
|
|
|
89
88
|
|
|
90
89
|
let handler = async (_event: JSON.t, _context: PulumiAws.Lambda.context) => {
|
|
91
90
|
let config =
|
|
92
|
-
|
|
91
|
+
NodeProcess.env->Dict.get("HANDLER_CONFIG")->Option.getOr(`{"logs":[]}`)->parseHandlerConfig
|
|
93
92
|
let logs = config.logs->Option.getOr([])
|
|
94
93
|
let _ = await logs->Array.map(relayLog)->Promise.all
|
|
95
94
|
""
|
|
@@ -18,7 +18,6 @@
|
|
|
18
18
|
// HANDLER_CONFIG shape:
|
|
19
19
|
// { "pgConnection": { host, port, database, username, secretArn } }
|
|
20
20
|
|
|
21
|
-
@val @scope("process") external processEnv: dict<string> = "env"
|
|
22
21
|
|
|
23
22
|
// Structured JSON logging shared by every deployed entry point (HandlerFactoryHelpers).
|
|
24
23
|
type logExtra = {comp?: string}
|
|
@@ -49,6 +48,6 @@ let runMigration = async (
|
|
|
49
48
|
}
|
|
50
49
|
|
|
51
50
|
let handler = async (_event: JSON.t, _context: PulumiAws.Lambda.context) => {
|
|
52
|
-
let config =
|
|
51
|
+
let config = NodeProcess.env->Dict.get("HANDLER_CONFIG")->Option.getOr("{}")->parseHandlerConfig
|
|
53
52
|
await runMigration(config)
|
|
54
53
|
}
|
|
@@ -10,7 +10,6 @@
|
|
|
10
10
|
// binds the Id module at the ReScript level, mirroring ExtensionPoint_Builder.
|
|
11
11
|
// Runtime-pure: no Pulumi value reaches this module's import graph.
|
|
12
12
|
|
|
13
|
-
@val @scope("process") external processEnv: dict<string> = "env"
|
|
14
13
|
|
|
15
14
|
// ── Shim bindings (HandlerFactoryHelpers.mjs) ───────────────────────────────
|
|
16
15
|
// The structured-log + Effect dispatch boundary shared by every deployed entry
|
|
@@ -64,7 +63,7 @@ type handlerConfig = {
|
|
|
64
63
|
|
|
65
64
|
// === Initialize eagerly at module load (Lambda cold start) ===
|
|
66
65
|
|
|
67
|
-
let config =
|
|
66
|
+
let config = NodeProcess.env->Dict.get("HANDLER_CONFIG")->Option.getOr("{}")->parseHandlerConfig
|
|
68
67
|
|
|
69
68
|
// Instantiate the Plugin EP mapping. updateApiSchema and manageSubscriptions
|
|
70
69
|
// are admin-only hooks; this Lambda only handles incoming commands (Heartbeat,
|
|
@@ -82,7 +81,7 @@ module EpSpec = {
|
|
|
82
81
|
let runtimeOps: ReventlessCore.PluginRuntimeOperations.operations = {
|
|
83
82
|
messagePublish: {sendMessageToChannel: Util_PluginMessage_Runtime.sendMessage},
|
|
84
83
|
}
|
|
85
|
-
let environment =
|
|
84
|
+
let environment = NodeProcess.env->Dict.get("Environment")->Option.getOr("unknown")
|
|
86
85
|
let updateApiSchema: option<Reventless.QueryEngine.operations => promise<unit>> = None
|
|
87
86
|
let manageSubscriptions: option<
|
|
88
87
|
(Reventless.Plugin.pluginDefinition, [#connect | #disconnect]) => promise<unit>,
|
|
@@ -108,7 +107,7 @@ let publishToAggregates: dict<ReventlessCore.CommandTopic.publishJsons> =
|
|
|
108
107
|
->Option.getOr(Dict.make())
|
|
109
108
|
->Dict.toArray
|
|
110
109
|
->Array.map(((aggName, envVarName)) => {
|
|
111
|
-
let queueUrl =
|
|
110
|
+
let queueUrl = NodeProcess.env->Dict.get(envVarName)->Option.getOr("")
|
|
112
111
|
let queue: Util_SQS_Runtime.resolvedQueue = {id: queueUrl, name: queueUrl, arn: ""}
|
|
113
112
|
(aggName, queue->CommandTopicChannel_SQS_Runtime.publishJsons(AWS.SQS_FIFO))
|
|
114
113
|
})
|
|
@@ -16,7 +16,6 @@
|
|
|
16
16
|
// Runtime-pure: no `open PulumiAws` values — Pulumi appears in type positions
|
|
17
17
|
// only (erased).
|
|
18
18
|
|
|
19
|
-
@val @scope("process") external processEnv: dict<string> = "env"
|
|
20
19
|
|
|
21
20
|
// ── Runtime-loaded spec-module reads (typed at the seam) ────────────────────
|
|
22
21
|
// The shells read `config` / `subIdConfig` off dynamically imported spec
|
|
@@ -71,8 +70,8 @@ let makeQueryDbOps = (
|
|
|
71
70
|
~indexes,
|
|
72
71
|
~subIdField?,
|
|
73
72
|
)->withLiveUpdates({
|
|
74
|
-
endpoint: ?(
|
|
75
|
-
region: ?(
|
|
73
|
+
endpoint: ?(NodeProcess.env->Dict.get("APPSYNC_ENDPOINT")),
|
|
74
|
+
region: ?(NodeProcess.env->Dict.get("AWS_REGION")),
|
|
76
75
|
topicName: ?stateTopicName,
|
|
77
76
|
subIdField: ?subIdField,
|
|
78
77
|
})
|
|
@@ -14,7 +14,6 @@
|
|
|
14
14
|
// ScheduledPublisher_CloudWatchEvents_Runtime directly — the layer ships it —
|
|
15
15
|
// so the mirror is gone.
|
|
16
16
|
|
|
17
|
-
@val @scope("process") external processEnv: dict<string> = "env"
|
|
18
17
|
@module("./HandlerFactoryHelpers.mjs") @scope("log")
|
|
19
18
|
external logWarn: (string, StreamRoutedEntryPoint_Ops.dispatchOpts) => unit = "warn"
|
|
20
19
|
|
|
@@ -71,7 +70,7 @@ let buildPublishCommands = (map: dict<string>): dict<ReventlessCore.CommandTopic
|
|
|
71
70
|
map
|
|
72
71
|
->Dict.toArray
|
|
73
72
|
->Array.filterMap(((aggName, envVarName)) =>
|
|
74
|
-
|
|
73
|
+
NodeProcess.env
|
|
75
74
|
->Dict.get(envVarName)
|
|
76
75
|
->Option.filter(queueUrl => queueUrl != "")
|
|
77
76
|
->Option.map(queueUrl => {
|
|
@@ -98,9 +97,9 @@ let makeSchedulerOps = (config: option<schedulerEnvConfig>): option<schedulerOps
|
|
|
98
97
|
| (None, None) => None
|
|
99
98
|
| (None, Some(cfg)) =>
|
|
100
99
|
switch (
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
100
|
+
NodeProcess.env->Dict.get(cfg.roleArnEnv),
|
|
101
|
+
NodeProcess.env->Dict.get(cfg.targetArnEnv),
|
|
102
|
+
NodeProcess.env->Dict.get(cfg.targetNameEnv),
|
|
104
103
|
) {
|
|
105
104
|
| (Some(roleArn), Some(targetArn), Some(targetName))
|
|
106
105
|
if roleArn != "" && targetArn != "" && targetName != "" =>
|
|
@@ -10,13 +10,12 @@
|
|
|
10
10
|
// are logged and skipped; 5xx / network failures are recorded and rethrown after
|
|
11
11
|
// the batch so the EventSourceMapping retries (bisectBatchOnFunctionError).
|
|
12
12
|
|
|
13
|
-
@val @scope("process") external processEnv: dict<string> = "env"
|
|
14
13
|
|
|
15
|
-
let endpoint =
|
|
14
|
+
let endpoint = NodeProcess.env->Dict.get("APPSYNC_ENDPOINT")->Option.getOr("")
|
|
16
15
|
|
|
17
16
|
// STATE_TOPIC_MAP: `{ <tableName>: <topicName> }`, injected at deploy time.
|
|
18
17
|
let topicMap: dict<string> =
|
|
19
|
-
switch
|
|
18
|
+
switch NodeProcess.env->Dict.get("STATE_TOPIC_MAP")->Option.getOr("{}")->JSON.parseOrThrow->JSON.Decode.object {
|
|
20
19
|
| Some(obj) =>
|
|
21
20
|
obj
|
|
22
21
|
->Dict.toArray
|
|
@@ -34,9 +34,6 @@ external getSignedUrl: (s3Client, putObjectCommand, presignOptions) => promise<s
|
|
|
34
34
|
|
|
35
35
|
// ── Node bindings (replacing the former `%raw` helpers with typed externals) ──
|
|
36
36
|
|
|
37
|
-
@val @scope("process") external processEnv: dict<string> = "env"
|
|
38
|
-
|
|
39
|
-
@module("node:crypto") external randomUUID: unit => string = "randomUUID"
|
|
40
37
|
|
|
41
38
|
type buffer
|
|
42
39
|
@val @scope("Buffer") external bufferFromBase64: (string, string) => buffer = "from"
|
|
@@ -44,7 +41,7 @@ type buffer
|
|
|
44
41
|
|
|
45
42
|
// Read an env var, mapping "" / unset to None.
|
|
46
43
|
let getEnv = (k: string): option<string> =>
|
|
47
|
-
switch
|
|
44
|
+
switch NodeProcess.env->Dict.get(k) {
|
|
48
45
|
| Some("") | None => None
|
|
49
46
|
| Some(v) => Some(v)
|
|
50
47
|
}
|
|
@@ -121,7 +118,7 @@ let handler = async (event: functionUrlEvent): response => {
|
|
|
121
118
|
// served prefix (`SERVED_PREFIX`, e.g. `uploads`) so the CloudFront
|
|
122
119
|
// `{prefix}/*` behavior fronts it. Callers PUT to this exact key.
|
|
123
120
|
let servedPrefix = getEnv("SERVED_PREFIX")->Option.getOr("uploads")
|
|
124
|
-
let key = `${servedPrefix}/${identityPrefix(event)}${randomUUID()}/${fileName}`
|
|
121
|
+
let key = `${servedPrefix}/${identityPrefix(event)}${NodeCrypto.randomUUID()}/${fileName}`
|
|
125
122
|
let client = makeS3Client()
|
|
126
123
|
let command = makePutObjectCommand({bucket, key, contentType: ?contentType})
|
|
127
124
|
let uploadUrl = await getSignedUrl(client, command, {expiresIn: 300})
|
|
@@ -9,13 +9,8 @@ let log = ReventlessCore.Logger.fromEnv()
|
|
|
9
9
|
|
|
10
10
|
// ── SHA-256 helper ─────────────────────────────────────────────────────────
|
|
11
11
|
|
|
12
|
-
type hashObject
|
|
13
|
-
@module("node:crypto") external createHash: string => hashObject = "createHash"
|
|
14
|
-
@send external hashUpdate: (hashObject, string) => hashObject = "update"
|
|
15
|
-
@send external hashDigest: (hashObject, string) => string = "digest"
|
|
16
|
-
|
|
17
12
|
let sha256Hex = (input: string): string =>
|
|
18
|
-
createHash("sha256")->hashUpdate(input)->hashDigest("hex")
|
|
13
|
+
NodeCrypto.createHash("sha256")->NodeCrypto.hashUpdate(input)->NodeCrypto.hashDigest("hex")
|
|
19
14
|
|
|
20
15
|
// ── Inline AppSync SDK binding ─────────────────────────────────────────────
|
|
21
16
|
|