@crvouga/mockingbird-service-junction 0.4.0 → 0.6.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.
@@ -2,7 +2,7 @@ import {
2
2
  IDENTITY_MODES,
3
3
  createRuntime,
4
4
  pullCorpus
5
- } from "./chunk-ICINEQ7D.js";
5
+ } from "./chunk-MS774AJA.js";
6
6
  import {
7
7
  defaultCorpus
8
8
  } from "./chunk-C2UGIPPM.js";
@@ -513,4 +513,4 @@ export {
513
513
  createServer2 as createServer,
514
514
  serveTarget
515
515
  };
516
- //# sourceMappingURL=chunk-CR35KYXY.js.map
516
+ //# sourceMappingURL=chunk-TG2EOH3J.js.map
package/dist/cli.js CHANGED
@@ -4,7 +4,7 @@ import {
4
4
  runCli,
5
5
  serveCommand,
6
6
  serveTarget
7
- } from "./chunk-CR35KYXY.js";
7
+ } from "./chunk-TG2EOH3J.js";
8
8
  import {
9
9
  DEFAULT_JUNCTION_BASE_URL,
10
10
  createRuntime,
@@ -12,7 +12,7 @@ import {
12
12
  isSandboxKey,
13
13
  pullCorpus,
14
14
  verifyAgainstReal
15
- } from "./chunk-ICINEQ7D.js";
15
+ } from "./chunk-MS774AJA.js";
16
16
  import {
17
17
  defaultCorpus
18
18
  } from "./chunk-C2UGIPPM.js";
package/dist/index.d.ts CHANGED
@@ -73,6 +73,10 @@ type Rng = {
73
73
  int(min: number, max: number): number;
74
74
  /** Restart the stream from its seed. */
75
75
  reset(): void;
76
+ /** Serializable engine state used by deterministic checkpoints. */
77
+ state(): number;
78
+ /** Restore a state previously returned by {@link state}. */
79
+ setState(state: number): void;
76
80
  seed: number;
77
81
  };
78
82
 
@@ -229,28 +233,6 @@ type Journal = {
229
233
  clear(namespace?: string): void;
230
234
  };
231
235
 
232
- /**
233
- * A point-in-time copy of everything a service namespace holds.
234
- *
235
- * All service state lives in the two core tables keyed by namespace, so a snapshot
236
- * is generic: any service gets per-test rollback without knowing its own schema.
237
- * Restoring is much cheaper than rebuilding a namespace from a corpus.
238
- */
239
- type NamespaceSnapshot = {
240
- namespace: string;
241
- records: {
242
- collection: string;
243
- id: string;
244
- seq: number;
245
- value: string;
246
- }[];
247
- sequences: {
248
- name: string;
249
- kind: string;
250
- value: number;
251
- }[];
252
- };
253
-
254
236
  /** Credential → namespace mapping behind `PUT /__admin/credentials`. */
255
237
  type CredentialRegistry = {
256
238
  set(credential: string, namespace: string): void;
@@ -263,6 +245,86 @@ type CredentialRegistry = {
263
245
  }[];
264
246
  };
265
247
 
248
+ /** A stable identifier for a point in a {@link Timeline}. */
249
+ type CheckpointId = string;
250
+ /** An immutable node in a timeline's checkpoint DAG. */
251
+ type Checkpoint<T> = Readonly<{
252
+ id: CheckpointId;
253
+ branch: string;
254
+ parent: CheckpointId | null;
255
+ /** Logical time supplied by the timeline's injected clock. */
256
+ at: number;
257
+ value: T;
258
+ }>;
259
+ type TimelineOptions = {
260
+ /** Logical clock used to stamp checkpoints. Defaults to a deterministic counter. */
261
+ now?: () => number;
262
+ /** Maximum retained checkpoints. Branch heads are never collected. Default 1,000. */
263
+ maxCheckpoints?: number;
264
+ /** Customize deterministic checkpoint IDs. */
265
+ id?: (sequence: number) => CheckpointId;
266
+ };
267
+ type CommitOptions = {
268
+ branch?: string;
269
+ /** Parent checkpoint. Defaults to the selected branch's current head. */
270
+ parent?: CheckpointId | null;
271
+ };
272
+ type ForkOptions = {
273
+ /** Checkpoint to fork from. Defaults to the main branch's head. */
274
+ from?: CheckpointId;
275
+ };
276
+ /**
277
+ * Small, storage-agnostic checkpoint DAG shared by service runtimes. Its values may be immutable
278
+ * records, namespace images, or copy-on-write SQL engine snapshots.
279
+ *
280
+ * Values are retained by reference. Engines can therefore use persistent/COW snapshots while
281
+ * simpler services can use immutable values. IDs and GC order are deterministic, and all IO
282
+ * (the logical clock) is injected.
283
+ */
284
+ declare class Timeline<T> {
285
+ readonly maxCheckpoints: number;
286
+ private readonly now;
287
+ private readonly makeId;
288
+ private readonly nodes;
289
+ private readonly heads;
290
+ /** Unreferenced nodes in the exact order they became collectible. */
291
+ private readonly evictable;
292
+ /** Branch heads plus explicit retainers. Absent means zero. */
293
+ private readonly references;
294
+ private readonly explicitPins;
295
+ private sequence;
296
+ constructor(options?: TimelineOptions);
297
+ /** Capture a new immutable value and move `branch` to it. */
298
+ commit(value: T, options?: CommitOptions): Checkpoint<T>;
299
+ /** Create a branch pointer without copying its checkpoint value. */
300
+ fork(branch: string, options?: ForkOptions): Checkpoint<T> | undefined;
301
+ /** Move a branch pointer to an existing checkpoint. */
302
+ checkout(branch: string, id: CheckpointId): Checkpoint<T>;
303
+ get(id: CheckpointId): Checkpoint<T>;
304
+ head(branch?: string): Checkpoint<T> | undefined;
305
+ hasBranch(branch: string): boolean;
306
+ branches(): Readonly<Record<string, CheckpointId>>;
307
+ checkpoints(): readonly Checkpoint<T>[];
308
+ /** Number of retained checkpoints without allocating an array. */
309
+ get size(): number;
310
+ /** Pin a checkpoint independently of branch heads (used by compatibility snapshot handles). */
311
+ retain(id: CheckpointId): Checkpoint<T>;
312
+ /** Release one explicit pin. Branch heads remain pinned until moved or deleted. */
313
+ release(id: CheckpointId): boolean;
314
+ deleteBranch(branch: string): boolean;
315
+ /**
316
+ * Deterministically discard oldest unpinned checkpoints. Collection is O(number removed):
317
+ * commits never scan pinned nodes or the retained history. Parents are metadata rather than a
318
+ * storage dependency, so a retained node remains usable after pruning.
319
+ */
320
+ gc(max?: number): CheckpointId[];
321
+ private collect;
322
+ private moveHead;
323
+ private addReference;
324
+ private removeReference;
325
+ private assertBranch;
326
+ }
327
+
266
328
  /**
267
329
  * Anything that can answer a Fetch `Request` with a `Response`.
268
330
  *
@@ -273,6 +335,28 @@ interface FetchAPI$1 {
273
335
  fetch(request: Request): Promise<Response>;
274
336
  }
275
337
 
338
+ /**
339
+ * A point-in-time copy of everything a service namespace holds.
340
+ *
341
+ * All service state lives in the two core tables keyed by namespace, so a snapshot
342
+ * is generic: any service gets per-test rollback without knowing its own schema.
343
+ * Restoring is much cheaper than rebuilding a namespace from a corpus.
344
+ */
345
+ type NamespaceSnapshot = {
346
+ namespace: string;
347
+ records: {
348
+ collection: string;
349
+ id: string;
350
+ seq: number;
351
+ value: string;
352
+ }[];
353
+ sequences: {
354
+ name: string;
355
+ kind: string;
356
+ value: number;
357
+ }[];
358
+ };
359
+
276
360
  type WebhookEndpoint$1 = {
277
361
  /** Stable id; generated when omitted. */
278
362
  id?: string;
@@ -293,6 +377,7 @@ type WebhookMessage = {
293
377
  body: string;
294
378
  contentType: string;
295
379
  tags: Record<string, string>;
380
+ headers?: Record<string, string>;
296
381
  /** Wall-clock ISO-8601 time of publication. */
297
382
  publishedAt: string;
298
383
  };
@@ -302,6 +387,8 @@ type WebhookAttempt$1 = {
302
387
  status: number | null;
303
388
  error: string | null;
304
389
  durationMs: number;
390
+ /** Exact receiver response body, when one was returned. */
391
+ responseBody?: string | null;
305
392
  };
306
393
  type WebhookDelivery$1 = {
307
394
  id: string;
@@ -329,6 +416,8 @@ type PublishInput = {
329
416
  /** Form parameters, when the vendor posts `application/x-www-form-urlencoded`. */
330
417
  form?: Record<string, string>;
331
418
  tags?: Record<string, string>;
419
+ /** Message-specific delivery headers, captured as part of durable message state. */
420
+ headers?: Record<string, string>;
332
421
  /** Message id; generated when omitted. */
333
422
  id?: string;
334
423
  };
@@ -353,6 +442,12 @@ type WebhookHub = {
353
442
  type ServiceInstance = FetchAPI$1 & {
354
443
  reset(): Promise<void>;
355
444
  };
445
+ type ServiceTimelineState = Readonly<{
446
+ snapshot: NamespaceSnapshot;
447
+ clock: Readonly<ReturnType<Clock["state"]>>;
448
+ rngState: number;
449
+ }>;
450
+ type ServiceCheckpoint = Checkpoint<ServiceTimelineState>;
356
451
  type ServiceRuntime<T extends ServiceInstance> = FetchAPI$1 & {
357
452
  readonly name: string;
358
453
  readonly sqlite: SqliteClient$1;
@@ -374,6 +469,20 @@ type ServiceRuntime<T extends ServiceInstance> = FetchAPI$1 & {
374
469
  reset(namespace?: string): Promise<void>;
375
470
  snapshot(namespace?: string): NamespaceSnapshot;
376
471
  restore(snapshot: NamespaceSnapshot, namespace?: string): void;
472
+ /** Capture the current branch. Mutating HTTP calls do this automatically. */
473
+ checkpoint(namespace?: string, branch?: string): ServiceCheckpoint;
474
+ /** Create an isolated branch, optionally from a historical checkpoint. */
475
+ branch(name: string, options?: {
476
+ namespace?: string;
477
+ at?: string;
478
+ }): ServiceCheckpoint;
479
+ /** Restore a branch, clock, and PRNG to a checkpoint. */
480
+ checkout(checkpoint: string, options?: {
481
+ namespace?: string;
482
+ branch?: string;
483
+ }): void;
484
+ /** Inspect the retained history for a namespace. */
485
+ timeline(namespace?: string): Timeline<ServiceTimelineState>;
377
486
  };
378
487
 
379
488
  /** Options every provider constructor accepts. */
@@ -882,6 +991,11 @@ type WebhookEndpoint = {
882
991
  /** Added to every delivery, e.g. a routing scope for a shared receiver. */
883
992
  headers?: Record<string, string>;
884
993
  fetch?: (request: Request) => Promise<Response>;
994
+ /** Injectable wall clock for signatures and delivery records. */
995
+ now?: () => number;
996
+ /** Injectable scheduler for timeouts and retry delays. */
997
+ schedule?: (callback: () => void, delayMs: number) => unknown;
998
+ cancel?: (handle: unknown) => void;
885
999
  };
886
1000
  type WebhookAttempt = {
887
1001
  attempt: number;
package/dist/index.js CHANGED
@@ -50,7 +50,7 @@ import {
50
50
  supportedOperationIds,
51
51
  verifyAgainstReal,
52
52
  verifySvix
53
- } from "./chunk-ICINEQ7D.js";
53
+ } from "./chunk-MS774AJA.js";
54
54
  import {
55
55
  SEALED_CORPUS_VERSION,
56
56
  SUPPORTED_SEALED_CORPUS_VERSIONS,
package/dist/server.d.ts CHANGED
@@ -74,6 +74,10 @@ type Rng$1 = {
74
74
  int(min: number, max: number): number;
75
75
  /** Restart the stream from its seed. */
76
76
  reset(): void;
77
+ /** Serializable engine state used by deterministic checkpoints. */
78
+ state(): number;
79
+ /** Restore a state previously returned by {@link state}. */
80
+ setState(state: number): void;
77
81
  seed: number;
78
82
  };
79
83
 
@@ -230,28 +234,6 @@ type Journal$1 = {
230
234
  clear(namespace?: string): void;
231
235
  };
232
236
 
233
- /**
234
- * A point-in-time copy of everything a service namespace holds.
235
- *
236
- * All service state lives in the two core tables keyed by namespace, so a snapshot
237
- * is generic: any service gets per-test rollback without knowing its own schema.
238
- * Restoring is much cheaper than rebuilding a namespace from a corpus.
239
- */
240
- type NamespaceSnapshot$1 = {
241
- namespace: string;
242
- records: {
243
- collection: string;
244
- id: string;
245
- seq: number;
246
- value: string;
247
- }[];
248
- sequences: {
249
- name: string;
250
- kind: string;
251
- value: number;
252
- }[];
253
- };
254
-
255
237
  /** Credential → namespace mapping behind `PUT /__admin/credentials`. */
256
238
  type CredentialRegistry$1 = {
257
239
  set(credential: string, namespace: string): void;
@@ -264,6 +246,86 @@ type CredentialRegistry$1 = {
264
246
  }[];
265
247
  };
266
248
 
249
+ /** A stable identifier for a point in a {@link Timeline}. */
250
+ type CheckpointId$1 = string;
251
+ /** An immutable node in a timeline's checkpoint DAG. */
252
+ type Checkpoint$1<T> = Readonly<{
253
+ id: CheckpointId$1;
254
+ branch: string;
255
+ parent: CheckpointId$1 | null;
256
+ /** Logical time supplied by the timeline's injected clock. */
257
+ at: number;
258
+ value: T;
259
+ }>;
260
+ type TimelineOptions$1 = {
261
+ /** Logical clock used to stamp checkpoints. Defaults to a deterministic counter. */
262
+ now?: () => number;
263
+ /** Maximum retained checkpoints. Branch heads are never collected. Default 1,000. */
264
+ maxCheckpoints?: number;
265
+ /** Customize deterministic checkpoint IDs. */
266
+ id?: (sequence: number) => CheckpointId$1;
267
+ };
268
+ type CommitOptions$1 = {
269
+ branch?: string;
270
+ /** Parent checkpoint. Defaults to the selected branch's current head. */
271
+ parent?: CheckpointId$1 | null;
272
+ };
273
+ type ForkOptions$1 = {
274
+ /** Checkpoint to fork from. Defaults to the main branch's head. */
275
+ from?: CheckpointId$1;
276
+ };
277
+ /**
278
+ * Small, storage-agnostic checkpoint DAG shared by service runtimes. Its values may be immutable
279
+ * records, namespace images, or copy-on-write SQL engine snapshots.
280
+ *
281
+ * Values are retained by reference. Engines can therefore use persistent/COW snapshots while
282
+ * simpler services can use immutable values. IDs and GC order are deterministic, and all IO
283
+ * (the logical clock) is injected.
284
+ */
285
+ declare class Timeline$1<T> {
286
+ readonly maxCheckpoints: number;
287
+ private readonly now;
288
+ private readonly makeId;
289
+ private readonly nodes;
290
+ private readonly heads;
291
+ /** Unreferenced nodes in the exact order they became collectible. */
292
+ private readonly evictable;
293
+ /** Branch heads plus explicit retainers. Absent means zero. */
294
+ private readonly references;
295
+ private readonly explicitPins;
296
+ private sequence;
297
+ constructor(options?: TimelineOptions$1);
298
+ /** Capture a new immutable value and move `branch` to it. */
299
+ commit(value: T, options?: CommitOptions$1): Checkpoint$1<T>;
300
+ /** Create a branch pointer without copying its checkpoint value. */
301
+ fork(branch: string, options?: ForkOptions$1): Checkpoint$1<T> | undefined;
302
+ /** Move a branch pointer to an existing checkpoint. */
303
+ checkout(branch: string, id: CheckpointId$1): Checkpoint$1<T>;
304
+ get(id: CheckpointId$1): Checkpoint$1<T>;
305
+ head(branch?: string): Checkpoint$1<T> | undefined;
306
+ hasBranch(branch: string): boolean;
307
+ branches(): Readonly<Record<string, CheckpointId$1>>;
308
+ checkpoints(): readonly Checkpoint$1<T>[];
309
+ /** Number of retained checkpoints without allocating an array. */
310
+ get size(): number;
311
+ /** Pin a checkpoint independently of branch heads (used by compatibility snapshot handles). */
312
+ retain(id: CheckpointId$1): Checkpoint$1<T>;
313
+ /** Release one explicit pin. Branch heads remain pinned until moved or deleted. */
314
+ release(id: CheckpointId$1): boolean;
315
+ deleteBranch(branch: string): boolean;
316
+ /**
317
+ * Deterministically discard oldest unpinned checkpoints. Collection is O(number removed):
318
+ * commits never scan pinned nodes or the retained history. Parents are metadata rather than a
319
+ * storage dependency, so a retained node remains usable after pruning.
320
+ */
321
+ gc(max?: number): CheckpointId$1[];
322
+ private collect;
323
+ private moveHead;
324
+ private addReference;
325
+ private removeReference;
326
+ private assertBranch;
327
+ }
328
+
267
329
  /**
268
330
  * Anything that can answer a Fetch `Request` with a `Response`.
269
331
  *
@@ -274,6 +336,28 @@ interface FetchAPI$2 {
274
336
  fetch(request: Request): Promise<Response>;
275
337
  }
276
338
 
339
+ /**
340
+ * A point-in-time copy of everything a service namespace holds.
341
+ *
342
+ * All service state lives in the two core tables keyed by namespace, so a snapshot
343
+ * is generic: any service gets per-test rollback without knowing its own schema.
344
+ * Restoring is much cheaper than rebuilding a namespace from a corpus.
345
+ */
346
+ type NamespaceSnapshot$1 = {
347
+ namespace: string;
348
+ records: {
349
+ collection: string;
350
+ id: string;
351
+ seq: number;
352
+ value: string;
353
+ }[];
354
+ sequences: {
355
+ name: string;
356
+ kind: string;
357
+ value: number;
358
+ }[];
359
+ };
360
+
277
361
  type WebhookEndpoint$2 = {
278
362
  /** Stable id; generated when omitted. */
279
363
  id?: string;
@@ -294,6 +378,7 @@ type WebhookMessage$1 = {
294
378
  body: string;
295
379
  contentType: string;
296
380
  tags: Record<string, string>;
381
+ headers?: Record<string, string>;
297
382
  /** Wall-clock ISO-8601 time of publication. */
298
383
  publishedAt: string;
299
384
  };
@@ -303,6 +388,8 @@ type WebhookAttempt$2 = {
303
388
  status: number | null;
304
389
  error: string | null;
305
390
  durationMs: number;
391
+ /** Exact receiver response body, when one was returned. */
392
+ responseBody?: string | null;
306
393
  };
307
394
  type WebhookDelivery$2 = {
308
395
  id: string;
@@ -330,6 +417,8 @@ type PublishInput$1 = {
330
417
  /** Form parameters, when the vendor posts `application/x-www-form-urlencoded`. */
331
418
  form?: Record<string, string>;
332
419
  tags?: Record<string, string>;
420
+ /** Message-specific delivery headers, captured as part of durable message state. */
421
+ headers?: Record<string, string>;
333
422
  /** Message id; generated when omitted. */
334
423
  id?: string;
335
424
  };
@@ -354,6 +443,12 @@ type WebhookHub$1 = {
354
443
  type ServiceInstance$1 = FetchAPI$2 & {
355
444
  reset(): Promise<void>;
356
445
  };
446
+ type ServiceTimelineState$1 = Readonly<{
447
+ snapshot: NamespaceSnapshot$1;
448
+ clock: Readonly<ReturnType<Clock$1["state"]>>;
449
+ rngState: number;
450
+ }>;
451
+ type ServiceCheckpoint$1 = Checkpoint$1<ServiceTimelineState$1>;
357
452
  type ServiceRuntime$1<T extends ServiceInstance$1> = FetchAPI$2 & {
358
453
  readonly name: string;
359
454
  readonly sqlite: SqliteClient$2;
@@ -375,6 +470,20 @@ type ServiceRuntime$1<T extends ServiceInstance$1> = FetchAPI$2 & {
375
470
  reset(namespace?: string): Promise<void>;
376
471
  snapshot(namespace?: string): NamespaceSnapshot$1;
377
472
  restore(snapshot: NamespaceSnapshot$1, namespace?: string): void;
473
+ /** Capture the current branch. Mutating HTTP calls do this automatically. */
474
+ checkpoint(namespace?: string, branch?: string): ServiceCheckpoint$1;
475
+ /** Create an isolated branch, optionally from a historical checkpoint. */
476
+ branch(name: string, options?: {
477
+ namespace?: string;
478
+ at?: string;
479
+ }): ServiceCheckpoint$1;
480
+ /** Restore a branch, clock, and PRNG to a checkpoint. */
481
+ checkout(checkpoint: string, options?: {
482
+ namespace?: string;
483
+ branch?: string;
484
+ }): void;
485
+ /** Inspect the retained history for a namespace. */
486
+ timeline(namespace?: string): Timeline$1<ServiceTimelineState$1>;
378
487
  };
379
488
 
380
489
  type CliOption = {
@@ -487,6 +596,10 @@ type Rng = {
487
596
  int(min: number, max: number): number;
488
597
  /** Restart the stream from its seed. */
489
598
  reset(): void;
599
+ /** Serializable engine state used by deterministic checkpoints. */
600
+ state(): number;
601
+ /** Restore a state previously returned by {@link state}. */
602
+ setState(state: number): void;
490
603
  seed: number;
491
604
  };
492
605
 
@@ -643,28 +756,6 @@ type Journal = {
643
756
  clear(namespace?: string): void;
644
757
  };
645
758
 
646
- /**
647
- * A point-in-time copy of everything a service namespace holds.
648
- *
649
- * All service state lives in the two core tables keyed by namespace, so a snapshot
650
- * is generic: any service gets per-test rollback without knowing its own schema.
651
- * Restoring is much cheaper than rebuilding a namespace from a corpus.
652
- */
653
- type NamespaceSnapshot = {
654
- namespace: string;
655
- records: {
656
- collection: string;
657
- id: string;
658
- seq: number;
659
- value: string;
660
- }[];
661
- sequences: {
662
- name: string;
663
- kind: string;
664
- value: number;
665
- }[];
666
- };
667
-
668
759
  /** Credential → namespace mapping behind `PUT /__admin/credentials`. */
669
760
  type CredentialRegistry = {
670
761
  set(credential: string, namespace: string): void;
@@ -677,6 +768,86 @@ type CredentialRegistry = {
677
768
  }[];
678
769
  };
679
770
 
771
+ /** A stable identifier for a point in a {@link Timeline}. */
772
+ type CheckpointId = string;
773
+ /** An immutable node in a timeline's checkpoint DAG. */
774
+ type Checkpoint<T> = Readonly<{
775
+ id: CheckpointId;
776
+ branch: string;
777
+ parent: CheckpointId | null;
778
+ /** Logical time supplied by the timeline's injected clock. */
779
+ at: number;
780
+ value: T;
781
+ }>;
782
+ type TimelineOptions = {
783
+ /** Logical clock used to stamp checkpoints. Defaults to a deterministic counter. */
784
+ now?: () => number;
785
+ /** Maximum retained checkpoints. Branch heads are never collected. Default 1,000. */
786
+ maxCheckpoints?: number;
787
+ /** Customize deterministic checkpoint IDs. */
788
+ id?: (sequence: number) => CheckpointId;
789
+ };
790
+ type CommitOptions = {
791
+ branch?: string;
792
+ /** Parent checkpoint. Defaults to the selected branch's current head. */
793
+ parent?: CheckpointId | null;
794
+ };
795
+ type ForkOptions = {
796
+ /** Checkpoint to fork from. Defaults to the main branch's head. */
797
+ from?: CheckpointId;
798
+ };
799
+ /**
800
+ * Small, storage-agnostic checkpoint DAG shared by service runtimes. Its values may be immutable
801
+ * records, namespace images, or copy-on-write SQL engine snapshots.
802
+ *
803
+ * Values are retained by reference. Engines can therefore use persistent/COW snapshots while
804
+ * simpler services can use immutable values. IDs and GC order are deterministic, and all IO
805
+ * (the logical clock) is injected.
806
+ */
807
+ declare class Timeline<T> {
808
+ readonly maxCheckpoints: number;
809
+ private readonly now;
810
+ private readonly makeId;
811
+ private readonly nodes;
812
+ private readonly heads;
813
+ /** Unreferenced nodes in the exact order they became collectible. */
814
+ private readonly evictable;
815
+ /** Branch heads plus explicit retainers. Absent means zero. */
816
+ private readonly references;
817
+ private readonly explicitPins;
818
+ private sequence;
819
+ constructor(options?: TimelineOptions);
820
+ /** Capture a new immutable value and move `branch` to it. */
821
+ commit(value: T, options?: CommitOptions): Checkpoint<T>;
822
+ /** Create a branch pointer without copying its checkpoint value. */
823
+ fork(branch: string, options?: ForkOptions): Checkpoint<T> | undefined;
824
+ /** Move a branch pointer to an existing checkpoint. */
825
+ checkout(branch: string, id: CheckpointId): Checkpoint<T>;
826
+ get(id: CheckpointId): Checkpoint<T>;
827
+ head(branch?: string): Checkpoint<T> | undefined;
828
+ hasBranch(branch: string): boolean;
829
+ branches(): Readonly<Record<string, CheckpointId>>;
830
+ checkpoints(): readonly Checkpoint<T>[];
831
+ /** Number of retained checkpoints without allocating an array. */
832
+ get size(): number;
833
+ /** Pin a checkpoint independently of branch heads (used by compatibility snapshot handles). */
834
+ retain(id: CheckpointId): Checkpoint<T>;
835
+ /** Release one explicit pin. Branch heads remain pinned until moved or deleted. */
836
+ release(id: CheckpointId): boolean;
837
+ deleteBranch(branch: string): boolean;
838
+ /**
839
+ * Deterministically discard oldest unpinned checkpoints. Collection is O(number removed):
840
+ * commits never scan pinned nodes or the retained history. Parents are metadata rather than a
841
+ * storage dependency, so a retained node remains usable after pruning.
842
+ */
843
+ gc(max?: number): CheckpointId[];
844
+ private collect;
845
+ private moveHead;
846
+ private addReference;
847
+ private removeReference;
848
+ private assertBranch;
849
+ }
850
+
680
851
  /**
681
852
  * Anything that can answer a Fetch `Request` with a `Response`.
682
853
  *
@@ -687,6 +858,28 @@ interface FetchAPI$1 {
687
858
  fetch(request: Request): Promise<Response>;
688
859
  }
689
860
 
861
+ /**
862
+ * A point-in-time copy of everything a service namespace holds.
863
+ *
864
+ * All service state lives in the two core tables keyed by namespace, so a snapshot
865
+ * is generic: any service gets per-test rollback without knowing its own schema.
866
+ * Restoring is much cheaper than rebuilding a namespace from a corpus.
867
+ */
868
+ type NamespaceSnapshot = {
869
+ namespace: string;
870
+ records: {
871
+ collection: string;
872
+ id: string;
873
+ seq: number;
874
+ value: string;
875
+ }[];
876
+ sequences: {
877
+ name: string;
878
+ kind: string;
879
+ value: number;
880
+ }[];
881
+ };
882
+
690
883
  type WebhookEndpoint$1 = {
691
884
  /** Stable id; generated when omitted. */
692
885
  id?: string;
@@ -707,6 +900,7 @@ type WebhookMessage = {
707
900
  body: string;
708
901
  contentType: string;
709
902
  tags: Record<string, string>;
903
+ headers?: Record<string, string>;
710
904
  /** Wall-clock ISO-8601 time of publication. */
711
905
  publishedAt: string;
712
906
  };
@@ -716,6 +910,8 @@ type WebhookAttempt$1 = {
716
910
  status: number | null;
717
911
  error: string | null;
718
912
  durationMs: number;
913
+ /** Exact receiver response body, when one was returned. */
914
+ responseBody?: string | null;
719
915
  };
720
916
  type WebhookDelivery$1 = {
721
917
  id: string;
@@ -743,6 +939,8 @@ type PublishInput = {
743
939
  /** Form parameters, when the vendor posts `application/x-www-form-urlencoded`. */
744
940
  form?: Record<string, string>;
745
941
  tags?: Record<string, string>;
942
+ /** Message-specific delivery headers, captured as part of durable message state. */
943
+ headers?: Record<string, string>;
746
944
  /** Message id; generated when omitted. */
747
945
  id?: string;
748
946
  };
@@ -767,6 +965,12 @@ type WebhookHub = {
767
965
  type ServiceInstance = FetchAPI$1 & {
768
966
  reset(): Promise<void>;
769
967
  };
968
+ type ServiceTimelineState = Readonly<{
969
+ snapshot: NamespaceSnapshot;
970
+ clock: Readonly<ReturnType<Clock["state"]>>;
971
+ rngState: number;
972
+ }>;
973
+ type ServiceCheckpoint = Checkpoint<ServiceTimelineState>;
770
974
  type ServiceRuntime<T extends ServiceInstance> = FetchAPI$1 & {
771
975
  readonly name: string;
772
976
  readonly sqlite: SqliteClient$1;
@@ -788,6 +992,20 @@ type ServiceRuntime<T extends ServiceInstance> = FetchAPI$1 & {
788
992
  reset(namespace?: string): Promise<void>;
789
993
  snapshot(namespace?: string): NamespaceSnapshot;
790
994
  restore(snapshot: NamespaceSnapshot, namespace?: string): void;
995
+ /** Capture the current branch. Mutating HTTP calls do this automatically. */
996
+ checkpoint(namespace?: string, branch?: string): ServiceCheckpoint;
997
+ /** Create an isolated branch, optionally from a historical checkpoint. */
998
+ branch(name: string, options?: {
999
+ namespace?: string;
1000
+ at?: string;
1001
+ }): ServiceCheckpoint;
1002
+ /** Restore a branch, clock, and PRNG to a checkpoint. */
1003
+ checkout(checkpoint: string, options?: {
1004
+ namespace?: string;
1005
+ branch?: string;
1006
+ }): void;
1007
+ /** Inspect the retained history for a namespace. */
1008
+ timeline(namespace?: string): Timeline<ServiceTimelineState>;
791
1009
  };
792
1010
 
793
1011
  /** Options every provider constructor accepts. */
@@ -1229,6 +1447,11 @@ type WebhookEndpoint = {
1229
1447
  /** Added to every delivery, e.g. a routing scope for a shared receiver. */
1230
1448
  headers?: Record<string, string>;
1231
1449
  fetch?: (request: Request) => Promise<Response>;
1450
+ /** Injectable wall clock for signatures and delivery records. */
1451
+ now?: () => number;
1452
+ /** Injectable scheduler for timeouts and retry delays. */
1453
+ schedule?: (callback: () => void, delayMs: number) => unknown;
1454
+ cancel?: (handle: unknown) => void;
1232
1455
  };
1233
1456
  type WebhookAttempt = {
1234
1457
  attempt: number;