@mitralab.io/functions-sdk 0.1.0 → 0.1.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/dist/index.cjs CHANGED
@@ -65,6 +65,11 @@ function requiredValue(value, name) {
65
65
  }
66
66
  return value.trim();
67
67
  }
68
+ function removeTrailingSlashes(value) {
69
+ let end = value.length;
70
+ while (end > 0 && value.charCodeAt(end - 1) === 47) end -= 1;
71
+ return value.slice(0, end);
72
+ }
68
73
  function normalizeApiUrl(value) {
69
74
  let parsed;
70
75
  try {
@@ -80,7 +85,7 @@ function normalizeApiUrl(value) {
80
85
  "apiUrl must not include credentials, query parameters, or a fragment"
81
86
  );
82
87
  }
83
- return parsed.toString().replace(/\/+$/, "");
88
+ return removeTrailingSlashes(parsed.toString());
84
89
  }
85
90
  function resolveConfig(config = {}, environment = readDefaultEnvironment()) {
86
91
  const apiUrl = normalizeApiUrl(
@@ -137,6 +142,45 @@ function redactDetails(value, accessToken) {
137
142
  function optionalString(value) {
138
143
  return typeof value === "string" ? value : void 0;
139
144
  }
145
+ function appendQueryParameters(url, params) {
146
+ for (const [key, value] of Object.entries(params)) {
147
+ if (value === void 0) continue;
148
+ url.searchParams.append(key, typeof value === "string" ? value : value.toString());
149
+ }
150
+ }
151
+ async function parsePayload(response) {
152
+ const text = await response.text();
153
+ try {
154
+ return JSON.parse(text);
155
+ } catch {
156
+ if (response.ok) {
157
+ throw new MitraApiError("The Mitra API returned invalid JSON", response.status, {
158
+ code: "INVALID_RESPONSE",
159
+ retryable: false
160
+ });
161
+ }
162
+ return {};
163
+ }
164
+ }
165
+ function createApiError(response, payload, accessToken) {
166
+ const errorPayload = payload && typeof payload === "object" ? payload : {};
167
+ const rawMessage = optionalString(errorPayload.message);
168
+ const message = redactText(
169
+ rawMessage ?? `Request failed with status ${response.status}`,
170
+ accessToken
171
+ );
172
+ const rawRequestId = optionalString(errorPayload.request_id) ?? optionalString(errorPayload.requestId) ?? response.headers.get("X-Request-Id") ?? void 0;
173
+ const rawCode = optionalString(errorPayload.error_code) ?? optionalString(errorPayload.code);
174
+ const requestId = rawRequestId === void 0 ? void 0 : redactText(rawRequestId, accessToken);
175
+ const code = rawCode === void 0 ? void 0 : redactText(rawCode, accessToken);
176
+ const retryable = typeof errorPayload.retryable === "boolean" ? errorPayload.retryable : response.status >= 500;
177
+ return new MitraApiError(message, response.status, {
178
+ ...code === void 0 ? {} : { code },
179
+ ...errorPayload.details === void 0 ? {} : { details: redactDetails(errorPayload.details, accessToken) },
180
+ ...requestId === void 0 ? {} : { requestId },
181
+ ...retryable === void 0 ? {} : { retryable }
182
+ });
183
+ }
140
184
  var HttpClient = class {
141
185
  #accessToken;
142
186
  baseUrl;
@@ -152,9 +196,7 @@ var HttpClient = class {
152
196
  }
153
197
  async request(path, options = {}) {
154
198
  const url = new URL(`${this.baseUrl}${path}`);
155
- for (const [key, value] of Object.entries(options.params ?? {})) {
156
- if (value !== void 0) url.searchParams.append(key, String(value));
157
- }
199
+ appendQueryParameters(url, options.params ?? {});
158
200
  const controller = new AbortController();
159
201
  const timeout = setTimeout(() => controller.abort(), this.timeoutMs);
160
202
  const hasBody = options.body !== void 0;
@@ -173,38 +215,8 @@ var HttpClient = class {
173
215
  signal: controller.signal
174
216
  });
175
217
  if (response.status === 204) return void 0;
176
- const text = await response.text();
177
- let payload;
178
- try {
179
- payload = JSON.parse(text);
180
- } catch {
181
- if (response.ok) {
182
- throw new MitraApiError("The Mitra API returned invalid JSON", response.status, {
183
- code: "INVALID_RESPONSE",
184
- retryable: false
185
- });
186
- }
187
- payload = {};
188
- }
189
- if (!response.ok) {
190
- const errorPayload = payload && typeof payload === "object" ? payload : {};
191
- const rawMessage = optionalString(errorPayload.message);
192
- const message = redactText(
193
- rawMessage ?? `Request failed with status ${response.status}`,
194
- this.#accessToken
195
- );
196
- const rawRequestId = optionalString(errorPayload.request_id) ?? optionalString(errorPayload.requestId) ?? response.headers.get("X-Request-Id") ?? void 0;
197
- const rawCode = optionalString(errorPayload.error_code) ?? optionalString(errorPayload.code);
198
- const requestId = rawRequestId === void 0 ? void 0 : redactText(rawRequestId, this.#accessToken);
199
- const code = rawCode === void 0 ? void 0 : redactText(rawCode, this.#accessToken);
200
- const retryable = typeof errorPayload.retryable === "boolean" ? errorPayload.retryable : response.status >= 500;
201
- throw new MitraApiError(message, response.status, {
202
- ...code === void 0 ? {} : { code },
203
- ...errorPayload.details === void 0 ? {} : { details: redactDetails(errorPayload.details, this.#accessToken) },
204
- ...requestId === void 0 ? {} : { requestId },
205
- ...retryable === void 0 ? {} : { retryable }
206
- });
207
- }
218
+ const payload = await parsePayload(response);
219
+ if (!response.ok) throw createApiError(response, payload, this.#accessToken);
208
220
  return payload;
209
221
  } catch (error) {
210
222
  if (error instanceof MitraApiError) throw error;
package/dist/index.js CHANGED
@@ -40,6 +40,11 @@ function requiredValue(value, name) {
40
40
  }
41
41
  return value.trim();
42
42
  }
43
+ function removeTrailingSlashes(value) {
44
+ let end = value.length;
45
+ while (end > 0 && value.charCodeAt(end - 1) === 47) end -= 1;
46
+ return value.slice(0, end);
47
+ }
43
48
  function normalizeApiUrl(value) {
44
49
  let parsed;
45
50
  try {
@@ -55,7 +60,7 @@ function normalizeApiUrl(value) {
55
60
  "apiUrl must not include credentials, query parameters, or a fragment"
56
61
  );
57
62
  }
58
- return parsed.toString().replace(/\/+$/, "");
63
+ return removeTrailingSlashes(parsed.toString());
59
64
  }
60
65
  function resolveConfig(config = {}, environment = readDefaultEnvironment()) {
61
66
  const apiUrl = normalizeApiUrl(
@@ -112,6 +117,45 @@ function redactDetails(value, accessToken) {
112
117
  function optionalString(value) {
113
118
  return typeof value === "string" ? value : void 0;
114
119
  }
120
+ function appendQueryParameters(url, params) {
121
+ for (const [key, value] of Object.entries(params)) {
122
+ if (value === void 0) continue;
123
+ url.searchParams.append(key, typeof value === "string" ? value : value.toString());
124
+ }
125
+ }
126
+ async function parsePayload(response) {
127
+ const text = await response.text();
128
+ try {
129
+ return JSON.parse(text);
130
+ } catch {
131
+ if (response.ok) {
132
+ throw new MitraApiError("The Mitra API returned invalid JSON", response.status, {
133
+ code: "INVALID_RESPONSE",
134
+ retryable: false
135
+ });
136
+ }
137
+ return {};
138
+ }
139
+ }
140
+ function createApiError(response, payload, accessToken) {
141
+ const errorPayload = payload && typeof payload === "object" ? payload : {};
142
+ const rawMessage = optionalString(errorPayload.message);
143
+ const message = redactText(
144
+ rawMessage ?? `Request failed with status ${response.status}`,
145
+ accessToken
146
+ );
147
+ const rawRequestId = optionalString(errorPayload.request_id) ?? optionalString(errorPayload.requestId) ?? response.headers.get("X-Request-Id") ?? void 0;
148
+ const rawCode = optionalString(errorPayload.error_code) ?? optionalString(errorPayload.code);
149
+ const requestId = rawRequestId === void 0 ? void 0 : redactText(rawRequestId, accessToken);
150
+ const code = rawCode === void 0 ? void 0 : redactText(rawCode, accessToken);
151
+ const retryable = typeof errorPayload.retryable === "boolean" ? errorPayload.retryable : response.status >= 500;
152
+ return new MitraApiError(message, response.status, {
153
+ ...code === void 0 ? {} : { code },
154
+ ...errorPayload.details === void 0 ? {} : { details: redactDetails(errorPayload.details, accessToken) },
155
+ ...requestId === void 0 ? {} : { requestId },
156
+ ...retryable === void 0 ? {} : { retryable }
157
+ });
158
+ }
115
159
  var HttpClient = class {
116
160
  #accessToken;
117
161
  baseUrl;
@@ -127,9 +171,7 @@ var HttpClient = class {
127
171
  }
128
172
  async request(path, options = {}) {
129
173
  const url = new URL(`${this.baseUrl}${path}`);
130
- for (const [key, value] of Object.entries(options.params ?? {})) {
131
- if (value !== void 0) url.searchParams.append(key, String(value));
132
- }
174
+ appendQueryParameters(url, options.params ?? {});
133
175
  const controller = new AbortController();
134
176
  const timeout = setTimeout(() => controller.abort(), this.timeoutMs);
135
177
  const hasBody = options.body !== void 0;
@@ -148,38 +190,8 @@ var HttpClient = class {
148
190
  signal: controller.signal
149
191
  });
150
192
  if (response.status === 204) return void 0;
151
- const text = await response.text();
152
- let payload;
153
- try {
154
- payload = JSON.parse(text);
155
- } catch {
156
- if (response.ok) {
157
- throw new MitraApiError("The Mitra API returned invalid JSON", response.status, {
158
- code: "INVALID_RESPONSE",
159
- retryable: false
160
- });
161
- }
162
- payload = {};
163
- }
164
- if (!response.ok) {
165
- const errorPayload = payload && typeof payload === "object" ? payload : {};
166
- const rawMessage = optionalString(errorPayload.message);
167
- const message = redactText(
168
- rawMessage ?? `Request failed with status ${response.status}`,
169
- this.#accessToken
170
- );
171
- const rawRequestId = optionalString(errorPayload.request_id) ?? optionalString(errorPayload.requestId) ?? response.headers.get("X-Request-Id") ?? void 0;
172
- const rawCode = optionalString(errorPayload.error_code) ?? optionalString(errorPayload.code);
173
- const requestId = rawRequestId === void 0 ? void 0 : redactText(rawRequestId, this.#accessToken);
174
- const code = rawCode === void 0 ? void 0 : redactText(rawCode, this.#accessToken);
175
- const retryable = typeof errorPayload.retryable === "boolean" ? errorPayload.retryable : response.status >= 500;
176
- throw new MitraApiError(message, response.status, {
177
- ...code === void 0 ? {} : { code },
178
- ...errorPayload.details === void 0 ? {} : { details: redactDetails(errorPayload.details, this.#accessToken) },
179
- ...requestId === void 0 ? {} : { requestId },
180
- ...retryable === void 0 ? {} : { retryable }
181
- });
182
- }
193
+ const payload = await parsePayload(response);
194
+ if (!response.ok) throw createApiError(response, payload, this.#accessToken);
183
195
  return payload;
184
196
  } catch (error) {
185
197
  if (error instanceof MitraApiError) throw error;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mitralab.io/functions-sdk",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "JavaScript and TypeScript SDK for Mitra Server Functions",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -72,11 +72,11 @@
72
72
  "@types/node": "^22.15.0",
73
73
  "@vitest/coverage-v8": "^3.2.4",
74
74
  "eslint": "^9.39.1",
75
- "globals": "^16.5.0",
75
+ "globals": "^17.11.0",
76
76
  "prettier": "^3.8.1",
77
77
  "tsup": "^8.5.1",
78
78
  "typescript": "~5.9.3",
79
- "typescript-eslint": "~8.55.0",
79
+ "typescript-eslint": "~8.67.0",
80
80
  "vite": "~6.4.3",
81
81
  "vitest": "^3.2.4"
82
82
  },