@ahoo-wang/wow-view-store 9.2.0-rc.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.
@@ -0,0 +1,102 @@
1
+ import { BindingError, WowError } from '@ahoo-wang/wow-client';
2
+ import { ViewStoreError, ViewStoreErrorCode } from '@ahoo-wang/wow-view-engine';
3
+ /**
4
+ * The view store's own error codes, beside Wow's (`ErrorCodes` of
5
+ * `@ahoo-wang/wow-client`).
6
+ *
7
+ * Named apart from the engine's `ViewStoreErrorCode` (the port's six codes): these
8
+ * are the server's `errorCode` strings, which a `ViewStoreError` carries as
9
+ * `detail.code`. Mirrors `ViewStoreErrorCodes` in
10
+ * `view-store/wow-view-store-api/src/main/kotlin/me/ahoo/wow/viewstore/api/ViewStoreErrorCodes.kt`.
11
+ */
12
+ export declare const WowViewStoreErrorCodes: Readonly<{
13
+ /** A write that is not a valid view or preferences write (HTTP 400). */
14
+ readonly VIEW_INVALID: "ViewInvalid";
15
+ /** The request carries no `CoSec-App-Id` (HTTP 400). */
16
+ readonly VIEW_APP_REQUIRED: "ViewAppRequired";
17
+ /** A system view is read-only (HTTP 403). */
18
+ readonly SYSTEM_VIEW_READ_ONLY: "SystemViewReadOnly";
19
+ /** The path's tenant or owner is missing, blank or invisible (HTTP 400). */
20
+ readonly VIEW_SCOPE_REQUIRED: "ViewScopeRequired";
21
+ /** The view store's event streams are closed to HTTP queries (HTTP 403). */
22
+ readonly VIEW_EVENT_STREAM_CLOSED: "ViewEventStreamClosed";
23
+ }>;
24
+ /**
25
+ * The binding error code a claim refusal names each shared dashboard with
26
+ * (`View.REFERENCED_BY_SHARED_DASHBOARD`): the board's id as `name`, its
27
+ * title as `msg`.
28
+ */
29
+ export declare const REFERENCED_BY_SHARED_DASHBOARD = "referenced-by-shared-dashboard";
30
+ /**
31
+ * A request that did not succeed, as the store reads it: the server's error,
32
+ * when the server answered with one, and the HTTP status, when a response
33
+ * came back at all.
34
+ */
35
+ export declare class Failure {
36
+ /** What the request threw. */
37
+ readonly cause: unknown;
38
+ /** The server's error, read from the failed response. */
39
+ readonly wow?: WowError | undefined;
40
+ /** The status of the failed response; absent when none came back. */
41
+ readonly status?: number | undefined;
42
+ constructor(
43
+ /** What the request threw. */
44
+ cause: unknown,
45
+ /** The server's error, read from the failed response. */
46
+ wow?: WowError | undefined,
47
+ /** The status of the failed response; absent when none came back. */
48
+ status?: number | undefined);
49
+ /** The server's error code, if it answered with one. */
50
+ get errorCode(): string | undefined;
51
+ get bindingErrors(): readonly BindingError[];
52
+ /**
53
+ * The path variable the fetcher's interceptors never filled, when that is
54
+ * why the request was never sent: the host's set-up is wrong, not the
55
+ * network.
56
+ */
57
+ get unfilled(): string | undefined;
58
+ /**
59
+ * The port's code for it (see {@link portCodeOf}). A path variable the
60
+ * interceptors never filled is `INVALID`, as the server's own
61
+ * `ViewScopeRequired` is: the request is wrong as built and a retry sends
62
+ * the same — not `UNAVAILABLE`, which would offer one.
63
+ */
64
+ get code(): ViewStoreErrorCode;
65
+ /**
66
+ * Whether the server (or something in front of it) answered at all: a
67
+ * response came back. An `UNAVAILABLE` that was answered is the server's
68
+ * own error — a 5xx, a timeout it reported — and not the network.
69
+ */
70
+ get reached(): boolean;
71
+ get message(): string;
72
+ /**
73
+ * The port's error, holding what it was read from: the request's own
74
+ * failure as `cause`, the server's error code as `detail` (a host tells
75
+ * `ViewAppRequired` from `ViewInvalid` by it), and for `UNAVAILABLE`
76
+ * whether the server answered (`reachable`).
77
+ */
78
+ toStoreError(): ViewStoreError;
79
+ /** {@link toStoreError} with another code: the same failure, read further. */
80
+ held(): {
81
+ cause: unknown;
82
+ detail?: {
83
+ code: string;
84
+ };
85
+ reachable?: true;
86
+ };
87
+ }
88
+ /** Whether the request id of a write was used before. */
89
+ export declare function isDuplicateRequest(failure: Failure): boolean;
90
+ /**
91
+ * The port's code for a server's answer, **by Wow's error code first**: the
92
+ * code says what the server decided, where one HTTP status carries several
93
+ * decisions (a `400` is a stale version on no server, but a bad title and a
94
+ * missing application alike). Only an answer without a code the store knows
95
+ * — a gateway's own page, a proxy, a code a later server adds — falls back to
96
+ * the status, and no answer at all (a network failure, a timeout, an abort)
97
+ * is `UNAVAILABLE`: the outcome is unknown, and a retry under the same
98
+ * `requestId` is what the port expects.
99
+ */
100
+ export declare function portCodeOf(errorCode: string | undefined, status: number | undefined): ViewStoreErrorCode;
101
+ /** What a failed request threw, read as a {@link Failure}. */
102
+ export declare function failureOf(error: unknown): Promise<Failure>;
@@ -0,0 +1,3 @@
1
+ export { WowViewStore, type WowViewStoreOptions } from './wowViewStore.js';
2
+ export { SHARED_OWNER_ID, SYSTEM_OWNER_ID, SYSTEM_TENANT_ID } from './paths.js';
3
+ export { WowViewStoreErrorCodes } from './errors.js';
@@ -0,0 +1,604 @@
1
+ import { ResultExtractors as e } from "@ahoo-wang/fetcher";
2
+ import { CommandHeaders as t, CommandStage as n, ErrorCodes as r, asc as i, filter as a, listQuery as o, singleQuery as s, toWowError as c } from "@ahoo-wang/wow-client";
3
+ import { ViewStoreError as l, isSystemInstanceId as u, isViewStoreError as d } from "@ahoo-wang/wow-view-engine";
4
+ //#region \0rolldown/runtime.js
5
+ var f = Object.freeze({
6
+ VIEW_INVALID: "ViewInvalid",
7
+ VIEW_APP_REQUIRED: "ViewAppRequired",
8
+ SYSTEM_VIEW_READ_ONLY: "SystemViewReadOnly",
9
+ VIEW_SCOPE_REQUIRED: "ViewScopeRequired",
10
+ VIEW_EVENT_STREAM_CLOSED: "ViewEventStreamClosed"
11
+ }), p = "referenced-by-shared-dashboard", m = {
12
+ [r.COMMAND_EXPECT_VERSION_CONFLICT]: "CONFLICT",
13
+ [r.EVENT_VERSION_CONFLICT]: "CONFLICT",
14
+ [r.SOURCING_VERSION_CONFLICT]: "CONFLICT",
15
+ [r.NOT_FOUND]: "NOT_FOUND",
16
+ [r.ILLEGAL_ACCESS_DELETED_AGGREGATE]: "NOT_FOUND",
17
+ [r.ILLEGAL_ACCESS_OWNER_AGGREGATE]: "FORBIDDEN",
18
+ [r.ILLEGAL_ACCESS_SPACE_AGGREGATE]: "FORBIDDEN",
19
+ [r.ILLEGAL_ACCESS_QUERY_SCOPE]: "FORBIDDEN",
20
+ [f.SYSTEM_VIEW_READ_ONLY]: "FORBIDDEN",
21
+ [f.VIEW_EVENT_STREAM_CLOSED]: "FORBIDDEN",
22
+ [f.VIEW_INVALID]: "INVALID",
23
+ [f.VIEW_APP_REQUIRED]: "INVALID",
24
+ [f.VIEW_SCOPE_REQUIRED]: "INVALID",
25
+ [r.BAD_REQUEST]: "INVALID",
26
+ [r.ILLEGAL_ARGUMENT]: "INVALID",
27
+ [r.ILLEGAL_STATE]: "UNAVAILABLE",
28
+ [r.COMMAND_VALIDATION]: "INVALID",
29
+ [r.DUPLICATE_AGGREGATE_ID]: "INVALID",
30
+ [r.QUERY_SCHEMA_VALIDATION]: "INVALID",
31
+ [r.REQUEST_TIMEOUT]: "UNAVAILABLE",
32
+ [r.TOO_MANY_REQUESTS]: "UNAVAILABLE",
33
+ [r.INTERNAL_SERVER_ERROR]: "UNAVAILABLE",
34
+ [r.QUERY_SCHEMA_UNAVAILABLE]: "UNAVAILABLE",
35
+ [r.QUERY_SCHEMA_CONFLICT]: "UNAVAILABLE"
36
+ }, Failure = class {
37
+ constructor(e, t, n) {
38
+ this.cause = e, this.wow = t, this.status = n;
39
+ }
40
+ get errorCode() {
41
+ return this.wow?.errorCode;
42
+ }
43
+ get bindingErrors() {
44
+ return this.wow?.bindingErrors ?? [];
45
+ }
46
+ get unfilled() {
47
+ if (!(this.wow || this.status !== void 0)) for (let e = this.cause, t = 0; e && t < 4; t++) {
48
+ let t = e.message, n = typeof t == "string" ? h.exec(t) : null;
49
+ if (n) return n[1];
50
+ e = e.cause;
51
+ }
52
+ }
53
+ get code() {
54
+ return this.unfilled === void 0 ? portCodeOf(this.errorCode, this.status) : "INVALID";
55
+ }
56
+ get reached() {
57
+ return this.wow !== void 0 || this.status !== void 0;
58
+ }
59
+ get message() {
60
+ if (this.wow) return this.wow.message;
61
+ let e = this.unfilled;
62
+ return e === void 0 ? this.status === void 0 ? `The view store could not be reached: ${reasonOf(this.cause)}` : `The view store answered HTTP ${this.status}` : `The fetcher's interceptors did not fill the path variable {${e}}`;
63
+ }
64
+ toStoreError() {
65
+ return new l(this.code, this.message, this.held());
66
+ }
67
+ held() {
68
+ let e = this.errorCode;
69
+ return {
70
+ cause: this.cause,
71
+ ...e === void 0 ? {} : { detail: { code: e } },
72
+ ...this.code === "UNAVAILABLE" && this.reached ? { reachable: !0 } : {}
73
+ };
74
+ }
75
+ }, h = /^Missing required path parameter: (\S+)/;
76
+ function isDuplicateRequest(e) {
77
+ return e.errorCode === r.DUPLICATE_REQUEST_ID;
78
+ }
79
+ function portCodeOf(e, t) {
80
+ let n = e === void 0 ? void 0 : m[e];
81
+ if (n) return n;
82
+ switch (t) {
83
+ case 400:
84
+ case 422: return "INVALID";
85
+ case 401:
86
+ case 403: return "FORBIDDEN";
87
+ case 404:
88
+ case 410: return "NOT_FOUND";
89
+ case 409:
90
+ case 412: return "CONFLICT";
91
+ default: return "UNAVAILABLE";
92
+ }
93
+ }
94
+ async function failureOf(e) {
95
+ let t = await c(e);
96
+ return new Failure(e, t, t?.status ?? statusOf(e));
97
+ }
98
+ function statusOf(e) {
99
+ if (typeof e == "object" && e) return e.exchange?.response?.status;
100
+ }
101
+ function reasonOf(e) {
102
+ if (typeof e == "object" && e) {
103
+ let { name: t, message: n } = e;
104
+ if (typeof n == "string") return typeof t == "string" ? `${t}: ${n}` : n;
105
+ }
106
+ return String(e);
107
+ }
108
+ //#endregion
109
+ //#region src/paths.ts
110
+ var g = "(shared)", _ = "(system)", v = "(platform)", y = "/view-store/tenant/{tenantId}/owner/{ownerId}", b = {
111
+ views: `${y}/view`,
112
+ view: `${y}/view/{id}`,
113
+ save: `${y}/view/{id}/save`,
114
+ rename: `${y}/view/{id}/rename`,
115
+ share: `${y}/view/{id}/share`,
116
+ claim: `${y}/view/{id}/claim`,
117
+ single: `${y}/view/snapshot/single`,
118
+ list: `${y}/view/snapshot/list`,
119
+ replay: `${y}/view/requests/{requestId}`,
120
+ systemViews: `${y}/system-views`,
121
+ systemView: `${y}/system-views/{id}`,
122
+ preferences: `${y}/definitions/{definitionId}/preferences`
123
+ };
124
+ function pathAt(e, t = {}) {
125
+ switch (e) {
126
+ case "shared": return {
127
+ ...t,
128
+ ownerId: g
129
+ };
130
+ case "system": return {
131
+ ...t,
132
+ tenantId: v,
133
+ ownerId: _
134
+ };
135
+ default: return { ...t };
136
+ }
137
+ }
138
+ //#endregion
139
+ //#region src/wire.ts
140
+ function isStored(e) {
141
+ return e.source === "stored" && typeof e.version == "number";
142
+ }
143
+ var x = [
144
+ "aggregateId",
145
+ "version",
146
+ "state.definitionId",
147
+ "state.title",
148
+ "state.audience",
149
+ "state.config.kind"
150
+ ];
151
+ function revisionOf(e) {
152
+ return String(e);
153
+ }
154
+ function toInstance(e) {
155
+ let { aggregateId: t, version: n, state: r } = e;
156
+ return {
157
+ id: t,
158
+ definitionId: r.definitionId,
159
+ title: r.title,
160
+ scope: r.audience,
161
+ revision: revisionOf(n),
162
+ config: r.config
163
+ };
164
+ }
165
+ function toSummary(e) {
166
+ let { aggregateId: t, version: n, state: r } = e;
167
+ return {
168
+ id: t,
169
+ definitionId: r.definitionId,
170
+ title: r.title,
171
+ scope: r.audience,
172
+ kind: r.config.kind,
173
+ revision: revisionOf(n)
174
+ };
175
+ }
176
+ function systemInstance(e) {
177
+ return {
178
+ id: e.id,
179
+ definitionId: e.definitionId,
180
+ title: e.title,
181
+ scope: "system",
182
+ revision: e.revision,
183
+ config: e.config,
184
+ ...isStored(e) ? { stored: !0 } : {}
185
+ };
186
+ }
187
+ function systemSummary(e) {
188
+ return {
189
+ id: e.id,
190
+ definitionId: e.definitionId,
191
+ title: e.title,
192
+ scope: "system",
193
+ kind: e.kind,
194
+ revision: e.revision,
195
+ ...isStored(e) ? { stored: !0 } : {}
196
+ };
197
+ }
198
+ function toPreferences(e) {
199
+ return preferencesAt({
200
+ order: e.order ?? [],
201
+ defaultInstanceId: e.defaultInstanceId ?? null,
202
+ autoRun: e.autoRun ?? void 0,
203
+ lastTabs: e.lastTabs ?? void 0
204
+ }, e.version);
205
+ }
206
+ function preferencesInput(e) {
207
+ let { order: t, defaultInstanceId: n, autoRun: r, lastTabs: i } = e;
208
+ return {
209
+ order: [...t],
210
+ defaultInstanceId: n ?? null,
211
+ ...r === void 0 ? {} : { autoRun: r },
212
+ ...i === void 0 ? {} : { lastTabs: { ...i } }
213
+ };
214
+ }
215
+ function preferencesAt(e, t) {
216
+ return {
217
+ ...preferencesInput(e),
218
+ revision: revisionOf(t)
219
+ };
220
+ }
221
+ function samePreferences(e, t) {
222
+ return canonical(e) === canonical(t);
223
+ }
224
+ function canonical(e) {
225
+ let { order: t, defaultInstanceId: n, autoRun: r, lastTabs: i } = preferencesInput(e), a = i && Object.entries(i).sort(([e], [t]) => e < t ? -1 : +(e > t));
226
+ return JSON.stringify([
227
+ t,
228
+ n,
229
+ r ?? null,
230
+ a ?? null
231
+ ]);
232
+ }
233
+ //#endregion
234
+ //#region src/wowViewStore.ts
235
+ var S = 1e3, C = 256, w = Symbol("not replayed"), WowViewStore = class {
236
+ constructor(e) {
237
+ this.places = /* @__PURE__ */ new Map(), this.preferenceOutcomes = new Remembered(), this.preferenceAttempts = new Remembered(), this.createAttempts = new Remembered(), this.storedVersions = new Remembered(O), this.fetcher = e.fetcher, e.permissions && (this.permissions = e.permissions);
238
+ }
239
+ list(e, t) {
240
+ return guard(async () => {
241
+ let n = o({
242
+ filter: a.eq("state.definitionId", e),
243
+ projection: { include: x },
244
+ sort: E,
245
+ limit: S
246
+ }), [r, i, s] = await Promise.all([
247
+ this.json("POST", b.list, "personal", {
248
+ body: n,
249
+ signal: t
250
+ }),
251
+ this.json("POST", b.list, "shared", {
252
+ body: n,
253
+ signal: t
254
+ }),
255
+ this.json("GET", b.systemViews, "shared", {
256
+ query: { definitionId: e },
257
+ signal: t
258
+ })
259
+ ]).catch((e) => {
260
+ throw e instanceof Failure && e.code === "NOT_FOUND" ? unsupported(e) : e;
261
+ });
262
+ for (let e of s) this.rememberSystem(e);
263
+ let c = /* @__PURE__ */ new Map();
264
+ for (let e of [
265
+ ...r.map(toSummary),
266
+ ...i.map(toSummary),
267
+ ...s.map(systemSummary)
268
+ ]) c.has(e.id) || (c.set(e.id, e), this.places.set(e.id, e.scope));
269
+ return [...c.values()].sort((e, t) => D[e.scope] - D[t.scope]);
270
+ });
271
+ }
272
+ get(e, t) {
273
+ return guard(async () => (await this.find(e, t)).instance);
274
+ }
275
+ create(e, t) {
276
+ return guard(async () => {
277
+ let n = e.scope, { requestId: r } = t;
278
+ if (this.createAttempts.has(r)) {
279
+ let e = await this.probe(n, t, !0), r = e?.status === 200 ? await e.json() : null;
280
+ if (r?.aggregateId) return this.places.set(r.aggregateId, n), n === "system" ? this.readAt("system", r.aggregateId, t.signal) : toInstance(r);
281
+ }
282
+ this.createAttempts.set(r, !0);
283
+ let { definitionId: i, title: a, config: o } = e, s = {
284
+ method: "POST",
285
+ url: b.views,
286
+ sentTo: n,
287
+ body: {
288
+ definitionId: i,
289
+ title: a,
290
+ config: o
291
+ },
292
+ landsAt: n
293
+ }, c = await this.json(s.method, s.url, n, {
294
+ body: s.body,
295
+ headers: writeHeaders(t),
296
+ signal: t.signal
297
+ }).catch(async (e) => {
298
+ throw await this.unsupportedOr(e, t.signal);
299
+ });
300
+ return await this.landed(c.aggregateId, s, c, t);
301
+ });
302
+ }
303
+ save(e, t, n, r) {
304
+ return this.write(e, n, r, (e) => ({
305
+ method: "PUT",
306
+ url: b.save,
307
+ sentTo: e,
308
+ body: { config: t },
309
+ landsAt: e
310
+ }));
311
+ }
312
+ rename(e, t, n, r) {
313
+ return this.write(e, n, r, (e) => ({
314
+ method: "PUT",
315
+ url: b.rename,
316
+ sentTo: e,
317
+ body: { title: t },
318
+ landsAt: e
319
+ }));
320
+ }
321
+ changeAudience(e, t, n, r) {
322
+ return this.write(e, n, r, (e) => e === "system" ? readOnly("A system view never moves audience") : t === "shared" ? {
323
+ method: "PUT",
324
+ url: b.share,
325
+ sentTo: e,
326
+ body: {},
327
+ landsAt: "shared"
328
+ } : {
329
+ method: "PUT",
330
+ url: b.claim,
331
+ sentTo: "personal",
332
+ landsAt: "personal"
333
+ });
334
+ }
335
+ async delete(e, t, n) {
336
+ await this.write(e, t, n, (e) => ({
337
+ method: "DELETE",
338
+ url: b.view,
339
+ sentTo: e,
340
+ body: {},
341
+ landsAt: null
342
+ }));
343
+ }
344
+ getPreferences(e, t) {
345
+ return guard(async () => toPreferences(await this.json("GET", b.preferences, "personal", {
346
+ path: { definitionId: e },
347
+ signal: t
348
+ }).catch(async (e) => {
349
+ throw await this.unsupportedOr(e, t);
350
+ })));
351
+ }
352
+ setPreferences(e, t, n) {
353
+ return guard(async () => {
354
+ let { requestId: r, signal: i } = n, a = this.preferenceOutcomes.get(r);
355
+ if (a) return structuredClone(a);
356
+ let o = this.preferenceAttempts.has(r);
357
+ this.preferenceAttempts.set(r, !0);
358
+ let s;
359
+ try {
360
+ let r = await this.json("PUT", b.preferences, "personal", {
361
+ path: { definitionId: e },
362
+ body: preferencesInput(t),
363
+ headers: writeHeaders(n, t.revision),
364
+ signal: i
365
+ });
366
+ s = typeof r.aggregateVersion == "number" ? preferencesAt(t, r.aggregateVersion) : await this.getPreferences(e, i);
367
+ } catch (n) {
368
+ if (!(n instanceof Failure) || n.code !== "CONFLICT" && !isDuplicateRequest(n)) throw await this.unsupportedOr(n, i);
369
+ let r = await this.getPreferences(e, i);
370
+ if ((o || isDuplicateRequest(n)) && samePreferences(r, t)) s = r;
371
+ else throw new l("CONFLICT", n.message, {
372
+ ...n.held(),
373
+ preferences: r
374
+ });
375
+ }
376
+ return this.preferenceOutcomes.set(r, s), structuredClone(s);
377
+ });
378
+ }
379
+ write(e, t, n, r) {
380
+ return guard(async () => {
381
+ let { signal: i } = n, a = this.places.get(e), o = a ?? (await this.find(e, i)).place, s = a === void 0;
382
+ for (;;) {
383
+ let a = r(o), c = t;
384
+ if (o === "system") {
385
+ let r = await this.storedVersion(e, t, a, n);
386
+ if ("answer" in r) return r.answer;
387
+ c = r.version;
388
+ }
389
+ let l;
390
+ try {
391
+ l = await this.json(a.method, a.url, a.sentTo, {
392
+ path: { id: e },
393
+ body: a.body,
394
+ headers: writeHeaders(n, c),
395
+ signal: i
396
+ });
397
+ } catch (t) {
398
+ if (!(t instanceof Failure)) throw t;
399
+ let c = await this.replayed(e, a, n, t);
400
+ if (c !== w) return c;
401
+ if (!s && (t.code === "NOT_FOUND" || t.code === "FORBIDDEN")) {
402
+ s = !0;
403
+ let t = (await this.find(e, i, null)).place;
404
+ if (t !== o && r(t).sentTo !== a.sentTo) {
405
+ o = t;
406
+ continue;
407
+ }
408
+ }
409
+ throw t.code === "CONFLICT" || isDuplicateRequest(t) ? await this.conflict(e, t, i) : await this.refusal(t, i);
410
+ }
411
+ return this.landed(e, a, l, n);
412
+ }
413
+ });
414
+ }
415
+ async landed(e, t, n, r) {
416
+ if (t.landsAt === null) return;
417
+ this.places.set(e, t.landsAt);
418
+ let i = n.aggregateVersion, a, o;
419
+ try {
420
+ if (a = await this.readAt(t.landsAt, e, r.signal), typeof i != "number" || a.revision === revisionOf(i) || t.landsAt === "system" && this.storedVersions.get(e)?.version === i) return a;
421
+ } catch (e) {
422
+ o = e;
423
+ }
424
+ let s = await this.replay(e, t, r, !1);
425
+ if (s !== w && s !== void 0) return s;
426
+ if (a) return a;
427
+ throw o;
428
+ }
429
+ async replayed(e, t, n, r) {
430
+ return r.code === "CONFLICT" || r.code === "NOT_FOUND" || isDuplicateRequest(r) ? this.replay(e, t, n, !0) : w;
431
+ }
432
+ async replay(e, t, n, r) {
433
+ let i = t.sentTo === "system" ? ["system"] : t.sentTo === "personal" ? ["personal", "shared"] : ["shared", "personal"];
434
+ for (let [a, o] of i.entries()) {
435
+ let i = await this.probe(o, n, r && a === 0);
436
+ if (!i) continue;
437
+ if (i.status === 204) return t.landsAt === null ? void 0 : w;
438
+ let s = await i.json();
439
+ return t.landsAt === null || s?.aggregateId !== e ? w : t.landsAt === "system" ? this.readAt("system", e, n.signal) : toInstance(s);
440
+ }
441
+ return w;
442
+ }
443
+ async probe(e, t, n) {
444
+ try {
445
+ return await this.send("GET", b.replay, e, {
446
+ path: { requestId: t.requestId },
447
+ signal: t.signal
448
+ });
449
+ } catch (e) {
450
+ if (e instanceof Failure && (e.code === "NOT_FOUND" || !n)) return;
451
+ throw e;
452
+ }
453
+ }
454
+ async conflict(e, t, n) {
455
+ let { instance: r } = await this.find(e, n, null);
456
+ return new l("CONFLICT", t.message, {
457
+ ...t.held(),
458
+ instance: r
459
+ });
460
+ }
461
+ async refusal(e, t) {
462
+ let n = e.bindingErrors.filter((e) => e.code === p);
463
+ if (e.code !== "INVALID" || n.length === 0) return e.toStoreError();
464
+ let r = await Promise.all(n.map((e) => this.boardTitle(e, t)));
465
+ return new l("INVALID", e.message, {
466
+ ...e.held(),
467
+ boards: r
468
+ });
469
+ }
470
+ async boardTitle(e, t) {
471
+ if (typeof e.msg == "string" && e.msg.trim() !== "") return e.msg;
472
+ try {
473
+ return (await this.readAt("shared", e.name, t)).title;
474
+ } catch {
475
+ return e.name;
476
+ }
477
+ }
478
+ async find(e, t, n = this.places.get(e)) {
479
+ if (!u(e)) {
480
+ let r = [
481
+ "personal",
482
+ "shared",
483
+ "system"
484
+ ];
485
+ n && r.sort((e, t) => Number(t === n) - Number(e === n));
486
+ for (let n of r) try {
487
+ let r = await this.readAt(n, e, t);
488
+ return this.places.set(e, n), {
489
+ place: n,
490
+ instance: r
491
+ };
492
+ } catch (e) {
493
+ if (e instanceof Failure && e.code === "NOT_FOUND") continue;
494
+ throw e;
495
+ }
496
+ if (!await this.served(t)) throw new l("UNSUPPORTED", T);
497
+ }
498
+ throw new l("NOT_FOUND", `No such view: ${e}`);
499
+ }
500
+ async served(e) {
501
+ try {
502
+ return await this.send("GET", b.systemViews, "shared", { signal: e }), !0;
503
+ } catch (e) {
504
+ return !(e instanceof Failure && e.code === "NOT_FOUND");
505
+ }
506
+ }
507
+ async unsupportedOr(e, t) {
508
+ return e instanceof Failure && e.code === "NOT_FOUND" && !await this.served(t) ? unsupported(e) : e;
509
+ }
510
+ rememberSystem(e) {
511
+ return this.storedVersions.set(e.id, isStored(e) ? {
512
+ revision: e.revision,
513
+ version: e.version
514
+ } : null), e;
515
+ }
516
+ async storedVersion(e, t, n, r) {
517
+ let i = this.storedVersions.get(e);
518
+ if (i === null && readOnly("Configured system views are read-only"), i?.revision !== t) {
519
+ let a = await this.readAt("system", e, r.signal);
520
+ if (i = this.storedVersions.get(e), i && i.revision !== t) {
521
+ let i = await this.replay(e, n, r, !1);
522
+ if (i !== w) return { answer: i };
523
+ throw new l("CONFLICT", `System view ${e} has moved on from revision ${t}`, { instance: a });
524
+ }
525
+ }
526
+ return i || readOnly("Configured system views are read-only"), { version: String(i.version) };
527
+ }
528
+ async readAt(e, t, n) {
529
+ return e === "system" ? systemInstance(this.rememberSystem(await this.json("GET", b.systemView, "shared", {
530
+ path: { id: t },
531
+ signal: n
532
+ }))) : toInstance(await this.json("POST", b.single, e, {
533
+ body: s({ filter: a.id(t) }),
534
+ signal: n
535
+ }));
536
+ }
537
+ async json(e, t, n, r) {
538
+ return await (await this.send(e, t, n, r)).json();
539
+ }
540
+ async send(t, n, r, { path: i, query: a, body: o, headers: s, signal: c }) {
541
+ try {
542
+ return await this.fetcher.request({
543
+ url: n,
544
+ method: t,
545
+ urlParams: {
546
+ path: pathAt(r, i),
547
+ query: a
548
+ },
549
+ body: o,
550
+ headers: s,
551
+ signal: c
552
+ }, { resultExtractor: e.Response });
553
+ } catch (e) {
554
+ throw await failureOf(e);
555
+ }
556
+ }
557
+ };
558
+ function writeHeaders(e, r) {
559
+ return {
560
+ [t.REQUEST_ID]: e.requestId,
561
+ [t.WAIT_STAGE]: n.SNAPSHOT,
562
+ ...r === void 0 ? {} : { [t.AGGREGATE_VERSION]: r }
563
+ };
564
+ }
565
+ var T = "This server has no view store";
566
+ function unsupported(e) {
567
+ return new l("UNSUPPORTED", T, e.held());
568
+ }
569
+ var E = [i("firstEventTime"), i("aggregateId")], D = {
570
+ system: 0,
571
+ shared: 1,
572
+ personal: 2
573
+ };
574
+ function readOnly(e) {
575
+ throw new l("FORBIDDEN", e);
576
+ }
577
+ async function guard(e) {
578
+ try {
579
+ return await e();
580
+ } catch (e) {
581
+ throw e instanceof Failure ? e.toStoreError() : d(e) ? e : new l("UNAVAILABLE", e instanceof Error ? e.message : String(e), {
582
+ cause: e,
583
+ ...e instanceof SyntaxError ? { reachable: !0 } : {}
584
+ });
585
+ }
586
+ }
587
+ var O = 1024, Remembered = class {
588
+ constructor(e = C) {
589
+ this.limit = e, this.entries = /* @__PURE__ */ new Map();
590
+ }
591
+ get(e) {
592
+ return this.entries.get(e);
593
+ }
594
+ has(e) {
595
+ return this.entries.has(e);
596
+ }
597
+ set(e, t) {
598
+ this.entries.delete(e), this.entries.set(e, t), this.entries.size > this.limit && this.entries.delete(this.entries.keys().next().value);
599
+ }
600
+ };
601
+ //#endregion
602
+ export { g as SHARED_OWNER_ID, _ as SYSTEM_OWNER_ID, v as SYSTEM_TENANT_ID, WowViewStore, f as WowViewStoreErrorCodes };
603
+
604
+ //# sourceMappingURL=index.es.js.map