@smplkit/sdk 1.3.6 → 1.3.7

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
@@ -67,38 +67,54 @@ var SmplError = class extends Error {
67
67
  statusCode;
68
68
  /** The raw response body, if available. */
69
69
  responseBody;
70
- constructor(message, statusCode, responseBody) {
70
+ /** Structured JSON:API error objects from the server response, if available. */
71
+ errors;
72
+ constructor(message, statusCode, responseBody, errors) {
71
73
  super(message);
72
74
  this.name = "SmplError";
73
75
  this.statusCode = statusCode;
74
76
  this.responseBody = responseBody;
77
+ this.errors = errors ?? [];
75
78
  Object.setPrototypeOf(this, new.target.prototype);
76
79
  }
80
+ toString() {
81
+ if (this.errors.length === 0) {
82
+ return `${this.name}: ${this.message}`;
83
+ }
84
+ if (this.errors.length === 1) {
85
+ return `${this.name}: ${this.message}
86
+ Error: ${JSON.stringify(this.errors[0])}`;
87
+ }
88
+ const lines = this.errors.map((e, i) => ` [${i}] ${JSON.stringify(e)}`);
89
+ return `${this.name}: ${this.message}
90
+ Errors:
91
+ ${lines.join("\n")}`;
92
+ }
77
93
  };
78
94
  var SmplConnectionError = class extends SmplError {
79
- constructor(message, statusCode, responseBody) {
80
- super(message, statusCode, responseBody);
95
+ constructor(message, statusCode, responseBody, errors) {
96
+ super(message, statusCode, responseBody, errors);
81
97
  this.name = "SmplConnectionError";
82
98
  Object.setPrototypeOf(this, new.target.prototype);
83
99
  }
84
100
  };
85
101
  var SmplTimeoutError = class extends SmplError {
86
- constructor(message, statusCode, responseBody) {
87
- super(message, statusCode, responseBody);
102
+ constructor(message, statusCode, responseBody, errors) {
103
+ super(message, statusCode, responseBody, errors);
88
104
  this.name = "SmplTimeoutError";
89
105
  Object.setPrototypeOf(this, new.target.prototype);
90
106
  }
91
107
  };
92
108
  var SmplNotFoundError = class extends SmplError {
93
- constructor(message, statusCode, responseBody) {
94
- super(message, statusCode ?? 404, responseBody);
109
+ constructor(message, statusCode, responseBody, errors) {
110
+ super(message, statusCode ?? 404, responseBody, errors);
95
111
  this.name = "SmplNotFoundError";
96
112
  Object.setPrototypeOf(this, new.target.prototype);
97
113
  }
98
114
  };
99
115
  var SmplConflictError = class extends SmplError {
100
- constructor(message, statusCode, responseBody) {
101
- super(message, statusCode ?? 409, responseBody);
116
+ constructor(message, statusCode, responseBody, errors) {
117
+ super(message, statusCode ?? 409, responseBody, errors);
102
118
  this.name = "SmplConflictError";
103
119
  Object.setPrototypeOf(this, new.target.prototype);
104
120
  }
@@ -111,12 +127,53 @@ var SmplNotConnectedError = class extends SmplError {
111
127
  }
112
128
  };
113
129
  var SmplValidationError = class extends SmplError {
114
- constructor(message, statusCode, responseBody) {
115
- super(message, statusCode ?? 422, responseBody);
130
+ constructor(message, statusCode, responseBody, errors) {
131
+ super(message, statusCode ?? 422, responseBody, errors);
116
132
  this.name = "SmplValidationError";
117
133
  Object.setPrototypeOf(this, new.target.prototype);
118
134
  }
119
135
  };
136
+ function parseJsonApiErrors(body) {
137
+ try {
138
+ const parsed = JSON.parse(body);
139
+ if (parsed && Array.isArray(parsed.errors)) {
140
+ return parsed.errors.map((e) => ({
141
+ ...e.status !== void 0 ? { status: String(e.status) } : {},
142
+ ...e.title !== void 0 ? { title: String(e.title) } : {},
143
+ ...e.detail !== void 0 ? { detail: String(e.detail) } : {},
144
+ ...e.source !== void 0 && typeof e.source === "object" && e.source !== null ? { source: e.source } : {}
145
+ }));
146
+ }
147
+ } catch {
148
+ }
149
+ return [];
150
+ }
151
+ function deriveMessage(errors, statusCode, body) {
152
+ if (errors.length === 0) {
153
+ return body ? `HTTP ${statusCode}: ${body}` : `HTTP ${statusCode}`;
154
+ }
155
+ const first = errors[0];
156
+ const base = first.detail ?? first.title ?? (first.status ? `HTTP ${first.status}` : `HTTP ${statusCode}`);
157
+ if (errors.length > 1) {
158
+ return `${base} (and ${errors.length - 1} more error${errors.length - 1 > 1 ? "s" : ""})`;
159
+ }
160
+ return base;
161
+ }
162
+ function throwForStatus(statusCode, body) {
163
+ const errors = parseJsonApiErrors(body);
164
+ const message = deriveMessage(errors, statusCode, body);
165
+ switch (statusCode) {
166
+ case 400:
167
+ case 422:
168
+ throw new SmplValidationError(message, statusCode, body, errors);
169
+ case 404:
170
+ throw new SmplNotFoundError(message, statusCode, body, errors);
171
+ case 409:
172
+ throw new SmplConflictError(message, statusCode, body, errors);
173
+ default:
174
+ throw new SmplError(message, statusCode, body, errors);
175
+ }
176
+ }
120
177
 
121
178
  // src/config/resolve.ts
122
179
  function deepMerge(base, override) {
@@ -337,18 +394,9 @@ function resourceToConfig(resource, client) {
337
394
  updatedAt: attrs.updated_at ? new Date(attrs.updated_at) : null
338
395
  });
339
396
  }
340
- async function checkError(response, context) {
397
+ async function checkError(response, _context) {
341
398
  const body = await response.text().catch(() => "");
342
- switch (response.status) {
343
- case 404:
344
- throw new SmplNotFoundError(body || context, 404, body);
345
- case 409:
346
- throw new SmplConflictError(body || context, 409, body);
347
- case 422:
348
- throw new SmplValidationError(body || context, 422, body);
349
- default:
350
- throw new SmplError(`HTTP ${response.status}: ${body}`, response.status, body);
351
- }
399
+ throwForStatus(response.status, body);
352
400
  }
353
401
  function wrapFetchError(err) {
354
402
  if (err instanceof SmplNotFoundError || err instanceof SmplConflictError || err instanceof SmplValidationError || err instanceof SmplError) {
@@ -851,18 +899,9 @@ var APP_BASE_URL = "https://app.smplkit.com";
851
899
  var CACHE_MAX_SIZE = 1e4;
852
900
  var CONTEXT_REGISTRATION_LRU_SIZE = 1e4;
853
901
  var CONTEXT_BATCH_FLUSH_SIZE = 100;
854
- async function checkError2(response, context) {
902
+ async function checkError2(response, _context) {
855
903
  const body = await response.text().catch(() => "");
856
- switch (response.status) {
857
- case 404:
858
- throw new SmplNotFoundError(body || context, 404, body);
859
- case 409:
860
- throw new SmplConflictError(body || context, 409, body);
861
- case 422:
862
- throw new SmplValidationError(body || context, 422, body);
863
- default:
864
- throw new SmplError(`HTTP ${response.status}: ${body}`, response.status, body);
865
- }
904
+ throwForStatus(response.status, body);
866
905
  }
867
906
  function wrapFetchError2(err) {
868
907
  if (err instanceof SmplNotFoundError || err instanceof SmplConflictError || err instanceof SmplValidationError || err instanceof SmplError) {
@@ -1841,38 +1880,61 @@ var SharedWebSocket = class {
1841
1880
  var import_node_fs = require("fs");
1842
1881
  var import_node_os = require("os");
1843
1882
  var import_node_path = require("path");
1844
- var NO_API_KEY_MESSAGE = "No API key provided. Set one of:\n 1. Pass apiKey to the constructor\n 2. Set the SMPLKIT_API_KEY environment variable\n 3. Create a ~/.smplkit file with:\n [default]\n api_key = your_key_here";
1845
- function resolveApiKey(explicit) {
1846
- if (explicit) return explicit;
1847
- const envVal = process.env.SMPLKIT_API_KEY;
1848
- if (envVal) return envVal;
1883
+ function noApiKeyMessage(environment) {
1884
+ return `No API key provided. Set one of:
1885
+ 1. Pass apiKey to the constructor
1886
+ 2. Set the SMPLKIT_API_KEY environment variable
1887
+ 3. Create a ~/.smplkit file with:
1888
+ [${environment}]
1889
+ api_key = your_key_here`;
1890
+ }
1891
+ function readApiKeyFromConfig(environment) {
1849
1892
  const configPath = (0, import_node_path.join)((0, import_node_os.homedir)(), ".smplkit");
1850
1893
  try {
1851
1894
  const content = (0, import_node_fs.readFileSync)(configPath, "utf-8");
1852
- let inDefaultSection = false;
1895
+ let currentSection = null;
1896
+ let envKey;
1897
+ let defaultKey;
1853
1898
  for (const line of content.split("\n")) {
1854
1899
  const trimmed = line.trim();
1855
1900
  if (trimmed === "" || trimmed.startsWith("#")) continue;
1856
1901
  if (trimmed.startsWith("[")) {
1857
- inDefaultSection = trimmed.toLowerCase() === "[default]";
1902
+ const sectionName = trimmed.slice(1, trimmed.indexOf("]")).toLowerCase();
1903
+ currentSection = sectionName;
1858
1904
  continue;
1859
1905
  }
1860
- if (inDefaultSection && trimmed.startsWith("api_key")) {
1906
+ if (currentSection && trimmed.startsWith("api_key")) {
1861
1907
  const eqIndex = trimmed.indexOf("=");
1862
1908
  if (eqIndex !== -1) {
1863
1909
  const value = trimmed.slice(eqIndex + 1).trim();
1864
- if (value) return value;
1910
+ if (value) {
1911
+ if (currentSection === environment.toLowerCase()) {
1912
+ envKey = value;
1913
+ } else if (currentSection === "default") {
1914
+ defaultKey = value;
1915
+ }
1916
+ }
1865
1917
  }
1866
1918
  }
1867
1919
  }
1920
+ return envKey ?? defaultKey;
1868
1921
  } catch {
1922
+ return void 0;
1869
1923
  }
1870
- throw new SmplError(NO_API_KEY_MESSAGE);
1924
+ }
1925
+ function resolveApiKey(explicit, environment) {
1926
+ if (explicit) return explicit;
1927
+ const envVal = process.env.SMPLKIT_API_KEY;
1928
+ if (envVal) return envVal;
1929
+ const fileKey = readApiKeyFromConfig(environment);
1930
+ if (fileKey) return fileKey;
1931
+ throw new SmplError(noApiKeyMessage(environment));
1871
1932
  }
1872
1933
 
1873
1934
  // src/client.ts
1874
1935
  var APP_BASE_URL2 = "https://app.smplkit.com";
1875
1936
  var NO_ENVIRONMENT_MESSAGE = "No environment provided. Set one of:\n 1. Pass environment to the constructor\n 2. Set the SMPLKIT_ENVIRONMENT environment variable";
1937
+ var NO_SERVICE_MESSAGE = "No service provided. Set one of:\n 1. Pass service in options\n 2. Set the SMPLKIT_SERVICE environment variable";
1876
1938
  var SmplClient = class {
1877
1939
  /** Client for config management-plane operations. */
1878
1940
  config;
@@ -1888,14 +1950,18 @@ var SmplClient = class {
1888
1950
  _timeout;
1889
1951
  _appHttp;
1890
1952
  constructor(options = {}) {
1891
- const apiKey = resolveApiKey(options.apiKey);
1892
- this._apiKey = apiKey;
1893
1953
  const environment = options.environment || process.env.SMPLKIT_ENVIRONMENT;
1894
1954
  if (!environment) {
1895
1955
  throw new SmplError(NO_ENVIRONMENT_MESSAGE);
1896
1956
  }
1897
1957
  this._environment = environment;
1898
- this._service = options.service || process.env.SMPLKIT_SERVICE || null;
1958
+ const service = options.service || process.env.SMPLKIT_SERVICE;
1959
+ if (!service) {
1960
+ throw new SmplError(NO_SERVICE_MESSAGE);
1961
+ }
1962
+ this._service = service;
1963
+ const apiKey = resolveApiKey(options.apiKey, environment);
1964
+ this._apiKey = apiKey;
1899
1965
  this._timeout = options.timeout ?? 3e4;
1900
1966
  const ms = this._timeout;
1901
1967
  this._appHttp = (0, import_openapi_fetch3.default)({
@@ -1935,9 +2001,7 @@ var SmplClient = class {
1935
2001
  */
1936
2002
  async connect() {
1937
2003
  if (this._connected) return;
1938
- if (this._service) {
1939
- await this._registerServiceContext();
1940
- }
2004
+ await this._registerServiceContext();
1941
2005
  await this.flags._connectInternal(this._environment);
1942
2006
  await this.config._connectInternal(this._environment);
1943
2007
  this._connected = true;