@dr-sentry/sdk 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/README.md +103 -5
  2. package/dist/cjs/cache.d.ts +30 -3
  3. package/dist/cjs/cache.d.ts.map +1 -1
  4. package/dist/cjs/cache.js +32 -5
  5. package/dist/cjs/cache.js.map +1 -1
  6. package/dist/cjs/client.d.ts +55 -1
  7. package/dist/cjs/client.d.ts.map +1 -1
  8. package/dist/cjs/client.js +297 -37
  9. package/dist/cjs/client.js.map +1 -1
  10. package/dist/cjs/defaults.d.ts +58 -0
  11. package/dist/cjs/defaults.d.ts.map +1 -0
  12. package/dist/cjs/defaults.js +175 -0
  13. package/dist/cjs/defaults.js.map +1 -0
  14. package/dist/cjs/index.d.ts +2 -1
  15. package/dist/cjs/index.d.ts.map +1 -1
  16. package/dist/cjs/index.js +4 -1
  17. package/dist/cjs/index.js.map +1 -1
  18. package/dist/cjs/persistence.d.ts +26 -0
  19. package/dist/cjs/persistence.d.ts.map +1 -0
  20. package/dist/cjs/persistence.js +74 -0
  21. package/dist/cjs/persistence.js.map +1 -0
  22. package/dist/cjs/status-reporter.d.ts +42 -0
  23. package/dist/cjs/status-reporter.d.ts.map +1 -0
  24. package/dist/cjs/status-reporter.js +153 -0
  25. package/dist/cjs/status-reporter.js.map +1 -0
  26. package/dist/cjs/streaming.d.ts +10 -0
  27. package/dist/cjs/streaming.d.ts.map +1 -1
  28. package/dist/cjs/streaming.js +9 -1
  29. package/dist/cjs/streaming.js.map +1 -1
  30. package/dist/cjs/sync.d.ts +105 -0
  31. package/dist/cjs/sync.d.ts.map +1 -0
  32. package/dist/cjs/sync.js +191 -0
  33. package/dist/cjs/sync.js.map +1 -0
  34. package/dist/cjs/types.d.ts +78 -1
  35. package/dist/cjs/types.d.ts.map +1 -1
  36. package/dist/esm/cache.d.ts +30 -3
  37. package/dist/esm/cache.d.ts.map +1 -1
  38. package/dist/esm/cache.js +32 -5
  39. package/dist/esm/cache.js.map +1 -1
  40. package/dist/esm/client.d.ts +55 -1
  41. package/dist/esm/client.d.ts.map +1 -1
  42. package/dist/esm/client.js +297 -37
  43. package/dist/esm/client.js.map +1 -1
  44. package/dist/esm/defaults.d.ts +58 -0
  45. package/dist/esm/defaults.d.ts.map +1 -0
  46. package/dist/esm/defaults.js +136 -0
  47. package/dist/esm/defaults.js.map +1 -0
  48. package/dist/esm/index.d.ts +2 -1
  49. package/dist/esm/index.d.ts.map +1 -1
  50. package/dist/esm/index.js +1 -0
  51. package/dist/esm/index.js.map +1 -1
  52. package/dist/esm/persistence.d.ts +26 -0
  53. package/dist/esm/persistence.d.ts.map +1 -0
  54. package/dist/esm/persistence.js +70 -0
  55. package/dist/esm/persistence.js.map +1 -0
  56. package/dist/esm/status-reporter.d.ts +42 -0
  57. package/dist/esm/status-reporter.d.ts.map +1 -0
  58. package/dist/esm/status-reporter.js +148 -0
  59. package/dist/esm/status-reporter.js.map +1 -0
  60. package/dist/esm/streaming.d.ts +10 -0
  61. package/dist/esm/streaming.d.ts.map +1 -1
  62. package/dist/esm/streaming.js +9 -1
  63. package/dist/esm/streaming.js.map +1 -1
  64. package/dist/esm/sync.d.ts +105 -0
  65. package/dist/esm/sync.d.ts.map +1 -0
  66. package/dist/esm/sync.js +187 -0
  67. package/dist/esm/sync.js.map +1 -0
  68. package/dist/esm/types.d.ts +78 -1
  69. package/dist/esm/types.d.ts.map +1 -1
  70. package/package.json +1 -1
package/README.md CHANGED
@@ -40,6 +40,42 @@ const config = await client.jsonValue('rate-limits', { rpm: 100 });
40
40
  client.close();
41
41
  ```
42
42
 
43
+ ## Status reporting (optional)
44
+
45
+ Enable `reportStatus` to have the SDK push version + health to DeploySentry automatically. No separate startup code needed — the SDK posts `POST /applications/:id/status` on init and on an interval.
46
+
47
+ ```typescript
48
+ const client = new DeploySentryClient({
49
+ apiKey: process.env.DS_API_KEY!,
50
+ environment: 'production',
51
+ project: 'my-app',
52
+ application: 'my-web-app',
53
+
54
+ // Agentless status reporting
55
+ applicationId: process.env.DS_APPLICATION_ID!, // UUID of the app
56
+ reportStatus: true,
57
+ reportStatusIntervalMs: 30_000, // default; 0 = startup-only
58
+ reportStatusVersion: process.env.APP_VERSION, // optional override
59
+ reportStatusCommitSha: process.env.GIT_SHA,
60
+ reportStatusDeploySlot: process.env.DS_DEPLOY_SLOT, // "stable" | "canary"
61
+ reportStatusTags: { region: process.env.REGION ?? 'unknown' },
62
+ reportStatusHealthProvider: async () => ({
63
+ state: (await isDbUp()) ? 'healthy' : 'degraded',
64
+ score: 0.99,
65
+ }),
66
+ });
67
+
68
+ await client.initialize();
69
+ ```
70
+
71
+ The API key must carry the `status:write` scope and be scoped to a single application + environment. When `reportStatus` is `true` but `applicationId` is omitted, the reporter logs a warning and is disabled — flag evaluation continues to work.
72
+
73
+ Without a `reportStatusHealthProvider`, the SDK sends `health: "healthy"` on every tick ("process alive" floor). Supply a provider if your app can detect degradation (stale DB, downstream outages, etc.).
74
+
75
+ Version auto-detection (when `reportStatusVersion` is omitted) checks these env vars in order: `APP_VERSION`, `GIT_SHA`, `GIT_COMMIT`, `SOURCE_COMMIT`, `RAILWAY_GIT_COMMIT_SHA`, `RENDER_GIT_COMMIT`, `VERCEL_GIT_COMMIT_SHA`, `HEROKU_SLUG_COMMIT`, `npm_package_version` — falling back to the literal string `"unknown"`.
76
+
77
+ The first `/status` report with a version DeploySentry has not seen auto-creates a `mode=record` deployment with `source="app-push"`, so deploy history populates even without a Railway/Render/etc. webhook configured.
78
+
43
79
  ## Evaluation Context
44
80
 
45
81
  Pass targeting context with every evaluation:
@@ -62,7 +98,7 @@ Every flag carries structured metadata describing its purpose, ownership, and li
62
98
  ```typescript
63
99
  const result = await client.detail('new-checkout');
64
100
 
65
- console.log(result.metadata.category); // 'release' | 'feature' | 'experiment' | 'ops' | 'permission'
101
+ console.log(result.metadata.category); // 'release' | 'feature' | 'experiment' | 'ops' | 'permission' | 'envvar'
66
102
  console.log(result.metadata.purpose); // "Gradual rollout of new checkout flow"
67
103
  console.log(result.metadata.owners); // ["payments-team", "jane@example.com"]
68
104
  console.log(result.metadata.isPermanent); // false
@@ -81,6 +117,7 @@ Flags are classified into categories that drive lifecycle policies:
81
117
  | `experiment` | A/B tests and experiments with defined end dates |
82
118
  | `ops` | Operational controls (kill switches, rate limits) |
83
119
  | `permission` | Entitlement and access-control flags |
120
+ | `envvar` | Non-secret environment variable tracking |
84
121
 
85
122
  Query by category:
86
123
 
@@ -113,6 +150,36 @@ List all cached flags:
113
150
  const flags = client.allFlags();
114
151
  ```
115
152
 
153
+ ## Inspecting Flag Sources (admin / support view)
154
+
155
+ `inspect()` returns a provenance-tagged snapshot of every flag the SDK currently knows about — drawn from all sources at once (live server cache, offline file config, and offline defaults). Each entry reports the resolved value, its type, **where the value came from**, an evaluation reason, and when it was last fetched. Wire it into an admin or support panel to see exactly what an application is serving and why.
156
+
157
+ ```typescript
158
+ const view = client.inspect();
159
+ // [
160
+ // {
161
+ // key: 'new-checkout',
162
+ // value: true,
163
+ // type: 'boolean',
164
+ // enabled: true,
165
+ // source: 'server', // 'server' | 'cache' | 'file' | 'default'
166
+ // reason: 'LIVE', // LIVE | CACHE | OFFLINE_FILE | OFFLINE_DEFAULT | DEFAULT
167
+ // fetchedAt: '2026-06-23T12:00:00.000Z',
168
+ // stale: false, // true when a cached value is past its TTL
169
+ // },
170
+ // ...
171
+ // ]
172
+ ```
173
+
174
+ | `source` | Meaning |
175
+ | --- | --- |
176
+ | `server` | Fetched live from the API and still within its cache TTL. |
177
+ | `cache` | A previously-fetched server value past its TTL, still served because the server is currently unreachable (`stale: true`). |
178
+ | `file` | An offline file — a `mode: 'file'` config, or the offline defaults loaded via `loadDefaults*()` (the `reason` distinguishes `OFFLINE_FILE` vs `OFFLINE_DEFAULT`). |
179
+ | `default` | No value from any source; callers receive their coded `defaultValue`. |
180
+
181
+ `inspect()` is a read-only snapshot — it does not contact the server or evaluate targeting rules for a specific user.
182
+
116
183
  ## Register / Dispatch Pattern
117
184
 
118
185
  The register/dispatch pattern lets you centralize all flag-gated behavior in one place instead of scattering `if/else` checks throughout your codebase. Register named operations with their handlers and optional flag keys, then dispatch by operation name at the call site.
@@ -191,6 +258,37 @@ const value = await client.boolValue('any-flag', true);
191
258
  // Returns the default value: true
192
259
  ```
193
260
 
261
+ ## Offline Defaults
262
+
263
+ For deployments where the SDK may briefly be unable to reach DeploySentry (CI runs without network, cold-start before SSE connects, air-gapped builds), commit a flag snapshot to your repo and load it as fallback. The SDK still prefers the live API; defaults only fire when both the API and the in-process cache are empty.
264
+
265
+ Generate the snapshot with the CLI:
266
+
267
+ ```bash
268
+ deploysentry flags export --application web --env production -f flags.json
269
+ ```
270
+
271
+ Then load it after constructing the client:
272
+
273
+ ```typescript
274
+ const client = new DeploySentryClient({
275
+ apiKey: process.env.DEPLOYSENTRY_API_KEY!,
276
+ environment: 'production',
277
+ project: 'my-app',
278
+ application: 'web',
279
+ });
280
+ await client.loadDefaultsFromFile('flags.json');
281
+ // or sync from an already-parsed object:
282
+ // client.loadDefaults(JSON.parse(fs.readFileSync('flags.json', 'utf-8')));
283
+ ```
284
+
285
+ Evaluation order:
286
+
287
+ 1. **Live API** when reachable.
288
+ 2. **In-process cache** (entries from prior live calls).
289
+ 3. **Offline defaults** loaded above — picks the per-environment value matching your `environment` option (by UUID first, then by name, case-insensitive). Falls back to the flag's global `default_value` when no env matches.
290
+ 4. **Caller's `defaultValue`** when the flag isn't in the export.
291
+
194
292
  ## Configuration
195
293
 
196
294
  | Option | Type | Required | Default | Description |
@@ -207,15 +305,15 @@ const value = await client.boolValue('any-flag', true);
207
305
 
208
306
  ## Offline / File Mode
209
307
 
210
- The SDK can load flag configurations from a local YAML file instead of (or as fallback to) the server.
308
+ The SDK can load flag configurations from a local YAML/JSON file. **The server is always the source of truth** the exported file is a *backup/fallback only*. In production use `server-with-fallback`: the SDK reaches the server first on every evaluation and consults the local file only when the server (and the in-process cache) are unreachable. Pure `file` mode (no server contact) is intended for local development, CI, and testing — not for normal production operation.
211
309
 
212
310
  ### Modes
213
311
 
214
312
  | Mode | Behavior |
215
313
  | --- | --- |
216
- | `server` (default) | API calls + SSE streaming |
217
- | `file` | Load from YAML file, evaluate locally. No server contact. |
218
- | `server-with-fallback` | Try server first. If unavailable, fall back to YAML file. |
314
+ | `server` (default) | API calls + SSE streaming. Server only. |
315
+ | `file` | Load from local file, evaluate locally. **No server contact — dev/CI/testing only.** |
316
+ | `server-with-fallback` | **Recommended for resilience.** Always try the server first; fall back to the local file only when the server is unreachable, then return to live as soon as it recovers. |
219
317
 
220
318
  ### Usage
221
319
 
@@ -1,4 +1,14 @@
1
1
  import { Flag } from './types';
2
+ /** A cache entry exposed for inspection, including staleness. */
3
+ export interface CacheInspectionEntry {
4
+ flag: Flag;
5
+ /** Epoch-ms when the entry was last written. */
6
+ storedAt: number;
7
+ /** Epoch-ms when the entry's TTL elapses. */
8
+ expiresAt: number;
9
+ /** True when the TTL has elapsed but the entry is still held. */
10
+ stale: boolean;
11
+ }
2
12
  /**
3
13
  * In-memory flag cache with per-entry TTL support.
4
14
  *
@@ -13,14 +23,31 @@ export declare class FlagCache {
13
23
  * Defaults to 60 000 (1 minute).
14
24
  */
15
25
  constructor(ttlMs?: number);
16
- /** Store or update a single flag in the cache. */
17
- set(flag: Flag): void;
26
+ /**
27
+ * Store or update a single flag in the cache.
28
+ *
29
+ * Pass `durable: true` for flags drawn from a full server sync (or a restored
30
+ * disk snapshot) so they never expire — the resilient sync engine keeps them
31
+ * fresh and the local copy must remain serveable while the server is
32
+ * unreachable. Omit it for single-flag SSE updates, which inherit the TTL.
33
+ */
34
+ set(flag: Flag, opts?: {
35
+ durable?: boolean;
36
+ }): void;
18
37
  /** Bulk-insert flags, replacing any stale entries. */
19
- setMany(flags: Flag[]): void;
38
+ setMany(flags: Flag[], opts?: {
39
+ durable?: boolean;
40
+ }): void;
20
41
  /** Retrieve a flag by key. Returns `undefined` if missing or expired. */
21
42
  get(key: string): Flag | undefined;
22
43
  /** Return all non-expired flags currently in the cache. */
23
44
  getAll(): Flag[];
45
+ /**
46
+ * Return every entry held in the cache — including stale (TTL-elapsed)
47
+ * entries — without evicting anything. For inspection / admin views only;
48
+ * read paths should use {@link get} / {@link getAll} which evict.
49
+ */
50
+ entries(): CacheInspectionEntry[];
24
51
  /** Remove a single key from the cache. */
25
52
  delete(key: string): void;
26
53
  /** Remove all expired entries. Returns the number of entries purged. */
@@ -1 +1 @@
1
- {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../src/cache.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAO/B;;;;;GAKG;AACH,qBAAa,SAAS;IACpB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAiC;IACvD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAE/B;;;OAGG;gBACS,KAAK,GAAE,MAAe;IAIlC,kDAAkD;IAClD,GAAG,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI;IAOrB,sDAAsD;IACtD,OAAO,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,IAAI;IAM5B,yEAAyE;IACzE,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS;IAYlC,2DAA2D;IAC3D,MAAM,IAAI,IAAI,EAAE;IAehB,0CAA0C;IAC1C,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAIzB,wEAAwE;IACxE,YAAY,IAAI,MAAM;IActB,uCAAuC;IACvC,KAAK,IAAI,IAAI;IAIb,8DAA8D;IAC9D,IAAI,IAAI,IAAI,MAAM,CAEjB;CACF"}
1
+ {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../src/cache.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAQ/B,iEAAiE;AACjE,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,IAAI,CAAC;IACX,gDAAgD;IAChD,QAAQ,EAAE,MAAM,CAAC;IACjB,6CAA6C;IAC7C,SAAS,EAAE,MAAM,CAAC;IAClB,iEAAiE;IACjE,KAAK,EAAE,OAAO,CAAC;CAChB;AAED;;;;;GAKG;AACH,qBAAa,SAAS;IACpB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAiC;IACvD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAE/B;;;OAGG;gBACS,KAAK,GAAE,MAAe;IAIlC;;;;;;;OAOG;IACH,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI;IASnD,sDAAsD;IACtD,OAAO,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,IAAI,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI;IAM1D,yEAAyE;IACzE,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS;IAYlC,2DAA2D;IAC3D,MAAM,IAAI,IAAI,EAAE;IAehB;;;;OAIG;IACH,OAAO,IAAI,oBAAoB,EAAE;IAcjC,0CAA0C;IAC1C,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAIzB,wEAAwE;IACxE,YAAY,IAAI,MAAM;IActB,uCAAuC;IACvC,KAAK,IAAI,IAAI;IAIb,8DAA8D;IAC9D,IAAI,IAAI,IAAI,MAAM,CAEjB;CACF"}
package/dist/cjs/cache.js CHANGED
@@ -17,17 +17,26 @@ class FlagCache {
17
17
  constructor(ttlMs = 60_000) {
18
18
  this.ttlMs = ttlMs;
19
19
  }
20
- /** Store or update a single flag in the cache. */
21
- set(flag) {
20
+ /**
21
+ * Store or update a single flag in the cache.
22
+ *
23
+ * Pass `durable: true` for flags drawn from a full server sync (or a restored
24
+ * disk snapshot) so they never expire — the resilient sync engine keeps them
25
+ * fresh and the local copy must remain serveable while the server is
26
+ * unreachable. Omit it for single-flag SSE updates, which inherit the TTL.
27
+ */
28
+ set(flag, opts) {
29
+ const now = Date.now();
22
30
  this.store.set(flag.key, {
23
31
  flag,
24
- expiresAt: Date.now() + this.ttlMs,
32
+ storedAt: now,
33
+ expiresAt: opts?.durable || this.ttlMs <= 0 ? Infinity : now + this.ttlMs,
25
34
  });
26
35
  }
27
36
  /** Bulk-insert flags, replacing any stale entries. */
28
- setMany(flags) {
37
+ setMany(flags, opts) {
29
38
  for (const flag of flags) {
30
- this.set(flag);
39
+ this.set(flag, opts);
31
40
  }
32
41
  }
33
42
  /** Retrieve a flag by key. Returns `undefined` if missing or expired. */
@@ -55,6 +64,24 @@ class FlagCache {
55
64
  }
56
65
  return result;
57
66
  }
67
+ /**
68
+ * Return every entry held in the cache — including stale (TTL-elapsed)
69
+ * entries — without evicting anything. For inspection / admin views only;
70
+ * read paths should use {@link get} / {@link getAll} which evict.
71
+ */
72
+ entries() {
73
+ const now = Date.now();
74
+ const result = [];
75
+ for (const entry of this.store.values()) {
76
+ result.push({
77
+ flag: entry.flag,
78
+ storedAt: entry.storedAt,
79
+ expiresAt: entry.expiresAt,
80
+ stale: now > entry.expiresAt,
81
+ });
82
+ }
83
+ return result;
84
+ }
58
85
  /** Remove a single key from the cache. */
59
86
  delete(key) {
60
87
  this.store.delete(key);
@@ -1 +1 @@
1
- {"version":3,"file":"cache.js","sourceRoot":"","sources":["../../src/cache.ts"],"names":[],"mappings":";;;AAOA;;;;;GAKG;AACH,MAAa,SAAS;IACH,KAAK,GAAG,IAAI,GAAG,EAAsB,CAAC;IACtC,KAAK,CAAS;IAE/B;;;OAGG;IACH,YAAY,QAAgB,MAAM;QAChC,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;IACrB,CAAC;IAED,kDAAkD;IAClD,GAAG,CAAC,IAAU;QACZ,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE;YACvB,IAAI;YACJ,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,KAAK;SACnC,CAAC,CAAC;IACL,CAAC;IAED,sDAAsD;IACtD,OAAO,CAAC,KAAa;QACnB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACjB,CAAC;IACH,CAAC;IAED,yEAAyE;IACzE,GAAG,CAAC,GAAW;QACb,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAClC,IAAI,CAAC,KAAK;YAAE,OAAO,SAAS,CAAC;QAE7B,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,SAAS,EAAE,CAAC;YACjC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACvB,OAAO,SAAS,CAAC;QACnB,CAAC;QAED,OAAO,KAAK,CAAC,IAAI,CAAC;IACpB,CAAC;IAED,2DAA2D;IAC3D,MAAM;QACJ,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,MAAM,MAAM,GAAW,EAAE,CAAC;QAE1B,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACtC,IAAI,GAAG,GAAG,KAAK,CAAC,SAAS,EAAE,CAAC;gBAC1B,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACzB,CAAC;iBAAM,CAAC;gBACN,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YAC1B,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,0CAA0C;IAC1C,MAAM,CAAC,GAAW;QAChB,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACzB,CAAC;IAED,wEAAwE;IACxE,YAAY;QACV,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,IAAI,MAAM,GAAG,CAAC,CAAC;QAEf,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACtC,IAAI,GAAG,GAAG,KAAK,CAAC,SAAS,EAAE,CAAC;gBAC1B,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gBACvB,MAAM,EAAE,CAAC;YACX,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,uCAAuC;IACvC,KAAK;QACH,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;IACrB,CAAC;IAED,8DAA8D;IAC9D,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;IACzB,CAAC;CACF;AArFD,8BAqFC"}
1
+ {"version":3,"file":"cache.js","sourceRoot":"","sources":["../../src/cache.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { ClientOptions, EvaluationContext, EvaluationResult, Flag, FlagCategory } from './types';
1
+ import { ClientOptions, EvaluationContext, EvaluationResult, Flag, FlagCategory, FlagInspection } from './types';
2
2
  /**
3
3
  * DeploySentry feature-flag client.
4
4
  *
@@ -29,9 +29,19 @@ export declare class DeploySentryClient {
29
29
  private readonly onFlagChange?;
30
30
  private readonly cache;
31
31
  private streamClient;
32
+ private readonly persistence;
33
+ private readonly resyncIntervalMs?;
34
+ private syncManager;
32
35
  private _initialized;
33
36
  private flagConfig;
37
+ private offlineDefaults;
38
+ private offlineDefaultsEnvUUID;
39
+ private flagConfigLoadedAt?;
40
+ private offlineDefaultsLoadedAt?;
41
+ private flagsVersion;
34
42
  private registry;
43
+ private statusReporter;
44
+ private readonly statusReporterOptions;
35
45
  constructor(options: ClientOptions);
36
46
  /**
37
47
  * Fetch the initial flag set and open an SSE connection for real-time
@@ -40,6 +50,7 @@ export declare class DeploySentryClient {
40
50
  initialize(): Promise<void>;
41
51
  /** Tear down the SSE connection and release resources. */
42
52
  close(): void;
53
+ private startStatusReporter;
43
54
  /**
44
55
  * Clear the local cache and re-fetch all flags from the server.
45
56
  * Useful when session state may have changed and the client needs
@@ -69,10 +80,53 @@ export declare class DeploySentryClient {
69
80
  flagOwners(key: string): string[];
70
81
  /** Return every flag currently held in the local cache. */
71
82
  allFlags(): Flag[];
83
+ /**
84
+ * Return a provenance-tagged view of every flag the SDK currently knows
85
+ * about, drawn from all sources (live server cache, offline file config,
86
+ * and offline defaults). Each entry reports the resolved value, its type,
87
+ * the {@link FlagSource | source} it came from, an evaluation reason code,
88
+ * and when it was last fetched / loaded.
89
+ *
90
+ * Intended for wiring into an admin or support panel so operators can see
91
+ * exactly what value an application is serving and where it came from. This
92
+ * is a read-only snapshot — it does not contact the server or evaluate
93
+ * targeting rules for a specific user.
94
+ */
95
+ inspect(): FlagInspection[];
72
96
  register<T extends (...args: any[]) => any>(operation: string, handler: T, flagKey?: string): void;
73
97
  dispatch<T extends (...args: any[]) => any>(operation: string, _context?: EvaluationContext): T;
74
98
  private evaluate;
99
+ /**
100
+ * Load offline default values from a flag-export file. When the live API
101
+ * is unreachable and the cache has no entry, the SDK falls back to these
102
+ * defaults for {@link boolValue} / {@link stringValue} / {@link intValue}
103
+ * / {@link jsonValue} calls.
104
+ *
105
+ * Accepts the JSON (default) or YAML format produced by
106
+ * `deploysentry flags export`.
107
+ *
108
+ * Environment matching: the SDK matches the configured `environment`
109
+ * option against the export's `environments[]` first by UUID, then by
110
+ * name (case-insensitive). When a match is found, that env's per-flag
111
+ * `{enabled, value}` overrides the flag's global `default_value`.
112
+ *
113
+ * @example
114
+ * await client.loadDefaultsFromFile('flags.json');
115
+ */
116
+ loadDefaultsFromFile(path: string): Promise<void>;
117
+ /**
118
+ * Synchronous variant of {@link loadDefaultsFromFile} that accepts an
119
+ * already-parsed object (or a JSON string).
120
+ */
121
+ loadDefaults(payload: unknown): void;
75
122
  private fetchAllFlags;
123
+ /**
124
+ * The project's flag-set version last loaded from the server, or `null` if
125
+ * no successful server load has happened (offline/file mode, or boot before
126
+ * the first sync). The version advances on any change to the project's flag
127
+ * state, so it validates exactly which flag set the SDK is serving.
128
+ */
129
+ getFlagsVersion(): number | null;
76
130
  private fetchFlag;
77
131
  private post;
78
132
  private request;
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/client.ts"],"names":[],"mappings":"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"}