@memoized-dom/data 0.0.1
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/README.md +591 -0
- package/dist/action.d.ts +44 -0
- package/dist/action.d.ts.map +1 -0
- package/dist/chunks/chunk-2CT6VOBD.js +1 -0
- package/dist/client.d.ts +4 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/errors.d.ts +21 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1 -0
- package/dist/internal.d.ts +5 -0
- package/dist/internal.d.ts.map +1 -0
- package/dist/internal.js +1 -0
- package/dist/notifications.d.ts +14 -0
- package/dist/notifications.d.ts.map +1 -0
- package/dist/optimistic.d.ts +9 -0
- package/dist/optimistic.d.ts.map +1 -0
- package/dist/request.d.ts +9 -0
- package/dist/request.d.ts.map +1 -0
- package/dist/resource.d.ts +81 -0
- package/dist/resource.d.ts.map +1 -0
- package/dist/schema.d.ts +3 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/types.d.ts +130 -0
- package/dist/types.d.ts.map +1 -0
- package/package.json +30 -0
package/README.md
ADDED
|
@@ -0,0 +1,591 @@
|
|
|
1
|
+
# `@memoized-dom/data`
|
|
2
|
+
|
|
3
|
+
Browser-first fetch resources and callable actions for memoized-dom.
|
|
4
|
+
|
|
5
|
+
> **Current scope:** the package is usable in ordinary JavaScript and in
|
|
6
|
+
> compiled memoized-dom components. The compiler treats imported resource and
|
|
7
|
+
> action values like other opaque third-party state: while their getters are
|
|
8
|
+
> rendered, it rereads them through the existing volatile frame fallback. No
|
|
9
|
+
> `$fetch`-specific compiler adapter or method allowlist is involved.
|
|
10
|
+
|
|
11
|
+
## Public API
|
|
12
|
+
|
|
13
|
+
The package exposes a default runtime plus an isolated-runtime factory:
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
import {
|
|
17
|
+
$action,
|
|
18
|
+
$fetch,
|
|
19
|
+
clearDataRuntime,
|
|
20
|
+
createDataRuntime,
|
|
21
|
+
RequestError,
|
|
22
|
+
} from '@memoized-dom/data';
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
- `$fetch` automatically performs a read request and returns a stable resource.
|
|
26
|
+
- `$action` creates a lazy callable operation for writes.
|
|
27
|
+
- `createDataRuntime` creates an isolated request, cache, and action boundary.
|
|
28
|
+
- `clearDataRuntime` clears active work and retained state in the default runtime.
|
|
29
|
+
- `RequestError` describes network, HTTP, decoding, and validation failures.
|
|
30
|
+
|
|
31
|
+
There is no provider, hook, or mutable global configuration API.
|
|
32
|
+
|
|
33
|
+
### Isolated runtimes
|
|
34
|
+
|
|
35
|
+
Use a separate runtime for each server request, test, tenant, or other ownership
|
|
36
|
+
boundary that must not share request state:
|
|
37
|
+
|
|
38
|
+
```ts
|
|
39
|
+
const data = createDataRuntime({
|
|
40
|
+
baseURL: 'https://api.example.test/',
|
|
41
|
+
fetch: customFetch,
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
const users = data.$fetch<User[]>('users');
|
|
45
|
+
data.clear();
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
`baseURL` resolves relative targets and `fetch` injects a compatible fetch
|
|
49
|
+
implementation. In a browser, the default base URL is `location.href`. A
|
|
50
|
+
non-browser runtime must provide `baseURL` when it uses relative targets.
|
|
51
|
+
|
|
52
|
+
`clear()` aborts active reads and actions, resets their visible pending state,
|
|
53
|
+
detaches live read resources, and drops retained request data. Existing resource
|
|
54
|
+
and action objects remain valid; a detached resource can be refreshed to start
|
|
55
|
+
new work. `clearDataRuntime()` performs the same operation on the exported
|
|
56
|
+
default `$fetch` and `$action` runtime.
|
|
57
|
+
|
|
58
|
+
### Component ownership
|
|
59
|
+
|
|
60
|
+
A runtime created inside a component should be cleared with the component:
|
|
61
|
+
|
|
62
|
+
```tsx
|
|
63
|
+
function Users() {
|
|
64
|
+
const data = createDataRuntime();
|
|
65
|
+
const users = data.$fetch<User[]>('/api/users');
|
|
66
|
+
cleanup(data.clear);
|
|
67
|
+
|
|
68
|
+
return <p>{users.pending ? 'Loading' : users.data?.length}</p>;
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Memoized-dom component factories run once, so this does not recreate the
|
|
73
|
+
runtime on every update. `cleanup(data.clear)` aborts component-owned reads and
|
|
74
|
+
actions when the component is removed. When using the default runtime, a
|
|
75
|
+
component can instead own one resource with `cleanup(users.abort)`.
|
|
76
|
+
|
|
77
|
+
Cleanup is explicit today because ordinary third-party libraries remain usable
|
|
78
|
+
without implementing a memoized-dom lifecycle interface.
|
|
79
|
+
|
|
80
|
+
## `$fetch`
|
|
81
|
+
|
|
82
|
+
### Basic request
|
|
83
|
+
|
|
84
|
+
```ts
|
|
85
|
+
interface User {
|
|
86
|
+
id: string;
|
|
87
|
+
name: string;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const users = $fetch<User[]>('/api/users');
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
The request starts automatically. `$fetch<User[]>()` tells TypeScript that a
|
|
94
|
+
successful decoded response is expected to be `User[]`.
|
|
95
|
+
|
|
96
|
+
The generic is a developer assertion. It does not validate the server response
|
|
97
|
+
at runtime. Optional runtime validation is explained later.
|
|
98
|
+
|
|
99
|
+
### Resource state
|
|
100
|
+
|
|
101
|
+
```ts
|
|
102
|
+
users.data; // User[] | undefined
|
|
103
|
+
users.error; // RequestError | null
|
|
104
|
+
users.status; // 'idle' | 'pending' | 'success' | 'error'
|
|
105
|
+
users.pending; // boolean
|
|
106
|
+
users.refreshing; // boolean
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
The initial cold request has this state:
|
|
110
|
+
|
|
111
|
+
```ts
|
|
112
|
+
users.status === 'pending';
|
|
113
|
+
users.pending === true;
|
|
114
|
+
users.refreshing === false;
|
|
115
|
+
users.data === undefined;
|
|
116
|
+
users.error === null;
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
After success:
|
|
120
|
+
|
|
121
|
+
```ts
|
|
122
|
+
users.status === 'success';
|
|
123
|
+
users.pending === false;
|
|
124
|
+
users.data !== undefined;
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
After an initial failure:
|
|
128
|
+
|
|
129
|
+
```ts
|
|
130
|
+
users.status === 'error';
|
|
131
|
+
users.pending === false;
|
|
132
|
+
users.data === undefined;
|
|
133
|
+
users.error instanceof RequestError;
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
During a refresh, previous data remains available:
|
|
137
|
+
|
|
138
|
+
```ts
|
|
139
|
+
users.status === 'success';
|
|
140
|
+
users.pending === true;
|
|
141
|
+
users.refreshing === true;
|
|
142
|
+
users.data; // previous successful data
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
A failed refresh preserves previous data. `status` remains `success`, and
|
|
146
|
+
`error` contains the refresh failure so the application may display a
|
|
147
|
+
non-blocking warning.
|
|
148
|
+
|
|
149
|
+
### Query parameters
|
|
150
|
+
|
|
151
|
+
```ts
|
|
152
|
+
const users = $fetch<User[]>('/api/users', {
|
|
153
|
+
query: {
|
|
154
|
+
search: 'Ada',
|
|
155
|
+
page: 2,
|
|
156
|
+
active: true,
|
|
157
|
+
tag: ['compiler', 'typescript'],
|
|
158
|
+
},
|
|
159
|
+
});
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Query values may be strings, numbers, booleans, `null`, arrays of those values,
|
|
163
|
+
or `undefined`. An `undefined` value is omitted. Arrays produce repeated query
|
|
164
|
+
fields. Query keys are normalized so equivalent requests share the same
|
|
165
|
+
identity regardless of object property order. URL fragments are removed because
|
|
166
|
+
they are not sent in HTTP requests and must not split request identity.
|
|
167
|
+
|
|
168
|
+
### Request headers
|
|
169
|
+
|
|
170
|
+
```ts
|
|
171
|
+
const profile = $fetch<Profile>('/api/profile', {
|
|
172
|
+
headers: {
|
|
173
|
+
Authorization: `Bearer ${token}`,
|
|
174
|
+
},
|
|
175
|
+
});
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
Headers participate in automatic request identity. Requests with different
|
|
179
|
+
authorization values therefore do not share data by default. Headers are copied
|
|
180
|
+
when the resource is created, so later mutation of a supplied `Headers` object
|
|
181
|
+
cannot make request execution disagree with its identity.
|
|
182
|
+
|
|
183
|
+
### Paused resource
|
|
184
|
+
|
|
185
|
+
`null` is the only paused target:
|
|
186
|
+
|
|
187
|
+
```ts
|
|
188
|
+
const user = $fetch<User>(
|
|
189
|
+
userId ? `/api/users/${userId}` : null,
|
|
190
|
+
);
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
A paused resource has `status: 'idle'` and performs no request. Automatic
|
|
194
|
+
reevaluation when `userId` changes is a deferred request-argument optimization;
|
|
195
|
+
the current call captures only the value passed at creation.
|
|
196
|
+
|
|
197
|
+
When request arguments change today, replace the component-local resource
|
|
198
|
+
explicitly and release the previous one:
|
|
199
|
+
|
|
200
|
+
```tsx
|
|
201
|
+
let users = loadUsers(search);
|
|
202
|
+
|
|
203
|
+
function setSearch(next: string) {
|
|
204
|
+
search = next;
|
|
205
|
+
const previous = users;
|
|
206
|
+
users = loadUsers(search);
|
|
207
|
+
previous.abort();
|
|
208
|
+
}
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
Because `users` is ordinary component `let` state, the existing compiler
|
|
212
|
+
updates its consumers. This is explicit resource ownership, not `$fetch`
|
|
213
|
+
recognition.
|
|
214
|
+
|
|
215
|
+
### Manual refresh
|
|
216
|
+
|
|
217
|
+
```ts
|
|
218
|
+
const latestUsers = await users.refresh();
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
`refresh()` always performs a new request and resolves with its decoded result.
|
|
222
|
+
Existing data remains visible while it runs.
|
|
223
|
+
|
|
224
|
+
### Abort
|
|
225
|
+
|
|
226
|
+
```ts
|
|
227
|
+
users.abort();
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
Aborting detaches this resource from its active shared request. If it was the
|
|
231
|
+
last consumer, the underlying request is aborted. If another resource still
|
|
232
|
+
uses that request, the request continues for the other resource.
|
|
233
|
+
|
|
234
|
+
Cancellation is not stored as `resource.error`.
|
|
235
|
+
|
|
236
|
+
Cancellation is also a client-side settlement boundary. Even when an injected
|
|
237
|
+
fetch implementation ignores `AbortSignal`, an aborted resource or action will
|
|
238
|
+
not accept its late result.
|
|
239
|
+
|
|
240
|
+
### Replacing data
|
|
241
|
+
|
|
242
|
+
`update()` requires the callback to return the new top-level value:
|
|
243
|
+
|
|
244
|
+
```ts
|
|
245
|
+
users.update(current => [
|
|
246
|
+
...(current ?? []),
|
|
247
|
+
newUser,
|
|
248
|
+
]);
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
### Direct mutation
|
|
252
|
+
|
|
253
|
+
`mutate()` ignores the callback's result and preserves the existing top-level
|
|
254
|
+
value:
|
|
255
|
+
|
|
256
|
+
```ts
|
|
257
|
+
users.mutate(current => {
|
|
258
|
+
current?.push(newUser);
|
|
259
|
+
});
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
These are deliberately separate. `Array.push()` returns a number, so an API
|
|
263
|
+
that treats callback returns as optional replacements could accidentally store
|
|
264
|
+
that number instead of the array.
|
|
265
|
+
|
|
266
|
+
Use `mutate()` for direct in-place changes and `update()` when a replacement is
|
|
267
|
+
required.
|
|
268
|
+
|
|
269
|
+
Both operations supersede a read that was already in flight. The older request
|
|
270
|
+
is aborted, and its result is ignored even when an injected fetch implementation
|
|
271
|
+
does not cooperate with `AbortSignal`. This prevents a stale server snapshot
|
|
272
|
+
from overwriting a newer local or optimistic write.
|
|
273
|
+
|
|
274
|
+
## Resource sharing
|
|
275
|
+
|
|
276
|
+
The default sharing mode is active sharing:
|
|
277
|
+
|
|
278
|
+
```ts
|
|
279
|
+
const first = $fetch<User[]>('/api/users');
|
|
280
|
+
const second = $fetch<User[]>('/api/users');
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
When both declarations describe the same normalized request:
|
|
284
|
+
|
|
285
|
+
1. The first resource starts the request.
|
|
286
|
+
2. The second resource joins that request instead of sending another one.
|
|
287
|
+
3. Both resources observe the same decoded value.
|
|
288
|
+
4. A third resource created while either remains active receives that value
|
|
289
|
+
immediately without another request.
|
|
290
|
+
5. After the final resource is disposed by the future integration layer, the
|
|
291
|
+
entry is removed.
|
|
292
|
+
6. A later resource performs a new request.
|
|
293
|
+
|
|
294
|
+
The identity includes the normalized URL, query, headers, and validator. An
|
|
295
|
+
explicit key can replace automatic identity when necessary:
|
|
296
|
+
|
|
297
|
+
```ts
|
|
298
|
+
const profile = $fetch<Profile>('/api/profile', {
|
|
299
|
+
key: ['profile', accountId],
|
|
300
|
+
});
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
### Sharing options
|
|
304
|
+
|
|
305
|
+
The current package implements only three clear modes:
|
|
306
|
+
|
|
307
|
+
```ts
|
|
308
|
+
// Default: share while at least one resource is active.
|
|
309
|
+
$fetch<User[]>('/api/users');
|
|
310
|
+
|
|
311
|
+
// Private: never share this resource's request or result.
|
|
312
|
+
$fetch<User[]>('/api/users', {
|
|
313
|
+
cache: false,
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
// Retain for this package instance until its internal store is cleared.
|
|
317
|
+
$fetch<User[]>('/api/users', {
|
|
318
|
+
cache: { scope: 'app' },
|
|
319
|
+
});
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
No freshness or retention duration is implemented in version `0.0.1`. Timing
|
|
323
|
+
options remain a design discussion and are not part of the package API.
|
|
324
|
+
|
|
325
|
+
This sharing store is separate from the browser HTTP cache, service workers,
|
|
326
|
+
and server `Cache-Control` headers.
|
|
327
|
+
|
|
328
|
+
## Optional response validation
|
|
329
|
+
|
|
330
|
+
This short form trusts the developer's generic assertion:
|
|
331
|
+
|
|
332
|
+
```ts
|
|
333
|
+
const users = $fetch<User[]>('/api/users');
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
For an external or untrusted API, a Standard Schema validator can infer and
|
|
337
|
+
check the decoded response:
|
|
338
|
+
|
|
339
|
+
```ts
|
|
340
|
+
const UserSchema = z.object({
|
|
341
|
+
id: z.string(),
|
|
342
|
+
name: z.string(),
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
const users = $fetch('/external/users', {
|
|
346
|
+
validate: z.array(UserSchema),
|
|
347
|
+
});
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
Here `users.data` is inferred as `User[] | undefined`. If the response does not
|
|
351
|
+
match the schema, invalid data is not stored and `users.error.kind` is
|
|
352
|
+
`'validation'`.
|
|
353
|
+
|
|
354
|
+
`validate` is optional. It does not replace the generic form and is not required
|
|
355
|
+
for application-owned endpoints.
|
|
356
|
+
|
|
357
|
+
## Destructuring
|
|
358
|
+
|
|
359
|
+
In the standalone package, normal JavaScript destructuring is a snapshot:
|
|
360
|
+
|
|
361
|
+
```ts
|
|
362
|
+
const { data, pending } = users;
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
Those two variables do not change by themselves because this package does not
|
|
366
|
+
rewrite JavaScript. The current compiler's opaque frame fallback also cannot
|
|
367
|
+
replay a value that was copied out once. Keep the resource object when values
|
|
368
|
+
must be read later:
|
|
369
|
+
|
|
370
|
+
```tsx
|
|
371
|
+
const users = $fetch<User[]>('/api/users');
|
|
372
|
+
|
|
373
|
+
function render() {
|
|
374
|
+
return users.pending ? 'Loading' : users.data;
|
|
375
|
+
}
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
Direct resource getters used by JSX are reread while the component is mounted.
|
|
379
|
+
Live destructuring could be added later, but it is not required for `$fetch` to
|
|
380
|
+
render correctly and must not depend on package or method names.
|
|
381
|
+
|
|
382
|
+
Methods are bound functions and are safe to extract:
|
|
383
|
+
|
|
384
|
+
```ts
|
|
385
|
+
const { refresh } = users;
|
|
386
|
+
await refresh();
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
## `$action`
|
|
390
|
+
|
|
391
|
+
### Creating and invoking an action
|
|
392
|
+
|
|
393
|
+
```ts
|
|
394
|
+
interface Todo {
|
|
395
|
+
id: string;
|
|
396
|
+
title: string;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
interface CreateTodo {
|
|
400
|
+
title: string;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
const createTodo = $action<Todo, CreateTodo>('/api/todos', {
|
|
404
|
+
method: 'POST',
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
const created = await createTodo({
|
|
408
|
+
title: 'Write documentation',
|
|
409
|
+
});
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
Creating the action sends no request. Calling it performs one invocation and
|
|
413
|
+
returns that invocation's promise.
|
|
414
|
+
|
|
415
|
+
Plain object and array inputs are encoded as JSON. Strings, `FormData`, blobs,
|
|
416
|
+
URL search parameters, array buffers, and other supported native request bodies
|
|
417
|
+
are passed through without JSON conversion.
|
|
418
|
+
|
|
419
|
+
The default method is `POST`. Supported methods are `POST`, `PUT`, `PATCH`, and
|
|
420
|
+
`DELETE`.
|
|
421
|
+
|
|
422
|
+
### Action state
|
|
423
|
+
|
|
424
|
+
```ts
|
|
425
|
+
createTodo.data; // Todo | undefined
|
|
426
|
+
createTodo.error; // RequestError | null
|
|
427
|
+
createTodo.status; // 'idle' | 'pending' | 'success' | 'error'
|
|
428
|
+
createTodo.pending; // boolean
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
Every invocation receives its own promise. The initial implementation permits
|
|
432
|
+
parallel calls. Visible `data`, `error`, and `status` belong to the most recently
|
|
433
|
+
started invocation; an older request settling late cannot overwrite newer
|
|
434
|
+
visible state.
|
|
435
|
+
|
|
436
|
+
```ts
|
|
437
|
+
createTodo.abort();
|
|
438
|
+
createTodo.reset();
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
`abort()` stops active client requests. It cannot guarantee that a server did
|
|
442
|
+
not already process a mutation. `reset()` aborts active work and returns visible
|
|
443
|
+
state to `idle`. Late results from fetch implementations that ignore abort are
|
|
444
|
+
discarded. With parallel calls, aborting one invocation does not allow it to
|
|
445
|
+
overwrite the state of a newer invocation.
|
|
446
|
+
|
|
447
|
+
### Success and error callbacks
|
|
448
|
+
|
|
449
|
+
```ts
|
|
450
|
+
const createTodo = $action<Todo, CreateTodo>('/api/todos', {
|
|
451
|
+
onSuccess(created, input) {
|
|
452
|
+
console.log('Created', created.id, 'from', input.title);
|
|
453
|
+
},
|
|
454
|
+
|
|
455
|
+
onError(error, input) {
|
|
456
|
+
console.error('Could not create', input.title, error);
|
|
457
|
+
},
|
|
458
|
+
});
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
Normal `try`/`catch` around the returned invocation promise remains valid and
|
|
462
|
+
does not require callbacks.
|
|
463
|
+
|
|
464
|
+
## Optimistic collection changes
|
|
465
|
+
|
|
466
|
+
An array resource exposes three typed change constructors:
|
|
467
|
+
|
|
468
|
+
```ts
|
|
469
|
+
todos.append(temporary);
|
|
470
|
+
todos.replace(current, temporary);
|
|
471
|
+
todos.remove(current);
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
They apply immediately and return an opaque optimistic change consumed by an
|
|
475
|
+
action invocation. Each change is single-use; passing the same change to a
|
|
476
|
+
second invocation throws instead of committing or rolling it back twice.
|
|
477
|
+
|
|
478
|
+
### Create
|
|
479
|
+
|
|
480
|
+
```ts
|
|
481
|
+
const created = await createTodo(input, {
|
|
482
|
+
optimistic: todos.append(temporary),
|
|
483
|
+
});
|
|
484
|
+
```
|
|
485
|
+
|
|
486
|
+
- `temporary` appears immediately.
|
|
487
|
+
- Failure removes only that temporary item.
|
|
488
|
+
- Success replaces that exact item with `created`, the action result.
|
|
489
|
+
- The list is not fetched again.
|
|
490
|
+
|
|
491
|
+
### Update
|
|
492
|
+
|
|
493
|
+
```ts
|
|
494
|
+
const saved = await updateTodo(input, {
|
|
495
|
+
optimistic: todos.replace(existing, optimisticVersion),
|
|
496
|
+
});
|
|
497
|
+
```
|
|
498
|
+
|
|
499
|
+
- `existing` is replaced immediately.
|
|
500
|
+
- Failure restores `existing`.
|
|
501
|
+
- Success installs `saved` in place of `optimisticVersion`.
|
|
502
|
+
|
|
503
|
+
`existing` should be the actual object reference obtained from `todos.data`.
|
|
504
|
+
|
|
505
|
+
### Delete
|
|
506
|
+
|
|
507
|
+
```ts
|
|
508
|
+
await deleteTodo(existing.id, {
|
|
509
|
+
optimistic: todos.remove<void>(existing),
|
|
510
|
+
});
|
|
511
|
+
```
|
|
512
|
+
|
|
513
|
+
- `existing` is removed immediately.
|
|
514
|
+
- Failure reinserts it at its previous position.
|
|
515
|
+
- Success keeps it removed.
|
|
516
|
+
|
|
517
|
+
If `existing` is not present, `replace()` and `remove()` return safe no-op
|
|
518
|
+
changes. Duplicate object references are handled one occurrence at a time.
|
|
519
|
+
|
|
520
|
+
Rollback operations target their own temporary/current item instead of
|
|
521
|
+
restoring a complete old array. A failed older action therefore does not erase
|
|
522
|
+
unrelated later additions.
|
|
523
|
+
|
|
524
|
+
## Optional related-resource refresh
|
|
525
|
+
|
|
526
|
+
Creating an item normally returns that item, so the optimistic list should
|
|
527
|
+
commit from the result rather than refetch itself:
|
|
528
|
+
|
|
529
|
+
```ts
|
|
530
|
+
await createTodo(input, {
|
|
531
|
+
optimistic: todos.append(temporary),
|
|
532
|
+
});
|
|
533
|
+
```
|
|
534
|
+
|
|
535
|
+
Refresh is only for another resource whose authoritative value cannot be
|
|
536
|
+
derived from the returned item:
|
|
537
|
+
|
|
538
|
+
```ts
|
|
539
|
+
await createTodo(input, {
|
|
540
|
+
optimistic: todos.append(temporary),
|
|
541
|
+
refresh: [todoStatistics],
|
|
542
|
+
});
|
|
543
|
+
```
|
|
544
|
+
|
|
545
|
+
The action result reconciles `todos`. Only `todoStatistics` is requested again.
|
|
546
|
+
Refresh requests start after the action succeeds and do not delay the action's
|
|
547
|
+
returned result.
|
|
548
|
+
|
|
549
|
+
## Errors
|
|
550
|
+
|
|
551
|
+
```ts
|
|
552
|
+
class RequestError<TData = unknown> extends Error {
|
|
553
|
+
readonly kind: 'network' | 'http' | 'decode' | 'validation';
|
|
554
|
+
readonly status: number | null;
|
|
555
|
+
readonly statusText: string | null;
|
|
556
|
+
readonly data: TData | undefined;
|
|
557
|
+
readonly issues: readonly StandardSchemaIssue[] | undefined;
|
|
558
|
+
}
|
|
559
|
+
```
|
|
560
|
+
|
|
561
|
+
Automatic `$fetch` requests store failures in `resource.error` without causing
|
|
562
|
+
an unhandled rejection. Awaited `refresh()` and action calls reject normally.
|
|
563
|
+
|
|
564
|
+
## Compiler behavior and optional future optimization
|
|
565
|
+
|
|
566
|
+
The current compiler needs no data-specific integration. An imported resource
|
|
567
|
+
whose getters participate in rendered output is an opaque value, so its owner
|
|
568
|
+
is marked volatile and reevaluated once per visible animation frame. This also
|
|
569
|
+
supports structural output such as loading branches and
|
|
570
|
+
`resource.data?.map(...)` lists. Polling stops when the owner is unmounted.
|
|
571
|
+
|
|
572
|
+
This is the same compatibility path used for animation engines, external
|
|
573
|
+
stores, and other third-party objects. Those libraries do not need to implement
|
|
574
|
+
a framework interface.
|
|
575
|
+
|
|
576
|
+
The package also exposes subscribe, immutable-snapshot, and dispose hooks from
|
|
577
|
+
`@memoized-dom/data/internal`. Generated code does not use them today. They are
|
|
578
|
+
available if measurements later justify an optional push optimization:
|
|
579
|
+
|
|
580
|
+
- notify only when resource/action state changes instead of pulling per frame;
|
|
581
|
+
- provide more precise invalidation;
|
|
582
|
+
- automate resource ownership and cleanup;
|
|
583
|
+
- recreate a resource when compiled request arguments change.
|
|
584
|
+
|
|
585
|
+
That optimization must preserve the opaque fallback. It must not make a
|
|
586
|
+
special interface mandatory for third-party libraries, recognize `$fetch` by
|
|
587
|
+
name, or approve mutation methods from a list. Direct writes to derived values
|
|
588
|
+
remain illegal; opaque receiver calls retain ordinary JavaScript semantics.
|
|
589
|
+
|
|
590
|
+
The complete evolving design and deferred server behavior live in the root
|
|
591
|
+
`data-loading-api.md` document.
|
package/dist/action.d.ts
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { SnapshotNotifier } from './notifications';
|
|
2
|
+
import type { FetchEnvironment } from './resource';
|
|
3
|
+
import type { Action, ActionListener, ActionOptions, ActionSnapshot } from './types';
|
|
4
|
+
interface MutableActionSnapshot<T> {
|
|
5
|
+
data: T | undefined;
|
|
6
|
+
error: import('./errors').RequestError | null;
|
|
7
|
+
status: ActionSnapshot<T>['status'];
|
|
8
|
+
pending: boolean;
|
|
9
|
+
}
|
|
10
|
+
interface ActionInvocation {
|
|
11
|
+
readonly abortController: AbortController;
|
|
12
|
+
readonly sequence: number;
|
|
13
|
+
cancelled: boolean;
|
|
14
|
+
}
|
|
15
|
+
declare class ActionController<T> {
|
|
16
|
+
readonly store: ActionStore;
|
|
17
|
+
readonly invocations: Set<ActionInvocation>;
|
|
18
|
+
readonly notifier: SnapshotNotifier<ActionSnapshot<T>>;
|
|
19
|
+
snapshot: MutableActionSnapshot<T>;
|
|
20
|
+
sequence: number;
|
|
21
|
+
disposed: boolean;
|
|
22
|
+
hasData: boolean;
|
|
23
|
+
constructor(store: ActionStore);
|
|
24
|
+
begin(invocation: ActionInvocation): void;
|
|
25
|
+
isVisible(invocation: ActionInvocation): boolean;
|
|
26
|
+
succeed(invocation: ActionInvocation, result: T): void;
|
|
27
|
+
fail(invocation: ActionInvocation, error: import('./errors').RequestError): void;
|
|
28
|
+
cancelInvocation(invocation: ActionInvocation, reason?: unknown): void;
|
|
29
|
+
finish(invocation: ActionInvocation): void;
|
|
30
|
+
abort(reset: boolean): void;
|
|
31
|
+
dispose(): void;
|
|
32
|
+
}
|
|
33
|
+
export declare class ActionStore {
|
|
34
|
+
private readonly active;
|
|
35
|
+
track(controller: ActionController<unknown>): void;
|
|
36
|
+
untrack(controller: ActionController<unknown>): void;
|
|
37
|
+
clear(): void;
|
|
38
|
+
}
|
|
39
|
+
export declare function createAction<TResult, TInput>(environment: FetchEnvironment, store: ActionStore, target: string | URL, options: ActionOptions<TResult, TInput>): Action<TResult, TInput>;
|
|
40
|
+
export declare function subscribeAction<T, TInput>(action: Action<T, TInput>, listener: ActionListener<T>): () => void;
|
|
41
|
+
export declare function actionSnapshot<T, TInput>(action: Action<T, TInput>): ActionSnapshot<T>;
|
|
42
|
+
export declare function disposeAction<T, TInput>(action: Action<T, TInput>): void;
|
|
43
|
+
export {};
|
|
44
|
+
//# sourceMappingURL=action.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"action.d.ts","sourceRoot":"","sources":["../src/action.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AASnD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,KAAK,EACV,MAAM,EAEN,cAAc,EACd,aAAa,EACb,cAAc,EACf,MAAM,SAAS,CAAC;AAEjB,UAAU,qBAAqB,CAAC,CAAC;IAC/B,IAAI,EAAE,CAAC,GAAG,SAAS,CAAC;IACpB,KAAK,EAAE,OAAO,UAAU,EAAE,YAAY,GAAG,IAAI,CAAC;IAC9C,MAAM,EAAE,cAAc,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;IACpC,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,UAAU,gBAAgB;IACxB,QAAQ,CAAC,eAAe,EAAE,eAAe,CAAC;IAC1C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,SAAS,EAAE,OAAO,CAAC;CACpB;AAMD,cAAM,gBAAgB,CAAC,CAAC;IAaV,QAAQ,CAAC,KAAK,EAAE,WAAW;IAZvC,QAAQ,CAAC,WAAW,wBAA+B;IACnD,QAAQ,CAAC,QAAQ,sCAAuD;IACxE,QAAQ,EAAE,qBAAqB,CAAC,CAAC,CAAC,CAKhC;IACF,QAAQ,SAAK;IACb,QAAQ,UAAS;IACjB,OAAO,UAAS;gBAEK,KAAK,EAAE,WAAW;IAEvC,KAAK,CAAC,UAAU,EAAE,gBAAgB,GAAG,IAAI;IAWzC,SAAS,CAAC,UAAU,EAAE,gBAAgB,GAAG,OAAO;IAIhD,OAAO,CAAC,UAAU,EAAE,gBAAgB,EAAE,MAAM,EAAE,CAAC,GAAG,IAAI;IAStD,IAAI,CACF,UAAU,EAAE,gBAAgB,EAC5B,KAAK,EAAE,OAAO,UAAU,EAAE,YAAY,GACrC,IAAI;IAOP,gBAAgB,CAAC,UAAU,EAAE,gBAAgB,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,IAAI;IAiBtE,MAAM,CAAC,UAAU,EAAE,gBAAgB,GAAG,IAAI;IAY1C,KAAK,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI;IAkB3B,OAAO,IAAI,IAAI;CAOhB;AAED,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAwC;IAE/D,KAAK,CAAC,UAAU,EAAE,gBAAgB,CAAC,OAAO,CAAC,GAAG,IAAI;IAIlD,OAAO,CAAC,UAAU,EAAE,gBAAgB,CAAC,OAAO,CAAC,GAAG,IAAI;IAIpD,KAAK,IAAI,IAAI;CAGd;AAaD,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAC1C,WAAW,EAAE,gBAAgB,EAC7B,KAAK,EAAE,WAAW,EAClB,MAAM,EAAE,MAAM,GAAG,GAAG,EACpB,OAAO,EAAE,aAAa,CAAC,OAAO,EAAE,MAAM,CAAC,GACtC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,CA+GzB;AAUD,wBAAgB,eAAe,CAAC,CAAC,EAAE,MAAM,EACvC,MAAM,EAAE,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC,EACzB,QAAQ,EAAE,cAAc,CAAC,CAAC,CAAC,GAC1B,MAAM,IAAI,CAIZ;AAED,wBAAgB,cAAc,CAAC,CAAC,EAAE,MAAM,EACtC,MAAM,EAAE,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC,GACxB,cAAc,CAAC,CAAC,CAAC,CAInB;AAED,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,EACrC,MAAM,EAAE,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC,GACxB,IAAI,CAEN"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var h=class extends Error{kind;status;statusText;data;issues;constructor(e,n){super(e,{cause:n.cause}),this.name="RequestError",this.kind=n.kind,this.status=n.status??null,this.statusText=n.statusText??null,this.data=n.data,this.issues=n.issues}};function T(t){return(t instanceof DOMException||t instanceof Error)&&t.name==="AbortError"}function v(t){return t instanceof h?t:new h(t instanceof Error?t.message:"Network request failed",{kind:"network",cause:t})}function ne(t){if(t.length===0)return;let e=t.length===1?t[0]:new AggregateError(t,"Data runtime listeners failed"),n=globalThis.reportError;try{n?.(e)}catch{}}var g=class{constructor(e){this.current=e}current;listeners=new Set;emitting=!1;pending=!1;notify(){if(this.emitting){this.pending=!0;return}this.emitting=!0;let e=[];try{do{this.pending=!1;let n=this.current();for(let s of[...this.listeners])if(this.listeners.has(s)){try{s(n)}catch(r){e.push(r)}if(this.pending)break}}while(this.pending)}finally{this.emitting=!1}ne(e)}subscribe(e){this.listeners.add(e);try{e(this.current())}catch(n){throw this.listeners.delete(e),n}return()=>this.listeners.delete(e)}clear(){this.listeners.clear()}};var F=new WeakMap;function b(t){let e=Object.freeze({kind:"memoized-dom.optimistic-change"});return F.set(e,t),e}function U(t){let e=F.get(t);if(e===void 0)throw new TypeError("Invalid optimistic change. Use append(), replace(), or remove() on a fetch resource.");return F.delete(t),e}async function j(t,e){let n=await t["~standard"].validate(e);if(n.issues!==void 0)throw new h("Response validation failed",{kind:"validation",issues:n.issues,data:e});return n.value}var P=new WeakMap,se=1;function re(t){if(t===void 0)return"none";let e=P.get(t);return e===void 0&&(e=se++,P.set(t,e)),String(e)}function oe(t,e){let n=t.indexOf("#"),s=n===-1?t:t.slice(0,n),r=s.indexOf("?"),o=r===-1?s:s.slice(0,r),i=new URLSearchParams(r===-1?"":s.slice(r+1));if(e!==void 0)for(let c of Object.keys(e).sort()){let u=e[c];if(u!==void 0)if(i.delete(c),Array.isArray(u))for(let f of u)i.append(c,String(f));else i.append(c,String(u))}i.sort();let a=i.toString();return`${o}${a===""?"":`?${a}`}`}function R(t,e,n){let s=t instanceof URL?t.href:t,r=n===void 0?s:new URL(s,n).href;return oe(r,e)}function ie(t){return[...new Headers(t).entries()].sort(([n],[s])=>n.localeCompare(s)).map(([n,s])=>`${encodeURIComponent(n)}=${encodeURIComponent(s)}`).join("&")}function ae(t){return(typeof t=="string"?[t]:t).map(n=>`${typeof n}:${encodeURIComponent(String(n))}`).join("|")}function V(t,e,n,s){return n!==void 0?`explicit|${ae(n)}`:`GET|${t}|${ie(e)}|schema:${re(s)}`}async function k(t,e){let n;try{t.status===204||t.status===205?n=void 0:n=(t.headers.get("content-type")?.toLowerCase()??"").includes("json")?await t.json():await t.text()}catch(s){throw T(s)?s:t.ok?new h("Failed to decode response",{kind:"decode",status:t.status,statusText:t.statusText,cause:s}):new h(`Request failed with status ${t.status}`,{kind:"http",status:t.status,statusText:t.statusText,cause:s})}if(!t.ok)throw new h(`Request failed with status ${t.status}`,{kind:"http",status:t.status,statusText:t.statusText,data:n});return e===void 0?n:j(e,n)}function l(t){return t.reason??new DOMException("The operation was aborted","AbortError")}function m(t,e){return e.aborted?Promise.reject(l(e)):new Promise((n,s)=>{let r=()=>s(l(e));e.addEventListener("abort",r,{once:!0}),Promise.resolve().then(t).then(n,s).finally(()=>{e.removeEventListener("abort",r)})})}function M(t,e){if(t!==void 0)return typeof t=="string"||t instanceof Blob||t instanceof FormData||t instanceof URLSearchParams||t instanceof ArrayBuffer||ArrayBuffer.isView(t)?t:(e.has("content-type")||e.set("content-type","application/json"),JSON.stringify(t))}function H(t){return Object.freeze({...t})}var I=class{constructor(e){this.store=e}store;invocations=new Set;notifier=new g(()=>H(this.snapshot));snapshot={data:void 0,error:null,status:"idle",pending:!1};sequence=0;disposed=!1;hasData=!1;begin(e){this.invocations.size===0&&this.store.track(this),this.invocations.add(e),this.snapshot.error=null,this.snapshot.status="pending",this.snapshot.pending=!0,this.notifier.notify()}isVisible(e){return!e.cancelled&&e.sequence===this.sequence}succeed(e,n){this.isVisible(e)&&(this.snapshot.data=n,this.snapshot.error=null,this.snapshot.status="success",this.hasData=!0,this.notifier.notify())}fail(e,n){this.isVisible(e)&&(this.snapshot.error=n,this.snapshot.status="error",this.notifier.notify())}cancelInvocation(e,n){if(e.cancelled)return;let s=this.isVisible(e);e.cancelled=!0,e.abortController.abort(n),s&&(this.sequence++,this.snapshot.error=null,this.snapshot.status=this.hasData?"success":"idle");let r=[...this.invocations].some(o=>!o.cancelled);(s||this.snapshot.pending!==r)&&(this.snapshot.pending=r,this.notifier.notify())}finish(e){this.invocations.delete(e),this.invocations.size===0&&this.store.untrack(this);let n=[...this.invocations].some(s=>!s.cancelled);this.snapshot.pending!==n&&(this.snapshot.pending=n,this.notifier.notify())}abort(e){this.sequence++;for(let n of this.invocations)n.cancelled=!0,n.abortController.abort();this.snapshot.error=null,this.snapshot.pending=!1,e?(this.snapshot.data=void 0,this.snapshot.status="idle",this.hasData=!1):this.snapshot.status=this.hasData?"success":"idle",this.notifier.notify()}dispose(){this.disposed||(this.abort(!0),this.disposed=!0,this.notifier.clear(),this.store.untrack(this))}},S=class{active=new Set;track(e){this.active.add(e)}untrack(e){this.active.delete(e)}clear(){for(let e of[...this.active])e.abort(!0)}},$=new WeakMap;function ce(t,e){return t===void 0?()=>{}:(t.addEventListener("abort",e,{once:!0}),()=>t.removeEventListener("abort",e))}function z(t,e,n,s){let r=new I(e),o=R(n,s.query,t.baseURL),a=async(c,u={})=>{let f=u.optimistic===void 0?void 0:U(u.optimistic);if(r.disposed)throw f?.rollback(),new Error("Cannot invoke a disposed action");if(u.signal?.aborted)throw f?.rollback(),l(u.signal);let d={sequence:++r.sequence,abortController:new AbortController,cancelled:!1};r.begin(d);let _=ce(u.signal,()=>r.cancelInvocation(d,l(u.signal))),x=!1;try{let p=new Headers(s.headers),y=M(c,p),ee=await m(()=>t.fetch()(o,{method:s.method??"POST",headers:p,body:y,signal:d.abortController.signal}),d.abortController.signal),w=await m(()=>k(ee,s.validate),d.abortController.signal);if(d.cancelled)throw l(d.abortController.signal);if(f?.commit(w),x=!0,r.succeed(d,w),await s.onSuccess?.(w,c),d.cancelled)throw l(d.abortController.signal);for(let te of u.refresh??[])te.refresh().catch(()=>{});return w}catch(p){if(x||f?.rollback(),d.cancelled||T(p))throw r.cancelInvocation(d),p;if(x)throw p;let y=v(p);r.fail(d,y);try{await s.onError?.(y,c)}catch{}throw y}finally{_(),r.finish(d)}};return Object.defineProperties(a,{data:{get:()=>r.snapshot.data},error:{get:()=>r.snapshot.error},status:{get:()=>r.snapshot.status},pending:{get:()=>r.snapshot.pending}}),a.abort=()=>{if(r.disposed)throw new Error("Cannot abort a disposed action");r.abort(!1)},a.reset=()=>{if(r.disposed)throw new Error("Cannot reset a disposed action");r.abort(!0)},$.set(a,r),a}function O(t){let e=$.get(t);if(e===void 0)throw new TypeError("Value is not an action from @memoized-dom/data");return e}function Se(t,e){let n=O(t);if(n.disposed)throw new Error("Cannot subscribe to a disposed action");return n.notifier.subscribe(e)}function Ce(t){return H(O(t).snapshot)}function Ee(t){O(t).dispose()}var q=()=>({data:void 0,error:null,status:"idle",pending:!1,refreshing:!1});function Q(t){return Object.freeze({...t})}function B(t){return t??"active"}var C=class{constructor(e,n){this.store=e;this.descriptor=n;this.cache=n.cache===!1?"active":n.cache}store;descriptor;consumers=new Set;snapshot=q();hasData=!1;cache;request=null;controller=null;generation=0;add(e){this.consumers.add(e),e.receive(this,this.snapshot)}remove(e,n){this.consumers.delete(e),this.consumers.size===0&&(this.cache==="active"?this.store.delete(this,n):this.cancelRequest(n))}cancelRequest(e){this.controller===null&&this.request===null||(this.generation++,this.controller?.abort(e),this.controller=null,this.request=null,this.snapshot.error=null,this.snapshot.pending=!1,this.snapshot.refreshing=!1,this.snapshot.status=this.hasData?"success":"idle")}upgradeCache(e){typeof e=="object"&&(this.cache=e)}emit(){for(let e of this.consumers)e.receive(this,this.snapshot)}update(e){let n=this.snapshot.data;this.snapshot.data=e(n),this.snapshot.error=null,this.snapshot.status="success",this.hasData=!0,this.emit()}mutate(e){let n=this.snapshot.data;e(n),this.snapshot.data=n,this.snapshot.error=null,this.snapshot.status="success",this.hasData=!0,this.emit()}start(e=!1){if(this.request!==null)return this.request;if(!e&&this.hasData)return Promise.resolve(this.snapshot.data);let n=++this.generation,s=new AbortController;this.controller=s,this.snapshot.error=null,this.snapshot.pending=!0,this.snapshot.refreshing=this.hasData,this.snapshot.status=this.hasData?"success":"pending",this.emit();let r=m(()=>this.store.environment.fetch()(this.descriptor.url,{method:"GET",headers:this.descriptor.headers,signal:s.signal}),s.signal).then(o=>m(()=>k(o,this.descriptor.schema),s.signal)).then(o=>(n!==this.generation||(this.snapshot={data:o,error:null,status:"success",pending:!1,refreshing:!1},this.hasData=!0,this.emit()),o),o=>{throw n!==this.generation?o:s.signal.aborted||T(o)?(this.snapshot.pending=!1,this.snapshot.refreshing=!1,this.snapshot.status=this.hasData?"success":"idle",this.emit(),o):(this.snapshot.error=v(o),this.snapshot.pending=!1,this.snapshot.refreshing=!1,this.snapshot.status=this.hasData?"success":"error",this.emit(),this.snapshot.error)}).finally(()=>{n===this.generation&&(this.request=null,this.controller=null)});return this.request=r,r.catch(()=>{}),r}dispose(e=!1,n){this.cancelRequest(n);for(let s of[...this.consumers])s.detachFrom(this,e);this.consumers.clear()}},E=class{constructor(e){this.environment=e}environment;entries=new Map;allEntries=new Set;acquire(e,n,s=!1){let r;if(e.cache===!1)r=new C(this,e),this.allEntries.add(r);else{let i=this.entries.get(e.identity);i===void 0?(r=new C(this,e),this.allEntries.add(r)):r=i,this.entries.set(e.identity,r),r.upgradeCache(e.cache)}return r.add(n),(s||r.snapshot.status==="idle"||r.snapshot.status==="error")&&r.start(s).catch(()=>{}),r}delete(e,n){this.entries.get(e.descriptor.identity)===e&&this.entries.delete(e.descriptor.identity),this.allEntries.delete(e),e.dispose(!1,n)}clear(){for(let e of[...this.allEntries])e.dispose(!0);this.entries.clear(),this.allEntries.clear()}},A=class{constructor(e,n,s=!1){this.store=e;this.descriptor=n;this.paused=s;let r=n.signal;if(r!==void 0){let o=()=>this.abort(l(r));if(r.aborted)return;r.addEventListener("abort",o,{once:!0}),this.removeSignalListener=()=>r.removeEventListener("abort",o)}s||this.attach(!1)}store;descriptor;paused;snapshot=q();entry=null;disposed=!1;removeSignalListener=null;notifier=new g(()=>Q(this.snapshot));attach(e){if(this.disposed)throw new Error("Cannot refresh a disposed fetch resource");this.entry=this.store.acquire(this.descriptor,this,e)}receive(e,n){this.entry!==null&&this.entry!==e||(this.snapshot={...n},this.notify())}detachFrom(e,n=!1){this.entry===e&&(this.entry=null,n&&(this.snapshot=q(),this.notify()))}notify(){this.notifier.notify()}refresh(){if(this.disposed)return Promise.reject(new Error("Cannot refresh a disposed fetch resource"));if(this.paused)return Promise.reject(new TypeError("Cannot refresh a fetch resource with a null target"));let e=this.descriptor.signal;if(e?.aborted)return Promise.reject(l(e));this.entry===null&&this.attach(!0);let n=this.entry.start(!0);return e===void 0?n:m(()=>n,e)}abort(e){if(this.disposed)throw new Error("Cannot abort a disposed fetch resource");this.detach(!0,e)}detach(e,n){let s=this.entry;s!==null&&(this.entry=null,s.remove(this,n)),this.snapshot.pending=!1,this.snapshot.refreshing=!1,this.snapshot.status=this.snapshot.status==="success"?"success":"idle",this.snapshot.error=null,e&&this.notify()}update(e){if(this.disposed)throw new Error("Cannot update a disposed fetch resource");if(this.entry===null){let n=this.snapshot.data;this.snapshot.data=e(n),this.snapshot.status="success",this.snapshot.error=null,this.notify();return}this.entry.update(e)}mutate(e){if(this.disposed)throw new Error("Cannot mutate a disposed fetch resource");if(this.entry===null){e(this.snapshot.data),this.snapshot.status="success",this.snapshot.error=null,this.notify();return}this.entry.mutate(e)}dispose(){this.disposed||(this.detach(!1),this.disposed=!0,this.removeSignalListener?.(),this.removeSignalListener=null,this.notifier.clear())}},G=new WeakMap;function L(t){return Array.isArray(t.snapshot.data)?t.snapshot.data:[]}var K=new WeakMap;function J(t){let e=K.get(t);return e===void 0&&(e=new Set,K.set(t,e)),e}function X(t,e,n){if(Object.is(t[e.index],n))return e.index;let s=-1;for(let r=0;r<t.length;r++)if(Object.is(t[r],n)){if(s!==-1)return-1;s=r}return s}function W(t,e,n,s,r){n.outcome=s,n.result=r;let o=e.base;for(let a of e.steps)a.outcome==="pending"?o=a.temporary:a.outcome==="committed"&&(o=a.result);let i=e.visible;e.visible=o,Object.is(i,o)||t.update(a=>{let c=[...a??[]],u=X(c,e,i);return u!==-1&&(c[u]=o),c}),e.steps.every(a=>a.outcome!=="pending")&&J(t).delete(e)}function ue(t,e){let n=L(t).length;return t.update(s=>[...s??[],e]),b({rollback(){t.update(s=>{let r=[...s??[]],o=r[n]===e?n:r.lastIndexOf(e);return o!==-1&&r.splice(o,1),r})},commit(s){t.update(r=>{let o=[...r??[]],i=o[n]===e?n:o.lastIndexOf(e);return i!==-1&&(o[i]=s),o})}})}function de(t,e,n){let s=L(t),r=s.indexOf(e);if(r===-1)return b({rollback(){},commit(){}});let o=J(t),i=[...o].find(c=>Object.is(c.visible,e)&&X(s,c,e)===r);i===void 0&&(i={index:r,base:e,visible:e,steps:[]},o.add(i));let a={temporary:n,outcome:"pending"};return i.steps.push(a),i.visible=n,t.update(c=>(c??[]).map((u,f)=>f===r?n:u)),b({rollback(){W(t,i,a,"rolled-back")},commit(c){W(t,i,a,"committed",c)}})}function he(t,e){let n=L(t).indexOf(e);return n===-1?b({rollback(){},commit(){}}):(t.update(s=>{let r=[...s??[]];return r[n]===e&&r.splice(n,1),r}),b({rollback(){t.update(s=>{let r=[...s??[]];return r.splice(Math.min(n,r.length),0,e),r})},commit(){}}))}function Y(t,e,n,s){if(n===null)return N(new A(t,{url:"",headers:s.headers,identity:"paused",cache:B(s.cache),schema:s.validate,signal:s.signal},!0));let r=R(n,s.query,e.baseURL),o=new Headers(s.headers),i={url:r,headers:o,identity:V(r,o,s.key,s.validate),cache:B(s.cache),schema:s.validate,signal:s.signal};return N(new A(t,i))}function N(t){let e=t,n={get data(){return t.snapshot.data},get error(){return t.snapshot.error},get status(){return t.snapshot.status},get pending(){return t.snapshot.pending},get refreshing(){return t.snapshot.refreshing},refresh:()=>t.refresh(),abort:()=>t.abort(),update:s=>t.update(s),mutate:s=>t.mutate(s),append:s=>ue(e,s),replace:(s,r)=>de(e,s,r),remove:s=>he(e,s)};return G.set(n,t),n}function D(t){let e=G.get(t);if(e===void 0)throw new TypeError("Value is not a fetch resource from @memoized-dom/data");return e}function qe(t,e){let n=D(t);if(n.disposed)throw new Error("Cannot subscribe to a disposed fetch resource");return n.notifier.subscribe(e)}function Le(t){D(t).dispose()}function De(t){return Q(D(t).snapshot)}function Z(t,e){return{baseURL:e??(typeof location>"u"?void 0:location.href),fetch(){let s=t??globalThis.fetch;if(s===void 0)throw new Error("No fetch implementation is available");return s}}}function Ve(t={}){let e=Z(t.fetch,t.baseURL),n=new E(e),s=new S;return{$fetch:((i,a={})=>Y(n,e,i,a)),$action:((i,a={})=>z(e,s,i,a)),clear(){s.clear(),n.clear()}}}export{h as a,Se as b,Ce as c,Ee as d,qe as e,Le as f,De as g,Ve as h};
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAGV,WAAW,EACX,kBAAkB,EAInB,MAAM,SAAS,CAAC;AAEjB,kEAAkE;AAClE,wBAAgB,iBAAiB,CAC/B,OAAO,GAAE,kBAAuB,GAC/B,WAAW,CAmCb"}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { StandardSchemaIssue } from './types';
|
|
2
|
+
export type RequestErrorKind = 'network' | 'http' | 'decode' | 'validation';
|
|
3
|
+
export interface RequestErrorOptions<TData> {
|
|
4
|
+
readonly kind: RequestErrorKind;
|
|
5
|
+
readonly status?: number | null;
|
|
6
|
+
readonly statusText?: string | null;
|
|
7
|
+
readonly data?: TData;
|
|
8
|
+
readonly issues?: readonly StandardSchemaIssue[];
|
|
9
|
+
readonly cause?: unknown;
|
|
10
|
+
}
|
|
11
|
+
export declare class RequestError<TData = unknown> extends Error {
|
|
12
|
+
readonly kind: RequestErrorKind;
|
|
13
|
+
readonly status: number | null;
|
|
14
|
+
readonly statusText: string | null;
|
|
15
|
+
readonly data: TData | undefined;
|
|
16
|
+
readonly issues: readonly StandardSchemaIssue[] | undefined;
|
|
17
|
+
constructor(message: string, options: RequestErrorOptions<TData>);
|
|
18
|
+
}
|
|
19
|
+
export declare function isAbortError(error: unknown): boolean;
|
|
20
|
+
export declare function toRequestError(error: unknown): RequestError;
|
|
21
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAEnD,MAAM,MAAM,gBAAgB,GACxB,SAAS,GACT,MAAM,GACN,QAAQ,GACR,YAAY,CAAC;AAEjB,MAAM,WAAW,mBAAmB,CAAC,KAAK;IACxC,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC;IAChC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,QAAQ,CAAC,IAAI,CAAC,EAAE,KAAK,CAAC;IACtB,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,mBAAmB,EAAE,CAAC;IACjD,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,qBAAa,YAAY,CAAC,KAAK,GAAG,OAAO,CAAE,SAAQ,KAAK;IACtD,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC;IAChC,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,QAAQ,CAAC,IAAI,EAAE,KAAK,GAAG,SAAS,CAAC;IACjC,QAAQ,CAAC,MAAM,EAAE,SAAS,mBAAmB,EAAE,GAAG,SAAS,CAAC;gBAEhD,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,mBAAmB,CAAC,KAAK,CAAC;CASjE;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAMpD;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,YAAY,CAM3D"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { createDataRuntime } from './client';
|
|
2
|
+
export declare const $fetch: import("./types").FetchFunction;
|
|
3
|
+
export declare const $action: import("./types").ActionFunction;
|
|
4
|
+
export declare const clearDataRuntime: () => void;
|
|
5
|
+
export { RequestError } from './errors';
|
|
6
|
+
export type { Action, ActionCallOptions, ActionFunction, ActionMethod, ActionOptions, AppCacheOptions, AsyncStatus, DataRuntime, DataRuntimeOptions, FetchCache, FetchCollectionChanges, FetchFunction, FetchOptions, FetchResource, FetchResourceCore, InferSchemaOutput, OptimisticChange, Query, QueryPrimitive, QueryValue, RequestKey, RequestKeyPart, StandardSchemaIssue, StandardSchemaResult, StandardSchemaV1, ValidatedFetchOptions, } from './types';
|
|
7
|
+
export type { RequestErrorKind, RequestErrorOptions } from './errors';
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAC7C,eAAO,MAAM,MAAM,iCAAwB,CAAC;AAC5C,eAAO,MAAM,OAAO,kCAAyB,CAAC;AAC9C,eAAO,MAAM,gBAAgB,YAAuB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAExC,YAAY,EACV,MAAM,EACN,iBAAiB,EACjB,cAAc,EACd,YAAY,EACZ,aAAa,EACb,eAAe,EACf,WAAW,EACX,WAAW,EACX,kBAAkB,EAClB,UAAU,EACV,sBAAsB,EACtB,aAAa,EACb,YAAY,EACZ,aAAa,EACb,iBAAiB,EACjB,iBAAiB,EACjB,gBAAgB,EAChB,KAAK,EACL,cAAc,EACd,UAAU,EACV,UAAU,EACV,cAAc,EACd,mBAAmB,EACnB,oBAAoB,EACpB,gBAAgB,EAChB,qBAAqB,GACtB,MAAM,SAAS,CAAC;AACjB,YAAY,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{a as o,h as t}from"./chunks/chunk-2CT6VOBD.js";var e=t(),a=e.$fetch,c=e.$action,n=e.clear;export{c as $action,a as $fetch,o as RequestError,n as clearDataRuntime,t as createDataRuntime};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { createDataRuntime } from './client';
|
|
2
|
+
export { actionSnapshot, disposeAction, subscribeAction, } from './action';
|
|
3
|
+
export { disposeFetchResource, fetchResourceSnapshot, subscribeFetchResource, } from './resource';
|
|
4
|
+
export type { ActionListener, ActionSnapshot, DataRuntime, DataRuntimeOptions, ResourceListener, ResourceSnapshot, } from './types';
|
|
5
|
+
//# sourceMappingURL=internal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"internal.d.ts","sourceRoot":"","sources":["../src/internal.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAC7C,OAAO,EACL,cAAc,EACd,aAAa,EACb,eAAe,GAChB,MAAM,UAAU,CAAC;AAClB,OAAO,EACL,oBAAoB,EACpB,qBAAqB,EACrB,sBAAsB,GACvB,MAAM,YAAY,CAAC;AACpB,YAAY,EACV,cAAc,EACd,cAAc,EACd,WAAW,EACX,kBAAkB,EAClB,gBAAgB,EAChB,gBAAgB,GACjB,MAAM,SAAS,CAAC"}
|
package/dist/internal.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{b as e,c as t,d as o,e as s,f as r,g as c,h as i}from"./chunks/chunk-2CT6VOBD.js";export{t as actionSnapshot,i as createDataRuntime,o as disposeAction,r as disposeFetchResource,c as fetchResourceSnapshot,e as subscribeAction,s as subscribeFetchResource};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
type Listener<T> = (value: T) => void;
|
|
2
|
+
/** Reentrancy-safe notification queue shared by resources and actions. */
|
|
3
|
+
export declare class SnapshotNotifier<T> {
|
|
4
|
+
private readonly current;
|
|
5
|
+
readonly listeners: Set<Listener<T>>;
|
|
6
|
+
private emitting;
|
|
7
|
+
private pending;
|
|
8
|
+
constructor(current: () => T);
|
|
9
|
+
notify(): void;
|
|
10
|
+
subscribe(listener: Listener<T>): () => void;
|
|
11
|
+
clear(): void;
|
|
12
|
+
}
|
|
13
|
+
export {};
|
|
14
|
+
//# sourceMappingURL=notifications.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notifications.d.ts","sourceRoot":"","sources":["../src/notifications.ts"],"names":[],"mappings":"AAAA,KAAK,QAAQ,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,CAAC;AAkBtC,0EAA0E;AAC1E,qBAAa,gBAAgB,CAAC,CAAC;IAKjB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAJpC,QAAQ,CAAC,SAAS,mBAA0B;IAC5C,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,OAAO,CAAS;gBAEK,OAAO,EAAE,MAAM,CAAC;IAE7C,MAAM,IAAI,IAAI;IA4Bd,SAAS,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,MAAM,IAAI;IAW5C,KAAK,IAAI,IAAI;CAGd"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { OptimisticChange } from './types';
|
|
2
|
+
interface OptimisticHandlers<TResult> {
|
|
3
|
+
readonly commit: (result: TResult) => void;
|
|
4
|
+
readonly rollback: () => void;
|
|
5
|
+
}
|
|
6
|
+
export declare function createOptimisticChange<TResult>(changeHandlers: OptimisticHandlers<TResult>): OptimisticChange<TResult>;
|
|
7
|
+
export declare function optimisticHandlers<TResult>(change: OptimisticChange<TResult>): OptimisticHandlers<TResult>;
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=optimistic.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"optimistic.d.ts","sourceRoot":"","sources":["../src/optimistic.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAEhD,UAAU,kBAAkB,CAAC,OAAO;IAClC,QAAQ,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;IAC3C,QAAQ,CAAC,QAAQ,EAAE,MAAM,IAAI,CAAC;CAC/B;AAID,wBAAgB,sBAAsB,CAAC,OAAO,EAC5C,cAAc,EAAE,kBAAkB,CAAC,OAAO,CAAC,GAC1C,gBAAgB,CAAC,OAAO,CAAC,CAS3B;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EACxC,MAAM,EAAE,gBAAgB,CAAC,OAAO,CAAC,GAChC,kBAAkB,CAAC,OAAO,CAAC,CAS7B"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Query, RequestKey, StandardSchemaV1 } from './types';
|
|
2
|
+
export declare function resolveRequestURL(target: string | URL, query: Query | undefined, baseURL: string | URL | undefined): string;
|
|
3
|
+
export declare function fetchIdentity(url: string, headers: HeadersInit | undefined, key: RequestKey | undefined, schema: StandardSchemaV1 | undefined): string;
|
|
4
|
+
export declare function decodeResponse(response: Response, schema: StandardSchemaV1 | undefined): Promise<unknown>;
|
|
5
|
+
export declare function abortReason(signal: AbortSignal): unknown;
|
|
6
|
+
/** Reject client interest immediately even when a custom fetcher ignores signals. */
|
|
7
|
+
export declare function abortable<T>(operation: () => PromiseLike<T> | T, signal: AbortSignal): Promise<T>;
|
|
8
|
+
export declare function encodeActionBody(input: unknown, headers: Headers): BodyInit | undefined;
|
|
9
|
+
//# sourceMappingURL=request.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request.d.ts","sourceRoot":"","sources":["../src/request.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,KAAK,EACL,UAAU,EACV,gBAAgB,EACjB,MAAM,SAAS,CAAC;AA0CjB,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,MAAM,GAAG,GAAG,EACpB,KAAK,EAAE,KAAK,GAAG,SAAS,EACxB,OAAO,EAAE,MAAM,GAAG,GAAG,GAAG,SAAS,GAChC,MAAM,CAIR;AAiBD,wBAAgB,aAAa,CAC3B,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,WAAW,GAAG,SAAS,EAChC,GAAG,EAAE,UAAU,GAAG,SAAS,EAC3B,MAAM,EAAE,gBAAgB,GAAG,SAAS,GACnC,MAAM,CAGR;AAED,wBAAsB,cAAc,CAClC,QAAQ,EAAE,QAAQ,EAClB,MAAM,EAAE,gBAAgB,GAAG,SAAS,GACnC,OAAO,CAAC,OAAO,CAAC,CA6ClB;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAExD;AAED,qFAAqF;AACrF,wBAAgB,SAAS,CAAC,CAAC,EACzB,SAAS,EAAE,MAAM,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,EACnC,MAAM,EAAE,WAAW,GAClB,OAAO,CAAC,CAAC,CAAC,CASZ;AAED,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,OAAO,EACd,OAAO,EAAE,OAAO,GACf,QAAQ,GAAG,SAAS,CAiBtB"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { SnapshotNotifier } from './notifications';
|
|
2
|
+
import type { FetchCache, FetchOptions, FetchResource, ResourceListener, ResourceSnapshot, StandardSchemaV1 } from './types';
|
|
3
|
+
interface FetchDescriptor {
|
|
4
|
+
readonly url: string;
|
|
5
|
+
readonly headers: HeadersInit | undefined;
|
|
6
|
+
readonly identity: string;
|
|
7
|
+
readonly cache: FetchCache;
|
|
8
|
+
readonly schema: StandardSchemaV1 | undefined;
|
|
9
|
+
readonly signal: AbortSignal | undefined;
|
|
10
|
+
}
|
|
11
|
+
export interface FetchEnvironment {
|
|
12
|
+
readonly fetch: () => typeof globalThis.fetch;
|
|
13
|
+
readonly baseURL: string | URL | undefined;
|
|
14
|
+
}
|
|
15
|
+
interface MutableSnapshot<T> {
|
|
16
|
+
data: T | undefined;
|
|
17
|
+
error: import('./errors').RequestError | null;
|
|
18
|
+
status: ResourceSnapshot<T>['status'];
|
|
19
|
+
pending: boolean;
|
|
20
|
+
refreshing: boolean;
|
|
21
|
+
}
|
|
22
|
+
declare class FetchEntry {
|
|
23
|
+
readonly store: FetchStore;
|
|
24
|
+
readonly descriptor: FetchDescriptor;
|
|
25
|
+
readonly consumers: Set<ResourceController<unknown>>;
|
|
26
|
+
snapshot: MutableSnapshot<unknown>;
|
|
27
|
+
hasData: boolean;
|
|
28
|
+
cache: Exclude<FetchCache, false>;
|
|
29
|
+
request: Promise<unknown> | null;
|
|
30
|
+
controller: AbortController | null;
|
|
31
|
+
private generation;
|
|
32
|
+
constructor(store: FetchStore, descriptor: FetchDescriptor);
|
|
33
|
+
add(controller: ResourceController<unknown>): void;
|
|
34
|
+
remove(controller: ResourceController<unknown>, reason?: unknown): void;
|
|
35
|
+
private cancelRequest;
|
|
36
|
+
upgradeCache(cache: FetchCache): void;
|
|
37
|
+
emit(): void;
|
|
38
|
+
update<T>(change: (current: T | undefined) => T): void;
|
|
39
|
+
mutate<T>(change: (current: T | undefined) => void): void;
|
|
40
|
+
start(force?: boolean): Promise<unknown>;
|
|
41
|
+
dispose(resetConsumers?: boolean, reason?: unknown): void;
|
|
42
|
+
}
|
|
43
|
+
export declare class FetchStore {
|
|
44
|
+
readonly environment: FetchEnvironment;
|
|
45
|
+
readonly entries: Map<string, FetchEntry>;
|
|
46
|
+
readonly allEntries: Set<FetchEntry>;
|
|
47
|
+
constructor(environment: FetchEnvironment);
|
|
48
|
+
acquire(descriptor: FetchDescriptor, consumer: ResourceController<unknown>, force?: boolean): FetchEntry;
|
|
49
|
+
delete(entry: FetchEntry, reason?: unknown): void;
|
|
50
|
+
clear(): void;
|
|
51
|
+
}
|
|
52
|
+
declare class ResourceController<T> {
|
|
53
|
+
readonly store: FetchStore;
|
|
54
|
+
readonly descriptor: FetchDescriptor;
|
|
55
|
+
readonly paused: boolean;
|
|
56
|
+
snapshot: MutableSnapshot<T>;
|
|
57
|
+
entry: FetchEntry | null;
|
|
58
|
+
disposed: boolean;
|
|
59
|
+
private removeSignalListener;
|
|
60
|
+
readonly notifier: SnapshotNotifier<ResourceSnapshot<T>>;
|
|
61
|
+
constructor(store: FetchStore, descriptor: FetchDescriptor, paused?: boolean);
|
|
62
|
+
attach(force: boolean): void;
|
|
63
|
+
receive(entry: FetchEntry, snapshot: MutableSnapshot<unknown>): void;
|
|
64
|
+
detachFrom(entry: FetchEntry, reset?: boolean): void;
|
|
65
|
+
notify(): void;
|
|
66
|
+
refresh(): Promise<T>;
|
|
67
|
+
abort(reason?: unknown): void;
|
|
68
|
+
private detach;
|
|
69
|
+
update(change: (current: T | undefined) => T): void;
|
|
70
|
+
mutate(change: (current: T | undefined) => void): void;
|
|
71
|
+
dispose(): void;
|
|
72
|
+
}
|
|
73
|
+
export declare function createFetchResource<T>(store: FetchStore, environment: FetchEnvironment, target: string | URL | null, options: FetchOptions & {
|
|
74
|
+
readonly validate?: StandardSchemaV1;
|
|
75
|
+
}): FetchResource<T>;
|
|
76
|
+
export declare function subscribeFetchResource<T>(resource: FetchResource<T>, listener: ResourceListener<T>): () => void;
|
|
77
|
+
export declare function disposeFetchResource<T>(resource: FetchResource<T>): void;
|
|
78
|
+
export declare function fetchResourceSnapshot<T>(resource: FetchResource<T>): ResourceSnapshot<T>;
|
|
79
|
+
export declare function createFetchEnvironment(fetcher: typeof globalThis.fetch | undefined, baseURL: string | URL | undefined): FetchEnvironment;
|
|
80
|
+
export {};
|
|
81
|
+
//# sourceMappingURL=resource.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resource.d.ts","sourceRoot":"","sources":["../src/resource.ts"],"names":[],"mappings":"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"}
|
package/dist/schema.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAEnE,wBAAsB,aAAa,CAAC,OAAO,SAAS,gBAAgB,EAClE,MAAM,EAAE,OAAO,EACf,KAAK,EAAE,OAAO,GACb,OAAO,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC,CAUrC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
export type AsyncStatus = 'idle' | 'pending' | 'success' | 'error';
|
|
2
|
+
export type QueryPrimitive = string | number | boolean | null;
|
|
3
|
+
export type QueryValue = QueryPrimitive | undefined | readonly QueryPrimitive[];
|
|
4
|
+
export type Query = Readonly<Record<string, QueryValue>>;
|
|
5
|
+
export type RequestKeyPart = string | number | boolean | null;
|
|
6
|
+
export type RequestKey = string | readonly RequestKeyPart[];
|
|
7
|
+
export interface StandardSchemaV1<TInput = unknown, TOutput = TInput> {
|
|
8
|
+
readonly '~standard': {
|
|
9
|
+
readonly version: 1;
|
|
10
|
+
readonly vendor: string;
|
|
11
|
+
readonly validate: (value: unknown) => StandardSchemaResult<TOutput> | Promise<StandardSchemaResult<TOutput>>;
|
|
12
|
+
readonly types?: {
|
|
13
|
+
readonly input: TInput;
|
|
14
|
+
readonly output: TOutput;
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
export type StandardSchemaResult<T> = {
|
|
19
|
+
readonly value: T;
|
|
20
|
+
readonly issues?: undefined;
|
|
21
|
+
} | {
|
|
22
|
+
readonly issues: readonly StandardSchemaIssue[];
|
|
23
|
+
readonly value?: undefined;
|
|
24
|
+
};
|
|
25
|
+
export interface StandardSchemaIssue {
|
|
26
|
+
readonly message: string;
|
|
27
|
+
readonly path?: readonly (PropertyKey | {
|
|
28
|
+
readonly key: PropertyKey;
|
|
29
|
+
})[];
|
|
30
|
+
}
|
|
31
|
+
export type InferSchemaOutput<TSchema extends StandardSchemaV1> = TSchema extends StandardSchemaV1<unknown, infer TOutput> ? TOutput : never;
|
|
32
|
+
export interface AppCacheOptions {
|
|
33
|
+
readonly scope: 'app';
|
|
34
|
+
}
|
|
35
|
+
export type FetchCache = false | 'active' | AppCacheOptions;
|
|
36
|
+
export interface FetchOptions {
|
|
37
|
+
readonly query?: Query;
|
|
38
|
+
readonly headers?: HeadersInit;
|
|
39
|
+
readonly key?: RequestKey;
|
|
40
|
+
readonly cache?: FetchCache;
|
|
41
|
+
readonly signal?: AbortSignal;
|
|
42
|
+
}
|
|
43
|
+
export interface ValidatedFetchOptions<TSchema extends StandardSchemaV1> extends FetchOptions {
|
|
44
|
+
readonly validate: TSchema;
|
|
45
|
+
}
|
|
46
|
+
export type ActionMethod = 'POST' | 'PUT' | 'PATCH' | 'DELETE';
|
|
47
|
+
export interface ActionOptions<TResult, TInput> {
|
|
48
|
+
readonly method?: ActionMethod;
|
|
49
|
+
readonly query?: Query;
|
|
50
|
+
readonly headers?: HeadersInit;
|
|
51
|
+
readonly validate?: StandardSchemaV1<unknown, TResult>;
|
|
52
|
+
readonly onSuccess?: (result: TResult, input: TInput) => void | Promise<void>;
|
|
53
|
+
readonly onError?: (error: import('./errors').RequestError, input: TInput) => void | Promise<void>;
|
|
54
|
+
}
|
|
55
|
+
/** Opaque change produced by a resource and consumed by an action call. */
|
|
56
|
+
export interface OptimisticChange<TResult = unknown> {
|
|
57
|
+
readonly kind: 'memoized-dom.optimistic-change';
|
|
58
|
+
/** Invariant phantom type connecting the change to an action result. */
|
|
59
|
+
readonly resultType?: (result: TResult) => TResult;
|
|
60
|
+
}
|
|
61
|
+
export interface RefreshableResource {
|
|
62
|
+
refresh(): Promise<unknown>;
|
|
63
|
+
}
|
|
64
|
+
export interface ActionCallOptions<TResult> {
|
|
65
|
+
readonly optimistic?: OptimisticChange<TResult>;
|
|
66
|
+
readonly refresh?: readonly RefreshableResource[];
|
|
67
|
+
readonly signal?: AbortSignal;
|
|
68
|
+
}
|
|
69
|
+
export interface FetchResourceCore<T> extends RefreshableResource {
|
|
70
|
+
readonly data: T | undefined;
|
|
71
|
+
readonly error: import('./errors').RequestError | null;
|
|
72
|
+
readonly status: AsyncStatus;
|
|
73
|
+
readonly pending: boolean;
|
|
74
|
+
readonly refreshing: boolean;
|
|
75
|
+
refresh(): Promise<T>;
|
|
76
|
+
abort(): void;
|
|
77
|
+
update(change: (current: T | undefined) => T): void;
|
|
78
|
+
mutate(change: (current: T | undefined) => void): void;
|
|
79
|
+
}
|
|
80
|
+
export interface FetchCollectionChanges<TItem> {
|
|
81
|
+
append(temporary: TItem): OptimisticChange<TItem>;
|
|
82
|
+
replace(current: TItem, temporary: TItem): OptimisticChange<TItem>;
|
|
83
|
+
remove<TResult = unknown>(current: TItem): OptimisticChange<TResult>;
|
|
84
|
+
}
|
|
85
|
+
export type FetchResource<T> = FetchResourceCore<T> & (T extends TItemArray<infer TItem> ? FetchCollectionChanges<TItem> : object);
|
|
86
|
+
type TItemArray<TItem> = TItem[];
|
|
87
|
+
export interface FetchFunction {
|
|
88
|
+
<T = unknown>(target: string | URL | null, options?: FetchOptions): FetchResource<T>;
|
|
89
|
+
<TSchema extends StandardSchemaV1>(target: string | URL | null, options: ValidatedFetchOptions<TSchema>): FetchResource<InferSchemaOutput<TSchema>>;
|
|
90
|
+
}
|
|
91
|
+
interface ActionState<TResult> {
|
|
92
|
+
readonly data: TResult | undefined;
|
|
93
|
+
readonly error: import('./errors').RequestError | null;
|
|
94
|
+
readonly status: AsyncStatus;
|
|
95
|
+
readonly pending: boolean;
|
|
96
|
+
abort(): void;
|
|
97
|
+
reset(): void;
|
|
98
|
+
}
|
|
99
|
+
type ActionCall<TResult, TInput> = [TInput] extends [void] ? (input?: TInput, options?: ActionCallOptions<TResult>) => Promise<TResult> : (input: TInput, options?: ActionCallOptions<TResult>) => Promise<TResult>;
|
|
100
|
+
export type Action<TResult, TInput = void> = ActionState<TResult> & ActionCall<TResult, TInput>;
|
|
101
|
+
export interface ActionFunction {
|
|
102
|
+
<TResult, TInput = void>(target: string | URL, options?: ActionOptions<TResult, TInput>): Action<TResult, TInput>;
|
|
103
|
+
}
|
|
104
|
+
export interface DataRuntimeOptions {
|
|
105
|
+
readonly fetch?: typeof globalThis.fetch;
|
|
106
|
+
readonly baseURL?: string | URL;
|
|
107
|
+
}
|
|
108
|
+
export interface DataRuntime {
|
|
109
|
+
readonly $fetch: FetchFunction;
|
|
110
|
+
readonly $action: ActionFunction;
|
|
111
|
+
/** Abort active work, detach live reads, and empty retained request data. */
|
|
112
|
+
clear(): void;
|
|
113
|
+
}
|
|
114
|
+
export interface ResourceSnapshot<T> {
|
|
115
|
+
readonly data: T | undefined;
|
|
116
|
+
readonly error: import('./errors').RequestError | null;
|
|
117
|
+
readonly status: AsyncStatus;
|
|
118
|
+
readonly pending: boolean;
|
|
119
|
+
readonly refreshing: boolean;
|
|
120
|
+
}
|
|
121
|
+
export type ResourceListener<T> = (snapshot: ResourceSnapshot<T>) => void;
|
|
122
|
+
export interface ActionSnapshot<T> {
|
|
123
|
+
readonly data: T | undefined;
|
|
124
|
+
readonly error: import('./errors').RequestError | null;
|
|
125
|
+
readonly status: AsyncStatus;
|
|
126
|
+
readonly pending: boolean;
|
|
127
|
+
}
|
|
128
|
+
export type ActionListener<T> = (snapshot: ActionSnapshot<T>) => void;
|
|
129
|
+
export {};
|
|
130
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@memoized-dom/data",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Browser-first fetch resources and callable actions for memoized-dom",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"sideEffects": false,
|
|
7
|
+
"files": [
|
|
8
|
+
"dist",
|
|
9
|
+
"README.md"
|
|
10
|
+
],
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"import": "./dist/index.js",
|
|
15
|
+
"default": "./dist/index.js"
|
|
16
|
+
},
|
|
17
|
+
"./internal": {
|
|
18
|
+
"types": "./dist/internal.d.ts",
|
|
19
|
+
"import": "./dist/internal.js",
|
|
20
|
+
"default": "./dist/internal.js"
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"scripts": {
|
|
24
|
+
"build": "bun run ./scripts/clean.ts && esbuild ./src/index.ts ./src/internal.ts --bundle --outdir=./dist --platform=browser --format=esm --target=es2022 --minify --splitting --entry-names=[name] --chunk-names=chunks/[name]-[hash] && tsc -p tsconfig.build.json",
|
|
25
|
+
"test": "vitest run --config vitest.config.ts && tsc -p tsconfig.test.json"
|
|
26
|
+
},
|
|
27
|
+
"publishConfig": {
|
|
28
|
+
"access": "public"
|
|
29
|
+
}
|
|
30
|
+
}
|