@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 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
- id: `${ctx.type}:${ctx.key}`,
1205
- name: ctx.name ?? ctx.key,
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
- _transport;
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: async (request) => {
1255
- const controller = new AbortController();
1256
- const timer = setTimeout(() => controller.abort(), ms);
1257
- try {
1258
- return await fetch(new Request(request, { signal: controller.signal }));
1259
- } catch (err) {
1260
- if (err instanceof DOMException && err.name === "AbortError") {
1261
- throw new SmplTimeoutError(`Request timed out after ${ms}ms`);
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 (direct HTTP not in generated spec)
1266
+ // Context type management (via generated app client)
1385
1267
  // ------------------------------------------------------------------
1386
1268
  /** Create a context type. */
1387
1269
  async createContextType(key, options) {
1388
- const resp = await this._transport.post(`${APP_BASE_URL}/api/v1/context_types`, {
1389
- data: { type: "context_type", attributes: { key, name: options.name } }
1390
- });
1391
- const data = resp.data ?? {};
1392
- return this._parseContextType(data);
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
- const resp = await this._transport.put(`${APP_BASE_URL}/api/v1/context_types/${ctId}`, {
1397
- data: { type: "context_type", attributes: { attributes: options.attributes } }
1398
- });
1399
- const data = resp.data ?? {};
1400
- return this._parseContextType(data);
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
- const resp = await this._transport.get(`${APP_BASE_URL}/api/v1/context_types`);
1405
- const items = resp.data ?? [];
1406
- return items.map((item) => this._parseContextType(item));
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
- await this._transport.delete(`${APP_BASE_URL}/api/v1/context_types/${ctId}`);
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
- const resp = await this._transport.get(`${APP_BASE_URL}/api/v1/contexts`, {
1415
- "filter[context_type]": options.contextTypeKey
1416
- });
1417
- return resp.data ?? [];
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._transport.post(`${APP_BASE_URL}/api/v1/contexts/bulk`, {
1708
- contexts: batch
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 fetch(`${APP_BASE_URL2}/api/v1/contexts/bulk`, {
1991
- method: "PUT",
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
- type: "service",
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
  }