@shipeasy/sdk 6.2.0 → 6.3.1
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/dist/client/index.d.mts +20 -1
- package/dist/client/index.d.ts +20 -1
- package/dist/client/index.js +126 -52
- package/dist/client/index.mjs +125 -52
- package/dist/openfeature-server/index.d.mts +12 -0
- package/dist/openfeature-server/index.d.ts +12 -0
- package/dist/openfeature-server/index.js +34 -1
- package/dist/openfeature-server/index.mjs +34 -1
- package/dist/openfeature-web/index.d.mts +10 -0
- package/dist/openfeature-web/index.d.ts +10 -0
- package/dist/server/index.d.mts +22 -1
- package/dist/server/index.d.ts +22 -1
- package/dist/server/index.js +117 -37
- package/dist/server/index.mjs +116 -37
- package/docs/skill/SKILL.md +16 -16
- package/package.json +7 -6
package/dist/client/index.mjs
CHANGED
|
@@ -57,6 +57,53 @@ function send(url) {
|
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
+
// src/logger.ts
|
|
61
|
+
var LOG_LEVELS = ["silent", "error", "warn", "info", "debug"];
|
|
62
|
+
var RANK = {
|
|
63
|
+
silent: 0,
|
|
64
|
+
error: 1,
|
|
65
|
+
warn: 2,
|
|
66
|
+
info: 3,
|
|
67
|
+
debug: 4
|
|
68
|
+
};
|
|
69
|
+
var currentLevel = "warn";
|
|
70
|
+
function setLogLevel(level) {
|
|
71
|
+
if (typeof level === "string" && Object.prototype.hasOwnProperty.call(RANK, level)) {
|
|
72
|
+
currentLevel = level;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
function write(method, args) {
|
|
76
|
+
try {
|
|
77
|
+
const c = globalThis.console;
|
|
78
|
+
if (!c) return;
|
|
79
|
+
const fn = c[method] ?? c.log;
|
|
80
|
+
if (typeof fn === "function") fn.call(c, ...args);
|
|
81
|
+
} catch {
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
var logger = {
|
|
85
|
+
error(...args) {
|
|
86
|
+
if (RANK[currentLevel] >= RANK.error) write("error", args);
|
|
87
|
+
},
|
|
88
|
+
warn(...args) {
|
|
89
|
+
if (RANK[currentLevel] >= RANK.warn) write("warn", args);
|
|
90
|
+
},
|
|
91
|
+
info(...args) {
|
|
92
|
+
if (RANK[currentLevel] >= RANK.info) write("info", args);
|
|
93
|
+
},
|
|
94
|
+
debug(...args) {
|
|
95
|
+
if (RANK[currentLevel] >= RANK.debug) write("debug", args);
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
function safeRun(label, fallback, fn) {
|
|
99
|
+
try {
|
|
100
|
+
return fn();
|
|
101
|
+
} catch (err) {
|
|
102
|
+
logger.error(`[shipeasy] ${label} failed \u2014 returning safe default:`, String(err));
|
|
103
|
+
return fallback;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
60
107
|
// src/see/core.ts
|
|
61
108
|
var SEE_MAX_MESSAGE = 500;
|
|
62
109
|
var SEE_MAX_STACK = 8e3;
|
|
@@ -900,6 +947,7 @@ var Engine = class _Engine {
|
|
|
900
947
|
this.notify();
|
|
901
948
|
};
|
|
902
949
|
constructor(opts) {
|
|
950
|
+
setLogLevel(opts.logLevel);
|
|
903
951
|
this.sdkKey = opts.sdkKey;
|
|
904
952
|
this.baseUrl = (opts.baseUrl ?? "https://edge.shipeasy.dev").replace(/\/$/, "");
|
|
905
953
|
this.env = opts.env ?? "prod";
|
|
@@ -1034,7 +1082,7 @@ var Engine = class _Engine {
|
|
|
1034
1082
|
try {
|
|
1035
1083
|
l();
|
|
1036
1084
|
} catch (err) {
|
|
1037
|
-
|
|
1085
|
+
logger.warn("[shipeasy] subscriber threw:", String(err));
|
|
1038
1086
|
}
|
|
1039
1087
|
}
|
|
1040
1088
|
}
|
|
@@ -1111,7 +1159,7 @@ var Engine = class _Engine {
|
|
|
1111
1159
|
try {
|
|
1112
1160
|
return opts.decode(raw);
|
|
1113
1161
|
} catch (err) {
|
|
1114
|
-
|
|
1162
|
+
logger.warn(`[shipeasy] getConfig('${name}') decode failed:`, String(err));
|
|
1115
1163
|
return void 0;
|
|
1116
1164
|
}
|
|
1117
1165
|
}
|
|
@@ -1144,7 +1192,7 @@ var Engine = class _Engine {
|
|
|
1144
1192
|
try {
|
|
1145
1193
|
return { inExperiment: true, group: entry.group, params: decode(entry.params) };
|
|
1146
1194
|
} catch (err) {
|
|
1147
|
-
|
|
1195
|
+
logger.warn(`[shipeasy] getExperiment('${name}') decode failed:`, String(err));
|
|
1148
1196
|
return notIn;
|
|
1149
1197
|
}
|
|
1150
1198
|
}
|
|
@@ -1347,6 +1395,7 @@ function shipeasy(opts) {
|
|
|
1347
1395
|
const client = configureShipeasy({
|
|
1348
1396
|
sdkKey: opts.clientKey,
|
|
1349
1397
|
baseUrl,
|
|
1398
|
+
logLevel: opts.logLevel,
|
|
1350
1399
|
autoGuardrails: blanket,
|
|
1351
1400
|
autoGuardrailGroups: groups,
|
|
1352
1401
|
autoCollectAlways: acObj?.always === true,
|
|
@@ -1359,7 +1408,7 @@ function shipeasy(opts) {
|
|
|
1359
1408
|
flags.notifyMounted();
|
|
1360
1409
|
if (opts.autoIdentify !== false) {
|
|
1361
1410
|
void client.identify({}).catch((err) => {
|
|
1362
|
-
|
|
1411
|
+
logger.warn("[shipeasy] auto-identify failed:", String(err));
|
|
1363
1412
|
});
|
|
1364
1413
|
}
|
|
1365
1414
|
return attachDevtools(client, { adminUrl: opts.adminUrl });
|
|
@@ -1447,7 +1496,7 @@ var flags = {
|
|
|
1447
1496
|
},
|
|
1448
1497
|
identify(user) {
|
|
1449
1498
|
if (!_client) {
|
|
1450
|
-
|
|
1499
|
+
logger.warn("[shipeasy] flags.identify called before configureShipeasy()");
|
|
1451
1500
|
return Promise.resolve();
|
|
1452
1501
|
}
|
|
1453
1502
|
return _client.identify(user);
|
|
@@ -1460,40 +1509,46 @@ var flags = {
|
|
|
1460
1509
|
* force-static pages where SSR has no flag data.
|
|
1461
1510
|
*/
|
|
1462
1511
|
get(name, defaultValue = false) {
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1512
|
+
return safeRun("flags.get", defaultValue, () => {
|
|
1513
|
+
const bs = getBootstrap();
|
|
1514
|
+
if (bs !== null && name in bs.flags) return bs.flags[name];
|
|
1515
|
+
if (!_mountedAndReady) return defaultValue;
|
|
1516
|
+
if (_client) return _client.getFlag(name, defaultValue);
|
|
1517
|
+
return readGateOverride(name) ?? defaultValue;
|
|
1518
|
+
});
|
|
1468
1519
|
},
|
|
1469
1520
|
/** Evaluate a gate and report why (value + reason). See {@link FlagDetail}. */
|
|
1470
1521
|
getDetail(name) {
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1522
|
+
return safeRun("flags.getDetail", { value: false, reason: "CLIENT_NOT_READY" }, () => {
|
|
1523
|
+
if (_client) return _client.getFlagDetail(name);
|
|
1524
|
+
const ov = readGateOverride(name);
|
|
1525
|
+
if (ov !== null) return { value: ov, reason: "OVERRIDE" };
|
|
1526
|
+
return { value: false, reason: "CLIENT_NOT_READY" };
|
|
1527
|
+
});
|
|
1475
1528
|
},
|
|
1476
1529
|
getConfig(name, decode) {
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1530
|
+
return safeRun("flags.getConfig", void 0, () => {
|
|
1531
|
+
const bs = getBootstrap();
|
|
1532
|
+
if (bs !== null && name in bs.configs) {
|
|
1533
|
+
const raw = bs.configs[name];
|
|
1534
|
+
if (!decode) return raw;
|
|
1535
|
+
try {
|
|
1536
|
+
return decode(raw);
|
|
1537
|
+
} catch {
|
|
1538
|
+
return void 0;
|
|
1539
|
+
}
|
|
1540
|
+
}
|
|
1541
|
+
if (!_mountedAndReady) return void 0;
|
|
1542
|
+
if (_client) return _client.getConfig(name, decode);
|
|
1543
|
+
const ov = readConfigOverride(name);
|
|
1544
|
+
if (ov === void 0) return void 0;
|
|
1545
|
+
if (!decode) return ov;
|
|
1481
1546
|
try {
|
|
1482
|
-
return decode(
|
|
1547
|
+
return decode(ov);
|
|
1483
1548
|
} catch {
|
|
1484
1549
|
return void 0;
|
|
1485
1550
|
}
|
|
1486
|
-
}
|
|
1487
|
-
if (!_mountedAndReady) return void 0;
|
|
1488
|
-
if (_client) return _client.getConfig(name, decode);
|
|
1489
|
-
const ov = readConfigOverride(name);
|
|
1490
|
-
if (ov === void 0) return void 0;
|
|
1491
|
-
if (!decode) return ov;
|
|
1492
|
-
try {
|
|
1493
|
-
return decode(ov);
|
|
1494
|
-
} catch {
|
|
1495
|
-
return void 0;
|
|
1496
|
-
}
|
|
1551
|
+
});
|
|
1497
1552
|
},
|
|
1498
1553
|
getExperiment(name, defaultParams, decodeOrOpts, variants) {
|
|
1499
1554
|
const fallback = {
|
|
@@ -1501,16 +1556,18 @@ var flags = {
|
|
|
1501
1556
|
group: "control",
|
|
1502
1557
|
params: defaultParams
|
|
1503
1558
|
};
|
|
1504
|
-
|
|
1505
|
-
|
|
1559
|
+
return safeRun("flags.getExperiment", fallback, () => {
|
|
1560
|
+
if (!_client) return fallback;
|
|
1561
|
+
return typeof decodeOrOpts === "function" ? _client.getExperiment(name, defaultParams, decodeOrOpts, variants) : _client.getExperiment(name, defaultParams, decodeOrOpts ?? {});
|
|
1562
|
+
});
|
|
1506
1563
|
},
|
|
1507
1564
|
/** Manually log an exposure for an enrolled experiment. See
|
|
1508
1565
|
* {@link Engine.logExposure}. No-op before configure(). */
|
|
1509
1566
|
logExposure(name) {
|
|
1510
|
-
_client?.logExposure(name);
|
|
1567
|
+
safeRun("flags.logExposure", void 0, () => _client?.logExposure(name));
|
|
1511
1568
|
},
|
|
1512
1569
|
track(eventName, props) {
|
|
1513
|
-
_client?.track(eventName, props);
|
|
1570
|
+
safeRun("flags.track", void 0, () => _client?.track(eventName, props));
|
|
1514
1571
|
},
|
|
1515
1572
|
/**
|
|
1516
1573
|
* Read a killswitch. Without `switchKey`, returns true when the killswitch is
|
|
@@ -1522,15 +1579,17 @@ var flags = {
|
|
|
1522
1579
|
* available synchronously on first render.
|
|
1523
1580
|
*/
|
|
1524
1581
|
ks(name, switchKey) {
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1582
|
+
return safeRun("flags.ks", false, () => {
|
|
1583
|
+
const bs = getBootstrap();
|
|
1584
|
+
if (bs !== null && bs.killswitches && name in bs.killswitches) {
|
|
1585
|
+
const ks = bs.killswitches[name];
|
|
1586
|
+
if (typeof ks === "boolean") return switchKey === void 0 ? ks : false;
|
|
1587
|
+
if (switchKey === void 0) return false;
|
|
1588
|
+
return ks[switchKey] === true;
|
|
1589
|
+
}
|
|
1590
|
+
if (!_mountedAndReady) return false;
|
|
1591
|
+
return _client?.getKillswitch(name, switchKey) ?? false;
|
|
1592
|
+
});
|
|
1534
1593
|
},
|
|
1535
1594
|
flush() {
|
|
1536
1595
|
return _client?.flush() ?? Promise.resolve();
|
|
@@ -1587,7 +1646,7 @@ var Client = class {
|
|
|
1587
1646
|
this.engine = engine;
|
|
1588
1647
|
this.attributes = _attributes(user);
|
|
1589
1648
|
this._identify = this.engine.identify(this.attributes).catch((err) => {
|
|
1590
|
-
|
|
1649
|
+
logger.warn("[shipeasy] Client identify failed:", String(err));
|
|
1591
1650
|
});
|
|
1592
1651
|
}
|
|
1593
1652
|
/** Resolves once the engine's identify() for this user has completed. */
|
|
@@ -1595,20 +1654,33 @@ var Client = class {
|
|
|
1595
1654
|
return this._identify;
|
|
1596
1655
|
}
|
|
1597
1656
|
getFlag(name, defaultValue = false) {
|
|
1598
|
-
return this.engine.getFlag(name, defaultValue);
|
|
1657
|
+
return safeRun("Client.getFlag", defaultValue, () => this.engine.getFlag(name, defaultValue));
|
|
1599
1658
|
}
|
|
1600
1659
|
getFlagDetail(name) {
|
|
1601
|
-
return
|
|
1660
|
+
return safeRun(
|
|
1661
|
+
"Client.getFlagDetail",
|
|
1662
|
+
{ value: false, reason: "CLIENT_NOT_READY" },
|
|
1663
|
+
() => this.engine.getFlagDetail(name)
|
|
1664
|
+
);
|
|
1602
1665
|
}
|
|
1603
1666
|
getConfig(name, decodeOrOpts) {
|
|
1604
|
-
return
|
|
1667
|
+
return safeRun(
|
|
1668
|
+
"Client.getConfig",
|
|
1669
|
+
void 0,
|
|
1670
|
+
() => this.engine.getConfig(name, decodeOrOpts)
|
|
1671
|
+
);
|
|
1605
1672
|
}
|
|
1606
1673
|
getExperiment(name, defaultParams, decode) {
|
|
1607
|
-
|
|
1674
|
+
const notIn = { inExperiment: false, group: "control", params: defaultParams };
|
|
1675
|
+
return safeRun(
|
|
1676
|
+
"Client.getExperiment",
|
|
1677
|
+
notIn,
|
|
1678
|
+
() => this.engine.getExperiment(name, defaultParams, decode)
|
|
1679
|
+
);
|
|
1608
1680
|
}
|
|
1609
1681
|
/** Read a killswitch (not user-bound; mirrors {@link Engine.getKillswitch}). */
|
|
1610
1682
|
getKillswitch(name, switchKey) {
|
|
1611
|
-
return this.engine.getKillswitch(name, switchKey);
|
|
1683
|
+
return safeRun("Client.getKillswitch", false, () => this.engine.getKillswitch(name, switchKey));
|
|
1612
1684
|
}
|
|
1613
1685
|
/**
|
|
1614
1686
|
* Record a conversion/metric event for the bound (identified) user. Delegates
|
|
@@ -1617,7 +1689,7 @@ var Client = class {
|
|
|
1617
1689
|
* test mode.
|
|
1618
1690
|
*/
|
|
1619
1691
|
track(eventName, props) {
|
|
1620
|
-
this.engine.track(eventName, props);
|
|
1692
|
+
safeRun("Client.track", void 0, () => this.engine.track(eventName, props));
|
|
1621
1693
|
}
|
|
1622
1694
|
/**
|
|
1623
1695
|
* Log an exposure for `name` at the treatment's render for the bound user.
|
|
@@ -1626,12 +1698,12 @@ var Client = class {
|
|
|
1626
1698
|
* `disableAutoExposure` to log exposure exactly when you render.
|
|
1627
1699
|
*/
|
|
1628
1700
|
logExposure(name) {
|
|
1629
|
-
this.engine.logExposure(name);
|
|
1701
|
+
safeRun("Client.logExposure", void 0, () => this.engine.logExposure(name));
|
|
1630
1702
|
}
|
|
1631
1703
|
};
|
|
1632
1704
|
function dispatchSee(problem, consequence, extras, kind) {
|
|
1633
1705
|
if (!_client) {
|
|
1634
|
-
|
|
1706
|
+
logger.warn("[shipeasy] see() called before shipeasy({ clientKey }) \u2014 error dropped");
|
|
1635
1707
|
return;
|
|
1636
1708
|
}
|
|
1637
1709
|
_client.reportError(problem, consequence, extras, kind);
|
|
@@ -1883,6 +1955,7 @@ export {
|
|
|
1883
1955
|
LABEL_MARKER_RE,
|
|
1884
1956
|
LABEL_MARKER_SEP,
|
|
1885
1957
|
LABEL_MARKER_START,
|
|
1958
|
+
LOG_LEVELS,
|
|
1886
1959
|
_resetConfigureForTests,
|
|
1887
1960
|
_resetShipeasyForTests,
|
|
1888
1961
|
attachDevtools,
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { Provider, EvaluationContext, Logger, ResolutionDetails, JsonValue } from '@openfeature/server-sdk';
|
|
2
2
|
|
|
3
|
+
type LogLevel = "silent" | "error" | "warn" | "info" | "debug";
|
|
4
|
+
|
|
3
5
|
type SeeExtras = Record<string, string | number | boolean | null | undefined>;
|
|
4
6
|
type SeeKind = "caught" | "uncaught" | "unhandled_rejection" | "network" | "violation";
|
|
5
7
|
/** Built by `causesThe(subject).to(outcome)` — never constructed by hand. */
|
|
@@ -137,6 +139,16 @@ interface EngineOptions {
|
|
|
137
139
|
disableTelemetry?: boolean;
|
|
138
140
|
/** Override the telemetry beacon host. Defaults to {@link DEFAULT_TELEMETRY_URL}. */
|
|
139
141
|
telemetryUrl?: string;
|
|
142
|
+
/**
|
|
143
|
+
* How chatty the SDK is on `console` when it catches an error internally.
|
|
144
|
+
* Every public runtime method (getFlag/getConfig/getExperiment/getKillswitch/
|
|
145
|
+
* track/logExposure/see) fails silently — it returns a safe default rather
|
|
146
|
+
* than throwing — and surfaces the swallowed error through this level so you
|
|
147
|
+
* still find out. Ordering: `silent` < `error` < `warn` < `info` < `debug`.
|
|
148
|
+
* Defaults to `"warn"` (prints `error` + `warn`). Pass `"silent"` to mute the
|
|
149
|
+
* SDK entirely. See {@link LogLevel}.
|
|
150
|
+
*/
|
|
151
|
+
logLevel?: LogLevel;
|
|
140
152
|
/**
|
|
141
153
|
* Attribute names usable for targeting but never persisted in analytics
|
|
142
154
|
* (LD/Statsig `privateAttributes`). The server evaluates locally so private
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { Provider, EvaluationContext, Logger, ResolutionDetails, JsonValue } from '@openfeature/server-sdk';
|
|
2
2
|
|
|
3
|
+
type LogLevel = "silent" | "error" | "warn" | "info" | "debug";
|
|
4
|
+
|
|
3
5
|
type SeeExtras = Record<string, string | number | boolean | null | undefined>;
|
|
4
6
|
type SeeKind = "caught" | "uncaught" | "unhandled_rejection" | "network" | "violation";
|
|
5
7
|
/** Built by `causesThe(subject).to(outcome)` — never constructed by hand. */
|
|
@@ -137,6 +139,16 @@ interface EngineOptions {
|
|
|
137
139
|
disableTelemetry?: boolean;
|
|
138
140
|
/** Override the telemetry beacon host. Defaults to {@link DEFAULT_TELEMETRY_URL}. */
|
|
139
141
|
telemetryUrl?: string;
|
|
142
|
+
/**
|
|
143
|
+
* How chatty the SDK is on `console` when it catches an error internally.
|
|
144
|
+
* Every public runtime method (getFlag/getConfig/getExperiment/getKillswitch/
|
|
145
|
+
* track/logExposure/see) fails silently — it returns a safe default rather
|
|
146
|
+
* than throwing — and surfaces the swallowed error through this level so you
|
|
147
|
+
* still find out. Ordering: `silent` < `error` < `warn` < `info` < `debug`.
|
|
148
|
+
* Defaults to `"warn"` (prints `error` + `warn`). Pass `"silent"` to mute the
|
|
149
|
+
* SDK entirely. See {@link LogLevel}.
|
|
150
|
+
*/
|
|
151
|
+
logLevel?: LogLevel;
|
|
140
152
|
/**
|
|
141
153
|
* Attribute names usable for targeting but never persisted in analytics
|
|
142
154
|
* (LD/Statsig `privateAttributes`). The server evaluates locally so private
|
|
@@ -28,6 +28,39 @@ var import_server_sdk = require("@openfeature/server-sdk");
|
|
|
28
28
|
// src/server/index.ts
|
|
29
29
|
var import_node_async_hooks = require("async_hooks");
|
|
30
30
|
|
|
31
|
+
// src/logger.ts
|
|
32
|
+
var RANK = {
|
|
33
|
+
silent: 0,
|
|
34
|
+
error: 1,
|
|
35
|
+
warn: 2,
|
|
36
|
+
info: 3,
|
|
37
|
+
debug: 4
|
|
38
|
+
};
|
|
39
|
+
var currentLevel = "warn";
|
|
40
|
+
function write(method, args) {
|
|
41
|
+
try {
|
|
42
|
+
const c = globalThis.console;
|
|
43
|
+
if (!c) return;
|
|
44
|
+
const fn = c[method] ?? c.log;
|
|
45
|
+
if (typeof fn === "function") fn.call(c, ...args);
|
|
46
|
+
} catch {
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
var logger = {
|
|
50
|
+
error(...args) {
|
|
51
|
+
if (RANK[currentLevel] >= RANK.error) write("error", args);
|
|
52
|
+
},
|
|
53
|
+
warn(...args) {
|
|
54
|
+
if (RANK[currentLevel] >= RANK.warn) write("warn", args);
|
|
55
|
+
},
|
|
56
|
+
info(...args) {
|
|
57
|
+
if (RANK[currentLevel] >= RANK.info) write("info", args);
|
|
58
|
+
},
|
|
59
|
+
debug(...args) {
|
|
60
|
+
if (RANK[currentLevel] >= RANK.debug) write("debug", args);
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
|
|
31
64
|
// src/see/core.ts
|
|
32
65
|
var SEE_MAX_SUBJECT = 200;
|
|
33
66
|
var SEE_MAX_EXTRA_VALUE = 200;
|
|
@@ -183,7 +216,7 @@ function getShipeasyServerClient() {
|
|
|
183
216
|
}
|
|
184
217
|
function dispatchSee(problem, consequence, extras, kind) {
|
|
185
218
|
if (!_server) {
|
|
186
|
-
|
|
219
|
+
logger.warn("[shipeasy] see() called before shipeasy({ serverKey }) \u2014 error dropped");
|
|
187
220
|
return;
|
|
188
221
|
}
|
|
189
222
|
_server.reportError(problem, consequence, extras, kind);
|
|
@@ -4,6 +4,39 @@ import { ErrorCode } from "@openfeature/server-sdk";
|
|
|
4
4
|
// src/server/index.ts
|
|
5
5
|
import { AsyncLocalStorage } from "async_hooks";
|
|
6
6
|
|
|
7
|
+
// src/logger.ts
|
|
8
|
+
var RANK = {
|
|
9
|
+
silent: 0,
|
|
10
|
+
error: 1,
|
|
11
|
+
warn: 2,
|
|
12
|
+
info: 3,
|
|
13
|
+
debug: 4
|
|
14
|
+
};
|
|
15
|
+
var currentLevel = "warn";
|
|
16
|
+
function write(method, args) {
|
|
17
|
+
try {
|
|
18
|
+
const c = globalThis.console;
|
|
19
|
+
if (!c) return;
|
|
20
|
+
const fn = c[method] ?? c.log;
|
|
21
|
+
if (typeof fn === "function") fn.call(c, ...args);
|
|
22
|
+
} catch {
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
var logger = {
|
|
26
|
+
error(...args) {
|
|
27
|
+
if (RANK[currentLevel] >= RANK.error) write("error", args);
|
|
28
|
+
},
|
|
29
|
+
warn(...args) {
|
|
30
|
+
if (RANK[currentLevel] >= RANK.warn) write("warn", args);
|
|
31
|
+
},
|
|
32
|
+
info(...args) {
|
|
33
|
+
if (RANK[currentLevel] >= RANK.info) write("info", args);
|
|
34
|
+
},
|
|
35
|
+
debug(...args) {
|
|
36
|
+
if (RANK[currentLevel] >= RANK.debug) write("debug", args);
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
|
|
7
40
|
// src/see/core.ts
|
|
8
41
|
var SEE_MAX_SUBJECT = 200;
|
|
9
42
|
var SEE_MAX_EXTRA_VALUE = 200;
|
|
@@ -159,7 +192,7 @@ function getShipeasyServerClient() {
|
|
|
159
192
|
}
|
|
160
193
|
function dispatchSee(problem, consequence, extras, kind) {
|
|
161
194
|
if (!_server) {
|
|
162
|
-
|
|
195
|
+
logger.warn("[shipeasy] see() called before shipeasy({ serverKey }) \u2014 error dropped");
|
|
163
196
|
return;
|
|
164
197
|
}
|
|
165
198
|
_server.reportError(problem, consequence, extras, kind);
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { Provider, EvaluationContext, Logger, ResolutionDetails, JsonValue } from '@openfeature/web-sdk';
|
|
2
2
|
|
|
3
|
+
type LogLevel = "silent" | "error" | "warn" | "info" | "debug";
|
|
4
|
+
|
|
3
5
|
type SeeExtras = Record<string, string | number | boolean | null | undefined>;
|
|
4
6
|
type SeeKind = "caught" | "uncaught" | "unhandled_rejection" | "network" | "violation";
|
|
5
7
|
/** Built by `causesThe(subject).to(outcome)` — never constructed by hand. */
|
|
@@ -131,6 +133,14 @@ interface EngineOptions {
|
|
|
131
133
|
disableTelemetry?: boolean;
|
|
132
134
|
/** Override the telemetry beacon host. Defaults to {@link DEFAULT_TELEMETRY_URL}. */
|
|
133
135
|
telemetryUrl?: string;
|
|
136
|
+
/**
|
|
137
|
+
* How chatty the SDK is on `console` when it catches an error internally.
|
|
138
|
+
* Every public runtime method (getFlag/getConfig/getExperiment/getKillswitch/
|
|
139
|
+
* track/logExposure/see) fails silently — returning a safe default instead of
|
|
140
|
+
* throwing — and surfaces the swallowed error through this level. Ordering:
|
|
141
|
+
* `silent` < `error` < `warn` < `info` < `debug`. Defaults to `"warn"`.
|
|
142
|
+
*/
|
|
143
|
+
logLevel?: LogLevel;
|
|
134
144
|
/**
|
|
135
145
|
* Suppress automatic exposure logging in `getExperiment` (Statsig's
|
|
136
146
|
* `disableExposureLogging`). Default false — reading an enrolled variant
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { Provider, EvaluationContext, Logger, ResolutionDetails, JsonValue } from '@openfeature/web-sdk';
|
|
2
2
|
|
|
3
|
+
type LogLevel = "silent" | "error" | "warn" | "info" | "debug";
|
|
4
|
+
|
|
3
5
|
type SeeExtras = Record<string, string | number | boolean | null | undefined>;
|
|
4
6
|
type SeeKind = "caught" | "uncaught" | "unhandled_rejection" | "network" | "violation";
|
|
5
7
|
/** Built by `causesThe(subject).to(outcome)` — never constructed by hand. */
|
|
@@ -131,6 +133,14 @@ interface EngineOptions {
|
|
|
131
133
|
disableTelemetry?: boolean;
|
|
132
134
|
/** Override the telemetry beacon host. Defaults to {@link DEFAULT_TELEMETRY_URL}. */
|
|
133
135
|
telemetryUrl?: string;
|
|
136
|
+
/**
|
|
137
|
+
* How chatty the SDK is on `console` when it catches an error internally.
|
|
138
|
+
* Every public runtime method (getFlag/getConfig/getExperiment/getKillswitch/
|
|
139
|
+
* track/logExposure/see) fails silently — returning a safe default instead of
|
|
140
|
+
* throwing — and surfaces the swallowed error through this level. Ordering:
|
|
141
|
+
* `silent` < `error` < `warn` < `info` < `debug`. Defaults to `"warn"`.
|
|
142
|
+
*/
|
|
143
|
+
logLevel?: LogLevel;
|
|
134
144
|
/**
|
|
135
145
|
* Suppress automatic exposure logging in `getExperiment` (Statsig's
|
|
136
146
|
* `disableExposureLogging`). Default false — reading an enrolled variant
|
package/dist/server/index.d.mts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
2
2
|
|
|
3
|
+
type LogLevel = "silent" | "error" | "warn" | "info" | "debug";
|
|
4
|
+
/** All accepted {@link LogLevel} values, in increasing verbosity. */
|
|
5
|
+
declare const LOG_LEVELS: readonly LogLevel[];
|
|
6
|
+
|
|
3
7
|
type SeeExtras = Record<string, string | number | boolean | null | undefined>;
|
|
4
8
|
type SeeKind = "caught" | "uncaught" | "unhandled_rejection" | "network" | "violation";
|
|
5
9
|
/** Built by `causesThe(subject).to(outcome)` — never constructed by hand. */
|
|
@@ -243,6 +247,16 @@ interface EngineOptions {
|
|
|
243
247
|
disableTelemetry?: boolean;
|
|
244
248
|
/** Override the telemetry beacon host. Defaults to {@link DEFAULT_TELEMETRY_URL}. */
|
|
245
249
|
telemetryUrl?: string;
|
|
250
|
+
/**
|
|
251
|
+
* How chatty the SDK is on `console` when it catches an error internally.
|
|
252
|
+
* Every public runtime method (getFlag/getConfig/getExperiment/getKillswitch/
|
|
253
|
+
* track/logExposure/see) fails silently — it returns a safe default rather
|
|
254
|
+
* than throwing — and surfaces the swallowed error through this level so you
|
|
255
|
+
* still find out. Ordering: `silent` < `error` < `warn` < `info` < `debug`.
|
|
256
|
+
* Defaults to `"warn"` (prints `error` + `warn`). Pass `"silent"` to mute the
|
|
257
|
+
* SDK entirely. See {@link LogLevel}.
|
|
258
|
+
*/
|
|
259
|
+
logLevel?: LogLevel;
|
|
246
260
|
/**
|
|
247
261
|
* Attribute names usable for targeting but never persisted in analytics
|
|
248
262
|
* (LD/Statsig `privateAttributes`). The server evaluates locally so private
|
|
@@ -460,6 +474,13 @@ interface ShipeasyServerConfig {
|
|
|
460
474
|
user?: User;
|
|
461
475
|
/** i18n profile to load for SSR translations, e.g. "en:prod". Defaults to "en:prod". */
|
|
462
476
|
i18nDefaultProfile?: string;
|
|
477
|
+
/**
|
|
478
|
+
* How chatty the SDK is on `console` when it swallows an internal error.
|
|
479
|
+
* `silent` < `error` < `warn` < `info` < `debug`; defaults to `"warn"`. Every
|
|
480
|
+
* runtime read/track/see call fails silently to a safe default and reports the
|
|
481
|
+
* cause at this level. See {@link EngineOptions.logLevel}.
|
|
482
|
+
*/
|
|
483
|
+
logLevel?: LogLevel;
|
|
463
484
|
/**
|
|
464
485
|
* Disable per-evaluation usage telemetry. ON by default. On Cloudflare
|
|
465
486
|
* Workers each beacon is an outbound subrequest, so disable on hot SSR paths
|
|
@@ -789,4 +810,4 @@ interface SeeApi {
|
|
|
789
810
|
*/
|
|
790
811
|
declare const see: SeeApi;
|
|
791
812
|
|
|
792
|
-
export { ANON_ID_COOKIE, type AttributesFn, type BootstrapData, type BootstrapEmitOptions, type BootstrapPayload, Client, type ConfigureOfflineOptions, type ConfigureOptions, type ConfigureTestOptions, type Consequence, Engine, type EngineEnv, type EngineOptions, type ExperimentResult, type ExpsBlob, FLAG_REASONS, type FetchLabelsOptions, type FlagDetail, type FlagReason, type FlagsBlob, type GetConfigOptions, type I18nForRequest, type LabelFile, type ScriptTagSpec, type SeeApi, type SeeChain, type SeeControlFlowChain, type SeeErrorEvent, type SeeExtras, type SeeKind, type SeeViolationChain, type ShipeasyServerConfig, type ShipeasyServerHandle, type StickyBucketStore, type StickyEntry, type User, type Violation, _murmur3ForTests, _resetConfigureForTests, _resetShipeasyServerForTests, clearOverrides, configure, configureForOffline, configureForTesting, configureShipeasyServer, createInMemoryStickyStore, fetchLabelsForSSR, flags, getBootstrapData, getBootstrapTags, getShipeasyServerClient, i18n, isExpected, onChange, overrideConfig, overrideExperiment, overrideFlag, see, seeContext, shipeasy, version };
|
|
813
|
+
export { ANON_ID_COOKIE, type AttributesFn, type BootstrapData, type BootstrapEmitOptions, type BootstrapPayload, Client, type ConfigureOfflineOptions, type ConfigureOptions, type ConfigureTestOptions, type Consequence, Engine, type EngineEnv, type EngineOptions, type ExperimentResult, type ExpsBlob, FLAG_REASONS, type FetchLabelsOptions, type FlagDetail, type FlagReason, type FlagsBlob, type GetConfigOptions, type I18nForRequest, LOG_LEVELS, type LabelFile, type LogLevel, type ScriptTagSpec, type SeeApi, type SeeChain, type SeeControlFlowChain, type SeeErrorEvent, type SeeExtras, type SeeKind, type SeeViolationChain, type ShipeasyServerConfig, type ShipeasyServerHandle, type StickyBucketStore, type StickyEntry, type User, type Violation, _murmur3ForTests, _resetConfigureForTests, _resetShipeasyServerForTests, clearOverrides, configure, configureForOffline, configureForTesting, configureShipeasyServer, createInMemoryStickyStore, fetchLabelsForSSR, flags, getBootstrapData, getBootstrapTags, getShipeasyServerClient, i18n, isExpected, onChange, overrideConfig, overrideExperiment, overrideFlag, see, seeContext, shipeasy, version };
|
package/dist/server/index.d.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
2
2
|
|
|
3
|
+
type LogLevel = "silent" | "error" | "warn" | "info" | "debug";
|
|
4
|
+
/** All accepted {@link LogLevel} values, in increasing verbosity. */
|
|
5
|
+
declare const LOG_LEVELS: readonly LogLevel[];
|
|
6
|
+
|
|
3
7
|
type SeeExtras = Record<string, string | number | boolean | null | undefined>;
|
|
4
8
|
type SeeKind = "caught" | "uncaught" | "unhandled_rejection" | "network" | "violation";
|
|
5
9
|
/** Built by `causesThe(subject).to(outcome)` — never constructed by hand. */
|
|
@@ -243,6 +247,16 @@ interface EngineOptions {
|
|
|
243
247
|
disableTelemetry?: boolean;
|
|
244
248
|
/** Override the telemetry beacon host. Defaults to {@link DEFAULT_TELEMETRY_URL}. */
|
|
245
249
|
telemetryUrl?: string;
|
|
250
|
+
/**
|
|
251
|
+
* How chatty the SDK is on `console` when it catches an error internally.
|
|
252
|
+
* Every public runtime method (getFlag/getConfig/getExperiment/getKillswitch/
|
|
253
|
+
* track/logExposure/see) fails silently — it returns a safe default rather
|
|
254
|
+
* than throwing — and surfaces the swallowed error through this level so you
|
|
255
|
+
* still find out. Ordering: `silent` < `error` < `warn` < `info` < `debug`.
|
|
256
|
+
* Defaults to `"warn"` (prints `error` + `warn`). Pass `"silent"` to mute the
|
|
257
|
+
* SDK entirely. See {@link LogLevel}.
|
|
258
|
+
*/
|
|
259
|
+
logLevel?: LogLevel;
|
|
246
260
|
/**
|
|
247
261
|
* Attribute names usable for targeting but never persisted in analytics
|
|
248
262
|
* (LD/Statsig `privateAttributes`). The server evaluates locally so private
|
|
@@ -460,6 +474,13 @@ interface ShipeasyServerConfig {
|
|
|
460
474
|
user?: User;
|
|
461
475
|
/** i18n profile to load for SSR translations, e.g. "en:prod". Defaults to "en:prod". */
|
|
462
476
|
i18nDefaultProfile?: string;
|
|
477
|
+
/**
|
|
478
|
+
* How chatty the SDK is on `console` when it swallows an internal error.
|
|
479
|
+
* `silent` < `error` < `warn` < `info` < `debug`; defaults to `"warn"`. Every
|
|
480
|
+
* runtime read/track/see call fails silently to a safe default and reports the
|
|
481
|
+
* cause at this level. See {@link EngineOptions.logLevel}.
|
|
482
|
+
*/
|
|
483
|
+
logLevel?: LogLevel;
|
|
463
484
|
/**
|
|
464
485
|
* Disable per-evaluation usage telemetry. ON by default. On Cloudflare
|
|
465
486
|
* Workers each beacon is an outbound subrequest, so disable on hot SSR paths
|
|
@@ -789,4 +810,4 @@ interface SeeApi {
|
|
|
789
810
|
*/
|
|
790
811
|
declare const see: SeeApi;
|
|
791
812
|
|
|
792
|
-
export { ANON_ID_COOKIE, type AttributesFn, type BootstrapData, type BootstrapEmitOptions, type BootstrapPayload, Client, type ConfigureOfflineOptions, type ConfigureOptions, type ConfigureTestOptions, type Consequence, Engine, type EngineEnv, type EngineOptions, type ExperimentResult, type ExpsBlob, FLAG_REASONS, type FetchLabelsOptions, type FlagDetail, type FlagReason, type FlagsBlob, type GetConfigOptions, type I18nForRequest, type LabelFile, type ScriptTagSpec, type SeeApi, type SeeChain, type SeeControlFlowChain, type SeeErrorEvent, type SeeExtras, type SeeKind, type SeeViolationChain, type ShipeasyServerConfig, type ShipeasyServerHandle, type StickyBucketStore, type StickyEntry, type User, type Violation, _murmur3ForTests, _resetConfigureForTests, _resetShipeasyServerForTests, clearOverrides, configure, configureForOffline, configureForTesting, configureShipeasyServer, createInMemoryStickyStore, fetchLabelsForSSR, flags, getBootstrapData, getBootstrapTags, getShipeasyServerClient, i18n, isExpected, onChange, overrideConfig, overrideExperiment, overrideFlag, see, seeContext, shipeasy, version };
|
|
813
|
+
export { ANON_ID_COOKIE, type AttributesFn, type BootstrapData, type BootstrapEmitOptions, type BootstrapPayload, Client, type ConfigureOfflineOptions, type ConfigureOptions, type ConfigureTestOptions, type Consequence, Engine, type EngineEnv, type EngineOptions, type ExperimentResult, type ExpsBlob, FLAG_REASONS, type FetchLabelsOptions, type FlagDetail, type FlagReason, type FlagsBlob, type GetConfigOptions, type I18nForRequest, LOG_LEVELS, type LabelFile, type LogLevel, type ScriptTagSpec, type SeeApi, type SeeChain, type SeeControlFlowChain, type SeeErrorEvent, type SeeExtras, type SeeKind, type SeeViolationChain, type ShipeasyServerConfig, type ShipeasyServerHandle, type StickyBucketStore, type StickyEntry, type User, type Violation, _murmur3ForTests, _resetConfigureForTests, _resetShipeasyServerForTests, clearOverrides, configure, configureForOffline, configureForTesting, configureShipeasyServer, createInMemoryStickyStore, fetchLabelsForSSR, flags, getBootstrapData, getBootstrapTags, getShipeasyServerClient, i18n, isExpected, onChange, overrideConfig, overrideExperiment, overrideFlag, see, seeContext, shipeasy, version };
|