@shipeasy/sdk 6.0.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/README.md +78 -351
- package/dist/client/index.d.mts +34 -1
- package/dist/client/index.d.ts +34 -1
- package/dist/client/index.js +142 -50
- package/dist/client/index.mjs +141 -50
- package/dist/openfeature-server/index.d.mts +27 -2
- package/dist/openfeature-server/index.d.ts +27 -2
- package/dist/openfeature-server/index.js +227 -4
- package/dist/openfeature-server/index.mjs +227 -4
- package/dist/openfeature-web/index.d.mts +10 -0
- package/dist/openfeature-web/index.d.ts +10 -0
- package/dist/server/index.d.mts +122 -1
- package/dist/server/index.d.ts +122 -1
- package/dist/server/index.js +214 -37
- package/dist/server/index.mjs +206 -37
- package/dist/skill-cli.js +56 -0
- package/docs/skill/SKILL.md +145 -0
- package/package.json +13 -6
package/dist/server/index.js
CHANGED
|
@@ -34,10 +34,14 @@ __export(server_exports, {
|
|
|
34
34
|
Client: () => Client,
|
|
35
35
|
Engine: () => Engine,
|
|
36
36
|
FLAG_REASONS: () => FLAG_REASONS,
|
|
37
|
+
LOG_LEVELS: () => LOG_LEVELS,
|
|
37
38
|
_murmur3ForTests: () => _murmur3ForTests,
|
|
38
39
|
_resetConfigureForTests: () => _resetConfigureForTests,
|
|
39
40
|
_resetShipeasyServerForTests: () => _resetShipeasyServerForTests,
|
|
41
|
+
clearOverrides: () => clearOverrides,
|
|
40
42
|
configure: () => configure,
|
|
43
|
+
configureForOffline: () => configureForOffline,
|
|
44
|
+
configureForTesting: () => configureForTesting,
|
|
41
45
|
configureShipeasyServer: () => configureShipeasyServer,
|
|
42
46
|
createInMemoryStickyStore: () => createInMemoryStickyStore,
|
|
43
47
|
fetchLabelsForSSR: () => fetchLabelsForSSR,
|
|
@@ -47,6 +51,10 @@ __export(server_exports, {
|
|
|
47
51
|
getShipeasyServerClient: () => getShipeasyServerClient,
|
|
48
52
|
i18n: () => i18n,
|
|
49
53
|
isExpected: () => isExpected,
|
|
54
|
+
onChange: () => onChange,
|
|
55
|
+
overrideConfig: () => overrideConfig,
|
|
56
|
+
overrideExperiment: () => overrideExperiment,
|
|
57
|
+
overrideFlag: () => overrideFlag,
|
|
50
58
|
see: () => see,
|
|
51
59
|
seeContext: () => seeContext,
|
|
52
60
|
shipeasy: () => shipeasy,
|
|
@@ -114,6 +122,53 @@ function send(url) {
|
|
|
114
122
|
}
|
|
115
123
|
}
|
|
116
124
|
|
|
125
|
+
// src/logger.ts
|
|
126
|
+
var LOG_LEVELS = ["silent", "error", "warn", "info", "debug"];
|
|
127
|
+
var RANK = {
|
|
128
|
+
silent: 0,
|
|
129
|
+
error: 1,
|
|
130
|
+
warn: 2,
|
|
131
|
+
info: 3,
|
|
132
|
+
debug: 4
|
|
133
|
+
};
|
|
134
|
+
var currentLevel = "warn";
|
|
135
|
+
function setLogLevel(level) {
|
|
136
|
+
if (typeof level === "string" && Object.prototype.hasOwnProperty.call(RANK, level)) {
|
|
137
|
+
currentLevel = level;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
function write(method, args) {
|
|
141
|
+
try {
|
|
142
|
+
const c = globalThis.console;
|
|
143
|
+
if (!c) return;
|
|
144
|
+
const fn = c[method] ?? c.log;
|
|
145
|
+
if (typeof fn === "function") fn.call(c, ...args);
|
|
146
|
+
} catch {
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
var logger = {
|
|
150
|
+
error(...args) {
|
|
151
|
+
if (RANK[currentLevel] >= RANK.error) write("error", args);
|
|
152
|
+
},
|
|
153
|
+
warn(...args) {
|
|
154
|
+
if (RANK[currentLevel] >= RANK.warn) write("warn", args);
|
|
155
|
+
},
|
|
156
|
+
info(...args) {
|
|
157
|
+
if (RANK[currentLevel] >= RANK.info) write("info", args);
|
|
158
|
+
},
|
|
159
|
+
debug(...args) {
|
|
160
|
+
if (RANK[currentLevel] >= RANK.debug) write("debug", args);
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
function safeRun(label, fallback, fn) {
|
|
164
|
+
try {
|
|
165
|
+
return fn();
|
|
166
|
+
} catch (err) {
|
|
167
|
+
logger.error(`[shipeasy] ${label} failed \u2014 returning safe default:`, String(err));
|
|
168
|
+
return fallback;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
117
172
|
// src/see/core.ts
|
|
118
173
|
var SEE_MAX_MESSAGE = 500;
|
|
119
174
|
var SEE_MAX_STACK = 8e3;
|
|
@@ -575,6 +630,7 @@ var Engine = class _Engine {
|
|
|
575
630
|
// 304). Never fired in testMode/offline (no polling happens there).
|
|
576
631
|
changeListeners = /* @__PURE__ */ new Set();
|
|
577
632
|
constructor(opts) {
|
|
633
|
+
setLogLevel(opts.logLevel);
|
|
578
634
|
this.apiKey = opts.apiKey;
|
|
579
635
|
this.baseUrl = (opts.baseUrl ?? "https://cdn.shipeasy.ai").replace(/\/$/, "");
|
|
580
636
|
this.env = opts.env ?? "prod";
|
|
@@ -698,14 +754,14 @@ var Engine = class _Engine {
|
|
|
698
754
|
try {
|
|
699
755
|
l();
|
|
700
756
|
} catch (err) {
|
|
701
|
-
|
|
757
|
+
logger.warn("[shipeasy] onChange listener threw:", String(err));
|
|
702
758
|
}
|
|
703
759
|
}
|
|
704
760
|
}
|
|
705
761
|
startPoll() {
|
|
706
762
|
this.timer = setInterval(() => {
|
|
707
763
|
this.fetchAll(true).catch(
|
|
708
|
-
(err) =>
|
|
764
|
+
(err) => logger.warn("[shipeasy] background poll failed:", String(err))
|
|
709
765
|
);
|
|
710
766
|
}, this.pollInterval * 1e3);
|
|
711
767
|
}
|
|
@@ -784,7 +840,12 @@ var Engine = class _Engine {
|
|
|
784
840
|
return "defaultValue" in opts ? opts.defaultValue : void 0;
|
|
785
841
|
}
|
|
786
842
|
if (!opts.decode) return raw;
|
|
787
|
-
|
|
843
|
+
try {
|
|
844
|
+
return opts.decode(raw);
|
|
845
|
+
} catch (err) {
|
|
846
|
+
logger.warn(`[shipeasy] getConfig('${name}') decode failed:`, String(err));
|
|
847
|
+
return "defaultValue" in opts ? opts.defaultValue : void 0;
|
|
848
|
+
}
|
|
788
849
|
}
|
|
789
850
|
getExperiment(name, user, defaultParams, decode) {
|
|
790
851
|
this.telemetry.emit("experiment", name);
|
|
@@ -799,7 +860,7 @@ var Engine = class _Engine {
|
|
|
799
860
|
try {
|
|
800
861
|
return { inExperiment: true, group: ov.group, params: decode(ov.params) };
|
|
801
862
|
} catch (err) {
|
|
802
|
-
|
|
863
|
+
logger.warn(`[shipeasy] getExperiment('${name}') override decode failed:`, String(err));
|
|
803
864
|
return notIn;
|
|
804
865
|
}
|
|
805
866
|
}
|
|
@@ -824,7 +885,7 @@ var Engine = class _Engine {
|
|
|
824
885
|
try {
|
|
825
886
|
return { inExperiment: true, group: g.name, params: decode(g.params) };
|
|
826
887
|
} catch (err) {
|
|
827
|
-
|
|
888
|
+
logger.warn(`[shipeasy] getExperiment('${name}') decode failed:`, String(err));
|
|
828
889
|
return notIn;
|
|
829
890
|
}
|
|
830
891
|
};
|
|
@@ -876,7 +937,7 @@ var Engine = class _Engine {
|
|
|
876
937
|
method: "POST",
|
|
877
938
|
headers: { "X-SDK-Key": this.apiKey, "Content-Type": "text/plain" },
|
|
878
939
|
body
|
|
879
|
-
}).catch((err) =>
|
|
940
|
+
}).catch((err) => logger.warn("[shipeasy] track failed:", String(err)));
|
|
880
941
|
}
|
|
881
942
|
/**
|
|
882
943
|
* Emit an exposure event for an experiment at the server-side decision point
|
|
@@ -907,7 +968,7 @@ var Engine = class _Engine {
|
|
|
907
968
|
method: "POST",
|
|
908
969
|
headers: { "X-SDK-Key": this.apiKey, "Content-Type": "text/plain" },
|
|
909
970
|
body
|
|
910
|
-
}).catch((err) =>
|
|
971
|
+
}).catch((err) => logger.warn("[shipeasy] logExposure failed:", String(err)));
|
|
911
972
|
}
|
|
912
973
|
/**
|
|
913
974
|
* Report a structured error into the errors primitive. Fire-and-forget —
|
|
@@ -927,7 +988,7 @@ var Engine = class _Engine {
|
|
|
927
988
|
method: "POST",
|
|
928
989
|
headers: { "X-SDK-Key": this.apiKey, "Content-Type": "text/plain" },
|
|
929
990
|
body: JSON.stringify({ events: [ev] })
|
|
930
|
-
}).catch((err) =>
|
|
991
|
+
}).catch((err) => logger.warn("[shipeasy] see() send failed:", String(err)));
|
|
931
992
|
} catch {
|
|
932
993
|
}
|
|
933
994
|
}
|
|
@@ -981,7 +1042,11 @@ var Engine = class _Engine {
|
|
|
981
1042
|
const ks = this.flagsBlob?.killswitches?.[name];
|
|
982
1043
|
if (!ks) return false;
|
|
983
1044
|
if (switchKey === void 0) return isEnabled(ks.killed);
|
|
984
|
-
|
|
1045
|
+
const switches = ks.switches ?? {};
|
|
1046
|
+
if (Object.prototype.hasOwnProperty.call(switches, switchKey)) {
|
|
1047
|
+
return isEnabled(switches[switchKey]);
|
|
1048
|
+
}
|
|
1049
|
+
return isEnabled(ks.killed);
|
|
985
1050
|
}
|
|
986
1051
|
};
|
|
987
1052
|
var _I18N_SSR_SYM = /* @__PURE__ */ Symbol.for("@shipeasy/sdk:ssr-i18n");
|
|
@@ -1110,7 +1175,7 @@ function _resetShipeasyServerForTests() {
|
|
|
1110
1175
|
async function shipeasy(opts) {
|
|
1111
1176
|
const serverKey = opts.serverKey ?? "";
|
|
1112
1177
|
if (!serverKey) {
|
|
1113
|
-
|
|
1178
|
+
logger.error(
|
|
1114
1179
|
"[shipeasy] No server key \u2014 flags, experiments and SSR i18n skipped. Pass `serverKey` to shipeasy() from @shipeasy/sdk/server with your server key (SHIPEASY_SERVER_KEY). Set it as a Worker secret with `wrangler secret put SHIPEASY_SERVER_KEY` (or add it to .env for local dev). Do not pass a client key here \u2014 the server entrypoint only accepts the server key."
|
|
1115
1180
|
);
|
|
1116
1181
|
}
|
|
@@ -1118,7 +1183,8 @@ async function shipeasy(opts) {
|
|
|
1118
1183
|
flags.configure({
|
|
1119
1184
|
apiKey: serverKey,
|
|
1120
1185
|
disableTelemetry: opts.disableTelemetry,
|
|
1121
|
-
privateAttributes: opts.privateAttributes
|
|
1186
|
+
privateAttributes: opts.privateAttributes,
|
|
1187
|
+
logLevel: opts.logLevel
|
|
1122
1188
|
});
|
|
1123
1189
|
let resolvedUrlOverrides = opts.urlOverrides;
|
|
1124
1190
|
if (!resolvedUrlOverrides) {
|
|
@@ -1244,21 +1310,30 @@ var flags = {
|
|
|
1244
1310
|
_server?.destroy();
|
|
1245
1311
|
},
|
|
1246
1312
|
get(name, user, defaultValue = false) {
|
|
1247
|
-
return _server?.getFlag(name, user, defaultValue) ?? defaultValue;
|
|
1313
|
+
return safeRun("flags.get", defaultValue, () => _server?.getFlag(name, user, defaultValue) ?? defaultValue);
|
|
1248
1314
|
},
|
|
1249
1315
|
/** Evaluate a gate and report why (value + reason). See {@link FlagDetail}. */
|
|
1250
1316
|
getDetail(name, user) {
|
|
1251
|
-
return
|
|
1317
|
+
return safeRun(
|
|
1318
|
+
"flags.getDetail",
|
|
1319
|
+
{ value: false, reason: "CLIENT_NOT_READY" },
|
|
1320
|
+
() => _server?.getFlagDetail(name, user) ?? { value: false, reason: "CLIENT_NOT_READY" }
|
|
1321
|
+
);
|
|
1252
1322
|
},
|
|
1253
1323
|
getConfig(name, decodeOrOpts) {
|
|
1254
|
-
return
|
|
1324
|
+
return safeRun(
|
|
1325
|
+
"flags.getConfig",
|
|
1326
|
+
void 0,
|
|
1327
|
+
() => _server?.getConfig(name, decodeOrOpts)
|
|
1328
|
+
);
|
|
1255
1329
|
},
|
|
1256
1330
|
getExperiment(name, user, defaultParams, decode) {
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1331
|
+
const notIn = { inExperiment: false, group: "control", params: defaultParams };
|
|
1332
|
+
return safeRun(
|
|
1333
|
+
"flags.getExperiment",
|
|
1334
|
+
notIn,
|
|
1335
|
+
() => _server?.getExperiment(name, user, defaultParams, decode) ?? notIn
|
|
1336
|
+
);
|
|
1262
1337
|
},
|
|
1263
1338
|
/**
|
|
1264
1339
|
* Read a killswitch. Without `switchKey`, returns true when the whole
|
|
@@ -1266,15 +1341,15 @@ var flags = {
|
|
|
1266
1341
|
* switch is on. Unknown killswitches / switches return false.
|
|
1267
1342
|
*/
|
|
1268
1343
|
ks(name, switchKey) {
|
|
1269
|
-
return _server?.getKillswitch(name, switchKey) ?? false;
|
|
1344
|
+
return safeRun("flags.ks", false, () => _server?.getKillswitch(name, switchKey) ?? false);
|
|
1270
1345
|
},
|
|
1271
1346
|
track(userId, eventName, props) {
|
|
1272
|
-
_server?.track(userId, eventName, props);
|
|
1347
|
+
safeRun("flags.track", void 0, () => _server?.track(userId, eventName, props));
|
|
1273
1348
|
},
|
|
1274
1349
|
/** Emit an exposure for an enrolled experiment at the decision point. See
|
|
1275
1350
|
* {@link Engine.logExposure}. No-op before configure(). */
|
|
1276
1351
|
logExposure(user, name) {
|
|
1277
|
-
_server?.logExposure(user, name);
|
|
1352
|
+
safeRun("flags.logExposure", void 0, () => _server?.logExposure(user, name));
|
|
1278
1353
|
},
|
|
1279
1354
|
/**
|
|
1280
1355
|
* Evaluate all flags / configs / experiments for a user against the locally
|
|
@@ -1282,27 +1357,81 @@ var flags = {
|
|
|
1282
1357
|
* overrides. Returns an empty payload when the blob hasn't been fetched yet.
|
|
1283
1358
|
*/
|
|
1284
1359
|
evaluate(user, rawUrl) {
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
configs: {},
|
|
1288
|
-
experiments: {},
|
|
1289
|
-
killswitches: {}
|
|
1290
|
-
};
|
|
1360
|
+
const empty = { flags: {}, configs: {}, experiments: {}, killswitches: {} };
|
|
1361
|
+
return safeRun("flags.evaluate", empty, () => _server?.evaluate(user, rawUrl) ?? empty);
|
|
1291
1362
|
}
|
|
1292
1363
|
};
|
|
1293
1364
|
var _identityAttributes = (user) => user && typeof user === "object" ? user : {};
|
|
1294
1365
|
var _attributes = _identityAttributes;
|
|
1295
1366
|
function configure(opts) {
|
|
1296
|
-
const { attributes, ...engineOpts } = opts;
|
|
1367
|
+
const { attributes, poll = false, init = true, ...engineOpts } = opts;
|
|
1297
1368
|
_attributes = attributes ?? _identityAttributes;
|
|
1298
1369
|
const engine = configureShipeasyServer(engineOpts);
|
|
1299
|
-
|
|
1300
|
-
|
|
1370
|
+
if (poll) {
|
|
1371
|
+
void engine.init().catch(() => {
|
|
1372
|
+
});
|
|
1373
|
+
} else if (init) {
|
|
1374
|
+
void engine.initOnce().catch(() => {
|
|
1375
|
+
});
|
|
1376
|
+
}
|
|
1301
1377
|
return engine;
|
|
1302
1378
|
}
|
|
1303
1379
|
function _resetConfigureForTests() {
|
|
1304
1380
|
_attributes = _identityAttributes;
|
|
1305
1381
|
}
|
|
1382
|
+
function _installGlobalEngine(engine, attributes) {
|
|
1383
|
+
_server?.destroy();
|
|
1384
|
+
_server = engine;
|
|
1385
|
+
_attributes = attributes ?? _identityAttributes;
|
|
1386
|
+
return engine;
|
|
1387
|
+
}
|
|
1388
|
+
function _applyOverrides(engine, flags2, configs, experiments) {
|
|
1389
|
+
for (const [name, value] of Object.entries(flags2 ?? {})) engine.overrideFlag(name, value);
|
|
1390
|
+
for (const [name, value] of Object.entries(configs ?? {})) engine.overrideConfig(name, value);
|
|
1391
|
+
for (const [name, [group, params]] of Object.entries(experiments ?? {}))
|
|
1392
|
+
engine.overrideExperiment(name, group, params);
|
|
1393
|
+
}
|
|
1394
|
+
function configureForTesting(opts = {}) {
|
|
1395
|
+
const engine = Engine.forTesting();
|
|
1396
|
+
_applyOverrides(engine, opts.flags, opts.configs, opts.experiments);
|
|
1397
|
+
return _installGlobalEngine(engine, opts.attributes);
|
|
1398
|
+
}
|
|
1399
|
+
function configureForOffline(opts) {
|
|
1400
|
+
let engine;
|
|
1401
|
+
if (opts.path !== void 0) {
|
|
1402
|
+
engine = Engine.fromFile(opts.path);
|
|
1403
|
+
} else if (opts.snapshot !== void 0) {
|
|
1404
|
+
engine = Engine.fromSnapshot(opts.snapshot);
|
|
1405
|
+
} else {
|
|
1406
|
+
throw new Error("[shipeasy] configureForOffline requires either { snapshot } or { path }");
|
|
1407
|
+
}
|
|
1408
|
+
_applyOverrides(engine, opts.flags, opts.configs, opts.experiments);
|
|
1409
|
+
return _installGlobalEngine(engine, opts.attributes);
|
|
1410
|
+
}
|
|
1411
|
+
function _requireGlobal(fn) {
|
|
1412
|
+
const engine = getShipeasyServerClient();
|
|
1413
|
+
if (!engine) {
|
|
1414
|
+
throw new Error(
|
|
1415
|
+
`[shipeasy] ${fn}(...) called before configure({ apiKey }) (or a configureFor* sibling).`
|
|
1416
|
+
);
|
|
1417
|
+
}
|
|
1418
|
+
return engine;
|
|
1419
|
+
}
|
|
1420
|
+
function overrideFlag(name, value) {
|
|
1421
|
+
_requireGlobal("overrideFlag").overrideFlag(name, value);
|
|
1422
|
+
}
|
|
1423
|
+
function overrideConfig(name, value) {
|
|
1424
|
+
_requireGlobal("overrideConfig").overrideConfig(name, value);
|
|
1425
|
+
}
|
|
1426
|
+
function overrideExperiment(name, group, params) {
|
|
1427
|
+
_requireGlobal("overrideExperiment").overrideExperiment(name, group, params);
|
|
1428
|
+
}
|
|
1429
|
+
function clearOverrides() {
|
|
1430
|
+
_requireGlobal("clearOverrides").clearOverrides();
|
|
1431
|
+
}
|
|
1432
|
+
function onChange(listener) {
|
|
1433
|
+
return _requireGlobal("onChange").onChange(listener);
|
|
1434
|
+
}
|
|
1306
1435
|
var Client = class {
|
|
1307
1436
|
engine;
|
|
1308
1437
|
/** The resolved attribute bag this handle evaluates against. */
|
|
@@ -1318,25 +1447,65 @@ var Client = class {
|
|
|
1318
1447
|
this.attributes = _attributes(user);
|
|
1319
1448
|
}
|
|
1320
1449
|
getFlag(name, defaultValue = false) {
|
|
1321
|
-
return
|
|
1450
|
+
return safeRun(
|
|
1451
|
+
"Client.getFlag",
|
|
1452
|
+
defaultValue,
|
|
1453
|
+
() => this.engine.getFlag(name, this.attributes, defaultValue)
|
|
1454
|
+
);
|
|
1322
1455
|
}
|
|
1323
1456
|
getFlagDetail(name) {
|
|
1324
|
-
return
|
|
1457
|
+
return safeRun(
|
|
1458
|
+
"Client.getFlagDetail",
|
|
1459
|
+
{ value: false, reason: "CLIENT_NOT_READY" },
|
|
1460
|
+
() => this.engine.getFlagDetail(name, this.attributes)
|
|
1461
|
+
);
|
|
1325
1462
|
}
|
|
1326
1463
|
getConfig(name, decodeOrOpts) {
|
|
1327
|
-
return
|
|
1464
|
+
return safeRun(
|
|
1465
|
+
"Client.getConfig",
|
|
1466
|
+
void 0,
|
|
1467
|
+
() => this.engine.getConfig(name, decodeOrOpts)
|
|
1468
|
+
);
|
|
1328
1469
|
}
|
|
1329
1470
|
getExperiment(name, defaultParams, decode) {
|
|
1330
|
-
|
|
1471
|
+
const notIn = { inExperiment: false, group: "control", params: defaultParams };
|
|
1472
|
+
return safeRun(
|
|
1473
|
+
"Client.getExperiment",
|
|
1474
|
+
notIn,
|
|
1475
|
+
() => this.engine.getExperiment(name, this.attributes, defaultParams, decode)
|
|
1476
|
+
);
|
|
1331
1477
|
}
|
|
1332
1478
|
/** Read a killswitch (not user-bound; mirrors {@link Engine.getKillswitch}). */
|
|
1333
1479
|
getKillswitch(name, switchKey) {
|
|
1334
|
-
return this.engine.getKillswitch(name, switchKey);
|
|
1480
|
+
return safeRun("Client.getKillswitch", false, () => this.engine.getKillswitch(name, switchKey));
|
|
1481
|
+
}
|
|
1482
|
+
/**
|
|
1483
|
+
* Record a conversion/metric event for the bound user. Derives the unit from
|
|
1484
|
+
* the resolved attribute bag (`user_id`, else `anonymous_id`) and delegates to
|
|
1485
|
+
* {@link Engine.track} — so an experiment is end-to-end Client-only (no need to
|
|
1486
|
+
* drop down to the Engine to log a conversion). Fire-and-forget; no-op in test
|
|
1487
|
+
* mode.
|
|
1488
|
+
*/
|
|
1489
|
+
track(eventName, props) {
|
|
1490
|
+
safeRun("Client.track", void 0, () => {
|
|
1491
|
+
const id = this.attributes.user_id ?? this.attributes.anonymous_id;
|
|
1492
|
+
if (id === void 0) return;
|
|
1493
|
+
this.engine.track(String(id), eventName, props);
|
|
1494
|
+
});
|
|
1495
|
+
}
|
|
1496
|
+
/**
|
|
1497
|
+
* Emit an exposure event for `name` at this server-side decision point for the
|
|
1498
|
+
* bound user. Delegates to {@link Engine.logExposure} with the resolved
|
|
1499
|
+
* attribute bag (re-evaluates enrolment; no-op when the user isn't enrolled or
|
|
1500
|
+
* in test mode).
|
|
1501
|
+
*/
|
|
1502
|
+
logExposure(name) {
|
|
1503
|
+
safeRun("Client.logExposure", void 0, () => this.engine.logExposure(this.attributes, name));
|
|
1335
1504
|
}
|
|
1336
1505
|
};
|
|
1337
1506
|
function dispatchSee(problem, consequence, extras, kind) {
|
|
1338
1507
|
if (!_server) {
|
|
1339
|
-
|
|
1508
|
+
logger.warn("[shipeasy] see() called before shipeasy({ serverKey }) \u2014 error dropped");
|
|
1340
1509
|
return;
|
|
1341
1510
|
}
|
|
1342
1511
|
_server.reportError(problem, consequence, extras, kind);
|
|
@@ -1354,10 +1523,14 @@ var see = Object.assign(
|
|
|
1354
1523
|
Client,
|
|
1355
1524
|
Engine,
|
|
1356
1525
|
FLAG_REASONS,
|
|
1526
|
+
LOG_LEVELS,
|
|
1357
1527
|
_murmur3ForTests,
|
|
1358
1528
|
_resetConfigureForTests,
|
|
1359
1529
|
_resetShipeasyServerForTests,
|
|
1530
|
+
clearOverrides,
|
|
1360
1531
|
configure,
|
|
1532
|
+
configureForOffline,
|
|
1533
|
+
configureForTesting,
|
|
1361
1534
|
configureShipeasyServer,
|
|
1362
1535
|
createInMemoryStickyStore,
|
|
1363
1536
|
fetchLabelsForSSR,
|
|
@@ -1367,6 +1540,10 @@ var see = Object.assign(
|
|
|
1367
1540
|
getShipeasyServerClient,
|
|
1368
1541
|
i18n,
|
|
1369
1542
|
isExpected,
|
|
1543
|
+
onChange,
|
|
1544
|
+
overrideConfig,
|
|
1545
|
+
overrideExperiment,
|
|
1546
|
+
overrideFlag,
|
|
1370
1547
|
see,
|
|
1371
1548
|
seeContext,
|
|
1372
1549
|
shipeasy,
|