@warp-drive/ember 5.6.0-alpha.14 → 5.6.0-alpha.17

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,81 @@
1
+ import type Owner from "@ember/owner";
2
+ import Component from "@glimmer/component";
3
+ import type { Awaitable } from "@warp-drive/core/request";
4
+ import { type PromiseState } from "@warp-drive/core/store/-private";
5
+ export declare const and: (x: unknown, y: unknown) => boolean;
6
+ interface ThrowSignature<E = Error | string | object> {
7
+ Args: {
8
+ error: E;
9
+ };
10
+ }
11
+ /**
12
+ * The `<Throw />` component is used to throw an error in a template.
13
+ *
14
+ * That's all it does. So don't use it unless the application should
15
+ * throw an error if it reaches this point in the template.
16
+ *
17
+ * ```hbs
18
+ * <Throw @error={{anError}} />
19
+ * ```
20
+ *
21
+ * @class <Throw />
22
+ * @public
23
+ */ export declare class Throw<T> extends Component<ThrowSignature<T>> {
24
+ constructor(owner: Owner, args: ThrowSignature<T>["Args"]);
25
+ }
26
+ interface AwaitSignature<
27
+ T,
28
+ E = Error | string | object
29
+ > {
30
+ Args: {
31
+ promise: Promise<T> | Awaitable<T, E>;
32
+ };
33
+ Blocks: {
34
+ pending: [];
35
+ error: [error: E];
36
+ success: [value: T];
37
+ };
38
+ }
39
+ /**
40
+ * The <Await /> component allow you to utilize reactive control flow
41
+ * for asynchronous states in your application.
42
+ *
43
+ * Await is ideal for handling "boundaries", outside which some state is
44
+ * still allowed to be unresolved and within which it MUST be resolved.
45
+ *
46
+ * ```gjs
47
+ * import { Await } from '@warp-drive/ember';
48
+ *
49
+ * <template>
50
+ * <Await @promise={{@request}}>
51
+ * <:pending>
52
+ * <Spinner />
53
+ * </:pending>
54
+ *
55
+ * <:error as |error|>
56
+ * <ErrorForm @error={{error}} />
57
+ * </:error>
58
+ *
59
+ * <:success as |result|>
60
+ * <h1>{{result.title}}</h1>
61
+ * </:success>
62
+ * </Await>
63
+ * </template>
64
+ * ```
65
+ *
66
+ * The <Await /> component requires that error states are properly handled.
67
+ *
68
+ * If no error block is provided and the promise rejects, the error will
69
+ * be thrown.
70
+ *
71
+ * @class <Await />
72
+ * @public
73
+ */ export declare class Await<
74
+ T,
75
+ E
76
+ > extends Component<AwaitSignature<T, E>> {
77
+ get state(): Readonly<PromiseState<T, E>>;
78
+ get error(): E;
79
+ get result(): T;
80
+ }
81
+ export {};
@@ -0,0 +1,346 @@
1
+ import Component from "@glimmer/component";
2
+ import type { Store, StoreRequestInput } from "@warp-drive/core";
3
+ import type { Future } from "@warp-drive/core/request";
4
+ import type { RequestLoadingState, RequestState, RequestSubscription } from "@warp-drive/core/store/-private";
5
+ import type { StructuredErrorDocument } from "@warp-drive/core/types/request";
6
+ type AutorefreshBehaviorType = "online" | "interval" | "invalid";
7
+ type AutorefreshBehaviorCombos = boolean | AutorefreshBehaviorType | `${AutorefreshBehaviorType},${AutorefreshBehaviorType}` | `${AutorefreshBehaviorType},${AutorefreshBehaviorType},${AutorefreshBehaviorType}`;
8
+ type ContentFeatures<RT> = {
9
+ isOnline: boolean;
10
+ isHidden: boolean;
11
+ isRefreshing: boolean;
12
+ refresh: () => Promise<void>;
13
+ reload: () => Promise<void>;
14
+ abort?: () => void;
15
+ latestRequest?: Future<RT>;
16
+ };
17
+ interface RequestSignature<
18
+ RT,
19
+ T,
20
+ E
21
+ > {
22
+ Args: {
23
+ /**
24
+ * The request to monitor. This should be a `Future` instance returned
25
+ * by either the `store.request` or `store.requestManager.request` methods.
26
+ *
27
+ */ request?: Future<RT>;
28
+ /**
29
+ * A query to use for the request. This should be an object that can be
30
+ * passed to `store.request`. Use this in place of `@request` if you would
31
+ * like the component to also initiate the request.
32
+ *
33
+ */ query?: StoreRequestInput<RT, T>;
34
+ /**
35
+ * The store instance to use for making requests. If contexts are available,
36
+ * the component will default to using the `store` on the context.
37
+ *
38
+ * This is required if the store is not available via context or should be
39
+ * different from the store provided via context.
40
+ *
41
+ */ store?: Store;
42
+ /**
43
+ * The autorefresh behavior for the request. This can be a boolean, or any
44
+ * combination of the following values: `'online'`, `'interval'`, `'invalid'`.
45
+ *
46
+ * - `'online'`: Refresh the request when the browser comes back online
47
+ * - `'interval'`: Refresh the request at a specified interval
48
+ * - `'invalid'`: Refresh the request when the store emits an invalidation
49
+ *
50
+ * If `true`, this is equivalent to `'online,invalid'`.
51
+ *
52
+ * Defaults to `false`.
53
+ *
54
+ */ autorefresh?: AutorefreshBehaviorCombos;
55
+ /**
56
+ * The number of milliseconds to wait before refreshing the request when the
57
+ * browser comes back online or the network becomes available.
58
+ *
59
+ * This also controls the interval at which the request will be refreshed if
60
+ * the `interval` autorefresh type is enabled.
61
+ *
62
+ * Defaults to `30_000` (30 seconds).
63
+ *
64
+ */ autorefreshThreshold?: number;
65
+ /**
66
+ * The behavior of the request initiated by autorefresh. This can be one of
67
+ * the following values:
68
+ *
69
+ * - `'refresh'`: Refresh the request in the background
70
+ * - `'reload'`: Force a reload of the request
71
+ * - `'policy'` (**default**): Let the store's configured CachePolicy decide whether to
72
+ * reload, refresh, or do nothing.
73
+ *
74
+ * Defaults to `'policy'`.
75
+ *
76
+ */ autorefreshBehavior?: "refresh" | "reload" | "policy";
77
+ };
78
+ Blocks: {
79
+ /**
80
+ * The block to render when the component is idle and waiting to be given a request.
81
+ *
82
+ */ idle: [];
83
+ /**
84
+ * The block to render when the request is loading.
85
+ *
86
+ */ loading: [state: RequestLoadingState];
87
+ /**
88
+ * The block to render when the request was cancelled.
89
+ *
90
+ */ cancelled: [error: StructuredErrorDocument<E>, features: {
91
+ isOnline: boolean;
92
+ isHidden: boolean;
93
+ retry: () => Promise<void>;
94
+ }];
95
+ /**
96
+ * The block to render when the request failed. If this block is not provided,
97
+ * the error will be rethrown.
98
+ *
99
+ * Thus it is required to provide an error block and proper error handling if
100
+ * you do not want the error to crash the application.
101
+ *
102
+ */ error: [error: StructuredErrorDocument<E>, features: {
103
+ isOnline: boolean;
104
+ isHidden: boolean;
105
+ retry: () => Promise<void>;
106
+ }];
107
+ /**
108
+ * The block to render when the request succeeded.
109
+ *
110
+ */ content: [value: RT, features: ContentFeatures<RT>];
111
+ always: [state: RequestState<RT, T, StructuredErrorDocument<E>>];
112
+ };
113
+ }
114
+ /**
115
+ * The `<Request />` component is a powerful tool for managing data fetching and
116
+ * state in your Ember application. It provides a declarative approach to reactive
117
+ * control-flow for managing requests and state in your application.
118
+ *
119
+ * The `<Request />` component is ideal for handling "boundaries", outside which some
120
+ * state is still allowed to be unresolved and within which it MUST be resolved.
121
+ *
122
+ * ## Request States
123
+ *
124
+ * `<Request />` has five states, only one of which will be active and rendered at a time.
125
+ *
126
+ * - `idle`: The component is waiting to be given a request to monitor
127
+ * - `loading`: The request is in progress
128
+ * - `error`: The request failed
129
+ * - `content`: The request succeeded
130
+ * - `cancelled`: The request was cancelled
131
+ *
132
+ * Additionally, the `content` state has a `refresh` method that can be used to
133
+ * refresh the request in the background, which is available as a sub-state of
134
+ * the `content` state.
135
+ *
136
+ * As with the `<Await />` component, if no error block is provided and the request
137
+ * rejects, the error will be thrown. Cancellation errors are swallowed instead of
138
+ * rethrown if no error block or cancellation block is present.
139
+ *
140
+ * ```gts
141
+ * import { Request } from '@warp-drive/ember';
142
+ *
143
+ * <template>
144
+ * <Request @request={{@request}}>
145
+ * <:loading as |state|>
146
+ * <Spinner @percentDone={{state.completedRatio}} />
147
+ * <button {{on "click" state.abort}}>Cancel</button>
148
+ * </:loading>
149
+ *
150
+ * <:error as |error state|>
151
+ * <ErrorForm @error={{error}} />
152
+ * <button {{on "click" state.retry}}>Retry</button>
153
+ * </:error>
154
+ *
155
+ * <:content as |data state|>
156
+ * <h1>{{data.title}}</h1>
157
+ * {{#if state.isBackgroundReloading}}
158
+ * <SmallSpinner />
159
+ * <button {{on "click" state.abort}}>Cancel</button>
160
+ * {{else}}
161
+ * <button {{on "click" state.refresh}}>Refresh</button>
162
+ * {{/if}}
163
+ * </:content>
164
+ *
165
+ * <:cancelled as |error state|>
166
+ * <h2>The Request was cancelled</h2>
167
+ * <button {{on "click" state.retry}}>Retry</button>
168
+ * </:cancelled>
169
+ *
170
+ * <:idle>
171
+ * <button {{on "click" @kickOffRequest}}>Load Preview?</button>
172
+ * </:idle>
173
+ *
174
+ * </Request>
175
+ * </template>
176
+ * ```
177
+ *
178
+ * ## Streaming Data
179
+ *
180
+ * The loading state exposes the download `ReadableStream` instance for consumption
181
+ *
182
+ * ```gjs
183
+ * import { Request } from '@warp-drive/ember';
184
+ *
185
+ * <template>
186
+ * <Request @request={{@request}}>
187
+ * <:loading as |state|>
188
+ * <Video @stream={{state.stream}} />
189
+ * </:loading>
190
+ *
191
+ * <:error as |error|>
192
+ * <ErrorForm @error={{error}} />
193
+ * </:error>
194
+ * </Request>
195
+ * </template>
196
+ * ```
197
+ *
198
+ * ## Retry
199
+ *
200
+ * Cancelled and error'd requests may be retried by calling the `retry` method.
201
+ *
202
+ * Retry will restart the state progression, using the loading, error, cancelled,
203
+ * and content blocks as appropriate.
204
+ *
205
+ * ## Reloading
206
+ *
207
+ * The `reload` method will force the request to be fully re-executed, bypassing
208
+ * cache and restarting the state progression through the loading, error, and
209
+ * content blocks as appropriate.
210
+ *
211
+ * Background reload (refresh) is a special substate of the content state that
212
+ * allows you to refresh the request in the background. This is useful for when
213
+ * you want to update the data in the background without blocking the UI.
214
+ *
215
+ * Reload and refresh are available as methods on the `content` state.
216
+ *
217
+ * ```gjs
218
+ * import { Request } from '@warp-drive/ember';
219
+ *
220
+ * <template>
221
+ * <Request @request={{@request}}>
222
+ * <:content as |data state|>
223
+ * <h1>{{data.title}}</h1>
224
+ * {{#if state.isBackgroundReloading}}
225
+ * <SmallSpinner />
226
+ * <button {{on "click" state.abort}}>Cancel</button>
227
+ * {{/if}}
228
+ *
229
+ * <button {{on "click" state.refresh}}>Refresh</button>
230
+ * <button {{on "click" state.reload}}>Reload</button>
231
+ * </:content>
232
+ * </Request>
233
+ * </template>
234
+ * ```
235
+ *
236
+ * ## Advanced Reloading
237
+ *
238
+ * We can nest our usage of `<Request />` to handle more advanced
239
+ * reloading scenarios.
240
+ *
241
+ * ```gjs
242
+ * import { Request } from '@warp-drive/ember';
243
+ *
244
+ * <template>
245
+ * <Request @request={{@request}}>
246
+ * <:cancelled>
247
+ * <h2>The Request Cancelled</h2>
248
+ * </:cancelled>
249
+ *
250
+ * <:error as |error|>
251
+ * <ErrorForm @error={{error}} />
252
+ * </:error>
253
+ *
254
+ * <:content as |result state|>
255
+ * <Request @request={{state.latestRequest}}>
256
+ * <!-- Handle Background Request -->
257
+ * </Request>
258
+ *
259
+ * <h1>{{result.title}}</h1>
260
+ *
261
+ * <button {{on "click" state.refresh}}>Refresh</button>
262
+ * </:content>
263
+ * </Request>
264
+ * </template>
265
+ * ```
266
+ *
267
+ * ## Autorefresh
268
+ *
269
+ * `<Request />` supports automatic refresh and reload under certain conditions.
270
+ *
271
+ * - `online`: This occurs when a browser window or tab comes back to the foreground
272
+ * after being backgrounded or when the network reports as being online after
273
+ * having been offline.
274
+ * - `interval`: This occurs when a specified amount of time has passed.
275
+ * - `invalid`: This occurs when the store emits a notification that the request
276
+ * has become invalid.
277
+ *
278
+ * You can specify when autorefresh should occur by setting the `autorefresh` arg
279
+ * to `true` or a comma-separated list of the above values.
280
+ *
281
+ * A value of `true` is equivalent to `'online,invalid'`.
282
+ *
283
+ * By default, an autorefresh will only occur if the browser was backgrounded or
284
+ * offline for more than 30s before coming back available. This amount of time can
285
+ * be tweaked by setting the number of milliseconds via `@autorefreshThreshold`.
286
+ *
287
+ * This arg also controls the interval at which the request will be refreshed
288
+ * if the `interval` autorefresh type is enabled.
289
+ *
290
+ * Finally, the behavior of the request initiated by autorefresh can be adjusted
291
+ * by setting the `autorefreshBehavior` arg to `'refresh'`, `'reload'`, or `'policy'`.
292
+ *
293
+ * - `'refresh'`: Refresh the request in the background
294
+ * - `'reload'`: Force a reload of the request
295
+ * - `'policy'` (**default**): Let the store's configured CachePolicy decide whether to
296
+ * reload, refresh, or do nothing.
297
+ *
298
+ * More advanced refresh and reload behaviors can be created by passing the reload and
299
+ * refresh actions into another component. For instance, refresh could be set up on a
300
+ * timer or on a websocket subscription.
301
+ *
302
+ *
303
+ * ```gjs
304
+ * import { Request } from '@warp-drive/ember';
305
+ *
306
+ * <template>
307
+ * <Request @request={{@request}}>
308
+ * <:content as |result state|>
309
+ * <h1>{{result.title}}</h1>
310
+ *
311
+ * <Interval @period={{30_000}} @fn={{state.refresh}} />
312
+ * <Subscribe @channel={{@someValue}} @fn={{state.refresh}} />
313
+ * </:content>
314
+ * </Request>
315
+ * </template>
316
+ * ```
317
+ *
318
+ * If a matching request is refreshed or reloaded by any other component,
319
+ * the `Request` component will react accordingly.
320
+ *
321
+ * ## Deduping
322
+ *
323
+ * The store dedupes requests by identity. If a request is made for the same identity
324
+ * from multiple `<Request />` components, even if the request is not referentially the
325
+ * same, only one actual request will be made.
326
+ *
327
+ *
328
+ * @class <Request />
329
+ * @public
330
+ */ export declare class Request<
331
+ RT,
332
+ T,
333
+ E
334
+ > extends Component<RequestSignature<RT, T, E>> {
335
+ /**
336
+ * The store instance to use for making requests. If contexts are available, this
337
+ * will be the `store` on the context, else it will be the store service.
338
+ *
339
+ * @internal
340
+ */ _store: Store;
341
+ get store(): Store;
342
+ _state: RequestSubscription<RT, T, E> | null;
343
+ get state(): RequestSubscription<RT, T, E>;
344
+ willDestroy(): void;
345
+ }
346
+ export {};