@crvouga/mockingbird-service-formbricks 2.1.0 → 2.3.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/server.d.ts CHANGED
@@ -1,6 +1,125 @@
1
1
  import { Server } from 'node:http';
2
2
  import { Hono } from 'hono';
3
3
 
4
+ /** Bind values accepted by Mockingbird's SQLite port (matches sqlite-mem / better-sqlite3). */
5
+ type SqliteValue$2 = null | number | bigint | string | Uint8Array | boolean;
6
+ /** Mutation counters returned by {@link SqliteStatement.run}. */
7
+ type SqliteRunResult$2 = {
8
+ changes: number;
9
+ lastInsertRowid: number | bigint;
10
+ };
11
+ /**
12
+ * Prepared statement bound to a {@link SqliteClient}.
13
+ *
14
+ * Pass bind values as rest arguments on each call (no sticky `bind()`).
15
+ */
16
+ interface SqliteStatement$2 {
17
+ run(...params: SqliteValue$2[]): SqliteRunResult$2;
18
+ all<T = Record<string, unknown>>(...params: SqliteValue$2[]): T[];
19
+ get<T = Record<string, unknown>>(...params: SqliteValue$2[]): T | undefined;
20
+ }
21
+ /**
22
+ * Sync SQLite client port owned by Mockingbird.
23
+ *
24
+ * Duck-typed so `@crvouga/mockingbird-service-sqlite` `Database`, better-sqlite3, and wrapped
25
+ * `bun:sqlite` instances all work when they expose this surface.
26
+ */
27
+ interface SqliteClient$2 {
28
+ exec(sql: string): void;
29
+ prepare(sql: string): SqliteStatement$2;
30
+ transaction<T>(fn: () => T): T;
31
+ }
32
+
33
+ /** A stable identifier for a point in a {@link Timeline}. */
34
+ type CheckpointId$1 = string;
35
+ /** An immutable node in a timeline's checkpoint DAG. */
36
+ type Checkpoint$1<T> = Readonly<{
37
+ id: CheckpointId$1;
38
+ branch: string;
39
+ parent: CheckpointId$1 | null;
40
+ /** Logical time supplied by the timeline's injected clock. */
41
+ at: number;
42
+ value: T;
43
+ }>;
44
+ type TimelineOptions$1 = {
45
+ /** Logical clock used to stamp checkpoints. Defaults to a deterministic counter. */
46
+ now?: () => number;
47
+ /** Maximum retained checkpoints. Branch heads are never collected. Default 1,000. */
48
+ maxCheckpoints?: number;
49
+ /** Customize deterministic checkpoint IDs. */
50
+ id?: (sequence: number) => CheckpointId$1;
51
+ };
52
+ type CommitOptions$1 = {
53
+ branch?: string;
54
+ /** Parent checkpoint. Defaults to the selected branch's current head. */
55
+ parent?: CheckpointId$1 | null;
56
+ };
57
+ type ForkOptions$1 = {
58
+ /** Checkpoint to fork from. Defaults to the main branch's head. */
59
+ from?: CheckpointId$1;
60
+ };
61
+ /**
62
+ * Small, storage-agnostic checkpoint DAG shared by service runtimes. Its values may be immutable
63
+ * records, namespace images, or copy-on-write SQL engine snapshots.
64
+ *
65
+ * Values are retained by reference. Engines can therefore use persistent/COW snapshots while
66
+ * simpler services can use immutable values. IDs and GC order are deterministic, and all IO
67
+ * (the logical clock) is injected.
68
+ */
69
+ declare class Timeline$1<T> {
70
+ readonly maxCheckpoints: number;
71
+ private readonly now;
72
+ private readonly makeId;
73
+ private readonly nodes;
74
+ private readonly heads;
75
+ /** Unreferenced nodes in the exact order they became collectible. */
76
+ private readonly evictable;
77
+ /** Branch heads plus explicit retainers. Absent means zero. */
78
+ private readonly references;
79
+ private readonly explicitPins;
80
+ private sequence;
81
+ constructor(options?: TimelineOptions$1);
82
+ /** Capture a new immutable value and move `branch` to it. */
83
+ commit(value: T, options?: CommitOptions$1): Checkpoint$1<T>;
84
+ /** Create a branch pointer without copying its checkpoint value. */
85
+ fork(branch: string, options?: ForkOptions$1): Checkpoint$1<T> | undefined;
86
+ /** Move a branch pointer to an existing checkpoint. */
87
+ checkout(branch: string, id: CheckpointId$1): Checkpoint$1<T>;
88
+ get(id: CheckpointId$1): Checkpoint$1<T>;
89
+ head(branch?: string): Checkpoint$1<T> | undefined;
90
+ hasBranch(branch: string): boolean;
91
+ branches(): Readonly<Record<string, CheckpointId$1>>;
92
+ checkpoints(): readonly Checkpoint$1<T>[];
93
+ /** Number of retained checkpoints without allocating an array. */
94
+ get size(): number;
95
+ /** Pin a checkpoint independently of branch heads (used by compatibility snapshot handles). */
96
+ retain(id: CheckpointId$1): Checkpoint$1<T>;
97
+ /** Release one explicit pin. Branch heads remain pinned until moved or deleted. */
98
+ release(id: CheckpointId$1): boolean;
99
+ deleteBranch(branch: string): boolean;
100
+ /**
101
+ * Deterministically discard oldest unpinned checkpoints. Collection is O(number removed):
102
+ * commits never scan pinned nodes or the retained history. Parents are metadata rather than a
103
+ * storage dependency, so a retained node remains usable after pruning.
104
+ */
105
+ gc(max?: number): CheckpointId$1[];
106
+ private collect;
107
+ private moveHead;
108
+ private addReference;
109
+ private removeReference;
110
+ private assertBranch;
111
+ }
112
+
113
+ /**
114
+ * Anything that can answer a Fetch `Request` with a `Response`.
115
+ *
116
+ * Every Mockingbird service implements this, and every runtime adapter consumes it.
117
+ * It is the only contract shared across the whole graph.
118
+ */
119
+ interface FetchAPI$2 {
120
+ fetch(request: Request): Promise<Response>;
121
+ }
122
+
4
123
  /**
5
124
  * The single source of time for a service.
6
125
  *
@@ -31,35 +150,6 @@ type Clock$1 = {
31
150
  state(): ClockState$1;
32
151
  };
33
152
 
34
- /** Bind values accepted by Mockingbird's SQLite port (matches sqlite-mem / better-sqlite3). */
35
- type SqliteValue$2 = null | number | bigint | string | Uint8Array | boolean;
36
- /** Mutation counters returned by {@link SqliteStatement.run}. */
37
- type SqliteRunResult$2 = {
38
- changes: number;
39
- lastInsertRowid: number | bigint;
40
- };
41
- /**
42
- * Prepared statement bound to a {@link SqliteClient}.
43
- *
44
- * Pass bind values as rest arguments on each call (no sticky `bind()`).
45
- */
46
- interface SqliteStatement$2 {
47
- run(...params: SqliteValue$2[]): SqliteRunResult$2;
48
- all<T = Record<string, unknown>>(...params: SqliteValue$2[]): T[];
49
- get<T = Record<string, unknown>>(...params: SqliteValue$2[]): T | undefined;
50
- }
51
- /**
52
- * Sync SQLite client port owned by Mockingbird.
53
- *
54
- * Duck-typed so `@crvouga/mockingbird-service-sqlite` `Database`, better-sqlite3, and wrapped
55
- * `bun:sqlite` instances all work when they expose this surface.
56
- */
57
- interface SqliteClient$2 {
58
- exec(sql: string): void;
59
- prepare(sql: string): SqliteStatement$2;
60
- transaction<T>(fn: () => T): T;
61
- }
62
-
63
153
  /**
64
154
  * Seeded pseudo-random numbers, so anything a mock invents — ids, jitter, which
65
155
  * request a percentage fault hits — is reproducible from a seed.
@@ -187,96 +277,6 @@ type FaultRegistry$1 = {
187
277
  take(candidate: FaultCandidate$1): Promise<FaultHit$1[]>;
188
278
  };
189
279
 
190
- /** A stable identifier for a point in a {@link Timeline}. */
191
- type CheckpointId$1 = string;
192
- /** An immutable node in a timeline's checkpoint DAG. */
193
- type Checkpoint$1<T> = Readonly<{
194
- id: CheckpointId$1;
195
- branch: string;
196
- parent: CheckpointId$1 | null;
197
- /** Logical time supplied by the timeline's injected clock. */
198
- at: number;
199
- value: T;
200
- }>;
201
- type TimelineOptions$1 = {
202
- /** Logical clock used to stamp checkpoints. Defaults to a deterministic counter. */
203
- now?: () => number;
204
- /** Maximum retained checkpoints. Branch heads are never collected. Default 1,000. */
205
- maxCheckpoints?: number;
206
- /** Customize deterministic checkpoint IDs. */
207
- id?: (sequence: number) => CheckpointId$1;
208
- };
209
- type CommitOptions$1 = {
210
- branch?: string;
211
- /** Parent checkpoint. Defaults to the selected branch's current head. */
212
- parent?: CheckpointId$1 | null;
213
- };
214
- type ForkOptions$1 = {
215
- /** Checkpoint to fork from. Defaults to the main branch's head. */
216
- from?: CheckpointId$1;
217
- };
218
- /**
219
- * Small, storage-agnostic checkpoint DAG shared by service runtimes. Its values may be immutable
220
- * records, namespace images, or copy-on-write SQL engine snapshots.
221
- *
222
- * Values are retained by reference. Engines can therefore use persistent/COW snapshots while
223
- * simpler services can use immutable values. IDs and GC order are deterministic, and all IO
224
- * (the logical clock) is injected.
225
- */
226
- declare class Timeline$1<T> {
227
- readonly maxCheckpoints: number;
228
- private readonly now;
229
- private readonly makeId;
230
- private readonly nodes;
231
- private readonly heads;
232
- /** Unreferenced nodes in the exact order they became collectible. */
233
- private readonly evictable;
234
- /** Branch heads plus explicit retainers. Absent means zero. */
235
- private readonly references;
236
- private readonly explicitPins;
237
- private sequence;
238
- constructor(options?: TimelineOptions$1);
239
- /** Capture a new immutable value and move `branch` to it. */
240
- commit(value: T, options?: CommitOptions$1): Checkpoint$1<T>;
241
- /** Create a branch pointer without copying its checkpoint value. */
242
- fork(branch: string, options?: ForkOptions$1): Checkpoint$1<T> | undefined;
243
- /** Move a branch pointer to an existing checkpoint. */
244
- checkout(branch: string, id: CheckpointId$1): Checkpoint$1<T>;
245
- get(id: CheckpointId$1): Checkpoint$1<T>;
246
- head(branch?: string): Checkpoint$1<T> | undefined;
247
- hasBranch(branch: string): boolean;
248
- branches(): Readonly<Record<string, CheckpointId$1>>;
249
- checkpoints(): readonly Checkpoint$1<T>[];
250
- /** Number of retained checkpoints without allocating an array. */
251
- get size(): number;
252
- /** Pin a checkpoint independently of branch heads (used by compatibility snapshot handles). */
253
- retain(id: CheckpointId$1): Checkpoint$1<T>;
254
- /** Release one explicit pin. Branch heads remain pinned until moved or deleted. */
255
- release(id: CheckpointId$1): boolean;
256
- deleteBranch(branch: string): boolean;
257
- /**
258
- * Deterministically discard oldest unpinned checkpoints. Collection is O(number removed):
259
- * commits never scan pinned nodes or the retained history. Parents are metadata rather than a
260
- * storage dependency, so a retained node remains usable after pruning.
261
- */
262
- gc(max?: number): CheckpointId$1[];
263
- private collect;
264
- private moveHead;
265
- private addReference;
266
- private removeReference;
267
- private assertBranch;
268
- }
269
-
270
- /**
271
- * Anything that can answer a Fetch `Request` with a `Response`.
272
- *
273
- * Every Mockingbird service implements this, and every runtime adapter consumes it.
274
- * It is the only contract shared across the whole graph.
275
- */
276
- interface FetchAPI$2 {
277
- fetch(request: Request): Promise<Response>;
278
- }
279
-
280
280
  /**
281
281
  * One problem with a request body, at a dotted path (`patient.address.city`, `items.0.sku`).
282
282
  * `kind` is `media_type` when the body is present but its media type is not one the operation
@@ -318,6 +318,10 @@ type RequestLog$1 = {
318
318
  ids?: Record<string, string>;
319
319
  /** Set when the service created a resource the request referred to but that did not exist. */
320
320
  adopted?: boolean;
321
+ /** Explicit durable acceptance, independent of response delivery. */
322
+ accepted?: boolean;
323
+ /** Checkpoint captured at explicit acceptance. */
324
+ checkpoint?: string;
321
325
  /** Set on a rejection (status ≥ 400) the mock produced itself, never on a scripted fault. */
322
326
  request?: RejectedRequest$1;
323
327
  /** The validation issues behind a rejection, when the service found any. */
@@ -615,47 +619,17 @@ type ServeTarget = {
615
619
  listening?(server: Listening): void;
616
620
  };
617
621
 
622
+ /** Bind values accepted by Mockingbird's SQLite port (matches sqlite-mem / better-sqlite3). */
623
+ type SqliteValue$1 = null | number | bigint | string | Uint8Array | boolean;
624
+ /** Mutation counters returned by {@link SqliteStatement.run}. */
625
+ type SqliteRunResult$1 = {
626
+ changes: number;
627
+ lastInsertRowid: number | bigint;
628
+ };
618
629
  /**
619
- * The single source of time for a service.
630
+ * Prepared statement bound to a {@link SqliteClient}.
620
631
  *
621
- * Every timestamp a mock writes reads from here, so a suite moves time instead of
622
- * sleeping: appointment windows, result delays and expiries become reachable in
623
- * milliseconds. A frozen clock also makes timestamps reproducible from a seed.
624
- */
625
- type ClockState = {
626
- /** Current epoch milliseconds. */
627
- now: number;
628
- /** True while time does not advance on its own. */
629
- frozen: boolean;
630
- /** Milliseconds this clock adds to its underlying source. */
631
- offsetMs: number;
632
- };
633
- type Clock = {
634
- now(): number;
635
- /** Pin the clock to an exact instant, keeping it frozen if it already was. */
636
- set(epochMs: number): void;
637
- /** Move the clock forward, or back with a negative delta. */
638
- advance(deltaMs: number): void;
639
- /** Stop time at the current instant. */
640
- freeze(): void;
641
- /** Resume from the current instant. */
642
- unfreeze(): void;
643
- /** Drop back to the underlying source, live. */
644
- reset(): void;
645
- state(): ClockState;
646
- };
647
-
648
- /** Bind values accepted by Mockingbird's SQLite port (matches sqlite-mem / better-sqlite3). */
649
- type SqliteValue$1 = null | number | bigint | string | Uint8Array | boolean;
650
- /** Mutation counters returned by {@link SqliteStatement.run}. */
651
- type SqliteRunResult$1 = {
652
- changes: number;
653
- lastInsertRowid: number | bigint;
654
- };
655
- /**
656
- * Prepared statement bound to a {@link SqliteClient}.
657
- *
658
- * Pass bind values as rest arguments on each call (no sticky `bind()`).
632
+ * Pass bind values as rest arguments on each call (no sticky `bind()`).
659
633
  */
660
634
  interface SqliteStatement$1 {
661
635
  run(...params: SqliteValue$1[]): SqliteRunResult$1;
@@ -717,131 +691,16 @@ declare class Collection<T> {
717
691
  }
718
692
 
719
693
  /**
720
- * Seeded pseudo-random numbers, so anything a mock invents — ids, jitter, which
721
- * request a percentage fault hits — is reproducible from a seed.
722
- *
723
- * mulberry32: small, fast, and stable across runtimes, which matters more here
724
- * than statistical quality.
725
- */
726
- type Rng = {
727
- /** Next value in `[0, 1)`. */
728
- next(): number;
729
- /** Next integer in `[min, max]`. */
730
- int(min: number, max: number): number;
731
- /** Restart the stream from its seed. */
732
- reset(): void;
733
- /** Serializable engine state used by deterministic checkpoints. */
734
- state(): number;
735
- /** Restore a state previously returned by {@link state}. */
736
- setState(state: number): void;
737
- seed: number;
738
- };
739
-
740
- /**
741
- * A deliberate failure injected in front of an operation.
742
- *
743
- * This is how a suite reaches the vendor's failure modes without the vendor: the
744
- * quota error that only appears when a shared sandbox is full, the 429 that only
745
- * appears under load, the 5xx that proves a retry path works.
694
+ * Sequential id source persisted in SQLite. Ids are deterministic for a given
695
+ * sequence history (`cus_` + 14 opaque chars), so reproductions stay stable.
746
696
  */
747
- type FaultRule = {
748
- /** Stable id, so a suite can retire exactly the rule it added. */
749
- id: string;
750
- /** Fault only this operation. Omit to match every operation. */
751
- operationId?: string;
752
- /** Fault only this HTTP method, case-insensitive. Omit to match every method. */
753
- method?: string;
754
- /** Fault only paths starting with this prefix. Omit to match every path. */
755
- pathPrefix?: string;
756
- /**
757
- * Fault only this namespace. Omit (or `"*"`) to fault every namespace — which is what
758
- * an in-process caller usually wants, and what a parallel worker usually does not:
759
- * rules added through `POST /__admin/faults` default to the calling namespace.
760
- */
761
- namespace?: string;
762
- /**
763
- * Status of the injected response. Omit for a rule that only delays (`delayMs` /
764
- * `latencyMs`), only drops the connection (`drop`), or only switches on an `effect`:
765
- * the request then still reaches the service.
766
- */
767
- status?: number;
768
- /** Response body, serialized as JSON. A string is sent as-is. */
769
- body?: unknown;
770
- headers?: Record<string, string>;
771
- /** Retire the rule after this many faults. Omit to keep it until removed. */
772
- count?: number;
773
- /** Fault this fraction of matching requests, `0`–`1`. Default `1`. */
774
- rate?: number;
775
- /** Hold the response back this long, to exercise timeouts. */
776
- delayMs?: number;
777
- /** Alias of `delayMs`. */
778
- latencyMs?: number;
779
- /**
780
- * Drop the connection instead of answering: an in-process `fetch` rejects with a
781
- * `TypeError`, and a served mock destroys the socket. Models "unknown outcome" failures.
782
- */
783
- drop?: boolean;
784
- /**
785
- * A named service behaviour to switch on for the matching request instead of (or
786
- * before) a canned response, e.g. `created_but_500` or `numeric_tracking_id`. Services
787
- * read it with `faultEffects(request)`.
788
- */
789
- effect?: string;
790
- /** Parameters for `effect`. */
791
- params?: Record<string, unknown>;
792
- /** From the preset this rule was expanded from, if any. */
793
- preset?: string;
794
- };
795
- /** A fault that fired for one request. */
796
- type FaultHit = {
797
- id: string;
798
- /** The injected response; absent when the rule only delays, drops, or sets an effect. */
799
- response?: Response;
800
- drop?: boolean;
801
- effect?: {
802
- name: string;
803
- params: Record<string, unknown>;
804
- };
805
- };
806
- /** What a request looks like to the fault matcher. */
807
- type FaultCandidate = {
808
- operationId: string | undefined;
809
- method: string;
810
- path: string;
811
- namespace: string;
812
- };
813
- type FaultRegistry = {
814
- isolateNamespaces(): void;
815
- snapshot(namespace: string): {
816
- rules: (FaultRule & {
817
- remaining: number | null;
818
- hits: number;
819
- position: number;
820
- })[];
821
- rngState: number;
822
- };
823
- add(rule: FaultRule): FaultRule;
824
- list(): (FaultRule & {
825
- remaining: number | null;
826
- hits: number;
827
- })[];
828
- remove(id: string): boolean;
829
- clear(): void;
830
- restore(namespace: string, state: {
831
- rules: (FaultRule & {
832
- remaining: number | null;
833
- hits: number;
834
- position: number;
835
- })[];
836
- rngState: number;
837
- }): void;
838
- /**
839
- * Every fault this request should get, in rule order, stopping at the first that answers
840
- * or drops (effect-only and delay-only rules let later rules match too). Consumes one of
841
- * each matching rule's remaining uses.
842
- */
843
- take(candidate: FaultCandidate): Promise<FaultHit[]>;
844
- };
697
+ declare class IdSequence {
698
+ private readonly sqlite;
699
+ private readonly namespace;
700
+ private readonly salt;
701
+ constructor(sqlite: SqliteClient$1, namespace: string, salt?: string);
702
+ next(prefix: string, length?: number): string;
703
+ }
845
704
 
846
705
  /** A stable identifier for a point in a {@link Timeline}. */
847
706
  type CheckpointId = string;
@@ -1180,6 +1039,163 @@ type OperationContext = {
1180
1039
  now: () => number;
1181
1040
  };
1182
1041
 
1042
+ /**
1043
+ * The single source of time for a service.
1044
+ *
1045
+ * Every timestamp a mock writes reads from here, so a suite moves time instead of
1046
+ * sleeping: appointment windows, result delays and expiries become reachable in
1047
+ * milliseconds. A frozen clock also makes timestamps reproducible from a seed.
1048
+ */
1049
+ type ClockState = {
1050
+ /** Current epoch milliseconds. */
1051
+ now: number;
1052
+ /** True while time does not advance on its own. */
1053
+ frozen: boolean;
1054
+ /** Milliseconds this clock adds to its underlying source. */
1055
+ offsetMs: number;
1056
+ };
1057
+ type Clock = {
1058
+ now(): number;
1059
+ /** Pin the clock to an exact instant, keeping it frozen if it already was. */
1060
+ set(epochMs: number): void;
1061
+ /** Move the clock forward, or back with a negative delta. */
1062
+ advance(deltaMs: number): void;
1063
+ /** Stop time at the current instant. */
1064
+ freeze(): void;
1065
+ /** Resume from the current instant. */
1066
+ unfreeze(): void;
1067
+ /** Drop back to the underlying source, live. */
1068
+ reset(): void;
1069
+ state(): ClockState;
1070
+ };
1071
+
1072
+ /**
1073
+ * Seeded pseudo-random numbers, so anything a mock invents — ids, jitter, which
1074
+ * request a percentage fault hits — is reproducible from a seed.
1075
+ *
1076
+ * mulberry32: small, fast, and stable across runtimes, which matters more here
1077
+ * than statistical quality.
1078
+ */
1079
+ type Rng = {
1080
+ /** Next value in `[0, 1)`. */
1081
+ next(): number;
1082
+ /** Next integer in `[min, max]`. */
1083
+ int(min: number, max: number): number;
1084
+ /** Restart the stream from its seed. */
1085
+ reset(): void;
1086
+ /** Serializable engine state used by deterministic checkpoints. */
1087
+ state(): number;
1088
+ /** Restore a state previously returned by {@link state}. */
1089
+ setState(state: number): void;
1090
+ seed: number;
1091
+ };
1092
+
1093
+ /**
1094
+ * A deliberate failure injected in front of an operation.
1095
+ *
1096
+ * This is how a suite reaches the vendor's failure modes without the vendor: the
1097
+ * quota error that only appears when a shared sandbox is full, the 429 that only
1098
+ * appears under load, the 5xx that proves a retry path works.
1099
+ */
1100
+ type FaultRule = {
1101
+ /** Stable id, so a suite can retire exactly the rule it added. */
1102
+ id: string;
1103
+ /** Fault only this operation. Omit to match every operation. */
1104
+ operationId?: string;
1105
+ /** Fault only this HTTP method, case-insensitive. Omit to match every method. */
1106
+ method?: string;
1107
+ /** Fault only paths starting with this prefix. Omit to match every path. */
1108
+ pathPrefix?: string;
1109
+ /**
1110
+ * Fault only this namespace. Omit (or `"*"`) to fault every namespace — which is what
1111
+ * an in-process caller usually wants, and what a parallel worker usually does not:
1112
+ * rules added through `POST /__admin/faults` default to the calling namespace.
1113
+ */
1114
+ namespace?: string;
1115
+ /**
1116
+ * Status of the injected response. Omit for a rule that only delays (`delayMs` /
1117
+ * `latencyMs`), only drops the connection (`drop`), or only switches on an `effect`:
1118
+ * the request then still reaches the service.
1119
+ */
1120
+ status?: number;
1121
+ /** Response body, serialized as JSON. A string is sent as-is. */
1122
+ body?: unknown;
1123
+ headers?: Record<string, string>;
1124
+ /** Retire the rule after this many faults. Omit to keep it until removed. */
1125
+ count?: number;
1126
+ /** Fault this fraction of matching requests, `0`–`1`. Default `1`. */
1127
+ rate?: number;
1128
+ /** Hold the response back this long, to exercise timeouts. */
1129
+ delayMs?: number;
1130
+ /** Alias of `delayMs`. */
1131
+ latencyMs?: number;
1132
+ /**
1133
+ * Drop the connection instead of answering: an in-process `fetch` rejects with a
1134
+ * `TypeError`, and a served mock destroys the socket. Models "unknown outcome" failures.
1135
+ */
1136
+ drop?: boolean;
1137
+ /**
1138
+ * A named service behaviour to switch on for the matching request instead of (or
1139
+ * before) a canned response, e.g. `created_but_500` or `numeric_tracking_id`. Services
1140
+ * read it with `faultEffects(request)`.
1141
+ */
1142
+ effect?: string;
1143
+ /** Parameters for `effect`. */
1144
+ params?: Record<string, unknown>;
1145
+ /** From the preset this rule was expanded from, if any. */
1146
+ preset?: string;
1147
+ };
1148
+ /** A fault that fired for one request. */
1149
+ type FaultHit = {
1150
+ id: string;
1151
+ /** The injected response; absent when the rule only delays, drops, or sets an effect. */
1152
+ response?: Response;
1153
+ drop?: boolean;
1154
+ effect?: {
1155
+ name: string;
1156
+ params: Record<string, unknown>;
1157
+ };
1158
+ };
1159
+ /** What a request looks like to the fault matcher. */
1160
+ type FaultCandidate = {
1161
+ operationId: string | undefined;
1162
+ method: string;
1163
+ path: string;
1164
+ namespace: string;
1165
+ };
1166
+ type FaultRegistry = {
1167
+ isolateNamespaces(): void;
1168
+ snapshot(namespace: string): {
1169
+ rules: (FaultRule & {
1170
+ remaining: number | null;
1171
+ hits: number;
1172
+ position: number;
1173
+ })[];
1174
+ rngState: number;
1175
+ };
1176
+ add(rule: FaultRule): FaultRule;
1177
+ list(): (FaultRule & {
1178
+ remaining: number | null;
1179
+ hits: number;
1180
+ })[];
1181
+ remove(id: string): boolean;
1182
+ clear(): void;
1183
+ restore(namespace: string, state: {
1184
+ rules: (FaultRule & {
1185
+ remaining: number | null;
1186
+ hits: number;
1187
+ position: number;
1188
+ })[];
1189
+ rngState: number;
1190
+ }): void;
1191
+ /**
1192
+ * Every fault this request should get, in rule order, stopping at the first that answers
1193
+ * or drops (effect-only and delay-only rules let later rules match too). Consumes one of
1194
+ * each matching rule's remaining uses.
1195
+ */
1196
+ take(candidate: FaultCandidate): Promise<FaultHit[]>;
1197
+ };
1198
+
1183
1199
  /**
1184
1200
  * One problem with a request body, at a dotted path (`patient.address.city`, `items.0.sku`).
1185
1201
  * `kind` is `media_type` when the body is present but its media type is not one the operation
@@ -1221,6 +1237,10 @@ type RequestLog = {
1221
1237
  ids?: Record<string, string>;
1222
1238
  /** Set when the service created a resource the request referred to but that did not exist. */
1223
1239
  adopted?: boolean;
1240
+ /** Explicit durable acceptance, independent of response delivery. */
1241
+ accepted?: boolean;
1242
+ /** Checkpoint captured at explicit acceptance. */
1243
+ checkpoint?: string;
1224
1244
  /** Set on a rejection (status ≥ 400) the mock produced itself, never on a scripted fault. */
1225
1245
  request?: RejectedRequest;
1226
1246
  /** The validation issues behind a rejection, when the service found any. */
@@ -1284,18 +1304,6 @@ type CredentialRegistry = {
1284
1304
  }[];
1285
1305
  };
1286
1306
 
1287
- /**
1288
- * Sequential id source persisted in SQLite. Ids are deterministic for a given
1289
- * sequence history (`cus_` + 14 opaque chars), so reproductions stay stable.
1290
- */
1291
- declare class IdSequence {
1292
- private readonly sqlite;
1293
- private readonly namespace;
1294
- private readonly salt;
1295
- constructor(sqlite: SqliteClient$1, namespace: string, salt?: string);
1296
- next(prefix: string, length?: number): string;
1297
- }
1298
-
1299
1307
  /**
1300
1308
  * A point-in-time copy of everything a service namespace holds.
1301
1309
  *
package/dist/server.js CHANGED
@@ -2,8 +2,8 @@ import {
2
2
  DEFAULT_PORT,
3
3
  createServer,
4
4
  serveTarget
5
- } from "./chunk-VBJ5ARFE.js";
6
- import "./chunk-KIJQHMEA.js";
5
+ } from "./chunk-4KQ2ITDL.js";
6
+ import "./chunk-URWHM2ZP.js";
7
7
  export {
8
8
  DEFAULT_PORT,
9
9
  createServer,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crvouga/mockingbird-service-formbricks",
3
- "version": "2.1.0",
3
+ "version": "2.3.0",
4
4
  "description": "Stateful mock of open-source Formbricks: the client environment state (seeded with a synthetic survey corpus), response creation with upstream's validation and {code, message, details} errors, the v1 management API, the widget script, and signed response webhooks.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -97,7 +97,7 @@
97
97
  "pack:check": "bun ../../../scripts/pack-check.ts"
98
98
  },
99
99
  "dependencies": {
100
- "@crvouga/mockingbird-service-sqlite": "2.1.0",
100
+ "@crvouga/mockingbird-service-sqlite": "2.1.1",
101
101
  "hono": "4.11.9"
102
102
  },
103
103
  "devDependencies": {