@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.
Files changed (36) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/package.json +13 -12
  3. package/rescript.json +1 -0
  4. package/src/adapter/Api/AppSyncEventsSigner_Ops.res +11 -29
  5. package/src/adapter/Api/Platform_ComponentDefinitions_Lambda_Ops.res +2 -3
  6. package/src/adapter/Api/Platform_UIFragments_Lambda_Ops.res +1 -2
  7. package/src/adapter/EventLogSubscription/EventLogSubscription_AppSync_Ops.res +2 -3
  8. package/src/adapter/Geocoder/Geocoder_AwsLocation_Ops.res +1 -2
  9. package/src/adapter/Runtime/AutomationSliceEntryPoint_Ops.res +1 -2
  10. package/src/adapter/Runtime/EventCollectorEntryPoint_Ops.res +5 -7
  11. package/src/adapter/Runtime/ExtensionPointEntryPoint_Ops.res +1 -2
  12. package/src/adapter/Runtime/HeartbeatEntryPoint.res +3 -4
  13. package/src/adapter/Runtime/PgChangeFeedRelayEntryPoint.res +1 -2
  14. package/src/adapter/Runtime/PgMigrationEntryPoint.res +1 -2
  15. package/src/adapter/Runtime/PluginExtensionPointEntryPoint.res +3 -4
  16. package/src/adapter/Runtime/ProjectionEntryPoint_Ops.res +2 -3
  17. package/src/adapter/Runtime/TaskBucketEntryPoint_Ops.res +4 -5
  18. package/src/adapter/StateTopic/StateTopic_AppSync_Ops.res +2 -3
  19. package/src/adapter/Upload/Upload_Presign_S3_Ops.res +2 -5
  20. package/src/components/Api/AppSync_Adapter.res +1 -6
  21. package/src/util/Util_Bundle.res +24 -50
  22. package/src/util/Util_Bundle.res.mjs +20 -20
  23. package/src/util/Util_LocalConfig.res +7 -14
  24. package/src/util/Util_LocalConfig.res.mjs +8 -8
  25. package/src/util/Util_SQS_Runtime.res +1 -5
  26. package/src/util/Util_StaticBundle.res +12 -29
  27. package/src/util/Util_StaticBundle.res.mjs +11 -11
  28. package/tests/ExtensionPointEntryPoint_OpsTest.res +1 -2
  29. package/tests/PgChangeFeedRelay_IntegrationTest.res +1 -2
  30. package/tests/PgMigrationEntryPoint_IntegrationTest.res +1 -2
  31. package/tests/PgPipeline_IntegrationTest.res +1 -2
  32. package/tests/TaskBucketEntryPoint_OpsTest.res +2 -3
  33. package/tests/Util_BundleResolveTest.res +12 -18
  34. package/tests/Util_BundleResolveTest.res.mjs +8 -8
  35. package/tests/Util_StaticBundleTest.res +28 -35
  36. 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.248",
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": "2.2.0-alpha.25",
15
- "@reventlessdev/rescript-jest": "1.0.0-alpha.9",
16
- "@reventlessdev/rescript-effect": "0.1.0-alpha.31",
17
- "@reventlessdev/rescript-pulumi-pulumi": "2.3.0-alpha.17",
18
- "@reventlessdev/rescript-pulumi-aws": "2.4.0-alpha.61",
19
- "@reventlessdev/rescript-uuid": "1.1.0-alpha.17",
20
- "@reventlessdev/reventless-core": "3.0.0-alpha.195",
21
- "@reventlessdev/reventless-infra": "3.0.0-alpha.113",
22
- "@reventlessdev/reventless-spec": "3.0.0-alpha.88",
23
- "@reventlessdev/reventless-interop": "3.0.0-alpha.29",
24
- "@reventlessdev/reventless-postgres": "3.0.0-alpha.59"
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
@@ -23,6 +23,7 @@
23
23
  ],
24
24
  "dependencies": [
25
25
  "sury",
26
+ "@reventlessdev/rescript-node",
26
27
  "@reventlessdev/rescript-jest",
27
28
  "@reventlessdev/rescript-aws-sdk",
28
29
  "@reventlessdev/rescript-effect",
@@ -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
- // ── node:crypto (string- and buffer-keyed HMAC; the signing key chain feeds a
15
- // Buffer digest back in as the next key) ──────────────────────────────────
14
+ let sha256hex = (data: string): string =>
15
+ NodeCrypto.createHash("sha256")->NodeCrypto.hashUpdate(data)->NodeCrypto.hashDigest("hex")
16
16
 
17
- type buffer
18
-
19
- type hmac
20
- @module("node:crypto") external createHmacStr: (string, string) => hmac = "createHmac"
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: processEnv->Dict.get("AWS_ACCESS_KEY_ID")->Option.getOr(""),
47
- secretAccessKey: processEnv->Dict.get("AWS_SECRET_ACCESS_KEY")->Option.getOr(""),
48
- sessionToken: processEnv->Dict.get("AWS_SESSION_TOKEN"),
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 => processEnv->Dict.get("AWS_REGION")->Option.getOr("eu-west-1")
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 = createHmacBuf("sha256", kSigning)->hmacUpdate(stringToSign)->hmacDigestHex("hex")
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 processEnv->Dict.get("ADMIN_ENTRY_JSON") {
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 processEnv->Dict.get("PLUGIN_RM_TABLE") {
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 processEnv->Dict.get("UI_FRAGMENT_RM_TABLE") {
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/" ++ processEnv->Dict.get("EVENT_LOG_CHANNEL")->Option.getOr("")
14
- let endpoint = processEnv->Dict.get("APPSYNC_ENDPOINT")->Option.getOr("")
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 processEnv->Dict.get(k) {
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: processEnv->Dict.get("Environment")->Option.getOr("unknown"),
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 = processEnv->Dict.get("Environment")->Option.getOr("unknown")
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(processEnv->Dict.get(envVarName)->Option.getOr("")),
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 => processEnv->Dict.get(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 = processEnv->Dict.get(envVarName)->Option.getOr("")
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 = processEnv->Dict.get("EP_QUEUE_URL")->Option.getOr("")
15
- let pluginId = processEnv->Dict.get("PLUGIN_ID")->Option.getOr("")
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
- processEnv
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
- processEnv->Dict.get("HANDLER_CONFIG")->Option.getOr(`{"logs":[]}`)->parseHandlerConfig
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 = processEnv->Dict.get("HANDLER_CONFIG")->Option.getOr("{}")->parseHandlerConfig
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 = processEnv->Dict.get("HANDLER_CONFIG")->Option.getOr("{}")->parseHandlerConfig
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 = processEnv->Dict.get("Environment")->Option.getOr("unknown")
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 = processEnv->Dict.get(envVarName)->Option.getOr("")
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: ?(processEnv->Dict.get("APPSYNC_ENDPOINT")),
75
- region: ?(processEnv->Dict.get("AWS_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
- processEnv
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
- processEnv->Dict.get(cfg.roleArnEnv),
102
- processEnv->Dict.get(cfg.targetArnEnv),
103
- processEnv->Dict.get(cfg.targetNameEnv),
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 = processEnv->Dict.get("APPSYNC_ENDPOINT")->Option.getOr("")
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 processEnv->Dict.get("STATE_TOPIC_MAP")->Option.getOr("{}")->JSON.parseOrThrow->JSON.Decode.object {
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 processEnv->Dict.get(k) {
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