@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.
- package/README.md +36 -0
- package/dist/index.d.mts +729 -0
- package/dist/index.d.ts +729 -0
- package/dist/index.js +1372 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +1343 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +35 -0
package/dist/index.d.ts
ADDED
|
@@ -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 };
|