@reventlessdev/reventless-aws 3.0.0-alpha.232 → 3.0.0-alpha.234

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 (110) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/package.json +7 -7
  3. package/src/adapter/Api/AppSyncEventsSigner_Ops.res +137 -0
  4. package/src/adapter/Api/AppSyncEventsSigner_Ops.res.mjs +121 -0
  5. package/src/adapter/Api/Platform_AdminScan_Ops.res +136 -0
  6. package/src/adapter/Api/Platform_AdminScan_Ops.res.mjs +98 -0
  7. package/src/adapter/Api/Platform_ComponentDefinitions_Lambda.res +12 -90
  8. package/src/adapter/Api/Platform_ComponentDefinitions_Lambda.res.mjs +11 -84
  9. package/src/adapter/Api/Platform_ComponentDefinitions_Lambda_Ops.res +86 -0
  10. package/src/adapter/Api/Platform_ComponentDefinitions_Lambda_Ops.res.mjs +79 -0
  11. package/src/adapter/Api/Platform_UIFragments_Lambda.res +9 -79
  12. package/src/adapter/Api/Platform_UIFragments_Lambda.res.mjs +7 -143
  13. package/src/adapter/Api/Platform_UIFragments_Lambda_Ops.res +48 -0
  14. package/src/adapter/Api/Platform_UIFragments_Lambda_Ops.res.mjs +63 -0
  15. package/src/adapter/EventLogSubscription/EventLogSubscription_AppSync.res +21 -80
  16. package/src/adapter/EventLogSubscription/EventLogSubscription_AppSync.res.mjs +23 -68
  17. package/src/adapter/EventLogSubscription/EventLogSubscription_AppSync_Ops.res +70 -0
  18. package/src/adapter/EventLogSubscription/EventLogSubscription_AppSync_Ops.res.mjs +68 -0
  19. package/src/adapter/Postgres/PgChangeFeedRelay_Builder.res +1 -1
  20. package/src/adapter/Postgres/PgChangeFeedRelay_Builder.res.mjs +1 -1
  21. package/src/adapter/Postgres/PgMigration_Builder.res +1 -1
  22. package/src/adapter/Postgres/PgMigration_Builder.res.mjs +1 -1
  23. package/src/adapter/Runtime/AutomationSliceEntryPoint.mjs +42 -126
  24. package/src/adapter/Runtime/AutomationSliceEntryPoint_Ops.res +246 -0
  25. package/src/adapter/Runtime/AutomationSliceEntryPoint_Ops.res.mjs +145 -0
  26. package/src/adapter/Runtime/AutomationSliceRuntime_Builder_Single.res +27 -2
  27. package/src/adapter/Runtime/AutomationSliceRuntime_Builder_Single.res.mjs +10 -3
  28. package/src/adapter/Runtime/CounterEntryPoint.mjs +19 -73
  29. package/src/adapter/Runtime/CounterEntryPoint_Ops.res +145 -0
  30. package/src/adapter/Runtime/CounterEntryPoint_Ops.res.mjs +129 -0
  31. package/src/adapter/Runtime/DcbCommandTopicEntryPoint.mjs +14 -1
  32. package/src/adapter/Runtime/DcbCommandTopicEntryPoint_Ops.res +22 -2
  33. package/src/adapter/Runtime/DcbCommandTopicEntryPoint_Ops.res.mjs +15 -4
  34. package/src/adapter/Runtime/EventCollectorEntryPoint.mjs +52 -510
  35. package/src/adapter/Runtime/EventCollectorEntryPoint_Ops.res +816 -0
  36. package/src/adapter/Runtime/EventCollectorEntryPoint_Ops.res.mjs +651 -0
  37. package/src/adapter/Runtime/EventMapperEntryPoint.mjs +23 -67
  38. package/src/adapter/Runtime/EventMapperEntryPoint_Ops.res +126 -0
  39. package/src/adapter/Runtime/EventMapperEntryPoint_Ops.res.mjs +83 -0
  40. package/src/adapter/Runtime/ExtensionPointEntryPoint.mjs +16 -63
  41. package/src/adapter/Runtime/ExtensionPointEntryPoint_Ops.res +150 -0
  42. package/src/adapter/Runtime/ExtensionPointEntryPoint_Ops.res.mjs +111 -0
  43. package/src/adapter/Runtime/PgChangeFeedRelayEntryPoint.res +96 -0
  44. package/src/adapter/Runtime/PgChangeFeedRelayEntryPoint.res.mjs +70 -0
  45. package/src/adapter/Runtime/PgMigrationEntryPoint.res +54 -0
  46. package/src/adapter/Runtime/PgMigrationEntryPoint.res.mjs +37 -0
  47. package/src/adapter/Runtime/PgQueryResolverEntryPoint.mjs +20 -55
  48. package/src/adapter/Runtime/PgQueryResolverEntryPoint_Ops.res +155 -0
  49. package/src/adapter/Runtime/PgQueryResolverEntryPoint_Ops.res.mjs +94 -0
  50. package/src/adapter/Runtime/ProjectionEntryPoint_Ops.res +80 -0
  51. package/src/adapter/Runtime/ProjectionEntryPoint_Ops.res.mjs +39 -0
  52. package/src/adapter/Runtime/QueryDbEntryPoint_Ops.res +4 -4
  53. package/src/adapter/Runtime/ReadModelEntryPoint.mjs +34 -153
  54. package/src/adapter/Runtime/ReadModelEntryPoint_Ops.res +114 -0
  55. package/src/adapter/Runtime/ReadModelEntryPoint_Ops.res.mjs +83 -0
  56. package/src/adapter/Runtime/RuntimeEnvironment_Lambda.res +26 -6
  57. package/src/adapter/Runtime/SideEffectEntryPoint.mjs +23 -64
  58. package/src/adapter/Runtime/SideEffectEntryPoint_Ops.res +71 -0
  59. package/src/adapter/Runtime/SideEffectEntryPoint_Ops.res.mjs +57 -0
  60. package/src/adapter/Runtime/StateChangeSliceRuntime_Builder_Single.res +5 -2
  61. package/src/adapter/Runtime/StateChangeSliceRuntime_Builder_Single.res.mjs +1 -1
  62. package/src/adapter/Runtime/StateViewSliceEntryPoint.mjs +34 -165
  63. package/src/adapter/Runtime/StateViewSliceEntryPoint_Ops.res +206 -0
  64. package/src/adapter/Runtime/StateViewSliceEntryPoint_Ops.res.mjs +105 -0
  65. package/src/adapter/Runtime/StreamRoutedEntryPoint_Ops.res +156 -0
  66. package/src/adapter/Runtime/StreamRoutedEntryPoint_Ops.res.mjs +123 -0
  67. package/src/adapter/Runtime/TaskBucketEntryPoint.mjs +18 -138
  68. package/src/adapter/Runtime/TaskBucketEntryPoint_Ops.res +198 -0
  69. package/src/adapter/Runtime/TaskBucketEntryPoint_Ops.res.mjs +155 -0
  70. package/src/adapter/StateTopic/StateTopic_AppSync.res +12 -170
  71. package/src/adapter/StateTopic/StateTopic_AppSync.res.mjs +7 -167
  72. package/src/adapter/StateTopic/StateTopic_AppSync_Ops.res +208 -0
  73. package/src/adapter/StateTopic/StateTopic_AppSync_Ops.res.mjs +183 -0
  74. package/src/components/AutomationSlice_Builder.res +2 -0
  75. package/src/components/AutomationSlice_Builder.res.mjs +1 -1
  76. package/src/components/OutboundTranslationSlice_Builder.res +1 -0
  77. package/src/components/OutboundTranslationSlice_Builder.res.mjs +1 -1
  78. package/src/plugin/runtime/PluginRuntime_Builder.res +13 -4
  79. package/src/plugin/runtime/PluginRuntime_Builder.res.mjs +1 -1
  80. package/tests/AppSyncEventsSigner_OpsTest.res +75 -0
  81. package/tests/AppSyncEventsSigner_OpsTest.res.mjs +44 -0
  82. package/tests/AppSyncEventsSigner_ParityFixture.mjs +36 -0
  83. package/tests/AutomationSliceEntryPoint_OpsTest.res +165 -0
  84. package/tests/AutomationSliceEntryPoint_OpsTest.res.mjs +280 -0
  85. package/tests/CounterEntryPoint_OpsTest.res +115 -0
  86. package/tests/CounterEntryPoint_OpsTest.res.mjs +150 -0
  87. package/tests/EventCollectorEntryPoint_OpsTest.res +216 -0
  88. package/tests/EventCollectorEntryPoint_OpsTest.res.mjs +339 -0
  89. package/tests/EventMapperEntryPoint_OpsTest.res +103 -0
  90. package/tests/EventMapperEntryPoint_OpsTest.res.mjs +120 -0
  91. package/tests/ExtensionPointEntryPoint_OpsTest.res +57 -0
  92. package/tests/ExtensionPointEntryPoint_OpsTest.res.mjs +54 -0
  93. package/tests/PgMigrationEntryPoint_IntegrationTest.res +22 -31
  94. package/tests/PgMigrationEntryPoint_IntegrationTest.res.mjs +20 -23
  95. package/tests/PgQueryResolverEntryPoint_OpsTest.res +38 -0
  96. package/tests/PgQueryResolverEntryPoint_OpsTest.res.mjs +31 -0
  97. package/tests/Platform_AdminScan_OpsTest.res +80 -0
  98. package/tests/Platform_AdminScan_OpsTest.res.mjs +127 -0
  99. package/tests/ReadModelEntryPoint_OpsTest.res +141 -0
  100. package/tests/ReadModelEntryPoint_OpsTest.res.mjs +267 -0
  101. package/tests/SideEffectEntryPoint_OpsTest.res +79 -0
  102. package/tests/SideEffectEntryPoint_OpsTest.res.mjs +105 -0
  103. package/tests/StateViewSliceEntryPoint_OpsTest.res +167 -0
  104. package/tests/StateViewSliceEntryPoint_OpsTest.res.mjs +296 -0
  105. package/tests/TaskBucketEntryPoint_OpsTest.res +117 -0
  106. package/tests/TaskBucketEntryPoint_OpsTest.res.mjs +165 -0
  107. package/tests/integration/StateViewSliceEntryPoint_IntegrationTest.res +42 -13
  108. package/tests/integration/StateViewSliceEntryPoint_IntegrationTest.res.mjs +29 -6
  109. package/src/adapter/Runtime/PgChangeFeedRelayEntryPoint.mjs +0 -57
  110. package/src/adapter/Runtime/PgMigrationEntryPoint.mjs +0 -40
@@ -0,0 +1,63 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+ import * as Stdlib_JSON from "@rescript/runtime/lib/es6/Stdlib_JSON.js";
4
+ import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
5
+ import * as Platform_AdminScan_Ops$ReventlessAws from "./Platform_AdminScan_Ops.res.mjs";
6
+
7
+ function str(item, key) {
8
+ return Stdlib_Option.flatMap(item[key], Stdlib_JSON.Decode.string);
9
+ }
10
+
11
+ function toEntry(item, name) {
12
+ let match = str(item, "pluginId");
13
+ let match$1 = str(item, "remoteEntryUrl");
14
+ if (match !== undefined && match$1 !== undefined && match$1 !== "") {
15
+ return Object.fromEntries([
16
+ [
17
+ "pluginId",
18
+ name
19
+ ],
20
+ [
21
+ "remoteEntryUrl",
22
+ match$1
23
+ ],
24
+ [
25
+ "panels",
26
+ Stdlib_Option.getOr(item["panels"], [])
27
+ ],
28
+ [
29
+ "pages",
30
+ Stdlib_Option.getOr(item["pages"], [])
31
+ ],
32
+ [
33
+ "registeredAt",
34
+ Stdlib_Option.getOr(item["registeredAt"], "")
35
+ ],
36
+ [
37
+ "updatedAt",
38
+ Stdlib_Option.getOr(item["updatedAt"], "")
39
+ ]
40
+ ]);
41
+ }
42
+ }
43
+
44
+ async function handler(_event) {
45
+ let table = process.env["UI_FRAGMENT_RM_TABLE"];
46
+ if (table !== undefined) {
47
+ if (table === "") {
48
+ console.error("Platform_UIFragments: UI_FRAGMENT_RM_TABLE env var not set");
49
+ return [];
50
+ }
51
+ let items = await Platform_AdminScan_Ops$ReventlessAws.scanAll(table, undefined, undefined, undefined);
52
+ return Platform_AdminScan_Ops$ReventlessAws.latestByName(items, item => str(item, "pluginId"), toEntry);
53
+ }
54
+ console.error("Platform_UIFragments: UI_FRAGMENT_RM_TABLE env var not set");
55
+ return [];
56
+ }
57
+
58
+ export {
59
+ str,
60
+ toEntry,
61
+ handler,
62
+ }
63
+ /* Platform_AdminScan_Ops-ReventlessAws Not a pure module */
@@ -15,78 +15,13 @@
15
15
 
16
16
  open PulumiAws
17
17
 
18
- // ── Handler code ─────────────────────────────────────────────────────────────
19
- //
20
- // Receives SNS-via-SQS records (rawMessageDelivery=true body IS the event JSON).
21
- // Publishes {position, eventType, payload} to AppSync Events channel.
22
-
23
- let makeHandlerCode = (~topicName: string): string => {
24
- // Mirrors StateTopic_AppSync.pathSegment: AppSync Events channel segments
25
- // allow only [A-Za-z0-9-]. Today's event-log displayNames are bare
26
- // PascalCase identifiers (Catalog, Ordering, Plugin) so the rule is a no-op
27
- // in practice — kept in lock-step prophylactically so a future displayName
28
- // carrying `@/./:` etc. doesn't hit the same silent-drop the Plugins admin
29
- // RM did when StateTopic still only normalised underscores.
30
- let channelName = topicName->String.replaceRegExp(%re("/[^A-Za-z0-9-]/g"), "-")
31
- `
32
- import { createHmac, createHash } from "node:crypto";
33
-
34
- const CHANNEL = "/default/${channelName}";
35
- const APPSYNC_ENDPOINT = process.env.APPSYNC_ENDPOINT;
36
- const AWS_REGION = process.env.AWS_REGION ?? "eu-west-1";
37
-
38
- function sha256hex(data) {
39
- return createHash("sha256").update(typeof data === "string" ? data : JSON.stringify(data)).digest("hex");
40
- }
41
- function hmacBuf(key, data) {
42
- return createHmac("sha256", key).update(data).digest();
43
- }
44
-
45
- async function signedHeaders(host, path, body) {
46
- const accessKeyId = process.env.AWS_ACCESS_KEY_ID;
47
- const secretAccessKey = process.env.AWS_SECRET_ACCESS_KEY;
48
- const sessionToken = process.env.AWS_SESSION_TOKEN;
49
- const now = new Date();
50
- const amzDate = now.toISOString().replace(/[:\\-]|\\..../g, "").slice(0, 15) + "Z";
51
- const dateStamp = now.toISOString().slice(0, 10).replace(/-/g, "");
52
- const headers = { host, "x-amz-date": amzDate, ...(sessionToken ? { "x-amz-security-token": sessionToken } : {}) };
53
- const canonH = Object.entries(headers).sort(([a],[b]) => a.localeCompare(b)).map(([k,v]) => \`\${k}:\${v}\\n\`).join("");
54
- const signH = Object.keys(headers).sort().join(";");
55
- const cr = ["POST", path, "", canonH, signH, sha256hex(body)].join("\\n");
56
- const scope = \`\${dateStamp}/\${AWS_REGION}/appsync/aws4_request\`;
57
- const sts = ["AWS4-HMAC-SHA256", amzDate, scope, sha256hex(cr)].join("\\n");
58
- const kDate = hmacBuf("AWS4" + secretAccessKey, dateStamp);
59
- const kSigning = hmacBuf(hmacBuf(hmacBuf(kDate, AWS_REGION), "appsync"), "aws4_request");
60
- const sig = createHmac("sha256", kSigning).update(sts).digest("hex");
61
- return { ...headers, Authorization: \`AWS4-HMAC-SHA256 Credential=\${accessKeyId}/\${scope}, SignedHeaders=\${signH}, Signature=\${sig}\` };
62
- }
63
-
64
- export async function handler(event) {
65
- const url = new URL(APPSYNC_ENDPOINT);
66
- for (const record of event.Records) {
67
- let body;
68
- try {
69
- body = JSON.parse(record.body);
70
- } catch (e) {
71
- console.error("EventLogSubscription: failed to parse record body", record.body, e);
72
- continue;
73
- }
74
- const payload = { position: body.position, eventType: body.eventType, payload: body.data };
75
- const reqBody = JSON.stringify({ id: record.messageId, channel: CHANNEL, events: [JSON.stringify(payload)] });
76
- const auth = await signedHeaders(url.hostname, "/event", reqBody);
77
- const res = await fetch(APPSYNC_ENDPOINT + "/event", {
78
- method: "POST",
79
- headers: { accept: "application/json, text/javascript", "content-encoding": "amz-1.0", "content-type": "application/json; charset=UTF-8", ...auth },
80
- body: reqBody,
81
- });
82
- if (!res.ok) {
83
- const txt = await res.text();
84
- console.error("EventLogSubscription publish failed:", res.status, txt);
85
- }
86
- }
87
- }
88
- `
89
- }
18
+ // AppSync Events channel segments allow only [A-Za-z0-9-]. Today's event-log
19
+ // displayNames are bare PascalCase identifiers (Catalog, Ordering, Plugin) so
20
+ // the rule is a no-op in practice kept prophylactically so a future displayName
21
+ // carrying `@/./:` etc. doesn't hit a silent-drop. Mirrors
22
+ // AppSyncEventsSigner_Ops.pathSegment (the runtime handler's equivalent).
23
+ let channelNameOf = (topicName: string): string =>
24
+ topicName->String.replaceRegExp(%re("/[^A-Za-z0-9-]/g"), "-")
90
25
 
91
26
  // ── Deploy-time resource builder ──────────────────────────────────────────────
92
27
 
@@ -224,15 +159,18 @@ let make = (
224
159
  )
225
160
  })
226
161
 
227
- // Lambda function — processes SQS records (SNS events) → AppSync Events channel
228
- let handlerCode = makeHandlerCode(~topicName)
229
- let archiveContents: dict<Pulumi.Archive.assetOrArchive> = Dict.make()
230
- archiveContents->Dict.set(
231
- "index.mjs",
232
- Pulumi.Asset.stringAsset(handlerCode)->Pulumi.Archive.assetToAssetOrArchive,
162
+ // Lambda function — processes SQS records (SNS events) → AppSync Events channel.
163
+ // Bundle reventless-aws (the compiled `_Ops` handler + its node:crypto signer
164
+ // live inside it) and re-export its `handler`; buildCodeArchive ships the ESM
165
+ // resolve-hook so `@rescript/runtime` resolves from the layer.
166
+ let channelName = channelNameOf(topicName)
167
+ let packageDirs = Dict.fromArray([
168
+ ("@reventlessdev/reventless-aws", Util_Bundle.resolvePackageRoot("@reventlessdev/reventless-aws")),
169
+ ])
170
+ let {code, sourceCodeHash} = Util_Bundle.buildCodeArchive(
171
+ ~entryPointModule="@reventlessdev/reventless-aws/src/adapter/EventLogSubscription/EventLogSubscription_AppSync_Ops.res.mjs",
172
+ ~packageDirs,
233
173
  )
234
- let code = Pulumi.Archive.assetArchive(archiveContents)
235
- let sourceCodeHash = Util_Bundle.hashString(handlerCode)
236
174
 
237
175
  let layers =
238
176
  Lambda.reventlessLayerArn
@@ -259,6 +197,9 @@ let make = (
259
197
  Lambda.Function.variables: Dict.fromArray([
260
198
  ("Environment", Pulumi.Pulumi.getStackName()->Pulumi.Input.make),
261
199
  ("APPSYNC_ENDPOINT", appsyncEndpoint->Pulumi.Output.asInput),
200
+ ("EVENT_LOG_CHANNEL", channelName->Pulumi.Input.make),
201
+ ("NODE_OPTIONS", Util_Bundle.esmLoaderNodeOptions->Pulumi.Input.make),
202
+ ("ESM_FALLBACK_DIRS", Util_Bundle.esmFallbackDirs->Pulumi.Input.make),
262
203
  ]),
263
204
  }: Lambda.Function.functionEnvironment
264
205
  )->Pulumi.Input.make,
@@ -16,66 +16,8 @@ import * as AppSync_EventsApi$ReventlessAws from "../Api/AppSync_EventsApi.res.m
16
16
  import * as Util_DeadLetterQueue$ReventlessAws from "../../util/Util_DeadLetterQueue.res.mjs";
17
17
  import * as Util_EventSourceMapping$ReventlessAws from "../../util/Util_EventSourceMapping.res.mjs";
18
18
 
19
- function makeHandlerCode(topicName) {
20
- let channelName = topicName.replace(/[^A-Za-z0-9-]/g, "-");
21
- return `
22
- import { createHmac, createHash } from "node:crypto";
23
-
24
- const CHANNEL = "/default/` + channelName + `";
25
- const APPSYNC_ENDPOINT = process.env.APPSYNC_ENDPOINT;
26
- const AWS_REGION = process.env.AWS_REGION ?? "eu-west-1";
27
-
28
- function sha256hex(data) {
29
- return createHash("sha256").update(typeof data === "string" ? data : JSON.stringify(data)).digest("hex");
30
- }
31
- function hmacBuf(key, data) {
32
- return createHmac("sha256", key).update(data).digest();
33
- }
34
-
35
- async function signedHeaders(host, path, body) {
36
- const accessKeyId = process.env.AWS_ACCESS_KEY_ID;
37
- const secretAccessKey = process.env.AWS_SECRET_ACCESS_KEY;
38
- const sessionToken = process.env.AWS_SESSION_TOKEN;
39
- const now = new Date();
40
- const amzDate = now.toISOString().replace(/[:\\-]|\\..../g, "").slice(0, 15) + "Z";
41
- const dateStamp = now.toISOString().slice(0, 10).replace(/-/g, "");
42
- const headers = { host, "x-amz-date": amzDate, ...(sessionToken ? { "x-amz-security-token": sessionToken } : {}) };
43
- const canonH = Object.entries(headers).sort(([a],[b]) => a.localeCompare(b)).map(([k,v]) => \`\${k}:\${v}\\n\`).join("");
44
- const signH = Object.keys(headers).sort().join(";");
45
- const cr = ["POST", path, "", canonH, signH, sha256hex(body)].join("\\n");
46
- const scope = \`\${dateStamp}/\${AWS_REGION}/appsync/aws4_request\`;
47
- const sts = ["AWS4-HMAC-SHA256", amzDate, scope, sha256hex(cr)].join("\\n");
48
- const kDate = hmacBuf("AWS4" + secretAccessKey, dateStamp);
49
- const kSigning = hmacBuf(hmacBuf(hmacBuf(kDate, AWS_REGION), "appsync"), "aws4_request");
50
- const sig = createHmac("sha256", kSigning).update(sts).digest("hex");
51
- return { ...headers, Authorization: \`AWS4-HMAC-SHA256 Credential=\${accessKeyId}/\${scope}, SignedHeaders=\${signH}, Signature=\${sig}\` };
52
- }
53
-
54
- export async function handler(event) {
55
- const url = new URL(APPSYNC_ENDPOINT);
56
- for (const record of event.Records) {
57
- let body;
58
- try {
59
- body = JSON.parse(record.body);
60
- } catch (e) {
61
- console.error("EventLogSubscription: failed to parse record body", record.body, e);
62
- continue;
63
- }
64
- const payload = { position: body.position, eventType: body.eventType, payload: body.data };
65
- const reqBody = JSON.stringify({ id: record.messageId, channel: CHANNEL, events: [JSON.stringify(payload)] });
66
- const auth = await signedHeaders(url.hostname, "/event", reqBody);
67
- const res = await fetch(APPSYNC_ENDPOINT + "/event", {
68
- method: "POST",
69
- headers: { accept: "application/json, text/javascript", "content-encoding": "amz-1.0", "content-type": "application/json; charset=UTF-8", ...auth },
70
- body: reqBody,
71
- });
72
- if (!res.ok) {
73
- const txt = await res.text();
74
- console.error("EventLogSubscription publish failed:", res.status, txt);
75
- }
76
- }
77
- }
78
- `;
19
+ function channelNameOf(topicName) {
20
+ return topicName.replace(/[^A-Za-z0-9-]/g, "-");
79
21
  }
80
22
 
81
23
  function make(name, topicName, eventTopicOutputs, eventsApi, opts) {
@@ -142,17 +84,18 @@ function make(name, topicName, eventTopicOutputs, eventsApi, opts) {
142
84
  role: lambdaRole.id
143
85
  }, opts);
144
86
  });
145
- let handlerCode = makeHandlerCode(topicName);
146
- let archiveContents = {};
147
- archiveContents["index.mjs"] = new (Pulumi.asset.StringAsset)(handlerCode);
148
- let code = new (Pulumi.asset.AssetArchive)(archiveContents);
149
- let sourceCodeHash = Util_Bundle$ReventlessAws.hashString(handlerCode);
87
+ let channelName = channelNameOf(topicName);
88
+ let packageDirs = Object.fromEntries([[
89
+ "@reventlessdev/reventless-aws",
90
+ Util_Bundle$ReventlessAws.resolvePackageRoot("@reventlessdev/reventless-aws")
91
+ ]]);
92
+ let match = Util_Bundle$ReventlessAws.buildCodeArchive("@reventlessdev/reventless-aws/src/adapter/EventLogSubscription/EventLogSubscription_AppSync_Ops.res.mjs", packageDirs, undefined);
150
93
  let layers = Stdlib_Option.getOr(Stdlib_Option.map(Lambda$PulumiAws.reventlessLayerArn, arn => [arn]), []);
151
94
  let appsyncEndpoint = AppSync_EventsApi$ReventlessAws.httpEndpoint(eventsApi);
152
95
  let lambda = new (Aws.lambda.Function)(name + "EventLogSubscriber", {
153
96
  handler: "index.handler",
154
97
  runtime: "nodejs22.x",
155
- code: code,
98
+ code: match.code,
156
99
  role: lambdaRole.arn,
157
100
  memorySize: 128,
158
101
  timeout: 30,
@@ -167,17 +110,29 @@ function make(name, topicName, eventTopicOutputs, eventsApi, opts) {
167
110
  [
168
111
  "APPSYNC_ENDPOINT",
169
112
  appsyncEndpoint
113
+ ],
114
+ [
115
+ "EVENT_LOG_CHANNEL",
116
+ channelName
117
+ ],
118
+ [
119
+ "NODE_OPTIONS",
120
+ Util_Bundle$ReventlessAws.esmLoaderNodeOptions
121
+ ],
122
+ [
123
+ "ESM_FALLBACK_DIRS",
124
+ Util_Bundle$ReventlessAws.esmFallbackDirs
170
125
  ]
171
126
  ])
172
127
  },
173
- sourceCodeHash: sourceCodeHash
128
+ sourceCodeHash: match.sourceCodeHash
174
129
  }, opts);
175
130
  let lambdaOutput = Pulumi.output(lambda);
176
131
  Util_EventSourceMapping$ReventlessAws.subscribeSqs(lambdaOutput, name + "EventLogSubEventSourceMapping", queue, undefined, AWS_Tags$ReventlessAws.make(name + "EventLogSubEventSourceMapping", EventTopic$ReventlessCore.componentType, "EventSourceMapping", undefined, name, undefined, undefined, undefined), opts);
177
132
  }
178
133
 
179
134
  export {
180
- makeHandlerCode,
135
+ channelNameOf,
181
136
  make,
182
137
  }
183
138
  /* @pulumi/aws Not a pure module */
@@ -0,0 +1,70 @@
1
+ // Runtime handler for the EventLog → AppSync Events subscription relay —
2
+ // compiled, type-checked ReScript (replaces the inline JS `makeHandlerCode`
3
+ // string in EventLogSubscription_AppSync.res). Runtime-pure and SDK-free: it
4
+ // signs with node:crypto via AppSyncEventsSigner_Ops (see the parity test).
5
+ //
6
+ // Triggered by SQS (SNS event-topic fan-in). For each record it parses the SNS
7
+ // body, wraps it as a `{position, eventType, payload}` event, and publishes it
8
+ // to the fixed plugin event-log channel on the AppSync Events API.
9
+
10
+ @val @scope("process") external processEnv: dict<string> = "env"
11
+
12
+ // 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("")
15
+
16
+ // SQS Lambda event (only the fields this handler reads).
17
+ type sqsRecord = {body: string, messageId: string}
18
+ type sqsEvent = {@as("Records") records: array<sqsRecord>}
19
+
20
+ let processRecord = async (
21
+ ~record: sqsRecord,
22
+ ~region: string,
23
+ ~creds: AppSyncEventsSigner_Ops.creds,
24
+ ): unit => {
25
+ let parsed = try Some(record.body->JSON.parseOrThrow) catch {
26
+ | _ => None
27
+ }
28
+ switch parsed->Option.flatMap(JSON.Decode.object) {
29
+ | None => Console.error2("EventLogSubscription: failed to parse record body", record.body)
30
+ | Some(body) =>
31
+ // Wrap as {position, eventType, payload}; omit fields absent on the source
32
+ // body (matches the former JS, where `undefined` fields drop from JSON).
33
+ let payload = Dict.make()
34
+ body->Dict.get("position")->Option.forEach(v => payload->Dict.set("position", v))
35
+ body->Dict.get("eventType")->Option.forEach(v => payload->Dict.set("eventType", v))
36
+ body->Dict.get("data")->Option.forEach(v => payload->Dict.set("payload", v))
37
+ let reqBody =
38
+ Dict.fromArray([
39
+ ("id", JSON.Encode.string(record.messageId)),
40
+ ("channel", JSON.Encode.string(channel)),
41
+ ("events", JSON.Encode.array([JSON.Encode.string(payload->JSON.Encode.object->JSON.stringify)])),
42
+ ])
43
+ ->JSON.Encode.object
44
+ ->JSON.stringify
45
+ let res = await AppSyncEventsSigner_Ops.postEvent(
46
+ ~endpoint,
47
+ ~region,
48
+ ~isoNow=Date.make()->Date.toISOString,
49
+ ~creds,
50
+ ~body=reqBody,
51
+ )
52
+ if !(res->AppSyncEventsSigner_Ops.responseOk) {
53
+ let txt = await res->AppSyncEventsSigner_Ops.responseText
54
+ Console.error3(
55
+ "EventLogSubscription publish failed:",
56
+ res->AppSyncEventsSigner_Ops.responseStatus->Int.toString,
57
+ txt,
58
+ )
59
+ }
60
+ }
61
+ }
62
+
63
+ let handler = async (event: sqsEvent): unit => {
64
+ let region = AppSyncEventsSigner_Ops.region()
65
+ let creds = AppSyncEventsSigner_Ops.envCreds()
66
+ // Sequential, mirroring the former for-await loop (order + at-least-once).
67
+ await event.records->Array.reduce(Promise.resolve(), (acc, record) =>
68
+ acc->Promise.then(_ => processRecord(~record, ~region, ~creds))
69
+ )
70
+ }
@@ -0,0 +1,68 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+ import * as Stdlib_JSON from "@rescript/runtime/lib/es6/Stdlib_JSON.js";
4
+ import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
5
+ import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
6
+ import * as AppSyncEventsSigner_Ops$ReventlessAws from "../Api/AppSyncEventsSigner_Ops.res.mjs";
7
+
8
+ let channel = "/default/" + Stdlib_Option.getOr(process.env["EVENT_LOG_CHANNEL"], "");
9
+
10
+ let endpoint = Stdlib_Option.getOr(process.env["APPSYNC_ENDPOINT"], "");
11
+
12
+ async function processRecord(record, region, creds) {
13
+ let parsed;
14
+ try {
15
+ parsed = JSON.parse(record.body);
16
+ } catch (exn) {
17
+ parsed = undefined;
18
+ }
19
+ let body = Stdlib_Option.flatMap(parsed, Stdlib_JSON.Decode.object);
20
+ if (body !== undefined) {
21
+ let payload = {};
22
+ Stdlib_Option.forEach(body["position"], v => {
23
+ payload["position"] = v;
24
+ });
25
+ Stdlib_Option.forEach(body["eventType"], v => {
26
+ payload["eventType"] = v;
27
+ });
28
+ Stdlib_Option.forEach(body["data"], v => {
29
+ payload["payload"] = v;
30
+ });
31
+ let reqBody = JSON.stringify(Object.fromEntries([
32
+ [
33
+ "id",
34
+ record.messageId
35
+ ],
36
+ [
37
+ "channel",
38
+ channel
39
+ ],
40
+ [
41
+ "events",
42
+ [JSON.stringify(payload)]
43
+ ]
44
+ ]));
45
+ let res = await AppSyncEventsSigner_Ops$ReventlessAws.postEvent(endpoint, region, new Date().toISOString(), creds, reqBody);
46
+ if (res.ok) {
47
+ return;
48
+ }
49
+ let txt = await res.text();
50
+ console.error("EventLogSubscription publish failed:", res.status.toString(), txt);
51
+ return;
52
+ }
53
+ console.error("EventLogSubscription: failed to parse record body", record.body);
54
+ }
55
+
56
+ async function handler(event) {
57
+ let region = AppSyncEventsSigner_Ops$ReventlessAws.region();
58
+ let creds = AppSyncEventsSigner_Ops$ReventlessAws.envCreds();
59
+ return await Stdlib_Array.reduce(event.Records, Promise.resolve(), (acc, record) => acc.then(() => processRecord(record, region, creds)));
60
+ }
61
+
62
+ export {
63
+ channel,
64
+ endpoint,
65
+ processRecord,
66
+ handler,
67
+ }
68
+ /* channel Not a pure module */
@@ -49,7 +49,7 @@ let make = (
49
49
  opts->Option.map(ReventlessCore.Util.Pulumi.ComponentResourceOptions.toCustomResourceOptions)
50
50
 
51
51
  let {code, sourceCodeHash} = Util_Bundle.buildCodeArchive(
52
- ~entryPointModule="@reventlessdev/reventless-aws/src/adapter/Runtime/PgChangeFeedRelayEntryPoint.mjs",
52
+ ~entryPointModule="@reventlessdev/reventless-aws/src/adapter/Runtime/PgChangeFeedRelayEntryPoint.res.mjs",
53
53
  ~packageDirs=Dict.make(),
54
54
  )
55
55
 
@@ -23,7 +23,7 @@ import * as RuntimeEnvironment_Lambda$ReventlessAws from "../Runtime/RuntimeEnvi
23
23
  function make(name, logs, securityGroupId, subnetIds, intervalMinutesOpt, opts) {
24
24
  let intervalMinutes = intervalMinutesOpt !== undefined ? intervalMinutesOpt : 1;
25
25
  let customOpts = Stdlib_Option.map(opts, Util_Pulumi$ReventlessCore.ComponentResourceOptions.toCustomResourceOptions);
26
- let match = Util_Bundle$ReventlessAws.buildCodeArchive("@reventlessdev/reventless-aws/src/adapter/Runtime/PgChangeFeedRelayEntryPoint.mjs", {}, undefined);
26
+ let match = Util_Bundle$ReventlessAws.buildCodeArchive("@reventlessdev/reventless-aws/src/adapter/Runtime/PgChangeFeedRelayEntryPoint.res.mjs", {}, undefined);
27
27
  let logJsonOutputs = logs.map(l => Pulumi.all([
28
28
  l.connectionConfig,
29
29
  l.targetQueueUrl
@@ -33,7 +33,7 @@ let make = (
33
33
  open PulumiAws
34
34
 
35
35
  let {code, sourceCodeHash} = Util_Bundle.buildCodeArchive(
36
- ~entryPointModule="@reventlessdev/reventless-aws/src/adapter/Runtime/PgMigrationEntryPoint.mjs",
36
+ ~entryPointModule="@reventlessdev/reventless-aws/src/adapter/Runtime/PgMigrationEntryPoint.res.mjs",
37
37
  ~packageDirs=Dict.make(),
38
38
  )
39
39
 
@@ -11,7 +11,7 @@ import * as Util_Bundle$ReventlessAws from "../../util/Util_Bundle.res.mjs";
11
11
  import * as RuntimeEnvironment_Lambda$ReventlessAws from "../Runtime/RuntimeEnvironment_Lambda.res.mjs";
12
12
 
13
13
  function make(name, handlerConfig, secretArn, securityGroupId, subnetIds, opts) {
14
- let match = Util_Bundle$ReventlessAws.buildCodeArchive("@reventlessdev/reventless-aws/src/adapter/Runtime/PgMigrationEntryPoint.mjs", {}, undefined);
14
+ let match = Util_Bundle$ReventlessAws.buildCodeArchive("@reventlessdev/reventless-aws/src/adapter/Runtime/PgMigrationEntryPoint.res.mjs", {}, undefined);
15
15
  let sourceCodeHash = match.sourceCodeHash;
16
16
  let envVars = Object.fromEntries([[
17
17
  "HANDLER_CONFIG",