@reventlessdev/reventless-local 3.0.0-alpha.185 → 3.0.0-alpha.186
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
CHANGED
|
@@ -3,6 +3,13 @@
|
|
|
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.186 (2026-08-01)
|
|
7
|
+
|
|
8
|
+
### Bug Fixes
|
|
9
|
+
|
|
10
|
+
* **core:** drain the inbound audit log per request, not wholesale ([e18d4ec](https://github.com/ReventlessDev/reventless-core/commit/e18d4ec4b7ffb38a9e2bd3594d39a07e2ee91851))
|
|
11
|
+
|
|
12
|
+
|
|
6
13
|
# 3.0.0-alpha.185 (2026-08-01)
|
|
7
14
|
|
|
8
15
|
**Note:** Version bump only for package @reventlessdev/reventless-local
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reventlessdev/reventless-local",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.186",
|
|
4
4
|
"description": "Local platform for Reventless (in-memory or SQLite backend, for development and testing without AWS)",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"bin": {
|
|
@@ -35,17 +35,17 @@
|
|
|
35
35
|
"sury": "11.0.0-alpha.4",
|
|
36
36
|
"ws": "^8.18.0",
|
|
37
37
|
"@reventlessdev/rescript-effect": "0.1.0-alpha.32",
|
|
38
|
-
"@reventlessdev/rescript-mcp-sdk": "1.0.0-alpha.21",
|
|
39
38
|
"@reventlessdev/rescript-jest": "1.0.0-alpha.10",
|
|
40
39
|
"@reventlessdev/rescript-graphql-yoga": "1.0.0-alpha.26",
|
|
40
|
+
"@reventlessdev/rescript-mcp-sdk": "1.0.0-alpha.21",
|
|
41
41
|
"@reventlessdev/rescript-node": "2.0.0-alpha.0",
|
|
42
42
|
"@reventlessdev/rescript-pulumi-pulumi": "2.3.0-alpha.18",
|
|
43
|
-
"@reventlessdev/reventless-core": "3.0.0-alpha.
|
|
44
|
-
"@reventlessdev/reventless-
|
|
43
|
+
"@reventlessdev/reventless-core": "3.0.0-alpha.198",
|
|
44
|
+
"@reventlessdev/reventless-graphql-server": "1.0.0-alpha.46",
|
|
45
|
+
"@reventlessdev/reventless-gwt": "1.0.0-alpha.145",
|
|
45
46
|
"@reventlessdev/reventless-infra": "3.0.0-alpha.115",
|
|
46
|
-
"@reventlessdev/reventless-
|
|
47
|
-
"@reventlessdev/reventless-
|
|
48
|
-
"@reventlessdev/reventless-postgres": "3.0.0-alpha.61"
|
|
47
|
+
"@reventlessdev/reventless-postgres": "3.0.0-alpha.62",
|
|
48
|
+
"@reventlessdev/reventless-spec": "3.0.0-alpha.90"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
51
|
"rescript": "12.3.0",
|
|
@@ -125,6 +125,60 @@ describe("InboundTranslationSlice Callback", () => {
|
|
|
125
125
|
})
|
|
126
126
|
})
|
|
127
127
|
|
|
128
|
+
// `auditLog` hands a row to whoever persists it and must not keep it: the dict
|
|
129
|
+
// outlives the request (a warm Lambda container serves many), so a drain that
|
|
130
|
+
// re-read the whole dict would rewrite every row the container had ever seen on
|
|
131
|
+
// every request — and, since the write overwrites by row id, would resurrect
|
|
132
|
+
// rows deleted from the table in between. Persisting is per-request and takes.
|
|
133
|
+
describe("draining the audit log", () => {
|
|
134
|
+
testPromise("taking a row leaves the log empty for the next request", async () => {
|
|
135
|
+
let mockPublish: ReventlessInfra.CommandTopic.publishJsons = async _cmds => ()
|
|
136
|
+
let input = status =>
|
|
137
|
+
{"paymentId": "pay-1", "orderId": "ord-1", "status": status}->Obj.magic
|
|
138
|
+
|
|
139
|
+
let first = await Callback.receive(mockPublish, input("completed"))
|
|
140
|
+
let firstId = first->ReventlessCore.InboundTranslationSlice_Callback.requestIdOf
|
|
141
|
+
expect(
|
|
142
|
+
Callback.auditLog
|
|
143
|
+
->ReventlessCore.InboundTranslationSlice_Callback.takeAuditRow(firstId)
|
|
144
|
+
->Option.isSome,
|
|
145
|
+
)->toBe(true)
|
|
146
|
+
expect(Callback.auditLog->Dict.toArray->Array.length)->toBe(0)
|
|
147
|
+
|
|
148
|
+
// A second request drains only its own row — the first one is gone, so it
|
|
149
|
+
// cannot be written a second time.
|
|
150
|
+
let second = await Callback.receive(mockPublish, input("completed"))
|
|
151
|
+
let secondId = second->ReventlessCore.InboundTranslationSlice_Callback.requestIdOf
|
|
152
|
+
expect(secondId == firstId)->toBe(false)
|
|
153
|
+
expect(Callback.auditLog->Dict.toArray->Array.length)->toBe(1)
|
|
154
|
+
expect(
|
|
155
|
+
Callback.auditLog
|
|
156
|
+
->ReventlessCore.InboundTranslationSlice_Callback.takeAuditRow(firstId)
|
|
157
|
+
->Option.isSome,
|
|
158
|
+
)->toBe(false)
|
|
159
|
+
expect(
|
|
160
|
+
Callback.auditLog
|
|
161
|
+
->ReventlessCore.InboundTranslationSlice_Callback.takeAuditRow(secondId)
|
|
162
|
+
->Option.isSome,
|
|
163
|
+
)->toBe(true)
|
|
164
|
+
})
|
|
165
|
+
|
|
166
|
+
testPromise("a rejected request's row is drained the same way", async () => {
|
|
167
|
+
let mockPublish: ReventlessInfra.CommandTopic.publishJsons = async _cmds => ()
|
|
168
|
+
let result = await Callback.receive(
|
|
169
|
+
mockPublish,
|
|
170
|
+
{"paymentId": "pay-1", "orderId": "ord-1", "status": "pending"}->Obj.magic,
|
|
171
|
+
)
|
|
172
|
+
let id = result->ReventlessCore.InboundTranslationSlice_Callback.requestIdOf
|
|
173
|
+
switch Callback.auditLog->ReventlessCore.InboundTranslationSlice_Callback.takeAuditRow(id) {
|
|
174
|
+
| Some(row) =>
|
|
175
|
+
expect(row.status)->toBe(ReventlessCore.InboundTranslationSlice_Callback.Failure)
|
|
176
|
+
| None => expect(true)->toBe(false)
|
|
177
|
+
}
|
|
178
|
+
expect(Callback.auditLog->Dict.toArray->Array.length)->toBe(0)
|
|
179
|
+
})
|
|
180
|
+
})
|
|
181
|
+
|
|
128
182
|
describe("multi-command", () => {
|
|
129
183
|
testPromise("translate returning multiple pairs publishes all commands", async () => {
|
|
130
184
|
// Use a spec that returns multiple commands
|
package/tests/components/inboundtranslationslice/InboundTranslationSliceCallbackTest.res.mjs
CHANGED
|
@@ -122,6 +122,45 @@ globalThis.describe("InboundTranslationSlice Callback", () => {
|
|
|
122
122
|
globalThis.expect(match[1].status).toBe("Failure");
|
|
123
123
|
});
|
|
124
124
|
});
|
|
125
|
+
globalThis.describe("draining the audit log", () => {
|
|
126
|
+
globalThis.test("taking a row leaves the log empty for the next request", async () => {
|
|
127
|
+
let mockPublish = async _cmds => {};
|
|
128
|
+
let first = await Callback.receive(mockPublish, {
|
|
129
|
+
paymentId: "pay-1",
|
|
130
|
+
orderId: "ord-1",
|
|
131
|
+
status: "completed"
|
|
132
|
+
});
|
|
133
|
+
let firstId = InboundTranslationSlice_Callback$ReventlessCore.requestIdOf(first);
|
|
134
|
+
globalThis.expect(Stdlib_Option.isSome(InboundTranslationSlice_Callback$ReventlessCore.takeAuditRow(Callback.auditLog, firstId))).toBe(true);
|
|
135
|
+
globalThis.expect(Object.entries(Callback.auditLog).length).toBe(0);
|
|
136
|
+
let second = await Callback.receive(mockPublish, {
|
|
137
|
+
paymentId: "pay-1",
|
|
138
|
+
orderId: "ord-1",
|
|
139
|
+
status: "completed"
|
|
140
|
+
});
|
|
141
|
+
let secondId = InboundTranslationSlice_Callback$ReventlessCore.requestIdOf(second);
|
|
142
|
+
globalThis.expect(secondId === firstId).toBe(false);
|
|
143
|
+
globalThis.expect(Object.entries(Callback.auditLog).length).toBe(1);
|
|
144
|
+
globalThis.expect(Stdlib_Option.isSome(InboundTranslationSlice_Callback$ReventlessCore.takeAuditRow(Callback.auditLog, firstId))).toBe(false);
|
|
145
|
+
globalThis.expect(Stdlib_Option.isSome(InboundTranslationSlice_Callback$ReventlessCore.takeAuditRow(Callback.auditLog, secondId))).toBe(true);
|
|
146
|
+
});
|
|
147
|
+
globalThis.test("a rejected request's row is drained the same way", async () => {
|
|
148
|
+
let mockPublish = async _cmds => {};
|
|
149
|
+
let result = await Callback.receive(mockPublish, {
|
|
150
|
+
paymentId: "pay-1",
|
|
151
|
+
orderId: "ord-1",
|
|
152
|
+
status: "pending"
|
|
153
|
+
});
|
|
154
|
+
let id = InboundTranslationSlice_Callback$ReventlessCore.requestIdOf(result);
|
|
155
|
+
let row = InboundTranslationSlice_Callback$ReventlessCore.takeAuditRow(Callback.auditLog, id);
|
|
156
|
+
if (row !== undefined) {
|
|
157
|
+
globalThis.expect(row.status).toBe("Failure");
|
|
158
|
+
} else {
|
|
159
|
+
globalThis.expect(true).toBe(false);
|
|
160
|
+
}
|
|
161
|
+
globalThis.expect(Object.entries(Callback.auditLog).length).toBe(0);
|
|
162
|
+
});
|
|
163
|
+
});
|
|
125
164
|
globalThis.describe("multi-command", () => {
|
|
126
165
|
globalThis.test("translate returning multiple pairs publishes all commands", async () => {
|
|
127
166
|
let moduleUrl = import.meta.url;
|