@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,165 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+ import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
4
+ import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
5
+ import * as TaskBucketEntryPoint_Ops$ReventlessAws from "../src/adapter/Runtime/TaskBucketEntryPoint_Ops.res.mjs";
6
+
7
+ function str(prim) {
8
+ return prim;
9
+ }
10
+
11
+ function obj(pairs) {
12
+ return Object.fromEntries(pairs);
13
+ }
14
+
15
+ globalThis.describe("TaskBucketEntryPoint_Ops.parseHandlerConfig", () => {
16
+ globalThis.test("empty raw config decodes to empty defaults", () => {
17
+ let c = TaskBucketEntryPoint_Ops$ReventlessAws.parseHandlerConfig("");
18
+ globalThis.expect(c.callbackModule).toBe("");
19
+ globalThis.expect(Object.entries(c.publishToAggregates).length).toBe(0);
20
+ globalThis.expect(Stdlib_Option.isNone(c.scheduler)).toBe(true);
21
+ });
22
+ globalThis.test("decodes callbackModule, publishToAggregates, and scheduler env names", () => {
23
+ let config = JSON.stringify(Object.fromEntries([
24
+ [
25
+ "callbackModule",
26
+ "@x/plugin/src/Task/ImportCatalog.res.mjs"
27
+ ],
28
+ [
29
+ "publishToAggregates",
30
+ Object.fromEntries([[
31
+ "Product",
32
+ "PTA_Product_QUEUE_URL"
33
+ ]])
34
+ ],
35
+ [
36
+ "scheduler",
37
+ Object.fromEntries([
38
+ [
39
+ "roleArnEnv",
40
+ "SCHEDULER_ROLE_ARN"
41
+ ],
42
+ [
43
+ "targetArnEnv",
44
+ "SCHEDULER_TARGET_ARN"
45
+ ],
46
+ [
47
+ "targetNameEnv",
48
+ "SCHEDULER_TARGET_NAME"
49
+ ]
50
+ ])
51
+ ]
52
+ ]));
53
+ let c = TaskBucketEntryPoint_Ops$ReventlessAws.parseHandlerConfig(config);
54
+ globalThis.expect(c.callbackModule).toBe("@x/plugin/src/Task/ImportCatalog.res.mjs");
55
+ globalThis.expect(c.publishToAggregates["Product"]).toEqual("PTA_Product_QUEUE_URL");
56
+ let s = c.scheduler;
57
+ if (s !== undefined) {
58
+ globalThis.expect(s.roleArnEnv).toBe("SCHEDULER_ROLE_ARN");
59
+ return;
60
+ } else {
61
+ return Stdlib_JsError.throwWithMessage("expected Some(scheduler)");
62
+ }
63
+ });
64
+ });
65
+
66
+ globalThis.describe("TaskBucketEntryPoint_Ops.buildPublishCommands", () => {
67
+ globalThis.test("resolves queue URLs via env vars, skipping unset or empty ones", () => {
68
+ process.env["TB_TEST_QUEUE_A"] = "https://sqs/a.fifo";
69
+ process.env["TB_TEST_QUEUE_EMPTY"] = "";
70
+ let map = Object.fromEntries([
71
+ [
72
+ "AggA",
73
+ "TB_TEST_QUEUE_A"
74
+ ],
75
+ [
76
+ "AggEmpty",
77
+ "TB_TEST_QUEUE_EMPTY"
78
+ ],
79
+ [
80
+ "AggUnset",
81
+ "TB_TEST_QUEUE_UNSET"
82
+ ]
83
+ ]);
84
+ let publish = TaskBucketEntryPoint_Ops$ReventlessAws.buildPublishCommands(map);
85
+ globalThis.expect(Stdlib_Option.isSome(publish["AggA"])).toBe(true);
86
+ globalThis.expect(Stdlib_Option.isNone(publish["AggEmpty"])).toBe(true);
87
+ globalThis.expect(Stdlib_Option.isNone(publish["AggUnset"])).toBe(true);
88
+ });
89
+ });
90
+
91
+ globalThis.describe("TaskBucketEntryPoint_Ops.dispatchTaskActions", () => {
92
+ let schedule = {
93
+ name: "sweep",
94
+ rate: {
95
+ TAG: "Minutes",
96
+ _0: 5
97
+ },
98
+ payload: "{}"
99
+ };
100
+ globalThis.test("routes PublishCommands to the aggregate's publish fn", async () => {
101
+ let published = [];
102
+ let publishCommands = Object.fromEntries([[
103
+ "Product",
104
+ async cmds => {
105
+ published.push(cmds);
106
+ }
107
+ ]]);
108
+ await TaskBucketEntryPoint_Ops$ReventlessAws.dispatchTaskActions([
109
+ {
110
+ TAG: "PublishCommands",
111
+ _0: "Product",
112
+ _1: []
113
+ },
114
+ {
115
+ TAG: "PublishCommands",
116
+ _0: "Nope",
117
+ _1: []
118
+ }
119
+ ], publishCommands, () => {});
120
+ globalThis.expect(published.length).toBe(1);
121
+ });
122
+ globalThis.test("routes schedule actions to the scheduler ops; skips when unconfigured", async () => {
123
+ let created = [];
124
+ let deleted = [];
125
+ let ops_createSchedule = async s => {
126
+ created.push(s.name);
127
+ };
128
+ let ops_deleteSchedule = async name => {
129
+ deleted.push(name);
130
+ };
131
+ let ops = {
132
+ createSchedule: ops_createSchedule,
133
+ deleteSchedule: ops_deleteSchedule
134
+ };
135
+ await TaskBucketEntryPoint_Ops$ReventlessAws.dispatchTaskActions([
136
+ {
137
+ TAG: "CreateSchedule",
138
+ _0: schedule
139
+ },
140
+ {
141
+ TAG: "DeleteSchedule",
142
+ _0: "sweep"
143
+ }
144
+ ], {}, () => ops);
145
+ globalThis.expect(created).toEqual(["sweep"]);
146
+ globalThis.expect(deleted).toEqual(["sweep"]);
147
+ await TaskBucketEntryPoint_Ops$ReventlessAws.dispatchTaskActions([
148
+ {
149
+ TAG: "CreateSchedule",
150
+ _0: schedule
151
+ },
152
+ {
153
+ TAG: "DeleteSchedule",
154
+ _0: "sweep"
155
+ }
156
+ ], {}, () => {});
157
+ globalThis.expect(created.length).toBe(1);
158
+ });
159
+ });
160
+
161
+ export {
162
+ str,
163
+ obj,
164
+ }
165
+ /* Not a pure module */
@@ -1,5 +1,6 @@
1
1
  // Integration regression guard for the StateViewSlice projection Lambda entry
2
- // point (`StateViewSliceEntryPoint.mjs`), run against DynamoDB Local.
2
+ // point (`StateViewSliceEntryPoint.mjs` + `StateViewSliceEntryPoint_Ops.res`),
3
+ // run against DynamoDB Local.
3
4
  //
4
5
  // Covers the 2026-07-09 incident: the deployed runtime built its projection
5
6
  // loop with `handleAction(action, queryDbOps, undefined)` — hardcoding
@@ -8,8 +9,10 @@
8
9
  // then hit the `MissingSubIdConfig` guard and silently wrote nothing, while the
9
10
  // in-memory GWT/callback path (which threads `subIdConfig`) stayed green. This
10
11
  // is a deployed-runtime vs test-harness parity gap: a unit test on the callback
11
- // path cannot catch it, so this test drives the *real* `.mjs` entry point that
12
- // production uses.
12
+ // path cannot catch it, so this test drives the real entry-point wiring the
13
+ // production shell uses — `makeRegisteredHandler` with the modules record read
14
+ // off the dynamically imported spec/projection modules, invoked with an
15
+ // SQS-shaped Lambda record so the full decode path runs.
13
16
  //
14
17
  // The fixture `SvsTestSlice` is an `@subId productId` view slice whose only
15
18
  // projection path is `UpdateMultiState`. Before the fix both appends no-op and
@@ -48,26 +51,52 @@ let createViewTable = async (tableName): Util_DynamoDb_Runtime.resolvedTable =>
48
51
  }
49
52
  }
50
53
 
51
- // Drives the real entry point: builds the handler via its exported
52
- // `buildJsonEventsHandler` factory (DynamoDB path — `pgConnection`/`stateTopicName`
53
- // undefined), feeds one encoded event through the effect Stream, and runs the
54
- // resulting Effect through the request context the production handler supplies.
54
+ // Drives the real entry-point wiring: mirrors the shell's untyped seam line for
55
+ // line a HANDLER_CONFIG-shaped entry (DynamoDB path — `pgConnection`/
56
+ // `stateTopicName` undefined) plus the modules record read off the dynamically
57
+ // imported spec/projection modules then feeds one SQS-shaped Lambda record
58
+ // through the registered stream handler, so the same decode path the deployed
59
+ // Lambda runs (handleStreamEvent → envelope decode → schema parse → project →
60
+ // handleAction) is exercised end to end.
55
61
  let runOneEvent: (string, JSON.t) => promise<unit> = %raw(`
56
62
  async (tableName, eventJson) => {
57
- const { buildJsonEventsHandler } = await import(
58
- "@reventlessdev/reventless-aws/src/adapter/Runtime/StateViewSliceEntryPoint.mjs"
63
+ const Ops = await import(
64
+ "@reventlessdev/reventless-aws/src/adapter/Runtime/StateViewSliceEntryPoint_Ops.res.mjs"
59
65
  );
60
66
  const specModule = await import("./SvsTestSlice.res.mjs");
61
67
  const projectionModule = await import("./SvsTestSlice_Projection.res.mjs");
62
68
  const Effect = await import("effect/Effect");
63
- const Stream = await import("effect/Stream");
64
69
  const { tag: requestContextTag } = await import(
65
70
  "@reventlessdev/reventless-core/src/RequestContext.res.mjs"
66
71
  );
67
72
 
68
- const handler = buildJsonEventsHandler(specModule, projectionModule, tableName, undefined, undefined);
69
- const stream = Stream.fromIterable([eventJson]);
70
- const effect = handler(stream)
73
+ const registered = Ops.makeRegisteredHandler(
74
+ {
75
+ specModule: "",
76
+ projectionModule: "",
77
+ queryDbTableName: tableName,
78
+ sourceUrn: "svs-test-urn",
79
+ stateTopicName: undefined,
80
+ pgConnection: undefined,
81
+ },
82
+ {
83
+ name: specModule.name,
84
+ consumedEventSchema: specModule.consumedEventSchema,
85
+ project: projectionModule.project,
86
+ config: specModule.config,
87
+ subIdConfig: specModule.subIdConfig,
88
+ },
89
+ );
90
+ const event = {
91
+ Records: [
92
+ {
93
+ eventSource: "aws:sqs",
94
+ eventSourceARN: "svs-test-urn",
95
+ body: JSON.stringify(eventJson),
96
+ },
97
+ ],
98
+ };
99
+ const effect = registered.handler(event, {})
71
100
  .pipe(Effect.provideService(requestContextTag, { correlationId: "svs-test" }));
72
101
  await Effect.runPromise(effect);
73
102
  }
@@ -69,20 +69,43 @@ async function createViewTable(tableName) {
69
69
  }
70
70
 
71
71
  let runOneEvent = (async (tableName, eventJson) => {
72
- const { buildJsonEventsHandler } = await import(
73
- "@reventlessdev/reventless-aws/src/adapter/Runtime/StateViewSliceEntryPoint.mjs"
72
+ const Ops = await import(
73
+ "@reventlessdev/reventless-aws/src/adapter/Runtime/StateViewSliceEntryPoint_Ops.res.mjs"
74
74
  );
75
75
  const specModule = await import("./SvsTestSlice.res.mjs");
76
76
  const projectionModule = await import("./SvsTestSlice_Projection.res.mjs");
77
77
  const Effect = await import("effect/Effect");
78
- const Stream = await import("effect/Stream");
79
78
  const { tag: requestContextTag } = await import(
80
79
  "@reventlessdev/reventless-core/src/RequestContext.res.mjs"
81
80
  );
82
81
 
83
- const handler = buildJsonEventsHandler(specModule, projectionModule, tableName, undefined, undefined);
84
- const stream = Stream.fromIterable([eventJson]);
85
- const effect = handler(stream)
82
+ const registered = Ops.makeRegisteredHandler(
83
+ {
84
+ specModule: "",
85
+ projectionModule: "",
86
+ queryDbTableName: tableName,
87
+ sourceUrn: "svs-test-urn",
88
+ stateTopicName: undefined,
89
+ pgConnection: undefined,
90
+ },
91
+ {
92
+ name: specModule.name,
93
+ consumedEventSchema: specModule.consumedEventSchema,
94
+ project: projectionModule.project,
95
+ config: specModule.config,
96
+ subIdConfig: specModule.subIdConfig,
97
+ },
98
+ );
99
+ const event = {
100
+ Records: [
101
+ {
102
+ eventSource: "aws:sqs",
103
+ eventSourceARN: "svs-test-urn",
104
+ body: JSON.stringify(eventJson),
105
+ },
106
+ ],
107
+ };
108
+ const effect = registered.handler(event, {})
86
109
  .pipe(Effect.provideService(requestContextTag, { correlationId: "svs-test" }));
87
110
  await Effect.runPromise(effect);
88
111
  });
@@ -1,57 +0,0 @@
1
- // PgChangeFeedRelay Lambda entry point (scheduled poll — B2.3).
2
- //
3
- // Triggered on a schedule (EventBridge rate rule). Each invocation drains every
4
- // Postgres log listed in HANDLER_CONFIG from its checkpoint — DCB (`dcb_event`)
5
- // and classic aggregate (`event_log`) logs alike — and relays the events,
6
- // transformed into the {id, meta, event} shape, onto the plugin EventCollector
7
- // SQS queue — which then fans out to projections, aggregate command topics, and
8
- // the cross-plugin SNS EventTopic.
9
- // See docs/plans/done/aws-postgres-change-feed-bridge.md.
10
- //
11
- // HANDLER_CONFIG shape:
12
- // { "logs": [ { "pgConnection": {host,port,database,username,secretArn},
13
- // "logName": string, // dcb_event/event_log log_name
14
- // "subscriber": string, // per-log checkpoint key
15
- // "targetQueueUrl": string, // plugin EventCollector SQS URL
16
- // "kind"?: "classic", // absent → DCB
17
- // "partitionTag"?: <derivedPartitionTag> } ] } // DCB only
18
-
19
- import { relay, relayClassic } from "@reventlessdev/reventless-aws/src/adapter/Postgres/PgChangeFeedRelay_Runtime.res.mjs";
20
- import { sendMessage } from "@reventlessdev/reventless-aws/src/util/Util_SQS_Runtime.res.mjs";
21
- import { makeQueueRef, log } from "./HandlerFactoryHelpers.mjs";
22
-
23
- // Standard (non-FIFO) EventCollector queue — no message group id needed. The
24
- // SQS handler parses each body straight back to JSON (Util_SQS_Runtime.parseSqsRecord).
25
- function makeSendBatch(targetQueueUrl) {
26
- const queue = makeQueueRef(targetQueueUrl);
27
- return (jsons) =>
28
- Promise.all(jsons.map((json) => sendMessage(queue, undefined, JSON.stringify(json)))).then(
29
- () => {}
30
- );
31
- }
32
-
33
- export async function handler(_event, _context) {
34
- const configStr = process.env["HANDLER_CONFIG"] || '{"logs":[]}';
35
- const config = JSON.parse(configStr);
36
- const logs = config.logs || [];
37
-
38
- await Promise.all(
39
- logs.map(async (l) => {
40
- const sendBatch = makeSendBatch(l.targetQueueUrl);
41
- try {
42
- const count =
43
- l.kind === "classic"
44
- ? await relayClassic(l.pgConnection, l.logName, l.subscriber, sendBatch)
45
- : await relay(l.pgConnection, l.logName, l.subscriber, l.partitionTag, sendBatch);
46
- log.debug("relayed " + count + " event(s) for " + l.logName, { comp: "PgChangeFeedRelay" });
47
- } catch (err) {
48
- // Log and continue — a failed log this tick is retried next tick from its
49
- // unchanged checkpoint (at-least-once; projections are idempotent).
50
- log.warn("relay failed for " + l.logName + ": " + (err?.message ?? String(err)), {
51
- comp: "PgChangeFeedRelay",
52
- });
53
- }
54
- })
55
- );
56
- return "";
57
- }
@@ -1,40 +0,0 @@
1
- // One-shot Postgres schema-migration Lambda entry point (A3).
2
- //
3
- // Invoked once during `pulumi up` by an `aws.lambda.Invocation` resource, from
4
- // INSIDE the DB's VPC, so the deploy runner needs no network path to a private
5
- // RDS instance. Runs the exact idempotent `PgSchema.ensureSchema` the local
6
- // backend runs at startup (reventless-local's `postgres` smart constructor), so
7
- // the AWS schema is byte-identical to local — zero drift. Every statement is
8
- // `IF NOT EXISTS`, so re-invocation (e.g. after a schema-DDL change bumps the
9
- // Lambda layer) is safe.
10
- //
11
- // HANDLER_CONFIG shape:
12
- // { "pgConnection": { host, port, database, username, secretArn } }
13
-
14
- import { poolFor } from "@reventlessdev/reventless-aws/src/adapter/Postgres/PgRuntime.res.mjs";
15
- import { ensureSchema } from "@reventlessdev/reventless-postgres/src/PgSchema.res.mjs";
16
- import { log } from "./HandlerFactoryHelpers.mjs";
17
-
18
- // Config parse → pool → ensureSchema, with the pool source injectable so the
19
- // orchestration is integration-testable against a real Postgres without the
20
- // Secrets Manager round-trip (mirrors PgChangeFeedRelay_Runtime's
21
- // relayWithPool/relay split). `opts.makePool` defaults to the production `poolFor`.
22
- export async function runMigration(config, opts = {}) {
23
- if (!config.pgConnection) {
24
- throw new Error("PgMigrationEntryPoint: HANDLER_CONFIG has no pgConnection");
25
- }
26
- // `poolFor` memoises one pool per secret ARN per container and resolves the
27
- // RDS-managed password from Secrets Manager via a cached provider.
28
- const makePool = opts.makePool ?? poolFor;
29
- const pool = makePool(config.pgConnection);
30
- await ensureSchema(pool);
31
- log.info("ensureSchema completed for " + config.pgConnection.database, {
32
- comp: "PgMigration",
33
- });
34
- return "ok";
35
- }
36
-
37
- export async function handler(_event, _context) {
38
- const config = JSON.parse(process.env["HANDLER_CONFIG"] || "{}");
39
- return runMigration(config);
40
- }