@crvouga/mockingbird-service-posthog 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.
@@ -5,7 +5,7 @@ import {
5
5
  parseDuration,
6
6
  resolveAdminPrefix,
7
7
  specsFromState
8
- } from "./chunk-VZ3ZHVNW.js";
8
+ } from "./chunk-DBFEFLR4.js";
9
9
 
10
10
  // ../../adapters/node/dist/cli.js
11
11
  import { readFile as readFile2 } from "node:fs/promises";
@@ -844,4 +844,4 @@ export {
844
844
  createServer2 as createServer,
845
845
  serveTarget
846
846
  };
847
- //# sourceMappingURL=chunk-SCY2VOTE.js.map
847
+ //# sourceMappingURL=chunk-NCOO3LKB.js.map
package/dist/cli.js CHANGED
@@ -3,8 +3,8 @@ import {
3
3
  runCli,
4
4
  serveCommand,
5
5
  serveTarget
6
- } from "./chunk-SCY2VOTE.js";
7
- import "./chunk-VZ3ZHVNW.js";
6
+ } from "./chunk-NCOO3LKB.js";
7
+ import "./chunk-DBFEFLR4.js";
8
8
 
9
9
  // src/cli.ts
10
10
  var code = await runCli(
package/dist/index.d.ts CHANGED
@@ -29,6 +29,8 @@ type FlagRecord = {
29
29
  /** JSON string sent as `metadata.payload` when the flag is enabled. */
30
30
  payload: string | null;
31
31
  overrides: FlagOverride[];
32
+ /** Original management filters; evaluation still uses the deterministic model. */
33
+ filters?: Record<string, unknown>;
32
34
  version: number;
33
35
  created_at: string;
34
36
  updated_at: string;
@@ -52,6 +54,7 @@ declare const evaluateFlag: (flag: FlagRecord, subject: FlagSubject) => Evaluati
52
54
  declare const payloadString: (payload: unknown) => string | null;
53
55
  /** Body of `PUT /__admin/flags/:key`, validated. */
54
56
  type FlagSpec = {
57
+ filters?: Record<string, unknown>;
55
58
  name?: string;
56
59
  active?: boolean;
57
60
  default: FlagValue | null;
@@ -71,36 +74,6 @@ interface FetchAPI$1 {
71
74
  fetch(request: Request): Promise<Response>;
72
75
  }
73
76
 
74
- /**
75
- * The single source of time for a service.
76
- *
77
- * Every timestamp a mock writes reads from here, so a suite moves time instead of
78
- * sleeping: appointment windows, result delays and expiries become reachable in
79
- * milliseconds. A frozen clock also makes timestamps reproducible from a seed.
80
- */
81
- type ClockState = {
82
- /** Current epoch milliseconds. */
83
- now: number;
84
- /** True while time does not advance on its own. */
85
- frozen: boolean;
86
- /** Milliseconds this clock adds to its underlying source. */
87
- offsetMs: number;
88
- };
89
- type Clock = {
90
- now(): number;
91
- /** Pin the clock to an exact instant, keeping it frozen if it already was. */
92
- set(epochMs: number): void;
93
- /** Move the clock forward, or back with a negative delta. */
94
- advance(deltaMs: number): void;
95
- /** Stop time at the current instant. */
96
- freeze(): void;
97
- /** Resume from the current instant. */
98
- unfreeze(): void;
99
- /** Drop back to the underlying source, live. */
100
- reset(): void;
101
- state(): ClockState;
102
- };
103
-
104
77
  /** Bind values accepted by Mockingbird's SQLite port (matches sqlite-mem / better-sqlite3). */
105
78
  type SqliteValue$1 = null | number | bigint | string | Uint8Array | boolean;
106
79
  /** Mutation counters returned by {@link SqliteStatement.run}. */
@@ -172,6 +145,151 @@ declare class Collection<T> {
172
145
  }>;
173
146
  }
174
147
 
148
+ /**
149
+ * Sequential id source persisted in SQLite. Ids are deterministic for a given
150
+ * sequence history (`cus_` + 14 opaque chars), so reproductions stay stable.
151
+ */
152
+ declare class IdSequence {
153
+ private readonly sqlite;
154
+ private readonly namespace;
155
+ private readonly salt;
156
+ constructor(sqlite: SqliteClient$1, namespace: string, salt?: string);
157
+ next(prefix: string, length?: number): string;
158
+ }
159
+
160
+ /** A stable identifier for a point in a {@link Timeline}. */
161
+ type CheckpointId = string;
162
+ /** An immutable node in a timeline's checkpoint DAG. */
163
+ type Checkpoint<T> = Readonly<{
164
+ id: CheckpointId;
165
+ branch: string;
166
+ parent: CheckpointId | null;
167
+ /** Logical time supplied by the timeline's injected clock. */
168
+ at: number;
169
+ value: T;
170
+ }>;
171
+ type TimelineOptions = {
172
+ /** Logical clock used to stamp checkpoints. Defaults to a deterministic counter. */
173
+ now?: () => number;
174
+ /** Maximum retained checkpoints. Branch heads are never collected. Default 1,000. */
175
+ maxCheckpoints?: number;
176
+ /** Customize deterministic checkpoint IDs. */
177
+ id?: (sequence: number) => CheckpointId;
178
+ };
179
+ type CommitOptions = {
180
+ branch?: string;
181
+ /** Parent checkpoint. Defaults to the selected branch's current head. */
182
+ parent?: CheckpointId | null;
183
+ };
184
+ type ForkOptions = {
185
+ /** Checkpoint to fork from. Defaults to the main branch's head. */
186
+ from?: CheckpointId;
187
+ };
188
+ /**
189
+ * Small, storage-agnostic checkpoint DAG shared by service runtimes. Its values may be immutable
190
+ * records, namespace images, or copy-on-write SQL engine snapshots.
191
+ *
192
+ * Values are retained by reference. Engines can therefore use persistent/COW snapshots while
193
+ * simpler services can use immutable values. IDs and GC order are deterministic, and all IO
194
+ * (the logical clock) is injected.
195
+ */
196
+ declare class Timeline<T> {
197
+ readonly maxCheckpoints: number;
198
+ private readonly now;
199
+ private readonly makeId;
200
+ private readonly nodes;
201
+ private readonly heads;
202
+ /** Unreferenced nodes in the exact order they became collectible. */
203
+ private readonly evictable;
204
+ /** Branch heads plus explicit retainers. Absent means zero. */
205
+ private readonly references;
206
+ private readonly explicitPins;
207
+ private sequence;
208
+ constructor(options?: TimelineOptions);
209
+ /** Capture a new immutable value and move `branch` to it. */
210
+ commit(value: T, options?: CommitOptions): Checkpoint<T>;
211
+ /** Create a branch pointer without copying its checkpoint value. */
212
+ fork(branch: string, options?: ForkOptions): Checkpoint<T> | undefined;
213
+ /** Move a branch pointer to an existing checkpoint. */
214
+ checkout(branch: string, id: CheckpointId): Checkpoint<T>;
215
+ get(id: CheckpointId): Checkpoint<T>;
216
+ head(branch?: string): Checkpoint<T> | undefined;
217
+ hasBranch(branch: string): boolean;
218
+ branches(): Readonly<Record<string, CheckpointId>>;
219
+ checkpoints(): readonly Checkpoint<T>[];
220
+ /** Number of retained checkpoints without allocating an array. */
221
+ get size(): number;
222
+ /** Pin a checkpoint independently of branch heads (used by compatibility snapshot handles). */
223
+ retain(id: CheckpointId): Checkpoint<T>;
224
+ /** Release one explicit pin. Branch heads remain pinned until moved or deleted. */
225
+ release(id: CheckpointId): boolean;
226
+ deleteBranch(branch: string): boolean;
227
+ /**
228
+ * Deterministically discard oldest unpinned checkpoints. Collection is O(number removed):
229
+ * commits never scan pinned nodes or the retained history. Parents are metadata rather than a
230
+ * storage dependency, so a retained node remains usable after pruning.
231
+ */
232
+ gc(max?: number): CheckpointId[];
233
+ private collect;
234
+ private moveHead;
235
+ private addReference;
236
+ private removeReference;
237
+ private assertBranch;
238
+ }
239
+
240
+ /**
241
+ * Anything that can answer a Fetch `Request` with a `Response`.
242
+ *
243
+ * Every Mockingbird service implements this, and every runtime adapter consumes it.
244
+ * It is the only contract shared across the whole graph.
245
+ */
246
+ interface FetchAPI {
247
+ fetch(request: Request): Promise<Response>;
248
+ }
249
+
250
+ /** Options every provider constructor accepts. */
251
+ type APIOptions = {
252
+ /** Sync SQLite client. Defaults to `@crvouga/mockingbird-service-sqlite`. */
253
+ sqlite?: SqliteClient$1;
254
+ /** Clock used for `created`-style fields. Default `Date.now`. */
255
+ now?: () => number;
256
+ /**
257
+ * Storage namespace for this instance's records. Instances sharing one SQLite
258
+ * client stay isolated when their namespaces differ. Defaults to the service name.
259
+ */
260
+ namespace?: string;
261
+ };
262
+
263
+ /**
264
+ * The single source of time for a service.
265
+ *
266
+ * Every timestamp a mock writes reads from here, so a suite moves time instead of
267
+ * sleeping: appointment windows, result delays and expiries become reachable in
268
+ * milliseconds. A frozen clock also makes timestamps reproducible from a seed.
269
+ */
270
+ type ClockState = {
271
+ /** Current epoch milliseconds. */
272
+ now: number;
273
+ /** True while time does not advance on its own. */
274
+ frozen: boolean;
275
+ /** Milliseconds this clock adds to its underlying source. */
276
+ offsetMs: number;
277
+ };
278
+ type Clock = {
279
+ now(): number;
280
+ /** Pin the clock to an exact instant, keeping it frozen if it already was. */
281
+ set(epochMs: number): void;
282
+ /** Move the clock forward, or back with a negative delta. */
283
+ advance(deltaMs: number): void;
284
+ /** Stop time at the current instant. */
285
+ freeze(): void;
286
+ /** Resume from the current instant. */
287
+ unfreeze(): void;
288
+ /** Drop back to the underlying source, live. */
289
+ reset(): void;
290
+ state(): ClockState;
291
+ };
292
+
175
293
  /**
176
294
  * Seeded pseudo-random numbers, so anything a mock invents — ids, jitter, which
177
295
  * request a percentage fault hits — is reproducible from a seed.
@@ -312,109 +430,6 @@ type FaultRegistry = {
312
430
  take(candidate: FaultCandidate): Promise<FaultHit[]>;
313
431
  };
314
432
 
315
- /** A stable identifier for a point in a {@link Timeline}. */
316
- type CheckpointId = string;
317
- /** An immutable node in a timeline's checkpoint DAG. */
318
- type Checkpoint<T> = Readonly<{
319
- id: CheckpointId;
320
- branch: string;
321
- parent: CheckpointId | null;
322
- /** Logical time supplied by the timeline's injected clock. */
323
- at: number;
324
- value: T;
325
- }>;
326
- type TimelineOptions = {
327
- /** Logical clock used to stamp checkpoints. Defaults to a deterministic counter. */
328
- now?: () => number;
329
- /** Maximum retained checkpoints. Branch heads are never collected. Default 1,000. */
330
- maxCheckpoints?: number;
331
- /** Customize deterministic checkpoint IDs. */
332
- id?: (sequence: number) => CheckpointId;
333
- };
334
- type CommitOptions = {
335
- branch?: string;
336
- /** Parent checkpoint. Defaults to the selected branch's current head. */
337
- parent?: CheckpointId | null;
338
- };
339
- type ForkOptions = {
340
- /** Checkpoint to fork from. Defaults to the main branch's head. */
341
- from?: CheckpointId;
342
- };
343
- /**
344
- * Small, storage-agnostic checkpoint DAG shared by service runtimes. Its values may be immutable
345
- * records, namespace images, or copy-on-write SQL engine snapshots.
346
- *
347
- * Values are retained by reference. Engines can therefore use persistent/COW snapshots while
348
- * simpler services can use immutable values. IDs and GC order are deterministic, and all IO
349
- * (the logical clock) is injected.
350
- */
351
- declare class Timeline<T> {
352
- readonly maxCheckpoints: number;
353
- private readonly now;
354
- private readonly makeId;
355
- private readonly nodes;
356
- private readonly heads;
357
- /** Unreferenced nodes in the exact order they became collectible. */
358
- private readonly evictable;
359
- /** Branch heads plus explicit retainers. Absent means zero. */
360
- private readonly references;
361
- private readonly explicitPins;
362
- private sequence;
363
- constructor(options?: TimelineOptions);
364
- /** Capture a new immutable value and move `branch` to it. */
365
- commit(value: T, options?: CommitOptions): Checkpoint<T>;
366
- /** Create a branch pointer without copying its checkpoint value. */
367
- fork(branch: string, options?: ForkOptions): Checkpoint<T> | undefined;
368
- /** Move a branch pointer to an existing checkpoint. */
369
- checkout(branch: string, id: CheckpointId): Checkpoint<T>;
370
- get(id: CheckpointId): Checkpoint<T>;
371
- head(branch?: string): Checkpoint<T> | undefined;
372
- hasBranch(branch: string): boolean;
373
- branches(): Readonly<Record<string, CheckpointId>>;
374
- checkpoints(): readonly Checkpoint<T>[];
375
- /** Number of retained checkpoints without allocating an array. */
376
- get size(): number;
377
- /** Pin a checkpoint independently of branch heads (used by compatibility snapshot handles). */
378
- retain(id: CheckpointId): Checkpoint<T>;
379
- /** Release one explicit pin. Branch heads remain pinned until moved or deleted. */
380
- release(id: CheckpointId): boolean;
381
- deleteBranch(branch: string): boolean;
382
- /**
383
- * Deterministically discard oldest unpinned checkpoints. Collection is O(number removed):
384
- * commits never scan pinned nodes or the retained history. Parents are metadata rather than a
385
- * storage dependency, so a retained node remains usable after pruning.
386
- */
387
- gc(max?: number): CheckpointId[];
388
- private collect;
389
- private moveHead;
390
- private addReference;
391
- private removeReference;
392
- private assertBranch;
393
- }
394
-
395
- /**
396
- * Anything that can answer a Fetch `Request` with a `Response`.
397
- *
398
- * Every Mockingbird service implements this, and every runtime adapter consumes it.
399
- * It is the only contract shared across the whole graph.
400
- */
401
- interface FetchAPI {
402
- fetch(request: Request): Promise<Response>;
403
- }
404
-
405
- /** Options every provider constructor accepts. */
406
- type APIOptions = {
407
- /** Sync SQLite client. Defaults to `@crvouga/mockingbird-service-sqlite`. */
408
- sqlite?: SqliteClient$1;
409
- /** Clock used for `created`-style fields. Default `Date.now`. */
410
- now?: () => number;
411
- /**
412
- * Storage namespace for this instance's records. Instances sharing one SQLite
413
- * client stay isolated when their namespaces differ. Defaults to the service name.
414
- */
415
- namespace?: string;
416
- };
417
-
418
433
  /**
419
434
  * One problem with a request body, at a dotted path (`patient.address.city`, `items.0.sku`).
420
435
  * `kind` is `media_type` when the body is present but its media type is not one the operation
@@ -456,6 +471,10 @@ type RequestLog = {
456
471
  ids?: Record<string, string>;
457
472
  /** Set when the service created a resource the request referred to but that did not exist. */
458
473
  adopted?: boolean;
474
+ /** Explicit durable acceptance, independent of response delivery. */
475
+ accepted?: boolean;
476
+ /** Checkpoint captured at explicit acceptance. */
477
+ checkpoint?: string;
459
478
  /** Set on a rejection (status ≥ 400) the mock produced itself, never on a scripted fault. */
460
479
  request?: RejectedRequest;
461
480
  /** The validation issues behind a rejection, when the service found any. */
@@ -519,18 +538,6 @@ type CredentialRegistry = {
519
538
  }[];
520
539
  };
521
540
 
522
- /**
523
- * Sequential id source persisted in SQLite. Ids are deterministic for a given
524
- * sequence history (`cus_` + 14 opaque chars), so reproductions stay stable.
525
- */
526
- declare class IdSequence {
527
- private readonly sqlite;
528
- private readonly namespace;
529
- private readonly salt;
530
- constructor(sqlite: SqliteClient$1, namespace: string, salt?: string);
531
- next(prefix: string, length?: number): string;
532
- }
533
-
534
541
  /**
535
542
  * A point-in-time copy of everything a service namespace holds.
536
543
  *
@@ -788,10 +795,24 @@ type Settings = {
788
795
  /** Session-recording posts to `/s/`, counted and discarded. */
789
796
  recordings: number;
790
797
  };
798
+ type ExperimentRecord = {
799
+ id: number;
800
+ projectId: string;
801
+ name: string;
802
+ feature_flag_key: string;
803
+ parameters: Record<string, unknown>;
804
+ metrics: unknown[];
805
+ start_date: string | null;
806
+ end_date: string | null;
807
+ archived: boolean;
808
+ created_at: string;
809
+ updated_at: string;
810
+ };
791
811
  declare class PostHogState {
792
812
  private readonly seed;
793
813
  private readonly now;
794
814
  readonly flags: Collection<FlagRecord>;
815
+ readonly experiments: Collection<ExperimentRecord>;
795
816
  readonly events: Collection<CapturedEvent>;
796
817
  readonly settings: Collection<Settings>;
797
818
  readonly ids: IdSequence;
@@ -1029,10 +1050,10 @@ type OpenAPIDocument = {
1029
1050
  };
1030
1051
 
1031
1052
  declare const document: OpenAPIDocument;
1032
- type OperationId = "EvaluateFlags" | "Decide" | "GetRemoteConfig" | "GetRemoteConfigScript" | "CaptureBatch" | "CaptureEvent" | "CaptureEventV0" | "CaptureRecording" | "GetRecorderScript" | "GetVersionedRecorderScript" | "ListSurveys" | "ListWebExperiments" | "ListFeatureFlags" | "CreateFeatureFlag" | "UpdateFeatureFlag" | "RunQuery";
1033
- type SupportedOperationId = "EvaluateFlags" | "Decide" | "GetRemoteConfig" | "GetRemoteConfigScript" | "CaptureBatch" | "CaptureEvent" | "CaptureEventV0" | "CaptureRecording" | "GetRecorderScript" | "GetVersionedRecorderScript" | "ListSurveys" | "ListWebExperiments" | "ListFeatureFlags" | "CreateFeatureFlag" | "UpdateFeatureFlag" | "RunQuery";
1034
- declare const operationIds: readonly ["EvaluateFlags", "Decide", "GetRemoteConfig", "GetRemoteConfigScript", "CaptureBatch", "CaptureEvent", "CaptureEventV0", "CaptureRecording", "GetRecorderScript", "GetVersionedRecorderScript", "ListSurveys", "ListWebExperiments", "ListFeatureFlags", "CreateFeatureFlag", "UpdateFeatureFlag", "RunQuery"];
1035
- declare const supportedOperationIds: readonly ["EvaluateFlags", "Decide", "GetRemoteConfig", "GetRemoteConfigScript", "CaptureBatch", "CaptureEvent", "CaptureEventV0", "CaptureRecording", "GetRecorderScript", "GetVersionedRecorderScript", "ListSurveys", "ListWebExperiments", "ListFeatureFlags", "CreateFeatureFlag", "UpdateFeatureFlag", "RunQuery"];
1053
+ type OperationId = "EvaluateFlags" | "Decide" | "GetRemoteConfig" | "GetRemoteConfigScript" | "CaptureBatch" | "CaptureEvent" | "CaptureEventV0" | "CaptureRecording" | "GetRecorderScript" | "GetVersionedRecorderScript" | "ListSurveys" | "ListWebExperiments" | "ListFeatureFlags" | "CreateFeatureFlag" | "GetFeatureFlag" | "UpdateFeatureFlag" | "ListExperiments" | "CreateExperiment" | "GetExperiment" | "UpdateExperiment" | "RunQuery";
1054
+ type SupportedOperationId = "EvaluateFlags" | "Decide" | "GetRemoteConfig" | "GetRemoteConfigScript" | "CaptureBatch" | "CaptureEvent" | "CaptureEventV0" | "CaptureRecording" | "GetRecorderScript" | "GetVersionedRecorderScript" | "ListSurveys" | "ListWebExperiments" | "ListFeatureFlags" | "CreateFeatureFlag" | "GetFeatureFlag" | "UpdateFeatureFlag" | "ListExperiments" | "CreateExperiment" | "GetExperiment" | "UpdateExperiment" | "RunQuery";
1055
+ declare const operationIds: readonly ["EvaluateFlags", "Decide", "GetRemoteConfig", "GetRemoteConfigScript", "CaptureBatch", "CaptureEvent", "CaptureEventV0", "CaptureRecording", "GetRecorderScript", "GetVersionedRecorderScript", "ListSurveys", "ListWebExperiments", "ListFeatureFlags", "CreateFeatureFlag", "GetFeatureFlag", "UpdateFeatureFlag", "ListExperiments", "CreateExperiment", "GetExperiment", "UpdateExperiment", "RunQuery"];
1056
+ declare const supportedOperationIds: readonly ["EvaluateFlags", "Decide", "GetRemoteConfig", "GetRemoteConfigScript", "CaptureBatch", "CaptureEvent", "CaptureEventV0", "CaptureRecording", "GetRecorderScript", "GetVersionedRecorderScript", "ListSurveys", "ListWebExperiments", "ListFeatureFlags", "CreateFeatureFlag", "GetFeatureFlag", "UpdateFeatureFlag", "ListExperiments", "CreateExperiment", "GetExperiment", "UpdateExperiment", "RunQuery"];
1036
1057
 
1037
1058
  /**
1038
1059
  * Every named PostHog misbehaviour our consumers branch on, switched on with
@@ -1064,6 +1085,7 @@ declare const createRuntime: (options?: PostHogRuntimeOptions) => PostHogRuntime
1064
1085
 
1065
1086
  declare const POSTHOG_NAMESPACE = "posthog";
1066
1087
  type PostHogAPIOptions = APIOptions & {
1088
+ adminPrefix?: string;
1067
1089
  /** Flags every namespace starts with (and returns to on reset), keyed by flag key. */
1068
1090
  flags?: Record<string, FlagSpec>;
1069
1091
  /** Initial per-namespace settings (session recording, canned HogQL results). */
@@ -1131,4 +1153,4 @@ declare class PostHogAPI implements FetchAPI$1 {
1131
1153
  }
1132
1154
 
1133
1155
  export { ACME_FLAG_STATE, POSTHOG_NAMESPACE, POSTHOG_PRESETS, PostHogAPI, createRuntime, decodePostHogBody, document, evaluateFlag, operationIds, parseFlagSpec, payloadString, scrubProperties, specsFromState, supportedOperationIds, tokenFromBody, valueForState };
1134
- export type { CapturedEvent, Evaluation, EventQuery, FetchAPI$1 as FetchAPI, FlagOverride, FlagRecord, FlagSpec, FlagStateFile, FlagSubject, FlagValue, ImportOptions, OperationId, PostHogAPIOptions, PostHogRuntime, PostHogRuntimeOptions, QueryResult, Settings, SqliteClient, SupportedOperationId };
1156
+ export type { CapturedEvent, Evaluation, EventQuery, ExperimentRecord, FetchAPI$1 as FetchAPI, FlagOverride, FlagRecord, FlagSpec, FlagStateFile, FlagSubject, FlagValue, ImportOptions, OperationId, PostHogAPIOptions, PostHogRuntime, PostHogRuntimeOptions, QueryResult, Settings, SqliteClient, SupportedOperationId };
package/dist/index.js CHANGED
@@ -15,7 +15,7 @@ import {
15
15
  supportedOperationIds,
16
16
  tokenFromBody,
17
17
  valueForState
18
- } from "./chunk-VZ3ZHVNW.js";
18
+ } from "./chunk-DBFEFLR4.js";
19
19
  export {
20
20
  ACME_FLAG_STATE,
21
21
  POSTHOG_NAMESPACE,