@reventlessdev/reventless-core 3.0.0-alpha.138 → 3.0.0-alpha.139

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.139 (2026-07-05)
7
+
8
+ ### Features
9
+
10
+ * **postgres:** add reventless-postgres backend + local-platform integration ([6913200](https://github.com/ReventlessDev/reventless-core/commit/69132001f9271e832a5af33416acd5b645feaf47))
11
+
12
+
6
13
  # 3.0.0-alpha.138 (2026-07-04)
7
14
 
8
15
  ### Features
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reventlessdev/reventless-core",
3
- "version": "3.0.0-alpha.138",
3
+ "version": "3.0.0-alpha.139",
4
4
  "description": "Core package for Reventless framework",
5
5
  "license": "Apache-2.0",
6
6
  "jest": {
@@ -28,17 +28,17 @@
28
28
  "dependencies": {
29
29
  "sury": "11.0.0-alpha.4",
30
30
  "uuid": "^13.0.0",
31
+ "@reventlessdev/rescript-effect": "0.1.0-alpha.24",
31
32
  "@reventlessdev/rescript-fast-csv": "1.2.0-alpha.11",
32
33
  "@reventlessdev/rescript-jest": "1.0.0-alpha.5",
33
34
  "@reventlessdev/rescript-node-streams": "1.1.0-alpha.10",
34
- "@reventlessdev/rescript-effect": "0.1.0-alpha.24",
35
35
  "@reventlessdev/rescript-hash-object": "1.2.0-alpha.10",
36
- "@reventlessdev/rescript-ssh2": "1.1.0-alpha.11",
37
36
  "@reventlessdev/rescript-pulumi-pulumi": "2.3.0-alpha.14",
38
37
  "@reventlessdev/rescript-uuid": "1.1.0-alpha.13",
38
+ "@reventlessdev/rescript-ssh2": "1.1.0-alpha.11",
39
39
  "@reventlessdev/reventless-interop": "3.0.0-alpha.23",
40
40
  "@reventlessdev/reventless-spec": "3.0.0-alpha.64",
41
- "@reventlessdev/reventless-infra": "3.0.0-alpha.84"
41
+ "@reventlessdev/reventless-infra": "3.0.0-alpha.85"
42
42
  },
43
43
  "devDependencies": {
44
44
  "rescript": "^12.3.0",
@@ -27,7 +27,7 @@ type operations = {
27
27
  append: (
28
28
  array<rawStoredEvent>,
29
29
  ~condition: Reventless.DcbTag.appendCondition=?,
30
- ) => promise<result<Reventless.DcbTag.sequencePosition, string>>,
30
+ ) => promise<result<Reventless.DcbTag.sequencePosition, ReventlessInfra.DcbEventLog.appendError>>,
31
31
  readStream: (
32
32
  ~query: Reventless.DcbTag.query,
33
33
  ~after: Reventless.DcbTag.sequencePosition=?,
@@ -358,6 +358,12 @@ module Make = (
358
358
  _ => Ok("ok"),
359
359
  )
360
360
  | Error(err) =>
361
+ // Typed classification (was substring-matching the error string,
362
+ // which disagreed with the backends' casing).
363
+ let (errorCode, errDetail) = switch err {
364
+ | ReventlessInfra.DcbEventLog.Conflict => ("Conflict", "conflict: condition check failed")
365
+ | StorageFailure(msg) => ("AppendFailed", msg)
366
+ }
361
367
  if retries > 0 {
362
368
  // Re-seed from the just-read snapshot so the retry reads only
363
369
  // the delta the conflicting writer added, not full history.
@@ -369,13 +375,12 @@ module Make = (
369
375
  EffectLogger.logWarn(
370
376
  ~comp,
371
377
  `append failed (retrying ${(maxRetries - retries + 1)
372
- ->Int.toString}/${maxRetries->Int.toString}): ${err}`,
378
+ ->Int.toString}/${maxRetries->Int.toString}): ${errDetail}`,
373
379
  )->Effect.flatMap(_ => attempt(~retries=retries - 1))
374
380
  } else {
375
381
  // Retries exhausted — drop any cached snapshot so the next
376
382
  // command for this entity takes the cold full-read path.
377
383
  cacheInvalidate()
378
- let errorCode = err->String.startsWith("Conflict") ? "Conflict" : "AppendFailed"
379
384
  // A surfaced Conflict means the 3-retry loop could not absorb
380
385
  // the contention — the operator signal for "this slice is hot"
381
386
  // (consider sharding / async — Issue 10, §4 of the analysis).
@@ -384,12 +389,12 @@ module Make = (
384
389
  }
385
390
  CommandTopic_Helpers.reportRejected(
386
391
  cmdJson.meta.msgId,
387
- {errorCode, errorDetail: err},
392
+ {errorCode, errorDetail: errDetail},
388
393
  )
389
394
  EffectLogger.logError(
390
395
  ~comp,
391
- `append failed, retries exhausted: ${err}`,
392
- )->Effect.map(_ => Error(err))
396
+ `append failed, retries exhausted: ${errDetail}`,
397
+ )->Effect.map(_ => Error(errDetail))
393
398
  }
394
399
  },
395
400
  )
@@ -235,27 +235,37 @@ function Make(Spec) {
235
235
  }));
236
236
  }
237
237
  let err = appendResult._0;
238
+ let match;
239
+ match = typeof err !== "object" ? [
240
+ "Conflict",
241
+ "conflict: condition check failed"
242
+ ] : [
243
+ "AppendFailed",
244
+ err._0
245
+ ];
246
+ let errDetail = match[1];
247
+ let errorCode = match[0];
238
248
  if (retries > 0) {
239
249
  seed.contents = [
240
250
  state,
241
251
  headPosition
242
252
  ];
243
253
  Metrics$ReventlessCore.emitCount("AppendRetry", Spec.name, undefined);
244
- return Effect.flatMap(EffectLogger$ReventlessCore.logWarn(comp, undefined, `append failed (retrying ` + ((3 - retries | 0) + 1 | 0).toString() + `/` + (3).toString() + `): ` + err), () => attempt(retries - 1 | 0));
245
- }
246
- cacheInvalidate();
247
- let errorCode = err.startsWith("Conflict") ? "Conflict" : "AppendFailed";
248
- if (errorCode === "Conflict") {
249
- Metrics$ReventlessCore.emitCount("AppendConflict", Spec.name, undefined);
254
+ return Effect.flatMap(EffectLogger$ReventlessCore.logWarn(comp, undefined, `append failed (retrying ` + ((3 - retries | 0) + 1 | 0).toString() + `/` + (3).toString() + `): ` + errDetail), () => attempt(retries - 1 | 0));
255
+ } else {
256
+ cacheInvalidate();
257
+ if (errorCode === "Conflict") {
258
+ Metrics$ReventlessCore.emitCount("AppendConflict", Spec.name, undefined);
259
+ }
260
+ CommandTopic_Helpers$ReventlessCore.reportRejected(cmdJson.meta.msgId, {
261
+ errorCode: errorCode,
262
+ errorDetail: errDetail
263
+ });
264
+ return Effect.map(EffectLogger$ReventlessCore.logError(comp, undefined, `append failed, retries exhausted: ` + errDetail), () => ({
265
+ TAG: "Error",
266
+ _0: errDetail
267
+ }));
250
268
  }
251
- CommandTopic_Helpers$ReventlessCore.reportRejected(cmdJson.meta.msgId, {
252
- errorCode: errorCode,
253
- errorDetail: err
254
- });
255
- return Effect.map(EffectLogger$ReventlessCore.logError(comp, undefined, `append failed, retries exhausted: ` + err), () => ({
256
- TAG: "Error",
257
- _0: err
258
- }));
259
269
  });
260
270
  }
261
271
  cachePut([
@@ -167,7 +167,7 @@ let makeMockStorage = (): mockStorage => {
167
167
  let append = async (newEvents, ~condition=?) => {
168
168
  if failNextAppendsRef.contents > 0 {
169
169
  failNextAppendsRef := failNextAppendsRef.contents - 1
170
- Error("conflict")
170
+ Error(ReventlessInfra.DcbEventLog.Conflict)
171
171
  } else {
172
172
  let conflictDetected = switch condition {
173
173
  | Some(cond: Reventless.DcbTag.appendCondition) =>
@@ -181,7 +181,7 @@ let makeMockStorage = (): mockStorage => {
181
181
  | None => false
182
182
  }
183
183
  if conflictDetected {
184
- Error("conflict: condition check failed")
184
+ Error(ReventlessInfra.DcbEventLog.Conflict)
185
185
  } else {
186
186
  let storedEvents = newEvents->Array.map((event: DcbEventLog_Adapter.rawStoredEvent) => {
187
187
  position := position.contents + 1
@@ -245,7 +245,7 @@ function makeMockStorage() {
245
245
  failNextAppendsRef.contents = failNextAppendsRef.contents - 1 | 0;
246
246
  return {
247
247
  TAG: "Error",
248
- _0: "conflict"
248
+ _0: "Conflict"
249
249
  };
250
250
  }
251
251
  let conflictDetected = condition !== undefined ? events.contents.some(event => {
@@ -260,7 +260,7 @@ function makeMockStorage() {
260
260
  if (conflictDetected) {
261
261
  return {
262
262
  TAG: "Error",
263
- _0: "conflict: condition check failed"
263
+ _0: "Conflict"
264
264
  };
265
265
  }
266
266
  let storedEvents = newEvents.map(event => {