@rotorsoft/act-tck 1.41.4 → 2.1.0

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/dist/index.cjs CHANGED
@@ -82,8 +82,7 @@ var seed_stream = async (store, stream, count, correlation) => {
82
82
  const out = [];
83
83
  for (let i = 0; i < count; i++) {
84
84
  const committed = await store.commit(
85
- stream,
86
- [inc(1)],
85
+ [{ stream, msgs: [inc(1)] }],
87
86
  make_meta({ correlation, stream })
88
87
  );
89
88
  out.push(...committed);
@@ -646,14 +645,17 @@ var apply_plan = async (store, plan, pii_isolation) => {
646
645
  if (op.t === "commit") {
647
646
  const msgs = op.pii && pii_isolation ? op.msgs.map((m, i) => i === 0 ? { ...m, pii: op.pii } : m) : op.msgs;
648
647
  await store.commit(
649
- op.stream,
650
- msgs,
648
+ [{ stream: op.stream, msgs }],
651
649
  make_meta({ stream: op.stream, correlation: plan.correlation })
652
650
  );
653
651
  } else if (op.t === "snapshot") {
654
652
  await store.commit(
655
- op.stream,
656
- [{ name: import_act.SNAP_EVENT, data: { count: op.count } }],
653
+ [
654
+ {
655
+ stream: op.stream,
656
+ msgs: [{ name: import_act.SNAP_EVENT, data: { count: op.count } }]
657
+ }
658
+ ],
657
659
  make_meta({ stream: op.stream, correlation: plan.correlation })
658
660
  );
659
661
  } else if (op.t === "truncate") {
@@ -662,8 +664,12 @@ var apply_plan = async (store, plan, pii_isolation) => {
662
664
  ]);
663
665
  } else if (op.t === "truncate_windowed") {
664
666
  await store.commit(
665
- op.stream,
666
- [{ name: import_act.SNAP_EVENT, data: { count: 1 } }],
667
+ [
668
+ {
669
+ stream: op.stream,
670
+ msgs: [{ name: import_act.SNAP_EVENT, data: { count: 1 } }]
671
+ }
672
+ ],
667
673
  make_meta({ stream: op.stream, correlation: plan.correlation })
668
674
  );
669
675
  await store.truncate([
@@ -974,8 +980,7 @@ var runStorePropertyTck = (options) => {
974
980
  for (const { stream, count } of commits) {
975
981
  const before = expected.get(stream) ?? -1;
976
982
  const committed = await store.commit(
977
- stream,
978
- events(count),
983
+ [{ stream, msgs: events(count) }],
979
984
  make_meta({ stream })
980
985
  );
981
986
  committed.forEach((e, i) => {
@@ -1000,8 +1005,7 @@ var runStorePropertyTck = (options) => {
1000
1005
  await reset2();
1001
1006
  for (const { stream: stream2, count } of commits) {
1002
1007
  await store.commit(
1003
- stream2,
1004
- events(count),
1008
+ [{ stream: stream2, msgs: events(count) }],
1005
1009
  make_meta({ stream: stream2 })
1006
1010
  );
1007
1011
  }
@@ -1009,10 +1013,8 @@ var runStorePropertyTck = (options) => {
1009
1013
  const before = await collect(store, { stream, stream_exact: true });
1010
1014
  await (0, import_vitest8.expect)(
1011
1015
  store.commit(
1012
- stream,
1013
- [inc(1)],
1014
- make_meta({ stream }),
1015
- before.length
1016
+ [{ stream, msgs: [inc(1)], expectedVersion: before.length }],
1017
+ make_meta({ stream })
1016
1018
  )
1017
1019
  ).rejects.toThrow();
1018
1020
  const after = await collect(store, { stream, stream_exact: true });
@@ -1039,8 +1041,7 @@ var runStorePropertyTck = (options) => {
1039
1041
  for (const op of ops) {
1040
1042
  if (op.kind === "commit") {
1041
1043
  await store.commit(
1042
- op.stream,
1043
- [inc(1)],
1044
+ [{ stream: op.stream, msgs: [inc(1)] }],
1044
1045
  make_meta({ stream: op.stream })
1045
1046
  );
1046
1047
  } else if (op.kind === "claim") {
@@ -1082,8 +1083,7 @@ var runStorePropertyTck = (options) => {
1082
1083
  await store.subscribe(all.map((stream) => ({ stream })));
1083
1084
  for (const stream of commitsA) {
1084
1085
  await store.commit(
1085
- stream,
1086
- [inc(1)],
1086
+ [{ stream, msgs: [inc(1)] }],
1087
1087
  make_meta({ stream })
1088
1088
  );
1089
1089
  }
@@ -1095,8 +1095,7 @@ var runStorePropertyTck = (options) => {
1095
1095
  for (const l of acked1) watermark1.set(l.stream, l.at);
1096
1096
  for (const stream of commitsB) {
1097
1097
  await store.commit(
1098
- stream,
1099
- [inc(1)],
1098
+ [{ stream, msgs: [inc(1)] }],
1100
1099
  make_meta({ stream })
1101
1100
  );
1102
1101
  }
@@ -1122,8 +1121,7 @@ var runStorePropertyTck = (options) => {
1122
1121
  await store.subscribe(streams.map((stream) => ({ stream })));
1123
1122
  for (const stream of commits) {
1124
1123
  await store.commit(
1125
- stream,
1126
- [inc(1)],
1124
+ [{ stream, msgs: [inc(1)] }],
1127
1125
  make_meta({ stream })
1128
1126
  );
1129
1127
  }
@@ -1133,8 +1131,7 @@ var runStorePropertyTck = (options) => {
1133
1131
  const blockedSet = new Set(claimed.map((l) => l.stream));
1134
1132
  await store.subscribe([{ stream: "ctrl" }]);
1135
1133
  await store.commit(
1136
- "ctrl",
1137
- [inc(1)],
1134
+ [{ stream: "ctrl", msgs: [inc(1)] }],
1138
1135
  make_meta({ stream: "ctrl" })
1139
1136
  );
1140
1137
  await mark_all(store);
@@ -1149,6 +1146,7 @@ var runStorePropertyTck = (options) => {
1149
1146
 
1150
1147
  // src/store-tck.ts
1151
1148
  var import_act2 = require("@rotorsoft/act");
1149
+ var import_adapter = require("@rotorsoft/act/adapter");
1152
1150
  var import_vitest9 = require("vitest");
1153
1151
  var import_zod2 = require("zod");
1154
1152
  var runStoreTck = (options) => {
@@ -1176,7 +1174,7 @@ var runStoreTck = (options) => {
1176
1174
  },
1177
1175
  row.source !== void 0 ? {
1178
1176
  stream: row.source,
1179
- stream_exact: (0, import_act2.is_literal_source)(row.source, row.stream)
1177
+ stream_exact: (0, import_adapter.isStreamName)(row.source, row.stream)
1180
1178
  } : {}
1181
1179
  );
1182
1180
  if (mark > row.at)
@@ -1213,14 +1211,12 @@ var runStoreTck = (options) => {
1213
1211
  await zero_config.seed();
1214
1212
  const s = `default-config-${uid()}`;
1215
1213
  const first = await zero_config.commit(
1216
- s,
1217
- [inc(1)],
1214
+ [{ stream: s, msgs: [inc(1)] }],
1218
1215
  make_meta({ stream: s })
1219
1216
  );
1220
1217
  (0, import_vitest9.expect)(first[0].version).toBe(0);
1221
1218
  const second = await zero_config.commit(
1222
- s,
1223
- [inc(2)],
1219
+ [{ stream: s, msgs: [inc(2)] }],
1224
1220
  make_meta({ stream: s })
1225
1221
  );
1226
1222
  (0, import_vitest9.expect)(second[0].version).toBe(1);
@@ -1236,12 +1232,371 @@ var runStoreTck = (options) => {
1236
1232
  });
1237
1233
  });
1238
1234
  }
1235
+ (0, import_vitest9.describe)("commit across streams", () => {
1236
+ const meta = make_meta({ stream: "across" });
1237
+ const count = (stream) => store.query(() => {
1238
+ }, { stream, stream_exact: true });
1239
+ (0, import_vitest9.it)("lands every append, each from its own head, with ids in append order", async () => {
1240
+ const a = `across-a-${uid()}`;
1241
+ const b = `across-b-${uid()}`;
1242
+ await store.commit(
1243
+ [{ stream: a, msgs: [inc(1)] }],
1244
+ meta
1245
+ );
1246
+ const committed = await store.commit(
1247
+ [
1248
+ { stream: a, msgs: [inc(2), inc(3)], expectedVersion: 0 },
1249
+ { stream: b, msgs: [dec(4)], expectedVersion: -1 }
1250
+ ],
1251
+ meta
1252
+ );
1253
+ (0, import_vitest9.expect)(committed.map((e) => [e.stream, e.version])).toEqual([
1254
+ [a, 1],
1255
+ [a, 2],
1256
+ [b, 0]
1257
+ ]);
1258
+ for (let i = 1; i < committed.length; i++)
1259
+ (0, import_vitest9.expect)(committed[i].id).toBeGreaterThan(committed[i - 1].id);
1260
+ const read = [];
1261
+ await store.query((e) => read.push(e.id), {
1262
+ after: committed[0].id - 1
1263
+ });
1264
+ (0, import_vitest9.expect)(read.filter((id) => committed.some((e) => e.id === id))).toEqual(
1265
+ committed.map((e) => e.id)
1266
+ );
1267
+ });
1268
+ (0, import_vitest9.it)("stores nothing when the first, a middle or the last append is stale, and names its stream", async () => {
1269
+ for (const at of [0, 1, 2]) {
1270
+ const streams = [0, 1, 2].map((i) => `across-stale-${i}-${uid()}`);
1271
+ for (const stream of streams)
1272
+ await store.commit(
1273
+ [{ stream, msgs: [inc(1)] }],
1274
+ meta
1275
+ );
1276
+ const refused = store.commit(
1277
+ streams.map((stream, i) => ({
1278
+ stream,
1279
+ msgs: [inc(2)],
1280
+ expectedVersion: i === at ? 5 : 0
1281
+ })),
1282
+ meta
1283
+ );
1284
+ await (0, import_vitest9.expect)(refused).rejects.toBeInstanceOf(import_act2.ConcurrencyError);
1285
+ await (0, import_vitest9.expect)(refused).rejects.toMatchObject({ stream: streams[at] });
1286
+ for (const stream of streams) (0, import_vitest9.expect)(await count(stream)).toBe(1);
1287
+ }
1288
+ });
1289
+ (0, import_vitest9.it)("refuses a stream named twice and an append with no events, storing nothing", async () => {
1290
+ const a = `across-twice-${uid()}`;
1291
+ const b = `across-empty-${uid()}`;
1292
+ await (0, import_vitest9.expect)(
1293
+ store.commit(
1294
+ [
1295
+ { stream: a, msgs: [inc(1)] },
1296
+ { stream: a, msgs: [inc(2)] }
1297
+ ],
1298
+ meta
1299
+ )
1300
+ ).rejects.toThrow(`stream "${a}" is named twice`);
1301
+ await (0, import_vitest9.expect)(
1302
+ store.commit(
1303
+ [
1304
+ { stream: a, msgs: [inc(1)] },
1305
+ { stream: b, msgs: [] }
1306
+ ],
1307
+ meta
1308
+ )
1309
+ ).rejects.toThrow(`the append to "${b}" has no events`);
1310
+ (0, import_vitest9.expect)(await count(a)).toBe(0);
1311
+ (0, import_vitest9.expect)(await count(b)).toBe(0);
1312
+ });
1313
+ (0, import_vitest9.it)("commits nothing for no appends", async () => {
1314
+ (0, import_vitest9.expect)(await store.commit([], meta)).toEqual([]);
1315
+ });
1316
+ (0, import_vitest9.it)("lands an unguarded append beside guarded ones", async () => {
1317
+ const a = `across-guarded-${uid()}`;
1318
+ const b = `across-free-${uid()}`;
1319
+ await store.commit(
1320
+ [{ stream: b, msgs: [inc(1)] }],
1321
+ meta
1322
+ );
1323
+ const committed = await store.commit(
1324
+ [
1325
+ { stream: a, msgs: [inc(1)], expectedVersion: -1 },
1326
+ { stream: b, msgs: [inc(2)] }
1327
+ ],
1328
+ meta
1329
+ );
1330
+ (0, import_vitest9.expect)(committed.map((e) => [e.stream, e.version])).toEqual([
1331
+ [a, 0],
1332
+ [b, 1]
1333
+ ]);
1334
+ });
1335
+ (0, import_vitest9.it)("stores every event of every append, whole", async () => {
1336
+ const a = `across-whole-a-${uid()}`;
1337
+ const b = `across-whole-b-${uid()}`;
1338
+ const across = make_meta({ stream: a });
1339
+ const committed = await store.commit(
1340
+ [
1341
+ { stream: a, msgs: [inc(1)] },
1342
+ { stream: b, msgs: [inc(2), dec(3)] }
1343
+ ],
1344
+ across
1345
+ );
1346
+ const shape = (e) => [
1347
+ e.name,
1348
+ e.data,
1349
+ e.meta
1350
+ ];
1351
+ const expected = [
1352
+ ["Incremented", { amount: 2 }, across],
1353
+ ["Decremented", { amount: 3 }, across]
1354
+ ];
1355
+ (0, import_vitest9.expect)(committed.filter((e) => e.stream === b).map(shape)).toEqual(
1356
+ expected
1357
+ );
1358
+ const stored = [];
1359
+ await store.query((e) => stored.push(e), {
1360
+ stream: b,
1361
+ stream_exact: true
1362
+ });
1363
+ (0, import_vitest9.expect)(stored.map(shape)).toEqual(expected);
1364
+ });
1365
+ import_vitest9.it.skipIf(!caps.pii_isolation)(
1366
+ "keeps the sensitive fields of a later append",
1367
+ async () => {
1368
+ const a = `across-pii-a-${uid()}`;
1369
+ const b = `across-pii-b-${uid()}`;
1370
+ await store.commit(
1371
+ [
1372
+ { stream: a, msgs: [inc(1)] },
1373
+ { stream: b, msgs: [{ ...inc(2), pii: { email: "e" } }] }
1374
+ ],
1375
+ make_meta({ stream: a })
1376
+ );
1377
+ const stored = [];
1378
+ await store.query((e) => stored.push(e.pii), {
1379
+ stream: b,
1380
+ stream_exact: true
1381
+ });
1382
+ (0, import_vitest9.expect)(stored).toEqual([{ email: "e" }]);
1383
+ }
1384
+ );
1385
+ (0, import_vitest9.it)("leaves nothing of the commit that lost a race, on any of its streams", async () => {
1386
+ const shared = `across-all-shared-${uid()}`;
1387
+ const [x, y] = [`across-all-x-${uid()}`, `across-all-y-${uid()}`];
1388
+ const race = (own) => store.commit(
1389
+ [
1390
+ { stream: own, msgs: [inc(1)], expectedVersion: -1 },
1391
+ { stream: shared, msgs: [inc(1)], expectedVersion: -1 }
1392
+ ],
1393
+ meta
1394
+ );
1395
+ const rs = await Promise.allSettled([race(x), race(y)]);
1396
+ (0, import_vitest9.expect)(rs.filter((r) => r.status === "fulfilled")).toHaveLength(1);
1397
+ (0, import_vitest9.expect)(await count(x) + await count(y)).toBe(1);
1398
+ });
1399
+ (0, import_vitest9.it)("lets one of two racing commits on a shared stream win, and both on disjoint streams", async () => {
1400
+ const shared = `across-shared-${uid()}`;
1401
+ const [x, y] = [`across-x-${uid()}`, `across-y-${uid()}`];
1402
+ const race = (own, other) => store.commit(
1403
+ [
1404
+ { stream: own, msgs: [inc(1)], expectedVersion: -1 },
1405
+ { stream: other, msgs: [inc(1)], expectedVersion: -1 }
1406
+ ],
1407
+ meta
1408
+ );
1409
+ const shared_race = await Promise.allSettled([
1410
+ race(x, shared),
1411
+ race(y, shared)
1412
+ ]);
1413
+ (0, import_vitest9.expect)(
1414
+ shared_race.filter((r2) => r2.status === "fulfilled")
1415
+ ).toHaveLength(1);
1416
+ const lost = shared_race.find((r2) => r2.status === "rejected");
1417
+ (0, import_vitest9.expect)(lost.reason).toBeInstanceOf(
1418
+ import_act2.ConcurrencyError
1419
+ );
1420
+ (0, import_vitest9.expect)(await count(shared)).toBe(1);
1421
+ const [p, q, r, t] = [0, 1, 2, 3].map((i) => `across-d${i}-${uid()}`);
1422
+ const disjoint = await Promise.allSettled([race(p, q), race(r, t)]);
1423
+ (0, import_vitest9.expect)(disjoint.every((d) => d.status === "fulfilled")).toBe(true);
1424
+ });
1425
+ });
1426
+ (0, import_vitest9.describe)("what a commit, guard or truncate must not get wrong", () => {
1427
+ const edge_uid = () => uid();
1428
+ const E = (data = { a: 1 }, pii) => ({
1429
+ name: "E",
1430
+ data,
1431
+ ...pii ? { pii } : {}
1432
+ });
1433
+ const edge_meta = (correlation = "m") => ({ correlation, causation: {} });
1434
+ const rows = async (query) => {
1435
+ const found = [];
1436
+ await store.query((e) => found.push(e), query);
1437
+ return found;
1438
+ };
1439
+ const one = (stream) => ({ stream, stream_exact: true });
1440
+ (0, import_vitest9.it)("names the FIRST stale stream when two are stale", async () => {
1441
+ const [a, b] = [`a-${edge_uid()}`, `b-${edge_uid()}`];
1442
+ const e = await store.commit(
1443
+ [
1444
+ { stream: a, msgs: [E()], expectedVersion: 3 },
1445
+ { stream: b, msgs: [E()], expectedVersion: 4 }
1446
+ ],
1447
+ edge_meta()
1448
+ ).catch((x) => x);
1449
+ (0, import_vitest9.expect)(e).toBeInstanceOf(import_act2.ConcurrencyError);
1450
+ (0, import_vitest9.expect)(e.stream).toBe(a);
1451
+ });
1452
+ (0, import_vitest9.it)("checks a stale expectedVersion of 0 inside a multi-stream commit", async () => {
1453
+ const [a, b] = [`a-${edge_uid()}`, `b-${edge_uid()}`];
1454
+ await store.commit(
1455
+ [{ stream: b, msgs: [E(), E()] }],
1456
+ edge_meta()
1457
+ );
1458
+ await (0, import_vitest9.expect)(
1459
+ store.commit(
1460
+ [
1461
+ { stream: a, msgs: [E()], expectedVersion: -1 },
1462
+ { stream: b, msgs: [E()], expectedVersion: 0 }
1463
+ ],
1464
+ edge_meta()
1465
+ )
1466
+ ).rejects.toBeInstanceOf(import_act2.ConcurrencyError);
1467
+ (0, import_vitest9.expect)(await rows(one(a))).toHaveLength(0);
1468
+ });
1469
+ (0, import_vitest9.it)("attaches meta to every append, not just the last", async () => {
1470
+ const ss = [0, 1, 2].map((i) => `m${i}-${edge_uid()}`);
1471
+ const c = `corr-${edge_uid()}`;
1472
+ await store.commit(
1473
+ ss.map((stream) => ({ stream, msgs: [E()] })),
1474
+ edge_meta(c)
1475
+ );
1476
+ for (const stream of ss)
1477
+ (0, import_vitest9.expect)((await rows(one(stream)))[0].meta.correlation).toBe(c);
1478
+ });
1479
+ (0, import_vitest9.it)("refuses a stream named twice when not adjacent", async () => {
1480
+ const [a, b] = [`a-${edge_uid()}`, `b-${edge_uid()}`];
1481
+ await (0, import_vitest9.expect)(
1482
+ store.commit(
1483
+ [
1484
+ { stream: a, msgs: [E()] },
1485
+ { stream: b, msgs: [E()] },
1486
+ { stream: a, msgs: [E()] }
1487
+ ],
1488
+ edge_meta()
1489
+ )
1490
+ ).rejects.toThrow("named twice");
1491
+ (0, import_vitest9.expect)(await rows(one(a))).toHaveLength(0);
1492
+ });
1493
+ (0, import_vitest9.it)("refuses a lone empty append (a version check alone)", async () => {
1494
+ const a = `a-${edge_uid()}`;
1495
+ await (0, import_vitest9.expect)(
1496
+ store.commit(
1497
+ [{ stream: a, msgs: [], expectedVersion: -1 }],
1498
+ edge_meta()
1499
+ )
1500
+ ).rejects.toThrow("no events");
1501
+ });
1502
+ (0, import_vitest9.it)("refuses an empty FIRST append", async () => {
1503
+ const [a, b] = [`a-${edge_uid()}`, `b-${edge_uid()}`];
1504
+ await (0, import_vitest9.expect)(
1505
+ store.commit(
1506
+ [
1507
+ { stream: a, msgs: [] },
1508
+ { stream: b, msgs: [E()] }
1509
+ ],
1510
+ edge_meta()
1511
+ )
1512
+ ).rejects.toThrow("no events");
1513
+ (0, import_vitest9.expect)(await rows(one(b))).toHaveLength(0);
1514
+ });
1515
+ (0, import_vitest9.it)("keeps the sensitive fields of the FIRST append", async () => {
1516
+ const [a, b] = [`a-${edge_uid()}`, `b-${edge_uid()}`];
1517
+ await store.commit(
1518
+ [
1519
+ { stream: a, msgs: [E({}, { email: "x" })] },
1520
+ { stream: b, msgs: [E()] }
1521
+ ],
1522
+ edge_meta()
1523
+ );
1524
+ (0, import_vitest9.expect)((await rows(one(a)))[0].pii).toEqual({ email: "x" });
1525
+ });
1526
+ (0, import_vitest9.it)("a guard below a trailing snapshot is stale", async () => {
1527
+ const a = `a-${edge_uid()}`;
1528
+ await store.commit([{ stream: a, msgs: [E()] }], edge_meta());
1529
+ await store.commit(
1530
+ [
1531
+ {
1532
+ stream: a,
1533
+ msgs: [{ name: import_act2.SNAP_EVENT, data: {} }],
1534
+ expectedVersion: 0
1535
+ }
1536
+ ],
1537
+ edge_meta()
1538
+ );
1539
+ await (0, import_vitest9.expect)(
1540
+ store.commit(
1541
+ [{ stream: a, msgs: [E()], expectedVersion: 0 }],
1542
+ edge_meta()
1543
+ )
1544
+ ).rejects.toBeInstanceOf(import_act2.ConcurrencyError);
1545
+ });
1546
+ (0, import_vitest9.it)("a guard below a trailing tombstone is stale (what stops a writer during a close)", async () => {
1547
+ const a = `a-${edge_uid()}`;
1548
+ await store.commit([{ stream: a, msgs: [E()] }], edge_meta());
1549
+ await store.commit(
1550
+ [
1551
+ {
1552
+ stream: a,
1553
+ msgs: [{ name: "__tombstone__", data: {} }],
1554
+ expectedVersion: 0
1555
+ }
1556
+ ],
1557
+ edge_meta()
1558
+ );
1559
+ await (0, import_vitest9.expect)(
1560
+ store.commit(
1561
+ [{ stream: a, msgs: [E()], expectedVersion: 0 }],
1562
+ edge_meta()
1563
+ )
1564
+ ).rejects.toBeInstanceOf(import_act2.ConcurrencyError);
1565
+ });
1566
+ (0, import_vitest9.it)("a commit after a full truncate continues from the seed at version 0", async () => {
1567
+ const a = `a-${edge_uid()}`;
1568
+ await store.commit(
1569
+ [{ stream: a, msgs: [E(), E(), E()] }],
1570
+ edge_meta()
1571
+ );
1572
+ await store.truncate([{ stream: a, snapshot: { n: 3 } }]);
1573
+ const [c] = await store.commit(
1574
+ [{ stream: a, msgs: [E()], expectedVersion: 0 }],
1575
+ edge_meta()
1576
+ );
1577
+ (0, import_vitest9.expect)(c.version).toBe(1);
1578
+ });
1579
+ (0, import_vitest9.it)("seeds a full truncate at version 0, carrying the meta it was given", async () => {
1580
+ const a = `a-${edge_uid()}`;
1581
+ await store.commit(
1582
+ [{ stream: a, msgs: [E(), E(), E()] }],
1583
+ edge_meta()
1584
+ );
1585
+ const c = `close-${edge_uid()}`;
1586
+ const r = await store.truncate([
1587
+ { stream: a, snapshot: { n: 3 }, meta: edge_meta(c) }
1588
+ ]);
1589
+ (0, import_vitest9.expect)(r.get(a).committed.version).toBe(0);
1590
+ const [seed] = await rows({ ...one(a), with_snaps: true });
1591
+ (0, import_vitest9.expect)(seed.version).toBe(0);
1592
+ (0, import_vitest9.expect)(seed.meta.correlation).toBe(c);
1593
+ });
1594
+ });
1239
1595
  (0, import_vitest9.describe)("commit", () => {
1240
1596
  (0, import_vitest9.it)("returns committed events with sequenced ids and versions", async () => {
1241
1597
  const s = `commit-seq-${uid()}`;
1242
1598
  const committed = await store.commit(
1243
- s,
1244
- [inc(1), inc(2), dec(3)],
1599
+ [{ stream: s, msgs: [inc(1), inc(2), dec(3)] }],
1245
1600
  make_meta({ stream: s })
1246
1601
  );
1247
1602
  (0, import_vitest9.expect)(committed).toHaveLength(3);
@@ -1258,8 +1613,7 @@ var runStoreTck = (options) => {
1258
1613
  const s = `commit-meta-${uid()}`;
1259
1614
  const correlation = `cor-${uid()}`;
1260
1615
  const committed = await store.commit(
1261
- s,
1262
- [inc(1)],
1616
+ [{ stream: s, msgs: [inc(1)] }],
1263
1617
  make_meta({ stream: s, correlation })
1264
1618
  );
1265
1619
  (0, import_vitest9.expect)(committed[0].stream).toBe(s);
@@ -1268,64 +1622,50 @@ var runStoreTck = (options) => {
1268
1622
  (0, import_vitest9.it)("throws ConcurrencyError when expectedVersion is wrong", async () => {
1269
1623
  const s = `commit-cc-${uid()}`;
1270
1624
  await store.commit(
1271
- s,
1272
- [inc(1)],
1625
+ [{ stream: s, msgs: [inc(1)] }],
1273
1626
  make_meta({ stream: s })
1274
1627
  );
1275
1628
  await store.commit(
1276
- s,
1277
- [inc(1)],
1278
- make_meta({ stream: s }),
1279
- 0
1629
+ [{ stream: s, msgs: [inc(1)], expectedVersion: 0 }],
1630
+ make_meta({ stream: s })
1280
1631
  );
1281
1632
  await (0, import_vitest9.expect)(
1282
- store.commit(s, [inc(1)], make_meta({ stream: s }), 0)
1633
+ store.commit(
1634
+ [{ stream: s, msgs: [inc(1)], expectedVersion: 0 }],
1635
+ make_meta({ stream: s })
1636
+ )
1283
1637
  ).rejects.toBeInstanceOf(import_act2.ConcurrencyError);
1284
1638
  });
1285
1639
  (0, import_vitest9.it)("treats expectedVersion -1 as an empty stream", async () => {
1286
1640
  const s = `commit-new-cc-${uid()}`;
1287
1641
  const [first] = await store.commit(
1288
- s,
1289
- [inc(1)],
1290
- make_meta({ stream: s }),
1291
- -1
1292
- );
1293
- (0, import_vitest9.expect)(first.version).toBe(0);
1294
- await (0, import_vitest9.expect)(
1295
- store.commit(s, [inc(1)], make_meta({ stream: s }), -1)
1296
- ).rejects.toBeInstanceOf(import_act2.ConcurrencyError);
1297
- });
1298
- (0, import_vitest9.it)("checks expectedVersion even when committing no events", async () => {
1299
- const s = `commit-empty-cc-${uid()}`;
1300
- await store.commit(
1301
- s,
1302
- [inc(1)],
1642
+ [{ stream: s, msgs: [inc(1)], expectedVersion: -1 }],
1303
1643
  make_meta({ stream: s })
1304
1644
  );
1645
+ (0, import_vitest9.expect)(first.version).toBe(0);
1305
1646
  await (0, import_vitest9.expect)(
1306
- store.commit(s, [], make_meta({ stream: s }), 5)
1647
+ store.commit(
1648
+ [{ stream: s, msgs: [inc(1)], expectedVersion: -1 }],
1649
+ make_meta({ stream: s })
1650
+ )
1307
1651
  ).rejects.toBeInstanceOf(import_act2.ConcurrencyError);
1308
- (0, import_vitest9.expect)(
1309
- await store.commit(s, [], make_meta({ stream: s }), 0)
1310
- ).toEqual([]);
1311
1652
  });
1312
1653
  (0, import_vitest9.it)("takes concurrent commits, reads and writes on one instance", async () => {
1313
1654
  const x = `commit-concurrent-x-${uid()}`;
1314
1655
  const y = `commit-concurrent-y-${uid()}`;
1315
1656
  const [first, second, other, read, subscribed] = await Promise.allSettled([
1316
1657
  store.commit(
1317
- x,
1318
- [inc(1)],
1319
- make_meta({ stream: x }),
1320
- -1
1658
+ [{ stream: x, msgs: [inc(1)], expectedVersion: -1 }],
1659
+ make_meta({ stream: x })
1321
1660
  ),
1322
1661
  store.commit(
1323
- x,
1324
- [inc(2)],
1325
- make_meta({ stream: x }),
1326
- -1
1662
+ [{ stream: x, msgs: [inc(2)], expectedVersion: -1 }],
1663
+ make_meta({ stream: x })
1664
+ ),
1665
+ store.commit(
1666
+ [{ stream: y, msgs: [inc(1)] }],
1667
+ make_meta({ stream: y })
1327
1668
  ),
1328
- store.commit(y, [inc(1)], make_meta({ stream: y })),
1329
1669
  store.query(() => {
1330
1670
  }, { stream: x, stream_exact: true }),
1331
1671
  // A source nothing writes, so later claims never see it.
@@ -1347,12 +1687,14 @@ var runStoreTck = (options) => {
1347
1687
  (0, import_vitest9.it)("preserves prior events when a concurrent commit is rejected", async () => {
1348
1688
  const s = `commit-cc-preserve-${uid()}`;
1349
1689
  await store.commit(
1350
- s,
1351
- [inc(1), inc(2)],
1690
+ [{ stream: s, msgs: [inc(1), inc(2)] }],
1352
1691
  make_meta({ stream: s })
1353
1692
  );
1354
1693
  await (0, import_vitest9.expect)(
1355
- store.commit(s, [inc(3)], make_meta({ stream: s }), 0)
1694
+ store.commit(
1695
+ [{ stream: s, msgs: [inc(3)], expectedVersion: 0 }],
1696
+ make_meta({ stream: s })
1697
+ )
1356
1698
  ).rejects.toBeInstanceOf(import_act2.ConcurrencyError);
1357
1699
  const found = await collect(store, { stream: s, stream_exact: true });
1358
1700
  (0, import_vitest9.expect)(found).toHaveLength(2);
@@ -1364,13 +1706,11 @@ var runStoreTck = (options) => {
1364
1706
  const s2 = `q-s2-${uid()}`;
1365
1707
  const cor = `q-cor-${uid()}`;
1366
1708
  await store.commit(
1367
- s1,
1368
- [inc(1), dec(1)],
1709
+ [{ stream: s1, msgs: [inc(1), dec(1)] }],
1369
1710
  make_meta({ stream: s1, correlation: cor })
1370
1711
  );
1371
1712
  await store.commit(
1372
- s2,
1373
- [inc(2), dec(2), reset()],
1713
+ [{ stream: s2, msgs: [inc(2), dec(2), reset()] }],
1374
1714
  make_meta({ stream: s2, correlation: cor })
1375
1715
  );
1376
1716
  const by_stream = await collect(store, {
@@ -1396,8 +1736,7 @@ var runStoreTck = (options) => {
1396
1736
  (0, import_vitest9.it)("excludes snapshots when called with no query object", async () => {
1397
1737
  const s = `q-nofilter-${uid()}`;
1398
1738
  await store.commit(
1399
- s,
1400
- [{ name: import_act2.SNAP_EVENT, data: { count: 0 } }],
1739
+ [{ stream: s, msgs: [{ name: import_act2.SNAP_EVENT, data: { count: 0 } }] }],
1401
1740
  make_meta({ stream: s })
1402
1741
  );
1403
1742
  const names = [];
@@ -1409,18 +1748,15 @@ var runStoreTck = (options) => {
1409
1748
  (0, import_vitest9.it)("with_snaps resumes from the latest snapshot per stream", async () => {
1410
1749
  const s = `q-snap-${uid()}`;
1411
1750
  await store.commit(
1412
- s,
1413
- [inc(1), inc(1)],
1751
+ [{ stream: s, msgs: [inc(1), inc(1)] }],
1414
1752
  make_meta({ stream: s })
1415
1753
  );
1416
1754
  const [snap] = await store.commit(
1417
- s,
1418
- [{ name: import_act2.SNAP_EVENT, data: { count: 2 } }],
1755
+ [{ stream: s, msgs: [{ name: import_act2.SNAP_EVENT, data: { count: 2 } }] }],
1419
1756
  make_meta({ stream: s })
1420
1757
  );
1421
1758
  await store.commit(
1422
- s,
1423
- [inc(1), inc(1), inc(1)],
1759
+ [{ stream: s, msgs: [inc(1), inc(1), inc(1)] }],
1424
1760
  make_meta({ stream: s })
1425
1761
  );
1426
1762
  const from_snap = await collect(store, {
@@ -1441,8 +1777,7 @@ var runStoreTck = (options) => {
1441
1777
  (0, import_vitest9.expect)(after_snap).toHaveLength(3);
1442
1778
  const s2 = `q-nosnap-${uid()}`;
1443
1779
  await store.commit(
1444
- s2,
1445
- [inc(1), inc(1)],
1780
+ [{ stream: s2, msgs: [inc(1), inc(1)] }],
1446
1781
  make_meta({ stream: s2 })
1447
1782
  );
1448
1783
  const full = await collect(store, {
@@ -1455,18 +1790,15 @@ var runStoreTck = (options) => {
1455
1790
  (0, import_vitest9.it)("with_snaps applies the resume floor on a backward scan too", async () => {
1456
1791
  const s = `q-snap-back-${uid()}`;
1457
1792
  await store.commit(
1458
- s,
1459
- [inc(1), inc(1)],
1793
+ [{ stream: s, msgs: [inc(1), inc(1)] }],
1460
1794
  make_meta({ stream: s })
1461
1795
  );
1462
1796
  const [snap] = await store.commit(
1463
- s,
1464
- [{ name: import_act2.SNAP_EVENT, data: { count: 2 } }],
1797
+ [{ stream: s, msgs: [{ name: import_act2.SNAP_EVENT, data: { count: 2 } }] }],
1465
1798
  make_meta({ stream: s })
1466
1799
  );
1467
1800
  await store.commit(
1468
- s,
1469
- [inc(1), inc(1), inc(1)],
1801
+ [{ stream: s, msgs: [inc(1), inc(1), inc(1)] }],
1470
1802
  make_meta({ stream: s })
1471
1803
  );
1472
1804
  const backward = await collect(store, {
@@ -1480,8 +1812,7 @@ var runStoreTck = (options) => {
1480
1812
  (0, import_vitest9.expect)(backward.every((e) => e.id >= snap.id)).toBe(true);
1481
1813
  const s2 = `q-nosnap-back-${uid()}`;
1482
1814
  await store.commit(
1483
- s2,
1484
- [inc(1), inc(1)],
1815
+ [{ stream: s2, msgs: [inc(1), inc(1)] }],
1485
1816
  make_meta({ stream: s2 })
1486
1817
  );
1487
1818
  const full = await collect(store, {
@@ -1495,8 +1826,7 @@ var runStoreTck = (options) => {
1495
1826
  (0, import_vitest9.it)("supports backward traversal", async () => {
1496
1827
  const s = `q-back-${uid()}`;
1497
1828
  const committed = await store.commit(
1498
- s,
1499
- [inc(1), inc(2), inc(3)],
1829
+ [{ stream: s, msgs: [inc(1), inc(2), inc(3)] }],
1500
1830
  make_meta({ stream: s })
1501
1831
  );
1502
1832
  const forward = await collect(store, { stream: s, stream_exact: true });
@@ -1521,8 +1851,7 @@ var runStoreTck = (options) => {
1521
1851
  (0, import_vitest9.it)("after/before bound the id range", async () => {
1522
1852
  const s = `q-bounds-${uid()}`;
1523
1853
  const committed = await store.commit(
1524
- s,
1525
- [inc(1), inc(2), inc(3), inc(4)],
1854
+ [{ stream: s, msgs: [inc(1), inc(2), inc(3), inc(4)] }],
1526
1855
  make_meta({ stream: s })
1527
1856
  );
1528
1857
  const after_first = await collect(store, {
@@ -1545,8 +1874,7 @@ var runStoreTck = (options) => {
1545
1874
  (0, import_vitest9.it)("names:[] matches no events", async () => {
1546
1875
  const s = `q-names-empty-${uid()}`;
1547
1876
  await store.commit(
1548
- s,
1549
- [inc(1), dec(1)],
1877
+ [{ stream: s, msgs: [inc(1), dec(1)] }],
1550
1878
  make_meta({ stream: s })
1551
1879
  );
1552
1880
  const none = await collect(store, {
@@ -1561,8 +1889,7 @@ var runStoreTck = (options) => {
1561
1889
  (0, import_vitest9.it)("after:0 and before:0 are honored as id bounds", async () => {
1562
1890
  const s = `q-zero-bound-${uid()}`;
1563
1891
  await store.commit(
1564
- s,
1565
- [inc(1), inc(2), inc(3)],
1892
+ [{ stream: s, msgs: [inc(1), inc(2), inc(3)] }],
1566
1893
  make_meta({ stream: s })
1567
1894
  );
1568
1895
  (0, import_vitest9.expect)(
@@ -1593,8 +1920,7 @@ var runStoreTck = (options) => {
1593
1920
  (0, import_vitest9.it)("created_after/created_before filter by timestamp", async () => {
1594
1921
  const s = `q-ts-${uid()}`;
1595
1922
  const committed = await store.commit(
1596
- s,
1597
- [inc(1)],
1923
+ [{ stream: s, msgs: [inc(1)] }],
1598
1924
  make_meta({ stream: s })
1599
1925
  );
1600
1926
  const ts = committed[0].created.getTime();
@@ -1617,8 +1943,7 @@ var runStoreTck = (options) => {
1617
1943
  (0, import_vitest9.it)("created bounds exclude the event they are pinned to", async () => {
1618
1944
  const s = `q-ts-self-${uid()}`;
1619
1945
  const committed = await store.commit(
1620
- s,
1621
- [inc(1)],
1946
+ [{ stream: s, msgs: [inc(1)] }],
1622
1947
  make_meta({ stream: s })
1623
1948
  );
1624
1949
  const own = committed[0].created;
@@ -1638,8 +1963,7 @@ var runStoreTck = (options) => {
1638
1963
  (0, import_vitest9.it)("backward traversal short-circuits at `after` id boundary", async () => {
1639
1964
  const s = `q-back-after-${uid()}`;
1640
1965
  const committed = await store.commit(
1641
- s,
1642
- [inc(1), inc(2), inc(3)],
1966
+ [{ stream: s, msgs: [inc(1), inc(2), inc(3)] }],
1643
1967
  make_meta({ stream: s })
1644
1968
  );
1645
1969
  const got = await collect(store, {
@@ -1656,8 +1980,7 @@ var runStoreTck = (options) => {
1656
1980
  (0, import_vitest9.it)("backward traversal short-circuits at `created_after` boundary", async () => {
1657
1981
  const s = `q-back-cafter-${uid()}`;
1658
1982
  await store.commit(
1659
- s,
1660
- [inc(1)],
1983
+ [{ stream: s, msgs: [inc(1)] }],
1661
1984
  make_meta({ stream: s })
1662
1985
  );
1663
1986
  const future = new Date(Date.now() + 6e4);
@@ -1672,8 +1995,7 @@ var runStoreTck = (options) => {
1672
1995
  (0, import_vitest9.it)("backward traversal honors created_before by skipping newer events", async () => {
1673
1996
  const s = `q-back-ts-${uid()}`;
1674
1997
  const committed = await store.commit(
1675
- s,
1676
- [inc(1)],
1998
+ [{ stream: s, msgs: [inc(1)] }],
1677
1999
  make_meta()
1678
2000
  );
1679
2001
  const past = new Date(committed[0].created.getTime() - 6e4);
@@ -1690,13 +2012,11 @@ var runStoreTck = (options) => {
1690
2012
  const a = `q-exact-${tag}`;
1691
2013
  const b = `q-exact-${tag}-extra`;
1692
2014
  await store.commit(
1693
- a,
1694
- [inc(1)],
2015
+ [{ stream: a, msgs: [inc(1)] }],
1695
2016
  make_meta({ stream: a })
1696
2017
  );
1697
2018
  await store.commit(
1698
- b,
1699
- [inc(2)],
2019
+ [{ stream: b, msgs: [inc(2)] }],
1700
2020
  make_meta({ stream: b })
1701
2021
  );
1702
2022
  const exact = await collect(store, { stream: a, stream_exact: true });
@@ -1708,13 +2028,11 @@ var runStoreTck = (options) => {
1708
2028
  const inner = `qr-${tag}-inner`;
1709
2029
  const longer = `qr-${tag}-inner-extra`;
1710
2030
  await store.commit(
1711
- inner,
1712
- [inc(1)],
2031
+ [{ stream: inner, msgs: [inc(1)] }],
1713
2032
  make_meta({ stream: inner })
1714
2033
  );
1715
2034
  await store.commit(
1716
- longer,
1717
- [inc(2)],
2035
+ [{ stream: longer, msgs: [inc(2)] }],
1718
2036
  make_meta({ stream: longer })
1719
2037
  );
1720
2038
  const got = await collect(store, { stream: `qr-${tag}-inner` });
@@ -1725,13 +2043,11 @@ var runStoreTck = (options) => {
1725
2043
  const inner = `qr-${tag}-anchor`;
1726
2044
  const longer = `qr-${tag}-anchor-extra`;
1727
2045
  await store.commit(
1728
- inner,
1729
- [inc(1)],
2046
+ [{ stream: inner, msgs: [inc(1)] }],
1730
2047
  make_meta({ stream: inner })
1731
2048
  );
1732
2049
  await store.commit(
1733
- longer,
1734
- [inc(2)],
2050
+ [{ stream: longer, msgs: [inc(2)] }],
1735
2051
  make_meta({ stream: longer })
1736
2052
  );
1737
2053
  const got = await collect(store, { stream: `^qr-${tag}-anchor$` });
@@ -1744,18 +2060,15 @@ var runStoreTck = (options) => {
1744
2060
  const b = `qr-${tag}-pfx-b`;
1745
2061
  const other = `zz-${tag}-other`;
1746
2062
  await store.commit(
1747
- a,
1748
- [inc(1)],
2063
+ [{ stream: a, msgs: [inc(1)] }],
1749
2064
  make_meta({ stream: a })
1750
2065
  );
1751
2066
  await store.commit(
1752
- b,
1753
- [inc(2)],
2067
+ [{ stream: b, msgs: [inc(2)] }],
1754
2068
  make_meta({ stream: b })
1755
2069
  );
1756
2070
  await store.commit(
1757
- other,
1758
- [inc(3)],
2071
+ [{ stream: other, msgs: [inc(3)] }],
1759
2072
  make_meta({ stream: other })
1760
2073
  );
1761
2074
  const got = await collect(store, { stream: `^qr-${tag}-pfx-` });
@@ -1766,8 +2079,7 @@ var runStoreTck = (options) => {
1766
2079
  const seed_streams = async (streams) => {
1767
2080
  for (const s of streams)
1768
2081
  await store.commit(
1769
- s,
1770
- [inc(1)],
2082
+ [{ stream: s, msgs: [inc(1)] }],
1771
2083
  make_meta({ stream: s })
1772
2084
  );
1773
2085
  };
@@ -1946,8 +2258,7 @@ var runStoreTck = (options) => {
1946
2258
  const src = `fresh-first-src-${uid()}`;
1947
2259
  await store.subscribe([{ stream: s, source: src }]);
1948
2260
  const [first] = await store.commit(
1949
- src,
1950
- [inc(1)],
2261
+ [{ stream: src, msgs: [inc(1)] }],
1951
2262
  make_meta({ stream: src })
1952
2263
  );
1953
2264
  await store.subscribe([{ stream: s, correlated_at: first.id }]);
@@ -2136,8 +2447,7 @@ var runStoreTck = (options) => {
2136
2447
  const src = `ws-unmarked-src-${uid()}`;
2137
2448
  await store.subscribe([{ stream: s, source: src }]);
2138
2449
  const [event] = await store.commit(
2139
- src,
2140
- [inc(1)],
2450
+ [{ stream: src, msgs: [inc(1)] }],
2141
2451
  make_meta({ stream: src })
2142
2452
  );
2143
2453
  (0, import_vitest9.expect)(await claimable(s)).toBe(false);
@@ -2169,8 +2479,7 @@ var runStoreTck = (options) => {
2169
2479
  const s = `claim-${uid()}`;
2170
2480
  await store.subscribe([{ stream: s }]);
2171
2481
  await store.commit(
2172
- s,
2173
- [inc(1)],
2482
+ [{ stream: s, msgs: [inc(1)] }],
2174
2483
  make_meta({ stream: s })
2175
2484
  );
2176
2485
  const by = `worker-${uid()}`;
@@ -2193,8 +2502,7 @@ var runStoreTck = (options) => {
2193
2502
  const other = `claim-other-${uid()}`;
2194
2503
  await store.subscribe([{ stream: s }]);
2195
2504
  await store.commit(
2196
- s,
2197
- [inc(1)],
2505
+ [{ stream: s, msgs: [inc(1)] }],
2198
2506
  make_meta({ stream: s })
2199
2507
  );
2200
2508
  await correlate();
@@ -2203,8 +2511,7 @@ var runStoreTck = (options) => {
2203
2511
  (0, import_vitest9.expect)(targetA).toBeDefined();
2204
2512
  await store.subscribe([{ stream: other }]);
2205
2513
  await store.commit(
2206
- other,
2207
- [inc(2)],
2514
+ [{ stream: other, msgs: [inc(2)] }],
2208
2515
  make_meta({ stream: other })
2209
2516
  );
2210
2517
  await correlate();
@@ -2217,8 +2524,7 @@ var runStoreTck = (options) => {
2217
2524
  const s = `claim-stolen-${uid()}`;
2218
2525
  await store.subscribe([{ stream: s }]);
2219
2526
  await store.commit(
2220
- s,
2221
- [inc(1), inc(2)],
2527
+ [{ stream: s, msgs: [inc(1), inc(2)] }],
2222
2528
  make_meta({ stream: s })
2223
2529
  );
2224
2530
  await correlate();
@@ -2244,8 +2550,7 @@ var runStoreTck = (options) => {
2244
2550
  const s = `claim-dual-${uid()}`;
2245
2551
  await store.subscribe([{ stream: s }]);
2246
2552
  await store.commit(
2247
- s,
2248
- [inc(1), inc(2)],
2553
+ [{ stream: s, msgs: [inc(1), inc(2)] }],
2249
2554
  make_meta({ stream: s })
2250
2555
  );
2251
2556
  await correlate();
@@ -2274,13 +2579,11 @@ var runStoreTck = (options) => {
2274
2579
  ]);
2275
2580
  for (const stream of highs)
2276
2581
  await fresh.commit(
2277
- stream,
2278
- [inc(1)],
2582
+ [{ stream, msgs: [inc(1)] }],
2279
2583
  make_meta({ stream })
2280
2584
  );
2281
2585
  await fresh.commit(
2282
- low,
2283
- [inc(1)],
2586
+ [{ stream: low, msgs: [inc(1)] }],
2284
2587
  make_meta({ stream: low })
2285
2588
  );
2286
2589
  const by = `w-${uid()}`;
@@ -2296,8 +2599,7 @@ var runStoreTck = (options) => {
2296
2599
  for (const l of leases) {
2297
2600
  await fresh.ack([{ ...l, at: l.at + 1 }]);
2298
2601
  await fresh.commit(
2299
- l.stream,
2300
- [inc(1)],
2602
+ [{ stream: l.stream, msgs: [inc(1)] }],
2301
2603
  make_meta({ stream: l.stream })
2302
2604
  );
2303
2605
  }
@@ -2311,8 +2613,7 @@ var runStoreTck = (options) => {
2311
2613
  const s = `claim-dedup-${uid()}`;
2312
2614
  await store.subscribe([{ stream: s }]);
2313
2615
  await store.commit(
2314
- s,
2315
- [inc(1)],
2616
+ [{ stream: s, msgs: [inc(1)] }],
2316
2617
  make_meta({ stream: s })
2317
2618
  );
2318
2619
  await correlate();
@@ -2325,13 +2626,11 @@ var runStoreTck = (options) => {
2325
2626
  const sibling = `ack-sibling-${uid()}`;
2326
2627
  await store.subscribe([{ stream: s }, { stream: sibling }]);
2327
2628
  await store.commit(
2328
- s,
2329
- [inc(1)],
2629
+ [{ stream: s, msgs: [inc(1)] }],
2330
2630
  make_meta({ stream: s })
2331
2631
  );
2332
2632
  await store.commit(
2333
- sibling,
2334
- [inc(2)],
2633
+ [{ stream: sibling, msgs: [inc(2)] }],
2335
2634
  make_meta({ stream: sibling })
2336
2635
  );
2337
2636
  await correlate();
@@ -2381,8 +2680,7 @@ var runStoreTck = (options) => {
2381
2680
  const s = `lease-retry-${uid()}`;
2382
2681
  await fresh.subscribe([{ stream: s }]);
2383
2682
  await fresh.commit(
2384
- s,
2385
- [inc(1)],
2683
+ [{ stream: s, msgs: [inc(1)] }],
2386
2684
  make_meta({ stream: s })
2387
2685
  );
2388
2686
  await correlate(fresh);
@@ -2407,8 +2705,7 @@ var runStoreTck = (options) => {
2407
2705
  const s = `lease-zero-${uid()}`;
2408
2706
  await fresh.subscribe([{ stream: s }]);
2409
2707
  const [committed] = await fresh.commit(
2410
- s,
2411
- [inc(1)],
2708
+ [{ stream: s, msgs: [inc(1)] }],
2412
2709
  make_meta({ stream: s })
2413
2710
  );
2414
2711
  await correlate(fresh);
@@ -2437,8 +2734,7 @@ var runStoreTck = (options) => {
2437
2734
  const s = `lease-lag-${uid()}`;
2438
2735
  await fresh.subscribe([{ stream: s }]);
2439
2736
  await fresh.commit(
2440
- s,
2441
- [inc(1)],
2737
+ [{ stream: s, msgs: [inc(1)] }],
2442
2738
  make_meta({ stream: s })
2443
2739
  );
2444
2740
  await correlate(fresh);
@@ -2567,8 +2863,7 @@ var runStoreTck = (options) => {
2567
2863
  await fresh.subscribe(streams.map((stream) => ({ stream })));
2568
2864
  for (const stream of streams) {
2569
2865
  await fresh.commit(
2570
- stream,
2571
- [inc(1)],
2866
+ [{ stream, msgs: [inc(1)] }],
2572
2867
  make_meta({ stream })
2573
2868
  );
2574
2869
  }
@@ -2640,8 +2935,7 @@ var runStoreTck = (options) => {
2640
2935
  const s = `block-${uid()}`;
2641
2936
  await store.subscribe([{ stream: s }]);
2642
2937
  await store.commit(
2643
- s,
2644
- [inc(1)],
2938
+ [{ stream: s, msgs: [inc(1)] }],
2645
2939
  make_meta({ stream: s })
2646
2940
  );
2647
2941
  await correlate();
@@ -2663,8 +2957,7 @@ var runStoreTck = (options) => {
2663
2957
  const s = `block-returns-${uid()}`;
2664
2958
  await store.subscribe([{ stream: s }]);
2665
2959
  await store.commit(
2666
- s,
2667
- [inc(1)],
2960
+ [{ stream: s, msgs: [inc(1)] }],
2668
2961
  make_meta({ stream: s })
2669
2962
  );
2670
2963
  await correlate();
@@ -2689,8 +2982,7 @@ var runStoreTck = (options) => {
2689
2982
  const s = `block-wrong-${uid()}`;
2690
2983
  await store.subscribe([{ stream: s }]);
2691
2984
  await store.commit(
2692
- s,
2693
- [inc(1)],
2985
+ [{ stream: s, msgs: [inc(1)] }],
2694
2986
  make_meta({ stream: s })
2695
2987
  );
2696
2988
  await correlate();
@@ -2708,8 +3000,7 @@ var runStoreTck = (options) => {
2708
3000
  const s = `block-twice-${uid()}`;
2709
3001
  await store.subscribe([{ stream: s }]);
2710
3002
  await store.commit(
2711
- s,
2712
- [inc(1)],
3003
+ [{ stream: s, msgs: [inc(1)] }],
2713
3004
  make_meta({ stream: s })
2714
3005
  );
2715
3006
  await correlate();
@@ -2734,8 +3025,7 @@ var runStoreTck = (options) => {
2734
3025
  await store.subscribe([{ stream: s }, { stream: ctl }]);
2735
3026
  for (const st of [s, ctl])
2736
3027
  await store.commit(
2737
- st,
2738
- [inc(1)],
3028
+ [{ stream: st, msgs: [inc(1)] }],
2739
3029
  make_meta({ stream: st })
2740
3030
  );
2741
3031
  (0, import_vitest9.expect)(await store.defer([s], Date.now() + 36e5)).toBe(1);
@@ -2748,8 +3038,7 @@ var runStoreTck = (options) => {
2748
3038
  const s = `defer-clock-${uid()}`;
2749
3039
  await store.subscribe([{ stream: s }]);
2750
3040
  await store.commit(
2751
- s,
2752
- [inc(1)],
3041
+ [{ stream: s, msgs: [inc(1)] }],
2753
3042
  make_meta({ stream: s })
2754
3043
  );
2755
3044
  (0, import_vitest9.expect)(await store.defer([s], Date.now() + 6e4)).toBe(1);
@@ -2772,8 +3061,7 @@ var runStoreTck = (options) => {
2772
3061
  const s = `defer-past-${uid()}`;
2773
3062
  await store.subscribe([{ stream: s }]);
2774
3063
  await store.commit(
2775
- s,
2776
- [inc(1)],
3064
+ [{ stream: s, msgs: [inc(1)] }],
2777
3065
  make_meta({ stream: s })
2778
3066
  );
2779
3067
  (0, import_vitest9.expect)(await store.defer([s], Date.now() - 1e3)).toBe(1);
@@ -2789,8 +3077,7 @@ var runStoreTck = (options) => {
2789
3077
  const s = `defer-retry-${uid()}`;
2790
3078
  await store.subscribe([{ stream: s }]);
2791
3079
  await store.commit(
2792
- s,
2793
- [inc(1)],
3080
+ [{ stream: s, msgs: [inc(1)] }],
2794
3081
  make_meta({ stream: s })
2795
3082
  );
2796
3083
  await store.defer([s], Date.now() + 36e5);
@@ -2812,8 +3099,7 @@ var runStoreTck = (options) => {
2812
3099
  const s = `defer-reset-${uid()}`;
2813
3100
  await store.subscribe([{ stream: s }]);
2814
3101
  await store.commit(
2815
- s,
2816
- [inc(1)],
3102
+ [{ stream: s, msgs: [inc(1)] }],
2817
3103
  make_meta({ stream: s })
2818
3104
  );
2819
3105
  await store.defer([s], Date.now() + 36e5);
@@ -2828,8 +3114,7 @@ var runStoreTck = (options) => {
2828
3114
  await store.subscribe([{ stream: deferred }, { stream: plain }]);
2829
3115
  for (const s of [deferred, plain])
2830
3116
  await store.commit(
2831
- s,
2832
- [inc(1)],
3117
+ [{ stream: s, msgs: [inc(1)] }],
2833
3118
  make_meta({ stream: s })
2834
3119
  );
2835
3120
  const due = Date.now() + 36e5;
@@ -2851,15 +3136,13 @@ var runStoreTck = (options) => {
2851
3136
  await store.subscribe([{ stream: a }, { stream: b }]);
2852
3137
  for (const s of [a, b])
2853
3138
  await store.commit(
2854
- s,
2855
- [inc(1)],
3139
+ [{ stream: s, msgs: [inc(1)] }],
2856
3140
  make_meta({ stream: s })
2857
3141
  );
2858
3142
  const ctl = `defer-filterctl-${tag}`;
2859
3143
  await store.subscribe([{ stream: ctl }]);
2860
3144
  await store.commit(
2861
- ctl,
2862
- [inc(1)],
3145
+ [{ stream: ctl, msgs: [inc(1)] }],
2863
3146
  make_meta({ stream: ctl })
2864
3147
  );
2865
3148
  const n = await store.defer(
@@ -2881,8 +3164,7 @@ var runStoreTck = (options) => {
2881
3164
  const s = `defer-dup-${uid()}`;
2882
3165
  await store.subscribe([{ stream: s }]);
2883
3166
  await store.commit(
2884
- s,
2885
- [inc(1)],
3167
+ [{ stream: s, msgs: [inc(1)] }],
2886
3168
  make_meta({ stream: s })
2887
3169
  );
2888
3170
  (0, import_vitest9.expect)(await store.defer([s, s], Date.now() + 36e5)).toBe(1);
@@ -2894,13 +3176,11 @@ var runStoreTck = (options) => {
2894
3176
  const ctl = `ackdefer-ctl-${uid()}`;
2895
3177
  await store.subscribe([{ stream: s }, { stream: ctl }]);
2896
3178
  await store.commit(
2897
- s,
2898
- [inc(1)],
3179
+ [{ stream: s, msgs: [inc(1)] }],
2899
3180
  make_meta({ stream: s })
2900
3181
  );
2901
3182
  const [ctl_head] = await store.commit(
2902
- ctl,
2903
- [inc(1)],
3183
+ [{ stream: ctl, msgs: [inc(1)] }],
2904
3184
  make_meta({ stream: ctl })
2905
3185
  );
2906
3186
  await correlate();
@@ -2914,8 +3194,7 @@ var runStoreTck = (options) => {
2914
3194
  (0, import_vitest9.expect)(acked.find((l) => l.stream === ctl)).toBeDefined();
2915
3195
  (0, import_vitest9.expect)(acked.find((l) => l.stream === s)).toBeUndefined();
2916
3196
  await store.commit(
2917
- ctl,
2918
- [inc(2)],
3197
+ [{ stream: ctl, msgs: [inc(2)] }],
2919
3198
  make_meta({ stream: ctl })
2920
3199
  );
2921
3200
  await correlate();
@@ -2927,8 +3206,7 @@ var runStoreTck = (options) => {
2927
3206
  const s = `ackdefer-past-${uid()}`;
2928
3207
  await store.subscribe([{ stream: s }]);
2929
3208
  await store.commit(
2930
- s,
2931
- [inc(1)],
3209
+ [{ stream: s, msgs: [inc(1)] }],
2932
3210
  make_meta({ stream: s })
2933
3211
  );
2934
3212
  await correlate();
@@ -2947,8 +3225,7 @@ var runStoreTck = (options) => {
2947
3225
  const s = `ackdefer-retry-${uid()}`;
2948
3226
  await store.subscribe([{ stream: s }]);
2949
3227
  await store.commit(
2950
- s,
2951
- [inc(1)],
3228
+ [{ stream: s, msgs: [inc(1)] }],
2952
3229
  make_meta({ stream: s })
2953
3230
  );
2954
3231
  await correlate();
@@ -2967,13 +3244,11 @@ var runStoreTck = (options) => {
2967
3244
  const s = `ackadvance-${uid()}`;
2968
3245
  await store.subscribe([{ stream: s }]);
2969
3246
  const [e1] = await store.commit(
2970
- s,
2971
- [inc(1)],
3247
+ [{ stream: s, msgs: [inc(1)] }],
2972
3248
  make_meta({ stream: s })
2973
3249
  );
2974
3250
  await store.commit(
2975
- s,
2976
- [inc(1)],
3251
+ [{ stream: s, msgs: [inc(1)] }],
2977
3252
  make_meta({ stream: s })
2978
3253
  );
2979
3254
  await correlate();
@@ -2995,8 +3270,7 @@ var runStoreTck = (options) => {
2995
3270
  const s = `ackdefer-owner-${uid()}`;
2996
3271
  await store.subscribe([{ stream: s }]);
2997
3272
  await store.commit(
2998
- s,
2999
- [inc(1)],
3273
+ [{ stream: s, msgs: [inc(1)] }],
3000
3274
  make_meta({ stream: s })
3001
3275
  );
3002
3276
  await correlate();
@@ -3014,8 +3288,7 @@ var runStoreTck = (options) => {
3014
3288
  const s = `reset-${uid()}`;
3015
3289
  await store.subscribe([{ stream: s }]);
3016
3290
  await store.commit(
3017
- s,
3018
- [inc(1)],
3291
+ [{ stream: s, msgs: [inc(1)] }],
3019
3292
  make_meta({ stream: s })
3020
3293
  );
3021
3294
  await correlate();
@@ -3034,8 +3307,7 @@ var runStoreTck = (options) => {
3034
3307
  const s = `reset-blk-${uid()}`;
3035
3308
  await store.subscribe([{ stream: s }]);
3036
3309
  await store.commit(
3037
- s,
3038
- [inc(1)],
3310
+ [{ stream: s, msgs: [inc(1)] }],
3039
3311
  make_meta({ stream: s })
3040
3312
  );
3041
3313
  await correlate();
@@ -3057,8 +3329,7 @@ var runStoreTck = (options) => {
3057
3329
  const s = `reset-dup-${uid()}`;
3058
3330
  await store.subscribe([{ stream: s }]);
3059
3331
  await store.commit(
3060
- s,
3061
- [inc(1)],
3332
+ [{ stream: s, msgs: [inc(1)] }],
3062
3333
  make_meta({ stream: s })
3063
3334
  );
3064
3335
  (0, import_vitest9.expect)(await store.reset([s, s])).toBe(1);
@@ -3069,13 +3340,11 @@ var runStoreTck = (options) => {
3069
3340
  const s = `unblock-${uid()}`;
3070
3341
  await store.subscribe([{ stream: s }]);
3071
3342
  await store.commit(
3072
- s,
3073
- [inc(1)],
3343
+ [{ stream: s, msgs: [inc(1)] }],
3074
3344
  make_meta({ stream: s })
3075
3345
  );
3076
3346
  await store.commit(
3077
- s,
3078
- [inc(2)],
3347
+ [{ stream: s, msgs: [inc(2)] }],
3079
3348
  make_meta({ stream: s })
3080
3349
  );
3081
3350
  await correlate();
@@ -3108,8 +3377,7 @@ var runStoreTck = (options) => {
3108
3377
  const s = `unblock-noop-${uid()}`;
3109
3378
  await store.subscribe([{ stream: s }]);
3110
3379
  await store.commit(
3111
- s,
3112
- [inc(1)],
3380
+ [{ stream: s, msgs: [inc(1)] }],
3113
3381
  make_meta({ stream: s })
3114
3382
  );
3115
3383
  (0, import_vitest9.expect)(await store.unblock([s])).toBe(0);
@@ -3123,13 +3391,11 @@ var runStoreTck = (options) => {
3123
3391
  const s2 = `unblock-mix-b-${uid()}`;
3124
3392
  await store.subscribe([{ stream: s1 }, { stream: s2 }]);
3125
3393
  await store.commit(
3126
- s1,
3127
- [inc(1)],
3394
+ [{ stream: s1, msgs: [inc(1)] }],
3128
3395
  make_meta({ stream: s1 })
3129
3396
  );
3130
3397
  await store.commit(
3131
- s2,
3132
- [inc(1)],
3398
+ [{ stream: s2, msgs: [inc(1)] }],
3133
3399
  make_meta({ stream: s2 })
3134
3400
  );
3135
3401
  await correlate();
@@ -3147,18 +3413,15 @@ var runStoreTck = (options) => {
3147
3413
  const s3 = `other-${tag}`;
3148
3414
  await store.subscribe([{ stream: s1 }, { stream: s2 }, { stream: s3 }]);
3149
3415
  await store.commit(
3150
- s1,
3151
- [inc(1)],
3416
+ [{ stream: s1, msgs: [inc(1)] }],
3152
3417
  make_meta({ stream: s1 })
3153
3418
  );
3154
3419
  await store.commit(
3155
- s2,
3156
- [inc(1)],
3420
+ [{ stream: s2, msgs: [inc(1)] }],
3157
3421
  make_meta({ stream: s2 })
3158
3422
  );
3159
3423
  await store.commit(
3160
- s3,
3161
- [inc(1)],
3424
+ [{ stream: s3, msgs: [inc(1)] }],
3162
3425
  make_meta({ stream: s3 })
3163
3426
  );
3164
3427
  await correlate();
@@ -3186,13 +3449,11 @@ var runStoreTck = (options) => {
3186
3449
  const s2 = `unblock-empty-${tag}-b`;
3187
3450
  await store.subscribe([{ stream: s1 }, { stream: s2 }]);
3188
3451
  await store.commit(
3189
- s1,
3190
- [inc(1)],
3452
+ [{ stream: s1, msgs: [inc(1)] }],
3191
3453
  make_meta({ stream: s1 })
3192
3454
  );
3193
3455
  await store.commit(
3194
- s2,
3195
- [inc(1)],
3456
+ [{ stream: s2, msgs: [inc(1)] }],
3196
3457
  make_meta({ stream: s2 })
3197
3458
  );
3198
3459
  await correlate();
@@ -3212,8 +3473,7 @@ var runStoreTck = (options) => {
3212
3473
  const s = `unblock-blocked-false-${tag}`;
3213
3474
  await store.subscribe([{ stream: s }]);
3214
3475
  await store.commit(
3215
- s,
3216
- [inc(1)],
3476
+ [{ stream: s, msgs: [inc(1)] }],
3217
3477
  make_meta({ stream: s })
3218
3478
  );
3219
3479
  (0, import_vitest9.expect)(
@@ -3236,18 +3496,15 @@ var runStoreTck = (options) => {
3236
3496
  { stream: other }
3237
3497
  ]);
3238
3498
  await store.commit(
3239
- s1,
3240
- [inc(1)],
3499
+ [{ stream: s1, msgs: [inc(1)] }],
3241
3500
  make_meta({ stream: s1 })
3242
3501
  );
3243
3502
  await store.commit(
3244
- s2,
3245
- [inc(1)],
3503
+ [{ stream: s2, msgs: [inc(1)] }],
3246
3504
  make_meta({ stream: s2 })
3247
3505
  );
3248
3506
  await store.commit(
3249
- other,
3250
- [inc(1)],
3507
+ [{ stream: other, msgs: [inc(1)] }],
3251
3508
  make_meta({ stream: other })
3252
3509
  );
3253
3510
  await correlate();
@@ -3278,13 +3535,11 @@ var runStoreTck = (options) => {
3278
3535
  const s2 = `reset-blocked-${tag}-fine`;
3279
3536
  await store.subscribe([{ stream: s1 }, { stream: s2 }]);
3280
3537
  await store.commit(
3281
- s1,
3282
- [inc(1)],
3538
+ [{ stream: s1, msgs: [inc(1)] }],
3283
3539
  make_meta({ stream: s1 })
3284
3540
  );
3285
3541
  await store.commit(
3286
- s2,
3287
- [inc(1)],
3542
+ [{ stream: s2, msgs: [inc(1)] }],
3288
3543
  make_meta({ stream: s2 })
3289
3544
  );
3290
3545
  await correlate();
@@ -3363,8 +3618,7 @@ var runStoreTck = (options) => {
3363
3618
  const ok = `pri-${tag}-ok`;
3364
3619
  const bad = `pri-${tag}-bad`;
3365
3620
  await fresh.commit(
3366
- src,
3367
- [inc(1)],
3621
+ [{ stream: src, msgs: [inc(1)] }],
3368
3622
  make_meta({ stream: src })
3369
3623
  );
3370
3624
  await fresh.subscribe([
@@ -3410,8 +3664,7 @@ var runStoreTck = (options) => {
3410
3664
  const tag = uid();
3411
3665
  const src = `pri-src-${tag}`;
3412
3666
  await fresh.commit(
3413
- src,
3414
- [inc(1), inc(2)],
3667
+ [{ stream: src, msgs: [inc(1), inc(2)] }],
3415
3668
  make_meta({ stream: src })
3416
3669
  );
3417
3670
  await fresh.subscribe([
@@ -3509,13 +3762,11 @@ var runStoreTck = (options) => {
3509
3762
  const sub_default = `lane-claim-def-${tag}`;
3510
3763
  const sub_slow = `lane-claim-slow-${tag}`;
3511
3764
  await store.commit(
3512
- src1,
3513
- [inc(1)],
3765
+ [{ stream: src1, msgs: [inc(1)] }],
3514
3766
  make_meta({ stream: src1 })
3515
3767
  );
3516
3768
  await store.commit(
3517
- src2,
3518
- [inc(1)],
3769
+ [{ stream: src2, msgs: [inc(1)] }],
3519
3770
  make_meta({ stream: src2 })
3520
3771
  );
3521
3772
  await store.subscribe([
@@ -3582,8 +3833,7 @@ var runStoreTck = (options) => {
3582
3833
  const a = `lane-reset-a-${tag}`;
3583
3834
  const b = `lane-reset-b-${tag}`;
3584
3835
  await store.commit(
3585
- src,
3586
- [inc(1)],
3836
+ [{ stream: src, msgs: [inc(1)] }],
3587
3837
  make_meta({ stream: src })
3588
3838
  );
3589
3839
  await store.subscribe([
@@ -3612,8 +3862,7 @@ var runStoreTck = (options) => {
3612
3862
  const a = `lane-ub-a-${tag}`;
3613
3863
  const b = `lane-ub-b-${tag}`;
3614
3864
  await store.commit(
3615
- src,
3616
- [inc(1)],
3865
+ [{ stream: src, msgs: [inc(1)] }],
3617
3866
  make_meta({ stream: src })
3618
3867
  );
3619
3868
  await store.subscribe([
@@ -3642,8 +3891,7 @@ var runStoreTck = (options) => {
3642
3891
  const tag = uid();
3643
3892
  const long = `${tag}-${"x".repeat(140)}`;
3644
3893
  await store.commit(
3645
- long,
3646
- [inc(1)],
3894
+ [{ stream: long, msgs: [inc(1)] }],
3647
3895
  make_meta({ stream: long })
3648
3896
  );
3649
3897
  await store.subscribe([
@@ -3668,8 +3916,7 @@ var runStoreTck = (options) => {
3668
3916
  for (const s of [restarted, retired]) {
3669
3917
  await store.subscribe([{ stream: s }]);
3670
3918
  await store.commit(
3671
- s,
3672
- [inc(1)],
3919
+ [{ stream: s, msgs: [inc(1)] }],
3673
3920
  make_meta({ stream: s })
3674
3921
  );
3675
3922
  }
@@ -3693,8 +3940,7 @@ var runStoreTck = (options) => {
3693
3940
  const lane = `inert-lane-${uid()}`;
3694
3941
  const s = `trunc-inert-${uid()}`;
3695
3942
  const [e] = await store.commit(
3696
- s,
3697
- [inc(1)],
3943
+ [{ stream: s, msgs: [inc(1)] }],
3698
3944
  make_meta({ stream: s })
3699
3945
  );
3700
3946
  await store.subscribe([{ stream: s, correlated_at: e.id, lane }]);
@@ -3709,8 +3955,7 @@ var runStoreTck = (options) => {
3709
3955
  (0, import_vitest9.it)("seeds a tombstone when no snapshot is provided", async () => {
3710
3956
  const s = `trunc-tomb-${uid()}`;
3711
3957
  await store.commit(
3712
- s,
3713
- [inc(1), inc(2)],
3958
+ [{ stream: s, msgs: [inc(1), inc(2)] }],
3714
3959
  make_meta({ stream: s })
3715
3960
  );
3716
3961
  const result = await store.truncate([{ stream: s }]);
@@ -3730,8 +3975,7 @@ var runStoreTck = (options) => {
3730
3975
  (0, import_vitest9.it)("seeds a snapshot when one is provided", async () => {
3731
3976
  const s = `trunc-snap-${uid()}`;
3732
3977
  await store.commit(
3733
- s,
3734
- [inc(1)],
3978
+ [{ stream: s, msgs: [inc(1)] }],
3735
3979
  make_meta({ stream: s })
3736
3980
  );
3737
3981
  const result = await store.truncate([
@@ -3754,8 +3998,7 @@ var runStoreTck = (options) => {
3754
3998
  (0, import_vitest9.it)("leaves exactly one seed when a stream is listed twice", async () => {
3755
3999
  const s = `trunc-dup-${uid()}`;
3756
4000
  await store.commit(
3757
- s,
3758
- [inc(1), inc(2)],
4001
+ [{ stream: s, msgs: [inc(1), inc(2)] }],
3759
4002
  make_meta({ stream: s })
3760
4003
  );
3761
4004
  const result = await store.truncate([
@@ -3776,13 +4019,11 @@ var runStoreTck = (options) => {
3776
4019
  (0, import_vitest9.it)("applies windowed targets before full ones", async () => {
3777
4020
  const s = `trunc-mix-${uid()}`;
3778
4021
  await store.commit(
3779
- s,
3780
- [inc(1)],
4022
+ [{ stream: s, msgs: [inc(1)] }],
3781
4023
  make_meta({ stream: s })
3782
4024
  );
3783
4025
  await store.commit(
3784
- s,
3785
- [inc(2)],
4026
+ [{ stream: s, msgs: [inc(2)] }],
3786
4027
  make_meta({ stream: s })
3787
4028
  );
3788
4029
  await (0, import_act2.sleep)(5);
@@ -3819,28 +4060,23 @@ var runStoreTck = (options) => {
3819
4060
  (0, import_vitest9.describe)("windowed (before boundary)", () => {
3820
4061
  async function seed_windowed(s) {
3821
4062
  await store.commit(
3822
- s,
3823
- [inc(1), inc(1)],
4063
+ [{ stream: s, msgs: [inc(1), inc(1)] }],
3824
4064
  make_meta({ stream: s })
3825
4065
  );
3826
4066
  const [snap_a] = await store.commit(
3827
- s,
3828
- [{ name: import_act2.SNAP_EVENT, data: { count: 2 } }],
4067
+ [{ stream: s, msgs: [{ name: import_act2.SNAP_EVENT, data: { count: 2 } }] }],
3829
4068
  make_meta({ stream: s })
3830
4069
  );
3831
4070
  await store.commit(
3832
- s,
3833
- [inc(1)],
4071
+ [{ stream: s, msgs: [inc(1)] }],
3834
4072
  make_meta({ stream: s })
3835
4073
  );
3836
4074
  const [snap_b] = await store.commit(
3837
- s,
3838
- [{ name: import_act2.SNAP_EVENT, data: { count: 3 } }],
4075
+ [{ stream: s, msgs: [{ name: import_act2.SNAP_EVENT, data: { count: 3 } }] }],
3839
4076
  make_meta({ stream: s })
3840
4077
  );
3841
4078
  await store.commit(
3842
- s,
3843
- [inc(1)],
4079
+ [{ stream: s, msgs: [inc(1)] }],
3844
4080
  make_meta({ stream: s })
3845
4081
  );
3846
4082
  return { snap_a, snap_b };
@@ -3910,8 +4146,7 @@ var runStoreTck = (options) => {
3910
4146
  (0, import_vitest9.it)("no-ops when no snapshot qualifies \u2014 stream absent from the result, events untouched", async () => {
3911
4147
  const s = `trunc-win-noop-${uid()}`;
3912
4148
  await store.commit(
3913
- s,
3914
- [inc(1), inc(1)],
4149
+ [{ stream: s, msgs: [inc(1), inc(1)] }],
3915
4150
  make_meta({ stream: s })
3916
4151
  );
3917
4152
  const none = await store.truncate([
@@ -3919,8 +4154,7 @@ var runStoreTck = (options) => {
3919
4154
  ]);
3920
4155
  (0, import_vitest9.expect)(none.has(s)).toBe(false);
3921
4156
  await store.commit(
3922
- s,
3923
- [{ name: import_act2.SNAP_EVENT, data: { count: 2 } }],
4157
+ [{ stream: s, msgs: [{ name: import_act2.SNAP_EVENT, data: { count: 2 } }] }],
3924
4158
  make_meta({ stream: s })
3925
4159
  );
3926
4160
  const too_early = await store.truncate([
@@ -3958,8 +4192,7 @@ var runStoreTck = (options) => {
3958
4192
  const f = `trunc-win-mix-f-${uid()}`;
3959
4193
  const { snap_b } = await seed_windowed(w);
3960
4194
  await store.commit(
3961
- f,
3962
- [inc(1)],
4195
+ [{ stream: f, msgs: [inc(1)] }],
3963
4196
  make_meta({ stream: f })
3964
4197
  );
3965
4198
  const result = await store.truncate([
@@ -3979,8 +4212,7 @@ var runStoreTck = (options) => {
3979
4212
  { stream: s, before: new Date(Date.now() + 6e4) }
3980
4213
  ]);
3981
4214
  const [next] = await store.commit(
3982
- s,
3983
- [inc(1)],
4215
+ [{ stream: s, msgs: [inc(1)] }],
3984
4216
  make_meta({ stream: s })
3985
4217
  );
3986
4218
  (0, import_vitest9.expect)(next.version).toBe(6);
@@ -4118,8 +4350,7 @@ var runStoreTck = (options) => {
4118
4350
  const sibling = `qb-${tag}-other`;
4119
4351
  await store.subscribe([{ stream: s }, { stream: sibling }]);
4120
4352
  await store.commit(
4121
- s,
4122
- [inc(1)],
4353
+ [{ stream: s, msgs: [inc(1)] }],
4123
4354
  make_meta({ stream: s })
4124
4355
  );
4125
4356
  await correlate();
@@ -4150,18 +4381,15 @@ var runStoreTck = (options) => {
4150
4381
  const sB = `qst-${tag}-b`;
4151
4382
  const sUnasked = `qst-${tag}-unasked`;
4152
4383
  await store.commit(
4153
- sA,
4154
- [inc(1), inc(2)],
4384
+ [{ stream: sA, msgs: [inc(1), inc(2)] }],
4155
4385
  make_meta({ stream: sA })
4156
4386
  );
4157
4387
  await store.commit(
4158
- sB,
4159
- [dec(5)],
4388
+ [{ stream: sB, msgs: [dec(5)] }],
4160
4389
  make_meta({ stream: sB })
4161
4390
  );
4162
4391
  await store.commit(
4163
- sUnasked,
4164
- [inc(99)],
4392
+ [{ stream: sUnasked, msgs: [inc(99)] }],
4165
4393
  make_meta({ stream: sUnasked })
4166
4394
  );
4167
4395
  const stats = await store.query_stats([sA, sB]);
@@ -4179,8 +4407,7 @@ var runStoreTck = (options) => {
4179
4407
  (0, import_vitest9.it)("limit: 0 returns no rows", async () => {
4180
4408
  const s = `qst-zero-${uid()}`;
4181
4409
  await store.commit(
4182
- s,
4183
- [inc(1)],
4410
+ [{ stream: s, msgs: [inc(1)] }],
4184
4411
  make_meta({ stream: s })
4185
4412
  );
4186
4413
  const filter = { stream: s, stream_exact: true };
@@ -4201,8 +4428,7 @@ var runStoreTck = (options) => {
4201
4428
  ];
4202
4429
  for (const s of names)
4203
4430
  await store.commit(
4204
- s,
4205
- [inc(1)],
4431
+ [{ stream: s, msgs: [inc(1)] }],
4206
4432
  make_meta({ stream: s })
4207
4433
  );
4208
4434
  const visited = [];
@@ -4225,18 +4451,15 @@ var runStoreTck = (options) => {
4225
4451
  const tag = uid();
4226
4452
  const s = `qst-tail-${tag}`;
4227
4453
  await store.commit(
4228
- s,
4229
- [inc(1)],
4454
+ [{ stream: s, msgs: [inc(1)] }],
4230
4455
  make_meta({ stream: s })
4231
4456
  );
4232
4457
  await store.commit(
4233
- s,
4234
- [inc(2)],
4458
+ [{ stream: s, msgs: [inc(2)] }],
4235
4459
  make_meta({ stream: s })
4236
4460
  );
4237
4461
  await store.commit(
4238
- s,
4239
- [inc(3)],
4462
+ [{ stream: s, msgs: [inc(3)] }],
4240
4463
  make_meta({ stream: s })
4241
4464
  );
4242
4465
  const stats = await store.query_stats([s], {
@@ -4252,14 +4475,12 @@ var runStoreTck = (options) => {
4252
4475
  const tag = uid();
4253
4476
  const s = `qst-cn-${tag}`;
4254
4477
  await store.commit(
4255
- s,
4256
- [inc(1)],
4478
+ [{ stream: s, msgs: [inc(1)] }],
4257
4479
  make_meta({ stream: s })
4258
4480
  );
4259
4481
  await store.truncate([{ stream: s, snapshot: { count: 99 } }]);
4260
4482
  await store.commit(
4261
- s,
4262
- [inc(2), inc(3), dec(1)],
4483
+ [{ stream: s, msgs: [inc(2), inc(3), dec(1)] }],
4263
4484
  make_meta({ stream: s })
4264
4485
  );
4265
4486
  const stats = await store.query_stats([s], {
@@ -4278,13 +4499,11 @@ var runStoreTck = (options) => {
4278
4499
  const s = `qst-excl-${tag}`;
4279
4500
  const sAllOut = `qst-allout-${tag}`;
4280
4501
  await store.commit(
4281
- s,
4282
- [inc(1), dec(2), inc(3)],
4502
+ [{ stream: s, msgs: [inc(1), dec(2), inc(3)] }],
4283
4503
  make_meta({ stream: s })
4284
4504
  );
4285
4505
  await store.commit(
4286
- sAllOut,
4287
- [inc(7)],
4506
+ [{ stream: sAllOut, msgs: [inc(7)] }],
4288
4507
  make_meta({ stream: sAllOut })
4289
4508
  );
4290
4509
  const all = await store.query_stats([s]);
@@ -4308,18 +4527,15 @@ var runStoreTck = (options) => {
4308
4527
  const tag = uid();
4309
4528
  const s = `qst-tt-${tag}`;
4310
4529
  const c1 = await store.commit(
4311
- s,
4312
- [inc(1)],
4530
+ [{ stream: s, msgs: [inc(1)] }],
4313
4531
  make_meta({ stream: s })
4314
4532
  );
4315
4533
  const c2 = await store.commit(
4316
- s,
4317
- [inc(2)],
4534
+ [{ stream: s, msgs: [inc(2)] }],
4318
4535
  make_meta({ stream: s })
4319
4536
  );
4320
4537
  await store.commit(
4321
- s,
4322
- [inc(3)],
4538
+ [{ stream: s, msgs: [inc(3)] }],
4323
4539
  make_meta({ stream: s })
4324
4540
  );
4325
4541
  const before = c2[0].id;
@@ -4343,18 +4559,15 @@ var runStoreTck = (options) => {
4343
4559
  const sB = `qsf-${tag}-orders-2`;
4344
4560
  const sOther = `qsf-${tag}-users-1`;
4345
4561
  await store.commit(
4346
- sA,
4347
- [inc(1)],
4562
+ [{ stream: sA, msgs: [inc(1)] }],
4348
4563
  make_meta({ stream: sA })
4349
4564
  );
4350
4565
  await store.commit(
4351
- sB,
4352
- [inc(2)],
4566
+ [{ stream: sB, msgs: [inc(2)] }],
4353
4567
  make_meta({ stream: sB })
4354
4568
  );
4355
4569
  await store.commit(
4356
- sOther,
4357
- [inc(3)],
4570
+ [{ stream: sOther, msgs: [inc(3)] }],
4358
4571
  make_meta({ stream: sOther })
4359
4572
  );
4360
4573
  const orders = await store.query_stats({
@@ -4377,13 +4590,11 @@ var runStoreTck = (options) => {
4377
4590
  const b = `qsc-${tag}-b`;
4378
4591
  await store.subscribe([{ stream: a }, { stream: b }]);
4379
4592
  await store.commit(
4380
- a,
4381
- [inc(1)],
4593
+ [{ stream: a, msgs: [inc(1)] }],
4382
4594
  make_meta({ stream: a })
4383
4595
  );
4384
4596
  await store.commit(
4385
- b,
4386
- [inc(2)],
4597
+ [{ stream: b, msgs: [inc(2)] }],
4387
4598
  make_meta({ stream: b })
4388
4599
  );
4389
4600
  await correlate();
@@ -4408,13 +4619,11 @@ var runStoreTck = (options) => {
4408
4619
  const a = `qse-${tag}-a`;
4409
4620
  const b = `qse-${tag}-b`;
4410
4621
  await store.commit(
4411
- a,
4412
- [inc(1)],
4622
+ [{ stream: a, msgs: [inc(1)] }],
4413
4623
  make_meta({ stream: a })
4414
4624
  );
4415
4625
  await store.commit(
4416
- b,
4417
- [dec(2)],
4626
+ [{ stream: b, msgs: [dec(2)] }],
4418
4627
  make_meta({ stream: b })
4419
4628
  );
4420
4629
  const all = await store.query_stats({});
@@ -4425,8 +4634,7 @@ var runStoreTck = (options) => {
4425
4634
  const tag = uid();
4426
4635
  const s = `qsfl-${tag}`;
4427
4636
  await store.commit(
4428
- s,
4429
- [inc(1), inc(2), dec(3)],
4637
+ [{ stream: s, msgs: [inc(1), inc(2), dec(3)] }],
4430
4638
  make_meta({ stream: s })
4431
4639
  );
4432
4640
  const c = await store.query_stats([s], {
@@ -4457,8 +4665,7 @@ var runStoreTck = (options) => {
4457
4665
  ];
4458
4666
  for (const s of streams) {
4459
4667
  await store.commit(
4460
- s,
4461
- [inc(1)],
4668
+ [{ stream: s, msgs: [inc(1)] }],
4462
4669
  make_meta({ stream: s })
4463
4670
  );
4464
4671
  }
@@ -4488,8 +4695,7 @@ var runStoreTck = (options) => {
4488
4695
  const tag = uid();
4489
4696
  for (const s of [`qsc-${tag}-c`, `qsc-${tag}-a`, `qsc-${tag}-b`])
4490
4697
  await store.commit(
4491
- s,
4492
- [inc(1), inc(2)],
4698
+ [{ stream: s, msgs: [inc(1), inc(2)] }],
4493
4699
  make_meta({ stream: s })
4494
4700
  );
4495
4701
  const pattern = { stream: `qsc-${tag}-.*` };
@@ -4638,8 +4844,7 @@ var runStoreTck = (options) => {
4638
4844
  const s = `head-${uid()}`;
4639
4845
  await store.subscribe([{ stream: s }]);
4640
4846
  await store.commit(
4641
- s,
4642
- [inc(1)],
4847
+ [{ stream: s, msgs: [inc(1)] }],
4643
4848
  make_meta({ stream: s })
4644
4849
  );
4645
4850
  const positions = [];
@@ -4655,7 +4860,7 @@ var runStoreTck = (options) => {
4655
4860
  const actor2 = { id: "reader", name: "Reader" };
4656
4861
  const reader = (shape) => {
4657
4862
  const Happened = import_zod2.z.object(shape);
4658
- return (0, import_act2.state)({ Reader: import_zod2.z.object({ n: import_zod2.z.number() }) }).init(() => ({ n: 0 })).emits({ Happened }).patch({ Happened: (_, s) => ({ n: s.n + 1 }) }).on({ Do: Happened }).emit((p) => ["Happened", p]).build();
4863
+ return (0, import_act2.state)({ Reader: import_zod2.z.object({ n: import_zod2.z.number() }) }).init(() => ({ n: 0 })).emits({ Happened }).patch({ Happened: (_, s) => ({ n: s.n + 1 }) }).on({ Do: Happened }).emit("Happened").build();
4659
4864
  };
4660
4865
  const over = async (S) => {
4661
4866
  const fresh = await options.factory();
@@ -4748,10 +4953,16 @@ var runStoreTck = (options) => {
4748
4953
  const t = await over(S);
4749
4954
  try {
4750
4955
  await t.fresh.commit(
4751
- t.stream,
4752
- [{ name: "Happened", data: { at: /* @__PURE__ */ new Date("2020-01-01") } }],
4753
- raw,
4754
- -1
4956
+ [
4957
+ {
4958
+ stream: t.stream,
4959
+ msgs: [
4960
+ { name: "Happened", data: { at: /* @__PURE__ */ new Date("2020-01-01") } }
4961
+ ],
4962
+ expectedVersion: -1
4963
+ }
4964
+ ],
4965
+ raw
4755
4966
  );
4756
4967
  const d = await t.read();
4757
4968
  (0, import_vitest9.expect)(d.label).toBeUndefined();
@@ -4765,10 +4976,14 @@ var runStoreTck = (options) => {
4765
4976
  const t = await over(S);
4766
4977
  try {
4767
4978
  await t.fresh.commit(
4768
- t.stream,
4769
- [{ name: "Happened", data: { at: "not a date" } }],
4770
- raw,
4771
- -1
4979
+ [
4980
+ {
4981
+ stream: t.stream,
4982
+ msgs: [{ name: "Happened", data: { at: "not a date" } }],
4983
+ expectedVersion: -1
4984
+ }
4985
+ ],
4986
+ raw
4772
4987
  );
4773
4988
  (0, import_vitest9.expect)((await t.read()).at).toBe("not a date");
4774
4989
  } finally {
@@ -4908,6 +5123,19 @@ var runStoreTck = (options) => {
4908
5123
  (0, import_vitest9.expect)((await take(k, who)).correlating).toBe(true);
4909
5124
  await release(k, who);
4910
5125
  });
5126
+ (0, import_vitest9.it)("advances the checkpoint for a caller refused the lease", async () => {
5127
+ const k = key();
5128
+ const holder = by();
5129
+ (0, import_vitest9.expect)((await take(k, holder)).correlating).toBe(true);
5130
+ const refused = await store.subscribe([], 123456, {
5131
+ key: k,
5132
+ by: by(),
5133
+ millis: 1e4
5134
+ });
5135
+ (0, import_vitest9.expect)(refused.correlating).toBe(false);
5136
+ (0, import_vitest9.expect)((await take(k, holder)).correlated_at).toBe(123456);
5137
+ await release(k, holder);
5138
+ });
4911
5139
  (0, import_vitest9.it)("answers undefined when no correlator is supplied", async () => {
4912
5140
  (0, import_vitest9.expect)(await store.subscribe([])).not.toHaveProperty("correlating");
4913
5141
  });
@@ -4989,7 +5217,234 @@ var runStoreTck = (options) => {
4989
5217
  });
4990
5218
  }
4991
5219
  );
5220
+ (0, import_vitest9.describe)("an action across streams", () => {
5221
+ const SeatTaken = import_zod2.z.object({ student: import_zod2.z.string() });
5222
+ const Seats = (0, import_act2.state)({
5223
+ Seats: import_zod2.z.object({ taken: import_zod2.z.number() }).refine((s) => s.taken <= 3, "the course is full")
5224
+ }).init(() => ({ taken: 0 })).emits({ SeatTaken }).patch({ SeatTaken: (_, s) => ({ taken: s.taken + 1 }) }).on({ TakeSeat: SeatTaken }).emit("SeatTaken").build();
5225
+ const Enroll = import_zod2.z.object({ course: import_zod2.z.string(), student: import_zod2.z.string() });
5226
+ const course = (data) => `course-${data.course}`;
5227
+ const Enrollment = (0, import_act2.state)({ Enrollment: Enroll }).init(() => ({ course: "", student: "" })).emits({ Enrolled: Enroll }).on({ Enroll }, { maxRetries: 8 }).loads(Seats, course, ["SeatTaken"]).requires([
5228
+ {
5229
+ description: "the course has a free seat",
5230
+ holds: (_, __, ___, { Seats: Seats2 }) => Seats2.taken < 3
5231
+ }
5232
+ ]).emit((data) => [
5233
+ ["Enrolled", data],
5234
+ ["SeatTaken", { student: data.student }]
5235
+ ]).on({ Overfill: Enroll }).loads(Seats, course, ["SeatTaken"]).emit((data) => [
5236
+ ["Enrolled", data],
5237
+ ["SeatTaken", { student: data.student }]
5238
+ ]).build();
5239
+ const actor2 = { id: "a", name: "a" };
5240
+ const at = (stream) => ({ stream, actor: actor2 });
5241
+ const over = async (run) => {
5242
+ const fresh = await options.factory();
5243
+ await fresh.seed();
5244
+ const cache = new import_act2.InMemoryCache();
5245
+ const app = (0, import_act2.act)().withState(Seats).withState(Enrollment).build({ scoped: { store: fresh, cache } });
5246
+ const c = `c${uid()}`;
5247
+ const events2 = async (stream) => {
5248
+ const found = [];
5249
+ await fresh.query((e) => found.push(e), {
5250
+ stream,
5251
+ stream_exact: true
5252
+ });
5253
+ return found;
5254
+ };
5255
+ try {
5256
+ await run({
5257
+ app,
5258
+ fresh,
5259
+ c,
5260
+ events: events2,
5261
+ seat: (student) => ({ course: c, student })
5262
+ });
5263
+ } finally {
5264
+ import_vitest9.vi.restoreAllMocks();
5265
+ await app.shutdown();
5266
+ await cache.dispose();
5267
+ await fresh.dispose();
5268
+ }
5269
+ };
5270
+ (0, import_vitest9.it)("commits both streams at once and fires committed once per stream", () => over(async ({ app, c, events: events2, seat }) => {
5271
+ const stream = `enr-${uid()}`;
5272
+ const heard = [];
5273
+ app.on("committed", (s) => heard.push(s));
5274
+ const snapshots = await app.do("Enroll", at(stream), seat("s1"));
5275
+ (0, import_vitest9.expect)(snapshots.map((s) => s.event?.name)).toEqual([
5276
+ "Enrolled"
5277
+ ]);
5278
+ const [own] = await events2(stream);
5279
+ const [other] = await events2(`course-${c}`);
5280
+ (0, import_vitest9.expect)(own.name).toBe("Enrolled");
5281
+ (0, import_vitest9.expect)(other.name).toBe("SeatTaken");
5282
+ (0, import_vitest9.expect)(other.id).toBeGreaterThan(own.id);
5283
+ (0, import_vitest9.expect)(other.meta.correlation).toBe(own.meta.correlation);
5284
+ (0, import_vitest9.expect)(heard.map((h) => h[0].event?.stream)).toEqual([
5285
+ stream,
5286
+ `course-${c}`
5287
+ ]);
5288
+ (0, import_vitest9.expect)((await app.load(Seats, `course-${c}`)).state.taken).toBe(1);
5289
+ }));
5290
+ (0, import_vitest9.it)("stores nothing on either stream when a rule or a schema refuses", () => over(async ({ app, c, events: events2, seat }) => {
5291
+ for (const i of [1, 2, 3])
5292
+ await app.do("TakeSeat", at(`course-${c}`), { student: `s${i}` });
5293
+ const [a, b] = [`enr-${uid()}`, `enr-${uid()}`];
5294
+ await (0, import_vitest9.expect)(app.do("Enroll", at(a), seat("late"))).rejects.toThrow(
5295
+ import_act2.PreconditionError
5296
+ );
5297
+ await (0, import_vitest9.expect)(app.do("Overfill", at(b), seat("late"))).rejects.toThrow(
5298
+ import_act2.ValidationError
5299
+ );
5300
+ (0, import_vitest9.expect)(await events2(a)).toEqual([]);
5301
+ (0, import_vitest9.expect)(await events2(b)).toEqual([]);
5302
+ (0, import_vitest9.expect)(await events2(`course-${c}`)).toHaveLength(3);
5303
+ }));
5304
+ (0, import_vitest9.it)("a rival on the loaded stream refuses the whole commit, naming that stream", () => over(async ({ app, fresh, c, events: events2, seat }) => {
5305
+ const commit = fresh.commit.bind(fresh);
5306
+ import_vitest9.vi.spyOn(fresh, "commit").mockImplementationOnce(
5307
+ async (...args) => {
5308
+ await commit(
5309
+ [
5310
+ {
5311
+ stream: `course-${c}`,
5312
+ msgs: [{ name: "SeatTaken", data: { student: "rival" } }]
5313
+ }
5314
+ ],
5315
+ { correlation: "rival", causation: {} }
5316
+ );
5317
+ return commit(...args);
5318
+ }
5319
+ );
5320
+ const stream = `enr-${uid()}`;
5321
+ const err = await app.do("Overfill", at(stream), seat("s")).catch((e) => e);
5322
+ (0, import_vitest9.expect)(err).toBeInstanceOf(import_act2.ConcurrencyError);
5323
+ (0, import_vitest9.expect)(err.stream).toBe(`course-${c}`);
5324
+ (0, import_vitest9.expect)(await events2(stream)).toEqual([]);
5325
+ (0, import_vitest9.expect)(await events2(`course-${c}`)).toHaveLength(1);
5326
+ }));
5327
+ (0, import_vitest9.it)("racing enrollments fill the seats exactly: the rest are refused by the rule", () => over(async ({ app, c, events: events2, seat }) => {
5328
+ const results = await Promise.allSettled(
5329
+ [1, 2, 3, 4, 5, 6].map(
5330
+ (i) => app.do("Enroll", at(`race-${uid()}-${i}`), seat(`s${i}`))
5331
+ )
5332
+ );
5333
+ (0, import_vitest9.expect)(results.filter((r) => r.status === "fulfilled")).toHaveLength(
5334
+ 3
5335
+ );
5336
+ for (const r of results.filter((r2) => r2.status === "rejected"))
5337
+ (0, import_vitest9.expect)(r.reason).toBeInstanceOf(
5338
+ import_act2.PreconditionError
5339
+ );
5340
+ (0, import_vitest9.expect)(await events2(`course-${c}`)).toHaveLength(3);
5341
+ }));
5342
+ });
4992
5343
  import_vitest9.describe.skipIf(!caps.restore)("restore (capability)", () => {
5344
+ (0, import_vitest9.describe)("what a restore must not get wrong", () => {
5345
+ const edge_uid = () => uid();
5346
+ const E = (data = { a: 1 }, pii) => ({
5347
+ name: "E",
5348
+ data,
5349
+ ...pii ? { pii } : {}
5350
+ });
5351
+ const edge_meta = (correlation = "m") => ({ correlation, causation: {} });
5352
+ const rows = async (query) => {
5353
+ const found = [];
5354
+ await store.query((e) => found.push(e), query);
5355
+ return found;
5356
+ };
5357
+ const one = (stream) => ({ stream, stream_exact: true });
5358
+ (0, import_vitest9.it)("a commit after restore continues each stream from its restored head", async () => {
5359
+ const a = `a-${edge_uid()}`;
5360
+ await store.commit(
5361
+ [{ stream: a, msgs: [E(), E()] }],
5362
+ edge_meta()
5363
+ );
5364
+ const log = await rows({ with_snaps: true });
5365
+ await store.restore(async (cb) => {
5366
+ for (const e of log) await cb(e);
5367
+ });
5368
+ const [c] = await store.commit(
5369
+ [{ stream: a, msgs: [E()], expectedVersion: 1 }],
5370
+ edge_meta()
5371
+ );
5372
+ (0, import_vitest9.expect)(c.version).toBe(2);
5373
+ });
5374
+ (0, import_vitest9.it)("restore renumbers: ids are dense whatever the source ids were", async () => {
5375
+ const a = `a-${edge_uid()}`;
5376
+ const ev = (version, id) => ({
5377
+ id,
5378
+ stream: a,
5379
+ version,
5380
+ name: "E",
5381
+ data: {},
5382
+ meta: edge_meta(),
5383
+ created: /* @__PURE__ */ new Date()
5384
+ });
5385
+ const ids = [];
5386
+ await store.restore(async (cb) => {
5387
+ ids.push(await cb(ev(0, 500)));
5388
+ ids.push(await cb(ev(1, 900)));
5389
+ });
5390
+ (0, import_vitest9.expect)(ids[1]).toBe(ids[0] + 1);
5391
+ (0, import_vitest9.expect)(ids[0]).toBeLessThanOrEqual(1);
5392
+ });
5393
+ (0, import_vitest9.it)("changes nothing when it fails", async () => {
5394
+ const a = `rb-${edge_uid()}`;
5395
+ const key = `k-${edge_uid()}`;
5396
+ const sub = `sub-${edge_uid()}`;
5397
+ const committed = await store.commit(
5398
+ [{ stream: a, msgs: [E({}, { email: "x" }), E()] }],
5399
+ edge_meta()
5400
+ );
5401
+ const head = committed.at(-1).id;
5402
+ await store.subscribe([{ stream: sub }], head);
5403
+ const keyed = await store.subscribe([], head, {
5404
+ key,
5405
+ by: "w",
5406
+ millis: 1
5407
+ });
5408
+ const shared = await store.subscribe([]);
5409
+ await (0, import_vitest9.expect)(
5410
+ store.restore(async (callback) => {
5411
+ await callback({
5412
+ id: 1,
5413
+ stream: "other",
5414
+ version: 0,
5415
+ name: "E",
5416
+ data: {},
5417
+ meta: edge_meta(),
5418
+ created: /* @__PURE__ */ new Date()
5419
+ });
5420
+ throw new Error("mid-restore");
5421
+ })
5422
+ ).rejects.toThrow();
5423
+ const subscriptions = [];
5424
+ await store.query_streams((p) => subscriptions.push(p.stream), {
5425
+ stream: sub,
5426
+ stream_exact: true
5427
+ });
5428
+ (0, import_vitest9.expect)(subscriptions).toEqual([sub]);
5429
+ (0, import_vitest9.expect)((await store.subscribe([])).correlated_at).toBe(
5430
+ shared.correlated_at
5431
+ );
5432
+ await (0, import_act2.sleep)(5);
5433
+ const keyed_after = await store.subscribe([], void 0, {
5434
+ key,
5435
+ by: "w2",
5436
+ millis: 1
5437
+ });
5438
+ (0, import_vitest9.expect)(keyed_after.correlated_at).toBe(keyed.correlated_at);
5439
+ (0, import_vitest9.expect)((await rows(one(a)))[0].pii).toEqual({ email: "x" });
5440
+ const [next] = await store.commit(
5441
+ [{ stream: a, msgs: [E()], expectedVersion: 1 }],
5442
+ edge_meta()
5443
+ );
5444
+ (0, import_vitest9.expect)(next.version).toBe(2);
5445
+ (0, import_vitest9.expect)(next.id).toBeGreaterThan(head);
5446
+ });
5447
+ });
4993
5448
  beforeEach(async () => {
4994
5449
  await store.drop();
4995
5450
  await store.seed();
@@ -5175,8 +5630,7 @@ var runStoreTck = (options) => {
5175
5630
  (0, import_vitest9.it)("wipes pre-existing events before inserting", async () => {
5176
5631
  const old = `restore-old-${uid()}`;
5177
5632
  await store.commit(
5178
- old,
5179
- [inc(1), inc(2)],
5633
+ [{ stream: old, msgs: [inc(1), inc(2)] }],
5180
5634
  make_meta({ stream: old })
5181
5635
  );
5182
5636
  const fresh = `restore-fresh-${uid()}`;
@@ -5323,8 +5777,7 @@ var runStoreTck = (options) => {
5323
5777
  (0, import_vitest9.it)("rolls back atomically when the source throws mid-iteration", async () => {
5324
5778
  const original = `restore-pre-${uid()}`;
5325
5779
  const committed = await store.commit(
5326
- original,
5327
- [inc(1), inc(2), inc(3)],
5780
+ [{ stream: original, msgs: [inc(1), inc(2), inc(3)] }],
5328
5781
  make_meta({ stream: original })
5329
5782
  );
5330
5783
  const explosive = {
@@ -5497,12 +5950,16 @@ var runStoreTck = (options) => {
5497
5950
  (0, import_vitest9.it)("commits and loads pii alongside data", async () => {
5498
5951
  const s = `pii-roundtrip-${uid()}`;
5499
5952
  const committed = await store.commit(
5500
- s,
5501
5953
  [
5502
5954
  {
5503
- name: "Incremented",
5504
- data: { amount: 1 },
5505
- pii: { email: "u@example.com", name: "Ursula" }
5955
+ stream: s,
5956
+ msgs: [
5957
+ {
5958
+ name: "Incremented",
5959
+ data: { amount: 1 },
5960
+ pii: { email: "u@example.com", name: "Ursula" }
5961
+ }
5962
+ ]
5506
5963
  }
5507
5964
  ],
5508
5965
  make_meta({ stream: s })
@@ -5525,12 +5982,16 @@ var runStoreTck = (options) => {
5525
5982
  });
5526
5983
  (0, import_vitest9.describe)("with_pii", () => {
5527
5984
  const seed_pii = async (s) => await store.commit(
5528
- s,
5529
5985
  [
5530
5986
  {
5531
- name: "Incremented",
5532
- data: { amount: 1 },
5533
- pii: { email: "w@example.com" }
5987
+ stream: s,
5988
+ msgs: [
5989
+ {
5990
+ name: "Incremented",
5991
+ data: { amount: 1 },
5992
+ pii: { email: "w@example.com" }
5993
+ }
5994
+ ]
5534
5995
  }
5535
5996
  ],
5536
5997
  make_meta({ stream: s })
@@ -5591,12 +6052,16 @@ var runStoreTck = (options) => {
5591
6052
  const s = `pii-date-${uid()}`;
5592
6053
  const when = /* @__PURE__ */ new Date("2024-03-01T10:20:30.000Z");
5593
6054
  await store.commit(
5594
- s,
5595
6055
  [
5596
6056
  {
5597
- name: "Incremented",
5598
- data: { amount: 1, at: when },
5599
- pii: { born: when }
6057
+ stream: s,
6058
+ msgs: [
6059
+ {
6060
+ name: "Incremented",
6061
+ data: { amount: 1, at: when },
6062
+ pii: { born: when }
6063
+ }
6064
+ ]
5600
6065
  }
5601
6066
  ],
5602
6067
  make_meta({ stream: s })
@@ -5619,17 +6084,21 @@ var runStoreTck = (options) => {
5619
6084
  (0, import_vitest9.it)("query_stats head/tail never carry pii \u2014 introspection surface is pii-safe", async () => {
5620
6085
  const s = `pii-stats-${uid()}`;
5621
6086
  await store.commit(
5622
- s,
5623
6087
  [
5624
6088
  {
5625
- name: "Incremented",
5626
- data: { amount: 1 },
5627
- pii: { email: "head@example.com" }
5628
- },
5629
- {
5630
- name: "Incremented",
5631
- data: { amount: 2 },
5632
- pii: { email: "tail@example.com" }
6089
+ stream: s,
6090
+ msgs: [
6091
+ {
6092
+ name: "Incremented",
6093
+ data: { amount: 1 },
6094
+ pii: { email: "head@example.com" }
6095
+ },
6096
+ {
6097
+ name: "Incremented",
6098
+ data: { amount: 2 },
6099
+ pii: { email: "tail@example.com" }
6100
+ }
6101
+ ]
5633
6102
  }
5634
6103
  ],
5635
6104
  make_meta({ stream: s })
@@ -5653,8 +6122,7 @@ var runStoreTck = (options) => {
5653
6122
  (0, import_vitest9.it)("passes through events without pii (pii is null or undefined on load)", async () => {
5654
6123
  const s = `pii-none-${uid()}`;
5655
6124
  await store.commit(
5656
- s,
5657
- [inc(1)],
6125
+ [{ stream: s, msgs: [inc(1)] }],
5658
6126
  make_meta({ stream: s })
5659
6127
  );
5660
6128
  const seen = [];
@@ -5670,17 +6138,21 @@ var runStoreTck = (options) => {
5670
6138
  (0, import_vitest9.it)("wipes pii for every event on the stream via forget_pii", async () => {
5671
6139
  const s = `pii-forget-${uid()}`;
5672
6140
  await store.commit(
5673
- s,
5674
6141
  [
5675
6142
  {
5676
- name: "Incremented",
5677
- data: { amount: 1 },
5678
- pii: { email: "a@example.com" }
5679
- },
5680
- {
5681
- name: "Incremented",
5682
- data: { amount: 2 },
5683
- pii: { email: "b@example.com" }
6143
+ stream: s,
6144
+ msgs: [
6145
+ {
6146
+ name: "Incremented",
6147
+ data: { amount: 1 },
6148
+ pii: { email: "a@example.com" }
6149
+ },
6150
+ {
6151
+ name: "Incremented",
6152
+ data: { amount: 2 },
6153
+ pii: { email: "b@example.com" }
6154
+ }
6155
+ ]
5684
6156
  }
5685
6157
  ],
5686
6158
  make_meta({ stream: s })
@@ -5705,12 +6177,16 @@ var runStoreTck = (options) => {
5705
6177
  (0, import_vitest9.it)("is idempotent \u2014 second forget_pii returns 0, no error", async () => {
5706
6178
  const s = `pii-forget-idem-${uid()}`;
5707
6179
  await store.commit(
5708
- s,
5709
6180
  [
5710
6181
  {
5711
- name: "Incremented",
5712
- data: { amount: 1 },
5713
- pii: { email: "u@example.com" }
6182
+ stream: s,
6183
+ msgs: [
6184
+ {
6185
+ name: "Incremented",
6186
+ data: { amount: 1 },
6187
+ pii: { email: "u@example.com" }
6188
+ }
6189
+ ]
5714
6190
  }
5715
6191
  ],
5716
6192
  make_meta({ stream: s })
@@ -5725,23 +6201,31 @@ var runStoreTck = (options) => {
5725
6201
  const sA = `pii-iso-a-${uid()}`;
5726
6202
  const sB = `pii-iso-b-${uid()}`;
5727
6203
  await store.commit(
5728
- sA,
5729
6204
  [
5730
6205
  {
5731
- name: "Incremented",
5732
- data: { amount: 1 },
5733
- pii: { email: "alice@example.com" }
6206
+ stream: sA,
6207
+ msgs: [
6208
+ {
6209
+ name: "Incremented",
6210
+ data: { amount: 1 },
6211
+ pii: { email: "alice@example.com" }
6212
+ }
6213
+ ]
5734
6214
  }
5735
6215
  ],
5736
6216
  make_meta({ stream: sA })
5737
6217
  );
5738
6218
  await store.commit(
5739
- sB,
5740
6219
  [
5741
6220
  {
5742
- name: "Incremented",
5743
- data: { amount: 1 },
5744
- pii: { email: "bob@example.com" }
6221
+ stream: sB,
6222
+ msgs: [
6223
+ {
6224
+ name: "Incremented",
6225
+ data: { amount: 1 },
6226
+ pii: { email: "bob@example.com" }
6227
+ }
6228
+ ]
5745
6229
  }
5746
6230
  ],
5747
6231
  make_meta({ stream: sB })
@@ -5767,8 +6251,7 @@ var runStoreTck = (options) => {
5767
6251
  (0, import_vitest9.it)("forget_pii on a stream with no pii events returns 0", async () => {
5768
6252
  const s = `pii-forget-empty-${uid()}`;
5769
6253
  await store.commit(
5770
- s,
5771
- [inc(1)],
6254
+ [{ stream: s, msgs: [inc(1)] }],
5772
6255
  make_meta({ stream: s })
5773
6256
  );
5774
6257
  const wiped = await store.forget_pii.call(store, s);
@@ -5793,8 +6276,7 @@ var runStoreTck = (options) => {
5793
6276
  try {
5794
6277
  const stream = `notify-${uid()}`;
5795
6278
  await writer.commit(
5796
- stream,
5797
- [inc(1)],
6279
+ [{ stream, msgs: [inc(1)] }],
5798
6280
  make_meta({ stream })
5799
6281
  );
5800
6282
  await arrived;
@@ -5822,18 +6304,15 @@ var runStoreTck = (options) => {
5822
6304
  const writer = await options.factory();
5823
6305
  try {
5824
6306
  await store.commit(
5825
- own,
5826
- [inc(1)],
6307
+ [{ stream: own, msgs: [inc(1)] }],
5827
6308
  make_meta({ stream: own })
5828
6309
  );
5829
6310
  await writer.commit(
5830
- remote,
5831
- [inc(1)],
6311
+ [{ stream: remote, msgs: [inc(1)] }],
5832
6312
  make_meta({ stream: remote })
5833
6313
  );
5834
6314
  await writer.commit(
5835
- sentinel,
5836
- [inc(1)],
6315
+ [{ stream: sentinel, msgs: [inc(1)] }],
5837
6316
  make_meta({ stream: sentinel })
5838
6317
  );
5839
6318
  await sentinel_arrived;
@@ -5845,7 +6324,7 @@ var runStoreTck = (options) => {
5845
6324
  await Promise.resolve(disposer());
5846
6325
  }
5847
6326
  });
5848
- (0, import_vitest9.it)("delivers one notification per commit transaction carrying the full event batch", async () => {
6327
+ (0, import_vitest9.it)("delivers one notification carrying a stream's full batch from one commit", async () => {
5849
6328
  const received = [];
5850
6329
  let resolve_sentinel;
5851
6330
  const sentinel_arrived = new Promise((res) => {
@@ -5860,13 +6339,11 @@ var runStoreTck = (options) => {
5860
6339
  const writer = await options.factory();
5861
6340
  try {
5862
6341
  await writer.commit(
5863
- batch,
5864
- [inc(1), inc(2), inc(3)],
6342
+ [{ stream: batch, msgs: [inc(1), inc(2), inc(3)] }],
5865
6343
  make_meta({ stream: batch })
5866
6344
  );
5867
6345
  await writer.commit(
5868
- sentinel,
5869
- [inc(1)],
6346
+ [{ stream: sentinel, msgs: [inc(1)] }],
5870
6347
  make_meta({ stream: sentinel })
5871
6348
  );
5872
6349
  await sentinel_arrived;
@@ -5889,6 +6366,45 @@ var runStoreTck = (options) => {
5889
6366
  await Promise.resolve(disposer());
5890
6367
  }
5891
6368
  });
6369
+ (0, import_vitest9.it)("delivers one notification per stream a commit appends to, with that stream's events", async () => {
6370
+ const received = [];
6371
+ let resolve_sentinel;
6372
+ const sentinel_arrived = new Promise((res) => {
6373
+ resolve_sentinel = res;
6374
+ });
6375
+ const a = `notify-across-a-${uid()}`;
6376
+ const b = `notify-across-b-${uid()}`;
6377
+ const sentinel = `notify-across-sentinel-${uid()}`;
6378
+ const disposer = await store.notify.call(store, (n) => {
6379
+ received.push(n);
6380
+ if (n.stream === sentinel) resolve_sentinel();
6381
+ });
6382
+ const writer = await options.factory();
6383
+ try {
6384
+ const committed = await writer.commit(
6385
+ [
6386
+ { stream: a, msgs: [inc(1), inc(2)] },
6387
+ { stream: b, msgs: [dec(3)] }
6388
+ ],
6389
+ make_meta({ stream: a })
6390
+ );
6391
+ await writer.commit(
6392
+ [{ stream: sentinel, msgs: [inc(1)] }],
6393
+ make_meta({ stream: sentinel })
6394
+ );
6395
+ await sentinel_arrived;
6396
+ for (const stream of [a, b]) {
6397
+ const of_stream = received.filter((n) => n.stream === stream);
6398
+ (0, import_vitest9.expect)(of_stream).toHaveLength(1);
6399
+ (0, import_vitest9.expect)(of_stream[0].events.map((e) => e.id)).toEqual(
6400
+ committed.filter((e) => e.stream === stream).map((e) => e.id)
6401
+ );
6402
+ }
6403
+ } finally {
6404
+ await writer.dispose();
6405
+ await Promise.resolve(disposer());
6406
+ }
6407
+ });
5892
6408
  });
5893
6409
  }
5894
6410
  });