@shipeasy/sdk 5.3.0 → 6.0.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 +106 -27
- package/dist/client/index.d.mts +90 -18
- package/dist/client/index.d.ts +90 -18
- package/dist/client/index.js +100 -11
- package/dist/client/index.mjs +96 -10
- package/dist/openfeature-server/index.d.mts +19 -19
- package/dist/openfeature-server/index.d.ts +19 -19
- package/dist/openfeature-web/index.d.mts +12 -12
- package/dist/openfeature-web/index.d.ts +12 -12
- package/dist/server/index.d.mts +134 -45
- package/dist/server/index.d.ts +134 -45
- package/dist/server/index.js +113 -45
- package/dist/server/index.mjs +107 -43
- package/package.json +1 -1
package/dist/client/index.js
CHANGED
|
@@ -20,14 +20,17 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/client/index.ts
|
|
21
21
|
var client_exports = {};
|
|
22
22
|
__export(client_exports, {
|
|
23
|
+
Client: () => Client,
|
|
24
|
+
Engine: () => Engine,
|
|
23
25
|
FLAG_REASONS: () => FLAG_REASONS,
|
|
24
|
-
FlagsClientBrowser: () => FlagsClientBrowser,
|
|
25
26
|
LABEL_MARKER_END: () => LABEL_MARKER_END,
|
|
26
27
|
LABEL_MARKER_RE: () => LABEL_MARKER_RE,
|
|
27
28
|
LABEL_MARKER_SEP: () => LABEL_MARKER_SEP,
|
|
28
29
|
LABEL_MARKER_START: () => LABEL_MARKER_START,
|
|
30
|
+
_resetConfigureForTests: () => _resetConfigureForTests,
|
|
29
31
|
_resetShipeasyForTests: () => _resetShipeasyForTests,
|
|
30
32
|
attachDevtools: () => attachDevtools,
|
|
33
|
+
configure: () => configure,
|
|
31
34
|
configureShipeasy: () => configureShipeasy,
|
|
32
35
|
encodeLabelMarker: () => encodeLabelMarker,
|
|
33
36
|
flags: () => flags,
|
|
@@ -768,7 +771,7 @@ function writeStickyCookie(map) {
|
|
|
768
771
|
function getOrCreateAnonId() {
|
|
769
772
|
let id = readAnonCookie();
|
|
770
773
|
if (!id && typeof window !== "undefined") {
|
|
771
|
-
id =
|
|
774
|
+
id = getBootstrap()?.anonId ?? null;
|
|
772
775
|
}
|
|
773
776
|
if (!id) {
|
|
774
777
|
try {
|
|
@@ -912,7 +915,7 @@ function readExperimentOverridesFromUrl() {
|
|
|
912
915
|
}
|
|
913
916
|
return out;
|
|
914
917
|
}
|
|
915
|
-
var
|
|
918
|
+
var Engine = class _Engine {
|
|
916
919
|
sdkKey;
|
|
917
920
|
baseUrl;
|
|
918
921
|
autoGuardrails;
|
|
@@ -934,7 +937,7 @@ var FlagsClientBrowser = class _FlagsClientBrowser {
|
|
|
934
937
|
// Monotonic counter so a later identify() always wins even if its /sdk/evaluate
|
|
935
938
|
// response races and lands before an earlier in-flight call's response.
|
|
936
939
|
identifySeq = 0;
|
|
937
|
-
// Test mode: built by `
|
|
940
|
+
// Test mode: built by `Engine.forTesting()`. When set, identify()
|
|
938
941
|
// never fetches, track() is a no-op, telemetry is off, and the client is
|
|
939
942
|
// already ready with an empty eval result.
|
|
940
943
|
testMode;
|
|
@@ -988,13 +991,13 @@ var FlagsClientBrowser = class _FlagsClientBrowser {
|
|
|
988
991
|
* key required.
|
|
989
992
|
*
|
|
990
993
|
* ```ts
|
|
991
|
-
* const client =
|
|
994
|
+
* const client = Engine.forTesting();
|
|
992
995
|
* client.overrideFlag("new_checkout", true);
|
|
993
996
|
* client.getFlag("new_checkout"); // true
|
|
994
997
|
* ```
|
|
995
998
|
*/
|
|
996
999
|
static forTesting(opts) {
|
|
997
|
-
return new
|
|
1000
|
+
return new _Engine({
|
|
998
1001
|
sdkKey: "",
|
|
999
1002
|
autoGuardrails: false,
|
|
1000
1003
|
...opts,
|
|
@@ -1415,7 +1418,7 @@ function shipeasy(opts) {
|
|
|
1415
1418
|
}
|
|
1416
1419
|
function configureShipeasy(opts) {
|
|
1417
1420
|
if (_client) return _client;
|
|
1418
|
-
_client = new
|
|
1421
|
+
_client = new Engine(opts);
|
|
1419
1422
|
return _client;
|
|
1420
1423
|
}
|
|
1421
1424
|
function getShipeasyClient() {
|
|
@@ -1430,6 +1433,13 @@ var _i18nLoaderInjected = false;
|
|
|
1430
1433
|
function injectI18nLoader(clientKey, baseUrl, profileOpt) {
|
|
1431
1434
|
if (_i18nLoaderInjected || typeof document === "undefined") return;
|
|
1432
1435
|
if (!clientKey || typeof document.createElement !== "function" || !document.head) return;
|
|
1436
|
+
try {
|
|
1437
|
+
if (document.querySelector?.('script[src*="/sdk/i18n/loader.js"][data-key]')) {
|
|
1438
|
+
_i18nLoaderInjected = true;
|
|
1439
|
+
return;
|
|
1440
|
+
}
|
|
1441
|
+
} catch {
|
|
1442
|
+
}
|
|
1433
1443
|
_i18nLoaderInjected = true;
|
|
1434
1444
|
try {
|
|
1435
1445
|
const bs = getBootstrap();
|
|
@@ -1442,9 +1452,36 @@ function injectI18nLoader(clientKey, baseUrl, profileOpt) {
|
|
|
1442
1452
|
} catch {
|
|
1443
1453
|
}
|
|
1444
1454
|
}
|
|
1455
|
+
var _bootstrapFromTag = null;
|
|
1456
|
+
function readBootstrapTag() {
|
|
1457
|
+
if (_bootstrapFromTag) return _bootstrapFromTag;
|
|
1458
|
+
if (typeof document === "undefined" || typeof document.querySelector !== "function") return null;
|
|
1459
|
+
const el = document.querySelector("script[data-se-bootstrap]");
|
|
1460
|
+
if (!el) return null;
|
|
1461
|
+
const J = (name) => {
|
|
1462
|
+
try {
|
|
1463
|
+
return JSON.parse(el.getAttribute(name) || "{}");
|
|
1464
|
+
} catch {
|
|
1465
|
+
return {};
|
|
1466
|
+
}
|
|
1467
|
+
};
|
|
1468
|
+
const bs = {
|
|
1469
|
+
flags: J("data-flags"),
|
|
1470
|
+
configs: J("data-configs"),
|
|
1471
|
+
experiments: J("data-experiments"),
|
|
1472
|
+
killswitches: J("data-killswitches"),
|
|
1473
|
+
i18nProfile: el.getAttribute("data-i18n-profile") || void 0,
|
|
1474
|
+
apiUrl: el.getAttribute("data-api-url") || void 0,
|
|
1475
|
+
anonId: el.getAttribute("data-anon-id") || void 0
|
|
1476
|
+
};
|
|
1477
|
+
_bootstrapFromTag = bs;
|
|
1478
|
+
return bs;
|
|
1479
|
+
}
|
|
1445
1480
|
function getBootstrap() {
|
|
1446
1481
|
if (typeof window === "undefined") return null;
|
|
1447
|
-
|
|
1482
|
+
const g = window.__SE_BOOTSTRAP;
|
|
1483
|
+
if (g) return g;
|
|
1484
|
+
return readBootstrapTag();
|
|
1448
1485
|
}
|
|
1449
1486
|
var _mountedAndReady = false;
|
|
1450
1487
|
var _standaloneListeners = /* @__PURE__ */ new Set();
|
|
@@ -1520,7 +1557,7 @@ var flags = {
|
|
|
1520
1557
|
return typeof decodeOrOpts === "function" ? _client.getExperiment(name, defaultParams, decodeOrOpts, variants) : _client.getExperiment(name, defaultParams, decodeOrOpts ?? {});
|
|
1521
1558
|
},
|
|
1522
1559
|
/** Manually log an exposure for an enrolled experiment. See
|
|
1523
|
-
* {@link
|
|
1560
|
+
* {@link Engine.logExposure}. No-op before configure(). */
|
|
1524
1561
|
logExposure(name) {
|
|
1525
1562
|
_client?.logExposure(name);
|
|
1526
1563
|
},
|
|
@@ -1577,6 +1614,55 @@ var flags = {
|
|
|
1577
1614
|
return _client?.ready ?? false;
|
|
1578
1615
|
}
|
|
1579
1616
|
};
|
|
1617
|
+
var _identityAttributes = (user) => user && typeof user === "object" ? user : {};
|
|
1618
|
+
var _attributes = _identityAttributes;
|
|
1619
|
+
function configure(opts) {
|
|
1620
|
+
const { attributes, ...clientConfig } = opts;
|
|
1621
|
+
_attributes = attributes ?? _identityAttributes;
|
|
1622
|
+
return shipeasy({ autoIdentify: false, ...clientConfig });
|
|
1623
|
+
}
|
|
1624
|
+
function _resetConfigureForTests() {
|
|
1625
|
+
_attributes = _identityAttributes;
|
|
1626
|
+
}
|
|
1627
|
+
var Client = class {
|
|
1628
|
+
engine;
|
|
1629
|
+
/** The resolved attribute bag this handle evaluates against. */
|
|
1630
|
+
attributes;
|
|
1631
|
+
_identify;
|
|
1632
|
+
constructor(user) {
|
|
1633
|
+
const engine = getShipeasyClient();
|
|
1634
|
+
if (!engine) {
|
|
1635
|
+
throw new Error(
|
|
1636
|
+
"[shipeasy] new Client(user) called before configure({ clientKey }). Call configure() once at app boot from @shipeasy/sdk/client."
|
|
1637
|
+
);
|
|
1638
|
+
}
|
|
1639
|
+
this.engine = engine;
|
|
1640
|
+
this.attributes = _attributes(user);
|
|
1641
|
+
this._identify = this.engine.identify(this.attributes).catch((err) => {
|
|
1642
|
+
console.warn("[shipeasy] Client identify failed:", String(err));
|
|
1643
|
+
});
|
|
1644
|
+
}
|
|
1645
|
+
/** Resolves once the engine's identify() for this user has completed. */
|
|
1646
|
+
ready() {
|
|
1647
|
+
return this._identify;
|
|
1648
|
+
}
|
|
1649
|
+
getFlag(name, defaultValue = false) {
|
|
1650
|
+
return this.engine.getFlag(name, defaultValue);
|
|
1651
|
+
}
|
|
1652
|
+
getFlagDetail(name) {
|
|
1653
|
+
return this.engine.getFlagDetail(name);
|
|
1654
|
+
}
|
|
1655
|
+
getConfig(name, decodeOrOpts) {
|
|
1656
|
+
return this.engine.getConfig(name, decodeOrOpts);
|
|
1657
|
+
}
|
|
1658
|
+
getExperiment(name, defaultParams, decode) {
|
|
1659
|
+
return this.engine.getExperiment(name, defaultParams, decode);
|
|
1660
|
+
}
|
|
1661
|
+
/** Read a killswitch (not user-bound; mirrors {@link Engine.getKillswitch}). */
|
|
1662
|
+
getKillswitch(name, switchKey) {
|
|
1663
|
+
return this.engine.getKillswitch(name, switchKey);
|
|
1664
|
+
}
|
|
1665
|
+
};
|
|
1580
1666
|
function dispatchSee(problem, consequence, extras, kind) {
|
|
1581
1667
|
if (!_client) {
|
|
1582
1668
|
console.warn("[shipeasy] see() called before shipeasy({ clientKey }) \u2014 error dropped");
|
|
@@ -1623,7 +1709,7 @@ function getSSRI18nStore() {
|
|
|
1623
1709
|
var _EDIT_MODE_FALLBACK_SYM = /* @__PURE__ */ Symbol.for("@shipeasy/sdk:ssr-edit-mode-fallback");
|
|
1624
1710
|
function isEditLabelsMode() {
|
|
1625
1711
|
if (typeof window !== "undefined") {
|
|
1626
|
-
return
|
|
1712
|
+
return new URLSearchParams(location.search).has("se_edit_labels") || /(?:^|;\s*)se_edit_labels=1(?:;|$)/.test(document.cookie);
|
|
1627
1713
|
}
|
|
1628
1714
|
const val = globalThis[_EDIT_MODE_SSR_SYM];
|
|
1629
1715
|
if (typeof val === "boolean") return val;
|
|
@@ -1825,14 +1911,17 @@ var i18n = {
|
|
|
1825
1911
|
};
|
|
1826
1912
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1827
1913
|
0 && (module.exports = {
|
|
1914
|
+
Client,
|
|
1915
|
+
Engine,
|
|
1828
1916
|
FLAG_REASONS,
|
|
1829
|
-
FlagsClientBrowser,
|
|
1830
1917
|
LABEL_MARKER_END,
|
|
1831
1918
|
LABEL_MARKER_RE,
|
|
1832
1919
|
LABEL_MARKER_SEP,
|
|
1833
1920
|
LABEL_MARKER_START,
|
|
1921
|
+
_resetConfigureForTests,
|
|
1834
1922
|
_resetShipeasyForTests,
|
|
1835
1923
|
attachDevtools,
|
|
1924
|
+
configure,
|
|
1836
1925
|
configureShipeasy,
|
|
1837
1926
|
encodeLabelMarker,
|
|
1838
1927
|
flags,
|
package/dist/client/index.mjs
CHANGED
|
@@ -719,7 +719,7 @@ function writeStickyCookie(map) {
|
|
|
719
719
|
function getOrCreateAnonId() {
|
|
720
720
|
let id = readAnonCookie();
|
|
721
721
|
if (!id && typeof window !== "undefined") {
|
|
722
|
-
id =
|
|
722
|
+
id = getBootstrap()?.anonId ?? null;
|
|
723
723
|
}
|
|
724
724
|
if (!id) {
|
|
725
725
|
try {
|
|
@@ -863,7 +863,7 @@ function readExperimentOverridesFromUrl() {
|
|
|
863
863
|
}
|
|
864
864
|
return out;
|
|
865
865
|
}
|
|
866
|
-
var
|
|
866
|
+
var Engine = class _Engine {
|
|
867
867
|
sdkKey;
|
|
868
868
|
baseUrl;
|
|
869
869
|
autoGuardrails;
|
|
@@ -885,7 +885,7 @@ var FlagsClientBrowser = class _FlagsClientBrowser {
|
|
|
885
885
|
// Monotonic counter so a later identify() always wins even if its /sdk/evaluate
|
|
886
886
|
// response races and lands before an earlier in-flight call's response.
|
|
887
887
|
identifySeq = 0;
|
|
888
|
-
// Test mode: built by `
|
|
888
|
+
// Test mode: built by `Engine.forTesting()`. When set, identify()
|
|
889
889
|
// never fetches, track() is a no-op, telemetry is off, and the client is
|
|
890
890
|
// already ready with an empty eval result.
|
|
891
891
|
testMode;
|
|
@@ -939,13 +939,13 @@ var FlagsClientBrowser = class _FlagsClientBrowser {
|
|
|
939
939
|
* key required.
|
|
940
940
|
*
|
|
941
941
|
* ```ts
|
|
942
|
-
* const client =
|
|
942
|
+
* const client = Engine.forTesting();
|
|
943
943
|
* client.overrideFlag("new_checkout", true);
|
|
944
944
|
* client.getFlag("new_checkout"); // true
|
|
945
945
|
* ```
|
|
946
946
|
*/
|
|
947
947
|
static forTesting(opts) {
|
|
948
|
-
return new
|
|
948
|
+
return new _Engine({
|
|
949
949
|
sdkKey: "",
|
|
950
950
|
autoGuardrails: false,
|
|
951
951
|
...opts,
|
|
@@ -1366,7 +1366,7 @@ function shipeasy(opts) {
|
|
|
1366
1366
|
}
|
|
1367
1367
|
function configureShipeasy(opts) {
|
|
1368
1368
|
if (_client) return _client;
|
|
1369
|
-
_client = new
|
|
1369
|
+
_client = new Engine(opts);
|
|
1370
1370
|
return _client;
|
|
1371
1371
|
}
|
|
1372
1372
|
function getShipeasyClient() {
|
|
@@ -1381,6 +1381,13 @@ var _i18nLoaderInjected = false;
|
|
|
1381
1381
|
function injectI18nLoader(clientKey, baseUrl, profileOpt) {
|
|
1382
1382
|
if (_i18nLoaderInjected || typeof document === "undefined") return;
|
|
1383
1383
|
if (!clientKey || typeof document.createElement !== "function" || !document.head) return;
|
|
1384
|
+
try {
|
|
1385
|
+
if (document.querySelector?.('script[src*="/sdk/i18n/loader.js"][data-key]')) {
|
|
1386
|
+
_i18nLoaderInjected = true;
|
|
1387
|
+
return;
|
|
1388
|
+
}
|
|
1389
|
+
} catch {
|
|
1390
|
+
}
|
|
1384
1391
|
_i18nLoaderInjected = true;
|
|
1385
1392
|
try {
|
|
1386
1393
|
const bs = getBootstrap();
|
|
@@ -1393,9 +1400,36 @@ function injectI18nLoader(clientKey, baseUrl, profileOpt) {
|
|
|
1393
1400
|
} catch {
|
|
1394
1401
|
}
|
|
1395
1402
|
}
|
|
1403
|
+
var _bootstrapFromTag = null;
|
|
1404
|
+
function readBootstrapTag() {
|
|
1405
|
+
if (_bootstrapFromTag) return _bootstrapFromTag;
|
|
1406
|
+
if (typeof document === "undefined" || typeof document.querySelector !== "function") return null;
|
|
1407
|
+
const el = document.querySelector("script[data-se-bootstrap]");
|
|
1408
|
+
if (!el) return null;
|
|
1409
|
+
const J = (name) => {
|
|
1410
|
+
try {
|
|
1411
|
+
return JSON.parse(el.getAttribute(name) || "{}");
|
|
1412
|
+
} catch {
|
|
1413
|
+
return {};
|
|
1414
|
+
}
|
|
1415
|
+
};
|
|
1416
|
+
const bs = {
|
|
1417
|
+
flags: J("data-flags"),
|
|
1418
|
+
configs: J("data-configs"),
|
|
1419
|
+
experiments: J("data-experiments"),
|
|
1420
|
+
killswitches: J("data-killswitches"),
|
|
1421
|
+
i18nProfile: el.getAttribute("data-i18n-profile") || void 0,
|
|
1422
|
+
apiUrl: el.getAttribute("data-api-url") || void 0,
|
|
1423
|
+
anonId: el.getAttribute("data-anon-id") || void 0
|
|
1424
|
+
};
|
|
1425
|
+
_bootstrapFromTag = bs;
|
|
1426
|
+
return bs;
|
|
1427
|
+
}
|
|
1396
1428
|
function getBootstrap() {
|
|
1397
1429
|
if (typeof window === "undefined") return null;
|
|
1398
|
-
|
|
1430
|
+
const g = window.__SE_BOOTSTRAP;
|
|
1431
|
+
if (g) return g;
|
|
1432
|
+
return readBootstrapTag();
|
|
1399
1433
|
}
|
|
1400
1434
|
var _mountedAndReady = false;
|
|
1401
1435
|
var _standaloneListeners = /* @__PURE__ */ new Set();
|
|
@@ -1471,7 +1505,7 @@ var flags = {
|
|
|
1471
1505
|
return typeof decodeOrOpts === "function" ? _client.getExperiment(name, defaultParams, decodeOrOpts, variants) : _client.getExperiment(name, defaultParams, decodeOrOpts ?? {});
|
|
1472
1506
|
},
|
|
1473
1507
|
/** Manually log an exposure for an enrolled experiment. See
|
|
1474
|
-
* {@link
|
|
1508
|
+
* {@link Engine.logExposure}. No-op before configure(). */
|
|
1475
1509
|
logExposure(name) {
|
|
1476
1510
|
_client?.logExposure(name);
|
|
1477
1511
|
},
|
|
@@ -1528,6 +1562,55 @@ var flags = {
|
|
|
1528
1562
|
return _client?.ready ?? false;
|
|
1529
1563
|
}
|
|
1530
1564
|
};
|
|
1565
|
+
var _identityAttributes = (user) => user && typeof user === "object" ? user : {};
|
|
1566
|
+
var _attributes = _identityAttributes;
|
|
1567
|
+
function configure(opts) {
|
|
1568
|
+
const { attributes, ...clientConfig } = opts;
|
|
1569
|
+
_attributes = attributes ?? _identityAttributes;
|
|
1570
|
+
return shipeasy({ autoIdentify: false, ...clientConfig });
|
|
1571
|
+
}
|
|
1572
|
+
function _resetConfigureForTests() {
|
|
1573
|
+
_attributes = _identityAttributes;
|
|
1574
|
+
}
|
|
1575
|
+
var Client = class {
|
|
1576
|
+
engine;
|
|
1577
|
+
/** The resolved attribute bag this handle evaluates against. */
|
|
1578
|
+
attributes;
|
|
1579
|
+
_identify;
|
|
1580
|
+
constructor(user) {
|
|
1581
|
+
const engine = getShipeasyClient();
|
|
1582
|
+
if (!engine) {
|
|
1583
|
+
throw new Error(
|
|
1584
|
+
"[shipeasy] new Client(user) called before configure({ clientKey }). Call configure() once at app boot from @shipeasy/sdk/client."
|
|
1585
|
+
);
|
|
1586
|
+
}
|
|
1587
|
+
this.engine = engine;
|
|
1588
|
+
this.attributes = _attributes(user);
|
|
1589
|
+
this._identify = this.engine.identify(this.attributes).catch((err) => {
|
|
1590
|
+
console.warn("[shipeasy] Client identify failed:", String(err));
|
|
1591
|
+
});
|
|
1592
|
+
}
|
|
1593
|
+
/** Resolves once the engine's identify() for this user has completed. */
|
|
1594
|
+
ready() {
|
|
1595
|
+
return this._identify;
|
|
1596
|
+
}
|
|
1597
|
+
getFlag(name, defaultValue = false) {
|
|
1598
|
+
return this.engine.getFlag(name, defaultValue);
|
|
1599
|
+
}
|
|
1600
|
+
getFlagDetail(name) {
|
|
1601
|
+
return this.engine.getFlagDetail(name);
|
|
1602
|
+
}
|
|
1603
|
+
getConfig(name, decodeOrOpts) {
|
|
1604
|
+
return this.engine.getConfig(name, decodeOrOpts);
|
|
1605
|
+
}
|
|
1606
|
+
getExperiment(name, defaultParams, decode) {
|
|
1607
|
+
return this.engine.getExperiment(name, defaultParams, decode);
|
|
1608
|
+
}
|
|
1609
|
+
/** Read a killswitch (not user-bound; mirrors {@link Engine.getKillswitch}). */
|
|
1610
|
+
getKillswitch(name, switchKey) {
|
|
1611
|
+
return this.engine.getKillswitch(name, switchKey);
|
|
1612
|
+
}
|
|
1613
|
+
};
|
|
1531
1614
|
function dispatchSee(problem, consequence, extras, kind) {
|
|
1532
1615
|
if (!_client) {
|
|
1533
1616
|
console.warn("[shipeasy] see() called before shipeasy({ clientKey }) \u2014 error dropped");
|
|
@@ -1574,7 +1657,7 @@ function getSSRI18nStore() {
|
|
|
1574
1657
|
var _EDIT_MODE_FALLBACK_SYM = /* @__PURE__ */ Symbol.for("@shipeasy/sdk:ssr-edit-mode-fallback");
|
|
1575
1658
|
function isEditLabelsMode() {
|
|
1576
1659
|
if (typeof window !== "undefined") {
|
|
1577
|
-
return
|
|
1660
|
+
return new URLSearchParams(location.search).has("se_edit_labels") || /(?:^|;\s*)se_edit_labels=1(?:;|$)/.test(document.cookie);
|
|
1578
1661
|
}
|
|
1579
1662
|
const val = globalThis[_EDIT_MODE_SSR_SYM];
|
|
1580
1663
|
if (typeof val === "boolean") return val;
|
|
@@ -1775,14 +1858,17 @@ var i18n = {
|
|
|
1775
1858
|
}
|
|
1776
1859
|
};
|
|
1777
1860
|
export {
|
|
1861
|
+
Client,
|
|
1862
|
+
Engine,
|
|
1778
1863
|
FLAG_REASONS,
|
|
1779
|
-
FlagsClientBrowser,
|
|
1780
1864
|
LABEL_MARKER_END,
|
|
1781
1865
|
LABEL_MARKER_RE,
|
|
1782
1866
|
LABEL_MARKER_SEP,
|
|
1783
1867
|
LABEL_MARKER_START,
|
|
1868
|
+
_resetConfigureForTests,
|
|
1784
1869
|
_resetShipeasyForTests,
|
|
1785
1870
|
attachDevtools,
|
|
1871
|
+
configure,
|
|
1786
1872
|
configureShipeasy,
|
|
1787
1873
|
encodeLabelMarker,
|
|
1788
1874
|
flags,
|
|
@@ -78,7 +78,7 @@ interface StickyEntry {
|
|
|
78
78
|
/**
|
|
79
79
|
* Pluggable sticky-bucketing store for the server (doc 20 §2). Keyed by the
|
|
80
80
|
* bucketing unit; the value is that unit's per-experiment assignments. Absent
|
|
81
|
-
* from {@link
|
|
81
|
+
* from {@link EngineOptions} ⇒ today's deterministic behaviour. Use
|
|
82
82
|
* {@link createInMemoryStickyStore} or a cookie-bridge built from request
|
|
83
83
|
* cookies.
|
|
84
84
|
*/
|
|
@@ -93,7 +93,7 @@ interface Killswitch {
|
|
|
93
93
|
killed: 0 | 1 | boolean;
|
|
94
94
|
switches?: Record<string, 0 | 1 | boolean>;
|
|
95
95
|
}
|
|
96
|
-
/** Body of `GET /sdk/flags` — the snapshot's `flags` field. See {@link
|
|
96
|
+
/** Body of `GET /sdk/flags` — the snapshot's `flags` field. See {@link Engine.fromSnapshot}. */
|
|
97
97
|
interface FlagsBlob {
|
|
98
98
|
version: string;
|
|
99
99
|
plan: string;
|
|
@@ -103,7 +103,7 @@ interface FlagsBlob {
|
|
|
103
103
|
}>;
|
|
104
104
|
killswitches: Record<string, Killswitch>;
|
|
105
105
|
}
|
|
106
|
-
/** Body of `GET /sdk/experiments` — the snapshot's `experiments` field. See {@link
|
|
106
|
+
/** Body of `GET /sdk/experiments` — the snapshot's `experiments` field. See {@link Engine.fromSnapshot}. */
|
|
107
107
|
interface ExpsBlob {
|
|
108
108
|
version: string;
|
|
109
109
|
universes: Record<string, Universe>;
|
|
@@ -115,12 +115,12 @@ interface BootstrapPayload {
|
|
|
115
115
|
experiments: Record<string, ExperimentResult<Record<string, unknown>>>;
|
|
116
116
|
killswitches: Record<string, boolean | Record<string, boolean>>;
|
|
117
117
|
}
|
|
118
|
-
type
|
|
119
|
-
interface
|
|
118
|
+
type EngineEnv = "dev" | "staging" | "prod";
|
|
119
|
+
interface EngineOptions {
|
|
120
120
|
apiKey: string;
|
|
121
121
|
baseUrl?: string;
|
|
122
122
|
/** Which published env to read values from. Defaults to "prod". */
|
|
123
|
-
env?:
|
|
123
|
+
env?: EngineEnv;
|
|
124
124
|
/**
|
|
125
125
|
* Preload the flags blob synchronously without a network fetch. Primarily
|
|
126
126
|
* for tests; production callers should rely on init()/initOnce().
|
|
@@ -155,12 +155,12 @@ interface FlagsClientOptions {
|
|
|
155
155
|
/**
|
|
156
156
|
* Test mode — no network at all. init()/initOnce() are no-ops (never fetch),
|
|
157
157
|
* track() is a no-op, telemetry is forced off, and the client starts
|
|
158
|
-
* "initialized" with an empty blob. Prefer the {@link
|
|
158
|
+
* "initialized" with an empty blob. Prefer the {@link Engine.forTesting}
|
|
159
159
|
* factory over passing this directly.
|
|
160
160
|
*/
|
|
161
161
|
testMode?: boolean;
|
|
162
162
|
}
|
|
163
|
-
declare class
|
|
163
|
+
declare class Engine {
|
|
164
164
|
private readonly apiKey;
|
|
165
165
|
private readonly baseUrl;
|
|
166
166
|
private readonly env;
|
|
@@ -180,7 +180,7 @@ declare class FlagsClient {
|
|
|
180
180
|
private readonly configOverrides;
|
|
181
181
|
private readonly experimentOverrides;
|
|
182
182
|
private readonly changeListeners;
|
|
183
|
-
constructor(opts:
|
|
183
|
+
constructor(opts: EngineOptions);
|
|
184
184
|
/**
|
|
185
185
|
* Build a no-network, immediately-usable client for tests (Statsig-style).
|
|
186
186
|
* init()/initOnce() are no-ops (never fetch), track() is a no-op, telemetry
|
|
@@ -188,12 +188,12 @@ declare class FlagsClient {
|
|
|
188
188
|
* with overrideFlag/overrideConfig/overrideExperiment. No SDK key required.
|
|
189
189
|
*
|
|
190
190
|
* ```ts
|
|
191
|
-
* const client =
|
|
191
|
+
* const client = Engine.forTesting();
|
|
192
192
|
* client.overrideFlag("new_checkout", true);
|
|
193
193
|
* client.getFlag("new_checkout", { user_id: "u1" }); // true
|
|
194
194
|
* ```
|
|
195
195
|
*/
|
|
196
|
-
static forTesting(opts?: Partial<
|
|
196
|
+
static forTesting(opts?: Partial<EngineOptions>): Engine;
|
|
197
197
|
/**
|
|
198
198
|
* Build a fully OFFLINE client from a pre-captured snapshot — no network ever.
|
|
199
199
|
* Reuses the test-mode plumbing (init()/initOnce()/track() are no-ops,
|
|
@@ -207,14 +207,14 @@ declare class FlagsClient {
|
|
|
207
207
|
static fromSnapshot(snapshot: {
|
|
208
208
|
flags: FlagsBlob;
|
|
209
209
|
experiments: ExpsBlob;
|
|
210
|
-
}):
|
|
210
|
+
}): Engine;
|
|
211
211
|
/**
|
|
212
212
|
* Build a fully OFFLINE client from a snapshot JSON file on disk (Node only —
|
|
213
213
|
* not available in the browser entrypoint). The file must contain
|
|
214
214
|
* `{ "flags": <GET /sdk/flags body>, "experiments": <GET /sdk/experiments body> }`.
|
|
215
|
-
* See {@link
|
|
215
|
+
* See {@link Engine.fromSnapshot}.
|
|
216
216
|
*/
|
|
217
|
-
static fromFile(path: string):
|
|
217
|
+
static fromFile(path: string): Engine;
|
|
218
218
|
init(): Promise<void>;
|
|
219
219
|
initOnce(): Promise<void>;
|
|
220
220
|
/** Force `getFlag(name, …)` to return `value`, ignoring the fetched gate. */
|
|
@@ -298,22 +298,22 @@ declare class FlagsClient {
|
|
|
298
298
|
*
|
|
299
299
|
* ```ts
|
|
300
300
|
* import { OpenFeature } from "@openfeature/server-sdk";
|
|
301
|
-
* import {
|
|
301
|
+
* import { Engine } from "@shipeasy/sdk/server";
|
|
302
302
|
* import { ShipeasyProvider } from "@shipeasy/sdk/openfeature-server";
|
|
303
303
|
*
|
|
304
|
-
* const client = new
|
|
304
|
+
* const client = new Engine({ apiKey: process.env.SHIPEASY_SERVER_KEY! });
|
|
305
305
|
* await OpenFeature.setProviderAndWait(new ShipeasyProvider(client));
|
|
306
306
|
*
|
|
307
307
|
* const ofClient = OpenFeature.getClient();
|
|
308
308
|
* const on = await ofClient.getBooleanValue("new_checkout", false, { targetingKey: "u1" });
|
|
309
309
|
* ```
|
|
310
310
|
*
|
|
311
|
-
* Pure adapter over `
|
|
311
|
+
* Pure adapter over `Engine` — no change to evaluation. `@openfeature/server-sdk`
|
|
312
312
|
* is an optional peer dependency; install it in the consuming app.
|
|
313
313
|
*/
|
|
314
314
|
|
|
315
315
|
/**
|
|
316
|
-
* Shipeasy OpenFeature provider (server paradigm). Wraps
|
|
316
|
+
* Shipeasy OpenFeature provider (server paradigm). Wraps an `Engine`;
|
|
317
317
|
* evaluation is local against the cached blob, so resolution is effectively
|
|
318
318
|
* synchronous (the methods are `async` only to satisfy the server contract).
|
|
319
319
|
*/
|
|
@@ -323,7 +323,7 @@ declare class ShipeasyProvider implements Provider {
|
|
|
323
323
|
readonly name: "shipeasy";
|
|
324
324
|
};
|
|
325
325
|
readonly runsOn: "server";
|
|
326
|
-
constructor(client:
|
|
326
|
+
constructor(client: Engine);
|
|
327
327
|
/** Fetch the rules blob once. The SDK fires `Ready` when this resolves. */
|
|
328
328
|
initialize(): Promise<void>;
|
|
329
329
|
onClose(): Promise<void>;
|
|
@@ -78,7 +78,7 @@ interface StickyEntry {
|
|
|
78
78
|
/**
|
|
79
79
|
* Pluggable sticky-bucketing store for the server (doc 20 §2). Keyed by the
|
|
80
80
|
* bucketing unit; the value is that unit's per-experiment assignments. Absent
|
|
81
|
-
* from {@link
|
|
81
|
+
* from {@link EngineOptions} ⇒ today's deterministic behaviour. Use
|
|
82
82
|
* {@link createInMemoryStickyStore} or a cookie-bridge built from request
|
|
83
83
|
* cookies.
|
|
84
84
|
*/
|
|
@@ -93,7 +93,7 @@ interface Killswitch {
|
|
|
93
93
|
killed: 0 | 1 | boolean;
|
|
94
94
|
switches?: Record<string, 0 | 1 | boolean>;
|
|
95
95
|
}
|
|
96
|
-
/** Body of `GET /sdk/flags` — the snapshot's `flags` field. See {@link
|
|
96
|
+
/** Body of `GET /sdk/flags` — the snapshot's `flags` field. See {@link Engine.fromSnapshot}. */
|
|
97
97
|
interface FlagsBlob {
|
|
98
98
|
version: string;
|
|
99
99
|
plan: string;
|
|
@@ -103,7 +103,7 @@ interface FlagsBlob {
|
|
|
103
103
|
}>;
|
|
104
104
|
killswitches: Record<string, Killswitch>;
|
|
105
105
|
}
|
|
106
|
-
/** Body of `GET /sdk/experiments` — the snapshot's `experiments` field. See {@link
|
|
106
|
+
/** Body of `GET /sdk/experiments` — the snapshot's `experiments` field. See {@link Engine.fromSnapshot}. */
|
|
107
107
|
interface ExpsBlob {
|
|
108
108
|
version: string;
|
|
109
109
|
universes: Record<string, Universe>;
|
|
@@ -115,12 +115,12 @@ interface BootstrapPayload {
|
|
|
115
115
|
experiments: Record<string, ExperimentResult<Record<string, unknown>>>;
|
|
116
116
|
killswitches: Record<string, boolean | Record<string, boolean>>;
|
|
117
117
|
}
|
|
118
|
-
type
|
|
119
|
-
interface
|
|
118
|
+
type EngineEnv = "dev" | "staging" | "prod";
|
|
119
|
+
interface EngineOptions {
|
|
120
120
|
apiKey: string;
|
|
121
121
|
baseUrl?: string;
|
|
122
122
|
/** Which published env to read values from. Defaults to "prod". */
|
|
123
|
-
env?:
|
|
123
|
+
env?: EngineEnv;
|
|
124
124
|
/**
|
|
125
125
|
* Preload the flags blob synchronously without a network fetch. Primarily
|
|
126
126
|
* for tests; production callers should rely on init()/initOnce().
|
|
@@ -155,12 +155,12 @@ interface FlagsClientOptions {
|
|
|
155
155
|
/**
|
|
156
156
|
* Test mode — no network at all. init()/initOnce() are no-ops (never fetch),
|
|
157
157
|
* track() is a no-op, telemetry is forced off, and the client starts
|
|
158
|
-
* "initialized" with an empty blob. Prefer the {@link
|
|
158
|
+
* "initialized" with an empty blob. Prefer the {@link Engine.forTesting}
|
|
159
159
|
* factory over passing this directly.
|
|
160
160
|
*/
|
|
161
161
|
testMode?: boolean;
|
|
162
162
|
}
|
|
163
|
-
declare class
|
|
163
|
+
declare class Engine {
|
|
164
164
|
private readonly apiKey;
|
|
165
165
|
private readonly baseUrl;
|
|
166
166
|
private readonly env;
|
|
@@ -180,7 +180,7 @@ declare class FlagsClient {
|
|
|
180
180
|
private readonly configOverrides;
|
|
181
181
|
private readonly experimentOverrides;
|
|
182
182
|
private readonly changeListeners;
|
|
183
|
-
constructor(opts:
|
|
183
|
+
constructor(opts: EngineOptions);
|
|
184
184
|
/**
|
|
185
185
|
* Build a no-network, immediately-usable client for tests (Statsig-style).
|
|
186
186
|
* init()/initOnce() are no-ops (never fetch), track() is a no-op, telemetry
|
|
@@ -188,12 +188,12 @@ declare class FlagsClient {
|
|
|
188
188
|
* with overrideFlag/overrideConfig/overrideExperiment. No SDK key required.
|
|
189
189
|
*
|
|
190
190
|
* ```ts
|
|
191
|
-
* const client =
|
|
191
|
+
* const client = Engine.forTesting();
|
|
192
192
|
* client.overrideFlag("new_checkout", true);
|
|
193
193
|
* client.getFlag("new_checkout", { user_id: "u1" }); // true
|
|
194
194
|
* ```
|
|
195
195
|
*/
|
|
196
|
-
static forTesting(opts?: Partial<
|
|
196
|
+
static forTesting(opts?: Partial<EngineOptions>): Engine;
|
|
197
197
|
/**
|
|
198
198
|
* Build a fully OFFLINE client from a pre-captured snapshot — no network ever.
|
|
199
199
|
* Reuses the test-mode plumbing (init()/initOnce()/track() are no-ops,
|
|
@@ -207,14 +207,14 @@ declare class FlagsClient {
|
|
|
207
207
|
static fromSnapshot(snapshot: {
|
|
208
208
|
flags: FlagsBlob;
|
|
209
209
|
experiments: ExpsBlob;
|
|
210
|
-
}):
|
|
210
|
+
}): Engine;
|
|
211
211
|
/**
|
|
212
212
|
* Build a fully OFFLINE client from a snapshot JSON file on disk (Node only —
|
|
213
213
|
* not available in the browser entrypoint). The file must contain
|
|
214
214
|
* `{ "flags": <GET /sdk/flags body>, "experiments": <GET /sdk/experiments body> }`.
|
|
215
|
-
* See {@link
|
|
215
|
+
* See {@link Engine.fromSnapshot}.
|
|
216
216
|
*/
|
|
217
|
-
static fromFile(path: string):
|
|
217
|
+
static fromFile(path: string): Engine;
|
|
218
218
|
init(): Promise<void>;
|
|
219
219
|
initOnce(): Promise<void>;
|
|
220
220
|
/** Force `getFlag(name, …)` to return `value`, ignoring the fetched gate. */
|
|
@@ -298,22 +298,22 @@ declare class FlagsClient {
|
|
|
298
298
|
*
|
|
299
299
|
* ```ts
|
|
300
300
|
* import { OpenFeature } from "@openfeature/server-sdk";
|
|
301
|
-
* import {
|
|
301
|
+
* import { Engine } from "@shipeasy/sdk/server";
|
|
302
302
|
* import { ShipeasyProvider } from "@shipeasy/sdk/openfeature-server";
|
|
303
303
|
*
|
|
304
|
-
* const client = new
|
|
304
|
+
* const client = new Engine({ apiKey: process.env.SHIPEASY_SERVER_KEY! });
|
|
305
305
|
* await OpenFeature.setProviderAndWait(new ShipeasyProvider(client));
|
|
306
306
|
*
|
|
307
307
|
* const ofClient = OpenFeature.getClient();
|
|
308
308
|
* const on = await ofClient.getBooleanValue("new_checkout", false, { targetingKey: "u1" });
|
|
309
309
|
* ```
|
|
310
310
|
*
|
|
311
|
-
* Pure adapter over `
|
|
311
|
+
* Pure adapter over `Engine` — no change to evaluation. `@openfeature/server-sdk`
|
|
312
312
|
* is an optional peer dependency; install it in the consuming app.
|
|
313
313
|
*/
|
|
314
314
|
|
|
315
315
|
/**
|
|
316
|
-
* Shipeasy OpenFeature provider (server paradigm). Wraps
|
|
316
|
+
* Shipeasy OpenFeature provider (server paradigm). Wraps an `Engine`;
|
|
317
317
|
* evaluation is local against the cached blob, so resolution is effectively
|
|
318
318
|
* synchronous (the methods are `async` only to satisfy the server contract).
|
|
319
319
|
*/
|
|
@@ -323,7 +323,7 @@ declare class ShipeasyProvider implements Provider {
|
|
|
323
323
|
readonly name: "shipeasy";
|
|
324
324
|
};
|
|
325
325
|
readonly runsOn: "server";
|
|
326
|
-
constructor(client:
|
|
326
|
+
constructor(client: Engine);
|
|
327
327
|
/** Fetch the rules blob once. The SDK fires `Ready` when this resolves. */
|
|
328
328
|
initialize(): Promise<void>;
|
|
329
329
|
onClose(): Promise<void>;
|