rest-client-vue 1.0.0-a1

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.
@@ -0,0 +1,1254 @@
1
+ var we = Object.defineProperty;
2
+ var Ce = (f, s, R) => s in f ? we(f, s, { enumerable: !0, configurable: !0, writable: !0, value: R }) : f[s] = R;
3
+ var re = (f, s, R) => (Ce(f, typeof s != "symbol" ? s + "" : s, R), R), Te = (f, s, R) => {
4
+ if (!s.has(f))
5
+ throw TypeError("Cannot " + R);
6
+ };
7
+ var Q = (f, s, R) => (Te(f, s, "read from private field"), R ? R.call(f) : s.get(f)), Se = (f, s, R) => {
8
+ if (s.has(f))
9
+ throw TypeError("Cannot add the same private member more than once");
10
+ s instanceof WeakSet ? s.add(f) : s.set(f, R);
11
+ };
12
+ import a from "lodash";
13
+ import { v4 as X } from "uuid";
14
+ import { ref as I, toRef as te, computed as m, watch as C, nextTick as Le } from "vue";
15
+ import P from "axios";
16
+ import me from "jsog";
17
+ import V from "json-stringify-deterministic";
18
+ import { defineStore as ye } from "pinia";
19
+ const pe = {
20
+ apiBaseUrl: "",
21
+ useVueLogger: !1
22
+ };
23
+ class ke extends Error {
24
+ constructor(R, L = void 0, e = void 0) {
25
+ super(R);
26
+ re(this, "context");
27
+ re(this, "innerError");
28
+ this.context = L, this.innerError = e;
29
+ }
30
+ }
31
+ var O;
32
+ class Ie {
33
+ constructor() {
34
+ Se(this, O, {});
35
+ }
36
+ clearAllStores() {
37
+ for (const s in Q(this, O))
38
+ Q(this, O)[s].clear();
39
+ }
40
+ destroyStore(s) {
41
+ Q(this, O)[s] && (Q(this, O)[s].$dispose(), delete Q(this, O)[s]);
42
+ }
43
+ getStore(s) {
44
+ return Q(this, O)[s];
45
+ }
46
+ registerStore(s, R) {
47
+ Q(this, O)[s] = R;
48
+ }
49
+ }
50
+ O = new WeakMap();
51
+ function v(f, s) {
52
+ return a.get(f, (s == null ? void 0 : s.idProperty) || "_id");
53
+ }
54
+ function $e(f, s) {
55
+ var R;
56
+ return f && ((R = s.filter) != null && R.resourceIds) && !s.order ? s.filter.resourceIds.map((L) => f.find((e) => v(e, s) == L)).filter((L) => L != null) : f;
57
+ }
58
+ const De = {
59
+ detail: {
60
+ allowMultiple: !0,
61
+ autoEdit: !1,
62
+ autoFromMultipleSelection: !0,
63
+ autoFromSingleInsertion: !0,
64
+ autoFromSingleSelection: !0,
65
+ constrainToSelection: !0
66
+ },
67
+ filter: {
68
+ namedFilter: null,
69
+ query: null,
70
+ resourceIds: null
71
+ },
72
+ idProperty: "_id",
73
+ limit: 5e3,
74
+ limitTransientDataToLocalCollection: !0,
75
+ loading: {
76
+ firstPageSize: 500,
77
+ pageSize: 5e3
78
+ },
79
+ order: [
80
+ // TODO Move to SFA LIMS.
81
+ [{ path: "history.creation.timestamp" }, "desc"],
82
+ [{ path: "history.creation.orderInBatch" }, "desc"]
83
+ ]
84
+ }, Y = {
85
+ resources: [],
86
+ status: "NotLoaded",
87
+ selection: [],
88
+ detailSelection: [],
89
+ invalidResources: [],
90
+ transientData: {}
91
+ }, le = {
92
+ editingDetailSelection: !1,
93
+ batchSaveAttempted: !1,
94
+ editors: [],
95
+ listNavigators: {}
96
+ }, Pe = (f, s) => {
97
+ s = a.merge({}, De, s);
98
+ const R = ye(f, {
99
+ state: () => ({
100
+ idProperty: s.idProperty,
101
+ filter: s.filter,
102
+ order: s.order || null,
103
+ referencePathsToExpand: s.referencePathsToExpand || null,
104
+ ...Y,
105
+ ...le
106
+ }),
107
+ getters: {
108
+ /**
109
+ * Get the REST query parameters that can be determined from the collection options.
110
+ *
111
+ * This includes all query parameters except offset and limit, which vary from request to request.
112
+ */
113
+ fixedQueryParams: (e) => {
114
+ var l, u, c, d;
115
+ const r = {};
116
+ (l = e.filter) != null && l.namedFilter && (r.namedFilter = e.filter.namedFilter);
117
+ const t = [];
118
+ if ((u = e.filter) != null && u.resourceIds && t.push({ l: { path: e.idProperty }, r: { constant: e.filter.resourceIds }, operator: "in" }), (c = e.filter) != null && c.query && t.push((d = e.filter) == null ? void 0 : d.query), t.length > 0) {
119
+ const y = t.length == 1 ? t[0] : { and: t };
120
+ r.q = V(y);
121
+ }
122
+ return e.order && (r.o = V(e.order)), e.referencePathsToExpand && (r.r = V(e.referencePathsToExpand)), r;
123
+ }
124
+ },
125
+ actions: {
126
+ // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
127
+ // Actions: Configuration
128
+ // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
129
+ /**
130
+ * Reset the store to its initial state.
131
+ *
132
+ * Configuration is retained, but REST collection contents and contextual state are reset.
133
+ */
134
+ reset() {
135
+ for (const e in Y)
136
+ this[e] = Y[e];
137
+ for (const e in le)
138
+ this[e] = le[e];
139
+ },
140
+ /**
141
+ * Reset the store to its initial state, but retain transient data if appropriate.
142
+ *
143
+ * As with {@link reset}, configuration is retained, but REST collection contents and contextual state are reset.
144
+ * Transient data are retained if options.limitTransientDataToLocalCollection is false.
145
+ */
146
+ resetRetainingTransientData() {
147
+ if (s.limitTransientDataToLocalCollection)
148
+ this.reset();
149
+ else {
150
+ const e = this.transientData;
151
+ this.reset(), this.transientData = e;
152
+ }
153
+ },
154
+ /**
155
+ * Turn editing mode on or off for the current detail selection.
156
+ *
157
+ * Components using this store use the editingDetailSelection state property to govern whether to show an editor for
158
+ * any current detail selection.
159
+ *
160
+ * @param editingDetailSelection The new setting: true if an the detail selection should be shown in an editor,
161
+ * false if not.
162
+ */
163
+ setEditingDetailSelection(e) {
164
+ this.editingDetailSelection = e;
165
+ },
166
+ // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
167
+ // Actions: Filtering the local collection
168
+ // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
169
+ /**
170
+ * Set the filter.
171
+ *
172
+ * This function sets the whole filter without triggering a reload of the local collection. More commonly, clients
173
+ * will call {@link setQuery} or {@link setFilterResourceIds}.
174
+ *
175
+ * @param filter The new filter.
176
+ */
177
+ setFilter(e) {
178
+ a.isEqual(e, this.filter) || (this.filter = e, this.status = "NotLoaded", this.resources = [], this.selection = [], this.detailSelection = [], this.invalidResources = [], this.editingDetailSelection = !1);
179
+ },
180
+ /**
181
+ * Set the filter query.
182
+ *
183
+ * If the collection has a state other than NotLoaded, it will be reloaded.
184
+ *
185
+ * @param query The new filter query.
186
+ * @return A promise that resolves when {@link loadResources} completes, or immediately if the collection does not
187
+ * need to be reloaded.
188
+ */
189
+ async setQuery(e) {
190
+ var r, t;
191
+ if (!a.isEqual(e, (r = this.filter) == null ? void 0 : r.query) && (e != null || ((t = this.filter) == null ? void 0 : t.query) != null)) {
192
+ const l = a.cloneDeep(this.filter) || {};
193
+ e !== null ? l.query = e : a.unset(l, "query");
194
+ const u = this.status;
195
+ this.setFilter(l), u != "NotLoaded" && await this.loadResources();
196
+ }
197
+ },
198
+ /**
199
+ * Set the list if resource IDs to filter on.
200
+ *
201
+ * If the collection has a state other than NotLoaded, it will be reloaded.
202
+ *
203
+ * @param resourceIds The list of resource IDs for the new filter.
204
+ * @return A promise that resolves when {@link loadResources} completes, or immediately if the collection does not
205
+ * need to be reloaded.
206
+ */
207
+ async setFilterResourceIds(e) {
208
+ if (!a.isEqual(e, a.get(this.filter, "resourceIds"))) {
209
+ const r = a.cloneDeep(this.filter) || {};
210
+ e != null ? r.resourceIds = e : a.unset(r, "resourceIds");
211
+ const t = this.status;
212
+ this.setFilter(r), t != "NotLoaded" && await this.loadResources();
213
+ }
214
+ },
215
+ // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
216
+ // Actions: Status
217
+ // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
218
+ /**
219
+ * Indicate that a batch save has been attempted and failed.
220
+ *
221
+ * Setting this flag is a way of communicating with other client code. The flag should be cleared after further
222
+ * edits or when another validation or save operations is attempted.
223
+ *
224
+ * @param batchSaveAttempted A flag indicating whether a batch save has been attempted and failed.
225
+ */
226
+ setBatchSaveAttempted(e) {
227
+ e != this.batchSaveAttempted && (this.batchSaveAttempted = e);
228
+ },
229
+ // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
230
+ // Actions: Loading and unloading the collection
231
+ // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
232
+ /**
233
+ * Clear the collection's contents.
234
+ *
235
+ * Configuration and contextual state are retained, but REST collection contents are reset.
236
+ */
237
+ clear() {
238
+ for (const e in Y)
239
+ this[e] = Y[e];
240
+ },
241
+ /**
242
+ * Clear the collection's contents, but retain transient data if appropriate.
243
+ *
244
+ * As with {@link reset}, configuration and contextual state are retained, but REST collection contents are reset.
245
+ * Transient data are retained if options.limitTransientDataToLocalCollection is false.
246
+ */
247
+ clearRetainingTransientData() {
248
+ if (s.limitTransientDataToLocalCollection)
249
+ this.reset();
250
+ else {
251
+ const e = this.transientData;
252
+ this.reset(), this.transientData = e;
253
+ }
254
+ },
255
+ /**
256
+ * Load the collection, if it has not been loaded.
257
+ *
258
+ * The collection will be loaded if its current status is not Loaded, Loading, LoadingMore, or Failed.
259
+ */
260
+ async ensureCollectionLoaded() {
261
+ ["Loaded", "Loading", "LoadingMore", "Failed"].includes(this.status) || await this.loadResources();
262
+ },
263
+ /**
264
+ * Load the collection.
265
+ *
266
+ * If pagination is enabled, this may result in multiple HTTP requests. The function's Promise is resolved once
267
+ * the first page is loaded.
268
+ *
269
+ * @param loadOptions Pagination options that may override the defaults.
270
+ */
271
+ async loadResources(e = {}) {
272
+ this.resetRetainingTransientData();
273
+ const r = X();
274
+ this._loadId = r, await this._loadResources(0, r, e);
275
+ },
276
+ /**
277
+ * Load the collection, optionally starting at some offset.
278
+ *
279
+ * If pagination is enabled, this may result in multiple HTTP requests. The function's Promise is resolved once
280
+ * the first page is loaded.
281
+ *
282
+ * @param offset The offset at which to start loading. When loading a whole collection, this will be 0; but if
283
+ * there are more pages to load, the function will call itself with the next page offset.
284
+ * @param loadId A unique identifier for this load operation, which is used to detect whether results should be
285
+ * discarded because a later load operation has been issued. Before calling this method, this identifier should
286
+ * be written to the store's state property named loadId.
287
+ * @param loadOptions Pagination options that may override the defaults.
288
+ */
289
+ async _loadResources(e, r, t) {
290
+ var b, q, A, z, B;
291
+ const l = e == 0;
292
+ if (this.status = l ? "Loading" : "LoadingMore", this._loadOffset = e, ((b = this.filter) == null ? void 0 : b.query) === !1) {
293
+ this.resources = [];
294
+ return;
295
+ }
296
+ const u = this.fixedQueryParams, c = a.cloneDeep(u), d = l ? (q = this.filter) != null && q.resourceIds && !this.order ? null : t.firstPageSize || ((A = s.loading) == null ? void 0 : A.firstPageSize) || t.pageSize || ((z = s.loading) == null ? void 0 : z.pageSize) || null : t.pageSize || ((B = s.loading) == null ? void 0 : B.pageSize) || null, y = d != null || s.limit != null ? a.min(a.filter([d, s.limit], (g) => g != null)) : void 0;
297
+ y != null ? (c.offset = e, c.limit = y) : e != 0 && (c.offset = e);
298
+ const U = a.map(
299
+ c,
300
+ (g, S) => g != null ? `${encodeURIComponent(S)}=${encodeURIComponent(g)}` : null
301
+ ).filter((g) => g != null).join("&"), T = a.isEmpty(U) ? s.restCollectionUrl : `${s.restCollectionUrl}?${U}`;
302
+ try {
303
+ const g = await P.get(T), S = this.fixedQueryParams;
304
+ if (r != this._loadId || e != this._loadOffset || !a.isEqual(u, S))
305
+ console.log(`Discarding resources fetched by obsolete query from ${s.restCollectionUrl}.`);
306
+ else {
307
+ const E = me.decode(a.get(g, "data.data", [])), $ = (l ? 0 : this.resources.length) + E.length, D = y == null || E.length < y || s.limit && $ >= s.limit;
308
+ console.log(
309
+ `Loaded ${E.length}${l ? "" : " more"} resources from ${s.restCollectionUrl}`
310
+ ), l && (this.resources = []);
311
+ const W = [...this.resources, ...E.map((H) => Object.freeze(H))];
312
+ this.resources = $e(W, this), this.status = D ? "Loaded" : "LoadingMore", D || this._loadResources(this.resources.length, r, t);
313
+ }
314
+ } catch (g) {
315
+ console.log(`Error while loading resources (URL="${T}"):`, g), this.clearRetainingTransientData(), this.status = "Failed";
316
+ }
317
+ },
318
+ // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
319
+ // Actions: Recording modifications to the collection
320
+ // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
321
+ /**
322
+ * Verify that a resource does not exist in the remote collection.
323
+ *
324
+ * After checking the remote collection and verifying that the resource does not exist, this function calls
325
+ * {@link recordDeletion} to delete it from the local collection.
326
+ *
327
+ * @param itemId The ID of the deleted resource to check.
328
+ * @return true if the record does not exist in the remote collection, false if it does or if an error occurred.
329
+ */
330
+ async checkForDeletedResource(e) {
331
+ let r;
332
+ try {
333
+ r = await P.get(`${s.restCollectionUrl}/${e}`);
334
+ } catch (t) {
335
+ P.isAxiosError(t) && (r = t.response);
336
+ }
337
+ return r && r.status == 404 ? (this.recordDeletion(e), !0) : !1;
338
+ },
339
+ /**
340
+ * Record a deletion, removing the deleted resource from the local collection.
341
+ *
342
+ * This should be called after deleting a resource from the remote collection. It is called, for instance, by
343
+ * {@link deleteResource}; but it can also be called when the application is aware of deletions from the remote
344
+ * collection made by other means.
345
+ *
346
+ * @param resourceId The ID of the resource that has been deleted.
347
+ */
348
+ recordDeletion(e) {
349
+ var r;
350
+ if (["Loaded", "LoadingMore"].includes(this.status)) {
351
+ let t = this.resources.findIndex((l) => v(l, this) == e);
352
+ t >= 0 && this.resources.splice(t, 1), t = this.selection.findIndex((l) => v(l, this) == e), t >= 0 && this.selection.splice(t, 1), t = this.detailSelection.findIndex((l) => v(l, this) == e), t >= 0 && (this.detailSelection.splice(t, 1), this.detailSelection.length == 0 && (this.editingDetailSelection = ((r = s.detail) == null ? void 0 : r.autoEdit) || !1)), s.limitTransientDataToLocalCollection && delete this.transientData[e];
353
+ }
354
+ },
355
+ /**
356
+ * Record an insertion, adding the inserted resource to the local collection.
357
+ *
358
+ * This should be called after inserting a resource into the remote collection. It is called, for instance, by
359
+ * {@link saveResource}; but it can also be called when the application is aware of insertions into the remote
360
+ * collection made by other means.
361
+ *
362
+ * It is important that the resources to be added to the local collection have the same object-graph
363
+ * characteristics as other resources in the local collection. (These characteristics include property inclusions
364
+ * and exclusions, as well as reference expansions.) To ensure this, you may call {@refreshResource} to fetch the
365
+ * resource using the collection's settings.
366
+ *
367
+ * @param resource The item that has been inserted.
368
+ * @param TODO
369
+ */
370
+ recordInsertion(e, { insertAtBeginning: r, transientData: t } = {}) {
371
+ var l;
372
+ if (["Loaded", "LoadingMore"].includes(this.status)) {
373
+ const u = Object.freeze(e);
374
+ r ? this.resources.unshift(u) : this.resources.push(u), (l = s.detail) != null && l.autoFromSingleInsertion && (this.detailSelection.length == 0 || this.detailSelection.length == 1 && v(this.detailSelection[0], this) == null) && (this.detailSelection = [u], this.editingDetailSelection = s.detail.autoEdit);
375
+ const c = v(e, this);
376
+ c && (t === void 0 ? delete this.transientData[c] : this.transientData[c] = t);
377
+ }
378
+ },
379
+ /**
380
+ * Record an update, making the same changes in the local collection.
381
+ *
382
+ * This should be called after updating a resource in the remote collection. It is called, for instance, by
383
+ * {@link saveResource} and {@link refreshResource}; but it can also be called when the application is aware of
384
+ * updates in the remote collection made by other means.
385
+ *
386
+ * It is important that the resource have the same object-graph characteristics as other resources in the local
387
+ * collection. (These characteristics include property inclusions and exclusions, as well as reference
388
+ * expansions.) To ensure this, you may instead call {@refreshResource} to fetch the resource using the
389
+ * collection's settings; this will in turn call {@link recordUpdate}.
390
+ *
391
+ * @param resource The item that has been updated.
392
+ */
393
+ recordUpdate(e) {
394
+ const r = v(e, this);
395
+ if (r && ["Loaded", "LoadingMore"].includes(this.status)) {
396
+ const t = Object.freeze(e);
397
+ let l = this.resources.findIndex((u) => v(u, this) == r);
398
+ l >= 0 && (this.resources[l] = t), l = this.selection.findIndex((u) => v(u, this) == r), l >= 0 && (this.selection[l] = t), l = this.detailSelection.findIndex((u) => v(u, this) == r), l >= 0 && (this.detailSelection[l] = t);
399
+ }
400
+ },
401
+ /**
402
+ * Refresh a resource by requesting it from the remote collection.
403
+ *
404
+ * If the resource already exists in the local collection, {@link recordUpdate} will be called to update it there.
405
+ * If not, this method will return the resource but will not add it to the collection.
406
+ *
407
+ * This function is called by {@link insertItem} and {@link updateItem} to ensure that the local copy of the added
408
+ * or updated resource has the same object-graph characteristics as the rest of the local collection.
409
+ *
410
+ * @param resourceId The ID of the resource to refresh.
411
+ * @return The refreshed resource, or null if refreshing failed.
412
+ */
413
+ async refreshResource(e) {
414
+ if (e) {
415
+ const r = {};
416
+ this.referencePathsToExpand && (r.r = V(this.referencePathsToExpand));
417
+ const t = a.map(
418
+ r,
419
+ (c, d) => c != null ? `${encodeURIComponent(d)}=${encodeURIComponent(c)}` : null
420
+ ).filter((c) => c != null).join("&"), l = a.isEmpty(t) ? `${s.restCollectionUrl}/${e}` : `${s.restCollectionUrl}/${e}?${t}`, u = await P.get(l);
421
+ if (u.status == 200) {
422
+ const c = u.data;
423
+ return this.recordUpdate(c), c;
424
+ }
425
+ }
426
+ return null;
427
+ },
428
+ // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
429
+ // Actions: Modifying the collection
430
+ // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
431
+ /**
432
+ * Insert a new unsaved resource into the local collection and enter editing mode.
433
+ *
434
+ * @param resourceDefaults Initial properties of the new resource.
435
+ */
436
+ addResource(e = {}) {
437
+ this.detailSelection = [a.omit(a.merge({}, e), this.idProperty)], this.editingDetailSelection = !0;
438
+ },
439
+ /**
440
+ * Delete one resource.
441
+ *
442
+ * A delete request is sent to the REST API. If it succeeds, the resource is removed from the local collection.
443
+ *
444
+ * @param resourceId The ID of the resource to delete.
445
+ */
446
+ async deleteResource(e) {
447
+ if ((await P.delete(`${s.restCollectionUrl}/${e}`)).status == 200 && ["Loaded", "LoadingMore"].includes(this.status)) {
448
+ let t = this.resources.findIndex((l) => v(l, this) == e);
449
+ t >= 0 && this.resources.splice(t, 1), t = this.selection.findIndex((l) => v(l, this) == e), t >= 0 && this.selection.splice(t, 1), t = this.detailSelection.findIndex((l) => v(l, this) == e), t >= 0 && (this.detailSelection.splice(t, 1), this.detailSelection.length == 0 && (this.editingDetailSelection = s.detail.autoEdit)), s.limitTransientDataToLocalCollection && delete this.transientData[e];
450
+ }
451
+ },
452
+ /**
453
+ * Write a new or updated resource to the remote collection, then mirror the change in the local collection.
454
+ *
455
+ * After writing changes, {@link refreshResource} is called to ensure that the local resource (which is also the
456
+ * return value) has the same object-graph characteristics as the rest of the local collection.
457
+ *
458
+ * @param resource The new or updated resource. If it has an ID, an update will be attempted; otherwise it will be
459
+ * created.
460
+ * @returns The refreshed local resource after the change has been persisted to the remote collection, or null if
461
+ * the operation failed.
462
+ */
463
+ async saveResource(e) {
464
+ const r = v(e, this), t = r == null, l = await P({
465
+ method: t ? "post" : "put",
466
+ url: t ? s.restCollectionUrl : `${s.restCollectionUrl}/${r}`,
467
+ data: e
468
+ });
469
+ if (l.status == 200) {
470
+ const u = l.data, c = v(u, this), d = c ? await this.refreshResource(c) : null;
471
+ return t && this.recordInsertion(d || Object.freeze(u)), d || u;
472
+ }
473
+ return null;
474
+ },
475
+ /**
476
+ * Write new and/or updated resources to the remote collection, and mirror the changes in the local collection.
477
+ *
478
+ * After writing changes, {@link refreshResource} is called to ensure that the local resource (which is also the
479
+ * return value) has the same object-graph characteristics as the rest of the local collection.
480
+ *
481
+ * @param resources Resources to create or update. The two operations may be mixed in the list; when a resource
482
+ * has an ID, an update will be attempted, while otherwise it will be added.
483
+ * @returns An array of refreshed local resources, one for each remote resource whose save operation succeeded.
484
+ */
485
+ async saveResources(e) {
486
+ const r = await P({
487
+ method: "put",
488
+ url: s.restCollectionUrl,
489
+ data: e
490
+ });
491
+ if (r.status == 200) {
492
+ const t = r.data || [], l = [];
493
+ for (const [u, c] of t.entries()) {
494
+ const d = v(e[u], this) == null, y = v(c, this), U = y ? await this.refreshResource(y) : null;
495
+ d && this.recordInsertion(U || c), l.push(U || Object.freeze(c));
496
+ }
497
+ return l;
498
+ }
499
+ return [];
500
+ },
501
+ // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
502
+ // Actions: Transient data
503
+ // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
504
+ /** Clear all transient data. */
505
+ clearTransientData() {
506
+ this.transientData = {};
507
+ },
508
+ /**
509
+ * Record which local resources currently fail validation.
510
+ *
511
+ * This is useful in multi-resource editing contexts.
512
+ *
513
+ * @param resourceIds The IDs of all local resources that failed validation.
514
+ */
515
+ setInvalidResourceIds(e) {
516
+ a.isEqual(e, this.invalidResources.map((r) => v(r, this))) || (this.invalidResources = e.map((r) => this.resources.find((t) => v(t, this) == r)).filter((r) => r != null));
517
+ },
518
+ /**
519
+ * Set transient data.
520
+ *
521
+ * @param transientData The new transient data.
522
+ * @param merge If true, combine each resource's transient data with existing transient data; if false, replace
523
+ * the transient data for each resource ID in the keys of transientData.
524
+ */
525
+ setTransientDataForResources(e) {
526
+ const { transientData: r, merge: t = !0 } = e;
527
+ t ? a.merge(this.transientData, r) : a.assign(this.transientData, r);
528
+ },
529
+ // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
530
+ // Actions: Managing selections
531
+ // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
532
+ /**
533
+ * Clear the selection.
534
+ */
535
+ clearSelection() {
536
+ this.setSelection([]);
537
+ },
538
+ /**
539
+ * Remove resources from the selection.
540
+ *
541
+ * @param resourceIds The IDs of resources to remove from the selection.
542
+ */
543
+ deselectResources(e) {
544
+ const r = this.selection.map((t) => v(t, this)).filter((t) => t != null && !e.includes(t));
545
+ this.setSelection(r);
546
+ },
547
+ /**
548
+ * Add to or replace the selection.
549
+ *
550
+ * @param recordIds The record IDs to select.
551
+ * @param addToSelection true if the existing selection should be expanded, false if it should be replaced.
552
+ * @param edit If not undefined, sets the editing mode of the new selection. If undefined, the editing mode will
553
+ * be left as is, or set to true if options.detail.autoEdit is true.
554
+ */
555
+ selectResources(e, r) {
556
+ const { addToSelection: t, edit: l } = r || {}, u = this.selection.map((d) => v(d, this));
557
+ let c = e;
558
+ if (t) {
559
+ const d = a.difference(e, u);
560
+ d.length > 0 && (c = u.concat(d).filter((y) => y != null));
561
+ }
562
+ a.isEqual(u, c) || this.setSelection(c, l);
563
+ },
564
+ /**
565
+ * Set a new selection.
566
+ *
567
+ * @param selectedResourceIds The resource IDs in the new selection.
568
+ * @param edit If not undefined, sets the editing mode of the new selection. If undefined, the editing mode will
569
+ * be left as is, or set to true if options.detail.autoEdit is true.
570
+ */
571
+ setSelection(e, r) {
572
+ if (!a.isEqual(e, this.selection.map((t) => v(t, this)))) {
573
+ let t = !0;
574
+ if (this.editors.length > 0) {
575
+ if (s.detail.autoFromSingleSelection && this.selection.length == 1)
576
+ t = !1;
577
+ else if (s.detail.autoFromMultipleSelection && s.detail.allowMultiple && this.selection.length > 1)
578
+ t = !1;
579
+ else if (s.detail.constrainToSelection) {
580
+ const l = this.selection.map((d) => v(d, this)), c = this.detailSelection.map((d) => v(d, this)).filter((d) => l.includes(d));
581
+ this.detailSelection.filter((d) => !c.includes(v(d, this))).length > 0 && (t = !1);
582
+ }
583
+ }
584
+ if (!t)
585
+ return;
586
+ if (this.selection = e.map((l) => this.resources.find((u) => v(u, this) == l)).filter((l) => l != null), s.detail.autoFromSingleSelection && this.selection.length == 1) {
587
+ const l = this.selection[0];
588
+ (this.detailSelection.length != 1 || v(this.detailSelection[0], this) != v(l, this)) && (this.detailSelection = [l]);
589
+ } else if (s.detail.autoFromMultipleSelection && s.detail.allowMultiple && this.selection.length > 1)
590
+ a.isEqual(
591
+ this.selection.map((l) => v(l, this)),
592
+ this.detailSelection.map((l) => v(l, this))
593
+ ) || (this.detailSelection = a.clone(this.selection));
594
+ else if (s.detail.constrainToSelection) {
595
+ const l = this.selection.map((d) => v(d, this)), u = this.detailSelection.map((d) => v(d, this)), c = u.filter((d) => l.includes(d));
596
+ a.isEqual(c, u) || (this.detailSelection = this.detailSelection.filter((d) => c.includes(v(d, this))));
597
+ }
598
+ this.detailSelection.length == 0 ? this.editingDetailSelection = !1 : this.editingDetailSelection = r !== void 0 ? r : this.editingDetailSelection || s.detail.autoEdit;
599
+ }
600
+ },
601
+ // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
602
+ // Actions: Managing the detail view
603
+ // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
604
+ /**
605
+ * Hide the detail view.
606
+ *
607
+ * This clears detailSelection and sets the detail editing mode to false.
608
+ */
609
+ hideDetail() {
610
+ this.detailSelection.length > 0 && (this.detailSelection = [], this.editingDetailSelection = !1);
611
+ },
612
+ /**
613
+ * Show the current selection in the detail view.
614
+ *
615
+ * If options.detail.allowMultiple is false and more than one resource is selected, the detail view will not be
616
+ * changed.
617
+ *
618
+ * @param edit If not undefined, sets the detail editing mode. If undefined, the editing mode will be left as is,
619
+ * or set to true if options.detail.autoEdit is true.
620
+ */
621
+ showSelectionAsDetail(e) {
622
+ if (this.selection.length <= 1 || s.detail.allowMultiple) {
623
+ const r = this.selection.map((l) => v(l, this)), t = this.detailSelection.map((l) => v(l, this));
624
+ a.isEqual(r, t) || (this.detailSelection = a.clone(this.selection)), this.detailSelection.length == 0 ? this.editingDetailSelection = !1 : this.editingDetailSelection = e !== void 0 ? e : this.editingDetailSelection || s.detail.autoEdit;
625
+ }
626
+ },
627
+ // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
628
+ // Actions: Tracking editors
629
+ // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
630
+ /**
631
+ * Deregister an editor.
632
+ *
633
+ * @param editor The editor to deregister.
634
+ */
635
+ deregisterEditor(e) {
636
+ a.remove(this.editors, (r) => r == e);
637
+ },
638
+ /**
639
+ * Register an editor.
640
+ *
641
+ * @param editor The editor to register.
642
+ */
643
+ registerEditor(e) {
644
+ this.editors.includes(e) || this.editors.push(e);
645
+ },
646
+ // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
647
+ // Actions: Tracking list navigators
648
+ // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
649
+ /**
650
+ * Deregister a list navigator.
651
+ *
652
+ * @param name The name of the list navigator to deregister.
653
+ * @param listNavigator The list navigator. If defined, the named list navigator will only be deleted if it equals
654
+ * this parameter.
655
+ */
656
+ deregisterListNavigator({ name: e, listNavigator: r }) {
657
+ (r == null || this.listNavigators[e] == r) && delete this.listNavigators[e];
658
+ },
659
+ /**
660
+ * Register a list navigator.
661
+ *
662
+ * Registering a component such as a list view as a list navigator can help other components with list navigation.
663
+ * For instance, code that implements a "next" button in a detail view might use the list navigator to determine
664
+ * what resource to select next.
665
+ *
666
+ * If another list navigator is registered under this name, its registration will be replaced.
667
+ *
668
+ * @param name The name under which to register the list navigator.
669
+ * @param listNavigator The list navigator.
670
+ */
671
+ registerListNavigator({ name: e, listNavigator: r }) {
672
+ this.listNavigators[e] != r && (this.listNavigators[e] = r);
673
+ }
674
+ }
675
+ });
676
+ return (() => {
677
+ const e = (r, t) => {
678
+ const l = R(r, t);
679
+ return ie.registerStore(l.$id, l), l;
680
+ };
681
+ return e.$id = R.$id, e;
682
+ })();
683
+ }, ie = new Ie(), Be = (f = {}) => {
684
+ var oe, ce, ue, de;
685
+ const {
686
+ collectionId: s,
687
+ draftBatchId: R,
688
+ enabled: L,
689
+ resourceType: e,
690
+ options: r
691
+ } = f, t = I(void 0), l = I(s), u = I(R), c = I(L ?? !0), d = I([te(e)]), y = I(r), U = m(() => u.value), T = I(c.value), b = I(X()), q = I((ce = (oe = y.value) == null ? void 0 : oe.filter) == null ? void 0 : ce.resourceIds), A = I((de = (ue = y.value) == null ? void 0 : ue.filter) == null ? void 0 : de.query), z = m(
692
+ () => u.value == null && l.value != null && ie.getStore(l.value) != null
693
+ ), B = I(z.value), g = m(() => $("status", "Uninitialized"));
694
+ function S(i) {
695
+ if (t.value)
696
+ return i(t.value);
697
+ }
698
+ async function E(i) {
699
+ if (t.value)
700
+ return await i(t.value);
701
+ }
702
+ function $(i, o) {
703
+ if (t.value)
704
+ return t.value[i];
705
+ if (o !== void 0)
706
+ return o;
707
+ throw "Attempted to use a REST collection store that has not been created, with no default value.";
708
+ }
709
+ const D = (i = {}) => {
710
+ var fe, ve, ge, Re;
711
+ const {
712
+ collectionId: o,
713
+ draftBatchId: w,
714
+ enabled: _,
715
+ resourceType: se,
716
+ options: he
717
+ } = i;
718
+ l.value = o, u.value = w, c.value = _ ?? !0, d.value = [te(se)], he != null && (y.value = he, q.value = (ve = (fe = y.value) == null ? void 0 : fe.filter) == null ? void 0 : ve.resourceIds, A.value = (Re = (ge = y.value) == null ? void 0 : ge.filter) == null ? void 0 : Re.query), b.value = X(), W(c.value);
719
+ }, W = async (i) => {
720
+ i != T.value && (T.value = i, i && (K(), N()));
721
+ }, H = async (i) => {
722
+ q.value = i, await E(async (o) => await o.setFilterResourceIds(q.value || null));
723
+ }, J = async (i) => {
724
+ if (A.value = i, g.value != "Uninitialized") {
725
+ const o = i, w = m(() => a.isFunction(o) ? p.value ? o(p.value) : null : o);
726
+ await E((_) => _.setQuery(w.value || null));
727
+ }
728
+ }, K = () => {
729
+ y.value = a.merge({}, y.value || {}, {
730
+ filter: { resourceIds: q.value, query: A.value }
731
+ });
732
+ }, p = m(
733
+ () => d.value[0].value || void 0
734
+ ), k = function(i) {
735
+ const o = a.get(i, "filter.query"), w = a.get(i, "referencePathsToExpand"), _ = a.isFunction(o) ? o(p.value) : o, se = p.value ? a.isFunction(w) ? w(p.value) : w || [] : [];
736
+ return {
737
+ ...a.cloneDeep(i || {}),
738
+ filter: {
739
+ ...a.cloneDeep((i == null ? void 0 : i.filter) || {}),
740
+ query: _
741
+ },
742
+ referencePathsToExpand: se
743
+ };
744
+ }, x = m(() => k(y.value)), M = m(() => {
745
+ if (!p.value)
746
+ return null;
747
+ if (x.value.restCollectionUrl !== void 0)
748
+ return x.value.restCollectionUrl;
749
+ if (!B.value)
750
+ return !p.value || !p.value.collectionName ? null : U.value ? `${ee.config.apiBaseUrl}/draft-batches/${U.value}/${p.value.collectionName}` : `${ee.config.apiBaseUrl}/${p.value.collectionName}`;
751
+ }), n = m(() => {
752
+ var i;
753
+ if (p.value)
754
+ return a.mergeWith(
755
+ a.cloneDeep(De),
756
+ x.value,
757
+ {
758
+ idProperty: (i = p.value) == null ? void 0 : i.idProperty,
759
+ restCollectionUrl: M.value || ""
760
+ },
761
+ (o, w) => {
762
+ if (a.isArray(w) && w.length == 0 && (o == null || a.isArray(o)))
763
+ return w;
764
+ }
765
+ );
766
+ }), h = I(0), F = m(
767
+ () => {
768
+ var i;
769
+ return h.value, l.value || p.value && ((i = p.value) == null ? void 0 : i.collectionName) && (U.value ? `draftBatches/${U.value}/${p.value.collectionName}/${b.value}` : `${p.value.collectionName}/${b.value}`) || null;
770
+ }
771
+ ), N = () => {
772
+ if (T.value) {
773
+ let i = !1;
774
+ return p.value && F.value && (t.value = ie.getStore(F.value), t.value ? i = !1 : n.value && (B.value = !1, t.value = Pe(F.value, n.value)(), i = !0)), i;
775
+ } else
776
+ return !1;
777
+ }, G = () => {
778
+ F.value && l.value == F.value ? (t.value = void 0, N()) : (t.value = void 0, h.value = h.value + 1, N());
779
+ };
780
+ C(U, (i, o) => {
781
+ a.isEqual(i, o) || G();
782
+ }), C(T, (i, o) => {
783
+ i != o && (i ? N() : t.value = void 0);
784
+ }), C(p, (i, o) => {
785
+ i && !o ? N() : !i && o || a.isEqual(i, o) || G();
786
+ }), C(n, (i, o) => {
787
+ a.isEqual(i, o) || G();
788
+ }), C(z, () => {
789
+ z.value || (B.value = !1);
790
+ }), C(F, () => N()), C(M, (i, o) => {
791
+ a.isEqual(i, o) || G();
792
+ });
793
+ const j = [], Ee = function(i) {
794
+ g.value != "Uninitialized" ? Le(i) : j.push(i);
795
+ };
796
+ return C(g, (i, o) => {
797
+ if (i != "Uninitialized" && o == "Uninitialized") {
798
+ const w = a.clone(j);
799
+ j.splice(0, j.length);
800
+ for (const _ of w)
801
+ _();
802
+ }
803
+ }), N(), {
804
+ // Configuration
805
+ collectionId: F,
806
+ draftBatchId: U,
807
+ resourceType: p,
808
+ // Status
809
+ enabled: T,
810
+ status: g,
811
+ batchSaveAttempted: m(() => $("batchSaveAttempted", !1)),
812
+ // Resources loaded from the REST API
813
+ invalidResources: m(() => $("invalidResources", [])),
814
+ resources: m(() => g.value != "Uninitialized" ? (E((i) => i.ensureCollectionLoaded()), $("resources", [])) : []),
815
+ // Transient data
816
+ transientData: m(() => $("transientData", [])),
817
+ // Selection and detail selection
818
+ detailSelection: m(() => $("detailSelection", [])),
819
+ editingDetailSelection: m(() => $("editingDetailSelection", !1)),
820
+ selection: m(() => $("selection", [])),
821
+ // Methods: Configuration
822
+ reconfigureCollection: D,
823
+ setEditingDetailSelection: (i) => S(
824
+ (o) => o.setEditingDetailSelection(i)
825
+ ),
826
+ setEnabled: W,
827
+ setFilterResourceIds: H,
828
+ setQuery: J,
829
+ // Methods: Status
830
+ ensureStore: N,
831
+ // TODO Rename
832
+ setBatchSaveAttempted: (i) => S((o) => o.setBatchSaveAttempted(i)),
833
+ // Local collection management
834
+ clear: () => S((i) => i.clear()),
835
+ ensureCollectionLoaded: async () => await E(async (i) => i.ensureCollectionLoaded()),
836
+ loadResources: async () => await E(async (i) => await i.loadResources()),
837
+ // Methods: Recording changes to the collection
838
+ addResource: (i) => S((o) => o.addResource(i)),
839
+ checkForDeletedResource: async (i) => await E(async (o) => await o.checkForDeletedResource(i)) == !0,
840
+ recordDeletion: (i) => S((o) => o.recordDeletion(i)),
841
+ recordInsertion: (i, { insertAtBeginning: o = !1, transientData: w = void 0 } = {}) => S((_) => _.recordInsertion(i, { insertAtBeginning: o, transientData: w })),
842
+ recordUpdate: (i) => S((o) => o.recordUpdate(i)),
843
+ refreshResource: async (i) => await E(
844
+ async (o) => await o.refreshResource(i)
845
+ ),
846
+ // Methods: Modifying the collection
847
+ deleteResource: async (i) => await E(
848
+ async (o) => await o.deleteResource(i)
849
+ ),
850
+ saveResource: async (i) => await E(async (o) => await o.saveResource(i)),
851
+ saveResources: async (i) => await E(async (o) => await o.saveResources(i)),
852
+ // Methods: Transient data
853
+ clearTransientData: () => S((i) => i.clearTransientData()),
854
+ setInvalidResourceIds: (i) => S((o) => o.setInvalidResourceIds(i)),
855
+ setTransientDataForResources: (i) => S(
856
+ (o) => o.setTransientDataForResources(i)
857
+ ),
858
+ // Methods: Selection and detail selection
859
+ clearSelection: () => S((i) => i.clearSelection()),
860
+ deselectResources: (i) => S((o) => o.deselectResources(i)),
861
+ selectResources: (i, o) => S(
862
+ (w) => w.selectResources(i, o)
863
+ ),
864
+ // Methods: Managing the detail view
865
+ hideDetail: () => S((i) => i.hideDetail()),
866
+ // Methods: Editors
867
+ deregisterEditor: (i) => S((o) => o.deregisterEditor(i)),
868
+ registerEditor: (i) => S((o) => o.registerEditor(i)),
869
+ // Methods: List navigators
870
+ deregisterListNavigator: (i) => S((o) => o.deregisterListNavigator(i)),
871
+ registerListNavigator: (i) => S((o) => o.registerListNavigator(i)),
872
+ // Callbacks
873
+ onItemsStoreReady: Ee
874
+ };
875
+ }, Qe = () => {
876
+ ie.clearAllStores();
877
+ };
878
+ function ae(f, s) {
879
+ return a.get(f, (s == null ? void 0 : s.idProperty) || "_id");
880
+ }
881
+ const Ue = {
882
+ idProperty: "_id"
883
+ }, Z = {
884
+ resource: null,
885
+ status: "NotLoaded"
886
+ }, xe = (f, s) => {
887
+ s = a.merge({}, Ue, s);
888
+ const R = ye(f, {
889
+ state: () => ({
890
+ idProperty: s.idProperty,
891
+ resourceId: s.resourceId || null,
892
+ resourceUrl: s.resourceUrl || null,
893
+ referencePathsToExpand: s.referencePathsToExpand || null,
894
+ ...Z
895
+ }),
896
+ getters: {
897
+ currentResourceUrl: (e) => e.resourceUrl || (s.restCollectionUrl && e.resourceId ? `${s.restCollectionUrl}/${e.resourceId}` : null) || s.restCollectionUrl || null,
898
+ /** Get the REST query parameters that can be determined from the options. */
899
+ fixedQueryParams: (e) => {
900
+ const r = {};
901
+ return e.referencePathsToExpand && (r.r = V(e.referencePathsToExpand)), r;
902
+ }
903
+ },
904
+ actions: {
905
+ // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
906
+ // Actions: Configuration
907
+ // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
908
+ /**
909
+ * Reset the store to its initial state.
910
+ *
911
+ * Configuration is retained, but REST resource content and contextual state are reset.
912
+ */
913
+ reset() {
914
+ for (const e in Z)
915
+ this[e] = Z[e];
916
+ },
917
+ async setResourceId(e) {
918
+ const r = this.currentResourceUrl;
919
+ this.resourceId = e, !a.isEqual(this.currentResourceUrl, r) && this.status != "NotLoaded" && await this.loadResource();
920
+ },
921
+ async setResourceUrl(e) {
922
+ const r = this.currentResourceUrl;
923
+ this.resourceUrl = e, !a.isEqual(this.currentResourceUrl, r) && this.status != "NotLoaded" && await this.loadResource();
924
+ },
925
+ // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
926
+ // Actions: Loading and unloading the collection
927
+ // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
928
+ /**
929
+ * Clear the resource.
930
+ *
931
+ * Configuration and contextual state are retained, but REST collection contents are reset.
932
+ */
933
+ clear() {
934
+ for (const e in Z)
935
+ this[e] = Z[e];
936
+ },
937
+ /**
938
+ * Load the resource, if it has not been loaded.
939
+ *
940
+ * The resource will be loaded if its current status is not Loaded, Loading, or Failed.
941
+ */
942
+ async ensureResourceLoaded() {
943
+ ["Loaded", "Loading", "Failed"].includes(this.status) || await this.loadResource();
944
+ },
945
+ /**
946
+ * Load the resource.
947
+ *
948
+ * @return A promise that resolves when the resource has been loaded.
949
+ */
950
+ async loadResource() {
951
+ this.reset();
952
+ const e = X();
953
+ if (this._loadId = e, this.currentResourceUrl) {
954
+ this.status = "Loading";
955
+ const r = this.fixedQueryParams, t = a.cloneDeep(r), l = a.map(
956
+ t,
957
+ (c, d) => c != null ? `${encodeURIComponent(d)}=${encodeURIComponent(c)}` : null
958
+ ).filter((c) => c != null).join("&"), u = a.isEmpty(l) ? this.currentResourceUrl : `${this.currentResourceUrl}?${l}`;
959
+ try {
960
+ const c = await P.get(u), d = this.fixedQueryParams;
961
+ e != this._loadId || !a.isEqual(r, d) ? console.log(`Discarding resource fetched by obsolete query from ${u}.`) : (this.resource = me.decode(a.get(c, "data", {})), this.status = "Loaded");
962
+ } catch (c) {
963
+ console.log(`Error while loading resource (URL="${u}")`, c), this.reset(), this.status = "Failed";
964
+ }
965
+ } else
966
+ throw "Cannot load a resource because its URL, or its ID and collection URL, are unknown.";
967
+ },
968
+ // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
969
+ // Actions: Recording modifications to the collection
970
+ // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
971
+ /**
972
+ * Verify that the resource does not exist in the remote collection.
973
+ *
974
+ * After checking the remote collection and verifying that the resource does not exist, this function calls
975
+ * {@link recordDeletion} to delete it from the local collection.
976
+ *
977
+ * @return true if the record does not exist in the remote collection, false if it does or if an error occurred.
978
+ */
979
+ async checkForDeletedResource() {
980
+ if (this.currentResourceUrl) {
981
+ let e;
982
+ try {
983
+ e = await P.get(this.currentResourceUrl);
984
+ } catch (r) {
985
+ P.isAxiosError(r) && (e = r.response);
986
+ }
987
+ return e && e.status == 404 ? (this.recordDeletion(), !0) : !1;
988
+ } else
989
+ throw "Cannot check for a deleted resource because its URL, or its ID and collection URL, are unknown.";
990
+ },
991
+ /**
992
+ * Record a deletion, removing the deleted resource from the local collection.
993
+ *
994
+ * This should be called after deleting the resource from the remote collection. It is called, for instance, by
995
+ * {@link deleteResource}; but it can also be called when the application is aware of a deletion from the remote
996
+ * collection made by other means.
997
+ */
998
+ recordDeletion() {
999
+ this.resource = null, this.status = "Loaded";
1000
+ },
1001
+ /**
1002
+ * Record an insertion, adding the inserted resource to the local collection.
1003
+ *
1004
+ * This should be called after inserting a resource into the remote collection. It is called, for instance, by
1005
+ * {@link saveResource}; but it can also be called when the application is aware of insertions into the remote
1006
+ * collection made by other means.
1007
+ *
1008
+ * This should only be called if the inserted resource is a saved version of the resource tracked by this store.
1009
+ * Otherwise the store's resource may not match its resourceId and resourceUrl properties when the function
1010
+ * returns.
1011
+ *
1012
+ * It is important that the resources to be added to the local collection have the same object-graph
1013
+ * characteristics as other resources in the local collection. (These characteristics include property inclusions
1014
+ * and exclusions, as well as reference expansions.) To ensure this, you may call {@refreshResource} to fetch the
1015
+ * resource using the collection's settings.
1016
+ *
1017
+ * @param resource The resource that has been inserted.
1018
+ */
1019
+ recordInsertion(e) {
1020
+ this.resourceId = ae(e, this) || null, this.status == "Loaded" && (this.resource = Object.freeze(e));
1021
+ },
1022
+ /**
1023
+ * Record an update, making the same changes in the local resource.
1024
+ *
1025
+ * This should be called after updating a remote resource. It is called, for instance, by {@link saveResource} and
1026
+ * {@link refreshResource}; but it can also be called when the application is aware of updates in the remote
1027
+ * collection made by other means.
1028
+ *
1029
+ * This should only be called if the inserted resource is a saved version of the resource tracked by this store.
1030
+ * Otherwise the store's resource may not match its resourceId and resourceUrl properties when the function
1031
+ * returns.
1032
+ *
1033
+ * It is important that the resource have the same object-graph characteristics as other resources in the local
1034
+ * collection. (These characteristics include property inclusions and exclusions, as well as reference
1035
+ * expansions.) To ensure this, you may instead call {@refreshResource} to fetch the resource using the
1036
+ * collection's settings; this will in turn call {@link recordUpdate}.
1037
+ *
1038
+ * @param resource The resource that has been updated.
1039
+ */
1040
+ recordUpdate(e) {
1041
+ this.resourceId = ae(e, this) || null, this.status == "Loaded" && (this.resource = Object.freeze(e));
1042
+ },
1043
+ async refreshResource() {
1044
+ return await this.loadResource(), this.resource;
1045
+ },
1046
+ // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1047
+ // Actions: Modifying the resource
1048
+ // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1049
+ /**
1050
+ * Delete the resource.
1051
+ *
1052
+ * A delete request is sent to the REST API. If it succeeds, the resource is removed from the local store.
1053
+ */
1054
+ async deleteResource() {
1055
+ if (this.currentResourceUrl)
1056
+ (await P.delete(this.currentResourceUrl)).status == 200 && this.recordDeletion();
1057
+ else
1058
+ throw "Cannot delete a resource because its URL, or its ID and collection URL, are unknown.";
1059
+ },
1060
+ /**
1061
+ * Write a new or updated resource to the remote resource, then mirror the change locally.
1062
+ *
1063
+ * After writing changes, {@link refreshResource} is called to ensure that the local resource (which is also the
1064
+ * return value) has the same object-graph characteristics as the rest of the local collection.
1065
+ *
1066
+ * @param resource The new or updated resource. If it has an ID, an update will be attempted; otherwise it will be
1067
+ * created.
1068
+ * @returns The refreshed local resource after the change has been persisted to the remote collection, or null if
1069
+ * the operation failed.
1070
+ */
1071
+ async saveResource(e) {
1072
+ const r = ae(e, this), t = r == null;
1073
+ if (!r)
1074
+ throw "The REST resource store cannot create new resources on the server.";
1075
+ if (!this.currentResourceUrl)
1076
+ throw "Cannot save a resource because its URL, or its ID and collection URL, are unknown.";
1077
+ const l = await P({
1078
+ method: t ? "post" : "put",
1079
+ url: this.currentResourceUrl,
1080
+ data: e
1081
+ });
1082
+ if (l.status == 200) {
1083
+ const u = l.data, c = await this.refreshResource();
1084
+ return t && this.recordInsertion(c || u), c || Object.freeze(u);
1085
+ }
1086
+ return null;
1087
+ },
1088
+ // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1089
+ // Actions: Custom API endpoints
1090
+ // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1091
+ async makeCustomApiRequest(e) {
1092
+ const { method: r, subpath: t, url: l, data: u } = e;
1093
+ let c = l;
1094
+ if (!c)
1095
+ if (this.currentResourceUrl)
1096
+ c = `${this.currentResourceUrl}/${t}`;
1097
+ else
1098
+ throw "Cannot make a custom API request for a resource because its URL, or its ID and collection URL, are unknown.";
1099
+ const d = await P({
1100
+ method: r || "get",
1101
+ url: c,
1102
+ data: u
1103
+ });
1104
+ return d.status >= 200 && d.status < 300 ? d.data : null;
1105
+ }
1106
+ }
1107
+ });
1108
+ return (() => {
1109
+ const e = (r, t) => {
1110
+ const l = R(r, t);
1111
+ return ne.registerStore(l.$id, l), l;
1112
+ };
1113
+ return e.$id = R.$id, e;
1114
+ })();
1115
+ }, ne = new Ie(), Me = (f = {}) => {
1116
+ const {
1117
+ resourceClientId: s,
1118
+ draftBatchId: R,
1119
+ enabled: L,
1120
+ resourceType: e,
1121
+ options: r
1122
+ } = f, t = I(void 0), l = I(s), u = I(R), c = I(L ?? !0), d = I([te(e)]), y = I(r), U = m(() => u.value), T = I(c.value), b = I(X()), q = m(
1123
+ () => u.value == null && l.value != null && ne.getStore(l.value) != null
1124
+ ), A = I(q.value), z = m(() => S("status", "Uninitialized"));
1125
+ function B(n) {
1126
+ if (t.value)
1127
+ return n(t.value);
1128
+ }
1129
+ async function g(n) {
1130
+ if (t.value)
1131
+ return await n(t.value);
1132
+ }
1133
+ function S(n, h) {
1134
+ if (t.value)
1135
+ return t.value[n];
1136
+ if (h !== void 0)
1137
+ return h;
1138
+ throw "Attempted to use a REST resource store that has not been created, with no default value.";
1139
+ }
1140
+ const E = (n = {}) => {
1141
+ const {
1142
+ resourceClientId: h,
1143
+ draftBatchId: F,
1144
+ enabled: N,
1145
+ resourceType: G,
1146
+ options: j
1147
+ } = n;
1148
+ l.value = h, u.value = F, c.value = N ?? !0, d.value = [te(G)], j != null && (y.value = j), b.value = X(), $(c.value);
1149
+ }, $ = async (n) => {
1150
+ n != T.value && (T.value = n, n && x());
1151
+ }, D = m(
1152
+ () => d.value[0].value || void 0
1153
+ ), W = function(n) {
1154
+ const h = a.get(n, "referencePathsToExpand"), F = D.value ? a.isFunction(h) ? h(D.value) : h || [] : [];
1155
+ return {
1156
+ ...a.cloneDeep(n || {}),
1157
+ referencePathsToExpand: F
1158
+ };
1159
+ }, H = m(() => W(y.value)), J = m(() => {
1160
+ if (!D.value)
1161
+ return null;
1162
+ if (!A.value)
1163
+ return !D.value || !D.value.collectionName ? null : U.value ? `${ee.config.apiBaseUrl}/draft-batches/${U.value}/${D.value.collectionName}` : `${ee.config.apiBaseUrl}/${D.value.collectionName}`;
1164
+ }), K = m(() => {
1165
+ if (D.value && J.value)
1166
+ return a.mergeWith(
1167
+ a.cloneDeep(Ue),
1168
+ H.value,
1169
+ {
1170
+ idProperty: D.value.idProperty,
1171
+ restCollectionUrl: J.value
1172
+ },
1173
+ (n, h) => {
1174
+ if (a.isArray(h) && h.length == 0 && (n == null || a.isArray(n)))
1175
+ return h;
1176
+ }
1177
+ );
1178
+ }), p = I(0), k = m(
1179
+ () => {
1180
+ var n;
1181
+ return p.value, l.value || D.value && ((n = D.value) == null ? void 0 : n.collectionName) && (U.value ? `draftBatches/${U.value}/${D.value.collectionName}/${b.value}` : `${D.value.collectionName}/${b.value}`) || null;
1182
+ }
1183
+ ), x = () => {
1184
+ if (T.value) {
1185
+ let n = !1;
1186
+ return D.value && k.value && (t.value = ne.getStore(k.value), t.value ? n = !1 : K.value && (A.value = !1, t.value = xe(k.value, K.value)(), n = !0)), n;
1187
+ } else
1188
+ return !1;
1189
+ }, M = () => {
1190
+ k.value && l.value == k.value ? (t.value = void 0, x()) : (t.value = void 0, p.value = p.value + 1, x());
1191
+ };
1192
+ return C(U, (n, h) => {
1193
+ a.isEqual(n, h) || M();
1194
+ }), C(T, (n, h) => {
1195
+ n != h && (n ? x() : t.value = void 0);
1196
+ }), C(D, (n, h) => {
1197
+ n && !h ? x() : !n && h || a.isEqual(n, h) || M();
1198
+ }), C(K, (n, h) => {
1199
+ a.isEqual(n, h) || M();
1200
+ }), C(q, () => {
1201
+ q.value || (A.value = !1);
1202
+ }), C(k, () => x()), C(J, (n, h) => {
1203
+ a.isEqual(n, h) || M();
1204
+ }), x(), {
1205
+ // Configuration
1206
+ resourceClientId: k,
1207
+ draftBatchId: U,
1208
+ enabled: T,
1209
+ resourceType: D,
1210
+ // Status
1211
+ status: z,
1212
+ // Resources loaded from the REST API
1213
+ resource: m(() => z.value != "Uninitialized" ? (g((n) => n.ensureResourceLoaded()), S("resource", [])) : []),
1214
+ resourceId: m(() => S("resourceId", null)),
1215
+ resourceUrl: m(() => S("resourceUrl", null)),
1216
+ // Methods: Configuration
1217
+ reconfigureClient: E,
1218
+ setEnabled: $,
1219
+ setResourceId: async (n) => await g(async (h) => await h.setResourceId(n)),
1220
+ setResourceUrl: async (n) => await g(async (h) => await h.setResourceUrl(n)),
1221
+ // Methods: Status
1222
+ ensureStore: x,
1223
+ // Methods: Resource management
1224
+ clear: () => B((n) => n.clear()),
1225
+ ensureResourceLoaded: async () => await g(async (n) => n.ensureResourceLoaded()),
1226
+ loadResource: async () => await g(async (n) => await n.loadResource()),
1227
+ // Methods: Recording changes to the resource
1228
+ checkForDeletedResource: async () => await g(async (n) => await n.checkForDeletedResource()) == !0,
1229
+ recordDeletion: () => g((n) => n.recordDeletion()),
1230
+ recordInsertion: (n) => g((h) => h.recordInsertion(n)),
1231
+ recordUpdate: (n) => g((h) => h.recordUpdate(n)),
1232
+ refreshResource: async () => await g(async (n) => await n.refreshResource()),
1233
+ // Methods: Modifying the resource
1234
+ deleteResource: async () => await g(async (n) => await n.deleteResource()),
1235
+ saveResource: async (n) => await g(async (h) => await h.saveResource(n)),
1236
+ // Methods: Custom API endpoints
1237
+ makeCustomApiRequest: async (n) => await g(
1238
+ async (h) => await h.makeCustomApiRequest(n)
1239
+ )
1240
+ };
1241
+ }, ee = {
1242
+ config: { ...pe }
1243
+ };
1244
+ function je(f) {
1245
+ ee.config = a.merge({}, pe, f);
1246
+ }
1247
+ export {
1248
+ ke as ApiClientError,
1249
+ Qe as clearAllRestCollections,
1250
+ je as initRestClient,
1251
+ ee as restClient,
1252
+ Be as useRestCollection,
1253
+ Me as useRestResource
1254
+ };