@liteguard/liteguard-browser 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 +50 -0
- package/dist/index.d.mts +52 -0
- package/dist/index.d.ts +52 -0
- package/dist/index.js +182 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +156 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +42 -0
package/README.md
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# @liteguard/liteguard-browser
|
|
2
|
+
|
|
3
|
+
[](https://github.com/liteguard/liteguard/actions/workflows/test-js.yml)
|
|
4
|
+
[](https://www.npmjs.com/package/@liteguard/liteguard-browser)
|
|
5
|
+
|
|
6
|
+
Liteguard for browser runtimes.
|
|
7
|
+
|
|
8
|
+
## Installation
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
npm install @liteguard/liteguard-browser
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Quick Start
|
|
15
|
+
|
|
16
|
+
```ts
|
|
17
|
+
import { LiteguardClient } from "@liteguard/liteguard-browser";
|
|
18
|
+
|
|
19
|
+
const client = await LiteguardClient.create("pckid-...", {
|
|
20
|
+
environment: "production",
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
const scope = client.createScope({ userId: "user-123", plan: "pro" });
|
|
24
|
+
|
|
25
|
+
if (scope.isOpen("payments.checkout")) {
|
|
26
|
+
// ...
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
await client.shutdown();
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Primary API
|
|
33
|
+
|
|
34
|
+
- `LiteguardClient.create()` creates and starts a client.
|
|
35
|
+
- `client.createScope()` creates an immutable scope.
|
|
36
|
+
- `scope.isOpen()` evaluates locally.
|
|
37
|
+
- `scope.executeIfOpen()` and `scope.executeIfOpenAsync()` measure guarded work.
|
|
38
|
+
- `scope.withProperties()` and `scope.withProtectedContext()` derive child scopes.
|
|
39
|
+
- `client.flush()` flushes buffered telemetry.
|
|
40
|
+
- `client.shutdown()` flushes and stops background work.
|
|
41
|
+
|
|
42
|
+
## Notes
|
|
43
|
+
|
|
44
|
+
- Prefer explicit scopes for async browser flows.
|
|
45
|
+
- Evaluation is local after the initial bundle fetch.
|
|
46
|
+
- Unadopted guards default open and emit no signals.
|
|
47
|
+
|
|
48
|
+
## License
|
|
49
|
+
|
|
50
|
+
Apache 2.0 — see [LICENSE](https://github.com/liteguard/liteguard/blob/main/LICENSE).
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { BaseLiteguardClient, ClientOptions, LiteguardScope, Properties, ProtectedContext } from '@liteguard/core';
|
|
2
|
+
export { ClientOptions, FlushOptions, GetGuardsRequest, GetGuardsResponse, Guard, GuardCheckPerformance, GuardExecutionPerformance, LiteguardChangeListener, LiteguardScope, Operator, Options, Properties, PropertyValue, ProtectedContext, Rule, ScopedOptions, SendUnadoptedGuardsRequest, SendUnadoptedGuardsResponse, Signal, SignalPerformance, TraceContext, evaluateGuard } from '@liteguard/core';
|
|
3
|
+
|
|
4
|
+
type SyncResult<T> = T extends PromiseLike<unknown> ? never : T;
|
|
5
|
+
/**
|
|
6
|
+
* Liteguard client for browser environments.
|
|
7
|
+
*
|
|
8
|
+
* Uses a stack-based execution adapter (no `AsyncLocalStorage`) and
|
|
9
|
+
* `performance.now()` / `performance.memory` for measurement. Automatically
|
|
10
|
+
* flushes buffered signals on `visibilitychange` and `pagehide`.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```ts
|
|
14
|
+
* import { LiteguardClient } from '@liteguard/liteguard-browser';
|
|
15
|
+
*
|
|
16
|
+
* const client = new LiteguardClient('pk_live_...');
|
|
17
|
+
* await client.start();
|
|
18
|
+
*
|
|
19
|
+
* if (client.isOpen('feature.beta')) {
|
|
20
|
+
* // new code path
|
|
21
|
+
* }
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
declare class LiteguardClient extends BaseLiteguardClient {
|
|
25
|
+
/**
|
|
26
|
+
* @param projectClientKeyId - Your project client key ID from the Liteguard dashboard.
|
|
27
|
+
* @param options - Optional SDK configuration overrides.
|
|
28
|
+
*/
|
|
29
|
+
constructor(projectClientKeyId: string, options?: ClientOptions);
|
|
30
|
+
/**
|
|
31
|
+
* Run `fn` inside `scope` for synchronous browser work only.
|
|
32
|
+
*
|
|
33
|
+
* Browser runtimes do not propagate Liteguard scope across `await`
|
|
34
|
+
* boundaries. For async work, pass an explicit `scope` to each call or use
|
|
35
|
+
* `scope.executeIfOpenAsync()`.
|
|
36
|
+
*/
|
|
37
|
+
runWithScope<T>(scope: LiteguardScope, fn: () => SyncResult<T>): SyncResult<T>;
|
|
38
|
+
/**
|
|
39
|
+
* Convenience helper for synchronous browser-only scope callbacks.
|
|
40
|
+
*/
|
|
41
|
+
withProperties<T>(properties: Properties, fn: () => SyncResult<T>): SyncResult<T>;
|
|
42
|
+
/**
|
|
43
|
+
* Bind protected context and run a synchronous callback in the derived scope.
|
|
44
|
+
*/
|
|
45
|
+
withProtectedContext<T>(protectedContext: ProtectedContext, fn: () => SyncResult<T>): Promise<Awaited<T>>;
|
|
46
|
+
/**
|
|
47
|
+
* Run `fn` inside a correlated synchronous execution scope.
|
|
48
|
+
*/
|
|
49
|
+
withExecution<T>(fn: () => SyncResult<T>): SyncResult<T>;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export { LiteguardClient };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { BaseLiteguardClient, ClientOptions, LiteguardScope, Properties, ProtectedContext } from '@liteguard/core';
|
|
2
|
+
export { ClientOptions, FlushOptions, GetGuardsRequest, GetGuardsResponse, Guard, GuardCheckPerformance, GuardExecutionPerformance, LiteguardChangeListener, LiteguardScope, Operator, Options, Properties, PropertyValue, ProtectedContext, Rule, ScopedOptions, SendUnadoptedGuardsRequest, SendUnadoptedGuardsResponse, Signal, SignalPerformance, TraceContext, evaluateGuard } from '@liteguard/core';
|
|
3
|
+
|
|
4
|
+
type SyncResult<T> = T extends PromiseLike<unknown> ? never : T;
|
|
5
|
+
/**
|
|
6
|
+
* Liteguard client for browser environments.
|
|
7
|
+
*
|
|
8
|
+
* Uses a stack-based execution adapter (no `AsyncLocalStorage`) and
|
|
9
|
+
* `performance.now()` / `performance.memory` for measurement. Automatically
|
|
10
|
+
* flushes buffered signals on `visibilitychange` and `pagehide`.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```ts
|
|
14
|
+
* import { LiteguardClient } from '@liteguard/liteguard-browser';
|
|
15
|
+
*
|
|
16
|
+
* const client = new LiteguardClient('pk_live_...');
|
|
17
|
+
* await client.start();
|
|
18
|
+
*
|
|
19
|
+
* if (client.isOpen('feature.beta')) {
|
|
20
|
+
* // new code path
|
|
21
|
+
* }
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
declare class LiteguardClient extends BaseLiteguardClient {
|
|
25
|
+
/**
|
|
26
|
+
* @param projectClientKeyId - Your project client key ID from the Liteguard dashboard.
|
|
27
|
+
* @param options - Optional SDK configuration overrides.
|
|
28
|
+
*/
|
|
29
|
+
constructor(projectClientKeyId: string, options?: ClientOptions);
|
|
30
|
+
/**
|
|
31
|
+
* Run `fn` inside `scope` for synchronous browser work only.
|
|
32
|
+
*
|
|
33
|
+
* Browser runtimes do not propagate Liteguard scope across `await`
|
|
34
|
+
* boundaries. For async work, pass an explicit `scope` to each call or use
|
|
35
|
+
* `scope.executeIfOpenAsync()`.
|
|
36
|
+
*/
|
|
37
|
+
runWithScope<T>(scope: LiteguardScope, fn: () => SyncResult<T>): SyncResult<T>;
|
|
38
|
+
/**
|
|
39
|
+
* Convenience helper for synchronous browser-only scope callbacks.
|
|
40
|
+
*/
|
|
41
|
+
withProperties<T>(properties: Properties, fn: () => SyncResult<T>): SyncResult<T>;
|
|
42
|
+
/**
|
|
43
|
+
* Bind protected context and run a synchronous callback in the derived scope.
|
|
44
|
+
*/
|
|
45
|
+
withProtectedContext<T>(protectedContext: ProtectedContext, fn: () => SyncResult<T>): Promise<Awaited<T>>;
|
|
46
|
+
/**
|
|
47
|
+
* Run `fn` inside a correlated synchronous execution scope.
|
|
48
|
+
*/
|
|
49
|
+
withExecution<T>(fn: () => SyncResult<T>): SyncResult<T>;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export { LiteguardClient };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
LiteguardClient: () => LiteguardClient,
|
|
24
|
+
evaluateGuard: () => import_core2.evaluateGuard
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(index_exports);
|
|
27
|
+
var import_core2 = require("@liteguard/core");
|
|
28
|
+
|
|
29
|
+
// src/client.ts
|
|
30
|
+
var import_core = require("@liteguard/core");
|
|
31
|
+
|
|
32
|
+
// src/runtime.ts
|
|
33
|
+
var StackExecutionAdapter = class {
|
|
34
|
+
current;
|
|
35
|
+
/** Return the currently active browser execution scope, if any. */
|
|
36
|
+
getStore() {
|
|
37
|
+
return this.current;
|
|
38
|
+
}
|
|
39
|
+
/** Run a callback while this adapter's execution scope is active. */
|
|
40
|
+
run(initialState, fn) {
|
|
41
|
+
const previous = this.current;
|
|
42
|
+
this.current = initialState;
|
|
43
|
+
try {
|
|
44
|
+
return fn();
|
|
45
|
+
} finally {
|
|
46
|
+
this.current = previous;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
var StackRequestScopeAdapter = class {
|
|
51
|
+
current;
|
|
52
|
+
/** Return the currently active browser request scope, if any. */
|
|
53
|
+
getStore() {
|
|
54
|
+
return this.current;
|
|
55
|
+
}
|
|
56
|
+
/** Run a callback while this adapter's request scope is active. */
|
|
57
|
+
run(initialState, fn) {
|
|
58
|
+
const previous = this.current;
|
|
59
|
+
this.current = initialState;
|
|
60
|
+
try {
|
|
61
|
+
return fn();
|
|
62
|
+
} finally {
|
|
63
|
+
this.current = previous;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
function getMemoryInfo() {
|
|
68
|
+
const perf = globalThis.performance;
|
|
69
|
+
return perf.memory;
|
|
70
|
+
}
|
|
71
|
+
var measurementAdapter = {
|
|
72
|
+
/** Capture a monotonic start time for a guarded execution in the browser. */
|
|
73
|
+
beginGuardExecution() {
|
|
74
|
+
return globalThis.performance?.now?.() ?? Date.now();
|
|
75
|
+
},
|
|
76
|
+
/** Capture heap statistics for a `guard_check` signal when available. */
|
|
77
|
+
captureGuardCheck() {
|
|
78
|
+
const memory = getMemoryInfo();
|
|
79
|
+
return {
|
|
80
|
+
guardCheck: {
|
|
81
|
+
...memory?.usedJSHeapSize !== void 0 ? { heapUsedBytes: memory.usedJSHeapSize } : {},
|
|
82
|
+
...memory?.totalJSHeapSize !== void 0 ? { heapTotalBytes: memory.totalJSHeapSize } : {}
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
},
|
|
86
|
+
/** Capture completion metrics for a guarded code path in the browser. */
|
|
87
|
+
captureGuardExecution(startToken, completed, error) {
|
|
88
|
+
const start = typeof startToken === "number" ? startToken : globalThis.performance?.now?.() ?? Date.now();
|
|
89
|
+
const end = globalThis.performance?.now?.() ?? Date.now();
|
|
90
|
+
const memory = getMemoryInfo();
|
|
91
|
+
return {
|
|
92
|
+
guardExecution: {
|
|
93
|
+
durationNs: Math.round((end - start) * 1e6),
|
|
94
|
+
...memory?.usedJSHeapSize !== void 0 ? { heapUsedEndBytes: memory.usedJSHeapSize } : {},
|
|
95
|
+
...memory?.totalJSHeapSize !== void 0 ? { heapTotalEndBytes: memory.totalJSHeapSize } : {},
|
|
96
|
+
completed,
|
|
97
|
+
...error && error instanceof Error && error.name ? { errorClass: error.name } : {}
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
var executionAdapter = new StackExecutionAdapter();
|
|
103
|
+
var requestScopeAdapter = new StackRequestScopeAdapter();
|
|
104
|
+
var browserRuntime = {
|
|
105
|
+
name: "browser",
|
|
106
|
+
supportsAsyncContextPropagation: false,
|
|
107
|
+
internalStackMarkers: ["/packages/core/src/", "/packages/liteguard-browser/src/", "/sdk/js/packages/"],
|
|
108
|
+
execution: executionAdapter,
|
|
109
|
+
requestScope: requestScopeAdapter,
|
|
110
|
+
measurement: measurementAdapter,
|
|
111
|
+
now: () => Date.now(),
|
|
112
|
+
monotonicNow: () => globalThis.performance?.now?.() ?? Date.now(),
|
|
113
|
+
fetch: (input, init) => globalThis.fetch(input, init),
|
|
114
|
+
setTimeout: (callback, ms) => globalThis.setTimeout(callback, ms),
|
|
115
|
+
clearTimeout: (handle) => globalThis.clearTimeout(handle),
|
|
116
|
+
setInterval: (callback, ms) => globalThis.setInterval(callback, ms),
|
|
117
|
+
clearInterval: (handle) => globalThis.clearInterval(handle),
|
|
118
|
+
installLifecycleHooks: ({ flushKeepalive }) => {
|
|
119
|
+
if (typeof window === "undefined" || typeof document === "undefined") {
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
const onVisibilityChange = () => {
|
|
123
|
+
if (document.visibilityState === "hidden") {
|
|
124
|
+
flushKeepalive();
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
const onPageHide = () => {
|
|
128
|
+
flushKeepalive();
|
|
129
|
+
};
|
|
130
|
+
document.addEventListener("visibilitychange", onVisibilityChange);
|
|
131
|
+
window.addEventListener("pagehide", onPageHide);
|
|
132
|
+
return () => {
|
|
133
|
+
document.removeEventListener("visibilitychange", onVisibilityChange);
|
|
134
|
+
window.removeEventListener("pagehide", onPageHide);
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
// src/client.ts
|
|
140
|
+
var LiteguardClient = class extends import_core.BaseLiteguardClient {
|
|
141
|
+
/**
|
|
142
|
+
* @param projectClientKeyId - Your project client key ID from the Liteguard dashboard.
|
|
143
|
+
* @param options - Optional SDK configuration overrides.
|
|
144
|
+
*/
|
|
145
|
+
constructor(projectClientKeyId, options = {}) {
|
|
146
|
+
super(browserRuntime, projectClientKeyId, options);
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Run `fn` inside `scope` for synchronous browser work only.
|
|
150
|
+
*
|
|
151
|
+
* Browser runtimes do not propagate Liteguard scope across `await`
|
|
152
|
+
* boundaries. For async work, pass an explicit `scope` to each call or use
|
|
153
|
+
* `scope.executeIfOpenAsync()`.
|
|
154
|
+
*/
|
|
155
|
+
runWithScope(scope, fn) {
|
|
156
|
+
return super.runWithScope(scope, fn);
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Convenience helper for synchronous browser-only scope callbacks.
|
|
160
|
+
*/
|
|
161
|
+
withProperties(properties, fn) {
|
|
162
|
+
return super.withProperties(properties, fn);
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Bind protected context and run a synchronous callback in the derived scope.
|
|
166
|
+
*/
|
|
167
|
+
async withProtectedContext(protectedContext, fn) {
|
|
168
|
+
return await super.withProtectedContext(protectedContext, fn);
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Run `fn` inside a correlated synchronous execution scope.
|
|
172
|
+
*/
|
|
173
|
+
withExecution(fn) {
|
|
174
|
+
return super.withExecution(fn);
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
178
|
+
0 && (module.exports = {
|
|
179
|
+
LiteguardClient,
|
|
180
|
+
evaluateGuard
|
|
181
|
+
});
|
|
182
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/client.ts","../src/runtime.ts"],"sourcesContent":["export type {\n GetGuardsRequest,\n GetGuardsResponse,\n Guard,\n GuardCheckPerformance,\n GuardExecutionPerformance,\n ClientOptions,\n FlushOptions,\n LiteguardChangeListener,\n LiteguardScope,\n Options,\n Operator,\n Properties,\n PropertyValue,\n ProtectedContext,\n Rule,\n SendUnadoptedGuardsRequest,\n SendUnadoptedGuardsResponse,\n Signal,\n SignalPerformance,\n ScopedOptions,\n TraceContext,\n} from '@liteguard/core';\nexport { evaluateGuard } from '@liteguard/core';\nexport { LiteguardClient } from './client.js';\n","import { BaseLiteguardClient } from '@liteguard/core';\nimport type { ClientOptions, LiteguardScope, Properties, ProtectedContext } from '@liteguard/core';\nimport { browserRuntime } from './runtime.js';\n\ntype SyncResult<T> = T extends PromiseLike<unknown> ? never : T;\n\n/**\n * Liteguard client for browser environments.\n *\n * Uses a stack-based execution adapter (no `AsyncLocalStorage`) and\n * `performance.now()` / `performance.memory` for measurement. Automatically\n * flushes buffered signals on `visibilitychange` and `pagehide`.\n *\n * @example\n * ```ts\n * import { LiteguardClient } from '@liteguard/liteguard-browser';\n *\n * const client = new LiteguardClient('pk_live_...');\n * await client.start();\n *\n * if (client.isOpen('feature.beta')) {\n * // new code path\n * }\n * ```\n */\nexport class LiteguardClient extends BaseLiteguardClient {\n /**\n * @param projectClientKeyId - Your project client key ID from the Liteguard dashboard.\n * @param options - Optional SDK configuration overrides.\n */\n constructor(projectClientKeyId: string, options: ClientOptions = {}) {\n super(browserRuntime, projectClientKeyId, options);\n }\n\n /**\n * Run `fn` inside `scope` for synchronous browser work only.\n *\n * Browser runtimes do not propagate Liteguard scope across `await`\n * boundaries. For async work, pass an explicit `scope` to each call or use\n * `scope.executeIfOpenAsync()`.\n */\n override runWithScope<T>(scope: LiteguardScope, fn: () => SyncResult<T>): SyncResult<T> {\n return super.runWithScope(scope, fn as () => T) as SyncResult<T>;\n }\n\n /**\n * Convenience helper for synchronous browser-only scope callbacks.\n */\n override withProperties<T>(properties: Properties, fn: () => SyncResult<T>): SyncResult<T> {\n return super.withProperties(properties, fn as () => T) as SyncResult<T>;\n }\n\n /**\n * Bind protected context and run a synchronous callback in the derived scope.\n */\n override async withProtectedContext<T>(\n protectedContext: ProtectedContext,\n fn: () => SyncResult<T>,\n ): Promise<Awaited<T>> {\n return await super.withProtectedContext(protectedContext, fn as () => T);\n }\n\n /**\n * Run `fn` inside a correlated synchronous execution scope.\n */\n override withExecution<T>(fn: () => SyncResult<T>): SyncResult<T> {\n return super.withExecution(fn as () => T) as SyncResult<T>;\n }\n}\n","import type {\n ExecutionAdapter,\n ExecutionState,\n MeasurementAdapter,\n RequestScopeAdapter,\n RequestScopeStore,\n RuntimeAdapter,\n Signal,\n} from '@liteguard/core';\n\ntype MemoryInfo = {\n usedJSHeapSize?: number;\n totalJSHeapSize?: number;\n jsHeapSizeLimit?: number;\n};\n\nclass StackExecutionAdapter implements ExecutionAdapter {\n private current: ExecutionState | undefined;\n\n /** Return the currently active browser execution scope, if any. */\n getStore(): ExecutionState | undefined {\n return this.current;\n }\n\n /** Run a callback while this adapter's execution scope is active. */\n run<T>(initialState: ExecutionState, fn: () => T): T {\n const previous = this.current;\n this.current = initialState;\n try {\n return fn();\n } finally {\n this.current = previous;\n }\n }\n}\n\nclass StackRequestScopeAdapter implements RequestScopeAdapter {\n private current: RequestScopeStore | undefined;\n\n /** Return the currently active browser request scope, if any. */\n getStore(): RequestScopeStore | undefined {\n return this.current;\n }\n\n /** Run a callback while this adapter's request scope is active. */\n run<T>(initialState: RequestScopeStore, fn: () => T): T {\n const previous = this.current;\n this.current = initialState;\n try {\n return fn();\n } finally {\n this.current = previous;\n }\n }\n}\n\n/** Read browser heap statistics when the runtime exposes them. */\nfunction getMemoryInfo(): MemoryInfo | undefined {\n const perf = globalThis.performance as Performance & { memory?: MemoryInfo };\n return perf.memory;\n}\n\nconst measurementAdapter: MeasurementAdapter = {\n /** Capture a monotonic start time for a guarded execution in the browser. */\n beginGuardExecution(): number {\n return globalThis.performance?.now?.() ?? Date.now();\n },\n /** Capture heap statistics for a `guard_check` signal when available. */\n captureGuardCheck(): NonNullable<Signal['measurement']> {\n const memory = getMemoryInfo();\n return {\n guardCheck: {\n ...(memory?.usedJSHeapSize !== undefined ? { heapUsedBytes: memory.usedJSHeapSize } : {}),\n ...(memory?.totalJSHeapSize !== undefined ? { heapTotalBytes: memory.totalJSHeapSize } : {}),\n },\n };\n },\n /** Capture completion metrics for a guarded code path in the browser. */\n captureGuardExecution(startToken: unknown, completed: boolean, error?: unknown): NonNullable<Signal['measurement']> {\n const start = typeof startToken === 'number' ? startToken : globalThis.performance?.now?.() ?? Date.now();\n const end = globalThis.performance?.now?.() ?? Date.now();\n const memory = getMemoryInfo();\n return {\n guardExecution: {\n durationNs: Math.round((end - start) * 1_000_000),\n ...(memory?.usedJSHeapSize !== undefined ? { heapUsedEndBytes: memory.usedJSHeapSize } : {}),\n ...(memory?.totalJSHeapSize !== undefined ? { heapTotalEndBytes: memory.totalJSHeapSize } : {}),\n completed,\n ...(error && error instanceof Error && error.name ? { errorClass: error.name } : {}),\n },\n };\n },\n};\n\nconst executionAdapter = new StackExecutionAdapter();\nconst requestScopeAdapter = new StackRequestScopeAdapter();\n\n/** Browser runtime adapter used by the platform-specific Liteguard client. */\nexport const browserRuntime: RuntimeAdapter = {\n name: 'browser',\n supportsAsyncContextPropagation: false,\n internalStackMarkers: ['/packages/core/src/', '/packages/liteguard-browser/src/', '/sdk/js/packages/'],\n execution: executionAdapter,\n requestScope: requestScopeAdapter,\n measurement: measurementAdapter,\n now: () => Date.now(),\n monotonicNow: () => globalThis.performance?.now?.() ?? Date.now(),\n fetch: (input, init) => globalThis.fetch(input, init),\n setTimeout: (callback, ms) => globalThis.setTimeout(callback, ms),\n clearTimeout: (handle) => globalThis.clearTimeout(handle as ReturnType<typeof setTimeout>),\n setInterval: (callback, ms) => globalThis.setInterval(callback, ms),\n clearInterval: (handle) => globalThis.clearInterval(handle as ReturnType<typeof setInterval>),\n installLifecycleHooks: ({ flushKeepalive }) => {\n if (typeof window === 'undefined' || typeof document === 'undefined') {\n return;\n }\n\n const onVisibilityChange = () => {\n if (document.visibilityState === 'hidden') {\n flushKeepalive();\n }\n };\n const onPageHide = () => {\n flushKeepalive();\n };\n\n document.addEventListener('visibilitychange', onVisibilityChange);\n window.addEventListener('pagehide', onPageHide);\n\n return () => {\n document.removeEventListener('visibilitychange', onVisibilityChange);\n window.removeEventListener('pagehide', onPageHide);\n };\n },\n};\n"],"mappings":"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","names":["import_core"]}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
import { evaluateGuard } from "@liteguard/core";
|
|
3
|
+
|
|
4
|
+
// src/client.ts
|
|
5
|
+
import { BaseLiteguardClient } from "@liteguard/core";
|
|
6
|
+
|
|
7
|
+
// src/runtime.ts
|
|
8
|
+
var StackExecutionAdapter = class {
|
|
9
|
+
current;
|
|
10
|
+
/** Return the currently active browser execution scope, if any. */
|
|
11
|
+
getStore() {
|
|
12
|
+
return this.current;
|
|
13
|
+
}
|
|
14
|
+
/** Run a callback while this adapter's execution scope is active. */
|
|
15
|
+
run(initialState, fn) {
|
|
16
|
+
const previous = this.current;
|
|
17
|
+
this.current = initialState;
|
|
18
|
+
try {
|
|
19
|
+
return fn();
|
|
20
|
+
} finally {
|
|
21
|
+
this.current = previous;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
var StackRequestScopeAdapter = class {
|
|
26
|
+
current;
|
|
27
|
+
/** Return the currently active browser request scope, if any. */
|
|
28
|
+
getStore() {
|
|
29
|
+
return this.current;
|
|
30
|
+
}
|
|
31
|
+
/** Run a callback while this adapter's request scope is active. */
|
|
32
|
+
run(initialState, fn) {
|
|
33
|
+
const previous = this.current;
|
|
34
|
+
this.current = initialState;
|
|
35
|
+
try {
|
|
36
|
+
return fn();
|
|
37
|
+
} finally {
|
|
38
|
+
this.current = previous;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
function getMemoryInfo() {
|
|
43
|
+
const perf = globalThis.performance;
|
|
44
|
+
return perf.memory;
|
|
45
|
+
}
|
|
46
|
+
var measurementAdapter = {
|
|
47
|
+
/** Capture a monotonic start time for a guarded execution in the browser. */
|
|
48
|
+
beginGuardExecution() {
|
|
49
|
+
return globalThis.performance?.now?.() ?? Date.now();
|
|
50
|
+
},
|
|
51
|
+
/** Capture heap statistics for a `guard_check` signal when available. */
|
|
52
|
+
captureGuardCheck() {
|
|
53
|
+
const memory = getMemoryInfo();
|
|
54
|
+
return {
|
|
55
|
+
guardCheck: {
|
|
56
|
+
...memory?.usedJSHeapSize !== void 0 ? { heapUsedBytes: memory.usedJSHeapSize } : {},
|
|
57
|
+
...memory?.totalJSHeapSize !== void 0 ? { heapTotalBytes: memory.totalJSHeapSize } : {}
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
},
|
|
61
|
+
/** Capture completion metrics for a guarded code path in the browser. */
|
|
62
|
+
captureGuardExecution(startToken, completed, error) {
|
|
63
|
+
const start = typeof startToken === "number" ? startToken : globalThis.performance?.now?.() ?? Date.now();
|
|
64
|
+
const end = globalThis.performance?.now?.() ?? Date.now();
|
|
65
|
+
const memory = getMemoryInfo();
|
|
66
|
+
return {
|
|
67
|
+
guardExecution: {
|
|
68
|
+
durationNs: Math.round((end - start) * 1e6),
|
|
69
|
+
...memory?.usedJSHeapSize !== void 0 ? { heapUsedEndBytes: memory.usedJSHeapSize } : {},
|
|
70
|
+
...memory?.totalJSHeapSize !== void 0 ? { heapTotalEndBytes: memory.totalJSHeapSize } : {},
|
|
71
|
+
completed,
|
|
72
|
+
...error && error instanceof Error && error.name ? { errorClass: error.name } : {}
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
var executionAdapter = new StackExecutionAdapter();
|
|
78
|
+
var requestScopeAdapter = new StackRequestScopeAdapter();
|
|
79
|
+
var browserRuntime = {
|
|
80
|
+
name: "browser",
|
|
81
|
+
supportsAsyncContextPropagation: false,
|
|
82
|
+
internalStackMarkers: ["/packages/core/src/", "/packages/liteguard-browser/src/", "/sdk/js/packages/"],
|
|
83
|
+
execution: executionAdapter,
|
|
84
|
+
requestScope: requestScopeAdapter,
|
|
85
|
+
measurement: measurementAdapter,
|
|
86
|
+
now: () => Date.now(),
|
|
87
|
+
monotonicNow: () => globalThis.performance?.now?.() ?? Date.now(),
|
|
88
|
+
fetch: (input, init) => globalThis.fetch(input, init),
|
|
89
|
+
setTimeout: (callback, ms) => globalThis.setTimeout(callback, ms),
|
|
90
|
+
clearTimeout: (handle) => globalThis.clearTimeout(handle),
|
|
91
|
+
setInterval: (callback, ms) => globalThis.setInterval(callback, ms),
|
|
92
|
+
clearInterval: (handle) => globalThis.clearInterval(handle),
|
|
93
|
+
installLifecycleHooks: ({ flushKeepalive }) => {
|
|
94
|
+
if (typeof window === "undefined" || typeof document === "undefined") {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
const onVisibilityChange = () => {
|
|
98
|
+
if (document.visibilityState === "hidden") {
|
|
99
|
+
flushKeepalive();
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
const onPageHide = () => {
|
|
103
|
+
flushKeepalive();
|
|
104
|
+
};
|
|
105
|
+
document.addEventListener("visibilitychange", onVisibilityChange);
|
|
106
|
+
window.addEventListener("pagehide", onPageHide);
|
|
107
|
+
return () => {
|
|
108
|
+
document.removeEventListener("visibilitychange", onVisibilityChange);
|
|
109
|
+
window.removeEventListener("pagehide", onPageHide);
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
// src/client.ts
|
|
115
|
+
var LiteguardClient = class extends BaseLiteguardClient {
|
|
116
|
+
/**
|
|
117
|
+
* @param projectClientKeyId - Your project client key ID from the Liteguard dashboard.
|
|
118
|
+
* @param options - Optional SDK configuration overrides.
|
|
119
|
+
*/
|
|
120
|
+
constructor(projectClientKeyId, options = {}) {
|
|
121
|
+
super(browserRuntime, projectClientKeyId, options);
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Run `fn` inside `scope` for synchronous browser work only.
|
|
125
|
+
*
|
|
126
|
+
* Browser runtimes do not propagate Liteguard scope across `await`
|
|
127
|
+
* boundaries. For async work, pass an explicit `scope` to each call or use
|
|
128
|
+
* `scope.executeIfOpenAsync()`.
|
|
129
|
+
*/
|
|
130
|
+
runWithScope(scope, fn) {
|
|
131
|
+
return super.runWithScope(scope, fn);
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Convenience helper for synchronous browser-only scope callbacks.
|
|
135
|
+
*/
|
|
136
|
+
withProperties(properties, fn) {
|
|
137
|
+
return super.withProperties(properties, fn);
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Bind protected context and run a synchronous callback in the derived scope.
|
|
141
|
+
*/
|
|
142
|
+
async withProtectedContext(protectedContext, fn) {
|
|
143
|
+
return await super.withProtectedContext(protectedContext, fn);
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Run `fn` inside a correlated synchronous execution scope.
|
|
147
|
+
*/
|
|
148
|
+
withExecution(fn) {
|
|
149
|
+
return super.withExecution(fn);
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
export {
|
|
153
|
+
LiteguardClient,
|
|
154
|
+
evaluateGuard
|
|
155
|
+
};
|
|
156
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/client.ts","../src/runtime.ts"],"sourcesContent":["export type {\n GetGuardsRequest,\n GetGuardsResponse,\n Guard,\n GuardCheckPerformance,\n GuardExecutionPerformance,\n ClientOptions,\n FlushOptions,\n LiteguardChangeListener,\n LiteguardScope,\n Options,\n Operator,\n Properties,\n PropertyValue,\n ProtectedContext,\n Rule,\n SendUnadoptedGuardsRequest,\n SendUnadoptedGuardsResponse,\n Signal,\n SignalPerformance,\n ScopedOptions,\n TraceContext,\n} from '@liteguard/core';\nexport { evaluateGuard } from '@liteguard/core';\nexport { LiteguardClient } from './client.js';\n","import { BaseLiteguardClient } from '@liteguard/core';\nimport type { ClientOptions, LiteguardScope, Properties, ProtectedContext } from '@liteguard/core';\nimport { browserRuntime } from './runtime.js';\n\ntype SyncResult<T> = T extends PromiseLike<unknown> ? never : T;\n\n/**\n * Liteguard client for browser environments.\n *\n * Uses a stack-based execution adapter (no `AsyncLocalStorage`) and\n * `performance.now()` / `performance.memory` for measurement. Automatically\n * flushes buffered signals on `visibilitychange` and `pagehide`.\n *\n * @example\n * ```ts\n * import { LiteguardClient } from '@liteguard/liteguard-browser';\n *\n * const client = new LiteguardClient('pk_live_...');\n * await client.start();\n *\n * if (client.isOpen('feature.beta')) {\n * // new code path\n * }\n * ```\n */\nexport class LiteguardClient extends BaseLiteguardClient {\n /**\n * @param projectClientKeyId - Your project client key ID from the Liteguard dashboard.\n * @param options - Optional SDK configuration overrides.\n */\n constructor(projectClientKeyId: string, options: ClientOptions = {}) {\n super(browserRuntime, projectClientKeyId, options);\n }\n\n /**\n * Run `fn` inside `scope` for synchronous browser work only.\n *\n * Browser runtimes do not propagate Liteguard scope across `await`\n * boundaries. For async work, pass an explicit `scope` to each call or use\n * `scope.executeIfOpenAsync()`.\n */\n override runWithScope<T>(scope: LiteguardScope, fn: () => SyncResult<T>): SyncResult<T> {\n return super.runWithScope(scope, fn as () => T) as SyncResult<T>;\n }\n\n /**\n * Convenience helper for synchronous browser-only scope callbacks.\n */\n override withProperties<T>(properties: Properties, fn: () => SyncResult<T>): SyncResult<T> {\n return super.withProperties(properties, fn as () => T) as SyncResult<T>;\n }\n\n /**\n * Bind protected context and run a synchronous callback in the derived scope.\n */\n override async withProtectedContext<T>(\n protectedContext: ProtectedContext,\n fn: () => SyncResult<T>,\n ): Promise<Awaited<T>> {\n return await super.withProtectedContext(protectedContext, fn as () => T);\n }\n\n /**\n * Run `fn` inside a correlated synchronous execution scope.\n */\n override withExecution<T>(fn: () => SyncResult<T>): SyncResult<T> {\n return super.withExecution(fn as () => T) as SyncResult<T>;\n }\n}\n","import type {\n ExecutionAdapter,\n ExecutionState,\n MeasurementAdapter,\n RequestScopeAdapter,\n RequestScopeStore,\n RuntimeAdapter,\n Signal,\n} from '@liteguard/core';\n\ntype MemoryInfo = {\n usedJSHeapSize?: number;\n totalJSHeapSize?: number;\n jsHeapSizeLimit?: number;\n};\n\nclass StackExecutionAdapter implements ExecutionAdapter {\n private current: ExecutionState | undefined;\n\n /** Return the currently active browser execution scope, if any. */\n getStore(): ExecutionState | undefined {\n return this.current;\n }\n\n /** Run a callback while this adapter's execution scope is active. */\n run<T>(initialState: ExecutionState, fn: () => T): T {\n const previous = this.current;\n this.current = initialState;\n try {\n return fn();\n } finally {\n this.current = previous;\n }\n }\n}\n\nclass StackRequestScopeAdapter implements RequestScopeAdapter {\n private current: RequestScopeStore | undefined;\n\n /** Return the currently active browser request scope, if any. */\n getStore(): RequestScopeStore | undefined {\n return this.current;\n }\n\n /** Run a callback while this adapter's request scope is active. */\n run<T>(initialState: RequestScopeStore, fn: () => T): T {\n const previous = this.current;\n this.current = initialState;\n try {\n return fn();\n } finally {\n this.current = previous;\n }\n }\n}\n\n/** Read browser heap statistics when the runtime exposes them. */\nfunction getMemoryInfo(): MemoryInfo | undefined {\n const perf = globalThis.performance as Performance & { memory?: MemoryInfo };\n return perf.memory;\n}\n\nconst measurementAdapter: MeasurementAdapter = {\n /** Capture a monotonic start time for a guarded execution in the browser. */\n beginGuardExecution(): number {\n return globalThis.performance?.now?.() ?? Date.now();\n },\n /** Capture heap statistics for a `guard_check` signal when available. */\n captureGuardCheck(): NonNullable<Signal['measurement']> {\n const memory = getMemoryInfo();\n return {\n guardCheck: {\n ...(memory?.usedJSHeapSize !== undefined ? { heapUsedBytes: memory.usedJSHeapSize } : {}),\n ...(memory?.totalJSHeapSize !== undefined ? { heapTotalBytes: memory.totalJSHeapSize } : {}),\n },\n };\n },\n /** Capture completion metrics for a guarded code path in the browser. */\n captureGuardExecution(startToken: unknown, completed: boolean, error?: unknown): NonNullable<Signal['measurement']> {\n const start = typeof startToken === 'number' ? startToken : globalThis.performance?.now?.() ?? Date.now();\n const end = globalThis.performance?.now?.() ?? Date.now();\n const memory = getMemoryInfo();\n return {\n guardExecution: {\n durationNs: Math.round((end - start) * 1_000_000),\n ...(memory?.usedJSHeapSize !== undefined ? { heapUsedEndBytes: memory.usedJSHeapSize } : {}),\n ...(memory?.totalJSHeapSize !== undefined ? { heapTotalEndBytes: memory.totalJSHeapSize } : {}),\n completed,\n ...(error && error instanceof Error && error.name ? { errorClass: error.name } : {}),\n },\n };\n },\n};\n\nconst executionAdapter = new StackExecutionAdapter();\nconst requestScopeAdapter = new StackRequestScopeAdapter();\n\n/** Browser runtime adapter used by the platform-specific Liteguard client. */\nexport const browserRuntime: RuntimeAdapter = {\n name: 'browser',\n supportsAsyncContextPropagation: false,\n internalStackMarkers: ['/packages/core/src/', '/packages/liteguard-browser/src/', '/sdk/js/packages/'],\n execution: executionAdapter,\n requestScope: requestScopeAdapter,\n measurement: measurementAdapter,\n now: () => Date.now(),\n monotonicNow: () => globalThis.performance?.now?.() ?? Date.now(),\n fetch: (input, init) => globalThis.fetch(input, init),\n setTimeout: (callback, ms) => globalThis.setTimeout(callback, ms),\n clearTimeout: (handle) => globalThis.clearTimeout(handle as ReturnType<typeof setTimeout>),\n setInterval: (callback, ms) => globalThis.setInterval(callback, ms),\n clearInterval: (handle) => globalThis.clearInterval(handle as ReturnType<typeof setInterval>),\n installLifecycleHooks: ({ flushKeepalive }) => {\n if (typeof window === 'undefined' || typeof document === 'undefined') {\n return;\n }\n\n const onVisibilityChange = () => {\n if (document.visibilityState === 'hidden') {\n flushKeepalive();\n }\n };\n const onPageHide = () => {\n flushKeepalive();\n };\n\n document.addEventListener('visibilitychange', onVisibilityChange);\n window.addEventListener('pagehide', onPageHide);\n\n return () => {\n document.removeEventListener('visibilitychange', onVisibilityChange);\n window.removeEventListener('pagehide', onPageHide);\n };\n },\n};\n"],"mappings":"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","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@liteguard/liteguard-browser",
|
|
3
|
+
"version": "0.2.20260314",
|
|
4
|
+
"description": "Liteguard SDK for browser runtimes — feature guards, observability, and security response evaluated locally with zero network overhead per check",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"module": "dist/index.mjs",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"license": "Apache-2.0",
|
|
9
|
+
"homepage": "https://liteguard.io",
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "https://github.com/liteguard/liteguard.git",
|
|
13
|
+
"directory": "sdk/js/packages/liteguard-browser"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"feature-flags",
|
|
17
|
+
"feature-guards",
|
|
18
|
+
"feature-toggles",
|
|
19
|
+
"liteguard",
|
|
20
|
+
"observability",
|
|
21
|
+
"security",
|
|
22
|
+
"browser"
|
|
23
|
+
],
|
|
24
|
+
"exports": {
|
|
25
|
+
".": {
|
|
26
|
+
"types": "./dist/index.d.ts",
|
|
27
|
+
"import": "./dist/index.mjs",
|
|
28
|
+
"require": "./dist/index.js"
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"files": [
|
|
32
|
+
"dist",
|
|
33
|
+
"README.md"
|
|
34
|
+
],
|
|
35
|
+
"sideEffects": false,
|
|
36
|
+
"scripts": {
|
|
37
|
+
"build": "tsup src/index.ts --format cjs,esm --dts --sourcemap --clean"
|
|
38
|
+
},
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"@liteguard/core": "*"
|
|
41
|
+
}
|
|
42
|
+
}
|