@warp-drive/core 5.8.0-alpha.40 → 5.8.0-alpha.41
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/declarations/configure.d.ts +1 -1
- package/declarations/reactive/-private/default-mode.d.ts +1 -1
- package/declarations/reactive/-private/fields/extension.d.ts +1 -1
- package/declarations/reactive/-private/fields/managed-array.d.ts +2 -2
- package/declarations/reactive/-private/fields/managed-object.d.ts +1 -1
- package/declarations/reactive.d.ts +2 -3
- package/declarations/signals/-leaked.d.ts +2 -0
- package/declarations/signals/-private.d.ts +6 -0
- package/declarations/{store/-private/new-core-tmp → signals}/promise-state.d.ts +1 -1
- package/declarations/{store/-private/new-core-tmp → signals}/request-state.d.ts +5 -5
- package/declarations/{store/-private/new-core-tmp → signals}/request-subscription.d.ts +4 -4
- package/declarations/store/-private/cache-handler/types.d.ts +2 -16
- package/declarations/store/-private/managers/cache-manager.d.ts +1 -14
- package/declarations/store/-private/record-arrays/legacy-many-array.d.ts +1 -1
- package/declarations/store/-private/record-arrays/resource-array.d.ts +1 -1
- package/declarations/store/-private.d.ts +0 -5
- package/declarations/store/deprecated/-private.d.ts +1 -1
- package/declarations/types/schema/fields.d.ts +4 -4
- package/dist/configure-DPUFCemT.js +1940 -0
- package/dist/configure.js +2 -1
- package/dist/{request-oqoLC9rz.js → future-BKkJJkj7.js} +1 -48
- package/dist/graph/-private.js +3 -2
- package/dist/{index-BKcD4JZK.js → index-CQP2NSqg.js} +58 -1826
- package/dist/index.js +5 -5
- package/dist/reactive/-private.js +1 -1
- package/dist/reactive.js +4 -129
- package/dist/request.js +49 -1
- package/dist/signals/-leaked.js +1 -0
- package/dist/store/-private.js +1 -2
- package/dist/types/-private.js +1 -1
- package/dist/unpkg/dev/-leaked-Co0EI6Go.js +1939 -0
- package/dist/unpkg/dev/configure.js +1 -1
- package/dist/unpkg/dev/{request-CA9K0gXq.js → future-DFfOzSoe.js} +1 -48
- package/dist/unpkg/dev/graph/-private.js +3 -2
- package/dist/unpkg/dev/{index-DqhXrNZ_.js → index-CepUPZlc.js} +57 -1825
- package/dist/unpkg/dev/index.js +4 -4
- package/dist/unpkg/dev/reactive/-private.js +1 -1
- package/dist/unpkg/dev/reactive.js +3 -127
- package/dist/unpkg/dev/request.js +49 -1
- package/dist/unpkg/dev/signals/-leaked.js +1 -0
- package/dist/unpkg/dev/store/-private.js +2 -3
- package/dist/unpkg/dev/types/-private.js +1 -1
- package/dist/unpkg/dev-deprecated/-leaked-DjMeRqdU.js +1939 -0
- package/dist/unpkg/dev-deprecated/configure.js +1 -1
- package/dist/unpkg/dev-deprecated/{request-CA9K0gXq.js → future-DFfOzSoe.js} +1 -48
- package/dist/unpkg/dev-deprecated/graph/-private.js +3 -2
- package/dist/unpkg/dev-deprecated/{index-BBlq5is_.js → index-C_EEmn_3.js} +56 -1824
- package/dist/unpkg/dev-deprecated/index.js +2 -2
- package/dist/unpkg/dev-deprecated/reactive.js +2 -126
- package/dist/unpkg/dev-deprecated/request.js +49 -1
- package/dist/unpkg/dev-deprecated/signals/-leaked.js +1 -0
- package/dist/unpkg/dev-deprecated/store/-private.js +1 -2
- package/dist/unpkg/dev-deprecated/types/-private.js +1 -1
- package/dist/unpkg/prod/-leaked-DUONXQDB.js +1676 -0
- package/dist/unpkg/prod/{-private-3C1OkYtZ.js → -private-sql1_mdx.js} +1 -1
- package/dist/unpkg/prod/configure.js +2 -1
- package/dist/unpkg/prod/graph/-private.js +3 -2
- package/dist/unpkg/prod/{handler-LAyD1Y5l.js → handler-EU_8ncB2.js} +2 -2
- package/dist/unpkg/prod/index.js +7 -5
- package/dist/unpkg/prod/promise-cache-DIT8Ypjq.js +19 -0
- package/dist/unpkg/prod/reactive/-private.js +1 -1
- package/dist/unpkg/prod/reactive.js +26 -123
- package/dist/unpkg/prod/{request-CN2LxbYX.js → request-BrJSCG6r.js} +3 -19
- package/dist/unpkg/prod/request.js +2 -1
- package/dist/unpkg/prod/{promise-state-ipG60SdD.js → schema-BSkHyoWz.js} +53 -1572
- package/dist/unpkg/prod/signals/-leaked.js +1 -0
- package/dist/unpkg/prod/store/-private.js +3 -4
- package/dist/unpkg/prod/types/-private.js +1 -1
- package/dist/unpkg/prod-deprecated/-leaked-DRNv9VIX.js +1676 -0
- package/dist/unpkg/prod-deprecated/configure.js +2 -1
- package/dist/unpkg/prod-deprecated/graph/-private.js +3 -2
- package/dist/unpkg/prod-deprecated/{handler-D639oFvl.js → handler-CCIu4sQ3.js} +1 -1
- package/dist/unpkg/prod-deprecated/{hooks-DGvi9teJ.js → hooks-Dv4Np0MY.js} +1 -1
- package/dist/unpkg/prod-deprecated/index.js +7 -5
- package/dist/unpkg/prod-deprecated/promise-cache-DIT8Ypjq.js +19 -0
- package/dist/unpkg/prod-deprecated/reactive.js +4 -125
- package/dist/unpkg/prod-deprecated/{request-CN2LxbYX.js → request-BrJSCG6r.js} +3 -19
- package/dist/unpkg/prod-deprecated/request.js +2 -1
- package/dist/unpkg/prod-deprecated/{promise-state-CYvoIPna.js → schema-CJcjHv0E.js} +52 -1571
- package/dist/unpkg/prod-deprecated/signals/-leaked.js +1 -0
- package/dist/unpkg/prod-deprecated/store/-private.js +2 -3
- package/dist/unpkg/prod-deprecated/types/-private.js +1 -1
- package/package.json +3 -3
- package/declarations/store/-private/new-core-tmp/expensive-subscription.d.ts +0 -24
- package/dist/configure-C3x8YXzL.js +0 -181
- package/dist/unpkg/dev/configure-BC66sfNO.js +0 -183
- package/dist/unpkg/dev-deprecated/configure-BC66sfNO.js +0 -183
- package/dist/unpkg/prod/configure-C0C1LpG6.js +0 -158
- package/dist/unpkg/prod/hooks-BfiqDg3O.js +0 -26
- package/dist/unpkg/prod-deprecated/configure-BQ8CpIcW.js +0 -158
- /package/declarations/{store/-private/new-core-tmp → signals}/reactivity/configure.d.ts +0 -0
- /package/declarations/{store/-private/new-core-tmp → signals}/reactivity/internal.d.ts +0 -0
- /package/declarations/{store/-private/new-core-tmp → signals}/reactivity/signal.d.ts +0 -0
- /package/dist/{unpkg/dev/-private-3C1OkYtZ.js → symbols-3C1OkYtZ.js} +0 -0
- /package/dist/{symbols-sql1_mdx.js → unpkg/dev/-private-sql1_mdx.js} +0 -0
|
@@ -1,484 +1,17 @@
|
|
|
1
|
+
import { d as defineGate, w as withSignalStore, n as notifyInternalSignal, p as peekInternalSignal, b as willSyncFlushWatchers, e as getOrCreateInternalSignal, f as consumeInternalSignal, h as createInternalSignal, A as ARRAY_SIGNAL, S as Signals, i as createSignalDescriptor, j as defineSignal, k as entangleSignal, l as entangleInitiallyStaleSignal, O as OBJECT_SIGNAL, m as createInternalMemo, o as waitFor } from "./-leaked-DjMeRqdU.js";
|
|
1
2
|
import { EnableHydration, SkipCache, STRUCTURED } from './types/request.js';
|
|
2
3
|
import { D as Destroy, a as Context, S as SOURCE, C as Checkout, b as Commit } from "./-private-3C1OkYtZ.js";
|
|
3
4
|
import { isResourceSchema } from './types/schema/fields.js';
|
|
4
|
-
import {
|
|
5
|
+
import { a as cloneResponseProperties, I as IS_CACHE_HANDLER, b as assertValidRequest, e as executeNextHandler, d as getRequestResult, u as upgradePromise, s as setPromiseResult, f as clearRequestResult } from "./future-DFfOzSoe.js";
|
|
5
6
|
import { getOrSetGlobal, peekTransient, setTransient, peekUniversalTransient, setUniversalTransient } from './types/-private.js';
|
|
6
|
-
import {
|
|
7
|
+
import { DefaultCachePolicy } from './store.js';
|
|
8
|
+
import { withBrand } from './request.js';
|
|
7
9
|
import { CACHE_OWNER, DEBUG_STALE_CACHE_OWNER, DEBUG_KEY_TYPE, DEBUG_CLIENT_ORIGINATED } from './types/identifier.js';
|
|
8
10
|
import { dasherize } from './utils/string.js';
|
|
9
11
|
import { g as getGlobalConfig } from "./runtime-DfhJzpZH.js";
|
|
10
|
-
import { DefaultCachePolicy } from './store.js';
|
|
11
12
|
import { setLogging, getRuntimeConfig } from './types/runtime.js';
|
|
12
13
|
import { RecordStore, Type } from './types/symbols.js';
|
|
13
14
|
import * as _importSync20 from '@ember/object';
|
|
14
|
-
const INITIALIZER_PROTO = {
|
|
15
|
-
isInitializer: true
|
|
16
|
-
};
|
|
17
|
-
function makeInitializer(fn) {
|
|
18
|
-
// we use a prototype to ensure that the initializer is not enumerable
|
|
19
|
-
// and does not interfere with the signal's value.
|
|
20
|
-
return Object.assign(Object.create(INITIALIZER_PROTO), {
|
|
21
|
-
value: fn
|
|
22
|
-
});
|
|
23
|
-
}
|
|
24
|
-
function isInitializer(obj) {
|
|
25
|
-
return typeof obj === 'object' && obj !== null && Object.getPrototypeOf(obj) === INITIALIZER_PROTO;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* A WarpDriveSignal is a wrapper around a framework specific or TC39 signal
|
|
30
|
-
* that enables us to store and manage the signal in a universal way.
|
|
31
|
-
*
|
|
32
|
-
* WarpDrive uses signals to manage three separate concepts:
|
|
33
|
-
*
|
|
34
|
-
* - as a `storage` for a value local to the object that we want to be reactive
|
|
35
|
-
* (see `@local` schema field for an example)
|
|
36
|
-
* - as a `gate` for a memoized getter that we want to act as a reactive property
|
|
37
|
-
* but whose value is computed/pulled from a non-reactive source elsewhere
|
|
38
|
-
* and whose latest value is stored in the signal
|
|
39
|
-
* (see `field` schema field for an example)
|
|
40
|
-
* - as a `gate` with a manually managed value updated on pull when `isStale` is true
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
* It offers
|
|
44
|
-
*
|
|
45
|
-
* - a non-reactive way to access/update the current value
|
|
46
|
-
* - a non-reactive way to mark the signal as dirtied
|
|
47
|
-
* - a non-reactive way to store content for why the signal was dirtied
|
|
48
|
-
* - access to the underlying Signal(s) in-use
|
|
49
|
-
*
|
|
50
|
-
* For debugging:
|
|
51
|
-
* - the "key" or "name" of the signal
|
|
52
|
-
* - the "object identity" or "context" to which the signal is attached
|
|
53
|
-
*
|
|
54
|
-
* @private
|
|
55
|
-
*/
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* We attach signals to their context object via
|
|
59
|
-
* a Map attached to the object via this symbol.
|
|
60
|
-
*
|
|
61
|
-
* This allows us to store multiple signals
|
|
62
|
-
* on the same object with smaller memory
|
|
63
|
-
* overhead and no WeakMap lookups.
|
|
64
|
-
*
|
|
65
|
-
* Performance sensitive objects should
|
|
66
|
-
* pre-warm their shape by assigning this
|
|
67
|
-
* during initialization.
|
|
68
|
-
*
|
|
69
|
-
* ```ts
|
|
70
|
-
* initializeSignalStore(obj);
|
|
71
|
-
* ```
|
|
72
|
-
*
|
|
73
|
-
* @private
|
|
74
|
-
*/
|
|
75
|
-
const Signals = getOrSetGlobal('Signals', Symbol('Signals'));
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* A util that will create a signal store on the object
|
|
79
|
-
* if it does not already exist and returns the associated
|
|
80
|
-
* signal store.
|
|
81
|
-
*
|
|
82
|
-
* @private
|
|
83
|
-
*/
|
|
84
|
-
function withSignalStore(obj) {
|
|
85
|
-
if (!obj[Signals]) {
|
|
86
|
-
initializeSignalStore(obj);
|
|
87
|
-
}
|
|
88
|
-
return obj[Signals];
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* A util that will create a signal store on the object
|
|
93
|
-
* if it does not already exist.
|
|
94
|
-
*
|
|
95
|
-
* Useful for pre-warming the shape of an object to ensure
|
|
96
|
-
* a key-transition to add it is not required later.
|
|
97
|
-
*
|
|
98
|
-
* @private
|
|
99
|
-
*/
|
|
100
|
-
function initializeSignalStore(obj) {
|
|
101
|
-
(test => {
|
|
102
|
-
if (!test) {
|
|
103
|
-
throw new Error(`Signal store already exists on object`);
|
|
104
|
-
}
|
|
105
|
-
})(!obj[Signals]);
|
|
106
|
-
obj[Signals] = new Map();
|
|
107
|
-
}
|
|
108
|
-
function createInternalSignal(signals, obj, key, initialValue) {
|
|
109
|
-
const warpDriveSignal = {
|
|
110
|
-
key,
|
|
111
|
-
context: obj,
|
|
112
|
-
signal: createSignal(obj, key),
|
|
113
|
-
value: isInitializer(initialValue) ? initialValue.value.call(obj) : initialValue,
|
|
114
|
-
isStale: false
|
|
115
|
-
};
|
|
116
|
-
signals.set(key, warpDriveSignal);
|
|
117
|
-
return warpDriveSignal;
|
|
118
|
-
}
|
|
119
|
-
function getOrCreateInternalSignal(signals, obj, key, initialValue) {
|
|
120
|
-
let signal = peekInternalSignal(signals, key);
|
|
121
|
-
if (!signal) {
|
|
122
|
-
signal = createInternalSignal(signals, obj, key, initialValue);
|
|
123
|
-
}
|
|
124
|
-
return signal;
|
|
125
|
-
}
|
|
126
|
-
function createInternalMemo(signals, object, key, fn) {
|
|
127
|
-
(test => {
|
|
128
|
-
if (!test) {
|
|
129
|
-
throw new Error(`Expected no signal/memo to exist for key "${String(key)}"`);
|
|
130
|
-
}
|
|
131
|
-
})(!peekInternalSignal(signals, key));
|
|
132
|
-
{
|
|
133
|
-
return withFrame(signals, object, key, fn);
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
function peekInternalSignal(signals, key) {
|
|
137
|
-
return signals?.get(key);
|
|
138
|
-
}
|
|
139
|
-
function consumeInternalSignal(signal) {
|
|
140
|
-
TrackingFrame?.signals.add(signal);
|
|
141
|
-
consumeSignal(signal.signal);
|
|
142
|
-
}
|
|
143
|
-
function notifyInternalSignal(signal) {
|
|
144
|
-
if (signal) {
|
|
145
|
-
signal.isStale = true;
|
|
146
|
-
notifySignal(signal.signal);
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
let TrackingFrame = null;
|
|
150
|
-
|
|
151
|
-
/**
|
|
152
|
-
* This is currently just for signals debugging, but it could be used in production
|
|
153
|
-
* if we wanted to eliminate the need for frameworks to implement createMemo / to
|
|
154
|
-
* allow us to add our own Watcher.
|
|
155
|
-
*
|
|
156
|
-
* @internal
|
|
157
|
-
*/
|
|
158
|
-
function withFrame(signals, object, key, fn) {
|
|
159
|
-
const frameSignals = new Set();
|
|
160
|
-
const frameFn = () => {
|
|
161
|
-
if (frameSignals.size) {
|
|
162
|
-
frameSignals.clear();
|
|
163
|
-
}
|
|
164
|
-
TrackingFrame = {
|
|
165
|
-
object,
|
|
166
|
-
key,
|
|
167
|
-
signals: frameSignals,
|
|
168
|
-
parent: TrackingFrame
|
|
169
|
-
};
|
|
170
|
-
try {
|
|
171
|
-
return fn();
|
|
172
|
-
} finally {
|
|
173
|
-
TrackingFrame = TrackingFrame.parent;
|
|
174
|
-
}
|
|
175
|
-
};
|
|
176
|
-
const memo = createMemo(object, key, frameFn);
|
|
177
|
-
// @ts-expect-error
|
|
178
|
-
memo.signals = frameSignals;
|
|
179
|
-
signals.set(key, memo);
|
|
180
|
-
return memo;
|
|
181
|
-
}
|
|
182
|
-
function isMemo(obj) {
|
|
183
|
-
// @ts-expect-error
|
|
184
|
-
return typeof obj === 'function' && obj.signals instanceof Set;
|
|
185
|
-
}
|
|
186
|
-
{
|
|
187
|
-
// @ts-expect-error adding to global API
|
|
188
|
-
globalThis.debugWarpDriveSignals = (obj, key) => {
|
|
189
|
-
const signals = obj[Signals];
|
|
190
|
-
if (!signals) {
|
|
191
|
-
log$1('The object has no associated signals');
|
|
192
|
-
return false;
|
|
193
|
-
}
|
|
194
|
-
if (key) {
|
|
195
|
-
const signal = signals.get(key);
|
|
196
|
-
if (!signal) {
|
|
197
|
-
log$1(`No signal found for key "${String(key)}"`);
|
|
198
|
-
return false;
|
|
199
|
-
}
|
|
200
|
-
log$1(signal);
|
|
201
|
-
if (isMemo(signal)) {
|
|
202
|
-
colorizeLines(printMemo(signal, key));
|
|
203
|
-
return true;
|
|
204
|
-
} else {
|
|
205
|
-
colorizeLines(printSignal(signal, key));
|
|
206
|
-
return true;
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
const lines = [];
|
|
210
|
-
for (const [k, signal] of signals) {
|
|
211
|
-
if (isMemo(signal)) continue;
|
|
212
|
-
printSignal(signal, k, lines);
|
|
213
|
-
}
|
|
214
|
-
for (const [k, signal] of signals) {
|
|
215
|
-
if (isMemo(signal)) {
|
|
216
|
-
printMemo(signal, k, lines);
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
log$1(signals);
|
|
220
|
-
colorizeLines(lines);
|
|
221
|
-
return true;
|
|
222
|
-
};
|
|
223
|
-
}
|
|
224
|
-
const LightColors = {
|
|
225
|
-
red: 'color: red;',
|
|
226
|
-
green: 'color: green;',
|
|
227
|
-
reset: 'color: inherit;'
|
|
228
|
-
};
|
|
229
|
-
const DarkColors = {
|
|
230
|
-
red: 'color: red;',
|
|
231
|
-
green: 'color: lightgreen;',
|
|
232
|
-
reset: 'color: inherit;'
|
|
233
|
-
};
|
|
234
|
-
function isLightMode$1() {
|
|
235
|
-
if (window?.matchMedia?.('(prefers-color-scheme: light)').matches) {
|
|
236
|
-
return true;
|
|
237
|
-
}
|
|
238
|
-
return false;
|
|
239
|
-
}
|
|
240
|
-
const RED = {};
|
|
241
|
-
const GREEN = {};
|
|
242
|
-
const RESET = {};
|
|
243
|
-
const EOL = {};
|
|
244
|
-
function colorizeLines(lines) {
|
|
245
|
-
const Colors = isLightMode$1() ? LightColors : DarkColors;
|
|
246
|
-
const colors = [];
|
|
247
|
-
let line = '';
|
|
248
|
-
for (const str of lines) {
|
|
249
|
-
if (str === RED) {
|
|
250
|
-
colors.push(Colors.red);
|
|
251
|
-
line += '%c';
|
|
252
|
-
} else if (str === GREEN) {
|
|
253
|
-
colors.push(Colors.green);
|
|
254
|
-
line += '%c';
|
|
255
|
-
} else if (str === RESET) {
|
|
256
|
-
colors.push(Colors.reset);
|
|
257
|
-
line += '%c';
|
|
258
|
-
} else if (str === EOL) {
|
|
259
|
-
line += '\n';
|
|
260
|
-
} else {
|
|
261
|
-
line += str;
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
log$1(line, ...colors);
|
|
265
|
-
}
|
|
266
|
-
function log$1(...args) {
|
|
267
|
-
// eslint-disable-next-line no-console
|
|
268
|
-
console.log(...args);
|
|
269
|
-
}
|
|
270
|
-
function isDirty(signal) {
|
|
271
|
-
return signal.isStale;
|
|
272
|
-
}
|
|
273
|
-
function isDirtyMemo(memo) {
|
|
274
|
-
// iterate simple signals first to get fastest answer
|
|
275
|
-
for (const signal of memo.signals) {
|
|
276
|
-
if (isMemo(signal)) continue;
|
|
277
|
-
if (isDirty(signal)) {
|
|
278
|
-
return true;
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
for (const signal of memo.signals) {
|
|
282
|
-
if (isMemo(signal)) {
|
|
283
|
-
return isDirtyMemo(signal);
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
return false;
|
|
287
|
-
}
|
|
288
|
-
function printSignal(signal, key, lines = [], depth = 0) {
|
|
289
|
-
const _dirty = isDirty(signal);
|
|
290
|
-
lines.push(`${''.padStart(depth * 2, ' ')}${_dirty ? '❌' : '✅'} `, _dirty ? RED : GREEN, `${String(key)}`, RESET, EOL);
|
|
291
|
-
return lines;
|
|
292
|
-
}
|
|
293
|
-
function printMemo(memo, key, lines = [], depth = 0) {
|
|
294
|
-
const _dirty = isDirtyMemo(memo);
|
|
295
|
-
lines.push(`${''.padStart(depth * 2, ' ')}${_dirty ? '❌' : '✅'} `, _dirty ? RED : GREEN, `<memo> ${String(key)}`, RESET, `: (consumes ${memo.signals.size} signals)`, EOL);
|
|
296
|
-
for (const signal of memo.signals) {
|
|
297
|
-
if (isMemo(signal)) continue;
|
|
298
|
-
printSignal(signal, signal.key, lines, depth + 1);
|
|
299
|
-
}
|
|
300
|
-
for (const signal of memo.signals) {
|
|
301
|
-
if (isMemo(signal)) {
|
|
302
|
-
printMemo(signal, signal.key, lines, depth + 1);
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
return lines;
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
/**
|
|
309
|
-
* Creates a signal for the key/object pairing and subscribes to the signal.
|
|
310
|
-
*
|
|
311
|
-
* Use when you need to ensure a signal exists and is subscribed to.
|
|
312
|
-
*
|
|
313
|
-
* @private
|
|
314
|
-
*/
|
|
315
|
-
function entangleSignal(signals, obj, key, initialValue) {
|
|
316
|
-
let internalSignal = peekInternalSignal(signals, key);
|
|
317
|
-
if (!internalSignal) {
|
|
318
|
-
internalSignal = createInternalSignal(signals, obj, key, initialValue);
|
|
319
|
-
}
|
|
320
|
-
consumeInternalSignal(internalSignal);
|
|
321
|
-
return internalSignal;
|
|
322
|
-
}
|
|
323
|
-
function entangleInitiallyStaleSignal(signals, obj, key, initialValue) {
|
|
324
|
-
let internalSignal = peekInternalSignal(signals, key);
|
|
325
|
-
if (!internalSignal) {
|
|
326
|
-
internalSignal = createInternalSignal(signals, obj, key, initialValue);
|
|
327
|
-
internalSignal.isStale = true; // mark it as stale
|
|
328
|
-
}
|
|
329
|
-
consumeInternalSignal(internalSignal);
|
|
330
|
-
return internalSignal;
|
|
331
|
-
}
|
|
332
|
-
function createSignalDescriptor(key, intialValue) {
|
|
333
|
-
return {
|
|
334
|
-
enumerable: true,
|
|
335
|
-
configurable: false,
|
|
336
|
-
get() {
|
|
337
|
-
const signals = withSignalStore(this);
|
|
338
|
-
const internalSignal = entangleSignal(signals, this, key, intialValue);
|
|
339
|
-
internalSignal.isStale = false; // reset stale state
|
|
340
|
-
return internalSignal.value;
|
|
341
|
-
},
|
|
342
|
-
set(value) {
|
|
343
|
-
const signals = withSignalStore(this);
|
|
344
|
-
const internalSignal = getOrCreateInternalSignal(signals, this, key, intialValue);
|
|
345
|
-
if (internalSignal.value !== value) {
|
|
346
|
-
internalSignal.value = value;
|
|
347
|
-
notifyInternalSignal(internalSignal);
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
};
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
/**
|
|
354
|
-
* define an enumerable signal property.
|
|
355
|
-
*
|
|
356
|
-
* Akin to Object.defineProperty.
|
|
357
|
-
*
|
|
358
|
-
* The signal will be lazily created when accessed and scoped to the
|
|
359
|
-
* instance of the object.
|
|
360
|
-
*
|
|
361
|
-
* @private
|
|
362
|
-
*/
|
|
363
|
-
function defineSignal(obj, key, v) {
|
|
364
|
-
Object.defineProperty(obj, key, createSignalDescriptor(key, v));
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
/**
|
|
368
|
-
* Define a non-enumerable signal property.
|
|
369
|
-
*
|
|
370
|
-
* @private
|
|
371
|
-
*/
|
|
372
|
-
function defineNonEnumerableSignal(obj, key, v) {
|
|
373
|
-
const desc = createSignalDescriptor(key, v);
|
|
374
|
-
desc.enumerable = false;
|
|
375
|
-
Object.defineProperty(obj, key, desc);
|
|
376
|
-
}
|
|
377
|
-
/**
|
|
378
|
-
* Decorator version of creating a signal.
|
|
379
|
-
*/
|
|
380
|
-
function signal(target, key, descriptor) {
|
|
381
|
-
// Error on `@signal()`, `@signal(...args)``
|
|
382
|
-
(test => {
|
|
383
|
-
if (!test) {
|
|
384
|
-
throw new Error('You attempted to use @signal(), which is not necessary nor supported. Remove the parentheses and you will be good to go!');
|
|
385
|
-
}
|
|
386
|
-
})(target !== undefined);
|
|
387
|
-
(test => {
|
|
388
|
-
if (!test) {
|
|
389
|
-
throw new Error(`You attempted to use @signal on with ${arguments.length > 1 ? 'arguments' : 'an argument'} ( @signal(${Array.from(arguments).map(d => `'${d}'`).join(', ')}) ), which is not supported. Dependencies are automatically tracked, so you can just use ${'`@signal`'}`);
|
|
390
|
-
}
|
|
391
|
-
})(typeof target === 'object' && typeof key === 'string' && typeof descriptor === 'object' && arguments.length === 3);
|
|
392
|
-
return createSignalDescriptor(key, descriptor.initializer ? makeInitializer(descriptor.initializer) : null);
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
/**
|
|
396
|
-
* Decorator version of creating a memoized getter
|
|
397
|
-
*/
|
|
398
|
-
function memoized(target, key, descriptor) {
|
|
399
|
-
// Error on `@memoized()`, `@memoized(...args)`, and `@memoized propName = value;`
|
|
400
|
-
(test => {
|
|
401
|
-
if (!test) {
|
|
402
|
-
throw new Error('You attempted to use @memoized(), which is not necessary nor supported. Remove the parentheses and you will be good to go!');
|
|
403
|
-
}
|
|
404
|
-
})(target !== undefined);
|
|
405
|
-
(test => {
|
|
406
|
-
if (!test) {
|
|
407
|
-
throw new Error(`You attempted to use @memoized on with ${arguments.length > 1 ? 'arguments' : 'an argument'} ( @memoized(${Array.from(arguments).map(d => `'${d}'`).join(', ')}), which is not supported. Dependencies are automatically tracked, so you can just use ${'`@memoized`'}`);
|
|
408
|
-
}
|
|
409
|
-
})(typeof target === 'object' && typeof key === 'string' && typeof descriptor === 'object' && arguments.length === 3);
|
|
410
|
-
(test => {
|
|
411
|
-
if (!test) {
|
|
412
|
-
throw new Error(`The @memoized decorator must be applied to getters. '${key}' is not a getter.`);
|
|
413
|
-
}
|
|
414
|
-
})(typeof descriptor.get === 'function');
|
|
415
|
-
|
|
416
|
-
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
417
|
-
const getter = descriptor.get;
|
|
418
|
-
descriptor.get = function () {
|
|
419
|
-
const signals = withSignalStore(this);
|
|
420
|
-
let memoSignal = signals.get(key);
|
|
421
|
-
if (!memoSignal) {
|
|
422
|
-
memoSignal = createInternalMemo(signals, this, key, getter.bind(this));
|
|
423
|
-
}
|
|
424
|
-
return memoSignal();
|
|
425
|
-
};
|
|
426
|
-
return descriptor;
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
/**
|
|
430
|
-
* Decorator version of creating a gate.
|
|
431
|
-
*
|
|
432
|
-
* @private
|
|
433
|
-
*/
|
|
434
|
-
function gate(_target, key, desc) {
|
|
435
|
-
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
436
|
-
const getter = desc.get;
|
|
437
|
-
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
438
|
-
const setter = desc.set;
|
|
439
|
-
const isLocal = desc.isLocal;
|
|
440
|
-
desc.get = function () {
|
|
441
|
-
const signals = withSignalStore(this);
|
|
442
|
-
let internalSignal = peekInternalSignal(signals, key);
|
|
443
|
-
if (!internalSignal) {
|
|
444
|
-
internalSignal = createInternalSignal(signals, this, key, getter.call(this));
|
|
445
|
-
} else if (internalSignal.isStale) {
|
|
446
|
-
internalSignal.isStale = false;
|
|
447
|
-
internalSignal.value = getter.call(this);
|
|
448
|
-
}
|
|
449
|
-
consumeInternalSignal(internalSignal);
|
|
450
|
-
return internalSignal.value;
|
|
451
|
-
};
|
|
452
|
-
if (setter) {
|
|
453
|
-
desc.set = function (v) {
|
|
454
|
-
const signals = withSignalStore(this);
|
|
455
|
-
let internalSignal = peekInternalSignal(signals, key);
|
|
456
|
-
if (!internalSignal) {
|
|
457
|
-
// we can't use `v` as initialValue here because setters don't
|
|
458
|
-
// return the value and the final value may be different
|
|
459
|
-
// than what the setter was called with.
|
|
460
|
-
internalSignal = createInternalSignal(signals, this, key, undefined);
|
|
461
|
-
internalSignal.isStale = true;
|
|
462
|
-
}
|
|
463
|
-
setter.call(this, v);
|
|
464
|
-
// when a gate is set, we do not notify the signal
|
|
465
|
-
// as its update is controlled externally.
|
|
466
|
-
// unless it specifically sets itself to be locally managed
|
|
467
|
-
if (isLocal) {
|
|
468
|
-
internalSignal.isStale = true;
|
|
469
|
-
notifyInternalSignal(internalSignal);
|
|
470
|
-
}
|
|
471
|
-
};
|
|
472
|
-
}
|
|
473
|
-
return desc;
|
|
474
|
-
}
|
|
475
|
-
function defineGate(obj, key, desc) {
|
|
476
|
-
const options = Object.assign({
|
|
477
|
-
enumerable: true,
|
|
478
|
-
configurable: false
|
|
479
|
-
}, gate(obj, key, desc));
|
|
480
|
-
Object.defineProperty(obj, key, options);
|
|
481
|
-
}
|
|
482
15
|
function urlFromLink(link) {
|
|
483
16
|
if (typeof link === 'string') return link;
|
|
484
17
|
return link.href;
|
|
@@ -2228,8 +1761,6 @@ class CacheManager {
|
|
|
2228
1761
|
* a `content` member and therefor must not assume the existence
|
|
2229
1762
|
* of `request` and `response` on the document.
|
|
2230
1763
|
*
|
|
2231
|
-
* @param {StructuredDocument} doc
|
|
2232
|
-
* @return {ResourceDocument}
|
|
2233
1764
|
* @public
|
|
2234
1765
|
*/
|
|
2235
1766
|
put(doc) {
|
|
@@ -2241,7 +1772,6 @@ class CacheManager {
|
|
|
2241
1772
|
*
|
|
2242
1773
|
* @public
|
|
2243
1774
|
* @param op the operation to perform
|
|
2244
|
-
* @return {void}
|
|
2245
1775
|
*/
|
|
2246
1776
|
patch(op) {
|
|
2247
1777
|
this.___cache.patch(op);
|
|
@@ -2252,7 +1782,6 @@ class CacheManager {
|
|
|
2252
1782
|
* on relationships only.
|
|
2253
1783
|
*
|
|
2254
1784
|
* @public
|
|
2255
|
-
* @param mutation
|
|
2256
1785
|
*/
|
|
2257
1786
|
mutate(mutation) {
|
|
2258
1787
|
this.___cache.mutate(mutation);
|
|
@@ -2286,8 +1815,7 @@ class CacheManager {
|
|
|
2286
1815
|
* notifications for relational data.
|
|
2287
1816
|
*
|
|
2288
1817
|
* @public
|
|
2289
|
-
* @
|
|
2290
|
-
* @return {ResourceDocument | ResourceBlob | null} the known resource data
|
|
1818
|
+
* @return the known resource data
|
|
2291
1819
|
*/
|
|
2292
1820
|
|
|
2293
1821
|
peek(cacheKey) {
|
|
@@ -2300,8 +1828,6 @@ class CacheManager {
|
|
|
2300
1828
|
* Peek the Cache for the existing request data associated with
|
|
2301
1829
|
* a cacheable request
|
|
2302
1830
|
*
|
|
2303
|
-
* @param {RequestKey}
|
|
2304
|
-
* @return {RequestKey | null}
|
|
2305
1831
|
* @public
|
|
2306
1832
|
*/
|
|
2307
1833
|
peekRequest(key) {
|
|
@@ -2329,7 +1855,6 @@ class CacheManager {
|
|
|
2329
1855
|
* utilize this method to fork the cache.
|
|
2330
1856
|
*
|
|
2331
1857
|
* @public
|
|
2332
|
-
* @return {Promise<Cache>}
|
|
2333
1858
|
*/
|
|
2334
1859
|
fork() {
|
|
2335
1860
|
return this.___cache.fork();
|
|
@@ -2342,9 +1867,7 @@ class CacheManager {
|
|
|
2342
1867
|
* preferring instead to merge at the Store level, which will
|
|
2343
1868
|
* utilize this method to merge the caches.
|
|
2344
1869
|
*
|
|
2345
|
-
* @param {Cache} cache
|
|
2346
1870
|
* @public
|
|
2347
|
-
* @return {Promise<void>}
|
|
2348
1871
|
*/
|
|
2349
1872
|
merge(cache) {
|
|
2350
1873
|
return this.___cache.merge(cache);
|
|
@@ -2394,7 +1917,6 @@ class CacheManager {
|
|
|
2394
1917
|
* which may be fed back into a new instance of the same Cache
|
|
2395
1918
|
* via `cache.hydrate`.
|
|
2396
1919
|
*
|
|
2397
|
-
* @return {Promise<ReadableStream>}
|
|
2398
1920
|
* @public
|
|
2399
1921
|
*/
|
|
2400
1922
|
dump() {
|
|
@@ -2413,8 +1935,6 @@ class CacheManager {
|
|
|
2413
1935
|
* behavior supports optimizing pre/fetching of data for route transitions
|
|
2414
1936
|
* via data-only SSR modes.
|
|
2415
1937
|
*
|
|
2416
|
-
* @param {ReadableStream} stream
|
|
2417
|
-
* @return {Promise<void>}
|
|
2418
1938
|
* @public
|
|
2419
1939
|
*/
|
|
2420
1940
|
hydrate(stream) {
|
|
@@ -5937,7 +5457,7 @@ class RecordReference {
|
|
|
5937
5457
|
simplest usage of this API is similar to `store.push`: you provide a
|
|
5938
5458
|
normalized hash of data and the object represented by the reference
|
|
5939
5459
|
will update.
|
|
5940
|
-
If you pass a promise to `push`,
|
|
5460
|
+
If you pass a promise to `push`, WarpDrive will not ask the adapter
|
|
5941
5461
|
for the data if another attempt to fetch it is made in the
|
|
5942
5462
|
interim. When the promise resolves, the underlying object is updated
|
|
5943
5463
|
with the new data, and the promise returned by *this function* is resolved
|
|
@@ -6823,7 +6343,7 @@ function constructResource(type, id, lid) {
|
|
|
6823
6343
|
|
|
6824
6344
|
### Inverses
|
|
6825
6345
|
|
|
6826
|
-
Often, the relationships in
|
|
6346
|
+
Often, the relationships in WarpDrive applications will have
|
|
6827
6347
|
an inverse. For example, imagine the following models are
|
|
6828
6348
|
defined:
|
|
6829
6349
|
|
|
@@ -7181,1180 +6701,59 @@ function mutate(collection, mutation, _SIGNAL) {
|
|
|
7181
6701
|
manager.mutate(mutation);
|
|
7182
6702
|
notifyInternalSignal(_SIGNAL);
|
|
7183
6703
|
}
|
|
7184
|
-
function
|
|
7185
|
-
|
|
7186
|
-
|
|
7187
|
-
|
|
7188
|
-
|
|
7189
|
-
|
|
7190
|
-
desc = decorator(prototype, prop, desc) || desc;
|
|
7191
|
-
}
|
|
7192
|
-
if (desc.initializer !== void 0) {
|
|
7193
|
-
desc.value = desc.initializer ? desc.initializer.call(prototype) : void 0;
|
|
7194
|
-
desc.initializer = void 0;
|
|
7195
|
-
}
|
|
7196
|
-
Object.defineProperty(prototype, prop, desc);
|
|
6704
|
+
function getAliasField(context) {
|
|
6705
|
+
(test => {
|
|
6706
|
+
{
|
|
6707
|
+
throw new Error(`Alias field access is not implemented`);
|
|
6708
|
+
}
|
|
6709
|
+
})();
|
|
7197
6710
|
}
|
|
7198
|
-
|
|
7199
|
-
|
|
7200
|
-
|
|
7201
|
-
|
|
7202
|
-
|
|
7203
|
-
|
|
6711
|
+
function setAliasField(context) {
|
|
6712
|
+
(test => {
|
|
6713
|
+
{
|
|
6714
|
+
throw new Error(`Alias field setting is not implemented`);
|
|
6715
|
+
}
|
|
6716
|
+
})();
|
|
6717
|
+
return false;
|
|
6718
|
+
}
|
|
6719
|
+
const ARRAY_GETTER_METHODS = new Set([Symbol.iterator, 'concat', 'entries', 'every', 'fill', 'filter', 'find', 'findIndex', 'flat', 'flatMap', 'forEach', 'includes', 'indexOf', 'join', 'keys', 'lastIndexOf', 'map', 'reduce', 'reduceRight', 'slice', 'some', 'values']);
|
|
6720
|
+
// const ARRAY_SETTER_METHODS = new Set<KeyType>(['push', 'pop', 'unshift', 'shift', 'splice', 'sort']);
|
|
6721
|
+
const SYNC_PROPS = new Set(['[]', 'length']);
|
|
6722
|
+
function isArrayGetter(prop) {
|
|
6723
|
+
return ARRAY_GETTER_METHODS.has(prop);
|
|
6724
|
+
}
|
|
6725
|
+
const ARRAY_SETTER_METHODS = new Set(['push', 'pop', 'unshift', 'shift', 'splice', 'sort']);
|
|
6726
|
+
function isArraySetter(prop) {
|
|
6727
|
+
return ARRAY_SETTER_METHODS.has(prop);
|
|
7204
6728
|
}
|
|
7205
6729
|
|
|
7206
|
-
|
|
7207
|
-
|
|
7208
|
-
|
|
7209
|
-
|
|
7210
|
-
/** @deprecated use {@link RecoveryFeatures} */
|
|
7211
|
-
|
|
7212
|
-
/**
|
|
7213
|
-
* Utilities for keeping the request fresh
|
|
7214
|
-
*/
|
|
7215
|
-
|
|
7216
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
7217
|
-
|
|
7218
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
7219
|
-
|
|
7220
|
-
/**
|
|
7221
|
-
* A reactive class
|
|
7222
|
-
*
|
|
7223
|
-
* @hideconstructor
|
|
7224
|
-
*/
|
|
7225
|
-
class RequestSubscription {
|
|
7226
|
-
/**
|
|
7227
|
-
* Whether the browser reports that the network is online.
|
|
7228
|
-
*/
|
|
6730
|
+
// function isSelfProp<T extends object>(self: T, prop: KeyType): prop is keyof T {
|
|
6731
|
+
// return prop in self;
|
|
6732
|
+
// }
|
|
7229
6733
|
|
|
7230
|
-
|
|
7231
|
-
|
|
7232
|
-
|
|
6734
|
+
function convertToInt(prop) {
|
|
6735
|
+
if (typeof prop === 'symbol') return null;
|
|
6736
|
+
const num = Number(prop);
|
|
6737
|
+
if (isNaN(num)) return null;
|
|
6738
|
+
return num % 1 === 0 ? num : null;
|
|
6739
|
+
}
|
|
6740
|
+
function safeForEach(instance, arr, store, callback, target) {
|
|
6741
|
+
if (target === undefined) {
|
|
6742
|
+
target = null;
|
|
6743
|
+
}
|
|
6744
|
+
// clone to prevent mutation
|
|
6745
|
+
arr = arr.slice();
|
|
6746
|
+
(test => {
|
|
6747
|
+
if (!test) {
|
|
6748
|
+
throw new Error('`forEach` expects a function as first argument.');
|
|
6749
|
+
}
|
|
6750
|
+
})(typeof callback === 'function');
|
|
7233
6751
|
|
|
7234
|
-
|
|
7235
|
-
|
|
7236
|
-
|
|
7237
|
-
|
|
7238
|
-
|
|
7239
|
-
* The most recent blocking request that was made, typically
|
|
7240
|
-
* the result of a reload.
|
|
7241
|
-
*
|
|
7242
|
-
* This will never be the original request passed as an arg to
|
|
7243
|
-
* the component.
|
|
7244
|
-
*
|
|
7245
|
-
* @internal
|
|
7246
|
-
*/
|
|
7247
|
-
|
|
7248
|
-
/**
|
|
7249
|
-
* The most recent request that was made, typically due to either a
|
|
7250
|
-
* reload or a refresh.
|
|
7251
|
-
*
|
|
7252
|
-
* This will never be the original request passed as an arg to
|
|
7253
|
-
* the component.
|
|
7254
|
-
*
|
|
7255
|
-
* @internal
|
|
7256
|
-
*/
|
|
7257
|
-
|
|
7258
|
-
/**
|
|
7259
|
-
* The time at which the network was reported as offline.
|
|
7260
|
-
*
|
|
7261
|
-
* @internal
|
|
7262
|
-
*/
|
|
7263
|
-
|
|
7264
|
-
/** @internal */
|
|
7265
|
-
|
|
7266
|
-
/** @internal */
|
|
7267
|
-
|
|
7268
|
-
/** @internal */
|
|
7269
|
-
|
|
7270
|
-
/** @internal */
|
|
7271
|
-
|
|
7272
|
-
/** @internal */
|
|
7273
|
-
|
|
7274
|
-
/**
|
|
7275
|
-
* The event listener for network status changes,
|
|
7276
|
-
* cached to use the reference for removal.
|
|
7277
|
-
*
|
|
7278
|
-
* @internal
|
|
7279
|
-
*/
|
|
7280
|
-
|
|
7281
|
-
/**
|
|
7282
|
-
* The event listener for visibility status changes,
|
|
7283
|
-
* cached to use the reference for removal.
|
|
7284
|
-
*
|
|
7285
|
-
* @internal
|
|
7286
|
-
*/
|
|
7287
|
-
|
|
7288
|
-
/**
|
|
7289
|
-
* The last request passed as an arg to the component,
|
|
7290
|
-
* cached for comparison.
|
|
7291
|
-
*
|
|
7292
|
-
* @internal
|
|
7293
|
-
*/
|
|
7294
|
-
|
|
7295
|
-
/**
|
|
7296
|
-
* The last query passed as an arg to the component,
|
|
7297
|
-
* cached for comparison.
|
|
7298
|
-
*
|
|
7299
|
-
* @internal
|
|
7300
|
-
*/
|
|
7301
|
-
|
|
7302
|
-
/** @internal */
|
|
7303
|
-
|
|
7304
|
-
/** @internal */
|
|
7305
|
-
|
|
7306
|
-
/** @internal */
|
|
7307
|
-
|
|
7308
|
-
/**
|
|
7309
|
-
* The Store this subscription subscribes to or the RequestManager
|
|
7310
|
-
* which issues this request.
|
|
7311
|
-
*/
|
|
7312
|
-
|
|
7313
|
-
/**
|
|
7314
|
-
* The Store or RequestManager that the last subscription is attached to.
|
|
7315
|
-
*
|
|
7316
|
-
* This differs from 'store' because a <Request /> may be passed a
|
|
7317
|
-
* request originating from a different store than the <Request />
|
|
7318
|
-
* component would use if it were to issue the request itself.
|
|
7319
|
-
*
|
|
7320
|
-
* @internal
|
|
7321
|
-
*/
|
|
7322
|
-
_requester;
|
|
7323
|
-
constructor(store, args) {
|
|
7324
|
-
this._args = args;
|
|
7325
|
-
this.store = store;
|
|
7326
|
-
this._subscribedTo = null;
|
|
7327
|
-
this._subscription = null;
|
|
7328
|
-
this._intervalStart = null;
|
|
7329
|
-
this._invalidated = false;
|
|
7330
|
-
this._nextInterval = null;
|
|
7331
|
-
this._requester = null;
|
|
7332
|
-
this.isDestroyed = false;
|
|
7333
|
-
this[DISPOSE] = _DISPOSE;
|
|
7334
|
-
this._installListeners();
|
|
7335
|
-
void this._beginPolling();
|
|
7336
|
-
}
|
|
7337
|
-
|
|
7338
|
-
/**
|
|
7339
|
-
* @internal
|
|
7340
|
-
*/
|
|
7341
|
-
async _beginPolling() {
|
|
7342
|
-
// await the initial request
|
|
7343
|
-
try {
|
|
7344
|
-
if (!this.isIdle) {
|
|
7345
|
-
await this.request;
|
|
7346
|
-
}
|
|
7347
|
-
} catch {
|
|
7348
|
-
// ignore errors here, we just want to wait for the request to finish
|
|
7349
|
-
} finally {
|
|
7350
|
-
if (!this.isDestroyed) {
|
|
7351
|
-
void this._scheduleInterval();
|
|
7352
|
-
}
|
|
7353
|
-
}
|
|
7354
|
-
}
|
|
7355
|
-
get isIdle() {
|
|
7356
|
-
const {
|
|
7357
|
-
request,
|
|
7358
|
-
query
|
|
7359
|
-
} = this._args;
|
|
7360
|
-
return Boolean(!request && !query);
|
|
7361
|
-
}
|
|
7362
|
-
static {
|
|
7363
|
-
decorateMethodV2(this.prototype, "isIdle", [memoized]);
|
|
7364
|
-
}
|
|
7365
|
-
get autorefreshTypes() {
|
|
7366
|
-
const {
|
|
7367
|
-
autorefresh
|
|
7368
|
-
} = this._args;
|
|
7369
|
-
let types;
|
|
7370
|
-
if (autorefresh === true) {
|
|
7371
|
-
types = ['online', 'invalid'];
|
|
7372
|
-
} else if (typeof autorefresh === 'string') {
|
|
7373
|
-
types = autorefresh.split(',');
|
|
7374
|
-
} else {
|
|
7375
|
-
types = [];
|
|
7376
|
-
}
|
|
7377
|
-
return new Set(types);
|
|
7378
|
-
}
|
|
7379
|
-
|
|
7380
|
-
// we only run this function on component creation
|
|
7381
|
-
// and when an update is triggered, so it does not
|
|
7382
|
-
// react to changes in the autorefreshThreshold
|
|
7383
|
-
// or autorefresh args.
|
|
7384
|
-
//
|
|
7385
|
-
// if we need to react to those changes, we can
|
|
7386
|
-
// use a modifier or internal component or some
|
|
7387
|
-
// such to trigger a re-run of this function.
|
|
7388
|
-
/** @internal */
|
|
7389
|
-
static {
|
|
7390
|
-
decorateMethodV2(this.prototype, "autorefreshTypes", [memoized]);
|
|
7391
|
-
}
|
|
7392
|
-
async _scheduleInterval() {
|
|
7393
|
-
const {
|
|
7394
|
-
autorefreshThreshold
|
|
7395
|
-
} = this._args;
|
|
7396
|
-
const hasValidThreshold = typeof autorefreshThreshold === 'number' && autorefreshThreshold > 0;
|
|
7397
|
-
if (
|
|
7398
|
-
// dont schedule in SSR
|
|
7399
|
-
typeof window === 'undefined' ||
|
|
7400
|
-
// dont schedule without a threshold
|
|
7401
|
-
!hasValidThreshold ||
|
|
7402
|
-
// dont schedule if we weren't told to
|
|
7403
|
-
!this.autorefreshTypes.has('interval') ||
|
|
7404
|
-
// dont schedule if we're already scheduled
|
|
7405
|
-
this._intervalStart !== null) {
|
|
7406
|
-
return;
|
|
7407
|
-
}
|
|
7408
|
-
|
|
7409
|
-
// if we have a current request, wait for it to finish
|
|
7410
|
-
// before scheduling the next one
|
|
7411
|
-
if (this._latestRequest) {
|
|
7412
|
-
try {
|
|
7413
|
-
await this._latestRequest;
|
|
7414
|
-
} catch {
|
|
7415
|
-
// ignore errors here, we just want to wait for the request to finish
|
|
7416
|
-
}
|
|
7417
|
-
if (this.isDestroyed) {
|
|
7418
|
-
return;
|
|
7419
|
-
}
|
|
7420
|
-
}
|
|
7421
|
-
|
|
7422
|
-
// setup the next interval
|
|
7423
|
-
this._intervalStart = Date.now();
|
|
7424
|
-
this._nextInterval = setTimeout(() => {
|
|
7425
|
-
this._maybeUpdate();
|
|
7426
|
-
}, autorefreshThreshold);
|
|
7427
|
-
}
|
|
7428
|
-
|
|
7429
|
-
/** @internal */
|
|
7430
|
-
_clearInterval() {
|
|
7431
|
-
if (this._nextInterval) {
|
|
7432
|
-
clearTimeout(this._nextInterval);
|
|
7433
|
-
this._intervalStart = null;
|
|
7434
|
-
}
|
|
7435
|
-
}
|
|
7436
|
-
/**
|
|
7437
|
-
* @internal
|
|
7438
|
-
*/
|
|
7439
|
-
_updateSubscriptions() {
|
|
7440
|
-
if (this.isIdle) {
|
|
7441
|
-
return;
|
|
7442
|
-
}
|
|
7443
|
-
const requestId = this._request.lid;
|
|
7444
|
-
|
|
7445
|
-
// if we're already subscribed to this request, we don't need to do anything
|
|
7446
|
-
if (this._subscribedTo === requestId) {
|
|
7447
|
-
return;
|
|
7448
|
-
}
|
|
7449
|
-
|
|
7450
|
-
// if we're subscribed to a different request, we need to unsubscribe
|
|
7451
|
-
this._removeSubscriptions();
|
|
7452
|
-
|
|
7453
|
-
// if we have a request, we need to subscribe to it
|
|
7454
|
-
const store = this._getRequester();
|
|
7455
|
-
this._requester = store;
|
|
7456
|
-
if (requestId && isStore(store)) {
|
|
7457
|
-
this._subscribedTo = requestId;
|
|
7458
|
-
this._subscription = store.notifications.subscribe(requestId, (_id, op) => {
|
|
7459
|
-
// ignore subscription events that occur while our own component's request
|
|
7460
|
-
// is occurring
|
|
7461
|
-
if (this._isUpdating) {
|
|
7462
|
-
return;
|
|
7463
|
-
}
|
|
7464
|
-
switch (op) {
|
|
7465
|
-
case 'invalidated':
|
|
7466
|
-
{
|
|
7467
|
-
// if we're subscribed to invalidations, we need to update
|
|
7468
|
-
if (this.autorefreshTypes.has('invalid')) {
|
|
7469
|
-
this._invalidated = true;
|
|
7470
|
-
this._maybeUpdate();
|
|
7471
|
-
}
|
|
7472
|
-
break;
|
|
7473
|
-
}
|
|
7474
|
-
case 'state':
|
|
7475
|
-
{
|
|
7476
|
-
const latest = store.requestManager._deduped.get(requestId);
|
|
7477
|
-
const priority = latest?.priority;
|
|
7478
|
-
const state = this.reqState;
|
|
7479
|
-
if (!priority) {
|
|
7480
|
-
// if there is no priority, we have completed whatever request
|
|
7481
|
-
// was occurring and so we are no longer refreshing (if we were)
|
|
7482
|
-
this.isRefreshing = false;
|
|
7483
|
-
} else if (priority.blocking && !state.isLoading) {
|
|
7484
|
-
// if we are blocking, there is an active request for this identity
|
|
7485
|
-
// that MUST be fulfilled from network (not cache).
|
|
7486
|
-
// Thus this is not "refreshing" because we should clear out and
|
|
7487
|
-
// block on this request.
|
|
7488
|
-
//
|
|
7489
|
-
// we receive state notifications when either a request initiates
|
|
7490
|
-
// or completes.
|
|
7491
|
-
//
|
|
7492
|
-
// In the completes case: we may receive the state notification
|
|
7493
|
-
// slightly before the request is finalized because the NotificationManager
|
|
7494
|
-
// may sync flush it (and thus deliver it before the microtask completes)
|
|
7495
|
-
//
|
|
7496
|
-
// In the initiates case: we aren't supposed to receive one unless there
|
|
7497
|
-
// is no other request in flight for this identity.
|
|
7498
|
-
//
|
|
7499
|
-
// However, there is a race condition here where the completed
|
|
7500
|
-
// notification can trigger an update that generates a new request
|
|
7501
|
-
// thus giving us an initiated notification before the older request
|
|
7502
|
-
// finalizes.
|
|
7503
|
-
//
|
|
7504
|
-
// When this occurs, if the triggered update happens to have caused
|
|
7505
|
-
// a new request to be made for the same identity AND that request
|
|
7506
|
-
// is the one passed into this component as the @request arg, then
|
|
7507
|
-
// getRequestState will return the state of the new request.
|
|
7508
|
-
// We can detect this by checking if the request state is "loading"
|
|
7509
|
-
// as outside of this case we would have a completed request.
|
|
7510
|
-
//
|
|
7511
|
-
// That is the reason for the `&& !state.isLoading` check above.
|
|
7512
|
-
|
|
7513
|
-
// TODO should we just treat this as refreshing?
|
|
7514
|
-
this.isRefreshing = false;
|
|
7515
|
-
this._maybeUpdate('policy', true);
|
|
7516
|
-
} else {
|
|
7517
|
-
this.isRefreshing = true;
|
|
7518
|
-
}
|
|
7519
|
-
}
|
|
7520
|
-
}
|
|
7521
|
-
});
|
|
7522
|
-
}
|
|
7523
|
-
}
|
|
7524
|
-
|
|
7525
|
-
/**
|
|
7526
|
-
* @internal
|
|
7527
|
-
*/
|
|
7528
|
-
_removeSubscriptions() {
|
|
7529
|
-
const store = this._requester;
|
|
7530
|
-
if (this._subscription && store && isStore(store)) {
|
|
7531
|
-
store.notifications.unsubscribe(this._subscription);
|
|
7532
|
-
this._subscribedTo = null;
|
|
7533
|
-
this._subscription = null;
|
|
7534
|
-
this._requester = null;
|
|
7535
|
-
}
|
|
7536
|
-
}
|
|
7537
|
-
|
|
7538
|
-
/**
|
|
7539
|
-
* Install the event listeners for network and visibility changes.
|
|
7540
|
-
* This is only done in browser environments with a global `window`.
|
|
7541
|
-
*
|
|
7542
|
-
* @internal
|
|
7543
|
-
*/
|
|
7544
|
-
_installListeners() {
|
|
7545
|
-
if (typeof window === 'undefined') {
|
|
7546
|
-
return;
|
|
7547
|
-
}
|
|
7548
|
-
this.isOnline = window.navigator.onLine;
|
|
7549
|
-
this._unavailableStart = this.isOnline ? null : Date.now();
|
|
7550
|
-
this.isHidden = document.visibilityState === 'hidden';
|
|
7551
|
-
this._onlineChanged = event => {
|
|
7552
|
-
this.isOnline = event.type === 'online';
|
|
7553
|
-
if (event.type === 'offline' && this._unavailableStart === null) {
|
|
7554
|
-
this._unavailableStart = Date.now();
|
|
7555
|
-
}
|
|
7556
|
-
this._maybeUpdate();
|
|
7557
|
-
};
|
|
7558
|
-
this._backgroundChanged = () => {
|
|
7559
|
-
const isHidden = document.visibilityState === 'hidden';
|
|
7560
|
-
this.isHidden = isHidden;
|
|
7561
|
-
if (isHidden && this._unavailableStart === null) {
|
|
7562
|
-
this._unavailableStart = Date.now();
|
|
7563
|
-
}
|
|
7564
|
-
this._maybeUpdate();
|
|
7565
|
-
};
|
|
7566
|
-
window.addEventListener('online', this._onlineChanged, {
|
|
7567
|
-
passive: true,
|
|
7568
|
-
capture: true
|
|
7569
|
-
});
|
|
7570
|
-
window.addEventListener('offline', this._onlineChanged, {
|
|
7571
|
-
passive: true,
|
|
7572
|
-
capture: true
|
|
7573
|
-
});
|
|
7574
|
-
document.addEventListener('visibilitychange', this._backgroundChanged, {
|
|
7575
|
-
passive: true,
|
|
7576
|
-
capture: true
|
|
7577
|
-
});
|
|
7578
|
-
}
|
|
7579
|
-
|
|
7580
|
-
/**
|
|
7581
|
-
* If the network is online and the tab is visible, either reload or refresh the request
|
|
7582
|
-
* based on the component's configuration and the requested update mode.
|
|
7583
|
-
*
|
|
7584
|
-
* Valid modes are:
|
|
7585
|
-
*
|
|
7586
|
-
* - `'reload'`: Force a reload of the request.
|
|
7587
|
-
* - `'refresh'`: Refresh the request in the background.
|
|
7588
|
-
* - `'policy'`: Make the request, letting the store's configured CachePolicy decide whether to reload, refresh, or do nothing.
|
|
7589
|
-
* - `undefined`: Make the request using the component's autorefreshBehavior setting if the autorefreshThreshold has passed.
|
|
7590
|
-
*
|
|
7591
|
-
* @internal
|
|
7592
|
-
*/
|
|
7593
|
-
_maybeUpdate(mode, silent) {
|
|
7594
|
-
if (this.isIdle) {
|
|
7595
|
-
return;
|
|
7596
|
-
}
|
|
7597
|
-
const {
|
|
7598
|
-
reqState
|
|
7599
|
-
} = this;
|
|
7600
|
-
if (reqState.isPending) {
|
|
7601
|
-
return;
|
|
7602
|
-
}
|
|
7603
|
-
const canAttempt = Boolean(this.isOnline && !this.isHidden && (mode || this.autorefreshTypes.size));
|
|
7604
|
-
if (!canAttempt) {
|
|
7605
|
-
if (!silent && mode && mode !== '_invalidated') {
|
|
7606
|
-
throw new Error(`Reload not available: the network is not online or the tab is hidden`);
|
|
7607
|
-
}
|
|
7608
|
-
return;
|
|
7609
|
-
}
|
|
7610
|
-
const {
|
|
7611
|
-
autorefreshTypes
|
|
7612
|
-
} = this;
|
|
7613
|
-
let shouldAttempt = this._invalidated || Boolean(mode);
|
|
7614
|
-
if (!shouldAttempt && autorefreshTypes.has('online')) {
|
|
7615
|
-
const {
|
|
7616
|
-
_unavailableStart
|
|
7617
|
-
} = this;
|
|
7618
|
-
const {
|
|
7619
|
-
autorefreshThreshold
|
|
7620
|
-
} = this._args;
|
|
7621
|
-
const deadline = typeof autorefreshThreshold === 'number' ? autorefreshThreshold : DEFAULT_DEADLINE;
|
|
7622
|
-
shouldAttempt = Boolean(_unavailableStart && Date.now() - _unavailableStart > deadline);
|
|
7623
|
-
}
|
|
7624
|
-
if (!shouldAttempt && autorefreshTypes.has('interval')) {
|
|
7625
|
-
const {
|
|
7626
|
-
_intervalStart
|
|
7627
|
-
} = this;
|
|
7628
|
-
const {
|
|
7629
|
-
autorefreshThreshold
|
|
7630
|
-
} = this._args;
|
|
7631
|
-
if (_intervalStart && typeof autorefreshThreshold === 'number' && autorefreshThreshold > 0) {
|
|
7632
|
-
shouldAttempt = Boolean(Date.now() - _intervalStart >= autorefreshThreshold);
|
|
7633
|
-
}
|
|
7634
|
-
}
|
|
7635
|
-
this._unavailableStart = null;
|
|
7636
|
-
this._invalidated = false;
|
|
7637
|
-
if (shouldAttempt) {
|
|
7638
|
-
this._clearInterval();
|
|
7639
|
-
this._isUpdating = true;
|
|
7640
|
-
const realMode = mode === '_invalidated' ? null : mode;
|
|
7641
|
-
const val = realMode ?? this._args.autorefreshBehavior ?? 'policy';
|
|
7642
|
-
|
|
7643
|
-
// if the future was generated by an older store version, it may not have
|
|
7644
|
-
// a requester set. In this case we append it to ensure that reload and
|
|
7645
|
-
// refresh will work appropriately.
|
|
7646
|
-
const requester = this._getRequester();
|
|
7647
|
-
if (!reqState._request.requester) {
|
|
7648
|
-
reqState._request.requester = requester;
|
|
7649
|
-
}
|
|
7650
|
-
switch (val) {
|
|
7651
|
-
case 'reload':
|
|
7652
|
-
this._latestRequest = reqState.reload();
|
|
7653
|
-
break;
|
|
7654
|
-
case 'refresh':
|
|
7655
|
-
this._latestRequest = reqState.refresh();
|
|
7656
|
-
break;
|
|
7657
|
-
case 'policy':
|
|
7658
|
-
this._latestRequest = reqState.refresh(true);
|
|
7659
|
-
break;
|
|
7660
|
-
default:
|
|
7661
|
-
(test => {
|
|
7662
|
-
{
|
|
7663
|
-
throw new Error(`Invalid ${mode ? 'update mode' : '@autorefreshBehavior'} for <Request />: ${isNeverString(val)}`);
|
|
7664
|
-
}
|
|
7665
|
-
})();
|
|
7666
|
-
}
|
|
7667
|
-
if (val !== 'refresh') {
|
|
7668
|
-
this._localRequest = this._latestRequest;
|
|
7669
|
-
}
|
|
7670
|
-
void this._scheduleInterval();
|
|
7671
|
-
void this._latestRequest.finally(() => {
|
|
7672
|
-
this._isUpdating = false;
|
|
7673
|
-
});
|
|
7674
|
-
}
|
|
7675
|
-
}
|
|
7676
|
-
|
|
7677
|
-
/**
|
|
7678
|
-
* @internal
|
|
7679
|
-
*/
|
|
7680
|
-
_getRequester() {
|
|
7681
|
-
// Note: we check for the requester's presence
|
|
7682
|
-
// as well as the request's presence because we may
|
|
7683
|
-
// be subscribed to a request issued by a store from an older
|
|
7684
|
-
// version of the library that didn't yet set requester.
|
|
7685
|
-
if (this._args.request?.requester) {
|
|
7686
|
-
return this._args.request.requester;
|
|
7687
|
-
}
|
|
7688
|
-
return this.store;
|
|
7689
|
-
}
|
|
7690
|
-
|
|
7691
|
-
/**
|
|
7692
|
-
* Retry the request, reloading it from the server.
|
|
7693
|
-
*/
|
|
7694
|
-
retry = async () => {
|
|
7695
|
-
this._maybeUpdate('reload');
|
|
7696
|
-
await this._localRequest;
|
|
7697
|
-
};
|
|
7698
|
-
|
|
7699
|
-
/**
|
|
7700
|
-
* Refresh the request, updating it in the background.
|
|
7701
|
-
*/
|
|
7702
|
-
refresh = async () => {
|
|
7703
|
-
this._maybeUpdate('refresh');
|
|
7704
|
-
await this._latestRequest;
|
|
7705
|
-
};
|
|
7706
|
-
|
|
7707
|
-
/**
|
|
7708
|
-
* features to yield to the error slot of a component
|
|
7709
|
-
*/
|
|
7710
|
-
get errorFeatures() {
|
|
7711
|
-
return {
|
|
7712
|
-
isHidden: this.isHidden,
|
|
7713
|
-
isOnline: this.isOnline,
|
|
7714
|
-
retry: this.retry
|
|
7715
|
-
};
|
|
7716
|
-
}
|
|
7717
|
-
|
|
7718
|
-
/**
|
|
7719
|
-
* features to yield to the content slot of a component
|
|
7720
|
-
*/
|
|
7721
|
-
static {
|
|
7722
|
-
decorateMethodV2(this.prototype, "errorFeatures", [memoized]);
|
|
7723
|
-
}
|
|
7724
|
-
get contentFeatures() {
|
|
7725
|
-
const feat = {
|
|
7726
|
-
isHidden: this.isHidden,
|
|
7727
|
-
isOnline: this.isOnline,
|
|
7728
|
-
reload: this.retry,
|
|
7729
|
-
refresh: this.refresh,
|
|
7730
|
-
isRefreshing: this.isRefreshing,
|
|
7731
|
-
latestRequest: this._latestRequest
|
|
7732
|
-
};
|
|
7733
|
-
if (feat.isRefreshing) {
|
|
7734
|
-
feat.abort = () => {
|
|
7735
|
-
this._latestRequest?.abort();
|
|
7736
|
-
};
|
|
7737
|
-
}
|
|
7738
|
-
return feat;
|
|
7739
|
-
}
|
|
7740
|
-
|
|
7741
|
-
/**
|
|
7742
|
-
* @internal
|
|
7743
|
-
*/
|
|
7744
|
-
static {
|
|
7745
|
-
decorateMethodV2(this.prototype, "contentFeatures", [memoized]);
|
|
7746
|
-
}
|
|
7747
|
-
get _request() {
|
|
7748
|
-
const {
|
|
7749
|
-
request,
|
|
7750
|
-
query
|
|
7751
|
-
} = this._args;
|
|
7752
|
-
(test => {
|
|
7753
|
-
if (!test) {
|
|
7754
|
-
throw new Error(`Cannot use both @request and @query args with the <Request> component`);
|
|
7755
|
-
}
|
|
7756
|
-
})(!request || !query);
|
|
7757
|
-
const {
|
|
7758
|
-
_localRequest,
|
|
7759
|
-
_originalRequest,
|
|
7760
|
-
_originalQuery
|
|
7761
|
-
} = this;
|
|
7762
|
-
const isOriginalRequest = request === _originalRequest && query === _originalQuery;
|
|
7763
|
-
if (_localRequest && isOriginalRequest) {
|
|
7764
|
-
return _localRequest;
|
|
7765
|
-
}
|
|
7766
|
-
|
|
7767
|
-
// update state checks for the next time
|
|
7768
|
-
this._originalQuery = query;
|
|
7769
|
-
this._originalRequest = request;
|
|
7770
|
-
if (request) {
|
|
7771
|
-
return request;
|
|
7772
|
-
}
|
|
7773
|
-
(test => {
|
|
7774
|
-
if (!test) {
|
|
7775
|
-
throw new Error(`You must provide either @request or an @query arg with the <Request> component`);
|
|
7776
|
-
}
|
|
7777
|
-
})(query);
|
|
7778
|
-
return this.store.request(query);
|
|
7779
|
-
}
|
|
7780
|
-
static {
|
|
7781
|
-
decorateMethodV2(this.prototype, "_request", [memoized]);
|
|
7782
|
-
}
|
|
7783
|
-
get request() {
|
|
7784
|
-
{
|
|
7785
|
-
try {
|
|
7786
|
-
const request = this._request;
|
|
7787
|
-
this._updateSubscriptions();
|
|
7788
|
-
return request;
|
|
7789
|
-
} catch (e) {
|
|
7790
|
-
// eslint-disable-next-line no-console
|
|
7791
|
-
console.log(e);
|
|
7792
|
-
throw new Error(`Unable to initialize the request`, {
|
|
7793
|
-
cause: e
|
|
7794
|
-
});
|
|
7795
|
-
}
|
|
7796
|
-
}
|
|
7797
|
-
}
|
|
7798
|
-
static {
|
|
7799
|
-
decorateMethodV2(this.prototype, "request", [memoized]);
|
|
7800
|
-
}
|
|
7801
|
-
get reqState() {
|
|
7802
|
-
return getRequestState(this.request);
|
|
7803
|
-
}
|
|
7804
|
-
get result() {
|
|
7805
|
-
return this.reqState.result;
|
|
7806
|
-
}
|
|
7807
|
-
}
|
|
7808
|
-
defineSignal(RequestSubscription.prototype, 'isOnline', true);
|
|
7809
|
-
defineSignal(RequestSubscription.prototype, 'isHidden', false);
|
|
7810
|
-
defineSignal(RequestSubscription.prototype, 'isRefreshing', false);
|
|
7811
|
-
defineSignal(RequestSubscription.prototype, '_localRequest', undefined);
|
|
7812
|
-
defineSignal(RequestSubscription.prototype, '_latestRequest', undefined);
|
|
7813
|
-
function isStore(store) {
|
|
7814
|
-
return 'requestManager' in store;
|
|
7815
|
-
}
|
|
7816
|
-
function createRequestSubscription(store, args) {
|
|
7817
|
-
return new RequestSubscription(store, args);
|
|
7818
|
-
}
|
|
7819
|
-
function upgradeSubscription(sub) {
|
|
7820
|
-
return sub;
|
|
7821
|
-
}
|
|
7822
|
-
function _DISPOSE() {
|
|
7823
|
-
const self = upgradeSubscription(this);
|
|
7824
|
-
self.isDestroyed = true;
|
|
7825
|
-
self._removeSubscriptions();
|
|
7826
|
-
if (typeof window === 'undefined') {
|
|
7827
|
-
return;
|
|
7828
|
-
}
|
|
7829
|
-
self._clearInterval();
|
|
7830
|
-
window.removeEventListener('online', self._onlineChanged, {
|
|
7831
|
-
passive: true,
|
|
7832
|
-
capture: true
|
|
7833
|
-
});
|
|
7834
|
-
window.removeEventListener('offline', self._onlineChanged, {
|
|
7835
|
-
passive: true,
|
|
7836
|
-
capture: true
|
|
7837
|
-
});
|
|
7838
|
-
document.removeEventListener('visibilitychange', self._backgroundChanged, {
|
|
7839
|
-
passive: true,
|
|
7840
|
-
capture: true
|
|
7841
|
-
});
|
|
7842
|
-
}
|
|
7843
|
-
const RequestCache = new WeakMap();
|
|
7844
|
-
function isAbortError(error) {
|
|
7845
|
-
return error instanceof DOMException && error.name === 'AbortError';
|
|
7846
|
-
}
|
|
7847
|
-
function upgradeLoadingState(state) {
|
|
7848
|
-
return state;
|
|
7849
|
-
}
|
|
7850
|
-
async function watchStream(stream, loadingState) {
|
|
7851
|
-
const state = upgradeLoadingState(loadingState);
|
|
7852
|
-
const reader = stream.getReader();
|
|
7853
|
-
let bytesLoaded = 0;
|
|
7854
|
-
let shouldForward = state._stream !== null && state._stream.readable.locked;
|
|
7855
|
-
let isForwarding = shouldForward;
|
|
7856
|
-
let writer = state._stream?.writable.getWriter();
|
|
7857
|
-
const buffer = [];
|
|
7858
|
-
state._isPending = false;
|
|
7859
|
-
state._isStarted = true;
|
|
7860
|
-
state._startTime = performance.now();
|
|
7861
|
-
while (true) {
|
|
7862
|
-
const {
|
|
7863
|
-
value,
|
|
7864
|
-
done
|
|
7865
|
-
} = await reader.read();
|
|
7866
|
-
if (done) {
|
|
7867
|
-
break;
|
|
7868
|
-
}
|
|
7869
|
-
bytesLoaded += value.byteLength;
|
|
7870
|
-
state._bytesLoaded = bytesLoaded;
|
|
7871
|
-
state._lastPacketTime = performance.now();
|
|
7872
|
-
shouldForward = shouldForward || state._stream !== null && state._stream.readable.locked;
|
|
7873
|
-
if (shouldForward) {
|
|
7874
|
-
if (!isForwarding) {
|
|
7875
|
-
isForwarding = true;
|
|
7876
|
-
writer = state._stream.writable.getWriter();
|
|
7877
|
-
for (const item of buffer) {
|
|
7878
|
-
await writer.ready;
|
|
7879
|
-
await writer.write(item);
|
|
7880
|
-
}
|
|
7881
|
-
buffer.length = 0;
|
|
7882
|
-
}
|
|
7883
|
-
await writer.ready;
|
|
7884
|
-
await writer.write(value);
|
|
7885
|
-
} else {
|
|
7886
|
-
buffer.push(value);
|
|
7887
|
-
}
|
|
7888
|
-
}
|
|
7889
|
-
|
|
7890
|
-
// if we are still forwarding, we need to close the writer
|
|
7891
|
-
if (isForwarding) {
|
|
7892
|
-
await writer.ready;
|
|
7893
|
-
await writer.close();
|
|
7894
|
-
} else if (state._stream) {
|
|
7895
|
-
// if we are not forwarding, we need to cancel the stream
|
|
7896
|
-
await state._stream.readable.cancel('The Stream Has Already Ended');
|
|
7897
|
-
state._stream = null;
|
|
7898
|
-
}
|
|
7899
|
-
const endTime = performance.now();
|
|
7900
|
-
state._endTime = endTime;
|
|
7901
|
-
state._isComplete = true;
|
|
7902
|
-
state._isStarted = false;
|
|
7903
|
-
}
|
|
7904
|
-
|
|
7905
|
-
/**
|
|
7906
|
-
* Lazily consumes the stream of a request, providing a number of
|
|
7907
|
-
* reactive properties that can be used to build UIs that respond
|
|
7908
|
-
* to the progress of a request.
|
|
7909
|
-
*
|
|
7910
|
-
* @hideconstructor
|
|
7911
|
-
*/
|
|
7912
|
-
class RequestLoadingState {
|
|
7913
|
-
/** @internal */
|
|
7914
|
-
|
|
7915
|
-
/** @internal */
|
|
7916
|
-
|
|
7917
|
-
/** @internal */
|
|
7918
|
-
|
|
7919
|
-
/** @internal */
|
|
7920
|
-
|
|
7921
|
-
/** @internal */
|
|
7922
|
-
|
|
7923
|
-
/** @internal */
|
|
7924
|
-
|
|
7925
|
-
/** @internal */
|
|
7926
|
-
|
|
7927
|
-
/** @internal */
|
|
7928
|
-
|
|
7929
|
-
/** @internal */
|
|
7930
|
-
|
|
7931
|
-
/** @internal */
|
|
7932
|
-
|
|
7933
|
-
/** @internal */
|
|
7934
|
-
|
|
7935
|
-
/** @internal */
|
|
7936
|
-
_stream = null;
|
|
7937
|
-
/** @internal */
|
|
7938
|
-
_future;
|
|
7939
|
-
/** @internal */
|
|
7940
|
-
_triggered = false;
|
|
7941
|
-
/** @internal */
|
|
7942
|
-
_trigger() {
|
|
7943
|
-
if (this._triggered) {
|
|
7944
|
-
return;
|
|
7945
|
-
}
|
|
7946
|
-
this._triggered = true;
|
|
7947
|
-
const future = this._future;
|
|
7948
|
-
const promise = future.getStream();
|
|
7949
|
-
if (promise.sizeHint) {
|
|
7950
|
-
this._sizeHint = promise.sizeHint;
|
|
7951
|
-
}
|
|
7952
|
-
this.promise = promise.then(stream => {
|
|
7953
|
-
if (!stream) {
|
|
7954
|
-
this._isPending = false;
|
|
7955
|
-
this._isComplete = true;
|
|
7956
|
-
return;
|
|
7957
|
-
}
|
|
7958
|
-
return watchStream(stream, this);
|
|
7959
|
-
}, error => {
|
|
7960
|
-
this._isPending = false;
|
|
7961
|
-
this._isStarted = false;
|
|
7962
|
-
if (isAbortError(error)) {
|
|
7963
|
-
this._isCancelled = true;
|
|
7964
|
-
this._isComplete = true;
|
|
7965
|
-
}
|
|
7966
|
-
this._isErrored = true;
|
|
7967
|
-
this._error = error;
|
|
7968
|
-
});
|
|
7969
|
-
}
|
|
7970
|
-
promise = null;
|
|
7971
|
-
get isPending() {
|
|
7972
|
-
this._trigger();
|
|
7973
|
-
return this._isPending;
|
|
7974
|
-
}
|
|
7975
|
-
get sizeHint() {
|
|
7976
|
-
this._trigger();
|
|
7977
|
-
return this._sizeHint;
|
|
7978
|
-
}
|
|
7979
|
-
get stream() {
|
|
7980
|
-
this._trigger();
|
|
7981
|
-
if (!this._stream) {
|
|
7982
|
-
if (this._isComplete || this._isCancelled || this._isErrored) {
|
|
7983
|
-
return null;
|
|
7984
|
-
}
|
|
7985
|
-
this._stream = new TransformStream();
|
|
7986
|
-
}
|
|
7987
|
-
return this._stream.readable;
|
|
7988
|
-
}
|
|
7989
|
-
get isStarted() {
|
|
7990
|
-
this._trigger();
|
|
7991
|
-
return this._isStarted;
|
|
7992
|
-
}
|
|
7993
|
-
get bytesLoaded() {
|
|
7994
|
-
this._trigger();
|
|
7995
|
-
return this._bytesLoaded;
|
|
7996
|
-
}
|
|
7997
|
-
get startTime() {
|
|
7998
|
-
this._trigger();
|
|
7999
|
-
return this._startTime;
|
|
8000
|
-
}
|
|
8001
|
-
get endTime() {
|
|
8002
|
-
this._trigger();
|
|
8003
|
-
return this._endTime;
|
|
8004
|
-
}
|
|
8005
|
-
get lastPacketTime() {
|
|
8006
|
-
this._trigger();
|
|
8007
|
-
return this._lastPacketTime;
|
|
8008
|
-
}
|
|
8009
|
-
get isComplete() {
|
|
8010
|
-
this._trigger();
|
|
8011
|
-
return this._isComplete;
|
|
8012
|
-
}
|
|
8013
|
-
get isCancelled() {
|
|
8014
|
-
this._trigger();
|
|
8015
|
-
return this._isCancelled;
|
|
8016
|
-
}
|
|
8017
|
-
get isErrored() {
|
|
8018
|
-
this._trigger();
|
|
8019
|
-
return this._isErrored;
|
|
8020
|
-
}
|
|
8021
|
-
get error() {
|
|
8022
|
-
this._trigger();
|
|
8023
|
-
return this._error;
|
|
8024
|
-
}
|
|
8025
|
-
get elapsedTime() {
|
|
8026
|
-
return (this.endTime || this.lastPacketTime) - this.startTime;
|
|
8027
|
-
}
|
|
8028
|
-
get completedRatio() {
|
|
8029
|
-
return this.sizeHint ? this.bytesLoaded / this.sizeHint : 0;
|
|
8030
|
-
}
|
|
8031
|
-
get remainingRatio() {
|
|
8032
|
-
return 1 - this.completedRatio;
|
|
8033
|
-
}
|
|
8034
|
-
get duration() {
|
|
8035
|
-
return this.endTime - this.startTime;
|
|
8036
|
-
}
|
|
8037
|
-
get speed() {
|
|
8038
|
-
// bytes per second
|
|
8039
|
-
return this.bytesLoaded / (this.elapsedTime / 1000);
|
|
8040
|
-
}
|
|
8041
|
-
constructor(future) {
|
|
8042
|
-
this._future = future;
|
|
8043
|
-
}
|
|
8044
|
-
abort = () => {
|
|
8045
|
-
this._future.abort();
|
|
8046
|
-
};
|
|
8047
|
-
}
|
|
8048
|
-
defineNonEnumerableSignal(RequestLoadingState.prototype, '_isPending', true);
|
|
8049
|
-
defineNonEnumerableSignal(RequestLoadingState.prototype, '_isStarted', false);
|
|
8050
|
-
defineNonEnumerableSignal(RequestLoadingState.prototype, '_isComplete', false);
|
|
8051
|
-
defineNonEnumerableSignal(RequestLoadingState.prototype, '_isCancelled', false);
|
|
8052
|
-
defineNonEnumerableSignal(RequestLoadingState.prototype, '_isErrored', false);
|
|
8053
|
-
defineNonEnumerableSignal(RequestLoadingState.prototype, '_error', null);
|
|
8054
|
-
defineNonEnumerableSignal(RequestLoadingState.prototype, '_sizeHint', 0);
|
|
8055
|
-
defineNonEnumerableSignal(RequestLoadingState.prototype, '_bytesLoaded', 0);
|
|
8056
|
-
defineNonEnumerableSignal(RequestLoadingState.prototype, '_startTime', 0);
|
|
8057
|
-
defineNonEnumerableSignal(RequestLoadingState.prototype, '_endTime', 0);
|
|
8058
|
-
defineNonEnumerableSignal(RequestLoadingState.prototype, '_lastPacketTime', 0);
|
|
8059
|
-
|
|
8060
|
-
/**
|
|
8061
|
-
* The state of a request in the "pending"
|
|
8062
|
-
* state. This is the default initial state.
|
|
8063
|
-
*
|
|
8064
|
-
* Extends the {@link PendingPromise} interface.
|
|
8065
|
-
*
|
|
8066
|
-
*/
|
|
8067
|
-
|
|
8068
|
-
/**
|
|
8069
|
-
* The state of a request in the "fulfilled" state.
|
|
8070
|
-
* This is the state of a request that has resolved
|
|
8071
|
-
* successfully.
|
|
8072
|
-
*
|
|
8073
|
-
* Extends the {@link ResolvedPromise} interface.
|
|
8074
|
-
*
|
|
8075
|
-
*/
|
|
8076
|
-
|
|
8077
|
-
/**
|
|
8078
|
-
* The state of a request in the "rejected" state.
|
|
8079
|
-
* This is the state of a request that has rejected
|
|
8080
|
-
* with an error.
|
|
8081
|
-
*
|
|
8082
|
-
* Extends the {@link RejectedPromise} interface.
|
|
8083
|
-
*
|
|
8084
|
-
*/
|
|
8085
|
-
|
|
8086
|
-
/**
|
|
8087
|
-
* The state of a request in the "cancelled" state.
|
|
8088
|
-
* This is the state of a promise that has been
|
|
8089
|
-
* cancelled.
|
|
8090
|
-
*
|
|
8091
|
-
*/
|
|
8092
|
-
|
|
8093
|
-
/**
|
|
8094
|
-
* RequestState extends the concept of {@link PromiseState} to provide a reactive
|
|
8095
|
-
* wrapper for a request {@link Future} which allows you write declarative code
|
|
8096
|
-
* around a Future's control flow.
|
|
8097
|
-
*
|
|
8098
|
-
* It is useful in both Template and JavaScript contexts, allowing you
|
|
8099
|
-
* to quickly derive behaviors and data from pending, error and success
|
|
8100
|
-
* states.
|
|
8101
|
-
*
|
|
8102
|
-
* The key difference between a {@link Promise} and a Future is that Futures provide
|
|
8103
|
-
* access to a {@link ReadableStream | stream} of their content, the {@link RequestKey} of the request (if any)
|
|
8104
|
-
* as well as the ability to attempt to {@link Future.abort | abort} the request.
|
|
8105
|
-
*
|
|
8106
|
-
* ```ts
|
|
8107
|
-
* interface Future<T> extends Promise<T>> {
|
|
8108
|
-
* getStream(): Promise<ReadableStream>;
|
|
8109
|
-
* abort(): void;
|
|
8110
|
-
* lid: RequestKey | null;
|
|
8111
|
-
* }
|
|
8112
|
-
* ```
|
|
8113
|
-
*
|
|
8114
|
-
* These additional APIs allow us to craft even richer state experiences.
|
|
8115
|
-
*
|
|
8116
|
-
* To get the state of a request, use {@link getRequestState}.
|
|
8117
|
-
*
|
|
8118
|
-
* See also:
|
|
8119
|
-
* - {@link PendingRequest}
|
|
8120
|
-
* - {@link ResolvedRequest}
|
|
8121
|
-
* - {@link RejectedRequest}
|
|
8122
|
-
* - {@link CancelledRequest}
|
|
8123
|
-
*
|
|
8124
|
-
*/
|
|
8125
|
-
|
|
8126
|
-
const RequestStateProto = {};
|
|
8127
|
-
function performRefresh(requester, request, isReload) {
|
|
8128
|
-
const req = Object.assign({}, request);
|
|
8129
|
-
const cacheOptions = Object.assign({}, req.cacheOptions);
|
|
8130
|
-
if (isReload) {
|
|
8131
|
-
// force direct to network
|
|
8132
|
-
cacheOptions.reload = true;
|
|
8133
|
-
} else if (isReload === false) {
|
|
8134
|
-
// delete reload to ensure we use backgroundReload / policy
|
|
8135
|
-
delete cacheOptions.reload;
|
|
8136
|
-
cacheOptions.backgroundReload = true;
|
|
8137
|
-
} else {
|
|
8138
|
-
// delete props to ensure we use the policy
|
|
8139
|
-
delete cacheOptions.backgroundReload;
|
|
8140
|
-
delete cacheOptions.reload;
|
|
8141
|
-
}
|
|
8142
|
-
req.cacheOptions = cacheOptions;
|
|
8143
|
-
return requester.request(req);
|
|
8144
|
-
}
|
|
8145
|
-
|
|
8146
|
-
// TODO introduce a new mechanism for defining multiple properties
|
|
8147
|
-
// that share a common signal
|
|
8148
|
-
defineSignal(RequestStateProto, 'reason', null);
|
|
8149
|
-
defineSignal(RequestStateProto, 'value', null);
|
|
8150
|
-
defineSignal(RequestStateProto, 'result', null);
|
|
8151
|
-
defineSignal(RequestStateProto, 'error', null);
|
|
8152
|
-
defineSignal(RequestStateProto, 'status', 'pending');
|
|
8153
|
-
defineSignal(RequestStateProto, 'isPending', true);
|
|
8154
|
-
defineSignal(RequestStateProto, 'isLoading', true);
|
|
8155
|
-
defineSignal(RequestStateProto, 'isSuccess', false);
|
|
8156
|
-
defineSignal(RequestStateProto, 'isError', false);
|
|
8157
|
-
defineSignal(RequestStateProto, 'request', null);
|
|
8158
|
-
defineSignal(RequestStateProto, 'response', null);
|
|
8159
|
-
Object.defineProperty(RequestStateProto, 'isCancelled', {
|
|
8160
|
-
get() {
|
|
8161
|
-
return this.isError && isAbortError(this.reason);
|
|
8162
|
-
}
|
|
8163
|
-
});
|
|
8164
|
-
Object.defineProperty(RequestStateProto, 'loadingState', {
|
|
8165
|
-
get() {
|
|
8166
|
-
if (!this._loadingState) {
|
|
8167
|
-
this._loadingState = new RequestLoadingState(this._request);
|
|
8168
|
-
}
|
|
8169
|
-
return this._loadingState;
|
|
8170
|
-
}
|
|
8171
|
-
});
|
|
8172
|
-
function createRequestState(future) {
|
|
8173
|
-
const state = getPromiseResult(future);
|
|
8174
|
-
const promiseState = Object.create(RequestStateProto);
|
|
8175
|
-
promiseState._request = future;
|
|
8176
|
-
// @ts-expect-error - we still attach it for PendingState
|
|
8177
|
-
promiseState.reload = () => {
|
|
8178
|
-
(test => {
|
|
8179
|
-
if (!test) {
|
|
8180
|
-
throw new Error(`Cannot reload a request that is still pending. Await or abort the original request first.`);
|
|
8181
|
-
}
|
|
8182
|
-
})(!promiseState.isPending);
|
|
8183
|
-
return performRefresh(future.requester, promiseState.request, true);
|
|
8184
|
-
};
|
|
8185
|
-
|
|
8186
|
-
// @ts-expect-error - we still attach it for PendingState
|
|
8187
|
-
promiseState.refresh = (usePolicy = false) => {
|
|
8188
|
-
(test => {
|
|
8189
|
-
if (!test) {
|
|
8190
|
-
throw new Error(`Cannot refresh a request that is still pending. Await or abort the original request first.`);
|
|
8191
|
-
}
|
|
8192
|
-
})(!promiseState.isPending);
|
|
8193
|
-
return performRefresh(future.requester, promiseState.request, usePolicy === true ? null : false);
|
|
8194
|
-
};
|
|
8195
|
-
if (state) {
|
|
8196
|
-
if (state.isError) {
|
|
8197
|
-
promiseState.error = state.result;
|
|
8198
|
-
promiseState.reason = state.result;
|
|
8199
|
-
promiseState.status = 'rejected';
|
|
8200
|
-
promiseState.isError = true;
|
|
8201
|
-
promiseState.isPending = false;
|
|
8202
|
-
promiseState.isLoading = false;
|
|
8203
|
-
promiseState.request = state.result.request;
|
|
8204
|
-
promiseState.response = state.result.response;
|
|
8205
|
-
} else {
|
|
8206
|
-
promiseState.result = state.result.content;
|
|
8207
|
-
promiseState.value = state.result.content;
|
|
8208
|
-
promiseState.status = 'fulfilled';
|
|
8209
|
-
promiseState.isSuccess = true;
|
|
8210
|
-
promiseState.isPending = false;
|
|
8211
|
-
promiseState.isLoading = false;
|
|
8212
|
-
promiseState.request = state.result.request;
|
|
8213
|
-
promiseState.response = state.result.response;
|
|
8214
|
-
}
|
|
8215
|
-
} else {
|
|
8216
|
-
void future.then(result => {
|
|
8217
|
-
setPromiseResult(future, {
|
|
8218
|
-
isError: false,
|
|
8219
|
-
result
|
|
8220
|
-
});
|
|
8221
|
-
promiseState.result = result.content;
|
|
8222
|
-
promiseState.value = result.content;
|
|
8223
|
-
promiseState.status = 'fulfilled';
|
|
8224
|
-
promiseState.isSuccess = true;
|
|
8225
|
-
promiseState.isPending = false;
|
|
8226
|
-
promiseState.isLoading = false;
|
|
8227
|
-
promiseState.request = result.request;
|
|
8228
|
-
promiseState.response = result.response;
|
|
8229
|
-
}, error => {
|
|
8230
|
-
setPromiseResult(future, {
|
|
8231
|
-
isError: true,
|
|
8232
|
-
result: error
|
|
8233
|
-
});
|
|
8234
|
-
promiseState.error = error;
|
|
8235
|
-
promiseState.reason = error;
|
|
8236
|
-
promiseState.status = 'rejected';
|
|
8237
|
-
promiseState.isError = true;
|
|
8238
|
-
promiseState.isPending = false;
|
|
8239
|
-
promiseState.isLoading = false;
|
|
8240
|
-
promiseState.request = error.request;
|
|
8241
|
-
promiseState.response = error.response;
|
|
8242
|
-
});
|
|
8243
|
-
}
|
|
8244
|
-
return promiseState;
|
|
8245
|
-
}
|
|
8246
|
-
|
|
8247
|
-
/**
|
|
8248
|
-
* `getRequestState` can be used in both JavaScript and Template contexts.
|
|
8249
|
-
*
|
|
8250
|
-
* ```ts
|
|
8251
|
-
* import { getRequestState } from '@warp-drive/ember';
|
|
8252
|
-
*
|
|
8253
|
-
* const state = getRequestState(future);
|
|
8254
|
-
* ```
|
|
8255
|
-
*
|
|
8256
|
-
* For instance, we could write a getter on a component that updates whenever
|
|
8257
|
-
* the request state advances or the future changes, by combining the function
|
|
8258
|
-
* with the use of `@cached`
|
|
8259
|
-
*
|
|
8260
|
-
* ```ts
|
|
8261
|
-
* class Component {
|
|
8262
|
-
* @cached
|
|
8263
|
-
* get title() {
|
|
8264
|
-
* const state = getRequestState(this.args.request);
|
|
8265
|
-
* if (state.isPending) {
|
|
8266
|
-
* return 'loading...';
|
|
8267
|
-
* }
|
|
8268
|
-
* if (state.isError) { return null; }
|
|
8269
|
-
* return state.result.title;
|
|
8270
|
-
* }
|
|
8271
|
-
* }
|
|
8272
|
-
* ```
|
|
8273
|
-
*
|
|
8274
|
-
* Or in a template as a helper:
|
|
8275
|
-
*
|
|
8276
|
-
* ```gjs
|
|
8277
|
-
* import { getRequestState } from '@warp-drive/ember';
|
|
8278
|
-
*
|
|
8279
|
-
* <template>
|
|
8280
|
-
* {{#let (getRequestState @request) as |state|}}
|
|
8281
|
-
* {{#if state.isPending}}
|
|
8282
|
-
* <Spinner />
|
|
8283
|
-
* {{else if state.isError}}
|
|
8284
|
-
* <ErrorForm @error={{state.error}} />
|
|
8285
|
-
* {{else}}
|
|
8286
|
-
* <h1>{{state.result.title}}</h1>
|
|
8287
|
-
* {{/if}}
|
|
8288
|
-
* {{/let}}
|
|
8289
|
-
* </template>
|
|
8290
|
-
* ```
|
|
8291
|
-
*
|
|
8292
|
-
* If looking to use in a template, consider also the `<Request />` component
|
|
8293
|
-
* which offers a number of additional capabilities for requests *beyond* what
|
|
8294
|
-
* `RequestState` provides.
|
|
8295
|
-
*
|
|
8296
|
-
*/
|
|
8297
|
-
function getRequestState(future) {
|
|
8298
|
-
let state = RequestCache.get(future);
|
|
8299
|
-
if (!state) {
|
|
8300
|
-
state = createRequestState(future);
|
|
8301
|
-
RequestCache.set(future, state);
|
|
8302
|
-
}
|
|
8303
|
-
return state;
|
|
8304
|
-
}
|
|
8305
|
-
function getAliasField(context) {
|
|
8306
|
-
(test => {
|
|
8307
|
-
{
|
|
8308
|
-
throw new Error(`Alias field access is not implemented`);
|
|
8309
|
-
}
|
|
8310
|
-
})();
|
|
8311
|
-
}
|
|
8312
|
-
function setAliasField(context) {
|
|
8313
|
-
(test => {
|
|
8314
|
-
{
|
|
8315
|
-
throw new Error(`Alias field setting is not implemented`);
|
|
8316
|
-
}
|
|
8317
|
-
})();
|
|
8318
|
-
return false;
|
|
8319
|
-
}
|
|
8320
|
-
const ARRAY_GETTER_METHODS = new Set([Symbol.iterator, 'concat', 'entries', 'every', 'fill', 'filter', 'find', 'findIndex', 'flat', 'flatMap', 'forEach', 'includes', 'indexOf', 'join', 'keys', 'lastIndexOf', 'map', 'reduce', 'reduceRight', 'slice', 'some', 'values']);
|
|
8321
|
-
// const ARRAY_SETTER_METHODS = new Set<KeyType>(['push', 'pop', 'unshift', 'shift', 'splice', 'sort']);
|
|
8322
|
-
const SYNC_PROPS = new Set(['[]', 'length']);
|
|
8323
|
-
function isArrayGetter(prop) {
|
|
8324
|
-
return ARRAY_GETTER_METHODS.has(prop);
|
|
8325
|
-
}
|
|
8326
|
-
const ARRAY_SETTER_METHODS = new Set(['push', 'pop', 'unshift', 'shift', 'splice', 'sort']);
|
|
8327
|
-
function isArraySetter(prop) {
|
|
8328
|
-
return ARRAY_SETTER_METHODS.has(prop);
|
|
8329
|
-
}
|
|
8330
|
-
|
|
8331
|
-
// function isSelfProp<T extends object>(self: T, prop: KeyType): prop is keyof T {
|
|
8332
|
-
// return prop in self;
|
|
8333
|
-
// }
|
|
8334
|
-
|
|
8335
|
-
function convertToInt(prop) {
|
|
8336
|
-
if (typeof prop === 'symbol') return null;
|
|
8337
|
-
const num = Number(prop);
|
|
8338
|
-
if (isNaN(num)) return null;
|
|
8339
|
-
return num % 1 === 0 ? num : null;
|
|
8340
|
-
}
|
|
8341
|
-
function safeForEach(instance, arr, store, callback, target) {
|
|
8342
|
-
if (target === undefined) {
|
|
8343
|
-
target = null;
|
|
8344
|
-
}
|
|
8345
|
-
// clone to prevent mutation
|
|
8346
|
-
arr = arr.slice();
|
|
8347
|
-
(test => {
|
|
8348
|
-
if (!test) {
|
|
8349
|
-
throw new Error('`forEach` expects a function as first argument.');
|
|
8350
|
-
}
|
|
8351
|
-
})(typeof callback === 'function');
|
|
8352
|
-
|
|
8353
|
-
// because we retrieveLatest above we need not worry if array is mutated during iteration
|
|
8354
|
-
// by unloadRecord/rollbackAttributes
|
|
8355
|
-
// push/add/removeObject may still be problematic
|
|
8356
|
-
// but this is a more traditionally expected forEach bug.
|
|
8357
|
-
const length = arr.length; // we need to access length to ensure we are consumed
|
|
6752
|
+
// because we retrieveLatest above we need not worry if array is mutated during iteration
|
|
6753
|
+
// by unloadRecord/rollbackAttributes
|
|
6754
|
+
// push/add/removeObject may still be problematic
|
|
6755
|
+
// but this is a more traditionally expected forEach bug.
|
|
6756
|
+
const length = arr.length; // we need to access length to ensure we are consumed
|
|
8358
6757
|
|
|
8359
6758
|
for (let index = 0; index < length; index++) {
|
|
8360
6759
|
callback.call(target, arr[index], index, instance);
|
|
@@ -11061,173 +9460,6 @@ function mergeMap(base, toApply) {
|
|
|
11061
9460
|
base.set(key, value);
|
|
11062
9461
|
}
|
|
11063
9462
|
}
|
|
11064
|
-
const PromiseCache = new WeakMap();
|
|
11065
|
-
|
|
11066
|
-
/**
|
|
11067
|
-
* The state of a promise in the "pending"
|
|
11068
|
-
* state. This is the default initial state.
|
|
11069
|
-
*
|
|
11070
|
-
*/
|
|
11071
|
-
|
|
11072
|
-
/**
|
|
11073
|
-
* The state of a promise in the "fulfilled" state.
|
|
11074
|
-
* This is the state of a promise that has resolved
|
|
11075
|
-
* successfully.
|
|
11076
|
-
*
|
|
11077
|
-
*/
|
|
11078
|
-
|
|
11079
|
-
/**
|
|
11080
|
-
* The state of a promise in the "rejected" state.
|
|
11081
|
-
* This is the state of a promise that has rejected
|
|
11082
|
-
* with an error.
|
|
11083
|
-
*
|
|
11084
|
-
*/
|
|
11085
|
-
|
|
11086
|
-
/**
|
|
11087
|
-
* The state of a promise. This is the type that is returned
|
|
11088
|
-
* from `getPromiseState`.
|
|
11089
|
-
*
|
|
11090
|
-
* See also:
|
|
11091
|
-
* - {@link PendingPromise}
|
|
11092
|
-
* - {@link ResolvedPromise}
|
|
11093
|
-
* - {@link RejectedPromise}
|
|
11094
|
-
*
|
|
11095
|
-
*/
|
|
11096
|
-
|
|
11097
|
-
const PromiseStateProto = {};
|
|
11098
|
-
|
|
11099
|
-
// TODO introduce a new mechanism for defining multiple properties
|
|
11100
|
-
// that share a common signal
|
|
11101
|
-
defineSignal(PromiseStateProto, 'reason', null);
|
|
11102
|
-
defineSignal(PromiseStateProto, 'value', null);
|
|
11103
|
-
defineSignal(PromiseStateProto, 'result', null);
|
|
11104
|
-
defineSignal(PromiseStateProto, 'error', null);
|
|
11105
|
-
defineSignal(PromiseStateProto, 'status', 'pending');
|
|
11106
|
-
defineSignal(PromiseStateProto, 'isPending', true);
|
|
11107
|
-
defineSignal(PromiseStateProto, 'isLoading', true);
|
|
11108
|
-
defineSignal(PromiseStateProto, 'isSuccess', false);
|
|
11109
|
-
defineSignal(PromiseStateProto, 'isError', false);
|
|
11110
|
-
function createPromiseState(promise) {
|
|
11111
|
-
const state = getPromiseResult(promise);
|
|
11112
|
-
const promiseState = Object.create(PromiseStateProto);
|
|
11113
|
-
if (state) {
|
|
11114
|
-
if (state.isError) {
|
|
11115
|
-
promiseState.error = state.result;
|
|
11116
|
-
promiseState.reason = state.result;
|
|
11117
|
-
promiseState.status = 'rejected';
|
|
11118
|
-
promiseState.isError = true;
|
|
11119
|
-
promiseState.isPending = false;
|
|
11120
|
-
promiseState.isLoading = false;
|
|
11121
|
-
} else {
|
|
11122
|
-
promiseState.result = state.result;
|
|
11123
|
-
promiseState.value = state.result;
|
|
11124
|
-
promiseState.status = 'fulfilled';
|
|
11125
|
-
promiseState.isSuccess = true;
|
|
11126
|
-
promiseState.isPending = false;
|
|
11127
|
-
promiseState.isLoading = false;
|
|
11128
|
-
}
|
|
11129
|
-
} else {
|
|
11130
|
-
void promise.then(result => {
|
|
11131
|
-
setPromiseResult(promise, {
|
|
11132
|
-
isError: false,
|
|
11133
|
-
result
|
|
11134
|
-
});
|
|
11135
|
-
promiseState.result = result;
|
|
11136
|
-
promiseState.value = result;
|
|
11137
|
-
promiseState.status = 'fulfilled';
|
|
11138
|
-
promiseState.isSuccess = true;
|
|
11139
|
-
promiseState.isPending = false;
|
|
11140
|
-
promiseState.isLoading = false;
|
|
11141
|
-
}, error => {
|
|
11142
|
-
setPromiseResult(promise, {
|
|
11143
|
-
isError: true,
|
|
11144
|
-
result: error
|
|
11145
|
-
});
|
|
11146
|
-
promiseState.error = error;
|
|
11147
|
-
promiseState.reason = error;
|
|
11148
|
-
promiseState.status = 'rejected';
|
|
11149
|
-
promiseState.isError = true;
|
|
11150
|
-
promiseState.isPending = false;
|
|
11151
|
-
promiseState.isLoading = false;
|
|
11152
|
-
});
|
|
11153
|
-
}
|
|
11154
|
-
return promiseState;
|
|
11155
|
-
}
|
|
11156
|
-
const LegacyPromiseProxy = Symbol.for('LegacyPromiseProxy');
|
|
11157
|
-
function isLegacyAwaitable(promise) {
|
|
11158
|
-
return LegacyPromiseProxy in promise && 'promise' in promise && promise[LegacyPromiseProxy] === true;
|
|
11159
|
-
}
|
|
11160
|
-
function getPromise(promise) {
|
|
11161
|
-
return isLegacyAwaitable(promise) ? promise.promise : promise;
|
|
11162
|
-
}
|
|
11163
|
-
|
|
11164
|
-
/**
|
|
11165
|
-
* Returns a reactive state-machine for the provided promise or awaitable.
|
|
11166
|
-
*
|
|
11167
|
-
* Repeat calls to `getPromiseState` with the same promise will return the same state object
|
|
11168
|
-
* making is safe and easy to use in templates and JavaScript code to produce reactive
|
|
11169
|
-
* behaviors around promises.
|
|
11170
|
-
*
|
|
11171
|
-
* `getPromiseState` can be used in both JavaScript and Template contexts.
|
|
11172
|
-
*
|
|
11173
|
-
* ```ts
|
|
11174
|
-
* import { getPromiseState } from '@warp-drive/ember';
|
|
11175
|
-
*
|
|
11176
|
-
* const state = getPromiseState(promise);
|
|
11177
|
-
* ```
|
|
11178
|
-
*
|
|
11179
|
-
* For instance, we could write a getter on a component that updates whenever
|
|
11180
|
-
* the promise state advances or the promise changes, by combining the function
|
|
11181
|
-
* with the use of `@cached`
|
|
11182
|
-
*
|
|
11183
|
-
* ```ts
|
|
11184
|
-
* class Component {
|
|
11185
|
-
* @cached
|
|
11186
|
-
* get title() {
|
|
11187
|
-
* const state = getPromiseState(this.args.request);
|
|
11188
|
-
* if (state.isPending) {
|
|
11189
|
-
* return 'loading...';
|
|
11190
|
-
* }
|
|
11191
|
-
* if (state.isError) { return null; }
|
|
11192
|
-
* return state.result.title;
|
|
11193
|
-
* }
|
|
11194
|
-
* }
|
|
11195
|
-
* ```
|
|
11196
|
-
*
|
|
11197
|
-
* Or in a template as a helper:
|
|
11198
|
-
*
|
|
11199
|
-
* ```gjs
|
|
11200
|
-
* import { getPromiseState } from '@warp-drive/ember';
|
|
11201
|
-
*
|
|
11202
|
-
* <template>
|
|
11203
|
-
* {{#let (getPromiseState @request) as |state|}}
|
|
11204
|
-
* {{#if state.isPending}} <Spinner />
|
|
11205
|
-
* {{else if state.isError}} <ErrorForm @error={{state.error}} />
|
|
11206
|
-
* {{else}}
|
|
11207
|
-
* <h1>{{state.result.title}}</h1>
|
|
11208
|
-
* {{/if}}
|
|
11209
|
-
* {{/let}}
|
|
11210
|
-
* </template>
|
|
11211
|
-
* ```
|
|
11212
|
-
*
|
|
11213
|
-
* If looking to use in a template, consider also the `<Await />` component.
|
|
11214
|
-
*
|
|
11215
|
-
* See also {@link PromiseState}
|
|
11216
|
-
*/
|
|
11217
|
-
function getPromiseState(promise) {
|
|
11218
|
-
(test => {
|
|
11219
|
-
if (!test) {
|
|
11220
|
-
throw new Error(`getPromiseState expects to be called with a promise: called with ${String(promise)}`);
|
|
11221
|
-
}
|
|
11222
|
-
})(promise);
|
|
11223
|
-
const _promise = getPromise(promise);
|
|
11224
|
-
let state = PromiseCache.get(_promise);
|
|
11225
|
-
if (!state) {
|
|
11226
|
-
state = createPromiseState(_promise);
|
|
11227
|
-
PromiseCache.set(_promise, state);
|
|
11228
|
-
}
|
|
11229
|
-
return state;
|
|
11230
|
-
}
|
|
11231
9463
|
|
|
11232
9464
|
// Lazily close over fetch to avoid breaking Mirage
|
|
11233
9465
|
const _fetch = typeof fetch !== 'undefined' ? (...args) => fetch(...args) : typeof FastBoot !== 'undefined' ? (...args) => FastBoot.require('node-fetch')(...args) : () => {
|
|
@@ -11772,4 +10004,4 @@ function useRecommendedStore(options, StoreKlass = Store) {
|
|
|
11772
10004
|
}
|
|
11773
10005
|
};
|
|
11774
10006
|
}
|
|
11775
|
-
export {
|
|
10007
|
+
export { useRecommendedStore as A, setIdentifierGenerationMethod as B, CacheHandler as C, setIdentifierUpdateMethod as D, setIdentifierForgetMethod as E, Fetch as F, setIdentifierResetMethod as G, setKeyInfoForResource as H, RecordArrayManager as R, Store as S, _clearCaches as _, isRequestKey as a, coerceId as b, constructResource as c, assertPrivateStore as d, ensureStringId as e, fastPush as f, isPrivateStore as g, assertPrivateCapabilities as h, isResourceKey as i, setRecordIdentifier as j, StoreMap as k, createLegacyManyArray as l, log as m, normalizeModelName as n, logGroup as o, checkout as p, instantiateRecord as q, recordIdentifierFor as r, storeFor as s, teardownRecord as t, SchemaService as u, fromIdentity as v, withDefaults as w, registerDerivations as x, commit as y, RequestManager as z };
|