@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.
- package/README.md +103 -5
- package/dist/cjs/cache.d.ts +30 -3
- package/dist/cjs/cache.d.ts.map +1 -1
- package/dist/cjs/cache.js +32 -5
- package/dist/cjs/cache.js.map +1 -1
- package/dist/cjs/client.d.ts +55 -1
- package/dist/cjs/client.d.ts.map +1 -1
- package/dist/cjs/client.js +297 -37
- package/dist/cjs/client.js.map +1 -1
- package/dist/cjs/defaults.d.ts +58 -0
- package/dist/cjs/defaults.d.ts.map +1 -0
- package/dist/cjs/defaults.js +175 -0
- package/dist/cjs/defaults.js.map +1 -0
- package/dist/cjs/index.d.ts +2 -1
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +4 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/persistence.d.ts +26 -0
- package/dist/cjs/persistence.d.ts.map +1 -0
- package/dist/cjs/persistence.js +74 -0
- package/dist/cjs/persistence.js.map +1 -0
- package/dist/cjs/status-reporter.d.ts +42 -0
- package/dist/cjs/status-reporter.d.ts.map +1 -0
- package/dist/cjs/status-reporter.js +153 -0
- package/dist/cjs/status-reporter.js.map +1 -0
- package/dist/cjs/streaming.d.ts +10 -0
- package/dist/cjs/streaming.d.ts.map +1 -1
- package/dist/cjs/streaming.js +9 -1
- package/dist/cjs/streaming.js.map +1 -1
- package/dist/cjs/sync.d.ts +105 -0
- package/dist/cjs/sync.d.ts.map +1 -0
- package/dist/cjs/sync.js +191 -0
- package/dist/cjs/sync.js.map +1 -0
- package/dist/cjs/types.d.ts +78 -1
- package/dist/cjs/types.d.ts.map +1 -1
- package/dist/esm/cache.d.ts +30 -3
- package/dist/esm/cache.d.ts.map +1 -1
- package/dist/esm/cache.js +32 -5
- package/dist/esm/cache.js.map +1 -1
- package/dist/esm/client.d.ts +55 -1
- package/dist/esm/client.d.ts.map +1 -1
- package/dist/esm/client.js +297 -37
- package/dist/esm/client.js.map +1 -1
- package/dist/esm/defaults.d.ts +58 -0
- package/dist/esm/defaults.d.ts.map +1 -0
- package/dist/esm/defaults.js +136 -0
- package/dist/esm/defaults.js.map +1 -0
- package/dist/esm/index.d.ts +2 -1
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +1 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/persistence.d.ts +26 -0
- package/dist/esm/persistence.d.ts.map +1 -0
- package/dist/esm/persistence.js +70 -0
- package/dist/esm/persistence.js.map +1 -0
- package/dist/esm/status-reporter.d.ts +42 -0
- package/dist/esm/status-reporter.d.ts.map +1 -0
- package/dist/esm/status-reporter.js +148 -0
- package/dist/esm/status-reporter.js.map +1 -0
- package/dist/esm/streaming.d.ts +10 -0
- package/dist/esm/streaming.d.ts.map +1 -1
- package/dist/esm/streaming.js +9 -1
- package/dist/esm/streaming.js.map +1 -1
- package/dist/esm/sync.d.ts +105 -0
- package/dist/esm/sync.d.ts.map +1 -0
- package/dist/esm/sync.js +187 -0
- package/dist/esm/sync.js.map +1 -0
- package/dist/esm/types.d.ts +78 -1
- package/dist/esm/types.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import * as fs from 'fs/promises';
|
|
2
|
+
/**
|
|
3
|
+
* Parse a YAMLExport JSON payload into an OfflineFlagDefault map.
|
|
4
|
+
*
|
|
5
|
+
* `environment` is the SDK's configured environment string. It is matched
|
|
6
|
+
* against the export's `environments[]` first by UUID, then by name
|
|
7
|
+
* (case-insensitive). The first match wins.
|
|
8
|
+
*/
|
|
9
|
+
export function parseDefaults(payload, environment) {
|
|
10
|
+
if (!payload || typeof payload !== 'object') {
|
|
11
|
+
throw new Error('deploysentry: defaults payload must be an object');
|
|
12
|
+
}
|
|
13
|
+
const exp = payload;
|
|
14
|
+
if (!Array.isArray(exp.flags)) {
|
|
15
|
+
throw new Error('deploysentry: defaults payload missing flags[] array');
|
|
16
|
+
}
|
|
17
|
+
let envUUID = '';
|
|
18
|
+
if (environment && Array.isArray(exp.environments)) {
|
|
19
|
+
for (const e of exp.environments) {
|
|
20
|
+
if (e.id === environment) {
|
|
21
|
+
envUUID = e.id;
|
|
22
|
+
break;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
if (!envUUID) {
|
|
26
|
+
for (const e of exp.environments) {
|
|
27
|
+
if (e.name && e.name.toLowerCase() === environment.toLowerCase()) {
|
|
28
|
+
envUUID = e.id;
|
|
29
|
+
break;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
const defaults = new Map();
|
|
35
|
+
for (const f of exp.flags) {
|
|
36
|
+
defaults.set(f.key, {
|
|
37
|
+
key: f.key,
|
|
38
|
+
flagType: f.flag_type,
|
|
39
|
+
defaultValue: f.default_value,
|
|
40
|
+
envStates: { ...(f.environments ?? {}) },
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
return { defaults, envUUID };
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Resolve the offline value for a flag key. Returns `undefined` when the
|
|
47
|
+
* flag is not in the loaded defaults. When an env override exists for the
|
|
48
|
+
* resolved env UUID, its `value` is returned; otherwise the flag's global
|
|
49
|
+
* `defaultValue` is returned.
|
|
50
|
+
*/
|
|
51
|
+
export function lookupOfflineDefault(defaults, envUUID, key) {
|
|
52
|
+
const d = defaults.get(key);
|
|
53
|
+
if (!d)
|
|
54
|
+
return undefined;
|
|
55
|
+
if (envUUID) {
|
|
56
|
+
const es = d.envStates[envUUID];
|
|
57
|
+
if (es && es.value !== '') {
|
|
58
|
+
return { value: es.value, enabled: es.enabled, flagType: d.flagType };
|
|
59
|
+
}
|
|
60
|
+
if (es) {
|
|
61
|
+
// Env state exists but value is empty — use flag default with this env's enabled flag.
|
|
62
|
+
return { value: d.defaultValue, enabled: es.enabled, flagType: d.flagType };
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return { value: d.defaultValue, enabled: true, flagType: d.flagType };
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Read a defaults JSON file from disk and return the parsed payload.
|
|
69
|
+
* Accepts either raw JSON or YAML based on the file extension.
|
|
70
|
+
*/
|
|
71
|
+
export async function readDefaultsFile(path) {
|
|
72
|
+
const data = await fs.readFile(path, 'utf-8');
|
|
73
|
+
if (path.endsWith('.yaml') || path.endsWith('.yml')) {
|
|
74
|
+
// Lazy-load js-yaml so SDK consumers who never call this don't pay
|
|
75
|
+
// for the dependency at startup.
|
|
76
|
+
const yaml = await import('js-yaml');
|
|
77
|
+
return yaml.load(data);
|
|
78
|
+
}
|
|
79
|
+
return JSON.parse(data);
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Coerce an offline default raw value into the requested TypeScript type.
|
|
83
|
+
* Mirrors the BoolValue / StringValue / IntValue helpers' coercion rules
|
|
84
|
+
* so offline defaults behave identically to live results.
|
|
85
|
+
*/
|
|
86
|
+
export function coerceOfflineValue(raw, requested) {
|
|
87
|
+
switch (requested) {
|
|
88
|
+
case 'bool': {
|
|
89
|
+
// raw may be a JSON literal ("true", "false") OR a plain string ("true").
|
|
90
|
+
let s = raw;
|
|
91
|
+
if (raw.length >= 2 && raw[0] === '"' && raw[raw.length - 1] === '"') {
|
|
92
|
+
s = raw.slice(1, -1);
|
|
93
|
+
}
|
|
94
|
+
const lower = s.toLowerCase();
|
|
95
|
+
if (lower === 'true')
|
|
96
|
+
return true;
|
|
97
|
+
if (lower === 'false')
|
|
98
|
+
return false;
|
|
99
|
+
return undefined;
|
|
100
|
+
}
|
|
101
|
+
case 'string': {
|
|
102
|
+
try {
|
|
103
|
+
const parsed = JSON.parse(raw);
|
|
104
|
+
if (typeof parsed === 'string')
|
|
105
|
+
return parsed;
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
// not JSON — treat raw as the string itself
|
|
109
|
+
}
|
|
110
|
+
return raw;
|
|
111
|
+
}
|
|
112
|
+
case 'number': {
|
|
113
|
+
const n = Number(raw);
|
|
114
|
+
if (Number.isFinite(n))
|
|
115
|
+
return n;
|
|
116
|
+
try {
|
|
117
|
+
const parsed = JSON.parse(raw);
|
|
118
|
+
if (typeof parsed === 'number' && Number.isFinite(parsed))
|
|
119
|
+
return parsed;
|
|
120
|
+
}
|
|
121
|
+
catch {
|
|
122
|
+
/* ignore */
|
|
123
|
+
}
|
|
124
|
+
return undefined;
|
|
125
|
+
}
|
|
126
|
+
case 'json': {
|
|
127
|
+
try {
|
|
128
|
+
return JSON.parse(raw);
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
return undefined;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
//# sourceMappingURL=defaults.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"defaults.js","sourceRoot":"","sources":["../../src/defaults.ts"],"names":[],"mappings":"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"}
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -25,5 +25,6 @@ export { FlagCache } from './cache.js';
|
|
|
25
25
|
export { FlagStreamClient } from './streaming.js';
|
|
26
26
|
export { loadFlagConfig } from './file-loader.js';
|
|
27
27
|
export { evaluateLocal } from './local-evaluator.js';
|
|
28
|
-
export
|
|
28
|
+
export { StatusReporter, resolveVersion } from './status-reporter.js';
|
|
29
|
+
export type { ClientOptions, EvaluationContext, EvaluationResult, Flag, FlagCategory, FlagInspection, FlagSource, FlagMetadata, FlagConfig, FlagConfigFlag, FlagConfigRule, FlagConfigEnvironment, ApiError, HealthReport, } from './types.js';
|
|
29
30
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/esm/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAEnE,YAAY,EACV,aAAa,EACb,iBAAiB,EACjB,gBAAgB,EAChB,IAAI,EACJ,YAAY,EACZ,cAAc,EACd,UAAU,EACV,YAAY,EACZ,UAAU,EACV,cAAc,EACd,cAAc,EACd,qBAAqB,EACrB,QAAQ,EACR,YAAY,GACb,MAAM,SAAS,CAAC"}
|
package/dist/esm/index.js
CHANGED
|
@@ -25,4 +25,5 @@ export { FlagCache } from './cache.js';
|
|
|
25
25
|
export { FlagStreamClient } from './streaming.js';
|
|
26
26
|
export { loadFlagConfig } from './file-loader.js';
|
|
27
27
|
export { evaluateLocal } from './local-evaluator.js';
|
|
28
|
+
export { StatusReporter, resolveVersion } from './status-reporter.js';
|
|
28
29
|
//# sourceMappingURL=index.js.map
|
package/dist/esm/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Flag } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Persists the last fully-synced flag set to a local JSON file so the SDK can
|
|
4
|
+
* serve a recent local copy on the next boot when the server is unreachable.
|
|
5
|
+
*
|
|
6
|
+
* Opt-in: only constructed when the caller supplies a `persistencePath`.
|
|
7
|
+
* Writes are atomic (temp file + rename) so a crash mid-write never corrupts
|
|
8
|
+
* an existing good snapshot. All failures are swallowed and surfaced via the
|
|
9
|
+
* optional logger — persistence is a best-effort durability aid, never a hard
|
|
10
|
+
* dependency of flag evaluation.
|
|
11
|
+
*/
|
|
12
|
+
export declare class FlagSnapshotStore {
|
|
13
|
+
private readonly path;
|
|
14
|
+
private readonly scope;
|
|
15
|
+
private readonly log;
|
|
16
|
+
constructor(path: string, scope: string, log?: (msg: string) => void);
|
|
17
|
+
/**
|
|
18
|
+
* Load the persisted snapshot. Returns the flags if a valid snapshot exists
|
|
19
|
+
* for the same scope, otherwise `null` (missing file, parse error, version
|
|
20
|
+
* mismatch, or scope mismatch).
|
|
21
|
+
*/
|
|
22
|
+
load(): Flag[] | null;
|
|
23
|
+
/** Atomically write the current flag set to disk. Best-effort. */
|
|
24
|
+
save(flags: Flag[]): void;
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=persistence.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"persistence.d.ts","sourceRoot":"","sources":["../../src/persistence.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAgB/B;;;;;;;;;GASG;AACH,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;IAC9B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAwB;gBAEhC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI;IAMpE;;;;OAIG;IACH,IAAI,IAAI,IAAI,EAAE,GAAG,IAAI;IAoBrB,kEAAkE;IAClE,IAAI,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,IAAI;CAiB1B"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { mkdirSync, readFileSync, renameSync, writeFileSync } from 'fs';
|
|
2
|
+
import { dirname } from 'path';
|
|
3
|
+
const SNAPSHOT_VERSION = 1;
|
|
4
|
+
/**
|
|
5
|
+
* Persists the last fully-synced flag set to a local JSON file so the SDK can
|
|
6
|
+
* serve a recent local copy on the next boot when the server is unreachable.
|
|
7
|
+
*
|
|
8
|
+
* Opt-in: only constructed when the caller supplies a `persistencePath`.
|
|
9
|
+
* Writes are atomic (temp file + rename) so a crash mid-write never corrupts
|
|
10
|
+
* an existing good snapshot. All failures are swallowed and surfaced via the
|
|
11
|
+
* optional logger — persistence is a best-effort durability aid, never a hard
|
|
12
|
+
* dependency of flag evaluation.
|
|
13
|
+
*/
|
|
14
|
+
export class FlagSnapshotStore {
|
|
15
|
+
path;
|
|
16
|
+
scope;
|
|
17
|
+
log;
|
|
18
|
+
constructor(path, scope, log) {
|
|
19
|
+
this.path = path;
|
|
20
|
+
this.scope = scope;
|
|
21
|
+
this.log = log ?? (() => { });
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Load the persisted snapshot. Returns the flags if a valid snapshot exists
|
|
25
|
+
* for the same scope, otherwise `null` (missing file, parse error, version
|
|
26
|
+
* mismatch, or scope mismatch).
|
|
27
|
+
*/
|
|
28
|
+
load() {
|
|
29
|
+
let raw;
|
|
30
|
+
try {
|
|
31
|
+
raw = readFileSync(this.path, 'utf8');
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
return null; // No snapshot yet — expected on first run.
|
|
35
|
+
}
|
|
36
|
+
try {
|
|
37
|
+
const parsed = JSON.parse(raw);
|
|
38
|
+
if (parsed.version !== SNAPSHOT_VERSION)
|
|
39
|
+
return null;
|
|
40
|
+
if (parsed.scope !== this.scope)
|
|
41
|
+
return null;
|
|
42
|
+
if (!Array.isArray(parsed.flags))
|
|
43
|
+
return null;
|
|
44
|
+
return parsed.flags;
|
|
45
|
+
}
|
|
46
|
+
catch (err) {
|
|
47
|
+
this.log(`failed to parse snapshot ${this.path}: ${String(err)}`);
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/** Atomically write the current flag set to disk. Best-effort. */
|
|
52
|
+
save(flags) {
|
|
53
|
+
const payload = {
|
|
54
|
+
version: SNAPSHOT_VERSION,
|
|
55
|
+
savedAt: new Date().toISOString(),
|
|
56
|
+
scope: this.scope,
|
|
57
|
+
flags,
|
|
58
|
+
};
|
|
59
|
+
const tmp = `${this.path}.${process.pid}.tmp`;
|
|
60
|
+
try {
|
|
61
|
+
mkdirSync(dirname(this.path), { recursive: true });
|
|
62
|
+
writeFileSync(tmp, JSON.stringify(payload), 'utf8');
|
|
63
|
+
renameSync(tmp, this.path); // Atomic on POSIX/Windows same-volume.
|
|
64
|
+
}
|
|
65
|
+
catch (err) {
|
|
66
|
+
this.log(`failed to persist snapshot ${this.path}: ${String(err)}`);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=persistence.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"persistence.js","sourceRoot":"","sources":["../../src/persistence.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,IAAI,CAAC;AACxE,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAe/B,MAAM,gBAAgB,GAAG,CAAC,CAAC;AAE3B;;;;;;;;;GASG;AACH,MAAM,OAAO,iBAAiB;IACX,IAAI,CAAS;IACb,KAAK,CAAS;IACd,GAAG,CAAwB;IAE5C,YAAY,IAAY,EAAE,KAAa,EAAE,GAA2B;QAClE,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,GAAG,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IAC/B,CAAC;IAED;;;;OAIG;IACH,IAAI;QACF,IAAI,GAAW,CAAC;QAChB,IAAI,CAAC;YACH,GAAG,GAAG,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QACxC,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC,CAAC,2CAA2C;QAC1D,CAAC;QAED,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAiB,CAAC;YAC/C,IAAI,MAAM,CAAC,OAAO,KAAK,gBAAgB;gBAAE,OAAO,IAAI,CAAC;YACrD,IAAI,MAAM,CAAC,KAAK,KAAK,IAAI,CAAC,KAAK;gBAAE,OAAO,IAAI,CAAC;YAC7C,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC;gBAAE,OAAO,IAAI,CAAC;YAC9C,OAAO,MAAM,CAAC,KAAK,CAAC;QACtB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,GAAG,CAAC,4BAA4B,IAAI,CAAC,IAAI,KAAK,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAClE,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED,kEAAkE;IAClE,IAAI,CAAC,KAAa;QAChB,MAAM,OAAO,GAAiB;YAC5B,OAAO,EAAE,gBAAgB;YACzB,OAAO,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACjC,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,KAAK;SACN,CAAC;QAEF,MAAM,GAAG,GAAG,GAAG,IAAI,CAAC,IAAI,IAAI,OAAO,CAAC,GAAG,MAAM,CAAC;QAC9C,IAAI,CAAC;YACH,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YACnD,aAAa,CAAC,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,CAAC;YACpD,UAAU,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,uCAAuC;QACrE,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,GAAG,CAAC,8BAA8B,IAAI,CAAC,IAAI,KAAK,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACtE,CAAC;IACH,CAAC;CACF"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { HealthReport } from './types.js';
|
|
2
|
+
/** Options passed to StatusReporter. Internal to the SDK. */
|
|
3
|
+
export interface StatusReporterOptions {
|
|
4
|
+
baseURL: string;
|
|
5
|
+
apiKey: string;
|
|
6
|
+
applicationId: string;
|
|
7
|
+
intervalMs?: number;
|
|
8
|
+
version?: string;
|
|
9
|
+
commitSha?: string;
|
|
10
|
+
deploySlot?: string;
|
|
11
|
+
tags?: Record<string, string>;
|
|
12
|
+
healthProvider?: () => HealthReport | Promise<HealthReport>;
|
|
13
|
+
/** Injection seam for tests. Defaults to global fetch. */
|
|
14
|
+
fetchImpl?: typeof fetch;
|
|
15
|
+
/** Injection seam for tests. */
|
|
16
|
+
warn?: (msg: string) => void;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Resolve the version the app should report, in this preference order:
|
|
20
|
+
* explicit config → standard env vars → `npm_package_version` → "unknown".
|
|
21
|
+
*/
|
|
22
|
+
export declare function resolveVersion(explicit?: string): string;
|
|
23
|
+
/**
|
|
24
|
+
* StatusReporter posts periodic `POST /applications/:id/status` updates to
|
|
25
|
+
* DeploySentry on behalf of a DeploySentryClient. Failures are swallowed
|
|
26
|
+
* (logged via `warn`) so flag evaluation is never blocked by reporting.
|
|
27
|
+
*/
|
|
28
|
+
export declare class StatusReporter {
|
|
29
|
+
private readonly opts;
|
|
30
|
+
private timer;
|
|
31
|
+
private stopped;
|
|
32
|
+
private backoff;
|
|
33
|
+
constructor(options: StatusReporterOptions);
|
|
34
|
+
/** Fire one immediate report and (if intervalMs > 0) schedule repeats. */
|
|
35
|
+
start(): void;
|
|
36
|
+
/** Stop scheduling further reports. In-flight reports still resolve. */
|
|
37
|
+
stop(): void;
|
|
38
|
+
/** Send exactly one report. Public for tests and explicit callers. */
|
|
39
|
+
reportOnce(): Promise<void>;
|
|
40
|
+
private tick;
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=status-reporter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status-reporter.d.ts","sourceRoot":"","sources":["../../src/status-reporter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAiB5C,6DAA6D;AAC7D,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,cAAc,CAAC,EAAE,MAAM,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;IAC5D,0DAA0D;IAC1D,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IACzB,gCAAgC;IAChC,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CAC9B;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CASxD;AAED;;;;GAIG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAGyE;IAE9F,OAAO,CAAC,KAAK,CAA8C;IAC3D,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,OAAO,CAAK;gBAER,OAAO,EAAE,qBAAqB;IAiB1C,0EAA0E;IAC1E,KAAK,IAAI,IAAI;IAKb,wEAAwE;IACxE,IAAI,IAAI,IAAI;IAQZ,sEAAsE;IAChE,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;YAuCnB,IAAI;CA+BnB"}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/** Environment variable names probed (in order) for the running version. */
|
|
2
|
+
const VERSION_ENV_CHAIN = [
|
|
3
|
+
'APP_VERSION',
|
|
4
|
+
'GIT_SHA',
|
|
5
|
+
'GIT_COMMIT',
|
|
6
|
+
'SOURCE_COMMIT',
|
|
7
|
+
'RAILWAY_GIT_COMMIT_SHA',
|
|
8
|
+
'RENDER_GIT_COMMIT',
|
|
9
|
+
'VERCEL_GIT_COMMIT_SHA',
|
|
10
|
+
'HEROKU_SLUG_COMMIT',
|
|
11
|
+
];
|
|
12
|
+
const MIN_BACKOFF_MS = 1_000;
|
|
13
|
+
const MAX_BACKOFF_MS = 5 * 60_000;
|
|
14
|
+
/**
|
|
15
|
+
* Resolve the version the app should report, in this preference order:
|
|
16
|
+
* explicit config → standard env vars → `npm_package_version` → "unknown".
|
|
17
|
+
*/
|
|
18
|
+
export function resolveVersion(explicit) {
|
|
19
|
+
if (explicit && explicit.trim())
|
|
20
|
+
return explicit;
|
|
21
|
+
const env = typeof process !== 'undefined' && process.env ? process.env : {};
|
|
22
|
+
for (const name of VERSION_ENV_CHAIN) {
|
|
23
|
+
const v = env[name];
|
|
24
|
+
if (v && v.trim())
|
|
25
|
+
return v;
|
|
26
|
+
}
|
|
27
|
+
if (env.npm_package_version)
|
|
28
|
+
return env.npm_package_version;
|
|
29
|
+
return 'unknown';
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* StatusReporter posts periodic `POST /applications/:id/status` updates to
|
|
33
|
+
* DeploySentry on behalf of a DeploySentryClient. Failures are swallowed
|
|
34
|
+
* (logged via `warn`) so flag evaluation is never blocked by reporting.
|
|
35
|
+
*/
|
|
36
|
+
export class StatusReporter {
|
|
37
|
+
opts;
|
|
38
|
+
timer = null;
|
|
39
|
+
stopped = false;
|
|
40
|
+
backoff = 0;
|
|
41
|
+
constructor(options) {
|
|
42
|
+
if (!options.baseURL)
|
|
43
|
+
throw new Error('baseURL is required');
|
|
44
|
+
if (!options.apiKey)
|
|
45
|
+
throw new Error('apiKey is required');
|
|
46
|
+
if (!options.applicationId)
|
|
47
|
+
throw new Error('applicationId is required');
|
|
48
|
+
const intervalMs = options.intervalMs ?? 30_000;
|
|
49
|
+
if (intervalMs < 0)
|
|
50
|
+
throw new Error('intervalMs must be >= 0');
|
|
51
|
+
this.opts = {
|
|
52
|
+
...options,
|
|
53
|
+
baseURL: options.baseURL.replace(/\/+$/, ''),
|
|
54
|
+
apiKey: options.apiKey,
|
|
55
|
+
applicationId: options.applicationId,
|
|
56
|
+
intervalMs,
|
|
57
|
+
warn: options.warn ?? ((msg) => console.warn('[DeploySentry] ' + msg)),
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
/** Fire one immediate report and (if intervalMs > 0) schedule repeats. */
|
|
61
|
+
start() {
|
|
62
|
+
this.stopped = false;
|
|
63
|
+
void this.tick();
|
|
64
|
+
}
|
|
65
|
+
/** Stop scheduling further reports. In-flight reports still resolve. */
|
|
66
|
+
stop() {
|
|
67
|
+
this.stopped = true;
|
|
68
|
+
if (this.timer) {
|
|
69
|
+
clearTimeout(this.timer);
|
|
70
|
+
this.timer = null;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/** Send exactly one report. Public for tests and explicit callers. */
|
|
74
|
+
async reportOnce() {
|
|
75
|
+
const version = resolveVersion(this.opts.version);
|
|
76
|
+
let health = { state: 'healthy' };
|
|
77
|
+
if (this.opts.healthProvider) {
|
|
78
|
+
try {
|
|
79
|
+
health = await this.opts.healthProvider();
|
|
80
|
+
}
|
|
81
|
+
catch (err) {
|
|
82
|
+
health = { state: 'unknown', reason: String(err?.message ?? err) };
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
const body = {
|
|
86
|
+
version,
|
|
87
|
+
health: health.state,
|
|
88
|
+
};
|
|
89
|
+
if (health.score !== undefined)
|
|
90
|
+
body.health_score = health.score;
|
|
91
|
+
if (health.reason)
|
|
92
|
+
body.health_reason = health.reason;
|
|
93
|
+
if (this.opts.commitSha)
|
|
94
|
+
body.commit_sha = this.opts.commitSha;
|
|
95
|
+
if (this.opts.deploySlot)
|
|
96
|
+
body.deploy_slot = this.opts.deploySlot;
|
|
97
|
+
if (this.opts.tags && Object.keys(this.opts.tags).length)
|
|
98
|
+
body.tags = this.opts.tags;
|
|
99
|
+
const fetchImpl = this.opts.fetchImpl ?? fetch;
|
|
100
|
+
const url = `${this.opts.baseURL}/api/v1/applications/${encodeURIComponent(this.opts.applicationId)}/status`;
|
|
101
|
+
const res = await fetchImpl(url, {
|
|
102
|
+
method: 'POST',
|
|
103
|
+
headers: {
|
|
104
|
+
'Content-Type': 'application/json',
|
|
105
|
+
Authorization: `ApiKey ${this.opts.apiKey}`,
|
|
106
|
+
},
|
|
107
|
+
body: JSON.stringify(body),
|
|
108
|
+
});
|
|
109
|
+
if (!res.ok) {
|
|
110
|
+
throw new Error(`status report failed: ${res.status} ${res.statusText}`);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
async tick() {
|
|
114
|
+
if (this.stopped)
|
|
115
|
+
return;
|
|
116
|
+
try {
|
|
117
|
+
await this.reportOnce();
|
|
118
|
+
this.backoff = 0; // success — clear backoff
|
|
119
|
+
}
|
|
120
|
+
catch (err) {
|
|
121
|
+
this.opts.warn(`status report error: ${err.message}`);
|
|
122
|
+
if (this.backoff >= MAX_BACKOFF_MS) {
|
|
123
|
+
// Already at the ceiling. Reset so the next schedule falls back to
|
|
124
|
+
// intervalMs — otherwise a server that recovers mid-outage takes up
|
|
125
|
+
// to MAX_BACKOFF_MS (5m) to be noticed, regardless of how tight the
|
|
126
|
+
// operator configured intervalMs. On the next failure the 1s ladder
|
|
127
|
+
// restarts, so the short-outage behavior (quickly re-probe while
|
|
128
|
+
// the server is still down) is preserved.
|
|
129
|
+
this.backoff = 0;
|
|
130
|
+
this.opts.warn(`status reporter backoff reset; probing every ${this.opts.intervalMs}ms`);
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
this.backoff = this.backoff === 0 ? MIN_BACKOFF_MS : Math.min(this.backoff * 2, MAX_BACKOFF_MS);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
if (this.stopped)
|
|
137
|
+
return;
|
|
138
|
+
if (this.opts.intervalMs === 0)
|
|
139
|
+
return; // startup-only
|
|
140
|
+
const nextDelay = this.backoff > 0 ? this.backoff : this.opts.intervalMs;
|
|
141
|
+
this.timer = setTimeout(() => void this.tick(), nextDelay);
|
|
142
|
+
// Allow Node to exit even when the timer is pending.
|
|
143
|
+
if (typeof this.timer.unref === 'function') {
|
|
144
|
+
this.timer.unref?.();
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
//# sourceMappingURL=status-reporter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status-reporter.js","sourceRoot":"","sources":["../../src/status-reporter.ts"],"names":[],"mappings":"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"}
|
package/dist/esm/streaming.d.ts
CHANGED
|
@@ -17,6 +17,14 @@ interface StreamOptions {
|
|
|
17
17
|
onChange: FlagChangeHandler;
|
|
18
18
|
/** Called when the stream encounters an error. */
|
|
19
19
|
onError?: StreamErrorHandler;
|
|
20
|
+
/** Called once the SSE connection is established (HTTP 200). */
|
|
21
|
+
onOpen?: () => void;
|
|
22
|
+
/**
|
|
23
|
+
* Called on any inbound stream activity — heartbeat comments (`:ping`) and
|
|
24
|
+
* data events alike. Lets the sync engine treat the stream as alive and gate
|
|
25
|
+
* its resync cadence on stream liveness.
|
|
26
|
+
*/
|
|
27
|
+
onHeartbeat?: () => void;
|
|
20
28
|
}
|
|
21
29
|
/**
|
|
22
30
|
* Lightweight SSE streaming client that keeps the local flag cache
|
|
@@ -34,6 +42,8 @@ export declare class FlagStreamClient {
|
|
|
34
42
|
private readonly headers;
|
|
35
43
|
private readonly onChange;
|
|
36
44
|
private readonly onError;
|
|
45
|
+
private readonly onOpen;
|
|
46
|
+
private readonly onHeartbeat;
|
|
37
47
|
constructor(options: StreamOptions);
|
|
38
48
|
/** Open the SSE connection and start processing events. */
|
|
39
49
|
connect(): Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"streaming.d.ts","sourceRoot":"","sources":["../../src/streaming.ts"],"names":[],"mappings":"AAAA,sDAAsD;AACtD,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,0EAA0E;AAC1E,MAAM,MAAM,iBAAiB,GAAG,CAAC,MAAM,EAAE,eAAe,KAAK,IAAI,CAAC;AAElE,oEAAoE;AACpE,MAAM,MAAM,kBAAkB,GAAG,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;AAOxD,UAAU,aAAa;IACrB,+DAA+D;IAC/D,GAAG,EAAE,MAAM,CAAC;IACZ,6DAA6D;IAC7D,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,8DAA8D;IAC9D,QAAQ,EAAE,iBAAiB,CAAC;IAC5B,kDAAkD;IAClD,OAAO,CAAC,EAAE,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"streaming.d.ts","sourceRoot":"","sources":["../../src/streaming.ts"],"names":[],"mappings":"AAAA,sDAAsD;AACtD,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,0EAA0E;AAC1E,MAAM,MAAM,iBAAiB,GAAG,CAAC,MAAM,EAAE,eAAe,KAAK,IAAI,CAAC;AAElE,oEAAoE;AACpE,MAAM,MAAM,kBAAkB,GAAG,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;AAOxD,UAAU,aAAa;IACrB,+DAA+D;IAC/D,GAAG,EAAE,MAAM,CAAC;IACZ,6DAA6D;IAC7D,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,8DAA8D;IAC9D,QAAQ,EAAE,iBAAiB,CAAC;IAC5B,kDAAkD;IAClD,OAAO,CAAC,EAAE,kBAAkB,CAAC;IAC7B,gEAAgE;IAChE,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;CAC1B;AAED;;;;;;GAMG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,eAAe,CAAgC;IACvD,OAAO,CAAC,cAAc,CAA8C;IACpE,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,OAAO,CAAwB;IAEvC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;IAC7B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAyB;IACjD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAoB;IAC7C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAqB;IAC7C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAa;IACpC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAa;gBAE7B,OAAO,EAAE,aAAa;IASlC,2DAA2D;IACrD,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAwC9B,2DAA2D;IAC3D,KAAK,IAAI,IAAI;YAkBC,aAAa;IA8B3B,OAAO,CAAC,YAAY;IAmCpB,OAAO,CAAC,iBAAiB;CAgB1B"}
|
package/dist/esm/streaming.js
CHANGED
|
@@ -18,11 +18,15 @@ export class FlagStreamClient {
|
|
|
18
18
|
headers;
|
|
19
19
|
onChange;
|
|
20
20
|
onError;
|
|
21
|
+
onOpen;
|
|
22
|
+
onHeartbeat;
|
|
21
23
|
constructor(options) {
|
|
22
24
|
this.url = options.url;
|
|
23
25
|
this.headers = options.headers;
|
|
24
26
|
this.onChange = options.onChange;
|
|
25
27
|
this.onError = options.onError ?? (() => { });
|
|
28
|
+
this.onOpen = options.onOpen ?? (() => { });
|
|
29
|
+
this.onHeartbeat = options.onHeartbeat ?? (() => { });
|
|
26
30
|
}
|
|
27
31
|
/** Open the SSE connection and start processing events. */
|
|
28
32
|
async connect() {
|
|
@@ -46,6 +50,7 @@ export class FlagStreamClient {
|
|
|
46
50
|
throw new Error('SSE response has no body');
|
|
47
51
|
}
|
|
48
52
|
this.retryMs = SSE_INITIAL_RETRY_MS;
|
|
53
|
+
this.onOpen();
|
|
49
54
|
await this.consumeStream(response.body);
|
|
50
55
|
}
|
|
51
56
|
catch (err) {
|
|
@@ -100,6 +105,9 @@ export class FlagStreamClient {
|
|
|
100
105
|
}
|
|
101
106
|
}
|
|
102
107
|
processEvent(raw) {
|
|
108
|
+
// Any inbound frame — including a heartbeat comment — means the stream is
|
|
109
|
+
// alive. Surface that before interpreting the payload.
|
|
110
|
+
this.onHeartbeat();
|
|
103
111
|
let eventType = 'message';
|
|
104
112
|
let data = '';
|
|
105
113
|
for (const line of raw.split('\n')) {
|
|
@@ -110,7 +118,7 @@ export class FlagStreamClient {
|
|
|
110
118
|
data += line.slice(5).trim();
|
|
111
119
|
}
|
|
112
120
|
else if (line.startsWith(':')) {
|
|
113
|
-
// SSE comment (heartbeat) —
|
|
121
|
+
// SSE comment (heartbeat) — liveness already recorded above; no payload.
|
|
114
122
|
return;
|
|
115
123
|
}
|
|
116
124
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"streaming.js","sourceRoot":"","sources":["../../src/streaming.ts"],"names":[],"mappings":"AAaA,MAAM,oBAAoB,GAAG,KAAK,CAAC;AACnC,MAAM,gBAAgB,GAAG,MAAM,CAAC;AAChC,MAAM,sBAAsB,GAAG,CAAC,CAAC;AACjC,MAAM,mBAAmB,GAAG,GAAG,CAAC;
|
|
1
|
+
{"version":3,"file":"streaming.js","sourceRoot":"","sources":["../../src/streaming.ts"],"names":[],"mappings":"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"}
|