@liteguard/core 0.2.20260314

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.
@@ -0,0 +1,729 @@
1
+ type PropertyValue = boolean | string | number;
2
+ type Properties = Record<string, PropertyValue>;
3
+ type Operator = 'EQUALS' | 'NOT_EQUALS' | 'IN' | 'NOT_IN' | 'REGEX' | 'GT' | 'GTE' | 'LT' | 'LTE';
4
+ interface Rule {
5
+ propertyName: string;
6
+ operator: Operator;
7
+ values: PropertyValue[];
8
+ result: boolean;
9
+ enabled: boolean;
10
+ }
11
+ interface Guard {
12
+ name: string;
13
+ rules: Rule[];
14
+ defaultValue: boolean;
15
+ adopted: boolean;
16
+ rateLimitPerMinute: number;
17
+ rateLimitProperties: string[];
18
+ disableMeasurement?: boolean;
19
+ }
20
+ interface ClientOptions {
21
+ environment?: string;
22
+ fallback?: boolean;
23
+ refreshRateSeconds?: number;
24
+ flushRateSeconds?: number;
25
+ flushSize?: number;
26
+ backendUrl?: string;
27
+ quiet?: boolean;
28
+ httpTimeoutSeconds?: number;
29
+ flushBufferMultiplier?: number;
30
+ disableMeasurement?: boolean;
31
+ }
32
+ interface Options {
33
+ properties?: Record<string, PropertyValue>;
34
+ fallback?: boolean;
35
+ disableMeasurement?: boolean;
36
+ }
37
+ interface ProtectedContext {
38
+ properties?: Record<string, string>;
39
+ signature: string;
40
+ }
41
+ interface GetGuardsRequest {
42
+ projectClientKeyId: string;
43
+ environment: string;
44
+ protectedContext?: ProtectedContext;
45
+ }
46
+ interface GetGuardsResponse {
47
+ guards: Guard[];
48
+ refreshRateSeconds: number;
49
+ etag: string;
50
+ }
51
+ interface TraceContext {
52
+ traceId: string;
53
+ spanId: string;
54
+ parentSpanId: string;
55
+ }
56
+ interface GuardCheckPerformance {
57
+ rssBytes?: number;
58
+ heapUsedBytes?: number;
59
+ heapTotalBytes?: number;
60
+ cpuTimeNs?: number;
61
+ gcCount?: number;
62
+ threadCount?: number;
63
+ }
64
+ interface GuardExecutionPerformance {
65
+ durationNs: number;
66
+ rssEndBytes?: number;
67
+ heapUsedEndBytes?: number;
68
+ heapTotalEndBytes?: number;
69
+ cpuTimeEndNs?: number;
70
+ gcCountEnd?: number;
71
+ threadCountEnd?: number;
72
+ completed: boolean;
73
+ errorClass?: string;
74
+ }
75
+ interface SignalPerformance {
76
+ guardCheck?: GuardCheckPerformance;
77
+ guardExecution?: GuardExecutionPerformance;
78
+ }
79
+ interface Signal {
80
+ guardName: string;
81
+ result: boolean;
82
+ properties?: Record<string, PropertyValue>;
83
+ timestampMs: number;
84
+ trace?: TraceContext;
85
+ signalId: string;
86
+ executionId: string;
87
+ parentSignalId?: string;
88
+ sequenceNumber: number;
89
+ callsiteId: string;
90
+ kind: string;
91
+ droppedSignalsSinceLast: number;
92
+ measurement?: SignalPerformance;
93
+ }
94
+ interface SendUnadoptedGuardsRequest {
95
+ projectClientKeyId: string;
96
+ environment: string;
97
+ guardNames: string[];
98
+ }
99
+ interface SendUnadoptedGuardsResponse {
100
+ accepted: boolean;
101
+ }
102
+
103
+ /**
104
+ * Snapshot of an in-flight execution scope, used to correlate guard check
105
+ * and guard execution signals within a single logical operation.
106
+ */
107
+ type ExecutionState = {
108
+ /** Unique identifier shared by all signals in this execution. */
109
+ executionId: string;
110
+ /** Signal ID of the most recently emitted signal in this execution. */
111
+ lastSignalId?: string;
112
+ /** Monotonically increasing counter within the execution. */
113
+ sequenceNumber: number;
114
+ };
115
+ /**
116
+ * Holds the active {@link LiteguardScope} for the current request or
117
+ * async context (e.g. via `AsyncLocalStorage` on Node.js).
118
+ */
119
+ type RequestScopeStore = {
120
+ currentScope: unknown;
121
+ };
122
+ /**
123
+ * Adapter that manages execution-scoped state so that guard signals emitted
124
+ * within the same logical operation share a common execution ID.
125
+ *
126
+ * Implementations should use a context-propagation mechanism appropriate for
127
+ * the runtime (e.g. `AsyncLocalStorage` on Node.js, stack-based on browsers).
128
+ */
129
+ interface ExecutionAdapter {
130
+ /** Return the current execution state, or `undefined` if none is active. */
131
+ getStore(): ExecutionState | undefined;
132
+ /**
133
+ * Run `fn` within a new execution context initialised with `initialState`.
134
+ *
135
+ * @param initialState - Fresh execution state for the new context.
136
+ * @param fn - Callback to execute within the context.
137
+ * @returns The return value of `fn`.
138
+ */
139
+ run<T>(initialState: ExecutionState, fn: () => T): T;
140
+ }
141
+ /**
142
+ * Adapter that manages per-request scope propagation so that properties and
143
+ * protected context are automatically available to guard checks within the
144
+ * same request or async context.
145
+ */
146
+ interface RequestScopeAdapter {
147
+ /** Return the current request-scope store, or `undefined` if none is active. */
148
+ getStore(): RequestScopeStore | undefined;
149
+ /**
150
+ * Run `fn` within the given request-scope store.
151
+ *
152
+ * @param initialState - The scope store to attach to the context.
153
+ * @param fn - Callback to execute within the scoped context.
154
+ * @returns The return value of `fn`.
155
+ */
156
+ run<T>(initialState: RequestScopeStore, fn: () => T): T;
157
+ }
158
+ /**
159
+ * Adapter that captures runtime performance metrics for guard check and
160
+ * guard execution signals.
161
+ *
162
+ * Implementations should return whatever metrics are cheaply available on the
163
+ * target platform (memory, CPU time, etc.). Returning `undefined` from a
164
+ * capture method disables measurement for that signal.
165
+ */
166
+ interface MeasurementAdapter {
167
+ /**
168
+ * Begin measuring a guard execution. Returns an opaque start token that
169
+ * will be passed back to {@link captureGuardExecution}.
170
+ */
171
+ beginGuardExecution(): unknown;
172
+ /**
173
+ * Capture a snapshot of runtime metrics at the moment a guard is checked.
174
+ *
175
+ * @returns A measurement payload, or `undefined` to skip measurement.
176
+ */
177
+ captureGuardCheck(): NonNullable<Signal['measurement']> | undefined;
178
+ /**
179
+ * Capture a snapshot of runtime metrics at the end of a guard execution.
180
+ *
181
+ * @param startToken - The opaque token returned by {@link beginGuardExecution}.
182
+ * @param completed - Whether the guarded function completed without throwing.
183
+ * @param error - The thrown error, if any.
184
+ * @returns A measurement payload, or `undefined` to skip measurement.
185
+ */
186
+ captureGuardExecution(startToken: unknown, completed: boolean, error?: unknown): NonNullable<Signal['measurement']> | undefined;
187
+ }
188
+ /**
189
+ * Platform abstraction layer that allows the Liteguard core to run on
190
+ * Node.js, browsers, or other JavaScript runtimes without direct
191
+ * dependencies on platform-specific APIs.
192
+ *
193
+ * Provide an implementation of this interface to
194
+ * {@link BaseLiteguardClient} when constructing a client for a new runtime.
195
+ */
196
+ interface RuntimeAdapter {
197
+ /** Human-readable runtime name (e.g. `"node"`, `"browser"`). */
198
+ readonly name: string;
199
+ /** Whether request/execution context remains correct across `await` boundaries. */
200
+ readonly supportsAsyncContextPropagation?: boolean;
201
+ /**
202
+ * Stack-frame substrings used to filter internal SDK frames when
203
+ * capturing call-site identifiers for telemetry signals.
204
+ */
205
+ readonly internalStackMarkers: string[];
206
+ /** Execution-scope adapter for signal correlation. */
207
+ readonly execution: ExecutionAdapter;
208
+ /** Optional request-scope adapter for per-request context propagation. */
209
+ readonly requestScope?: RequestScopeAdapter;
210
+ /** Performance measurement adapter. */
211
+ readonly measurement: MeasurementAdapter;
212
+ /** Return the current wall-clock time in milliseconds (like `Date.now()`). */
213
+ now(): number;
214
+ /** Return a monotonic timestamp in milliseconds (like `performance.now()`). */
215
+ monotonicNow(): number;
216
+ /** Perform an HTTP fetch with the given URL and options. */
217
+ fetch(input: string, init: RequestInit): Promise<Response>;
218
+ /** Schedule a one-shot timer. Returns an opaque handle for {@link clearTimeout}. */
219
+ setTimeout(callback: () => void, ms: number): unknown;
220
+ /** Cancel a timer created by {@link setTimeout}. */
221
+ clearTimeout(handle: unknown): void;
222
+ /** Schedule a repeating timer. Returns an opaque handle for {@link clearInterval}. */
223
+ setInterval(callback: () => void, ms: number): unknown;
224
+ /** Cancel a timer created by {@link setInterval}. */
225
+ clearInterval(handle: unknown): void;
226
+ /**
227
+ * Detach a timer handle so it does not prevent the process from exiting
228
+ * (e.g. call `handle.unref()` on Node.js). Optional — no-op by default.
229
+ */
230
+ detachTimer?(handle: unknown): void;
231
+ /**
232
+ * Install platform lifecycle hooks (e.g. `visibilitychange` / `pagehide`
233
+ * in browsers) that flush buffered signals before the page unloads.
234
+ *
235
+ * @returns A cleanup function that removes the installed hooks, or `void`.
236
+ */
237
+ installLifecycleHooks?(hooks: {
238
+ flushKeepalive: () => void;
239
+ }): (() => void) | void;
240
+ }
241
+
242
+ /** Callback invoked whenever the guard bundle is refreshed from the backend. */
243
+ type LiteguardChangeListener = () => void;
244
+ /** Options for {@link BaseLiteguardClient.flushSignals}. */
245
+ type FlushOptions = {
246
+ /**
247
+ * When `true`, the underlying `fetch` request is sent with the
248
+ * [`keepalive`](https://developer.mozilla.org/en-US/docs/Web/API/Request/keepalive)
249
+ * flag so it survives page navigation. Set this when flushing during
250
+ * `visibilitychange` or `pagehide` in the browser.
251
+ */
252
+ keepalive?: boolean;
253
+ };
254
+ /**
255
+ * Per-call options accepted by guard-evaluation methods. Extends the
256
+ * standard {@link Options} with an optional explicit {@link LiteguardScope}.
257
+ */
258
+ type ScopedOptions = Partial<Options> & {
259
+ /**
260
+ * Explicit scope to evaluate against. When omitted the client resolves the
261
+ * scope from the current async context or falls back to the default scope.
262
+ */
263
+ scope?: LiteguardScope;
264
+ };
265
+ type ScopeSnapshot = {
266
+ properties: Properties;
267
+ protectedBundleKey: string;
268
+ protectedContext: ProtectedContext | null;
269
+ };
270
+ /**
271
+ * An immutable snapshot of evaluation context (properties and optional
272
+ * protected context) that can be passed to guard-evaluation methods.
273
+ *
274
+ * Scopes are created via {@link BaseLiteguardClient.createScope} or by
275
+ * deriving from an existing scope with methods like {@link withProperties}.
276
+ * They are cheap to create and safe to share across async boundaries.
277
+ */
278
+ declare class LiteguardScope {
279
+ private readonly client;
280
+ private readonly snapshot;
281
+ /** @internal — use {@link BaseLiteguardClient.createScope} instead. */
282
+ constructor(client: BaseLiteguardClient, snapshot: ScopeSnapshot);
283
+ /**
284
+ * Derive a new scope with the given properties merged on top of this
285
+ * scope's existing properties. Does not mutate the current scope.
286
+ *
287
+ * @param properties - Key/value pairs to merge into the new scope.
288
+ * @returns A new {@link LiteguardScope} with the merged properties.
289
+ */
290
+ withProperties(properties: Properties): LiteguardScope;
291
+ /**
292
+ * Alias for {@link withProperties} — derives a new scope with additional properties.
293
+ *
294
+ * @param properties - Key/value pairs to add.
295
+ * @returns A new {@link LiteguardScope} with the merged properties.
296
+ */
297
+ addProperties(properties: Properties): LiteguardScope;
298
+ /**
299
+ * Derive a new scope with the specified property keys removed.
300
+ *
301
+ * @param names - Property keys to remove.
302
+ * @returns A new {@link LiteguardScope} without the listed properties.
303
+ */
304
+ clearProperties(names: string[]): LiteguardScope;
305
+ /**
306
+ * Derive a new scope with all properties removed.
307
+ *
308
+ * @returns A new {@link LiteguardScope} with an empty property bag.
309
+ */
310
+ resetProperties(): LiteguardScope;
311
+ /**
312
+ * Derive a new scope bound to the supplied protected context. The client
313
+ * will fetch (or reuse) a guard bundle specific to this context.
314
+ *
315
+ * @param protectedContext - Signed context bundle from your auth backend.
316
+ * @returns A new {@link LiteguardScope} bound to the protected context.
317
+ */
318
+ bindProtectedContext(protectedContext: ProtectedContext): Promise<LiteguardScope>;
319
+ /**
320
+ * Derive a new scope with protected context cleared, reverting to the
321
+ * public guard bundle.
322
+ *
323
+ * @returns A new {@link LiteguardScope} using the public guard bundle.
324
+ */
325
+ clearProtectedContext(): LiteguardScope;
326
+ /**
327
+ * Check whether the named guard is open within this scope. Buffers a
328
+ * `guard_check` telemetry signal.
329
+ *
330
+ * @param name - Guard name (e.g. `"payments.checkout"`).
331
+ * @param options - Optional per-call overrides (extra properties, fallback).
332
+ * @returns `true` if the guard is open, `false` otherwise.
333
+ */
334
+ isOpen(name: string, options?: Partial<Options>): boolean;
335
+ /**
336
+ * Check whether the named guard is open without emitting a telemetry
337
+ * signal or consuming a rate-limit slot. Useful in hot paths or render
338
+ * loops where you only need the boolean result.
339
+ *
340
+ * @param name - Guard name to evaluate.
341
+ * @param options - Optional per-call overrides.
342
+ * @returns `true` if the guard is open, `false` otherwise.
343
+ */
344
+ peekIsOpen(name: string, options?: Partial<Options>): boolean;
345
+ /**
346
+ * Evaluate the guard and, if open, call `fn` within a correlated execution
347
+ * scope. Returns `fn`'s result when open, or `undefined` when closed.
348
+ *
349
+ * Emits both a `guard_check` and a `guard_execution` telemetry signal so
350
+ * you can measure the guarded code path.
351
+ *
352
+ * @param name - Guard name to evaluate.
353
+ * @param fn - Synchronous function to invoke when the guard is open.
354
+ * @param options - Optional per-call overrides.
355
+ * @returns The return value of `fn`, or `undefined` if the guard is closed.
356
+ */
357
+ executeIfOpen<T>(name: string, fn: () => T, options?: Partial<Options>): T | undefined;
358
+ /**
359
+ * Async variant of {@link executeIfOpen}. Evaluates the guard and, if open,
360
+ * awaits `fn` within a correlated execution scope.
361
+ *
362
+ * @param name - Guard name to evaluate.
363
+ * @param fn - Async function to invoke when the guard is open.
364
+ * @param options - Optional per-call overrides.
365
+ * @returns The resolved value of `fn`, or `undefined` if the guard is closed.
366
+ */
367
+ executeIfOpenAsync<T>(name: string, fn: () => Promise<T>, options?: Partial<Options>): Promise<T | undefined>;
368
+ /**
369
+ * Run `fn` with this scope as the active scope for all guard checks made
370
+ * during its execution.
371
+ *
372
+ * @param fn - Callback to execute within this scope.
373
+ * @returns The return value of `fn`.
374
+ */
375
+ run<T>(fn: () => T): T;
376
+ /**
377
+ * Run `fn` with this scope active **and** inside a Liteguard execution
378
+ * context so that all guard signals share a common execution ID.
379
+ *
380
+ * @param fn - Callback to execute.
381
+ * @returns The return value of `fn`.
382
+ */
383
+ withExecution<T>(fn: () => T): T;
384
+ /**
385
+ * Return a shallow copy of this scope's properties.
386
+ *
387
+ * @returns A plain object of property key/value pairs.
388
+ */
389
+ getProperties(): Properties;
390
+ /**
391
+ * Return the protected context bound to this scope, or `null` if none.
392
+ *
393
+ * @returns A copy of the protected context, or `null`.
394
+ */
395
+ getProtectedContext(): ProtectedContext | null;
396
+ _getBundleKey(): string;
397
+ _getSnapshot(): ScopeSnapshot;
398
+ _belongsTo(client: BaseLiteguardClient): boolean;
399
+ }
400
+ /**
401
+ * Core Liteguard client that evaluates guards, buffers telemetry signals,
402
+ * and manages background refresh and flush cycles.
403
+ *
404
+ * This is the platform-agnostic base class. Use the platform-specific
405
+ * `LiteguardClient` from `@liteguard/liteguard-node` or
406
+ * `@liteguard/liteguard-browser` unless you are providing a custom
407
+ * {@link RuntimeAdapter}.
408
+ */
409
+ declare class BaseLiteguardClient {
410
+ private readonly projectClientKeyId;
411
+ private readonly runtime;
412
+ private readonly options;
413
+ private readonly bundles;
414
+ private defaultScope;
415
+ private signalBuffer;
416
+ private droppedSignalsPending;
417
+ private readonly reportedUnadoptedGuards;
418
+ private readonly pendingUnadoptedGuards;
419
+ private refreshTimer;
420
+ private flushTimer;
421
+ private lifecycleCleanup;
422
+ private currentRefreshRateSeconds;
423
+ private readonly rateLimitState;
424
+ private readonly listeners;
425
+ /**
426
+ * Create a new Liteguard client.
427
+ *
428
+ * Call {@link start} after construction to fetch the initial guard bundle
429
+ * and begin background timers.
430
+ *
431
+ * @param runtime - Platform adapter providing timers, fetch, and context storage.
432
+ * @param projectClientKeyId - Your project client key ID from the Liteguard dashboard.
433
+ * @param options - Optional SDK configuration overrides.
434
+ */
435
+ constructor(runtime: RuntimeAdapter, projectClientKeyId: string, options?: ClientOptions);
436
+ /**
437
+ * Fetch the initial public guard bundle and start background refresh and
438
+ * flush timers. Must be called once after construction before using the
439
+ * client in production.
440
+ */
441
+ start(): Promise<void>;
442
+ /**
443
+ * Stop all background timers and flush remaining buffered signals.
444
+ * After calling `shutdown` the client should not be used further.
445
+ */
446
+ shutdown(): Promise<void>;
447
+ /**
448
+ * Returns `true` once the initial public guard bundle has been fetched.
449
+ */
450
+ isReady(): boolean;
451
+ /**
452
+ * Register a listener that is called whenever the guard bundle is refreshed.
453
+ *
454
+ * @param listener - Callback invoked on each guard bundle update.
455
+ * @returns An unsubscribe function — call it to remove the listener.
456
+ *
457
+ * @example
458
+ * ```ts
459
+ * const unsubscribe = client.subscribe(() => {
460
+ * console.log('Guards refreshed');
461
+ * });
462
+ * // later…
463
+ * unsubscribe();
464
+ * ```
465
+ */
466
+ subscribe(listener: LiteguardChangeListener): () => void;
467
+ /**
468
+ * Create a new request scope with optional initial properties. The scope
469
+ * uses the public guard bundle by default; call
470
+ * {@link LiteguardScope.bindProtectedContext} on the returned scope to
471
+ * attach signed user context.
472
+ *
473
+ * @param properties - Initial property key/value pairs for the scope.
474
+ * @returns A new {@link LiteguardScope}.
475
+ *
476
+ * @example
477
+ * ```ts
478
+ * const scope = client.createScope({ plan: 'enterprise' });
479
+ * scope.isOpen('feature.beta'); // evaluates with plan=enterprise
480
+ * ```
481
+ */
482
+ createScope(properties?: Properties): LiteguardScope;
483
+ /**
484
+ * Return the currently active request scope, or the shared default scope
485
+ * when no request-local scope is active.
486
+ *
487
+ * On Node.js, the active scope is resolved from `AsyncLocalStorage` so
488
+ * each concurrent request can carry its own context automatically.
489
+ *
490
+ * @returns The active {@link LiteguardScope}.
491
+ */
492
+ getActiveScope(): LiteguardScope;
493
+ /**
494
+ * Run `fn` inside the given request scope. All guard checks performed
495
+ * during `fn` will use the properties and protected context of `scope`.
496
+ *
497
+ * @param scope - The scope to activate.
498
+ * @param fn - Callback to execute within the scope.
499
+ * @returns The return value of `fn`.
500
+ */
501
+ runWithScope<T>(scope: LiteguardScope, fn: () => T): T;
502
+ /**
503
+ * Convenience helper that derives a scope from the current active scope,
504
+ * merges in the supplied properties, and runs `fn` inside it.
505
+ *
506
+ * @param properties - Key/value pairs to add for the duration of `fn`.
507
+ * @param fn - Callback to execute within the scoped context.
508
+ * @returns The return value of `fn`.
509
+ *
510
+ * @example
511
+ * ```ts
512
+ * const result = client.withProperties({ userId: '42' }, () => {
513
+ * return client.isOpen('feature.beta');
514
+ * });
515
+ * ```
516
+ */
517
+ withProperties<T>(properties: Properties, fn: () => T): T;
518
+ /**
519
+ * Bind protected context to a derived scope and run `fn` inside it.
520
+ * Fetches (or reuses) a guard bundle specific to this context before
521
+ * executing `fn`.
522
+ *
523
+ * @param protectedContext - Signed context bundle from your auth backend.
524
+ * @param fn - Callback to execute within the protected scope.
525
+ * @returns The (awaited) return value of `fn`.
526
+ */
527
+ withProtectedContext<T>(protectedContext: ProtectedContext, fn: () => T | Promise<T>): Promise<Awaited<T>>;
528
+ /**
529
+ * Run `fn` inside a Liteguard execution scope so that all guard signals
530
+ * emitted during `fn` share a common execution ID for correlated
531
+ * telemetry. If an execution scope is already active, `fn` is called
532
+ * directly without creating a new one.
533
+ *
534
+ * @param fn - Callback to execute within the execution scope.
535
+ * @returns The return value of `fn`.
536
+ */
537
+ withExecution<T>(fn: () => T): T;
538
+ /**
539
+ * Return `true` if the named guard is open for the resolved request scope.
540
+ * Buffers a `guard_check` telemetry signal and consumes a rate-limit slot
541
+ * when applicable.
542
+ *
543
+ * Guards that have not yet been adopted on the Liteguard dashboard always
544
+ * return `true`, allowing you to instrument code before enabling the guard.
545
+ *
546
+ * @param name - Guard name (e.g. `"payments.checkout"`).
547
+ * @param callOptions - Optional per-call overrides (extra properties, fallback, scope).
548
+ * @returns `true` if the guard is open, `false` otherwise.
549
+ */
550
+ isOpen(name: string, callOptions?: ScopedOptions): boolean;
551
+ /**
552
+ * Signal-free variant of {@link isOpen}. Returns the same boolean result
553
+ * but does **not** emit a telemetry signal or consume a rate-limit slot.
554
+ * Ideal for render loops or other hot paths where you only need the
555
+ * boolean value.
556
+ *
557
+ * @param name - Guard name to evaluate.
558
+ * @param callOptions - Optional per-call overrides.
559
+ * @returns `true` if the guard is open, `false` otherwise.
560
+ */
561
+ peekIsOpen(name: string, callOptions?: ScopedOptions): boolean;
562
+ private evaluateIsOpen;
563
+ /**
564
+ * Evaluate the guard and, if open, call `fn` inside a correlated execution
565
+ * scope. Returns `fn`'s result when the guard is open, or `undefined` when
566
+ * closed. Emits correlated `guard_check` and `guard_execution` signals.
567
+ *
568
+ * @param name - Guard name to evaluate.
569
+ * @param fn - Synchronous function to invoke when the guard is open.
570
+ * @param callOptions - Optional per-call overrides.
571
+ * @returns The return value of `fn`, or `undefined` if the guard is closed.
572
+ *
573
+ * @example
574
+ * ```ts
575
+ * const banner = client.executeIfOpen('promo.banner', () => {
576
+ * return renderPromoBanner();
577
+ * });
578
+ * ```
579
+ */
580
+ executeIfOpen<T>(name: string, fn: () => T, callOptions?: ScopedOptions): T | undefined;
581
+ /**
582
+ * Async variant of {@link executeIfOpen}. Evaluates the guard and, if
583
+ * open, awaits `fn` inside a correlated execution scope.
584
+ *
585
+ * @param name - Guard name to evaluate.
586
+ * @param fn - Async function to invoke when the guard is open.
587
+ * @param callOptions - Optional per-call overrides.
588
+ * @returns The resolved value of `fn`, or `undefined` if the guard is closed.
589
+ */
590
+ executeIfOpenAsync<T>(name: string, fn: () => Promise<T>, callOptions?: ScopedOptions): Promise<T | undefined>;
591
+ private executeIfOpenAsyncWithoutAsyncContext;
592
+ /**
593
+ * Merge `properties` into the active scope's property bag and persist
594
+ * the derived scope as the new active scope. Subsequent {@link isOpen}
595
+ * calls will include these properties unless overridden per-call.
596
+ *
597
+ * @param properties - Key/value pairs to add.
598
+ * @returns The new active {@link LiteguardScope}.
599
+ */
600
+ addProperties(properties: Properties): LiteguardScope;
601
+ /**
602
+ * Remove the given property keys from the active scope and persist the
603
+ * resulting scope.
604
+ *
605
+ * @param names - Property keys to remove.
606
+ * @returns The new active {@link LiteguardScope}.
607
+ */
608
+ clearProperties(names: string[]): LiteguardScope;
609
+ /**
610
+ * Remove all properties from the active scope and persist the resulting
611
+ * scope.
612
+ *
613
+ * @returns The new active {@link LiteguardScope} with an empty property bag.
614
+ */
615
+ resetProperties(): LiteguardScope;
616
+ /**
617
+ * Bind protected context to the active scope and persist the derived
618
+ * scope. Fetches (or reuses) a guard bundle specific to this context.
619
+ *
620
+ * @param protectedContext - Signed context bundle from your auth backend.
621
+ * @returns The new active {@link LiteguardScope}.
622
+ */
623
+ bindProtectedContext(protectedContext: ProtectedContext): Promise<LiteguardScope>;
624
+ /**
625
+ * Clear protected context from the active scope and revert to the
626
+ * public guard bundle.
627
+ *
628
+ * @returns The new active {@link LiteguardScope}.
629
+ */
630
+ clearProtectedContext(): LiteguardScope;
631
+ /**
632
+ * Immediately transmit all buffered telemetry signals to the backend. Also
633
+ * flushes any pending unadopted-guard reports.
634
+ *
635
+ * Call this before process exit or page unload to avoid losing signals.
636
+ *
637
+ * @param options - Flush options (e.g. `{ keepalive: true }` for page unload).
638
+ */
639
+ flushSignals(options?: FlushOptions): Promise<void>;
640
+ /** Notify subscribers that client-visible state has changed. */
641
+ protected emitChange(): void;
642
+ /** @internal Derive a new immutable scope from an existing scope snapshot. */
643
+ _deriveScope(scope: LiteguardScope, patch: Partial<ScopeSnapshot>): LiteguardScope;
644
+ /** @internal Bind protected context to a scope and ensure its bundle is loaded. */
645
+ _bindProtectedContextToScope(scope: LiteguardScope, protectedContext: ProtectedContext): Promise<LiteguardScope>;
646
+ /** Persist a derived scope into the current request-local or default scope slot. */
647
+ private replaceCurrentScope;
648
+ /** Resolve the active runtime scope store into a client-owned scope instance. */
649
+ private getRuntimeScope;
650
+ /** Validate and resolve the scope used for a client operation. */
651
+ private resolveScope;
652
+ /** Queue a one-time report for a guard that exists only in application code. */
653
+ private recordUnadoptedGuard;
654
+ /** Schedule the next periodic guard refresh using the current refresh interval. */
655
+ private scheduleNextRefresh;
656
+ /** Refresh every cached bundle once, then reschedule the next cycle. */
657
+ private runRefreshCycle;
658
+ /** Create an empty bundle placeholder before the first successful fetch. */
659
+ private createEmptyBundle;
660
+ /** Return a cached bundle by key, if present. */
661
+ private getBundle;
662
+ /** Resolve the bundle used for a scope, falling back to the public bundle. */
663
+ private bundleForScope;
664
+ /** Ensure the bundle for a protected context exists locally and is ready. */
665
+ private ensureBundleForProtectedContext;
666
+ /** Use the shortest bundle refresh rate so all cached bundles stay current. */
667
+ private recomputeRefreshInterval;
668
+ /** Fetch the latest guard bundle for a bundle key, respecting ETags and timeouts. */
669
+ private fetchGuardsForBundle;
670
+ /** Create an `AbortSignal` that cancels an HTTP request after `timeoutMs`. */
671
+ private createTimeoutSignal;
672
+ /** Send a JSON POST request to the Liteguard backend with the SDK defaults applied. */
673
+ private post;
674
+ /** Buffer a telemetry signal and trigger an eager flush when the batch is full. */
675
+ private bufferSignal;
676
+ /** Allocate signal correlation metadata for the current execution context. */
677
+ private nextSignalMetadata;
678
+ private runWithExplicitExecutionState;
679
+ /** Capture the first external stack frame so telemetry can identify the call site. */
680
+ private captureCallsiteId;
681
+ /** Build the in-memory rate-limit bucket key for a guard and property set. */
682
+ private rateLimitBucketKey;
683
+ private checkRateLimit;
684
+ /** Check whether a guard would pass the current rate-limit window without consuming a slot. */
685
+ private wouldPassRateLimit;
686
+ /** Decide whether performance measurement should be captured for this guard call. */
687
+ private isMeasurementEnabled;
688
+ /** Return the hard cap for the in-memory signal buffer after flush failures. */
689
+ private maxBufferSize;
690
+ /** Drain and reset the count of dropped signals to attach to the next emitted signal. */
691
+ private takeDroppedSignals;
692
+ /** Write a warning only when quiet mode is disabled. */
693
+ private log;
694
+ /** @internal Test helper for swapping the public guard bundle in memory. */
695
+ _setGuards(guards: Guard[]): void;
696
+ /** @internal Test helper for swapping a protected-context bundle in memory. */
697
+ _setProtectedGuards(protectedContext: ProtectedContext, guards: Guard[]): void;
698
+ /** @internal Clear all rate-limit counters, or only those for a specific guard. */
699
+ _resetRateLimitState(name?: string): void;
700
+ /** @internal Return the default scope properties for tests and diagnostics. */
701
+ _getContext(): Properties;
702
+ /** @internal Return the default scope protected context for tests and diagnostics. */
703
+ _getProtectedContext(): ProtectedContext | null;
704
+ /** @internal Return the active refresh cadence for tests and diagnostics. */
705
+ _getRefreshRateSeconds(): number;
706
+ /** @internal Return a cloned view of the buffered signals for tests and diagnostics. */
707
+ _getSignalBuffer(): Signal[];
708
+ /** @internal Return the sorted set of queued unadopted guards. */
709
+ _getPendingUnadoptedGuards(): string[];
710
+ /** @internal Return the currently cached bundle keys. */
711
+ _getBundleKeys(): string[];
712
+ /** @internal Expose the request-scope store for tests. */
713
+ _getRequestScopeStore(): RequestScopeStore | undefined;
714
+ }
715
+
716
+ /**
717
+ * Evaluate all rules for a guard against the given properties.
718
+ *
719
+ * Rules are checked in order; the first matching, enabled rule wins and its
720
+ * `result` is returned. If no rule matches, the guard's `defaultValue` is
721
+ * returned instead.
722
+ *
723
+ * @param guard - The guard definition containing rules and a default value.
724
+ * @param properties - The property bag to evaluate each rule against.
725
+ * @returns `true` if the guard is open (traffic should proceed), `false` otherwise.
726
+ */
727
+ declare function evaluateGuard(guard: Guard, properties: Properties): boolean;
728
+
729
+ export { BaseLiteguardClient, type ClientOptions, type ExecutionAdapter, type ExecutionState, type FlushOptions, type GetGuardsRequest, type GetGuardsResponse, type Guard, type GuardCheckPerformance, type GuardExecutionPerformance, type LiteguardChangeListener, LiteguardScope, type MeasurementAdapter, type Operator, type Options, type Properties, type PropertyValue, type ProtectedContext, type RequestScopeAdapter, type RequestScopeStore, type Rule, type RuntimeAdapter, type ScopedOptions, type SendUnadoptedGuardsRequest, type SendUnadoptedGuardsResponse, type Signal, type SignalPerformance, type TraceContext, evaluateGuard };