@rotorsoft/act-tck 1.25.0 → 1.26.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.js CHANGED
@@ -2185,6 +2185,165 @@ var runStoreTck = (options) => {
2185
2185
  const result = await store.truncate([{ stream: s }]);
2186
2186
  expect8(result.get(s)?.deleted).toBe(0);
2187
2187
  });
2188
+ describe8("windowed (before boundary)", () => {
2189
+ async function seed_windowed(s) {
2190
+ await store.commit(
2191
+ s,
2192
+ [inc(1), inc(1)],
2193
+ make_meta({ stream: s })
2194
+ );
2195
+ const [snap_a] = await store.commit(
2196
+ s,
2197
+ [{ name: SNAP_EVENT2, data: { count: 2 } }],
2198
+ make_meta({ stream: s })
2199
+ );
2200
+ await store.commit(
2201
+ s,
2202
+ [inc(1)],
2203
+ make_meta({ stream: s })
2204
+ );
2205
+ const [snap_b] = await store.commit(
2206
+ s,
2207
+ [{ name: SNAP_EVENT2, data: { count: 3 } }],
2208
+ make_meta({ stream: s })
2209
+ );
2210
+ await store.commit(
2211
+ s,
2212
+ [inc(1)],
2213
+ make_meta({ stream: s })
2214
+ );
2215
+ return { snap_a, snap_b };
2216
+ }
2217
+ it7("deletes the prefix below the closest safe snapshot and keeps the snapshot + tail", async () => {
2218
+ const s = `trunc-win-${uid()}`;
2219
+ const { snap_b } = await seed_windowed(s);
2220
+ const before = new Date(Date.now() + 6e4);
2221
+ const result = await store.truncate([{ stream: s, before }]);
2222
+ const entry2 = result.get(s);
2223
+ expect8(entry2?.deleted).toBe(4);
2224
+ expect8(entry2?.committed.id).toBe(snap_b.id);
2225
+ expect8(entry2?.committed.name).toBe(SNAP_EVENT2);
2226
+ expect8(entry2?.committed.data).toEqual({ count: 3 });
2227
+ expect8(entry2?.before).toEqual(before);
2228
+ const remaining = await collect(store, {
2229
+ stream: s,
2230
+ stream_exact: true,
2231
+ with_snaps: true,
2232
+ after: -1
2233
+ });
2234
+ expect8(remaining.map((e) => e.name)).toEqual([
2235
+ SNAP_EVENT2,
2236
+ "Incremented"
2237
+ ]);
2238
+ expect8(remaining[0].id).toBe(snap_b.id);
2239
+ });
2240
+ it7("honors the max_id cap \u2014 boundary never rises past a lagging consumer", async () => {
2241
+ const s = `trunc-win-cap-${uid()}`;
2242
+ const { snap_a, snap_b } = await seed_windowed(s);
2243
+ const before = new Date(Date.now() + 6e4);
2244
+ const result = await store.truncate([
2245
+ { stream: s, before, max_id: snap_a.id }
2246
+ ]);
2247
+ const entry2 = result.get(s);
2248
+ expect8(entry2?.committed.id).toBe(snap_a.id);
2249
+ expect8(entry2?.deleted).toBe(2);
2250
+ const remaining = await collect(store, {
2251
+ stream: s,
2252
+ stream_exact: true,
2253
+ with_snaps: true,
2254
+ after: -1
2255
+ });
2256
+ expect8(remaining.map((e) => e.id)).toContain(snap_b.id);
2257
+ expect8(remaining[0].id).toBe(snap_a.id);
2258
+ expect8(remaining).toHaveLength(4);
2259
+ });
2260
+ it7("no-ops when no snapshot qualifies \u2014 stream absent from the result, events untouched", async () => {
2261
+ const s = `trunc-win-noop-${uid()}`;
2262
+ await store.commit(
2263
+ s,
2264
+ [inc(1), inc(1)],
2265
+ make_meta({ stream: s })
2266
+ );
2267
+ const none = await store.truncate([
2268
+ { stream: s, before: new Date(Date.now() + 6e4) }
2269
+ ]);
2270
+ expect8(none.has(s)).toBe(false);
2271
+ await store.commit(
2272
+ s,
2273
+ [{ name: SNAP_EVENT2, data: { count: 2 } }],
2274
+ make_meta({ stream: s })
2275
+ );
2276
+ const too_early = await store.truncate([
2277
+ { stream: s, before: /* @__PURE__ */ new Date(0) }
2278
+ ]);
2279
+ expect8(too_early.has(s)).toBe(false);
2280
+ const missing = await store.truncate([
2281
+ { stream: `trunc-win-missing-${uid()}`, before: /* @__PURE__ */ new Date() }
2282
+ ]);
2283
+ expect8(missing.size).toBe(0);
2284
+ const remaining = await collect(store, {
2285
+ stream: s,
2286
+ stream_exact: true,
2287
+ with_snaps: true,
2288
+ after: -1
2289
+ });
2290
+ expect8(remaining).toHaveLength(3);
2291
+ });
2292
+ it7("leaves subscriptions untouched, unlike a full truncate", async () => {
2293
+ const s = `trunc-win-subs-${uid()}`;
2294
+ await seed_windowed(s);
2295
+ await store.subscribe([{ stream: s }]);
2296
+ await store.truncate([
2297
+ { stream: s, before: new Date(Date.now() + 6e4) }
2298
+ ]);
2299
+ const positions = [];
2300
+ await store.query_streams((p) => positions.push(p.stream), {
2301
+ stream: s,
2302
+ stream_exact: true
2303
+ });
2304
+ expect8(positions).toEqual([s]);
2305
+ });
2306
+ it7("mixes full and windowed targets in one call", async () => {
2307
+ const w = `trunc-win-mix-w-${uid()}`;
2308
+ const f = `trunc-win-mix-f-${uid()}`;
2309
+ const { snap_b } = await seed_windowed(w);
2310
+ await store.commit(
2311
+ f,
2312
+ [inc(1)],
2313
+ make_meta({ stream: f })
2314
+ );
2315
+ const result = await store.truncate([
2316
+ { stream: w, before: new Date(Date.now() + 6e4) },
2317
+ { stream: f }
2318
+ ]);
2319
+ expect8(result.get(w)?.committed.id).toBe(snap_b.id);
2320
+ expect8(result.get(w)?.before).toBeInstanceOf(Date);
2321
+ expect8(result.get(f)?.deleted).toBe(1);
2322
+ expect8(result.get(f)?.committed.name).toBe("__tombstone__");
2323
+ expect8(result.get(f)?.before).toBeUndefined();
2324
+ });
2325
+ it7("keeps the stream writable and readable after a prune", async () => {
2326
+ const s = `trunc-win-cont-${uid()}`;
2327
+ const { snap_b } = await seed_windowed(s);
2328
+ await store.truncate([
2329
+ { stream: s, before: new Date(Date.now() + 6e4) }
2330
+ ]);
2331
+ const [next] = await store.commit(
2332
+ s,
2333
+ [inc(1)],
2334
+ make_meta({ stream: s })
2335
+ );
2336
+ expect8(next.version).toBe(6);
2337
+ expect8(next.id).toBeGreaterThan(snap_b.id);
2338
+ const replay = await collect(store, {
2339
+ stream: s,
2340
+ stream_exact: true,
2341
+ with_snaps: true
2342
+ });
2343
+ expect8(replay[0].id).toBe(snap_b.id);
2344
+ expect8(replay).toHaveLength(3);
2345
+ });
2346
+ });
2188
2347
  });
2189
2348
  describe8("query_streams", () => {
2190
2349
  it7("returns positions filtered by stream regex, exact, source, and source_exact", async () => {