@web-ts-toolkit/access-router-client 0.31.5 → 0.33.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.
Files changed (7) hide show
  1. package/README.md +258 -14
  2. package/index.d.mts +453 -85
  3. package/index.d.ts +453 -85
  4. package/index.js +1133 -368
  5. package/index.mjs +1133 -368
  6. package/llms.txt +39 -5
  7. package/package.json +11 -4
package/index.mjs CHANGED
@@ -1,10 +1,8 @@
1
1
  // src/adapter.ts
2
- import axios, { mergeConfig as mergeConfig5 } from "axios";
3
- import { castArray, isEmpty } from "@web-ts-toolkit/utils";
2
+ import axios2, { mergeConfig as mergeConfig5 } from "axios";
4
3
 
5
4
  // src/services/model-service.ts
6
5
  import { mergeConfig as mergeConfig3 } from "axios";
7
- import { set as set3 } from "@web-ts-toolkit/utils";
8
6
 
9
7
  // src/model.ts
10
8
  import {
@@ -12,42 +10,162 @@ import {
12
10
  cloneDeep,
13
11
  get as getValue,
14
12
  hasOwn,
13
+ isEqual,
15
14
  omit,
16
15
  pick,
17
16
  set as setValue
18
17
  } from "@web-ts-toolkit/utils";
18
+ var MissingPersistenceIdentityError = class extends Error {
19
+ constructor(message) {
20
+ super(message);
21
+ this.name = "MissingPersistenceIdentityError";
22
+ }
23
+ };
19
24
  var Model = class _Model {
20
- constructor(data, adapter) {
25
+ constructor(data, adapter, persistenceId, fromExisting) {
21
26
  this.modifiedPaths = /* @__PURE__ */ new Set();
27
+ this._persistenceId = persistenceId;
28
+ this._fromExisting = fromExisting ?? false;
22
29
  this._snapshot = cloneDeep(data);
23
30
  this.defineHiddenDataProp(cloneDeep(data));
24
31
  this.defineHiddenAdapterProp(adapter);
25
32
  this.definePublicDataProps();
26
33
  this.initializeDirtyState();
27
34
  }
28
- static create(data, adapter) {
29
- return new _Model(data, adapter);
30
- }
35
+ static create(data, adapter, persistenceId, fromExisting) {
36
+ return new _Model(data, adapter, persistenceId, fromExisting);
37
+ }
38
+ /**
39
+ * Persists the currently dirty paths to the server, then merges the
40
+ * server's response back into local state.
41
+ *
42
+ * Concurrency contract:
43
+ *
44
+ * 1. Submitted paths and their values are snapshotted before the request
45
+ * starts, so an in-flight response cannot wipe edits that were made
46
+ * while the request was pending.
47
+ * 2. On success, a submitted path is cleared from `modifiedPaths` only if
48
+ * its current local value still equals the submitted value — i.e. the
49
+ * user has not concurrently re-edited it to a different value.
50
+ * 3. Server-returned values overwrite local values for paths the user did
51
+ * NOT concurrently re-modify during the in-flight save; for paths the
52
+ * user did concurrently re-modify, the local value is preserved and
53
+ * the dirty flag is retained so the concurrent edit is resubmitted on
54
+ * the next `save()`. (Deterministic conflict rule: the newer local
55
+ * edit wins for the same path; the server value becomes its reset
56
+ * baseline without replacing the newer local value.)
57
+ * 4. On failure, no dirty state is cleared and no local value is
58
+ * overwritten; the caller can retry `save()` with the same set.
59
+ * 5. The return value echoes `{ ...result, data }` where `data` is a
60
+ * refreshed `Model` snapshot of the post-save local state (or `null`
61
+ * on failure), matching `ModelResponse<T, TData>`.
62
+ *
63
+ * Persistence identity (ARC-21): create-vs-update is resolved from a
64
+ * captured persistence identity rather than from the projected `_data`
65
+ * payload alone, so a read that strips `_id` (e.g. `select: { name: 1,
66
+ * _id: 0 }`) cannot turn a subsequent `save()` into a silent create of
67
+ * a duplicate. When `_data._id` is present it takes precedence so callers
68
+ * can still deliberately aim `_id` at a bogus id to observe a failing
69
+ * save. When neither `_data._id` nor a captured persistence identity is
70
+ * available (e.g. `readAdvancedFilter` with an `_id`-excluding
71
+ * projection), `save()` throws `MissingPersistenceIdentityError` instead
72
+ * of POSTing a new document.
73
+ */
31
74
  async save(reqConfig) {
32
- let result;
33
- if (this._data._id) {
34
- result = await this._service.update(this._data._id, this.prepareData(), { returningAll: false }, reqConfig);
35
- } else {
36
- result = await this._service.create(this.prepareData(), null, reqConfig);
75
+ const submittedPaths = new Set(this.modifiedPaths);
76
+ const submittedValues = {};
77
+ for (const path of submittedPaths) {
78
+ submittedValues[path] = cloneDeep(getValue(this._data, path));
79
+ }
80
+ const submittedData = this.prepareData();
81
+ const persistenceId = this._data._id ?? this._persistenceId;
82
+ if (persistenceId == null && this._fromExisting) {
83
+ throw new MissingPersistenceIdentityError(
84
+ "Model.save() cannot determine create-vs-update without a persistence identity. A read of an existing document produced a Model whose projection strips `_id` and no identity was captured at read time. Use `read(id)` / `readAdvanced(id, ...)` (which capture the identifier as a persistence identity), or include `_id` in the projection."
85
+ );
86
+ }
87
+ const isCreate = persistenceId == null;
88
+ const result = isCreate ? await this._service.create(submittedData, null, reqConfig) : await this._service.update(String(persistenceId), submittedData, { returningAll: false }, reqConfig);
89
+ if (!result.success) {
90
+ return { ...result, data: null };
91
+ }
92
+ const isConcurrentEdit = (path) => {
93
+ if (!submittedPaths.has(path)) {
94
+ return this.modifiedPaths.has(path);
95
+ }
96
+ const current = getValue(this._data, path);
97
+ const submitted = submittedValues[path];
98
+ return !isEqual(current, submitted);
99
+ };
100
+ const serverData = result.raw ?? {};
101
+ for (const key of Object.keys(serverData)) {
102
+ const normKey = this.normalizePath(key);
103
+ if (normKey === "_id") continue;
104
+ if (isConcurrentEdit(normKey)) {
105
+ continue;
106
+ }
107
+ const serverValue = serverData[key];
108
+ const before = getValue(this._data, normKey);
109
+ if (!isEqual(before, serverValue)) {
110
+ this._data[normKey] = serverValue;
111
+ }
112
+ this.modifiedPaths.delete(normKey);
113
+ }
114
+ for (const path of submittedPaths) {
115
+ if (!isConcurrentEdit(path)) {
116
+ this.modifiedPaths.delete(path);
117
+ }
118
+ }
119
+ if (isCreate && serverData._id != null) {
120
+ this._data._id = String(serverData._id);
121
+ this.modifiedPaths.delete("_id");
37
122
  }
38
- if (result.success) {
39
- this.updateModel(result.raw);
40
- this._snapshot = cloneDeep(this._data);
41
- this.modifiedPaths.clear();
123
+ const latestId = this._data._id ?? (serverData._id != null ? String(serverData._id) : void 0);
124
+ if (latestId != null) {
125
+ this._persistenceId = latestId;
42
126
  }
127
+ const nextSnapshot = Array.isArray(this._snapshot) ? [] : {};
128
+ const dataRecord = this._data;
129
+ for (const key of Object.keys(dataRecord)) {
130
+ const normKey = this.normalizePath(key);
131
+ if (this.modifiedPaths.has(normKey)) {
132
+ if (submittedPaths.has(normKey)) {
133
+ nextSnapshot[key] = cloneDeep(hasOwn(serverData, key) ? serverData[key] : submittedValues[normKey]);
134
+ } else {
135
+ nextSnapshot[key] = cloneDeep(this._snapshot[key]);
136
+ }
137
+ } else {
138
+ nextSnapshot[key] = cloneDeep(dataRecord[key]);
139
+ }
140
+ }
141
+ this._snapshot = nextSnapshot;
142
+ this.definePublicDataProps();
43
143
  return {
44
144
  ...result,
45
- data: result.success ? _Model.create(this._data, this._service) : null
145
+ // The post-save snapshot is always an existing document, so propagate
146
+ // `_fromExisting=true` plus the refreshed persistence identity so the
147
+ // returned wrapper cannot later silently create a duplicate. (If the
148
+ // caller intends a fresh draft, they construct `new Model({...}, s)`
149
+ // directly — `${_fromExisting}` defaults to `false` there.)
150
+ data: _Model.create(this._data, this._service, this._persistenceId, true)
46
151
  };
47
152
  }
48
153
  isDirty(path) {
49
154
  return path ? this.modifiedPaths.has(this.normalizePath(String(path))) : this.modifiedPaths.size > 0;
50
155
  }
156
+ /**
157
+ * Marks a path dirty and skips snapshot reconciliation. This is the
158
+ * explicit "include this path on the next save()" escape hatch: even when
159
+ * the effective value still equals the snapshot, the path stays dirty so
160
+ * callers can force a field to be re-sent to the server (e.g., to retrigger
161
+ * server-side defaults or to re-submit a value that another client may
162
+ * have reverted).
163
+ *
164
+ * For implicit writes that reconcile against the snapshot automatically
165
+ * (reverting a field to its baseline clears the dirty flag), use `set()`,
166
+ * `assign(...)`, or direct property assignment — those entry points all
167
+ * run `reconcilePath` after the write.
168
+ */
51
169
  markModified(path) {
52
170
  this.trackModified(String(path));
53
171
  return this;
@@ -63,6 +181,7 @@ var Model = class _Model {
63
181
  setValue(this._data, path, value);
64
182
  this.trackModified(path);
65
183
  this.definePublicDataProps();
184
+ this.reconcilePath(this.normalizePath(path));
66
185
  return this;
67
186
  }
68
187
  assign(partial) {
@@ -75,6 +194,9 @@ var Model = class _Model {
75
194
  }
76
195
  }
77
196
  this.definePublicDataProps();
197
+ for (let x = 0; x < keys.length; x++) {
198
+ this.reconcilePath(this.normalizePath(String(keys[x])));
199
+ }
78
200
  return this;
79
201
  }
80
202
  reset() {
@@ -88,10 +210,6 @@ var Model = class _Model {
88
210
  toJSON() {
89
211
  return this.toObject();
90
212
  }
91
- updateModel(data) {
92
- assignObject(this._data, data);
93
- this.definePublicDataProps();
94
- }
95
213
  replaceData(data) {
96
214
  const nextData = cloneDeep(data);
97
215
  const currentKeys = Object.keys(this._data);
@@ -105,7 +223,7 @@ var Model = class _Model {
105
223
  this.definePublicDataProps();
106
224
  }
107
225
  initializeDirtyState() {
108
- if (this._data._id) {
226
+ if (this._fromExisting || this._data._id) {
109
227
  return;
110
228
  }
111
229
  const keys = Object.keys(this._data);
@@ -129,6 +247,7 @@ var Model = class _Model {
129
247
  }
130
248
  this.trackModified(keystr);
131
249
  target[key] = value;
250
+ this.reconcilePath(this.normalizePath(keystr));
132
251
  return true;
133
252
  }
134
253
  }),
@@ -164,24 +283,42 @@ var Model = class _Model {
164
283
  normalizePath(path) {
165
284
  return path.split(".")[0];
166
285
  }
286
+ /**
287
+ * Removes `path` from the dirty set when its current top-level value deeply
288
+ * equals the snapshot baseline. Used uniformly by `set()`, `assign()`,
289
+ * public property setters (via the proxy), and `markModified()` so all
290
+ * entry points share the same tracking rule.
291
+ *
292
+ * Note: `_id` is intentionally never reconciled away here — it is excluded
293
+ * from `initializeDirtyState` and managed explicitly during `save()`
294
+ * reconciliation.
295
+ */
296
+ reconcilePath(path) {
297
+ if (path === "_id") return;
298
+ if (!this.modifiedPaths.has(path)) return;
299
+ const current = this._data[path];
300
+ const base = this._snapshot[path];
301
+ if (isEqual(current, base)) {
302
+ this.modifiedPaths.delete(path);
303
+ }
304
+ }
167
305
  };
168
306
 
169
307
  // src/services/service.ts
170
- import { AxiosHeaders } from "axios";
308
+ import { AxiosHeaders as AxiosHeaders2 } from "axios";
171
309
 
172
310
  // src/constants.ts
173
311
  var CACHE_HEADER = "x-axios-cache";
174
312
 
175
313
  // src/services/wrap.ts
176
- import { mergeConfig } from "axios";
177
- import { set } from "@web-ts-toolkit/utils";
314
+ import { AxiosHeaders, mergeConfig } from "axios";
178
315
 
179
316
  // src/helpers.ts
180
317
  import { isPlainObject, mapValues } from "@web-ts-toolkit/utils";
181
318
  function replaceSubQuery(filter) {
182
319
  if (!isPlainObject(filter)) return filter;
183
320
  const ret = mapValues(filter, (val) => {
184
- if (val && val.__op && val.__query) {
321
+ if (isPlainObject(val) && "__op" in val && val.__op && "__query" in val && val.__query) {
185
322
  return {
186
323
  $$sq: val.__query
187
324
  };
@@ -196,16 +333,20 @@ function replaceSubQuery(filter) {
196
333
  });
197
334
  return ret;
198
335
  }
336
+ function encodePathSegment(value) {
337
+ if (value === void 0 || value === null) return "";
338
+ return encodeURIComponent(String(value));
339
+ }
199
340
  function template(templateString, data) {
200
341
  return templateString.replace(/\{\{(\w+)\}\}/g, (match, key) => {
201
- return data[key] !== void 0 ? data[key] : match;
342
+ return data[key] !== void 0 ? encodePathSegment(data[key]) : match;
202
343
  });
203
344
  }
204
345
  function getWrapContext(url, options, config) {
205
346
  const { queryParams, pathParams } = options ?? {};
206
347
  const finalUrl = pathParams ? template(url, pathParams) : url;
207
- if (queryParams && config) config.params = queryParams;
208
- return { finalUrl, finalConfig: config };
348
+ const finalConfig = queryParams && config ? { ...config, params: queryParams } : queryParams && !config ? { params: queryParams } : config;
349
+ return { finalUrl, finalConfig };
209
350
  }
210
351
 
211
352
  // src/services/wrap.ts
@@ -215,10 +356,12 @@ function resolveUrl(basePath, url) {
215
356
  return basePath ? `${removeTrailingSlash(basePath)}/${removeLeadingSlash(url)}` : url;
216
357
  }
217
358
  function prepareConfig(defaultConfig, cacheValue, requestConfig) {
218
- set(defaultConfig, `headers.${CACHE_HEADER}`, cacheValue);
219
- return mergeConfig(defaultConfig, requestConfig);
359
+ const headerClone = new AxiosHeaders(defaultConfig.headers);
360
+ headerClone.set(CACHE_HEADER, cacheValue);
361
+ const defaulted = { ...defaultConfig, headers: headerClone };
362
+ return mergeConfig(defaulted, requestConfig);
220
363
  }
221
- function createWrapHelper(axios2, basePath) {
364
+ function createWrapHelper(axios3, basePath) {
222
365
  return {
223
366
  wrapGet: (url, defaultConfig = {}) => {
224
367
  const _url = resolveUrl(basePath, url);
@@ -228,7 +371,7 @@ function createWrapHelper(axios2, basePath) {
228
371
  options,
229
372
  prepareConfig(defaultConfig, "true", requestConfig)
230
373
  );
231
- return axios2.get(finalUrl, finalConfig);
374
+ return axios3.get(finalUrl, finalConfig);
232
375
  };
233
376
  },
234
377
  wrapPost: (url, defaultConfig = {}) => {
@@ -239,7 +382,7 @@ function createWrapHelper(axios2, basePath) {
239
382
  options,
240
383
  prepareConfig(defaultConfig, "false", requestConfig)
241
384
  );
242
- return axios2.post(finalUrl, data, finalConfig);
385
+ return axios3.post(finalUrl, data, finalConfig);
243
386
  };
244
387
  },
245
388
  wrapPut: (url, defaultConfig = {}) => {
@@ -250,7 +393,7 @@ function createWrapHelper(axios2, basePath) {
250
393
  options,
251
394
  prepareConfig(defaultConfig, "false", requestConfig)
252
395
  );
253
- return axios2.put(finalUrl, data, finalConfig);
396
+ return axios3.put(finalUrl, data, finalConfig);
254
397
  };
255
398
  },
256
399
  wrapPatch: (url, defaultConfig = {}) => {
@@ -261,7 +404,7 @@ function createWrapHelper(axios2, basePath) {
261
404
  options,
262
405
  prepareConfig(defaultConfig, "false", requestConfig)
263
406
  );
264
- return axios2.patch(finalUrl, data, finalConfig);
407
+ return axios3.patch(finalUrl, data, finalConfig);
265
408
  };
266
409
  },
267
410
  wrapDelete: (url, defaultConfig = {}) => {
@@ -272,7 +415,7 @@ function createWrapHelper(axios2, basePath) {
272
415
  options,
273
416
  prepareConfig(defaultConfig, "false", requestConfig)
274
417
  );
275
- return axios2.delete(finalUrl, finalConfig);
418
+ return axios3.delete(finalUrl, finalConfig);
276
419
  };
277
420
  }
278
421
  };
@@ -322,38 +465,77 @@ var stringifyErrorPayload = (value) => {
322
465
  return String(value);
323
466
  }
324
467
  };
468
+ function finalizeOperationResult({
469
+ success,
470
+ raw,
471
+ status,
472
+ headers = {},
473
+ message,
474
+ totalCount
475
+ }) {
476
+ if (success) {
477
+ return {
478
+ success: true,
479
+ raw,
480
+ data: raw,
481
+ message: "",
482
+ status,
483
+ headers,
484
+ ...totalCount == null ? {} : { totalCount }
485
+ };
486
+ }
487
+ return {
488
+ success: false,
489
+ raw,
490
+ data: null,
491
+ message: message ?? stringifyErrorPayload(raw),
492
+ status,
493
+ headers,
494
+ ...totalCount == null ? {} : { totalCount }
495
+ };
496
+ }
497
+ var normalizeTransportFailure = (error) => {
498
+ const transportError = error && typeof error === "object" ? error : {};
499
+ let raw = null;
500
+ let status = 0;
501
+ let headers = {};
502
+ let message;
503
+ if (transportError.response) {
504
+ status = transportError.response.status;
505
+ headers = transportError.response.headers;
506
+ raw = transportError.response.data;
507
+ } else if (transportError.request) {
508
+ message = "The server is not responding";
509
+ } else {
510
+ message = transportError.message;
511
+ }
512
+ return finalizeOperationResult({ success: false, raw, status, headers, message });
513
+ };
325
514
  var Service = class {
326
- constructor(axios2, basePath) {
327
- this._axios = axios2;
515
+ constructor(axios3, basePath, throwOnError = false) {
516
+ this._axios = axios3;
328
517
  this._basePath = basePath;
329
- this._wrap = createWrapHelper(axios2, basePath);
518
+ this._wrap = createWrapHelper(axios3, basePath);
519
+ this._throwOnError = throwOnError;
330
520
  }
331
521
  handleSuccess(res, extra = {}) {
332
- return { success: true, raw: res.data, status: res.status, headers: res.headers, ...extra };
522
+ return {
523
+ ...finalizeOperationResult({
524
+ success: true,
525
+ raw: res.data,
526
+ status: res.status,
527
+ headers: res.headers
528
+ }),
529
+ ...extra
530
+ };
333
531
  }
334
532
  // See https://axios-http.com/docs/handling-errors
335
533
  handleError(error) {
336
- const result = {
337
- success: false,
338
- raw: null,
339
- data: null,
340
- message: "",
341
- status: 0,
342
- headers: {}
343
- };
344
- if (error.response) {
345
- result.status = error.response.status;
346
- result.headers = error.response.headers;
347
- const responseData = error.response.data;
348
- result.raw = responseData;
349
- result.data = responseData;
350
- result.message = stringifyErrorPayload(responseData);
351
- } else if (error.request) {
352
- result.message = "The server is not responding";
353
- } else {
354
- result.message = error.message;
355
- }
356
- return result;
534
+ return normalizeTransportFailure(error);
535
+ }
536
+ /** Resolves per-call policy against the already-resolved service/adapter default. */
537
+ resolveThrowOnError(override) {
538
+ return override ?? this._throwOnError;
357
539
  }
358
540
  wrapGet(url, defaultAxiosRequestConfig = {}) {
359
541
  return this._wrap.wrapGet(url, defaultAxiosRequestConfig);
@@ -370,15 +552,40 @@ var Service = class {
370
552
  wrapDelete(url, defaultAxiosRequestConfig = {}) {
371
553
  return this._wrap.wrapDelete(url, defaultAxiosRequestConfig);
372
554
  }
555
+ /**
556
+ * Public bridge to the per-service success/failure callback pipeline and
557
+ * `throwOnError` policy. Adapter-internal grouping machinery calls this so
558
+ * that grouped entries go through the same finalization the direct path
559
+ * uses (`createResponseHandler`). Returns `res` unchanged on success and
560
+ * throws `ServiceError` when both `res.success === false` and the
561
+ * `throwOnError` override (or the service-level default) are enabled.
562
+ */
563
+ applyResponseCallbacks(res, throwOnErrorOverride) {
564
+ const handler = this._handleCallbacks;
565
+ return handler ? handler(res, throwOnErrorOverride) : res;
566
+ }
567
+ /**
568
+ * Returns a fresh headers object that includes the package-owned
569
+ * `CACHE_HEADER` set to `"true"` (cache eligible) or `"false"` (bypass)
570
+ * according to the `ignoreCache` option. The caller's `CACHE_HEADER`
571
+ * value, if any, wins over the `ignoreCache` default.
572
+ *
573
+ * The input `headers` object is **never mutated**: an `AxiosHeaders`
574
+ * instance is cloned via `.toJSON()` before any value is set, and a
575
+ * plain-object headers input is shallow-copied. Reusing the same
576
+ * caller-owned headers across multiple requests therefore has no
577
+ * hidden side effects, and the order of invocations is irrelevant.
578
+ */
373
579
  updateHeaders(headers, { ignoreCache }) {
374
580
  const cacheValue = ignoreCache ? "false" : "true";
375
581
  if (!headers) {
376
582
  return { [CACHE_HEADER]: cacheValue };
377
583
  }
378
- if (headers instanceof AxiosHeaders) {
584
+ if (headers instanceof AxiosHeaders2) {
379
585
  if (headers.has(CACHE_HEADER)) return headers;
380
- headers.set(CACHE_HEADER, cacheValue);
381
- return headers;
586
+ const cloned = new AxiosHeaders2(headers.toJSON());
587
+ cloned.set(CACHE_HEADER, cacheValue);
588
+ return cloned;
382
589
  }
383
590
  if (CACHE_HEADER in headers) return headers;
384
591
  return {
@@ -391,16 +598,399 @@ var ServiceError = class extends Error {
391
598
  constructor(result) {
392
599
  super(result.message);
393
600
  this.name = "ServiceError";
394
- this.success = result.success;
601
+ this.success = false;
395
602
  this.raw = result.raw;
396
- this.data = result.data;
603
+ this.data = null;
397
604
  this.status = result.status;
398
605
  this.headers = result.headers;
399
606
  }
400
607
  };
401
608
 
609
+ // src/services/interceptors.ts
610
+ import axios, { AxiosHeaders as AxiosHeaders4 } from "axios";
611
+
612
+ // src/services/cache-utils.ts
613
+ import { AxiosHeaders as AxiosHeaders3 } from "axios";
614
+ import { omitBy } from "@web-ts-toolkit/utils";
615
+ var normalizeConfigValue = (value) => {
616
+ if (value == null) return value;
617
+ if (value instanceof AxiosHeaders3) {
618
+ return normalizeConfigValue(value.toJSON());
619
+ }
620
+ if (Array.isArray(value)) {
621
+ return value.map((item) => normalizeConfigValue(item));
622
+ }
623
+ if (typeof value === "object") {
624
+ return Object.entries(omitBy(value, (item) => item === void 0)).sort(([left], [right]) => left.localeCompare(right)).reduce((acc, [key, item]) => {
625
+ acc[key] = normalizeConfigValue(item);
626
+ return acc;
627
+ }, {});
628
+ }
629
+ return value;
630
+ };
631
+
632
+ // src/services/interceptors.ts
633
+ var DEFAULT_CACHE_CAPACITY = 100;
634
+ var CACHEABLE_METHODS = /* @__PURE__ */ new Set(["get"]);
635
+ var MUTATION_METHODS = /* @__PURE__ */ new Set(["post", "put", "patch", "delete"]);
636
+ var CACHEABLE_RESPONSE_TYPES = /* @__PURE__ */ new Set(["", "json", "text"]);
637
+ var SENSITIVE_CACHE_HEADERS = /* @__PURE__ */ new Set([
638
+ "authorization",
639
+ "cookie",
640
+ "set-cookie",
641
+ "proxy-authorization",
642
+ "www-authenticate"
643
+ ]);
644
+ var cloneConfigWithCacheBypass = (config) => {
645
+ const baseConfig = config ?? {};
646
+ const next = { ...baseConfig };
647
+ const sourceHeaders = config?.headers;
648
+ if (sourceHeaders instanceof AxiosHeaders4) {
649
+ next.headers = sourceHeaders.toJSON();
650
+ } else if (sourceHeaders && typeof sourceHeaders === "object") {
651
+ next.headers = { ...sourceHeaders };
652
+ } else {
653
+ next.headers = {};
654
+ }
655
+ next.headers[CACHE_HEADER] = "false";
656
+ return next;
657
+ };
658
+ var SimpleCache = class {
659
+ constructor(opts = {}) {
660
+ this.cache = /* @__PURE__ */ new Map();
661
+ this.timers = /* @__PURE__ */ new Map();
662
+ this.capacity = opts.capacity !== void 0 && Number.isFinite(opts.capacity) && opts.capacity > 0 ? Math.floor(opts.capacity) : DEFAULT_CACHE_CAPACITY;
663
+ this.clone = opts.clone ?? defaultClone;
664
+ }
665
+ set(key, value, ttl) {
666
+ if (this.cache.size >= this.capacity && !this.cache.has(key)) {
667
+ const oldestKey = this.cache.keys().next().value;
668
+ if (oldestKey !== void 0) {
669
+ this.delete(oldestKey);
670
+ }
671
+ }
672
+ this.cache.delete(key);
673
+ this.cache.set(key, value);
674
+ if (ttl && ttl > 0) {
675
+ const existing = this.timers.get(key);
676
+ if (existing) clearTimeout(existing);
677
+ const timer = setTimeout(() => {
678
+ this.cache.delete(key);
679
+ this.timers.delete(key);
680
+ }, ttl);
681
+ if (typeof timer === "object" && timer && "unref" in timer && typeof timer.unref === "function") {
682
+ timer.unref();
683
+ }
684
+ this.timers.set(key, timer);
685
+ }
686
+ }
687
+ get(key) {
688
+ const value = this.cache.get(key);
689
+ if (value === void 0) {
690
+ return void 0;
691
+ }
692
+ this.cache.delete(key);
693
+ this.cache.set(key, value);
694
+ return this.clone(value);
695
+ }
696
+ has(key) {
697
+ return this.cache.has(key);
698
+ }
699
+ delete(key) {
700
+ const timer = this.timers.get(key);
701
+ if (timer) {
702
+ clearTimeout(timer);
703
+ this.timers.delete(key);
704
+ }
705
+ return this.cache.delete(key);
706
+ }
707
+ clear() {
708
+ for (const timer of this.timers.values()) {
709
+ clearTimeout(timer);
710
+ }
711
+ this.timers.clear();
712
+ this.cache.clear();
713
+ }
714
+ dispose() {
715
+ this.clear();
716
+ }
717
+ };
718
+ var defaultClone = (value) => {
719
+ if (value == null) return value;
720
+ try {
721
+ return JSON.parse(JSON.stringify(value));
722
+ } catch {
723
+ return value;
724
+ }
725
+ };
726
+ var CACHE_REQUEST_STATE = /* @__PURE__ */ Symbol("access-router-client.cache-request-state");
727
+ var CACHE_DISPOSED_ERROR = "Access router client cache was disposed while the request was in flight";
728
+ var setCacheRequestState = (config, state) => {
729
+ Object.defineProperty(config, CACHE_REQUEST_STATE, {
730
+ configurable: false,
731
+ enumerable: false,
732
+ writable: false,
733
+ value: Object.freeze(state)
734
+ });
735
+ };
736
+ var isUnsupportedResponseBody = (response) => {
737
+ const responseType = response.config?.responseType;
738
+ if (responseType === "stream" || responseType === "arraybuffer" || responseType === "blob" || responseType === "document") {
739
+ return true;
740
+ }
741
+ const data = response.data;
742
+ if (data == null) return false;
743
+ if (typeof data === "string") return false;
744
+ if (typeof data !== "object") return false;
745
+ if (Array.isArray(data)) return false;
746
+ try {
747
+ JSON.stringify(data);
748
+ return false;
749
+ } catch {
750
+ return true;
751
+ }
752
+ };
753
+ var snapshotResponse = (response) => {
754
+ const headers = response.headers instanceof AxiosHeaders4 ? response.headers.toJSON() : { ...response.headers ?? {} };
755
+ return {
756
+ data: defaultClone(response.data),
757
+ status: response.status,
758
+ statusText: response.statusText,
759
+ headers: defaultClone(headers)
760
+ };
761
+ };
762
+ var serializeHeaders = (headers) => {
763
+ const resolvedHeaders = headers instanceof AxiosHeaders4 ? headers.toJSON() : headers;
764
+ const normalizedHeaders = Object.entries(resolvedHeaders ?? {}).filter(([key, value]) => {
765
+ const normalizedKey = key.toLowerCase();
766
+ return normalizedKey !== CACHE_HEADER.toLowerCase() && !SENSITIVE_CACHE_HEADERS.has(normalizedKey) && value !== void 0;
767
+ }).reduce((acc, [key, value]) => {
768
+ acc[key.toLowerCase()] = value;
769
+ return acc;
770
+ }, {});
771
+ return JSON.stringify(normalizeConfigValue(normalizedHeaders));
772
+ };
773
+ var hasStableCacheValue = (value, seen = /* @__PURE__ */ new Set()) => {
774
+ if (value == null || typeof value === "string" || typeof value === "number" || typeof value === "boolean")
775
+ return true;
776
+ if (typeof value !== "object") return false;
777
+ if (seen.has(value)) return false;
778
+ if (value instanceof AxiosHeaders4) {
779
+ return hasStableCacheValue(value.toJSON(), seen);
780
+ }
781
+ const prototype = Object.getPrototypeOf(value);
782
+ if (!Array.isArray(value) && prototype !== Object.prototype && prototype !== null) return false;
783
+ seen.add(value);
784
+ const stable = Object.values(value).every((item) => hasStableCacheValue(item, seen));
785
+ seen.delete(value);
786
+ return stable;
787
+ };
788
+ var sameTransform = (configured, defaultValue) => {
789
+ const configuredList = Array.isArray(configured) ? configured : [configured];
790
+ const defaultList = Array.isArray(defaultValue) ? defaultValue : [defaultValue];
791
+ return configuredList.length === defaultList.length && configuredList.every((item, index) => item === defaultList[index]);
792
+ };
793
+ var sameConfigIdentity = (configured, defaultValue) => {
794
+ if (Array.isArray(configured) && Array.isArray(defaultValue)) {
795
+ return configured.length === defaultValue.length && configured.every((item, index) => item === defaultValue[index]);
796
+ }
797
+ return configured === defaultValue;
798
+ };
799
+ var isCacheEligible = (config, instance) => {
800
+ const method = (config.method ?? "get").toLowerCase();
801
+ const responseType = config.responseType ?? "";
802
+ return CACHEABLE_METHODS.has(method) && CACHEABLE_RESPONSE_TYPES.has(responseType) && config.paramsSerializer === void 0 && config.auth === void 0 && config.signal === void 0 && config.cancelToken === void 0 && config.onDownloadProgress === void 0 && config.onUploadProgress === void 0 && sameConfigIdentity(config.adapter, instance.defaults.adapter) && sameTransform(config.transformRequest, instance.defaults.transformRequest) && sameTransform(config.transformResponse, instance.defaults.transformResponse) && hasStableCacheValue(config.params) && hasStableCacheValue(config.data) && hasStableCacheValue(config.headers);
803
+ };
804
+ function generateCacheKey(config, partition) {
805
+ const responseSemantics = JSON.stringify({
806
+ responseType: config.responseType ?? "",
807
+ responseEncoding: config.responseEncoding ?? "",
808
+ decompress: config.decompress ?? true,
809
+ timeout: config.timeout ?? 0,
810
+ maxContentLength: config.maxContentLength ?? -1,
811
+ maxBodyLength: config.maxBodyLength ?? -1,
812
+ withCredentials: Boolean(config.withCredentials),
813
+ transitional: normalizeConfigValue(config.transitional)
814
+ });
815
+ const key = `${config.baseURL}/${config.url}_${config.method}_${generateParamKey(config.params)}_${generateDataKey(
816
+ config.data
817
+ )}_${partition ?? ""}_${serializeHeaders(config.headers)}_${responseSemantics}`;
818
+ return encodeURI(key);
819
+ }
820
+ function generateParamKey(params) {
821
+ if (!params) return "";
822
+ return JSON.stringify(normalizeConfigValue(params));
823
+ }
824
+ function generateDataKey(data) {
825
+ if (!data) return "";
826
+ return typeof data === "string" ? data : JSON.stringify(normalizeConfigValue(data));
827
+ }
828
+ var resolveWithCredentials = (config, withCredentialsDefault) => {
829
+ if (config.withCredentials !== void 0) {
830
+ return Boolean(config.withCredentials);
831
+ }
832
+ return withCredentialsDefault;
833
+ };
834
+ function useCacheInterceptors(instance, policyOrTtl) {
835
+ const policy = typeof policyOrTtl === "number" ? { ttl: policyOrTtl } : policyOrTtl;
836
+ const store = new SimpleCache({ capacity: policy.capacity, clone: policy.clone });
837
+ const withCredentialsDefault = policy.withCredentialsDefault ?? Boolean(instance.defaults.withCredentials);
838
+ const inflight = /* @__PURE__ */ new Map();
839
+ let generation = 0;
840
+ let disposed = false;
841
+ const finalizeInflight = (slot) => {
842
+ if (inflight.get(slot.key) === slot) {
843
+ inflight.delete(slot.key);
844
+ }
845
+ };
846
+ const resolveInflight = (slot, response) => {
847
+ if (slot.settled) return;
848
+ slot.settled = true;
849
+ slot.resolve(response);
850
+ finalizeInflight(slot);
851
+ };
852
+ const rejectInflight = (slot, error) => {
853
+ if (slot.settled) return;
854
+ slot.settled = true;
855
+ slot.reject(error);
856
+ finalizeInflight(slot);
857
+ };
858
+ const invalidate = () => {
859
+ generation += 1;
860
+ store.clear();
861
+ inflight.clear();
862
+ };
863
+ instance.interceptors.request.use(
864
+ async (config) => {
865
+ if (disposed || config.headers[CACHE_HEADER] === "false" || !isCacheEligible(config, instance)) return config;
866
+ const isCredentialed = resolveWithCredentials(config, withCredentialsDefault);
867
+ const partitionKey = policy.partitionForRequest?.(config);
868
+ if (isCredentialed && !partitionKey) {
869
+ return config;
870
+ }
871
+ const key = generateCacheKey(config, partitionKey);
872
+ policy.onCacheKey?.(key);
873
+ const snapshot = store.get(key);
874
+ if (snapshot) {
875
+ setCacheRequestState(config, Object.freeze({ key, generation, role: "hit" }));
876
+ config.adapter = async (_config) => {
877
+ return {
878
+ data: snapshot.data,
879
+ status: snapshot.status,
880
+ statusText: snapshot.statusText,
881
+ headers: { ...snapshot.headers, [CACHE_HEADER]: "true" },
882
+ config: _config
883
+ };
884
+ };
885
+ return config;
886
+ }
887
+ const existing = inflight.get(key);
888
+ if (existing) {
889
+ config.adapter = async (_config) => {
890
+ const response = await existing.promise;
891
+ const shared = response;
892
+ return {
893
+ data: defaultClone(shared.data),
894
+ status: shared.status,
895
+ statusText: shared.statusText,
896
+ headers: { ...shared.headers, [CACHE_HEADER]: "true" },
897
+ config: _config
898
+ };
899
+ };
900
+ setCacheRequestState(config, Object.freeze({ key, generation, role: "tail", slot: existing }));
901
+ return config;
902
+ }
903
+ let resolvePromise;
904
+ let rejectPromise;
905
+ const inflightPromise = new Promise((resolve, reject) => {
906
+ resolvePromise = resolve;
907
+ rejectPromise = reject;
908
+ });
909
+ inflightPromise.catch(() => {
910
+ });
911
+ const slot = {
912
+ key,
913
+ generation,
914
+ promise: inflightPromise,
915
+ resolve: resolvePromise,
916
+ reject: rejectPromise,
917
+ settled: false
918
+ };
919
+ inflight.set(key, slot);
920
+ const nextConfig = { ...config };
921
+ setCacheRequestState(nextConfig, Object.freeze({ key, generation, role: "source", slot }));
922
+ let realAdapter = config.adapter;
923
+ if (realAdapter === void 0 || realAdapter === null) {
924
+ realAdapter = instance.defaults.adapter;
925
+ }
926
+ const dispatch = typeof realAdapter === "function" ? realAdapter : typeof axios.getAdapter === "function" ? axios.getAdapter(
927
+ realAdapter,
928
+ instance.defaults
929
+ ) : void 0;
930
+ nextConfig.adapter = async (adapterConfig) => {
931
+ if (!dispatch) {
932
+ const response = await adapterConfig.adapter;
933
+ return response;
934
+ }
935
+ try {
936
+ const response = await dispatch(adapterConfig);
937
+ return response;
938
+ } catch (error) {
939
+ rejectInflight(slot, error);
940
+ throw error;
941
+ }
942
+ };
943
+ return nextConfig;
944
+ },
945
+ (error) => Promise.reject(error)
946
+ );
947
+ instance.interceptors.response.use(
948
+ (response) => {
949
+ const method = (response.config.method ?? "get").toLowerCase();
950
+ if (response.config.headers[CACHE_HEADER] === "false" || MUTATION_METHODS.has(method)) {
951
+ if (response.status >= 200 && response.status < 300) {
952
+ invalidate();
953
+ }
954
+ return response;
955
+ }
956
+ const state = response.config[CACHE_REQUEST_STATE];
957
+ if (!state || state.role !== "source" || !state.slot) {
958
+ return response;
959
+ }
960
+ if (response.status >= 200 && response.status < 300) {
961
+ if (!disposed && state.generation === generation && !isUnsupportedResponseBody(response)) {
962
+ store.set(state.key, snapshotResponse(response), policy.ttl);
963
+ }
964
+ }
965
+ resolveInflight(state.slot, response);
966
+ return response;
967
+ },
968
+ (error) => {
969
+ const state = (error?.config ?? {})[CACHE_REQUEST_STATE];
970
+ if (state?.role === "source" && state.slot) {
971
+ rejectInflight(state.slot, error);
972
+ }
973
+ return Promise.reject(error);
974
+ }
975
+ );
976
+ return {
977
+ clear: invalidate,
978
+ dispose: () => {
979
+ if (disposed) return;
980
+ disposed = true;
981
+ generation += 1;
982
+ store.dispose();
983
+ const error = new Error(CACHE_DISPOSED_ERROR);
984
+ for (const slot of inflight.values()) {
985
+ rejectInflight(slot, error);
986
+ }
987
+ inflight.clear();
988
+ }
989
+ };
990
+ }
991
+
402
992
  // src/services/shared.ts
403
- import { get, noop, set as set2 } from "@web-ts-toolkit/utils";
993
+ import { castArray, get, noop, set } from "@web-ts-toolkit/utils";
404
994
 
405
995
  // src/enums.ts
406
996
  var CustomHeaders = /* @__PURE__ */ ((CustomHeaders2) => {
@@ -415,10 +1005,118 @@ var CustomHeaders = /* @__PURE__ */ ((CustomHeaders2) => {
415
1005
  })(CustomHeaders || {});
416
1006
 
417
1007
  // src/services/shared.ts
1008
+ var getSubdocumentResultShape = (query) => {
1009
+ if (query.target !== "model") return void 0;
1010
+ switch (query.op) {
1011
+ case "subList":
1012
+ case "subCreate":
1013
+ case "subBulkUpdate":
1014
+ return "list";
1015
+ case "subRead":
1016
+ case "subUpdate":
1017
+ return "single";
1018
+ case "subDelete":
1019
+ return "scalar";
1020
+ default:
1021
+ return void 0;
1022
+ }
1023
+ };
1024
+ function finalizeRootEntry(query, entry, responseHeaders, service) {
1025
+ const { result, message: entryMessage, statusCode, op } = entry;
1026
+ const success = result.success;
1027
+ const baseResult = finalizeOperationResult({
1028
+ success,
1029
+ raw: success ? result.data : result,
1030
+ status: statusCode,
1031
+ headers: responseHeaders,
1032
+ message: success ? void 0 : entryMessage
1033
+ });
1034
+ let _raw = baseResult.raw;
1035
+ let _data = baseResult.data;
1036
+ const subdocumentResultShape = getSubdocumentResultShape(query);
1037
+ if (!success) {
1038
+ _data = null;
1039
+ } else if (subdocumentResultShape) {
1040
+ if (subdocumentResultShape === "list") {
1041
+ const rows = result.data == null ? [] : castArray(result.data);
1042
+ _raw = rows;
1043
+ _data = rows;
1044
+ }
1045
+ } else if (query.target === "model") {
1046
+ const modelService = service;
1047
+ if (result.kind === "list" && Array.isArray(result.data)) {
1048
+ if (op === "create" && !Array.isArray(query.data) && result.data.length === 1) {
1049
+ _raw = result.data[0];
1050
+ if (modelService) {
1051
+ _data = Model.create(result.data[0], modelService, void 0, true);
1052
+ }
1053
+ } else if (op !== "distinct") {
1054
+ const rows = castArray(result.data);
1055
+ if (modelService) {
1056
+ _data = rows.map((item) => Model.create(item, modelService, void 0, true));
1057
+ } else {
1058
+ _data = rows;
1059
+ }
1060
+ }
1061
+ } else if (result.kind === "single" && (op === "new" || op === "read" || op === "update" || op === "upsert")) {
1062
+ if (op === "new" && result.data && typeof result.data === "object") {
1063
+ const { _id: _generatedId, ...draft } = result.data;
1064
+ void _generatedId;
1065
+ _raw = draft;
1066
+ _data = draft;
1067
+ }
1068
+ if (modelService) {
1069
+ const fromExisting = op !== "new";
1070
+ const persistenceId = op === "read" && query.target === "model" && "id" in query ? query.id : void 0;
1071
+ _data = Model.create(_data, modelService, persistenceId, fromExisting);
1072
+ }
1073
+ }
1074
+ }
1075
+ const isSubdocumentList = subdocumentResultShape === "list";
1076
+ const isModelOrDataList = !subdocumentResultShape && query.op === "list";
1077
+ const returnedCount = Array.isArray(_data) ? _data.length : 0;
1078
+ const totalCount = success && query.options?.includeCount === true ? result.totalCount ?? result.count ?? returnedCount : 0;
1079
+ return {
1080
+ success,
1081
+ raw: _raw,
1082
+ data: _data,
1083
+ message: baseResult.message,
1084
+ status: statusCode,
1085
+ ...isSubdocumentList ? { count: success ? returnedCount : 0 } : {},
1086
+ ...isModelOrDataList ? { totalCount } : {},
1087
+ headers: responseHeaders
1088
+ };
1089
+ }
1090
+ function finalizeRootTransportFailure(query, error) {
1091
+ const failure = normalizeTransportFailure(error);
1092
+ const subdocumentResultShape = getSubdocumentResultShape(query);
1093
+ return {
1094
+ ...failure,
1095
+ ...subdocumentResultShape === "list" ? { count: 0 } : {},
1096
+ ...!subdocumentResultShape && query.op === "list" ? { totalCount: 0 } : {}
1097
+ };
1098
+ }
1099
+ function applyGroupCallbacks(entries, services, groupThrowOnError) {
1100
+ let callbackError;
1101
+ for (let i = 0; i < entries.length; i++) {
1102
+ const svc = services[i];
1103
+ try {
1104
+ entries[i] = svc?.applyResponseCallbacks ? svc.applyResponseCallbacks(entries[i], false) : entries[i];
1105
+ } catch (error) {
1106
+ callbackError ??= error;
1107
+ }
1108
+ }
1109
+ if (callbackError) throw callbackError;
1110
+ if (groupThrowOnError) {
1111
+ const failure = entries.find((entry) => !entry.success);
1112
+ if (failure) throw new ServiceError(toResultError(failure));
1113
+ }
1114
+ return entries;
1115
+ }
418
1116
  var toResultError = (result) => ({
419
1117
  success: false,
420
1118
  raw: result.raw ?? null,
421
- data: result.data ?? null,
1119
+ data: null,
422
1120
  message: result.message ?? "",
423
1121
  status: result.status ?? 0,
424
1122
  headers: result.headers ?? {}
@@ -431,9 +1129,13 @@ var isLegacyListPayload = (value) => {
431
1129
  };
432
1130
  var setDefaultObjectProp = (obj, key, value) => {
433
1131
  if (!get(obj, key)) {
434
- set2(obj, key, value);
1132
+ set(obj, key, value);
435
1133
  }
436
1134
  };
1135
+ var ensureListResultCount = (result) => {
1136
+ result.totalCount ??= 0;
1137
+ return result;
1138
+ };
437
1139
  var createResponseHandler = (onSuccess, onFailure, throwOnError) => {
438
1140
  const successHandler = onSuccess ?? noop;
439
1141
  const failureHandler = onFailure ?? noop;
@@ -450,6 +1152,7 @@ var createResponseHandler = (onSuccess, onFailure, throwOnError) => {
450
1152
  };
451
1153
  };
452
1154
  function processListResult(result, { includeCount, includeExtraHeaders }, wrapItem) {
1155
+ ensureListResultCount(result);
453
1156
  const wrappedRows = get(result, "raw.data");
454
1157
  const wrappedTotalCount = get(result, "raw.meta.totalCount");
455
1158
  if (Array.isArray(wrappedRows)) {
@@ -482,11 +1185,40 @@ function processListResult(result, { includeCount, includeExtraHeaders }, wrapIt
482
1185
  }
483
1186
 
484
1187
  // src/lazy-promise.ts
1188
+ var STARTED_KEY = /* @__PURE__ */ Symbol("started");
1189
+ var executionClaims = /* @__PURE__ */ new WeakMap();
1190
+ var claimLazyRequest = (request, mode, owner) => {
1191
+ const claim = executionClaims.get(request);
1192
+ if (!claim) {
1193
+ executionClaims.set(request, { mode, owner });
1194
+ return;
1195
+ }
1196
+ if (mode === "grouped") {
1197
+ if (claim.mode === "direct") {
1198
+ throw new Error(
1199
+ "Cannot group a request that has already started execution; group() must be called before await/then/catch/finally/exec on each input"
1200
+ );
1201
+ }
1202
+ throw new Error("Cannot group a request already claimed for grouped execution");
1203
+ }
1204
+ throw new Error("Cannot execute a request already claimed for grouped execution");
1205
+ };
1206
+ var releaseLazyRequestClaim = (request, owner) => {
1207
+ const claim = executionClaims.get(request);
1208
+ if (claim?.mode === "grouped" && claim.owner === owner) {
1209
+ executionClaims.delete(request);
1210
+ }
1211
+ };
485
1212
  var wrapLazyPromise = (promiseFn, meta) => {
486
1213
  let promise;
487
1214
  const exec = () => {
488
1215
  if (!promise) {
489
- promise = promiseFn();
1216
+ try {
1217
+ claimLazyRequest(prom, "direct");
1218
+ promise = Promise.resolve().then(promiseFn);
1219
+ } catch (error) {
1220
+ promise = Promise.reject(error);
1221
+ }
490
1222
  }
491
1223
  return promise;
492
1224
  };
@@ -509,32 +1241,62 @@ var wrapLazyPromise = (promiseFn, meta) => {
509
1241
  value: "Promise",
510
1242
  writable: false,
511
1243
  enumerable: false,
512
- configurable: true
1244
+ configurable: false
1245
+ });
1246
+ Object.defineProperty(prom, STARTED_KEY, {
1247
+ get: () => executionClaims.has(prom),
1248
+ enumerable: false,
1249
+ configurable: false
513
1250
  });
514
- Object.assign(prom, meta);
1251
+ if (meta != null) {
1252
+ const metaKeys = Object.keys(meta);
1253
+ for (let i = 0; i < metaKeys.length; i++) {
1254
+ const key = metaKeys[i];
1255
+ Object.defineProperty(prom, key, {
1256
+ value: meta[key],
1257
+ enumerable: false,
1258
+ writable: false,
1259
+ configurable: false
1260
+ });
1261
+ }
1262
+ }
515
1263
  return prom;
516
1264
  };
517
1265
 
518
1266
  // src/services/request.ts
519
1267
  function makeRequest(execute, meta) {
520
- return wrapLazyPromise(execute, meta);
1268
+ const effectiveMeta = {
1269
+ ...meta,
1270
+ __throwOnError: meta.__service?.resolveThrowOnError(meta.__throwOnError) ?? Boolean(meta.__throwOnError)
1271
+ };
1272
+ return wrapLazyPromise(execute, effectiveMeta);
521
1273
  }
522
1274
 
523
1275
  // src/services/sub-ops.ts
524
1276
  import { mergeConfig as mergeConfig2 } from "axios";
1277
+ var toArray = (value) => Array.isArray(value) ? value : value == null ? [] : [value];
1278
+ var ensureSubdocumentListCount = (result) => {
1279
+ result.count ??= 0;
1280
+ return result;
1281
+ };
525
1282
  function buildSubDocumentOps(ctx, id, sub) {
526
- const { axios: axios2, basePath, modelName, queryPath, handleSuccess, handleError, _handleCallbacks, parentService } = ctx;
527
- const asS = parentService;
1283
+ const { axios: axios3, basePath, modelName, queryPath, handleSuccess, handleError, _handleCallbacks, parentService } = ctx;
528
1284
  return {
529
1285
  list: (axiosRequestConfig) => {
530
1286
  const { throwOnError, ...reqConfig } = axiosRequestConfig ?? {};
531
1287
  return makeRequest(
532
- () => axios2.get(`${basePath}/${id}/${sub}`, mergeConfig2(reqConfig, { params: {} })).then(handleSuccess).then((result) => {
533
- result.totalCount = Array.isArray(result.raw) ? result.raw.length : 0;
534
- result.data = Array.isArray(result.raw) ? result.raw.map((item) => Model.create(item, asS)) : [];
1288
+ () => axios3.get(
1289
+ `${basePath}/${encodePathSegment(id)}/${encodePathSegment(sub)}`,
1290
+ mergeConfig2(reqConfig, { params: {} })
1291
+ ).then(handleSuccess).then((result) => {
1292
+ const rawArray = toArray(result.raw);
1293
+ result.raw = rawArray;
1294
+ result.count = rawArray.length;
1295
+ result.data = rawArray;
535
1296
  return result;
536
- }).catch(handleError).then((res) => _handleCallbacks(res, throwOnError)),
1297
+ }).catch(handleError).then(ensureSubdocumentListCount).then((res) => _handleCallbacks(res, throwOnError)),
537
1298
  {
1299
+ __throwOnError: throwOnError,
538
1300
  __op: "listSub",
539
1301
  __query: {
540
1302
  target: "model",
@@ -556,14 +1318,21 @@ function buildSubDocumentOps(ctx, id, sub) {
556
1318
  const select = args?.select;
557
1319
  const { throwOnError, ...reqConfig } = axiosRequestConfig ?? {};
558
1320
  return makeRequest(
559
- () => axios2.post(`${basePath}/${id}/${sub}/${queryPath}`, { filter, select }, reqConfig).then(handleSuccess).then((result) => {
560
- result.totalCount = Array.isArray(result.raw) ? result.raw.length : 0;
561
- result.data = Array.isArray(result.raw) ? result.raw.map((item) => Model.create(item, asS)) : [];
1321
+ () => axios3.post(
1322
+ `${basePath}/${encodePathSegment(id)}/${encodePathSegment(sub)}/${queryPath}`,
1323
+ { filter, select },
1324
+ reqConfig
1325
+ ).then(handleSuccess).then((result) => {
1326
+ const rawArray = toArray(result.raw);
1327
+ result.raw = rawArray;
1328
+ result.count = rawArray.length;
1329
+ result.data = rawArray;
562
1330
  return result;
563
- }).catch(handleError).then(
1331
+ }).catch(handleError).then(ensureSubdocumentListCount).then(
564
1332
  (res) => _handleCallbacks(res, throwOnError)
565
1333
  ),
566
1334
  {
1335
+ __throwOnError: throwOnError,
567
1336
  __op: "listAdvancedSub",
568
1337
  __query: {
569
1338
  target: "model",
@@ -584,11 +1353,15 @@ function buildSubDocumentOps(ctx, id, sub) {
584
1353
  read: (subId, axiosRequestConfig) => {
585
1354
  const { throwOnError, ...reqConfig } = axiosRequestConfig ?? {};
586
1355
  return makeRequest(
587
- () => axios2.get(`${basePath}/${id}/${sub}/${subId}`, mergeConfig2(reqConfig, { params: {} })).then(handleSuccess).then((result) => {
588
- result.data = result.success ? Model.create(result.raw, asS) : null;
1356
+ () => axios3.get(
1357
+ `${basePath}/${encodePathSegment(id)}/${encodePathSegment(sub)}/${encodePathSegment(subId)}`,
1358
+ mergeConfig2(reqConfig, { params: {} })
1359
+ ).then(handleSuccess).then((result) => {
1360
+ result.data = result.success ? result.raw : null;
589
1361
  return result;
590
1362
  }).catch(handleError).then((res) => _handleCallbacks(res, throwOnError)),
591
1363
  {
1364
+ __throwOnError: throwOnError,
592
1365
  __op: "readSub",
593
1366
  __query: {
594
1367
  target: "model",
@@ -610,13 +1383,18 @@ function buildSubDocumentOps(ctx, id, sub) {
610
1383
  const { select, populate } = args ?? {};
611
1384
  const { throwOnError, ...reqConfig } = axiosRequestConfig ?? {};
612
1385
  return makeRequest(
613
- () => axios2.post(`${basePath}/${id}/${sub}/${subId}/${queryPath}`, { select, populate }, reqConfig).then(handleSuccess).then((result) => {
614
- result.data = result.success ? Model.create(result.raw, asS) : null;
1386
+ () => axios3.post(
1387
+ `${basePath}/${encodePathSegment(id)}/${encodePathSegment(sub)}/${encodePathSegment(subId)}/${queryPath}`,
1388
+ { select, populate },
1389
+ reqConfig
1390
+ ).then(handleSuccess).then((result) => {
1391
+ result.data = result.success ? result.raw : null;
615
1392
  return result;
616
1393
  }).catch(handleError).then(
617
1394
  (res) => _handleCallbacks(res, throwOnError)
618
1395
  ),
619
1396
  {
1397
+ __throwOnError: throwOnError,
620
1398
  __op: "readAdvancedSub",
621
1399
  __query: {
622
1400
  target: "model",
@@ -635,13 +1413,18 @@ function buildSubDocumentOps(ctx, id, sub) {
635
1413
  );
636
1414
  },
637
1415
  update: (subId, data, axiosRequestConfig) => {
638
- const { throwOnError, ...reqConfig } = axiosRequestConfig ?? {};
1416
+ const { throwOnError, ...reqConfig } = cloneConfigWithCacheBypass(axiosRequestConfig ?? {});
639
1417
  return makeRequest(
640
- () => axios2.patch(`${basePath}/${id}/${sub}/${subId}`, data, mergeConfig2(reqConfig, { params: {} })).then(handleSuccess).then((result) => {
641
- result.data = result.success ? Model.create(result.raw, asS) : null;
1418
+ () => axios3.patch(
1419
+ `${basePath}/${encodePathSegment(id)}/${encodePathSegment(sub)}/${encodePathSegment(subId)}`,
1420
+ data,
1421
+ mergeConfig2(reqConfig, { params: {} })
1422
+ ).then(handleSuccess).then((result) => {
1423
+ result.data = result.success ? result.raw : null;
642
1424
  return result;
643
1425
  }).catch(handleError).then((res) => _handleCallbacks(res, throwOnError)),
644
1426
  {
1427
+ __throwOnError: throwOnError,
645
1428
  __op: "updateSub",
646
1429
  __query: {
647
1430
  target: "model",
@@ -660,13 +1443,21 @@ function buildSubDocumentOps(ctx, id, sub) {
660
1443
  );
661
1444
  },
662
1445
  bulkUpdate: (data, axiosRequestConfig) => {
663
- const { throwOnError, ...reqConfig } = axiosRequestConfig ?? {};
1446
+ const { throwOnError, ...reqConfig } = cloneConfigWithCacheBypass(axiosRequestConfig ?? {});
664
1447
  return makeRequest(
665
- () => axios2.patch(`${basePath}/${id}/${sub}`, data, mergeConfig2(reqConfig, { params: {} })).then(handleSuccess).then((result) => {
666
- result.data = Array.isArray(result.raw) ? result.raw.map((item) => Model.create(item, asS)) : [];
1448
+ () => axios3.patch(
1449
+ `${basePath}/${encodePathSegment(id)}/${encodePathSegment(sub)}`,
1450
+ data,
1451
+ mergeConfig2(reqConfig, { params: {} })
1452
+ ).then(handleSuccess).then((result) => {
1453
+ const rawArray = toArray(result.raw);
1454
+ result.raw = rawArray;
1455
+ result.count = rawArray.length;
1456
+ result.data = rawArray;
667
1457
  return result;
668
- }).catch(handleError).then((res) => _handleCallbacks(res, throwOnError)),
1458
+ }).catch(handleError).then(ensureSubdocumentListCount).then((res) => _handleCallbacks(res, throwOnError)),
669
1459
  {
1460
+ __throwOnError: throwOnError,
670
1461
  __op: "bulkUpdateSub",
671
1462
  __query: {
672
1463
  target: "model",
@@ -684,30 +1475,42 @@ function buildSubDocumentOps(ctx, id, sub) {
684
1475
  );
685
1476
  },
686
1477
  create: (data, axiosRequestConfig) => {
687
- const { throwOnError, ...reqConfig } = axiosRequestConfig ?? {};
1478
+ const { throwOnError, ...reqConfig } = cloneConfigWithCacheBypass(axiosRequestConfig ?? {});
688
1479
  return makeRequest(
689
- () => axios2.post(`${basePath}/${id}/${sub}`, data, mergeConfig2(reqConfig, { params: {} })).then(handleSuccess).then((result) => {
690
- result.data = result.success ? Model.create(result.raw, asS) : null;
1480
+ () => axios3.post(
1481
+ `${basePath}/${encodePathSegment(id)}/${encodePathSegment(sub)}`,
1482
+ data,
1483
+ mergeConfig2(reqConfig, { params: {} })
1484
+ ).then(handleSuccess).then((result) => {
1485
+ const rawArray = toArray(result.raw);
1486
+ result.raw = rawArray;
1487
+ result.count = rawArray.length;
1488
+ result.data = rawArray;
691
1489
  return result;
692
- }).catch(handleError).then((res) => _handleCallbacks(res, throwOnError)),
1490
+ }).catch(handleError).then(ensureSubdocumentListCount).then((res) => _handleCallbacks(res, throwOnError)),
693
1491
  {
1492
+ __throwOnError: throwOnError,
694
1493
  __op: "createSub",
695
- __query: { target: "model", name: modelName, model: modelName, op: "subCreate", id, sub, data, options: {} },
1494
+ __query: { target: "model", name: modelName, op: "subCreate", id, sub, data, options: {} },
696
1495
  __requestConfig: reqConfig,
697
1496
  __service: parentService
698
1497
  }
699
1498
  );
700
1499
  },
701
1500
  delete: (subId, axiosRequestConfig) => {
702
- const { throwOnError, ...reqConfig } = axiosRequestConfig ?? {};
1501
+ const { throwOnError, ...reqConfig } = cloneConfigWithCacheBypass(axiosRequestConfig ?? {});
703
1502
  return makeRequest(
704
- () => axios2.delete(`${basePath}/${id}/${sub}/${subId}`, reqConfig).then(handleSuccess).then((result) => {
705
- result.data = result.raw;
1503
+ () => axios3.delete(
1504
+ `${basePath}/${encodePathSegment(id)}/${encodePathSegment(sub)}/${encodePathSegment(subId)}`,
1505
+ reqConfig
1506
+ ).then(handleSuccess).then((result) => {
1507
+ if (result.success) result.data = result.raw;
706
1508
  return result;
707
1509
  }).catch(handleError).then((res) => _handleCallbacks(res, throwOnError)),
708
1510
  {
1511
+ __throwOnError: throwOnError,
709
1512
  __op: "deleteSub",
710
- __query: { target: "model", name: modelName, model: modelName, op: "subDelete", id, sub, subId },
1513
+ __query: { target: "model", name: modelName, op: "subDelete", id, sub, subId },
711
1514
  __requestConfig: reqConfig,
712
1515
  __service: parentService
713
1516
  }
@@ -718,8 +1521,8 @@ function buildSubDocumentOps(ctx, id, sub) {
718
1521
 
719
1522
  // src/services/model-service.ts
720
1523
  var ModelService = class extends Service {
721
- constructor({ axios: axios2, modelName, basePath, queryPath, mutationPath, onSuccess, onFailure, throwOnError }, defaults) {
722
- super(axios2, basePath);
1524
+ constructor({ axios: axios3, modelName, basePath, queryPath, mutationPath, onSuccess, onFailure, throwOnError }, defaults) {
1525
+ super(axios3, basePath, throwOnError);
723
1526
  this._modelName = modelName;
724
1527
  this._queryPath = queryPath;
725
1528
  this._mutationPath = mutationPath;
@@ -783,10 +1586,15 @@ var ModelService = class extends Service {
783
1586
  return processListResult(
784
1587
  result,
785
1588
  { includeCount, includeExtraHeaders },
786
- (item) => Model.create(item, this)
1589
+ // ARC-21: list items come from existing documents, so mark
1590
+ // them as `_fromExisting=true` even if the server response
1591
+ // (or a custom adapter) strips `_id` — a save on such an item
1592
+ // must throw rather than silently re-create.
1593
+ (item) => Model.create(item, this, void 0, true)
787
1594
  );
788
- }).catch(this.handleError).then((res) => this._handleCallbacks(res, throwOnError)),
1595
+ }).catch(this.handleError).then(ensureListResultCount).then((res) => this._handleCallbacks(res, throwOnError)),
789
1596
  {
1597
+ __throwOnError: throwOnError,
790
1598
  __op: "list",
791
1599
  __query: {
792
1600
  target: "model",
@@ -795,7 +1603,7 @@ var ModelService = class extends Service {
795
1603
  op: "list",
796
1604
  filter: {},
797
1605
  args: { skip, limit, page, pageSize },
798
- options: { skim, includePermissions, includeCount, includeExtraHeaders },
1606
+ options: { skim, includePermissions, includeCount },
799
1607
  sqOptions: sq
800
1608
  },
801
1609
  __requestConfig: reqConfig,
@@ -848,12 +1656,18 @@ var ModelService = class extends Service {
848
1656
  return processListResult(
849
1657
  result,
850
1658
  { includeCount, includeExtraHeaders },
851
- (item) => Model.create(item, this)
1659
+ (item) => (
1660
+ // ARC-21: listAdvanced items come from existing documents;
1661
+ // mark `_fromExisting=true` so a save cannot silently re-create
1662
+ // when a server response shape drops `_id`.
1663
+ Model.create(item, this, void 0, true)
1664
+ )
852
1665
  );
853
- }).catch(this.handleError).then(
1666
+ }).catch(this.handleError).then(ensureListResultCount).then(
854
1667
  (res) => this._handleCallbacks(res, throwOnError)
855
1668
  ),
856
1669
  {
1670
+ __throwOnError: throwOnError,
857
1671
  __op: "listAdvanced",
858
1672
  __query: {
859
1673
  target: "model",
@@ -862,7 +1676,7 @@ var ModelService = class extends Service {
862
1676
  op: "list",
863
1677
  filter: _filter,
864
1678
  args: { select, sort, populate, include, skip, limit, page, pageSize, tasks },
865
- options: { skim, includePermissions, includeCount, includeExtraHeaders, populateAccess },
1679
+ options: { skim, includePermissions, includeCount, populateAccess },
866
1680
  sqOptions: sq
867
1681
  },
868
1682
  __requestConfig: reqConfig,
@@ -872,14 +1686,25 @@ var ModelService = class extends Service {
872
1686
  }
873
1687
  create(data, options, axiosRequestConfig) {
874
1688
  const { includePermissions = this._defaults.createOptions.includePermissions ?? true } = options ?? {};
875
- const { throwOnError, ...reqConfig } = axiosRequestConfig ?? {};
876
- set3(reqConfig, `headers.${CACHE_HEADER}`, "false");
1689
+ const { throwOnError, ...reqConfig } = cloneConfigWithCacheBypass(axiosRequestConfig ?? {});
1690
+ const bulk = Array.isArray(data);
877
1691
  return makeRequest(
878
1692
  () => this._axios.post(this._basePath, data, mergeConfig3(reqConfig, { params: { include_permissions: includePermissions } })).then(this.handleSuccess).then((result) => {
879
- result.data = result.success ? Model.create(result.raw, this) : null;
1693
+ if (result.success) {
1694
+ if (bulk) {
1695
+ const rows = Array.isArray(result.raw) ? result.raw : [result.raw];
1696
+ result.raw = rows;
1697
+ result.data = rows.map((row) => Model.create(row, this, void 0, true));
1698
+ } else {
1699
+ result.data = Model.create(result.raw, this, void 0, true);
1700
+ }
1701
+ }
880
1702
  return result;
881
- }).catch(this.handleError).then((res) => this._handleCallbacks(res, throwOnError)),
1703
+ }).catch(this.handleError).then(
1704
+ (res) => this._handleCallbacks(res, throwOnError)
1705
+ ),
882
1706
  {
1707
+ __throwOnError: throwOnError,
883
1708
  __op: "create",
884
1709
  __query: {
885
1710
  target: "model",
@@ -901,20 +1726,27 @@ var ModelService = class extends Service {
901
1726
  includePermissions = this._defaults.createAdvancedOptions.includePermissions ?? true,
902
1727
  populateAccess = this._defaults.createAdvancedOptions.populateAccess
903
1728
  } = options ?? {};
904
- const { throwOnError, ...reqConfig } = axiosRequestConfig ?? {};
905
- set3(reqConfig, `headers.${CACHE_HEADER}`, "false");
1729
+ const { throwOnError, ...reqConfig } = cloneConfigWithCacheBypass(axiosRequestConfig ?? {});
1730
+ const bulk = Array.isArray(data);
906
1731
  return makeRequest(
907
1732
  () => this._axios.post(
908
1733
  `${this._basePath}/${this._mutationPath}`,
909
1734
  { data, select, populate, tasks, options: { includePermissions, populateAccess } },
910
1735
  reqConfig
911
1736
  ).then(this.handleSuccess).then((result) => {
912
- result.data = result.success ? Model.create(result.raw, this) : null;
1737
+ if (result.success) {
1738
+ if (bulk) {
1739
+ const rows = Array.isArray(result.raw) ? result.raw : [result.raw];
1740
+ result.raw = rows;
1741
+ result.data = rows.map((row) => Model.create(row, this, void 0, true));
1742
+ } else {
1743
+ result.data = Model.create(result.raw, this, void 0, true);
1744
+ }
1745
+ }
913
1746
  return result;
914
- }).catch(this.handleError).then(
915
- (res) => this._handleCallbacks(res, throwOnError)
916
- ),
1747
+ }).catch(this.handleError).then((res) => this._handleCallbacks(res, throwOnError)),
917
1748
  {
1749
+ __throwOnError: throwOnError,
918
1750
  __op: "createAdvanced",
919
1751
  __query: {
920
1752
  target: "model",
@@ -931,15 +1763,24 @@ var ModelService = class extends Service {
931
1763
  );
932
1764
  }
933
1765
  upsert(data, options, axiosRequestConfig) {
934
- const { returningAll = this._defaults.upsertOptions.returningAll ?? true } = options ?? {};
935
- const { throwOnError, ...reqConfig } = axiosRequestConfig ?? {};
936
- set3(reqConfig, `headers.${CACHE_HEADER}`, "false");
1766
+ const {
1767
+ returningAll = this._defaults.upsertOptions.returningAll ?? true,
1768
+ includePermissions = this._defaults.upsertOptions.includePermissions ?? true
1769
+ } = options ?? {};
1770
+ const { throwOnError, ...reqConfig } = cloneConfigWithCacheBypass(axiosRequestConfig ?? {});
937
1771
  return makeRequest(
938
- () => this._axios.put(this._basePath, data, mergeConfig3(reqConfig, { params: { returning_all: returningAll } })).then(this.handleSuccess).then((result) => {
939
- result.data = result.success ? Model.create(result.raw, this) : null;
1772
+ () => this._axios.put(
1773
+ this._basePath,
1774
+ data,
1775
+ mergeConfig3(reqConfig, {
1776
+ params: { returning_all: returningAll, include_permissions: includePermissions }
1777
+ })
1778
+ ).then(this.handleSuccess).then((result) => {
1779
+ result.data = result.success ? Model.create(result.raw, this, void 0, true) : null;
940
1780
  return result;
941
1781
  }).catch(this.handleError).then((res) => this._handleCallbacks(res, throwOnError)),
942
1782
  {
1783
+ __throwOnError: throwOnError,
943
1784
  __op: "upsert",
944
1785
  __query: {
945
1786
  target: "model",
@@ -947,7 +1788,7 @@ var ModelService = class extends Service {
947
1788
  model: this._modelName,
948
1789
  op: "upsert",
949
1790
  data,
950
- options: { returningAll }
1791
+ options: { returningAll, includePermissions }
951
1792
  },
952
1793
  __requestConfig: reqConfig,
953
1794
  __service: this
@@ -962,8 +1803,7 @@ var ModelService = class extends Service {
962
1803
  includePermissions = this._defaults.upsertAdvancedOptions.includePermissions ?? true,
963
1804
  populateAccess = this._defaults.upsertAdvancedOptions.populateAccess
964
1805
  } = options ?? {};
965
- const { throwOnError, ...reqConfig } = axiosRequestConfig ?? {};
966
- set3(reqConfig, `headers.${CACHE_HEADER}`, "false");
1806
+ const { throwOnError, ...reqConfig } = cloneConfigWithCacheBypass(axiosRequestConfig ?? {});
967
1807
  return makeRequest(
968
1808
  () => this._axios.put(
969
1809
  `${this._basePath}/${this._mutationPath}`,
@@ -976,12 +1816,13 @@ var ModelService = class extends Service {
976
1816
  },
977
1817
  reqConfig
978
1818
  ).then(this.handleSuccess).then((result) => {
979
- result.data = result.success ? Model.create(result.raw, this) : null;
1819
+ result.data = result.success ? Model.create(result.raw, this, void 0, true) : null;
980
1820
  return result;
981
1821
  }).catch(this.handleError).then(
982
1822
  (res) => this._handleCallbacks(res, throwOnError)
983
1823
  ),
984
1824
  {
1825
+ __throwOnError: throwOnError,
985
1826
  __op: "upsertAdvanced",
986
1827
  __query: {
987
1828
  target: "model",
@@ -998,14 +1839,14 @@ var ModelService = class extends Service {
998
1839
  );
999
1840
  }
1000
1841
  delete(identifier, axiosRequestConfig) {
1001
- const { throwOnError, ...reqConfig } = axiosRequestConfig ?? {};
1002
- set3(reqConfig, `headers.${CACHE_HEADER}`, "false");
1842
+ const { throwOnError, ...reqConfig } = cloneConfigWithCacheBypass(axiosRequestConfig ?? {});
1003
1843
  return makeRequest(
1004
- () => this._axios.delete(`${this._basePath}/${identifier}`, reqConfig).then(this.handleSuccess).then((result) => {
1005
- result.data = result.raw;
1844
+ () => this._axios.delete(`${this._basePath}/${encodePathSegment(identifier)}`, reqConfig).then(this.handleSuccess).then((result) => {
1845
+ if (result.success) result.data = result.raw;
1006
1846
  return result;
1007
1847
  }).catch(this.handleError).then((res) => this._handleCallbacks(res, throwOnError)),
1008
1848
  {
1849
+ __throwOnError: throwOnError,
1009
1850
  __op: "delete",
1010
1851
  __query: {
1011
1852
  target: "model",
@@ -1020,15 +1861,17 @@ var ModelService = class extends Service {
1020
1861
  );
1021
1862
  }
1022
1863
  new(axiosRequestConfig) {
1023
- const { throwOnError, ...reqConfig } = axiosRequestConfig ?? {};
1024
- set3(reqConfig, `headers.${CACHE_HEADER}`, "false");
1864
+ const { throwOnError, ...reqConfig } = cloneConfigWithCacheBypass(axiosRequestConfig ?? {});
1025
1865
  return makeRequest(
1026
1866
  () => this._axios.get(`${this._basePath}/new`, reqConfig).then(this.handleSuccess).then((result) => {
1027
- delete result.raw._id;
1028
- result.data = result.success ? Model.create(result.raw, this) : null;
1867
+ if (result.success) {
1868
+ delete result.raw._id;
1869
+ result.data = Model.create(result.raw, this);
1870
+ }
1029
1871
  return result;
1030
1872
  }).catch(this.handleError).then((res) => this._handleCallbacks(res, throwOnError)),
1031
1873
  {
1874
+ __throwOnError: throwOnError,
1032
1875
  __op: "new",
1033
1876
  __query: {
1034
1877
  target: "model",
@@ -1044,11 +1887,12 @@ var ModelService = class extends Service {
1044
1887
  distinct(field, axiosRequestConfig) {
1045
1888
  const { throwOnError, ...reqConfig } = axiosRequestConfig ?? {};
1046
1889
  return makeRequest(
1047
- () => this._axios.get(`${this._basePath}/distinct/${field}`, reqConfig).then(this.handleSuccess).then((result) => {
1048
- result.data = result.raw;
1890
+ () => this._axios.get(`${this._basePath}/distinct/${encodePathSegment(field)}`, reqConfig).then(this.handleSuccess).then((result) => {
1891
+ if (result.success) result.data = result.raw;
1049
1892
  return result;
1050
1893
  }).catch(this.handleError).then((res) => this._handleCallbacks(res, throwOnError)),
1051
1894
  {
1895
+ __throwOnError: throwOnError,
1052
1896
  __op: "distinct",
1053
1897
  __query: {
1054
1898
  target: "model",
@@ -1065,11 +1909,12 @@ var ModelService = class extends Service {
1065
1909
  distinctAdvanced(field, conditions, axiosRequestConfig) {
1066
1910
  const { throwOnError, ...reqConfig } = axiosRequestConfig ?? {};
1067
1911
  return makeRequest(
1068
- () => this._axios.post(`${this._basePath}/distinct/${field}`, conditions, reqConfig).then(this.handleSuccess).then((result) => {
1069
- result.data = result.raw;
1912
+ () => this._axios.post(`${this._basePath}/distinct/${encodePathSegment(field)}`, { filter: conditions }, reqConfig).then(this.handleSuccess).then((result) => {
1913
+ if (result.success) result.data = result.raw;
1070
1914
  return result;
1071
1915
  }).catch(this.handleError).then((res) => this._handleCallbacks(res, throwOnError)),
1072
1916
  {
1917
+ __throwOnError: throwOnError,
1073
1918
  __op: "distinctAdvanced",
1074
1919
  __query: {
1075
1920
  target: "model",
@@ -1088,10 +1933,11 @@ var ModelService = class extends Service {
1088
1933
  const { throwOnError, ...reqConfig } = axiosRequestConfig ?? {};
1089
1934
  return makeRequest(
1090
1935
  () => this._axios.get(`${this._basePath}/count`, reqConfig).then(this.handleSuccess).then((result) => {
1091
- result.data = result.raw;
1936
+ if (result.success) result.data = result.raw;
1092
1937
  return result;
1093
1938
  }).catch(this.handleError).then((res) => this._handleCallbacks(res, throwOnError)),
1094
1939
  {
1940
+ __throwOnError: throwOnError,
1095
1941
  __op: "count",
1096
1942
  __query: {
1097
1943
  target: "model",
@@ -1104,23 +1950,22 @@ var ModelService = class extends Service {
1104
1950
  }
1105
1951
  );
1106
1952
  }
1107
- countAdvanced(filter, args, axiosRequestConfig) {
1108
- const { access } = args ?? {};
1953
+ countAdvanced(filter, axiosRequestConfig) {
1109
1954
  const { throwOnError, ...reqConfig } = axiosRequestConfig ?? {};
1110
1955
  return makeRequest(
1111
- () => this._axios.post(`${this._basePath}/count`, { filter, options: { access } }, reqConfig).then(this.handleSuccess).then((result) => {
1112
- result.data = result.raw;
1956
+ () => this._axios.post(`${this._basePath}/count`, { filter }, reqConfig).then(this.handleSuccess).then((result) => {
1957
+ if (result.success) result.data = result.raw;
1113
1958
  return result;
1114
1959
  }).catch(this.handleError).then((res) => this._handleCallbacks(res, throwOnError)),
1115
1960
  {
1961
+ __throwOnError: throwOnError,
1116
1962
  __op: "countAdvanced",
1117
1963
  __query: {
1118
1964
  target: "model",
1119
1965
  name: this._modelName,
1120
1966
  model: this._modelName,
1121
1967
  op: "count",
1122
- filter,
1123
- options: { access }
1968
+ filter
1124
1969
  },
1125
1970
  __requestConfig: reqConfig,
1126
1971
  __service: this
@@ -1141,15 +1986,16 @@ var ModelService = class extends Service {
1141
1986
  reqConfig.headers = this.updateHeaders(reqConfig.headers, { ignoreCache });
1142
1987
  return makeRequest(
1143
1988
  () => this._axios.get(
1144
- `${this._basePath}/${identifier}`,
1989
+ `${this._basePath}/${encodePathSegment(identifier)}`,
1145
1990
  mergeConfig3(reqConfig, {
1146
1991
  params: { include_permissions: includePermissions, try_list: tryList }
1147
1992
  })
1148
1993
  ).then(this.handleSuccess).then((result) => {
1149
- result.data = result.success ? Model.create(result.raw, this) : null;
1994
+ result.data = result.success ? Model.create(result.raw, this, identifier, true) : null;
1150
1995
  return result;
1151
1996
  }).catch(this.handleError).then((res) => this._handleCallbacks(res, throwOnError)),
1152
1997
  {
1998
+ __throwOnError: throwOnError,
1153
1999
  __op: "read",
1154
2000
  __query: {
1155
2001
  target: "model",
@@ -1185,7 +2031,7 @@ var ModelService = class extends Service {
1185
2031
  reqConfig.headers = this.updateHeaders(reqConfig.headers, { ignoreCache });
1186
2032
  return makeRequest(
1187
2033
  () => this._axios.post(
1188
- `${this._basePath}/${this._queryPath}/${identifier}`,
2034
+ `${this._basePath}/${this._queryPath}/${encodePathSegment(identifier)}`,
1189
2035
  {
1190
2036
  select,
1191
2037
  populate,
@@ -1195,12 +2041,13 @@ var ModelService = class extends Service {
1195
2041
  },
1196
2042
  reqConfig
1197
2043
  ).then(this.handleSuccess).then((result) => {
1198
- result.data = result.success ? Model.create(result.raw, this) : null;
2044
+ result.data = result.success ? Model.create(result.raw, this, identifier, true) : null;
1199
2045
  return result;
1200
2046
  }).catch(this.handleError).then(
1201
2047
  (res) => this._handleCallbacks(res, throwOnError)
1202
2048
  ),
1203
2049
  {
2050
+ __throwOnError: throwOnError,
1204
2051
  __op: "readAdvanced",
1205
2052
  __query: {
1206
2053
  target: "model",
@@ -1250,12 +2097,13 @@ var ModelService = class extends Service {
1250
2097
  },
1251
2098
  reqConfig
1252
2099
  ).then(this.handleSuccess).then((result) => {
1253
- result.data = result.success ? Model.create(result.raw, this) : null;
2100
+ result.data = result.success ? Model.create(result.raw, this, void 0, true) : null;
1254
2101
  return result;
1255
2102
  }).catch(this.handleError).then(
1256
2103
  (res) => this._handleCallbacks(res, throwOnError)
1257
2104
  ),
1258
2105
  {
2106
+ __throwOnError: throwOnError,
1259
2107
  __op: "readAdvancedFilter",
1260
2108
  __query: {
1261
2109
  target: "model",
@@ -1273,19 +2121,24 @@ var ModelService = class extends Service {
1273
2121
  );
1274
2122
  }
1275
2123
  update(identifier, data, options, axiosRequestConfig) {
1276
- const { returningAll = this._defaults.updateOptions.returningAll ?? true } = options ?? {};
1277
- const { throwOnError, ...reqConfig } = axiosRequestConfig ?? {};
1278
- set3(reqConfig, `headers.${CACHE_HEADER}`, "false");
2124
+ const {
2125
+ returningAll = this._defaults.updateOptions.returningAll ?? true,
2126
+ includePermissions = this._defaults.updateOptions.includePermissions ?? true
2127
+ } = options ?? {};
2128
+ const { throwOnError, ...reqConfig } = cloneConfigWithCacheBypass(axiosRequestConfig ?? {});
1279
2129
  return makeRequest(
1280
2130
  () => this._axios.patch(
1281
- `${this._basePath}/${identifier}`,
2131
+ `${this._basePath}/${encodePathSegment(identifier)}`,
1282
2132
  data,
1283
- mergeConfig3(reqConfig, { params: { returning_all: returningAll } })
2133
+ mergeConfig3(reqConfig, {
2134
+ params: { returning_all: returningAll, include_permissions: includePermissions }
2135
+ })
1284
2136
  ).then(this.handleSuccess).then((result) => {
1285
- result.data = result.success ? Model.create(result.raw, this) : null;
2137
+ result.data = result.success ? Model.create(result.raw, this, void 0, true) : null;
1286
2138
  return result;
1287
2139
  }).catch(this.handleError).then((res) => this._handleCallbacks(res, throwOnError)),
1288
2140
  {
2141
+ __throwOnError: throwOnError,
1289
2142
  __op: "update",
1290
2143
  __query: {
1291
2144
  target: "model",
@@ -1294,7 +2147,7 @@ var ModelService = class extends Service {
1294
2147
  op: "update",
1295
2148
  id: identifier,
1296
2149
  data,
1297
- options: { returningAll }
2150
+ options: { returningAll, includePermissions }
1298
2151
  },
1299
2152
  __requestConfig: reqConfig,
1300
2153
  __service: this
@@ -1309,11 +2162,10 @@ var ModelService = class extends Service {
1309
2162
  includePermissions = this._defaults.updateAdvancedOptions.includePermissions ?? true,
1310
2163
  populateAccess = this._defaults.updateAdvancedOptions.populateAccess
1311
2164
  } = options ?? {};
1312
- const { throwOnError, ...reqConfig } = axiosRequestConfig ?? {};
1313
- set3(reqConfig, `headers.${CACHE_HEADER}`, "false");
2165
+ const { throwOnError, ...reqConfig } = cloneConfigWithCacheBypass(axiosRequestConfig ?? {});
1314
2166
  return makeRequest(
1315
2167
  () => this._axios.patch(
1316
- `${this._basePath}/${this._mutationPath}/${identifier}`,
2168
+ `${this._basePath}/${this._mutationPath}/${encodePathSegment(identifier)}`,
1317
2169
  {
1318
2170
  data,
1319
2171
  select,
@@ -1323,12 +2175,13 @@ var ModelService = class extends Service {
1323
2175
  },
1324
2176
  reqConfig
1325
2177
  ).then(this.handleSuccess).then((result) => {
1326
- result.data = result.success ? Model.create(result.raw, this) : null;
2178
+ result.data = result.success ? Model.create(result.raw, this, void 0, true) : null;
1327
2179
  return result;
1328
2180
  }).catch(this.handleError).then(
1329
2181
  (res) => this._handleCallbacks(res, throwOnError)
1330
2182
  ),
1331
2183
  {
2184
+ __throwOnError: throwOnError,
1332
2185
  __op: "updateAdvanced",
1333
2186
  __query: {
1334
2187
  target: "model",
@@ -1377,8 +2230,8 @@ var ModelService = class extends Service {
1377
2230
  // src/services/data-service.ts
1378
2231
  import { mergeConfig as mergeConfig4 } from "axios";
1379
2232
  var DataService = class extends Service {
1380
- constructor({ axios: axios2, dataName, basePath, queryPath, onSuccess, onFailure, throwOnError }, defaults) {
1381
- super(axios2, basePath);
2233
+ constructor({ axios: axios3, dataName, basePath, queryPath, onSuccess, onFailure, throwOnError }, defaults) {
2234
+ super(axios3, basePath, throwOnError);
1382
2235
  this._dataName = dataName;
1383
2236
  this._queryPath = queryPath;
1384
2237
  this._defaults = defaults ?? {};
@@ -1404,7 +2257,6 @@ var DataService = class extends Service {
1404
2257
  pageSize = this._defaults.listArgs.pageSize
1405
2258
  } = args ?? {};
1406
2259
  const {
1407
- includePermissions = this._defaults.listOptions.includePermissions ?? false,
1408
2260
  includeCount = this._defaults.listOptions.includeCount ?? false,
1409
2261
  includeExtraHeaders = this._defaults.listOptions.includeExtraHeaders ?? false,
1410
2262
  ignoreCache = this._defaults.listOptions.ignoreCache ?? false
@@ -1420,15 +2272,15 @@ var DataService = class extends Service {
1420
2272
  limit,
1421
2273
  page,
1422
2274
  page_size: pageSize,
1423
- include_permissions: includePermissions,
1424
2275
  include_count: includeCount,
1425
2276
  include_extra_headers: includeExtraHeaders
1426
2277
  }
1427
2278
  })
1428
2279
  ).then(this.handleSuccess).then((result) => {
1429
2280
  return processListResult(result, { includeCount, includeExtraHeaders });
1430
- }).catch(this.handleError).then((res) => this._handleCallbacks(res, throwOnError)),
2281
+ }).catch(this.handleError).then(ensureListResultCount).then((res) => this._handleCallbacks(res, throwOnError)),
1431
2282
  {
2283
+ __throwOnError: throwOnError,
1432
2284
  __op: "list",
1433
2285
  __query: {
1434
2286
  target: "data",
@@ -1436,7 +2288,7 @@ var DataService = class extends Service {
1436
2288
  op: "list",
1437
2289
  filter: {},
1438
2290
  args: { skip, limit, page, pageSize },
1439
- options: { includePermissions, includeCount, includeExtraHeaders }
2291
+ options: { includeCount }
1440
2292
  },
1441
2293
  __requestConfig: reqConfig,
1442
2294
  __service: this
@@ -1453,7 +2305,6 @@ var DataService = class extends Service {
1453
2305
  } = args ?? {};
1454
2306
  const select = args?.select ?? this._defaults.listAdvancedArgs.select;
1455
2307
  const {
1456
- includePermissions = this._defaults.listAdvancedOptions.includePermissions ?? false,
1457
2308
  includeCount = this._defaults.listAdvancedOptions.includeCount ?? false,
1458
2309
  includeExtraHeaders = this._defaults.listAdvancedOptions.includeExtraHeaders ?? false,
1459
2310
  ignoreCache = this._defaults.listAdvancedOptions.ignoreCache ?? false
@@ -1472,7 +2323,7 @@ var DataService = class extends Service {
1472
2323
  limit,
1473
2324
  page,
1474
2325
  pageSize,
1475
- options: { includePermissions, includeCount, includeExtraHeaders }
2326
+ options: { includeCount, includeExtraHeaders }
1476
2327
  },
1477
2328
  reqConfig
1478
2329
  ).then(this.handleSuccess).then((result) => {
@@ -1480,10 +2331,11 @@ var DataService = class extends Service {
1480
2331
  includeCount,
1481
2332
  includeExtraHeaders
1482
2333
  });
1483
- }).catch(this.handleError).then(
2334
+ }).catch(this.handleError).then(ensureListResultCount).then(
1484
2335
  (res) => this._handleCallbacks(res, throwOnError)
1485
2336
  ),
1486
2337
  {
2338
+ __throwOnError: throwOnError,
1487
2339
  __op: "listAdvanced",
1488
2340
  __query: {
1489
2341
  target: "data",
@@ -1491,7 +2343,7 @@ var DataService = class extends Service {
1491
2343
  op: "list",
1492
2344
  filter: _filter,
1493
2345
  args: { select, sort, skip, limit, page, pageSize },
1494
- options: { includePermissions, includeCount, includeExtraHeaders }
2346
+ options: { includeCount }
1495
2347
  },
1496
2348
  __requestConfig: reqConfig,
1497
2349
  __service: this
@@ -1502,23 +2354,16 @@ var DataService = class extends Service {
1502
2354
  // Document operations
1503
2355
  // ---------------------------------------------------------------------------
1504
2356
  read(identifier, options, axiosRequestConfig) {
1505
- const {
1506
- includePermissions = this._defaults.readOptions.includePermissions ?? true,
1507
- ignoreCache = this._defaults.readOptions.ignoreCache ?? false
1508
- } = options ?? {};
2357
+ const { ignoreCache = this._defaults.readOptions.ignoreCache ?? false } = options ?? {};
1509
2358
  const { throwOnError, ...reqConfig } = axiosRequestConfig ?? {};
1510
2359
  reqConfig.headers = this.updateHeaders(reqConfig.headers, { ignoreCache });
1511
2360
  return makeRequest(
1512
- () => this._axios.get(
1513
- `${this._basePath}/${identifier}`,
1514
- mergeConfig4(reqConfig, {
1515
- params: { include_permissions: includePermissions }
1516
- })
1517
- ).then(this.handleSuccess).then((result) => {
1518
- result.data = result.raw;
2361
+ () => this._axios.get(`${this._basePath}/${encodePathSegment(identifier)}`, reqConfig).then(this.handleSuccess).then((result) => {
2362
+ if (result.success) result.data = result.raw;
1519
2363
  return result;
1520
2364
  }).catch(this.handleError).then((res) => this._handleCallbacks(res, throwOnError)),
1521
2365
  {
2366
+ __throwOnError: throwOnError,
1522
2367
  __op: "read",
1523
2368
  __query: {
1524
2369
  target: "data",
@@ -1526,7 +2371,7 @@ var DataService = class extends Service {
1526
2371
  op: "read",
1527
2372
  id: identifier,
1528
2373
  args: {},
1529
- options: { includePermissions }
2374
+ options: {}
1530
2375
  },
1531
2376
  __requestConfig: reqConfig,
1532
2377
  __service: this
@@ -1534,19 +2379,19 @@ var DataService = class extends Service {
1534
2379
  );
1535
2380
  }
1536
2381
  readAdvanced(identifier, args, options, axiosRequestConfig) {
1537
- const { ignoreCache = this._defaults.readAdvancedArgs.ignoreCache ?? false } = args ?? {};
1538
2382
  const select = args?.select ?? this._defaults.readAdvancedArgs.select;
1539
- const { includePermissions = this._defaults.readAdvancedOptions.includePermissions ?? true } = options ?? {};
2383
+ const { ignoreCache = this._defaults.readAdvancedOptions.ignoreCache ?? false } = options ?? {};
1540
2384
  const { throwOnError, ...reqConfig } = axiosRequestConfig ?? {};
1541
2385
  reqConfig.headers = this.updateHeaders(reqConfig.headers, { ignoreCache });
1542
2386
  return makeRequest(
1543
- () => this._axios.post(`${this._basePath}/${this._queryPath}/${identifier}`, { select }, reqConfig).then(this.handleSuccess).then((result) => {
1544
- result.data = result.raw;
2387
+ () => this._axios.post(`${this._basePath}/${this._queryPath}/${encodePathSegment(identifier)}`, { select }, reqConfig).then(this.handleSuccess).then((result) => {
2388
+ if (result.success) result.data = result.raw;
1545
2389
  return result;
1546
2390
  }).catch(this.handleError).then(
1547
2391
  (res) => this._handleCallbacks(res, throwOnError)
1548
2392
  ),
1549
2393
  {
2394
+ __throwOnError: throwOnError,
1550
2395
  __op: "readAdvanced",
1551
2396
  __query: {
1552
2397
  target: "data",
@@ -1554,7 +2399,7 @@ var DataService = class extends Service {
1554
2399
  op: "read",
1555
2400
  id: identifier,
1556
2401
  args: { select },
1557
- options: { includePermissions }
2402
+ options: {}
1558
2403
  },
1559
2404
  __requestConfig: reqConfig,
1560
2405
  __service: this
@@ -1563,19 +2408,19 @@ var DataService = class extends Service {
1563
2408
  }
1564
2409
  readAdvancedFilter(filter, args, options, axiosRequestConfig) {
1565
2410
  const select = args?.select ?? this._defaults.readAdvancedArgs.select;
1566
- const { ignoreCache = this._defaults.readAdvancedArgs.ignoreCache ?? false } = args ?? {};
1567
- const { includePermissions = this._defaults.readAdvancedOptions.includePermissions ?? true } = options ?? {};
2411
+ const { ignoreCache = this._defaults.readAdvancedOptions.ignoreCache ?? false } = options ?? {};
1568
2412
  const { throwOnError, ...reqConfig } = axiosRequestConfig ?? {};
1569
2413
  reqConfig.headers = this.updateHeaders(reqConfig.headers, { ignoreCache });
1570
2414
  const _filter = replaceSubQuery(filter);
1571
2415
  return makeRequest(
1572
2416
  () => this._axios.post(`${this._basePath}/${this._queryPath}/__filter`, { filter: _filter, select }, reqConfig).then(this.handleSuccess).then((result) => {
1573
- result.data = result.raw;
2417
+ if (result.success) result.data = result.raw;
1574
2418
  return result;
1575
2419
  }).catch(this.handleError).then(
1576
2420
  (res) => this._handleCallbacks(res, throwOnError)
1577
2421
  ),
1578
2422
  {
2423
+ __throwOnError: throwOnError,
1579
2424
  __op: "readAdvancedFilter",
1580
2425
  __query: {
1581
2426
  target: "data",
@@ -1583,7 +2428,7 @@ var DataService = class extends Service {
1583
2428
  op: "read",
1584
2429
  filter: _filter,
1585
2430
  args: { select },
1586
- options: { includePermissions }
2431
+ options: {}
1587
2432
  },
1588
2433
  __requestConfig: reqConfig,
1589
2434
  __service: this
@@ -1592,132 +2437,8 @@ var DataService = class extends Service {
1592
2437
  }
1593
2438
  };
1594
2439
 
1595
- // src/services/interceptors.ts
1596
- import { AxiosHeaders as AxiosHeaders3 } from "axios";
1597
-
1598
- // src/services/cache-utils.ts
1599
- import { AxiosHeaders as AxiosHeaders2 } from "axios";
1600
- import { omitBy } from "@web-ts-toolkit/utils";
1601
- var normalizeConfigValue = (value) => {
1602
- if (value == null) return value;
1603
- if (value instanceof AxiosHeaders2) {
1604
- return normalizeConfigValue(value.toJSON());
1605
- }
1606
- if (Array.isArray(value)) {
1607
- return value.map((item) => normalizeConfigValue(item));
1608
- }
1609
- if (typeof value === "object") {
1610
- return Object.entries(omitBy(value, (item) => item === void 0)).sort(([left], [right]) => left.localeCompare(right)).reduce((acc, [key, item]) => {
1611
- acc[key] = normalizeConfigValue(item);
1612
- return acc;
1613
- }, {});
1614
- }
1615
- return value;
1616
- };
1617
-
1618
- // src/services/interceptors.ts
1619
- var SimpleCache = class {
1620
- constructor() {
1621
- this.cache = /* @__PURE__ */ new Map();
1622
- this.timers = /* @__PURE__ */ new Map();
1623
- }
1624
- set(key, value, ttl) {
1625
- this.cache.set(key, value);
1626
- if (ttl && ttl > 0) {
1627
- const existing = this.timers.get(key);
1628
- if (existing) clearTimeout(existing);
1629
- this.timers.set(
1630
- key,
1631
- setTimeout(() => {
1632
- this.cache.delete(key);
1633
- this.timers.delete(key);
1634
- }, ttl)
1635
- );
1636
- }
1637
- }
1638
- get(key) {
1639
- return this.cache.get(key);
1640
- }
1641
- has(key) {
1642
- return this.cache.has(key);
1643
- }
1644
- delete(key) {
1645
- const timer = this.timers.get(key);
1646
- if (timer) {
1647
- clearTimeout(timer);
1648
- this.timers.delete(key);
1649
- }
1650
- return this.cache.delete(key);
1651
- }
1652
- };
1653
- var IGNORED_CACHE_HEADERS = /* @__PURE__ */ new Set([
1654
- "accept",
1655
- "accept-encoding",
1656
- "cache-control",
1657
- "connection",
1658
- "content-length",
1659
- "content-type",
1660
- "expires",
1661
- "host",
1662
- "pragma",
1663
- "user-agent"
1664
- ]);
1665
- var serializeHeaders = (headers) => {
1666
- const resolvedHeaders = headers instanceof AxiosHeaders3 ? headers.toJSON() : headers;
1667
- const normalizedHeaders = Object.entries(resolvedHeaders ?? {}).filter(([key, value]) => {
1668
- const normalizedKey = key.toLowerCase();
1669
- return normalizedKey !== CACHE_HEADER.toLowerCase() && !IGNORED_CACHE_HEADERS.has(normalizedKey) && value !== void 0;
1670
- }).reduce((acc, [key, value]) => {
1671
- acc[key.toLowerCase()] = value;
1672
- return acc;
1673
- }, {});
1674
- return JSON.stringify(normalizeConfigValue(normalizedHeaders));
1675
- };
1676
- function generateCacheKey(config) {
1677
- const key = `${config.baseURL}/${config.url}_${config.method}_${generateParamKey(config.params)}_${generateDataKey(
1678
- config.data
1679
- )}_${serializeHeaders(config.headers)}`;
1680
- return encodeURI(key);
1681
- }
1682
- function generateParamKey(params) {
1683
- if (!params) return "";
1684
- return JSON.stringify(normalizeConfigValue(params));
1685
- }
1686
- function generateDataKey(data) {
1687
- if (!data) return "";
1688
- return typeof data === "string" ? data : JSON.stringify(normalizeConfigValue(data));
1689
- }
1690
- function useCacheInterceptors(instance, cacheTTL) {
1691
- const store = new SimpleCache();
1692
- instance.interceptors.request.use(
1693
- async (config) => {
1694
- if (config.headers[CACHE_HEADER] === "false") return config;
1695
- const key = generateCacheKey(config);
1696
- const cachedResponse = store.get(key);
1697
- if (!cachedResponse) {
1698
- return config;
1699
- }
1700
- config.adapter = async (_config) => {
1701
- return {
1702
- ...cachedResponse,
1703
- config: _config,
1704
- headers: { ...cachedResponse.headers, [CACHE_HEADER]: "true" }
1705
- };
1706
- };
1707
- return config;
1708
- },
1709
- (error) => Promise.reject(error)
1710
- );
1711
- instance.interceptors.response.use(
1712
- (response) => {
1713
- if (response.config.headers[CACHE_HEADER] === "false") return response;
1714
- const key = generateCacheKey(response.config);
1715
- store.set(key, response, cacheTTL);
1716
- return response;
1717
- },
1718
- (error) => Promise.reject(error)
1719
- );
1720
- }
2440
+ // src/services/symbols.ts
2441
+ var ADAPTER_ID_KEY = /* @__PURE__ */ Symbol("adapterId");
1721
2442
 
1722
2443
  // src/adapter.ts
1723
2444
  var defaultAxiosConfig = Object.freeze({
@@ -1730,7 +2451,12 @@ var defaultAxiosConfig = Object.freeze({
1730
2451
  Expires: "0"
1731
2452
  }
1732
2453
  });
1733
- var isModelQuery = (query) => query.target === "model";
2454
+ var noopCacheController = {
2455
+ clear: () => {
2456
+ },
2457
+ dispose: () => {
2458
+ }
2459
+ };
1734
2460
  var serializeRequestConfig = (config) => JSON.stringify(normalizeConfigValue(config ?? {}));
1735
2461
  var isObjectRecord = (value) => value != null && typeof value === "object" && !Array.isArray(value);
1736
2462
  var mergeServiceDefaults = (adapterDefaults, serviceDefaults) => {
@@ -1755,20 +2481,39 @@ var mergeServiceDefaults = (adapterDefaults, serviceDefaults) => {
1755
2481
  };
1756
2482
  function createAdapter(axiosConfig, adapterOptions) {
1757
2483
  const merged = mergeConfig5(defaultAxiosConfig, axiosConfig ?? {});
1758
- const instance = axios.create(merged);
2484
+ const instance = axios2.create(merged);
1759
2485
  const {
1760
2486
  rootRouterPath = "root",
1761
2487
  onSuccess: onSuccessRoot,
1762
2488
  onFailure: onFailureRoot,
1763
2489
  throwOnError: throwOnErrorRoot,
1764
2490
  cacheTTL = 0,
2491
+ cachePartition,
2492
+ cacheCapacity,
1765
2493
  modelDefaults: adapterModelDefaults,
1766
2494
  dataDefaults: adapterDataDefaults
1767
2495
  } = adapterOptions ?? {};
1768
- if (cacheTTL > 0) useCacheInterceptors(instance, cacheTTL);
2496
+ const cacheController = cacheTTL > 0 ? useCacheInterceptors(instance, {
2497
+ ttl: cacheTTL,
2498
+ capacity: cacheCapacity,
2499
+ withCredentialsDefault: Boolean(instance.defaults.withCredentials),
2500
+ partitionForRequest: cachePartition
2501
+ }) : noopCacheController;
1769
2502
  const wraps = createWrapHelper(instance);
2503
+ const adapterId = /* @__PURE__ */ Symbol("adapter");
2504
+ const stampAdapterId = (service) => {
2505
+ Object.defineProperty(service, ADAPTER_ID_KEY, {
2506
+ value: adapterId,
2507
+ enumerable: false,
2508
+ writable: false,
2509
+ configurable: false
2510
+ });
2511
+ return service;
2512
+ };
1770
2513
  return Object.freeze({
1771
2514
  axios: instance,
2515
+ clearCache: cacheController.clear,
2516
+ disposeCache: cacheController.dispose,
1772
2517
  createModelService: ({
1773
2518
  modelName,
1774
2519
  basePath,
@@ -1778,7 +2523,7 @@ function createAdapter(axiosConfig, adapterOptions) {
1778
2523
  onFailure,
1779
2524
  throwOnError
1780
2525
  }, defaults) => {
1781
- return new ModelService(
2526
+ const service = new ModelService(
1782
2527
  {
1783
2528
  axios: instance,
1784
2529
  modelName,
@@ -1791,9 +2536,10 @@ function createAdapter(axiosConfig, adapterOptions) {
1791
2536
  },
1792
2537
  mergeServiceDefaults(adapterModelDefaults, defaults)
1793
2538
  );
2539
+ return stampAdapterId(service);
1794
2540
  },
1795
2541
  createDataService: ({ dataName, basePath, queryPath = "__query", onSuccess, onFailure, throwOnError }, defaults) => {
1796
- return new DataService(
2542
+ const service = new DataService(
1797
2543
  {
1798
2544
  axios: instance,
1799
2545
  dataName,
@@ -1805,6 +2551,7 @@ function createAdapter(axiosConfig, adapterOptions) {
1805
2551
  },
1806
2552
  mergeServiceDefaults(adapterDataDefaults, defaults)
1807
2553
  );
2554
+ return stampAdapterId(service);
1808
2555
  },
1809
2556
  wrapGet: wraps.wrapGet,
1810
2557
  wrapPost: wraps.wrapPost,
@@ -1814,55 +2561,72 @@ function createAdapter(axiosConfig, adapterOptions) {
1814
2561
  group: async (...proms) => {
1815
2562
  let sharedConfig;
1816
2563
  let sharedConfigKey;
2564
+ let groupThrowOnError;
1817
2565
  const defs = proms.map((prom, index) => {
1818
- if (!isEmpty(prom.__requestConfig)) {
1819
- const configKey = serializeRequestConfig(prom.__requestConfig);
1820
- if (sharedConfigKey && sharedConfigKey !== configKey) {
1821
- throw new Error("Grouped requests must share the same axios request config");
1822
- }
1823
- sharedConfig = prom.__requestConfig;
1824
- sharedConfigKey = configKey;
2566
+ const service = prom.__service;
2567
+ if (!service || service[ADAPTER_ID_KEY] !== adapterId) {
2568
+ throw new Error(
2569
+ "Cannot group a request owned by a different adapter; create the request from this adapter's services"
2570
+ );
2571
+ }
2572
+ if (groupThrowOnError != null && groupThrowOnError !== prom.__throwOnError) {
2573
+ throw new Error("Grouped requests must share the same effective throwOnError policy");
2574
+ }
2575
+ groupThrowOnError = prom.__throwOnError;
2576
+ const configKey = serializeRequestConfig(prom.__requestConfig);
2577
+ if (sharedConfigKey != null && sharedConfigKey !== configKey) {
2578
+ throw new Error("Grouped requests must share the same axios request config");
1825
2579
  }
2580
+ sharedConfig = prom.__requestConfig ?? {};
2581
+ sharedConfigKey = configKey;
1826
2582
  const query = { ...prom.__query };
2583
+ if (query.target === "model") {
2584
+ delete query.model;
2585
+ }
1827
2586
  if (prom.__query.order == null) {
1828
2587
  query.order = index;
1829
2588
  }
1830
2589
  return query;
1831
2590
  });
1832
- const result = await instance.post(rootRouterPath, defs, sharedConfig ?? {}).then((res) => {
1833
- const responseHeaders = res.headers ?? {};
1834
- return res.data.map(({ result: result2, message, statusCode, op }, index) => {
1835
- const service = proms[index].__service;
1836
- const query = proms[index].__query;
1837
- const success = result2.success;
1838
- let _raw = success ? result2.data : null;
1839
- let _data = _raw;
1840
- if (!success) {
1841
- _data = null;
1842
- } else if (isModelQuery(query)) {
1843
- const modelService = service;
1844
- if (result2.kind === "list" && Array.isArray(result2.data)) {
1845
- if (op === "create" && result2.data.length === 1) {
1846
- _raw = result2.data[0];
1847
- _data = Model.create(result2.data[0], modelService);
1848
- } else if (!["distinct", "subList"].includes(op)) {
1849
- _data = castArray(result2.data).map((item) => Model.create(item, modelService));
1850
- }
1851
- } else if (result2.kind === "single" && ["new", "read", "update", "upsert"].includes(op)) {
1852
- _data = Model.create(result2.data, modelService);
1853
- }
1854
- }
1855
- return {
1856
- success,
1857
- raw: _raw,
1858
- data: _data,
2591
+ const groupOwner = /* @__PURE__ */ Symbol("group");
2592
+ const claimed = [];
2593
+ try {
2594
+ for (const prom of proms) {
2595
+ claimLazyRequest(prom, "grouped", groupOwner);
2596
+ claimed.push(prom);
2597
+ }
2598
+ } catch (error) {
2599
+ for (const prom of claimed) {
2600
+ releaseLazyRequestClaim(prom, groupOwner);
2601
+ }
2602
+ throw error;
2603
+ }
2604
+ const result = await instance.post(rootRouterPath, defs, sharedConfig ?? {}).then(
2605
+ (res) => {
2606
+ const rawEntries = res.data.map(({ result: result2, message, statusCode, op }) => ({
2607
+ result: result2,
1859
2608
  message,
1860
- status: statusCode,
1861
- totalCount: result2.success && result2.kind === "list" ? result2.totalCount ?? result2.count ?? 0 : 0,
1862
- headers: responseHeaders
1863
- };
1864
- });
1865
- });
2609
+ statusCode,
2610
+ op
2611
+ }));
2612
+ const finalized = rawEntries.map(
2613
+ (rawEntry, index) => finalizeRootEntry(proms[index].__query, rawEntry, {}, proms[index].__service)
2614
+ );
2615
+ return applyGroupCallbacks(
2616
+ finalized,
2617
+ proms.map((p) => p.__service),
2618
+ groupThrowOnError ?? false
2619
+ );
2620
+ },
2621
+ (error) => {
2622
+ const failures = proms.map((prom) => finalizeRootTransportFailure(prom.__query, error));
2623
+ return applyGroupCallbacks(
2624
+ failures,
2625
+ proms.map((p) => p.__service),
2626
+ groupThrowOnError ?? false
2627
+ );
2628
+ }
2629
+ );
1866
2630
  return result;
1867
2631
  }
1868
2632
  });
@@ -1886,6 +2650,7 @@ function removeItemById(items, targetItem) {
1886
2650
  export {
1887
2651
  CustomHeaders,
1888
2652
  DataService,
2653
+ MissingPersistenceIdentityError,
1889
2654
  Model,
1890
2655
  ModelService,
1891
2656
  Service,