@frogfish/k2db-api 1.0.10 → 1.0.11

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.d.ts CHANGED
@@ -5,12 +5,29 @@ interface K2ClientOptions {
5
5
  apiKey?: string;
6
6
  fetch?: typeof fetch;
7
7
  headers?: Record<string, string>;
8
+ /**
9
+ * Default TTL (ms) for cacheable, read-only requests.
10
+ * Set to 0 to disable client-side caching globally.
11
+ * @default 60000
12
+ */
13
+ readCacheTtlMs?: number;
14
+ /**
15
+ * Maximum number of concurrent in-flight HTTP requests.
16
+ * 0 or undefined means unlimited.
17
+ */
18
+ maxConcurrentRequests?: number;
8
19
  }
9
20
  interface RequestOptions {
10
21
  apiKey?: string;
11
22
  scope?: string;
12
23
  headers?: Record<string, string>;
13
24
  signal?: AbortSignal;
25
+ /**
26
+ * Per-request cache TTL override (ms). Only applies to cacheable read requests.
27
+ * - undefined: use client default
28
+ * - 0: disable caching for this request
29
+ */
30
+ cacheTtlMs?: number;
14
31
  }
15
32
  interface CreateResult {
16
33
  id: string;
@@ -74,11 +91,6 @@ interface ReadyNotOk {
74
91
  interface HealthOk {
75
92
  status: 'ok';
76
93
  }
77
- declare class K2ApiError extends Error {
78
- status: number;
79
- body: unknown;
80
- constructor(message: string, status: number, body: unknown);
81
- }
82
94
  interface ProblemDetailsPayload {
83
95
  type?: string;
84
96
  title?: string;
@@ -98,6 +110,12 @@ declare class K2DbApiClient {
98
110
  private apiKey;
99
111
  private fetchImpl;
100
112
  private defaultHeaders;
113
+ private readonly readCacheTtlMs;
114
+ private readonly inflight;
115
+ private readonly cache;
116
+ private readonly maxConcurrentRequests;
117
+ private activeRequests;
118
+ private readonly waiters;
101
119
  constructor(options: K2ClientOptions);
102
120
  health(options?: RequestOptions): Promise<HealthOk>;
103
121
  ready(options?: RequestOptions): Promise<ReadyOk | ReadyNotOk>;
@@ -124,6 +142,14 @@ declare class K2DbApiClient {
124
142
  adminCreateHistoryIndexes(collection: string, payload?: Record<string, unknown>, options?: RequestOptions): Promise<{
125
143
  message: string;
126
144
  }>;
145
+ private serviceErrorFromHttpStatus;
146
+ private invalidateCache;
147
+ private isCacheableRead;
148
+ private stableStringify;
149
+ private fnv1a64;
150
+ private requestSignature;
151
+ private acquireRequestSlot;
152
+ private releaseRequestSlot;
127
153
  private request;
128
154
  private tryRehydrateK2Error;
129
155
  private parseServiceError;
@@ -131,4 +157,4 @@ declare class K2DbApiClient {
131
157
  private buildHeaders;
132
158
  }
133
159
 
134
- export { type AggregateRequest, type BulkUpdateRequest, type CountRequest, type CountResult, type CreateResult, type ErrorChainItem, type HealthOk, type IndexRequest, K2ApiError, type K2ClientOptions, K2DbApiClient, type ProblemDetailsPayload, type ReadyNotOk, type ReadyOk, type RequestOptions, type RestoreRequest, type RestoreResult, type SearchRequest, type UpdateResult, type VersionInfo, type VersionedUpdateRequest, type VersionedUpdateResult };
160
+ export { type AggregateRequest, type BulkUpdateRequest, type CountRequest, type CountResult, type CreateResult, type ErrorChainItem, type HealthOk, type IndexRequest, type K2ClientOptions, K2DbApiClient, type ProblemDetailsPayload, type ReadyNotOk, type ReadyOk, type RequestOptions, type RestoreRequest, type RestoreResult, type SearchRequest, type UpdateResult, type VersionInfo, type VersionedUpdateRequest, type VersionedUpdateResult };
package/dist/index.js CHANGED
@@ -1,25 +1,25 @@
1
1
  // src/k2db-client.ts
2
2
  import { K2Error, ServiceError } from "@frogfish/k2error";
3
- var K2ApiError = class extends Error {
4
- status;
5
- body;
6
- constructor(message, status, body) {
7
- super(message);
8
- this.name = "K2ApiError";
9
- this.status = status;
10
- this.body = body;
11
- }
12
- };
13
3
  var K2DbApiClient = class {
14
4
  baseUrl;
15
5
  apiKey;
16
6
  fetchImpl;
17
7
  defaultHeaders;
8
+ readCacheTtlMs;
9
+ // Read-only request memoization + in-flight collapse (Angular-proofing)
10
+ inflight = /* @__PURE__ */ new Map();
11
+ cache = /* @__PURE__ */ new Map();
12
+ // Optional global concurrency limiter
13
+ maxConcurrentRequests;
14
+ activeRequests = 0;
15
+ waiters = [];
18
16
  constructor(options) {
19
17
  this.baseUrl = options.baseUrl.replace(/\/+$/, "");
20
18
  this.apiKey = options.apiKey;
21
19
  this.fetchImpl = options.fetch ?? globalThis.fetch;
22
20
  this.defaultHeaders = options.headers;
21
+ this.readCacheTtlMs = typeof options.readCacheTtlMs === "number" && Number.isFinite(options.readCacheTtlMs) ? Math.max(0, options.readCacheTtlMs) : 6e4;
22
+ this.maxConcurrentRequests = typeof options.maxConcurrentRequests === "number" && Number.isFinite(options.maxConcurrentRequests) ? Math.max(0, Math.floor(options.maxConcurrentRequests)) : 0;
23
23
  }
24
24
  async health(options = {}) {
25
25
  return this.request("GET", "/health", { ...options, authOptional: true });
@@ -28,28 +28,35 @@ var K2DbApiClient = class {
28
28
  return this.request("GET", "/ready", { ...options, authOptional: true });
29
29
  }
30
30
  async create(collection, document, options = {}) {
31
- return this.request("POST", `/v1/${encodeURIComponent(collection)}`, {
31
+ const res = await this.request("POST", `/v1/${encodeURIComponent(collection)}`, {
32
32
  ...options,
33
33
  body: document
34
34
  });
35
+ this.invalidateCache();
36
+ return res;
35
37
  }
36
38
  async getById(collection, id, options = {}) {
37
39
  return this.request("GET", `/v1/${encodeURIComponent(collection)}/${encodeURIComponent(id)}`, options);
38
40
  }
39
41
  async patchById(collection, id, updates, options = {}) {
40
- return this.request("PATCH", `/v1/${encodeURIComponent(collection)}/${encodeURIComponent(id)}`, {
42
+ const res = await this.request("PATCH", `/v1/${encodeURIComponent(collection)}/${encodeURIComponent(id)}`, {
41
43
  ...options,
42
44
  body: updates
43
45
  });
46
+ this.invalidateCache();
47
+ return res;
44
48
  }
45
49
  async deleteById(collection, id, options = {}) {
46
50
  await this.request("DELETE", `/v1/${encodeURIComponent(collection)}/${encodeURIComponent(id)}`, options);
51
+ this.invalidateCache();
47
52
  }
48
53
  async patchCollection(collection, payload, options = {}) {
49
- return this.request("PATCH", `/v1/${encodeURIComponent(collection)}`, {
54
+ const res = await this.request("PATCH", `/v1/${encodeURIComponent(collection)}`, {
50
55
  ...options,
51
56
  body: payload
52
57
  });
58
+ this.invalidateCache();
59
+ return res;
53
60
  }
54
61
  async search(collection, payload = {}, options = {}) {
55
62
  return this.request("POST", `/v1/${encodeURIComponent(collection)}/search`, {
@@ -70,10 +77,12 @@ var K2DbApiClient = class {
70
77
  });
71
78
  }
72
79
  async restore(collection, payload, options = {}) {
73
- return this.request("POST", `/v1/${encodeURIComponent(collection)}/restore`, {
80
+ const res = await this.request("POST", `/v1/${encodeURIComponent(collection)}/restore`, {
74
81
  ...options,
75
82
  body: payload
76
83
  });
84
+ this.invalidateCache();
85
+ return res;
77
86
  }
78
87
  async getVersions(collection, id, query = {}, options = {}) {
79
88
  return this.request("GET", `/v1/${encodeURIComponent(collection)}/${encodeURIComponent(id)}/versions`, {
@@ -82,39 +91,166 @@ var K2DbApiClient = class {
82
91
  });
83
92
  }
84
93
  async patchVersions(collection, id, payload, options = {}) {
85
- return this.request("PATCH", `/v1/${encodeURIComponent(collection)}/${encodeURIComponent(id)}/versions`, {
94
+ const res = await this.request("PATCH", `/v1/${encodeURIComponent(collection)}/${encodeURIComponent(id)}/versions`, {
86
95
  ...options,
87
96
  body: payload
88
97
  });
98
+ this.invalidateCache();
99
+ return res;
89
100
  }
90
101
  async revertVersion(collection, id, version, options = {}) {
91
- return this.request(
102
+ const res = await this.request(
92
103
  "POST",
93
104
  `/v1/${encodeURIComponent(collection)}/${encodeURIComponent(id)}/versions/${encodeURIComponent(String(version))}/revert`,
94
105
  options
95
106
  );
107
+ this.invalidateCache();
108
+ return res;
96
109
  }
97
110
  async adminDeleteCollection(collection, options = {}) {
98
111
  await this.request("DELETE", `/v1/admin/${encodeURIComponent(collection)}`, options);
112
+ this.invalidateCache();
99
113
  }
100
114
  async adminDeleteById(collection, id, options = {}) {
101
115
  await this.request("DELETE", `/v1/admin/${encodeURIComponent(collection)}/${encodeURIComponent(id)}`, options);
116
+ this.invalidateCache();
102
117
  }
103
118
  async adminCreateIndexes(collection, payload, options = {}) {
104
- return this.request("POST", `/v1/admin/${encodeURIComponent(collection)}/indexes`, {
119
+ const res = await this.request("POST", `/v1/admin/${encodeURIComponent(collection)}/indexes`, {
105
120
  ...options,
106
121
  body: payload
107
122
  });
123
+ this.invalidateCache();
124
+ return res;
108
125
  }
109
126
  async adminCreateHistoryIndexes(collection, payload = {}, options = {}) {
110
- return this.request("POST", `/v1/admin/${encodeURIComponent(collection)}/history-indexes`, {
127
+ const res = await this.request("POST", `/v1/admin/${encodeURIComponent(collection)}/history-indexes`, {
111
128
  ...options,
112
129
  body: payload
113
130
  });
131
+ this.invalidateCache();
132
+ return res;
133
+ }
134
+ serviceErrorFromHttpStatus(status) {
135
+ switch (status) {
136
+ case 400:
137
+ return ServiceError.BAD_REQUEST;
138
+ case 401:
139
+ return ServiceError.UNAUTHORIZED;
140
+ case 402:
141
+ return ServiceError.PAYMENT_REQUIRED;
142
+ case 403:
143
+ return ServiceError.FORBIDDEN;
144
+ case 404:
145
+ return ServiceError.NOT_FOUND;
146
+ case 405:
147
+ return ServiceError.UNSUPPORTED_METHOD;
148
+ case 409:
149
+ return ServiceError.CONFLICT;
150
+ case 429:
151
+ return ServiceError.TOO_MANY_REQUESTS;
152
+ case 501:
153
+ return ServiceError.NOT_IMPLEMENTED;
154
+ case 502:
155
+ return ServiceError.BAD_GATEWAY;
156
+ case 503:
157
+ return ServiceError.SERVICE_UNAVAILABLE;
158
+ case 504:
159
+ return ServiceError.GATEWAY_TIMEOUT;
160
+ default:
161
+ return status >= 500 ? ServiceError.SYSTEM_ERROR : ServiceError.SERVICE_ERROR;
162
+ }
163
+ }
164
+ invalidateCache() {
165
+ this.cache.clear();
166
+ }
167
+ isCacheableRead(method, path) {
168
+ if (method === "GET") return true;
169
+ if (method !== "POST") return false;
170
+ return path.endsWith("/search") || path.endsWith("/aggregate") || path.endsWith("/count");
171
+ }
172
+ // Deterministic JSON stringifier (sorted keys) so request signatures are stable.
173
+ stableStringify(x) {
174
+ if (x === null || x === void 0) return "null";
175
+ const t = typeof x;
176
+ if (t === "string") return JSON.stringify(x);
177
+ if (t === "number" || t === "boolean") return JSON.stringify(x);
178
+ if (t !== "object") return JSON.stringify(String(x));
179
+ if (Array.isArray(x)) {
180
+ return `[${x.map((v) => this.stableStringify(v)).join(",")}]`;
181
+ }
182
+ const obj = x;
183
+ const keys = Object.keys(obj).sort();
184
+ return `{${keys.map((k) => `${JSON.stringify(k)}:${this.stableStringify(obj[k])}`).join(",")}}`;
185
+ }
186
+ // Non-cryptographic 64-bit FNV-1a hash (hex). Fast and good enough for cache keys.
187
+ fnv1a64(s) {
188
+ let h = 0xcbf29ce484222325n;
189
+ const prime = 0x100000001b3n;
190
+ for (let i = 0; i < s.length; i++) {
191
+ h ^= BigInt(s.charCodeAt(i));
192
+ h = h * prime & 0xffffffffffffffffn;
193
+ }
194
+ return h.toString(16).padStart(16, "0");
195
+ }
196
+ requestSignature(method, url, headers, body) {
197
+ const scope = headers["x-scope"] ?? "";
198
+ const auth = headers.authorization ?? "";
199
+ const authKey = auth ? this.fnv1a64(auth) : "";
200
+ const bodyKey = body === void 0 ? "" : this.stableStringify(body);
201
+ const raw = `${method} ${url}
202
+ scope=${scope}
203
+ auth=${authKey}
204
+ body=${bodyKey}`;
205
+ return this.fnv1a64(raw);
206
+ }
207
+ async acquireRequestSlot(signal) {
208
+ if (!this.maxConcurrentRequests || this.maxConcurrentRequests <= 0) return;
209
+ if (this.activeRequests < this.maxConcurrentRequests) {
210
+ this.activeRequests++;
211
+ return;
212
+ }
213
+ await new Promise((resolve, reject) => {
214
+ const onAbort = () => {
215
+ const idx = this.waiters.indexOf(wakeup);
216
+ if (idx >= 0) this.waiters.splice(idx, 1);
217
+ reject(new K2Error(ServiceError.TOO_MANY_REQUESTS, "Request aborted while waiting for a slot", "k2db_client_semaphore_abort"));
218
+ };
219
+ const wakeup = () => {
220
+ if (signal) signal.removeEventListener("abort", onAbort);
221
+ this.activeRequests++;
222
+ resolve();
223
+ };
224
+ if (signal?.aborted) {
225
+ reject(new K2Error(ServiceError.TOO_MANY_REQUESTS, "Request aborted while waiting for a slot", "k2db_client_semaphore_abort"));
226
+ return;
227
+ }
228
+ if (signal) signal.addEventListener("abort", onAbort, { once: true });
229
+ this.waiters.push(wakeup);
230
+ });
231
+ }
232
+ releaseRequestSlot() {
233
+ if (!this.maxConcurrentRequests || this.maxConcurrentRequests <= 0) return;
234
+ this.activeRequests = Math.max(0, this.activeRequests - 1);
235
+ const next = this.waiters.shift();
236
+ if (next) next();
114
237
  }
115
238
  async request(method, path, options) {
116
239
  const url = this.buildUrl(path, options.query);
117
240
  const headers = this.buildHeaders(options);
241
+ const cacheable = this.isCacheableRead(method, path);
242
+ const ttlMs = cacheable ? options.cacheTtlMs ?? this.readCacheTtlMs : 0;
243
+ const sig = ttlMs > 0 ? this.requestSignature(method, url, headers, options.body) : "";
244
+ if (ttlMs > 0) {
245
+ const now = Date.now();
246
+ const hit = this.cache.get(sig);
247
+ if (hit) {
248
+ if (hit.expiresAt > now) return hit.value;
249
+ this.cache.delete(sig);
250
+ }
251
+ const inflight = this.inflight.get(sig);
252
+ if (inflight) return await inflight;
253
+ }
118
254
  const init = {
119
255
  method,
120
256
  headers
@@ -125,32 +261,79 @@ var K2DbApiClient = class {
125
261
  if (options.body !== void 0) {
126
262
  init.body = JSON.stringify(options.body);
127
263
  }
128
- const res = await this.fetchImpl(url, init);
129
- if (res.status === 204) {
130
- return void 0;
131
- }
132
- const contentType = res.headers.get("content-type") ?? "";
133
- const isJson = contentType.includes("application/json") || contentType.includes("application/problem+json");
134
- const payload = isJson ? await res.json() : await res.text();
135
- if (!res.ok) {
136
- if (isJson) {
137
- const k2err = this.tryRehydrateK2Error(payload, res.status);
138
- if (k2err) {
139
- throw k2err;
264
+ const run = (async () => {
265
+ let res;
266
+ await this.acquireRequestSlot(options.signal);
267
+ try {
268
+ res = await this.fetchImpl(url, init);
269
+ } catch (err) {
270
+ throw new K2Error(
271
+ ServiceError.SERVICE_UNAVAILABLE,
272
+ "Network request failed",
273
+ "k2db_client_fetch",
274
+ err
275
+ );
276
+ } finally {
277
+ this.releaseRequestSlot();
278
+ }
279
+ if (res.status === 204) {
280
+ return void 0;
281
+ }
282
+ const contentType = res.headers.get("content-type") ?? "";
283
+ const isJson = contentType.includes("application/json") || contentType.includes("application/problem+json");
284
+ let payload;
285
+ try {
286
+ payload = isJson ? await res.json() : await res.text();
287
+ } catch (err) {
288
+ const k2 = new K2Error(
289
+ this.serviceErrorFromHttpStatus(res.status),
290
+ "Failed to parse server response",
291
+ "k2db_client_parse",
292
+ err
293
+ );
294
+ k2.code = res.status;
295
+ throw k2;
296
+ }
297
+ if (!res.ok) {
298
+ if (isJson) {
299
+ const k2err = this.tryRehydrateK2Error(payload, res.status);
300
+ if (k2err) {
301
+ throw k2err;
302
+ }
303
+ }
304
+ const detail = typeof payload === "string" && payload ? payload : typeof payload?.detail === "string" && payload.detail ? payload.detail : `Request failed: ${res.status}`;
305
+ const trace = typeof payload?.trace === "string" ? payload.trace : void 0;
306
+ const k2 = new K2Error(this.serviceErrorFromHttpStatus(res.status), detail, trace, payload);
307
+ k2.code = res.status;
308
+ if (payload && typeof payload === "object" && Array.isArray(payload.chain)) {
309
+ k2.chain = payload.chain;
140
310
  }
311
+ throw k2;
312
+ }
313
+ return payload;
314
+ })();
315
+ if (ttlMs > 0) {
316
+ this.inflight.set(sig, run);
317
+ }
318
+ try {
319
+ const value = await run;
320
+ if (ttlMs > 0) {
321
+ this.cache.set(sig, { expiresAt: Date.now() + ttlMs, value });
322
+ }
323
+ return value;
324
+ } finally {
325
+ if (ttlMs > 0) {
326
+ this.inflight.delete(sig);
141
327
  }
142
- const message = typeof payload === "string" && payload ? payload : `Request failed: ${res.status}`;
143
- throw new K2ApiError(message, res.status, payload);
144
328
  }
145
- return payload;
146
329
  }
147
330
  tryRehydrateK2Error(payload, status) {
148
331
  if (!payload || typeof payload !== "object") return null;
149
332
  const problem = payload;
150
333
  const errorId = this.parseServiceError(problem.type);
151
- if (!errorId && !problem.detail) return null;
334
+ if (!errorId) return null;
152
335
  const err = new K2Error(
153
- errorId ?? ServiceError.SERVICE_ERROR,
336
+ errorId,
154
337
  problem.detail ?? `Request failed: ${status}`,
155
338
  problem.trace
156
339
  );
@@ -204,7 +387,6 @@ var K2DbApiClient = class {
204
387
  }
205
388
  };
206
389
  export {
207
- K2ApiError,
208
390
  K2DbApiClient
209
391
  };
210
392
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/k2db-client.ts"],"sourcesContent":["import { K2Error, ServiceError } from '@frogfish/k2error'\n\nexport interface K2ClientOptions {\n baseUrl: string\n apiKey?: string\n fetch?: typeof fetch\n headers?: Record<string, string>\n}\n\nexport interface RequestOptions {\n apiKey?: string\n scope?: string\n headers?: Record<string, string>\n signal?: AbortSignal\n}\n\nexport interface CreateResult {\n id: string\n created: boolean\n}\n\nexport interface UpdateResult {\n updated: number\n}\n\nexport interface RestoreResult {\n restored: number\n}\n\nexport interface CountResult {\n count: number\n}\n\nexport interface SearchRequest {\n filter?: Record<string, unknown>\n params?: Record<string, unknown>\n skip?: number\n limit?: number\n}\n\nexport interface AggregateRequest {\n criteria: Record<string, unknown>[]\n skip?: number\n limit?: number\n}\n\nexport interface CountRequest {\n criteria?: Record<string, unknown>\n}\n\nexport interface BulkUpdateRequest<TValues extends Record<string, unknown>> {\n criteria: Record<string, unknown>\n values: Partial<TValues>\n}\n\nexport interface RestoreRequest {\n criteria: Record<string, unknown>\n}\n\nexport interface VersionedUpdateRequest<TData extends Record<string, unknown>> {\n data: Partial<TData>\n replace?: boolean\n maxVersions?: number\n}\n\nexport interface VersionInfo<TData extends Record<string, unknown>> {\n version: number\n timestamp: string\n data: TData\n}\n\nexport interface VersionedUpdateResult {\n version: number\n updated: number\n}\n\nexport interface IndexRequest {\n indexSpec: Record<string, unknown>\n options?: Record<string, unknown>\n}\n\nexport interface ReadyOk {\n status: 'ready'\n}\n\nexport interface ReadyNotOk {\n status: 'not-ready'\n databases: string[]\n}\n\nexport interface HealthOk {\n status: 'ok'\n}\n\nexport class K2ApiError extends Error {\n status: number\n body: unknown\n\n constructor(message: string, status: number, body: unknown) {\n super(message)\n this.name = 'K2ApiError'\n this.status = status\n this.body = body\n }\n}\n\nexport interface ProblemDetailsPayload {\n type?: string\n title?: string\n status?: number\n detail?: string\n trace?: string\n chain?: ErrorChainItem[]\n}\n\nexport interface ErrorChainItem {\n error: ServiceError\n error_description: string\n stage?: string\n at: number\n}\n\nexport class K2DbApiClient {\n private baseUrl: string\n private apiKey: string | undefined\n private fetchImpl: typeof fetch\n private defaultHeaders: Record<string, string> | undefined\n\n constructor(options: K2ClientOptions) {\n this.baseUrl = options.baseUrl.replace(/\\/+$/, '')\n this.apiKey = options.apiKey\n this.fetchImpl = options.fetch ?? globalThis.fetch\n this.defaultHeaders = options.headers\n }\n\n async health(options: RequestOptions = {}): Promise<HealthOk> {\n return this.request('GET', '/health', { ...options, authOptional: true })\n }\n\n async ready(options: RequestOptions = {}): Promise<ReadyOk | ReadyNotOk> {\n return this.request('GET', '/ready', { ...options, authOptional: true })\n }\n\n async create<TDoc extends Record<string, unknown>>(\n collection: string,\n document: Partial<TDoc>,\n options: RequestOptions = {}\n ): Promise<CreateResult> {\n return this.request('POST', `/v1/${encodeURIComponent(collection)}`, {\n ...options,\n body: document,\n })\n }\n\n async getById<TDoc extends Record<string, unknown>>(\n collection: string,\n id: string,\n options: RequestOptions = {}\n ): Promise<TDoc> {\n return this.request('GET', `/v1/${encodeURIComponent(collection)}/${encodeURIComponent(id)}`, options)\n }\n\n async patchById<TDoc extends Record<string, unknown>>(\n collection: string,\n id: string,\n updates: Partial<TDoc>,\n options: RequestOptions = {}\n ): Promise<UpdateResult> {\n return this.request('PATCH', `/v1/${encodeURIComponent(collection)}/${encodeURIComponent(id)}`, {\n ...options,\n body: updates,\n })\n }\n\n async deleteById(\n collection: string,\n id: string,\n options: RequestOptions = {}\n ): Promise<void> {\n await this.request('DELETE', `/v1/${encodeURIComponent(collection)}/${encodeURIComponent(id)}`, options)\n }\n\n async patchCollection<TDoc extends Record<string, unknown>>(\n collection: string,\n payload: BulkUpdateRequest<TDoc>,\n options: RequestOptions = {}\n ): Promise<UpdateResult> {\n return this.request('PATCH', `/v1/${encodeURIComponent(collection)}`, {\n ...options,\n body: payload,\n })\n }\n\n async search<TDoc extends Record<string, unknown>>(\n collection: string,\n payload: SearchRequest = {},\n options: RequestOptions = {}\n ): Promise<TDoc[]> {\n return this.request('POST', `/v1/${encodeURIComponent(collection)}/search`, {\n ...options,\n body: payload,\n })\n }\n\n async aggregate<TDoc extends Record<string, unknown>>(\n collection: string,\n payload: AggregateRequest,\n options: RequestOptions = {}\n ): Promise<TDoc[]> {\n return this.request('POST', `/v1/${encodeURIComponent(collection)}/aggregate`, {\n ...options,\n body: payload,\n })\n }\n\n async count(\n collection: string,\n payload: CountRequest = {},\n options: RequestOptions = {}\n ): Promise<CountResult> {\n return this.request('POST', `/v1/${encodeURIComponent(collection)}/count`, {\n ...options,\n body: payload,\n })\n }\n\n async restore(\n collection: string,\n payload: RestoreRequest,\n options: RequestOptions = {}\n ): Promise<RestoreResult> {\n return this.request('POST', `/v1/${encodeURIComponent(collection)}/restore`, {\n ...options,\n body: payload,\n })\n }\n\n async getVersions<TDoc extends Record<string, unknown>>(\n collection: string,\n id: string,\n query: { skip?: number; limit?: number } = {},\n options: RequestOptions = {}\n ): Promise<Array<VersionInfo<TDoc>>> {\n return this.request('GET', `/v1/${encodeURIComponent(collection)}/${encodeURIComponent(id)}/versions`, {\n ...options,\n query,\n })\n }\n\n async patchVersions<TDoc extends Record<string, unknown>>(\n collection: string,\n id: string,\n payload: VersionedUpdateRequest<TDoc>,\n options: RequestOptions = {}\n ): Promise<VersionedUpdateResult[]> {\n return this.request('PATCH', `/v1/${encodeURIComponent(collection)}/${encodeURIComponent(id)}/versions`, {\n ...options,\n body: payload,\n })\n }\n\n async revertVersion(\n collection: string,\n id: string,\n version: number,\n options: RequestOptions = {}\n ): Promise<UpdateResult> {\n return this.request(\n 'POST',\n `/v1/${encodeURIComponent(collection)}/${encodeURIComponent(id)}/versions/${encodeURIComponent(String(version))}/revert`,\n options\n )\n }\n\n async adminDeleteCollection(\n collection: string,\n options: RequestOptions = {}\n ): Promise<void> {\n await this.request('DELETE', `/v1/admin/${encodeURIComponent(collection)}`, options)\n }\n\n async adminDeleteById(\n collection: string,\n id: string,\n options: RequestOptions = {}\n ): Promise<void> {\n await this.request('DELETE', `/v1/admin/${encodeURIComponent(collection)}/${encodeURIComponent(id)}`, options)\n }\n\n async adminCreateIndexes(\n collection: string,\n payload: IndexRequest,\n options: RequestOptions = {}\n ): Promise<{ message: string }> {\n return this.request('POST', `/v1/admin/${encodeURIComponent(collection)}/indexes`, {\n ...options,\n body: payload,\n })\n }\n\n async adminCreateHistoryIndexes(\n collection: string,\n payload: Record<string, unknown> = {},\n options: RequestOptions = {}\n ): Promise<{ message: string }> {\n return this.request('POST', `/v1/admin/${encodeURIComponent(collection)}/history-indexes`, {\n ...options,\n body: payload,\n })\n }\n\n private async request<T>(\n method: string,\n path: string,\n options: RequestOptions & {\n body?: unknown\n query?: Record<string, unknown>\n authOptional?: boolean\n }\n ): Promise<T> {\n const url = this.buildUrl(path, options.query)\n const headers = this.buildHeaders(options)\n const init: RequestInit = {\n method,\n headers,\n }\n if (options.signal) {\n init.signal = options.signal\n }\n if (options.body !== undefined) {\n init.body = JSON.stringify(options.body)\n }\n\n const res = await this.fetchImpl(url, init)\n\n if (res.status === 204) {\n return undefined as T\n }\n\n const contentType = res.headers.get('content-type') ?? ''\n const isJson = contentType.includes('application/json') || contentType.includes('application/problem+json')\n const payload = isJson ? await res.json() : await res.text()\n\n if (!res.ok) {\n if (isJson) {\n const k2err = this.tryRehydrateK2Error(payload, res.status)\n if (k2err) {\n throw k2err\n }\n }\n\n const message = typeof payload === 'string' && payload ? payload : `Request failed: ${res.status}`\n throw new K2ApiError(message, res.status, payload)\n }\n\n return payload as T\n }\n\n private tryRehydrateK2Error(payload: unknown, status: number): K2Error | null {\n if (!payload || typeof payload !== 'object') return null\n\n const problem = payload as ProblemDetailsPayload\n const errorId = this.parseServiceError(problem.type)\n if (!errorId && !problem.detail) return null\n\n const err = new K2Error(\n errorId ?? ServiceError.SERVICE_ERROR,\n problem.detail ?? `Request failed: ${status}`,\n problem.trace\n )\n\n if (typeof problem.status === 'number' && Number.isFinite(problem.status)) {\n err.code = problem.status\n } else {\n err.code = status\n }\n\n if (Array.isArray(problem.chain)) {\n err.chain = problem.chain\n }\n\n return err\n }\n\n private parseServiceError(typeValue: string | undefined): ServiceError | undefined {\n if (!typeValue || typeof typeValue !== 'string') return undefined\n const prefix = 'urn:service-error:'\n if (!typeValue.startsWith(prefix)) return undefined\n const id = typeValue.slice(prefix.length)\n if (!id) return undefined\n const values = Object.values(ServiceError) as string[]\n return values.includes(id) ? (id as ServiceError) : undefined\n }\n\n private buildUrl(path: string, query?: Record<string, unknown>): string {\n const base = `${this.baseUrl}${path.startsWith('/') ? '' : '/'}${path}`\n if (!query || Object.keys(query).length === 0) return base\n\n const params = new URLSearchParams()\n for (const [key, value] of Object.entries(query)) {\n if (value === undefined || value === null) continue\n params.set(key, String(value))\n }\n\n const qs = params.toString()\n return qs ? `${base}?${qs}` : base\n }\n\n private buildHeaders(options: RequestOptions & { body?: unknown; authOptional?: boolean }): Record<string, string> {\n const headers: Record<string, string> = {\n accept: 'application/json',\n ...this.defaultHeaders,\n ...options.headers,\n }\n\n if (options.body !== undefined) {\n headers['content-type'] = 'application/json'\n }\n\n if (options.scope) {\n headers['x-scope'] = options.scope\n }\n\n const apiKey = options.apiKey ?? this.apiKey\n if (apiKey && !options.authOptional) {\n headers.authorization = apiKey.startsWith('ApiKey ') ? apiKey : `ApiKey ${apiKey}`\n }\n\n return headers\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/k2db-client.ts"],"sourcesContent":["import { K2Error, ServiceError } from '@frogfish/k2error'\n\nexport interface K2ClientOptions {\n baseUrl: string\n apiKey?: string\n fetch?: typeof fetch\n headers?: Record<string, string>\n\n /**\n * Default TTL (ms) for cacheable, read-only requests.\n * Set to 0 to disable client-side caching globally.\n * @default 60000\n */\n readCacheTtlMs?: number\n\n /**\n * Maximum number of concurrent in-flight HTTP requests.\n * 0 or undefined means unlimited.\n */\n maxConcurrentRequests?: number\n}\n\nexport interface RequestOptions {\n apiKey?: string\n scope?: string\n headers?: Record<string, string>\n signal?: AbortSignal\n\n /**\n * Per-request cache TTL override (ms). Only applies to cacheable read requests.\n * - undefined: use client default\n * - 0: disable caching for this request\n */\n cacheTtlMs?: number\n}\n\nexport interface CreateResult {\n id: string\n created: boolean\n}\n\nexport interface UpdateResult {\n updated: number\n}\n\nexport interface RestoreResult {\n restored: number\n}\n\nexport interface CountResult {\n count: number\n}\n\nexport interface SearchRequest {\n filter?: Record<string, unknown>\n params?: Record<string, unknown>\n skip?: number\n limit?: number\n}\n\nexport interface AggregateRequest {\n criteria: Record<string, unknown>[]\n skip?: number\n limit?: number\n}\n\nexport interface CountRequest {\n criteria?: Record<string, unknown>\n}\n\nexport interface BulkUpdateRequest<TValues extends Record<string, unknown>> {\n criteria: Record<string, unknown>\n values: Partial<TValues>\n}\n\nexport interface RestoreRequest {\n criteria: Record<string, unknown>\n}\n\nexport interface VersionedUpdateRequest<TData extends Record<string, unknown>> {\n data: Partial<TData>\n replace?: boolean\n maxVersions?: number\n}\n\nexport interface VersionInfo<TData extends Record<string, unknown>> {\n version: number\n timestamp: string\n data: TData\n}\n\nexport interface VersionedUpdateResult {\n version: number\n updated: number\n}\n\nexport interface IndexRequest {\n indexSpec: Record<string, unknown>\n options?: Record<string, unknown>\n}\n\nexport interface ReadyOk {\n status: 'ready'\n}\n\nexport interface ReadyNotOk {\n status: 'not-ready'\n databases: string[]\n}\n\nexport interface HealthOk {\n status: 'ok'\n}\n\nexport interface ProblemDetailsPayload {\n type?: string\n title?: string\n status?: number\n detail?: string\n trace?: string\n chain?: ErrorChainItem[]\n}\n\nexport interface ErrorChainItem {\n error: ServiceError\n error_description: string\n stage?: string\n at: number\n}\n\nexport class K2DbApiClient {\n private baseUrl: string\n private apiKey: string | undefined\n private fetchImpl: typeof fetch\n private defaultHeaders: Record<string, string> | undefined\n\n private readonly readCacheTtlMs: number\n\n // Read-only request memoization + in-flight collapse (Angular-proofing)\n private readonly inflight = new Map<string, Promise<unknown>>()\n private readonly cache = new Map<string, { expiresAt: number; value: unknown }>()\n\n // Optional global concurrency limiter\n private readonly maxConcurrentRequests: number\n private activeRequests = 0\n private readonly waiters: Array<() => void> = []\n\n constructor(options: K2ClientOptions) {\n this.baseUrl = options.baseUrl.replace(/\\/+$/, '')\n this.apiKey = options.apiKey\n this.fetchImpl = options.fetch ?? globalThis.fetch\n this.defaultHeaders = options.headers\n this.readCacheTtlMs = typeof options.readCacheTtlMs === 'number' && Number.isFinite(options.readCacheTtlMs)\n ? Math.max(0, options.readCacheTtlMs)\n : 60_000\n this.maxConcurrentRequests = typeof options.maxConcurrentRequests === 'number' && Number.isFinite(options.maxConcurrentRequests)\n ? Math.max(0, Math.floor(options.maxConcurrentRequests))\n : 0\n }\n\n async health(options: RequestOptions = {}): Promise<HealthOk> {\n return this.request('GET', '/health', { ...options, authOptional: true })\n }\n\n async ready(options: RequestOptions = {}): Promise<ReadyOk | ReadyNotOk> {\n return this.request('GET', '/ready', { ...options, authOptional: true })\n }\n\n async create<TDoc extends Record<string, unknown>>(\n collection: string,\n document: Partial<TDoc>,\n options: RequestOptions = {}\n ): Promise<CreateResult> {\n const res = await this.request<CreateResult>('POST', `/v1/${encodeURIComponent(collection)}`, {\n ...options,\n body: document,\n })\n this.invalidateCache()\n return res\n }\n\n async getById<TDoc extends Record<string, unknown>>(\n collection: string,\n id: string,\n options: RequestOptions = {}\n ): Promise<TDoc> {\n return this.request('GET', `/v1/${encodeURIComponent(collection)}/${encodeURIComponent(id)}`, options)\n }\n\n async patchById<TDoc extends Record<string, unknown>>(\n collection: string,\n id: string,\n updates: Partial<TDoc>,\n options: RequestOptions = {}\n ): Promise<UpdateResult> {\n const res = await this.request<UpdateResult>('PATCH', `/v1/${encodeURIComponent(collection)}/${encodeURIComponent(id)}`, {\n ...options,\n body: updates,\n })\n this.invalidateCache()\n return res\n }\n\n async deleteById(\n collection: string,\n id: string,\n options: RequestOptions = {}\n ): Promise<void> {\n await this.request('DELETE', `/v1/${encodeURIComponent(collection)}/${encodeURIComponent(id)}`, options)\n this.invalidateCache()\n }\n\n async patchCollection<TDoc extends Record<string, unknown>>(\n collection: string,\n payload: BulkUpdateRequest<TDoc>,\n options: RequestOptions = {}\n ): Promise<UpdateResult> {\n const res = await this.request<UpdateResult>('PATCH', `/v1/${encodeURIComponent(collection)}`, {\n ...options,\n body: payload,\n })\n this.invalidateCache()\n return res\n }\n\n async search<TDoc extends Record<string, unknown>>(\n collection: string,\n payload: SearchRequest = {},\n options: RequestOptions = {}\n ): Promise<TDoc[]> {\n return this.request('POST', `/v1/${encodeURIComponent(collection)}/search`, {\n ...options,\n body: payload,\n })\n }\n\n async aggregate<TDoc extends Record<string, unknown>>(\n collection: string,\n payload: AggregateRequest,\n options: RequestOptions = {}\n ): Promise<TDoc[]> {\n return this.request('POST', `/v1/${encodeURIComponent(collection)}/aggregate`, {\n ...options,\n body: payload,\n })\n }\n\n async count(\n collection: string,\n payload: CountRequest = {},\n options: RequestOptions = {}\n ): Promise<CountResult> {\n return this.request('POST', `/v1/${encodeURIComponent(collection)}/count`, {\n ...options,\n body: payload,\n })\n }\n\n async restore(\n collection: string,\n payload: RestoreRequest,\n options: RequestOptions = {}\n ): Promise<RestoreResult> {\n const res = await this.request<RestoreResult>('POST', `/v1/${encodeURIComponent(collection)}/restore`, {\n ...options,\n body: payload,\n })\n this.invalidateCache()\n return res\n }\n\n async getVersions<TDoc extends Record<string, unknown>>(\n collection: string,\n id: string,\n query: { skip?: number; limit?: number } = {},\n options: RequestOptions = {}\n ): Promise<Array<VersionInfo<TDoc>>> {\n return this.request('GET', `/v1/${encodeURIComponent(collection)}/${encodeURIComponent(id)}/versions`, {\n ...options,\n query,\n })\n }\n\n async patchVersions<TDoc extends Record<string, unknown>>(\n collection: string,\n id: string,\n payload: VersionedUpdateRequest<TDoc>,\n options: RequestOptions = {}\n ): Promise<VersionedUpdateResult[]> {\n const res = await this.request<VersionedUpdateResult[]>('PATCH', `/v1/${encodeURIComponent(collection)}/${encodeURIComponent(id)}/versions`, {\n ...options,\n body: payload,\n })\n this.invalidateCache()\n return res\n }\n\n async revertVersion(\n collection: string,\n id: string,\n version: number,\n options: RequestOptions = {}\n ): Promise<UpdateResult> {\n const res = await this.request<UpdateResult>(\n 'POST',\n `/v1/${encodeURIComponent(collection)}/${encodeURIComponent(id)}/versions/${encodeURIComponent(String(version))}/revert`,\n options\n )\n this.invalidateCache()\n return res\n }\n\n async adminDeleteCollection(\n collection: string,\n options: RequestOptions = {}\n ): Promise<void> {\n await this.request('DELETE', `/v1/admin/${encodeURIComponent(collection)}`, options)\n this.invalidateCache()\n }\n\n async adminDeleteById(\n collection: string,\n id: string,\n options: RequestOptions = {}\n ): Promise<void> {\n await this.request('DELETE', `/v1/admin/${encodeURIComponent(collection)}/${encodeURIComponent(id)}`, options)\n this.invalidateCache()\n }\n\n async adminCreateIndexes(\n collection: string,\n payload: IndexRequest,\n options: RequestOptions = {}\n ): Promise<{ message: string }> {\n const res = await this.request<{ message: string }>('POST', `/v1/admin/${encodeURIComponent(collection)}/indexes`, {\n ...options,\n body: payload,\n })\n this.invalidateCache()\n return res\n }\n\n async adminCreateHistoryIndexes(\n collection: string,\n payload: Record<string, unknown> = {},\n options: RequestOptions = {}\n ): Promise<{ message: string }> {\n const res = await this.request<{ message: string }>('POST', `/v1/admin/${encodeURIComponent(collection)}/history-indexes`, {\n ...options,\n body: payload,\n })\n this.invalidateCache()\n return res\n }\n\n private serviceErrorFromHttpStatus(status: number): ServiceError {\n // Best-effort mapping when server didn't return a K2Error payload.\n switch (status) {\n case 400:\n return ServiceError.BAD_REQUEST\n case 401:\n return ServiceError.UNAUTHORIZED\n case 402:\n return ServiceError.PAYMENT_REQUIRED\n case 403:\n return ServiceError.FORBIDDEN\n case 404:\n return ServiceError.NOT_FOUND\n case 405:\n return ServiceError.UNSUPPORTED_METHOD\n case 409:\n return ServiceError.CONFLICT\n case 429:\n return ServiceError.TOO_MANY_REQUESTS\n case 501:\n return ServiceError.NOT_IMPLEMENTED\n case 502:\n return ServiceError.BAD_GATEWAY\n case 503:\n return ServiceError.SERVICE_UNAVAILABLE\n case 504:\n return ServiceError.GATEWAY_TIMEOUT\n default:\n // 5xx → system_error, otherwise service_error\n return status >= 500 ? ServiceError.SYSTEM_ERROR : ServiceError.SERVICE_ERROR\n }\n }\n\n private invalidateCache(): void {\n this.cache.clear()\n }\n\n private isCacheableRead(method: string, path: string): boolean {\n if (method === 'GET') return true\n if (method !== 'POST') return false\n // These POST endpoints are idempotent reads in k2db.\n return path.endsWith('/search') || path.endsWith('/aggregate') || path.endsWith('/count')\n }\n\n // Deterministic JSON stringifier (sorted keys) so request signatures are stable.\n private stableStringify(x: unknown): string {\n if (x === null || x === undefined) return 'null'\n const t = typeof x\n if (t === 'string') return JSON.stringify(x)\n if (t === 'number' || t === 'boolean') return JSON.stringify(x)\n if (t !== 'object') return JSON.stringify(String(x))\n\n if (Array.isArray(x)) {\n return `[${x.map((v) => this.stableStringify(v)).join(',')}]`\n }\n\n const obj = x as Record<string, unknown>\n const keys = Object.keys(obj).sort()\n return `{${keys.map((k) => `${JSON.stringify(k)}:${this.stableStringify(obj[k])}`).join(',')}}`\n }\n\n // Non-cryptographic 64-bit FNV-1a hash (hex). Fast and good enough for cache keys.\n private fnv1a64(s: string): string {\n let h = 0xcbf29ce484222325n\n const prime = 0x100000001b3n\n for (let i = 0; i < s.length; i++) {\n h ^= BigInt(s.charCodeAt(i))\n h = (h * prime) & 0xffffffffffffffffn\n }\n return h.toString(16).padStart(16, '0')\n }\n\n private requestSignature(method: string, url: string, headers: Record<string, string>, body: unknown): string {\n const scope = headers['x-scope'] ?? ''\n const auth = headers.authorization ?? ''\n const authKey = auth ? this.fnv1a64(auth) : ''\n const bodyKey = body === undefined ? '' : this.stableStringify(body)\n const raw = `${method} ${url}\\nscope=${scope}\\nauth=${authKey}\\nbody=${bodyKey}`\n return this.fnv1a64(raw)\n }\n\n private async acquireRequestSlot(signal?: AbortSignal): Promise<void> {\n if (!this.maxConcurrentRequests || this.maxConcurrentRequests <= 0) return\n\n if (this.activeRequests < this.maxConcurrentRequests) {\n this.activeRequests++\n return\n }\n\n await new Promise<void>((resolve, reject) => {\n const onAbort = () => {\n // Remove this waiter if it's still queued\n const idx = this.waiters.indexOf(wakeup)\n if (idx >= 0) this.waiters.splice(idx, 1)\n reject(new K2Error(ServiceError.TOO_MANY_REQUESTS, 'Request aborted while waiting for a slot', 'k2db_client_semaphore_abort'))\n }\n\n const wakeup = () => {\n if (signal) signal.removeEventListener('abort', onAbort)\n this.activeRequests++\n resolve()\n }\n\n if (signal?.aborted) {\n reject(new K2Error(ServiceError.TOO_MANY_REQUESTS, 'Request aborted while waiting for a slot', 'k2db_client_semaphore_abort'))\n return\n }\n\n if (signal) signal.addEventListener('abort', onAbort, { once: true })\n this.waiters.push(wakeup)\n })\n }\n\n private releaseRequestSlot(): void {\n if (!this.maxConcurrentRequests || this.maxConcurrentRequests <= 0) return\n\n this.activeRequests = Math.max(0, this.activeRequests - 1)\n const next = this.waiters.shift()\n if (next) next()\n }\n\n private async request<T>(\n method: string,\n path: string,\n options: RequestOptions & {\n body?: unknown\n query?: Record<string, unknown>\n authOptional?: boolean\n }\n ): Promise<T> {\n const url = this.buildUrl(path, options.query)\n const headers = this.buildHeaders(options)\n\n const cacheable = this.isCacheableRead(method, path)\n const ttlMs = cacheable ? (options.cacheTtlMs ?? this.readCacheTtlMs) : 0\n const sig = ttlMs > 0 ? this.requestSignature(method, url, headers, options.body) : ''\n\n if (ttlMs > 0) {\n const now = Date.now()\n const hit = this.cache.get(sig)\n if (hit) {\n if (hit.expiresAt > now) return hit.value as T\n this.cache.delete(sig)\n }\n const inflight = this.inflight.get(sig)\n if (inflight) return (await inflight) as T\n }\n\n const init: RequestInit = {\n method,\n headers,\n }\n if (options.signal) {\n init.signal = options.signal\n }\n if (options.body !== undefined) {\n init.body = JSON.stringify(options.body)\n }\n\n const run = (async (): Promise<T> => {\n let res: Response\n await this.acquireRequestSlot(options.signal)\n try {\n res = await this.fetchImpl(url, init)\n } catch (err) {\n // Network / CORS / DNS / abort, etc.\n throw new K2Error(\n ServiceError.SERVICE_UNAVAILABLE,\n 'Network request failed',\n 'k2db_client_fetch',\n err\n )\n } finally {\n this.releaseRequestSlot()\n }\n\n if (res.status === 204) {\n return undefined as T\n }\n\n const contentType = res.headers.get('content-type') ?? ''\n const isJson = contentType.includes('application/json') || contentType.includes('application/problem+json')\n\n let payload: unknown\n try {\n payload = isJson ? await res.json() : await res.text()\n } catch (err) {\n // Response parse error. Keep as K2Error and include status.\n const k2 = new K2Error(\n this.serviceErrorFromHttpStatus(res.status),\n 'Failed to parse server response',\n 'k2db_client_parse',\n err\n )\n k2.code = res.status\n throw k2\n }\n\n if (!res.ok) {\n // Preferred path: server already sent RFC7807 K2Error payload.\n if (isJson) {\n const k2err = this.tryRehydrateK2Error(payload, res.status)\n if (k2err) {\n throw k2err\n }\n }\n\n // Fallback: synthesize a K2Error from HTTP + payload.\n const detail =\n typeof payload === 'string' && payload\n ? payload\n : typeof (payload as any)?.detail === 'string' && (payload as any).detail\n ? ((payload as any).detail as string)\n : `Request failed: ${res.status}`\n\n const trace = typeof (payload as any)?.trace === 'string' ? ((payload as any).trace as string) : undefined\n\n const k2 = new K2Error(this.serviceErrorFromHttpStatus(res.status), detail, trace, payload)\n k2.code = res.status\n\n // If payload looks like a Problem Details chain, keep it.\n if (payload && typeof payload === 'object' && Array.isArray((payload as any).chain)) {\n k2.chain = (payload as any).chain\n }\n\n throw k2\n }\n\n return payload as T\n })()\n\n if (ttlMs > 0) {\n this.inflight.set(sig, run as Promise<unknown>)\n }\n\n try {\n const value = await run\n if (ttlMs > 0) {\n this.cache.set(sig, { expiresAt: Date.now() + ttlMs, value })\n }\n return value\n } finally {\n if (ttlMs > 0) {\n this.inflight.delete(sig)\n }\n }\n }\n\n private tryRehydrateK2Error(payload: unknown, status: number): K2Error | null {\n if (!payload || typeof payload !== 'object') return null\n\n const problem = payload as ProblemDetailsPayload\n const errorId = this.parseServiceError(problem.type)\n if (!errorId) return null\n\n const err = new K2Error(\n errorId,\n problem.detail ?? `Request failed: ${status}`,\n problem.trace\n )\n\n if (typeof problem.status === 'number' && Number.isFinite(problem.status)) {\n err.code = problem.status\n } else {\n err.code = status\n }\n\n if (Array.isArray(problem.chain)) {\n err.chain = problem.chain\n }\n\n return err\n }\n\n private parseServiceError(typeValue: string | undefined): ServiceError | undefined {\n if (!typeValue || typeof typeValue !== 'string') return undefined\n const prefix = 'urn:service-error:'\n if (!typeValue.startsWith(prefix)) return undefined\n const id = typeValue.slice(prefix.length)\n if (!id) return undefined\n const values = Object.values(ServiceError) as string[]\n return values.includes(id) ? (id as ServiceError) : undefined\n }\n\n private buildUrl(path: string, query?: Record<string, unknown>): string {\n const base = `${this.baseUrl}${path.startsWith('/') ? '' : '/'}${path}`\n if (!query || Object.keys(query).length === 0) return base\n\n const params = new URLSearchParams()\n for (const [key, value] of Object.entries(query)) {\n if (value === undefined || value === null) continue\n params.set(key, String(value))\n }\n\n const qs = params.toString()\n return qs ? `${base}?${qs}` : base\n }\n\n private buildHeaders(options: RequestOptions & { body?: unknown; authOptional?: boolean }): Record<string, string> {\n const headers: Record<string, string> = {\n accept: 'application/json',\n ...this.defaultHeaders,\n ...options.headers,\n }\n\n if (options.body !== undefined) {\n headers['content-type'] = 'application/json'\n }\n\n if (options.scope) {\n headers['x-scope'] = options.scope\n }\n\n const apiKey = options.apiKey ?? this.apiKey\n if (apiKey && !options.authOptional) {\n headers.authorization = apiKey.startsWith('ApiKey ') ? apiKey : `ApiKey ${apiKey}`\n }\n\n return headers\n }\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@frogfish/k2db-api",
3
- "version": "1.0.10",
3
+ "version": "1.0.11",
4
4
  "description": "K2DB API client",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",