@smplkit/sdk 1.2.6 → 1.3.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/dist/index.cjs +129 -178
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -4
- package/dist/index.d.ts +7 -4
- package/dist/index.js +129 -178
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -55,6 +55,9 @@ __export(index_exports, {
|
|
|
55
55
|
});
|
|
56
56
|
module.exports = __toCommonJS(index_exports);
|
|
57
57
|
|
|
58
|
+
// src/client.ts
|
|
59
|
+
var import_openapi_fetch3 = __toESM(require("openapi-fetch"), 1);
|
|
60
|
+
|
|
58
61
|
// src/config/client.ts
|
|
59
62
|
var import_openapi_fetch = __toESM(require("openapi-fetch"), 1);
|
|
60
63
|
|
|
@@ -721,135 +724,6 @@ var ConfigClient = class {
|
|
|
721
724
|
// src/flags/client.ts
|
|
722
725
|
var import_openapi_fetch2 = __toESM(require("openapi-fetch"), 1);
|
|
723
726
|
|
|
724
|
-
// src/auth.ts
|
|
725
|
-
function buildAuthHeader(apiKey) {
|
|
726
|
-
return `Bearer ${apiKey}`;
|
|
727
|
-
}
|
|
728
|
-
|
|
729
|
-
// src/transport.ts
|
|
730
|
-
var SDK_VERSION = "0.0.0";
|
|
731
|
-
var DEFAULT_TIMEOUT_MS = 3e4;
|
|
732
|
-
var Transport = class {
|
|
733
|
-
apiKey;
|
|
734
|
-
timeout;
|
|
735
|
-
constructor(options) {
|
|
736
|
-
this.apiKey = options.apiKey;
|
|
737
|
-
this.timeout = options.timeout ?? DEFAULT_TIMEOUT_MS;
|
|
738
|
-
}
|
|
739
|
-
/**
|
|
740
|
-
* Send a GET request.
|
|
741
|
-
*
|
|
742
|
-
* @param url - Fully-qualified URL (e.g. `https://config.smplkit.com/api/v1/configs`).
|
|
743
|
-
* @param params - Optional query parameters.
|
|
744
|
-
* @returns Parsed JSON response body.
|
|
745
|
-
*/
|
|
746
|
-
async get(url, params) {
|
|
747
|
-
return this.request("GET", url, void 0, params);
|
|
748
|
-
}
|
|
749
|
-
/**
|
|
750
|
-
* Send a POST request with a JSON body.
|
|
751
|
-
*
|
|
752
|
-
* @param url - Fully-qualified URL.
|
|
753
|
-
* @param body - JSON-serializable request body.
|
|
754
|
-
* @returns Parsed JSON response body.
|
|
755
|
-
*/
|
|
756
|
-
async post(url, body) {
|
|
757
|
-
return this.request("POST", url, body);
|
|
758
|
-
}
|
|
759
|
-
/**
|
|
760
|
-
* Send a PUT request with a JSON body.
|
|
761
|
-
*
|
|
762
|
-
* @param url - Fully-qualified URL.
|
|
763
|
-
* @param body - JSON-serializable request body.
|
|
764
|
-
* @returns Parsed JSON response body.
|
|
765
|
-
*/
|
|
766
|
-
async put(url, body) {
|
|
767
|
-
return this.request("PUT", url, body);
|
|
768
|
-
}
|
|
769
|
-
/**
|
|
770
|
-
* Send a DELETE request.
|
|
771
|
-
*
|
|
772
|
-
* @param url - Fully-qualified URL.
|
|
773
|
-
* @returns Parsed JSON response body (empty object for 204 responses).
|
|
774
|
-
*/
|
|
775
|
-
async delete(url) {
|
|
776
|
-
return this.request("DELETE", url);
|
|
777
|
-
}
|
|
778
|
-
/**
|
|
779
|
-
* Core request method. Handles headers, timeouts, and error mapping.
|
|
780
|
-
*/
|
|
781
|
-
async request(method, url, body, params) {
|
|
782
|
-
if (params) {
|
|
783
|
-
const searchParams = new URLSearchParams(params);
|
|
784
|
-
url += `?${searchParams.toString()}`;
|
|
785
|
-
}
|
|
786
|
-
const headers = {
|
|
787
|
-
Authorization: buildAuthHeader(this.apiKey),
|
|
788
|
-
"User-Agent": `smplkit-typescript-sdk/${SDK_VERSION}`,
|
|
789
|
-
Accept: "application/vnd.api+json"
|
|
790
|
-
};
|
|
791
|
-
if (body !== void 0) {
|
|
792
|
-
headers["Content-Type"] = "application/vnd.api+json";
|
|
793
|
-
}
|
|
794
|
-
const controller = new AbortController();
|
|
795
|
-
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
796
|
-
let response;
|
|
797
|
-
try {
|
|
798
|
-
response = await fetch(url, {
|
|
799
|
-
method,
|
|
800
|
-
headers,
|
|
801
|
-
body: body !== void 0 ? JSON.stringify(body) : void 0,
|
|
802
|
-
signal: controller.signal
|
|
803
|
-
});
|
|
804
|
-
} catch (error) {
|
|
805
|
-
clearTimeout(timeoutId);
|
|
806
|
-
if (error instanceof DOMException && error.name === "AbortError") {
|
|
807
|
-
throw new SmplTimeoutError(`Request timed out after ${this.timeout}ms`);
|
|
808
|
-
}
|
|
809
|
-
if (error instanceof TypeError) {
|
|
810
|
-
throw new SmplConnectionError(`Network error: ${error.message}`);
|
|
811
|
-
}
|
|
812
|
-
throw new SmplConnectionError(
|
|
813
|
-
`Request failed: ${error instanceof Error ? error.message : String(error)}`
|
|
814
|
-
);
|
|
815
|
-
} finally {
|
|
816
|
-
clearTimeout(timeoutId);
|
|
817
|
-
}
|
|
818
|
-
if (response.status === 204) {
|
|
819
|
-
return {};
|
|
820
|
-
}
|
|
821
|
-
const responseText = await response.text();
|
|
822
|
-
if (!response.ok) {
|
|
823
|
-
this.throwForStatus(response.status, responseText);
|
|
824
|
-
}
|
|
825
|
-
try {
|
|
826
|
-
return JSON.parse(responseText);
|
|
827
|
-
} catch {
|
|
828
|
-
throw new SmplError(`Invalid JSON response: ${responseText}`, response.status, responseText);
|
|
829
|
-
}
|
|
830
|
-
}
|
|
831
|
-
/**
|
|
832
|
-
* Map HTTP error status codes to typed SDK exceptions.
|
|
833
|
-
*
|
|
834
|
-
* @throws {SmplNotFoundError} On 404.
|
|
835
|
-
* @throws {SmplConflictError} On 409.
|
|
836
|
-
* @throws {SmplValidationError} On 422.
|
|
837
|
-
* @throws {SmplError} On any other non-2xx status.
|
|
838
|
-
*/
|
|
839
|
-
throwForStatus(status, body) {
|
|
840
|
-
switch (status) {
|
|
841
|
-
case 404:
|
|
842
|
-
throw new SmplNotFoundError(body, 404, body);
|
|
843
|
-
case 409:
|
|
844
|
-
throw new SmplConflictError(body, 409, body);
|
|
845
|
-
case 422:
|
|
846
|
-
throw new SmplValidationError(body, 422, body);
|
|
847
|
-
default:
|
|
848
|
-
throw new SmplError(`HTTP ${status}: ${body}`, status, body);
|
|
849
|
-
}
|
|
850
|
-
}
|
|
851
|
-
};
|
|
852
|
-
|
|
853
727
|
// src/flags/models.ts
|
|
854
728
|
var Flag = class {
|
|
855
729
|
/** UUID of the flag. */
|
|
@@ -1201,8 +1075,8 @@ var ContextRegistrationBuffer = class {
|
|
|
1201
1075
|
}
|
|
1202
1076
|
this._seen.set(cacheKey, ctx.attributes);
|
|
1203
1077
|
this._pending.push({
|
|
1204
|
-
|
|
1205
|
-
|
|
1078
|
+
type: ctx.type,
|
|
1079
|
+
key: ctx.key,
|
|
1206
1080
|
attributes: { ...ctx.attributes }
|
|
1207
1081
|
});
|
|
1208
1082
|
}
|
|
@@ -1225,7 +1099,7 @@ var FlagsClient = class {
|
|
|
1225
1099
|
/** @internal */
|
|
1226
1100
|
_http;
|
|
1227
1101
|
/** @internal */
|
|
1228
|
-
|
|
1102
|
+
_appHttp;
|
|
1229
1103
|
// Runtime state
|
|
1230
1104
|
_environment = null;
|
|
1231
1105
|
_flagStore = {};
|
|
@@ -1245,28 +1119,36 @@ var FlagsClient = class {
|
|
|
1245
1119
|
this._apiKey = apiKey;
|
|
1246
1120
|
this._ensureWs = ensureWs;
|
|
1247
1121
|
const ms = timeout ?? 3e4;
|
|
1122
|
+
const fetchWithTimeout = async (request) => {
|
|
1123
|
+
const controller = new AbortController();
|
|
1124
|
+
const timer = setTimeout(() => controller.abort(), ms);
|
|
1125
|
+
try {
|
|
1126
|
+
return await fetch(new Request(request, { signal: controller.signal }));
|
|
1127
|
+
} catch (err) {
|
|
1128
|
+
if (err instanceof DOMException && err.name === "AbortError") {
|
|
1129
|
+
throw new SmplTimeoutError(`Request timed out after ${ms}ms`);
|
|
1130
|
+
}
|
|
1131
|
+
throw err;
|
|
1132
|
+
} finally {
|
|
1133
|
+
clearTimeout(timer);
|
|
1134
|
+
}
|
|
1135
|
+
};
|
|
1248
1136
|
this._http = (0, import_openapi_fetch2.default)({
|
|
1249
1137
|
baseUrl: FLAGS_BASE_URL,
|
|
1250
1138
|
headers: {
|
|
1251
1139
|
Authorization: `Bearer ${apiKey}`,
|
|
1252
1140
|
Accept: "application/json"
|
|
1253
1141
|
},
|
|
1254
|
-
fetch:
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
throw err;
|
|
1264
|
-
} finally {
|
|
1265
|
-
clearTimeout(timer);
|
|
1266
|
-
}
|
|
1267
|
-
}
|
|
1142
|
+
fetch: fetchWithTimeout
|
|
1143
|
+
});
|
|
1144
|
+
this._appHttp = (0, import_openapi_fetch2.default)({
|
|
1145
|
+
baseUrl: APP_BASE_URL,
|
|
1146
|
+
headers: {
|
|
1147
|
+
Authorization: `Bearer ${apiKey}`,
|
|
1148
|
+
Accept: "application/json"
|
|
1149
|
+
},
|
|
1150
|
+
fetch: fetchWithTimeout
|
|
1268
1151
|
});
|
|
1269
|
-
this._transport = new Transport({ apiKey, timeout: ms });
|
|
1270
1152
|
}
|
|
1271
1153
|
// ------------------------------------------------------------------
|
|
1272
1154
|
// Management methods
|
|
@@ -1381,40 +1263,87 @@ var FlagsClient = class {
|
|
|
1381
1263
|
return this._resourceToModel(data.data);
|
|
1382
1264
|
}
|
|
1383
1265
|
// ------------------------------------------------------------------
|
|
1384
|
-
// Context type management (
|
|
1266
|
+
// Context type management (via generated app client)
|
|
1385
1267
|
// ------------------------------------------------------------------
|
|
1386
1268
|
/** Create a context type. */
|
|
1387
1269
|
async createContextType(key, options) {
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1270
|
+
let data;
|
|
1271
|
+
try {
|
|
1272
|
+
const result = await this._appHttp.POST("/api/v1/context_types", {
|
|
1273
|
+
body: {
|
|
1274
|
+
data: { type: "context_type", attributes: { key, name: options.name } }
|
|
1275
|
+
}
|
|
1276
|
+
});
|
|
1277
|
+
if (result.error !== void 0)
|
|
1278
|
+
await checkError2(result.response, "Failed to create context type");
|
|
1279
|
+
data = result.data;
|
|
1280
|
+
} catch (err) {
|
|
1281
|
+
wrapFetchError2(err);
|
|
1282
|
+
}
|
|
1283
|
+
if (!data || !data.data) throw new SmplValidationError("Failed to create context type");
|
|
1284
|
+
return this._parseContextType(data.data);
|
|
1393
1285
|
}
|
|
1394
1286
|
/** Update a context type (merge attributes). */
|
|
1395
1287
|
async updateContextType(ctId, options) {
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1288
|
+
let data;
|
|
1289
|
+
try {
|
|
1290
|
+
const result = await this._appHttp.PUT("/api/v1/context_types/{id}", {
|
|
1291
|
+
params: { path: { id: ctId } },
|
|
1292
|
+
body: {
|
|
1293
|
+
data: {
|
|
1294
|
+
type: "context_type",
|
|
1295
|
+
attributes: { key: options.key, name: options.name, attributes: options.attributes }
|
|
1296
|
+
}
|
|
1297
|
+
}
|
|
1298
|
+
});
|
|
1299
|
+
if (result.error !== void 0)
|
|
1300
|
+
await checkError2(result.response, `Failed to update context type ${ctId}`);
|
|
1301
|
+
data = result.data;
|
|
1302
|
+
} catch (err) {
|
|
1303
|
+
wrapFetchError2(err);
|
|
1304
|
+
}
|
|
1305
|
+
if (!data || !data.data) throw new SmplValidationError(`Failed to update context type ${ctId}`);
|
|
1306
|
+
return this._parseContextType(data.data);
|
|
1401
1307
|
}
|
|
1402
1308
|
/** List all context types. */
|
|
1403
1309
|
async listContextTypes() {
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1310
|
+
let data;
|
|
1311
|
+
try {
|
|
1312
|
+
const result = await this._appHttp.GET("/api/v1/context_types");
|
|
1313
|
+
if (result.error !== void 0)
|
|
1314
|
+
await checkError2(result.response, "Failed to list context types");
|
|
1315
|
+
data = result.data;
|
|
1316
|
+
} catch (err) {
|
|
1317
|
+
wrapFetchError2(err);
|
|
1318
|
+
}
|
|
1319
|
+
if (!data || !data.data) throw new SmplValidationError("Failed to list context types");
|
|
1320
|
+
return data.data.map((item) => this._parseContextType(item));
|
|
1407
1321
|
}
|
|
1408
1322
|
/** Delete a context type. */
|
|
1409
1323
|
async deleteContextType(ctId) {
|
|
1410
|
-
|
|
1324
|
+
try {
|
|
1325
|
+
const result = await this._appHttp.DELETE("/api/v1/context_types/{id}", {
|
|
1326
|
+
params: { path: { id: ctId } }
|
|
1327
|
+
});
|
|
1328
|
+
if (result.error !== void 0 && result.response.status !== 204)
|
|
1329
|
+
await checkError2(result.response, `Failed to delete context type ${ctId}`);
|
|
1330
|
+
} catch (err) {
|
|
1331
|
+
wrapFetchError2(err);
|
|
1332
|
+
}
|
|
1411
1333
|
}
|
|
1412
1334
|
/** List context instances filtered by context type key. */
|
|
1413
1335
|
async listContexts(options) {
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1336
|
+
let data;
|
|
1337
|
+
try {
|
|
1338
|
+
const result = await this._appHttp.GET("/api/v1/contexts", {
|
|
1339
|
+
params: { query: { "filter[context_type_id]": options.contextTypeKey } }
|
|
1340
|
+
});
|
|
1341
|
+
if (result.error !== void 0) await checkError2(result.response, "Failed to list contexts");
|
|
1342
|
+
data = result.data;
|
|
1343
|
+
} catch (err) {
|
|
1344
|
+
wrapFetchError2(err);
|
|
1345
|
+
}
|
|
1346
|
+
return data?.data ?? [];
|
|
1418
1347
|
}
|
|
1419
1348
|
// ------------------------------------------------------------------
|
|
1420
1349
|
// Runtime: typed flag handles
|
|
@@ -1704,8 +1633,13 @@ var FlagsClient = class {
|
|
|
1704
1633
|
const batch = this._contextBuffer.drain();
|
|
1705
1634
|
if (batch.length === 0) return;
|
|
1706
1635
|
try {
|
|
1707
|
-
await this.
|
|
1708
|
-
|
|
1636
|
+
await this._appHttp.POST("/api/v1/contexts/bulk", {
|
|
1637
|
+
body: {
|
|
1638
|
+
contexts: batch.map((ctx) => ({
|
|
1639
|
+
id: `${ctx.type}:${ctx.key}`,
|
|
1640
|
+
attributes: ctx.attributes
|
|
1641
|
+
}))
|
|
1642
|
+
}
|
|
1709
1643
|
});
|
|
1710
1644
|
} catch {
|
|
1711
1645
|
}
|
|
@@ -1951,6 +1885,7 @@ var SmplClient = class {
|
|
|
1951
1885
|
_service;
|
|
1952
1886
|
_connected = false;
|
|
1953
1887
|
_timeout;
|
|
1888
|
+
_appHttp;
|
|
1954
1889
|
constructor(options = {}) {
|
|
1955
1890
|
const apiKey = resolveApiKey(options.apiKey);
|
|
1956
1891
|
this._apiKey = apiKey;
|
|
@@ -1961,6 +1896,28 @@ var SmplClient = class {
|
|
|
1961
1896
|
this._environment = environment;
|
|
1962
1897
|
this._service = options.service || process.env.SMPLKIT_SERVICE || null;
|
|
1963
1898
|
this._timeout = options.timeout ?? 3e4;
|
|
1899
|
+
const ms = this._timeout;
|
|
1900
|
+
this._appHttp = (0, import_openapi_fetch3.default)({
|
|
1901
|
+
baseUrl: APP_BASE_URL2,
|
|
1902
|
+
headers: {
|
|
1903
|
+
Authorization: `Bearer ${apiKey}`,
|
|
1904
|
+
Accept: "application/json"
|
|
1905
|
+
},
|
|
1906
|
+
fetch: async (request) => {
|
|
1907
|
+
const controller = new AbortController();
|
|
1908
|
+
const timer = setTimeout(() => controller.abort(), ms);
|
|
1909
|
+
try {
|
|
1910
|
+
return await fetch(new Request(request, { signal: controller.signal }));
|
|
1911
|
+
} catch (err) {
|
|
1912
|
+
if (err instanceof DOMException && err.name === "AbortError") {
|
|
1913
|
+
throw new SmplTimeoutError(`Request timed out after ${ms}ms`);
|
|
1914
|
+
}
|
|
1915
|
+
throw err;
|
|
1916
|
+
} finally {
|
|
1917
|
+
clearTimeout(timer);
|
|
1918
|
+
}
|
|
1919
|
+
}
|
|
1920
|
+
});
|
|
1964
1921
|
this.config = new ConfigClient(apiKey, this._timeout);
|
|
1965
1922
|
this.flags = new FlagsClient(apiKey, () => this._ensureWs(), this._timeout);
|
|
1966
1923
|
this.config._getSharedWs = () => this._ensureWs();
|
|
@@ -1987,21 +1944,15 @@ var SmplClient = class {
|
|
|
1987
1944
|
/** @internal */
|
|
1988
1945
|
async _registerServiceContext() {
|
|
1989
1946
|
try {
|
|
1990
|
-
await
|
|
1991
|
-
|
|
1992
|
-
headers: {
|
|
1993
|
-
Authorization: `Bearer ${this._apiKey}`,
|
|
1994
|
-
"Content-Type": "application/json"
|
|
1995
|
-
},
|
|
1996
|
-
body: JSON.stringify({
|
|
1947
|
+
await this._appHttp.POST("/api/v1/contexts/bulk", {
|
|
1948
|
+
body: {
|
|
1997
1949
|
contexts: [
|
|
1998
1950
|
{
|
|
1999
|
-
|
|
2000
|
-
key: this._service,
|
|
1951
|
+
id: `service:${this._service}`,
|
|
2001
1952
|
attributes: { name: this._service }
|
|
2002
1953
|
}
|
|
2003
1954
|
]
|
|
2004
|
-
}
|
|
1955
|
+
}
|
|
2005
1956
|
});
|
|
2006
1957
|
} catch {
|
|
2007
1958
|
}
|