@absolutejs/absolute 0.19.0-beta.1070 → 0.19.0-beta.1072
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/dist/angular/components/core/streamingSlotRegistrar.js +1 -1
- package/dist/angular/components/core/streamingSlotRegistry.js +2 -2
- package/dist/angular/index.js +55 -2
- package/dist/angular/index.js.map +3 -3
- package/dist/angular/server.js +55 -2
- package/dist/angular/server.js.map +3 -3
- package/dist/build.js +55 -2
- package/dist/build.js.map +3 -3
- package/dist/cli/index.js +58 -17
- package/dist/index.js +55 -2
- package/dist/index.js.map +3 -3
- package/dist/src/vue/index.d.ts +2 -0
- package/dist/src/vue/useResource.d.ts +65 -0
- package/dist/vue/index.js +68 -1
- package/dist/vue/index.js.map +5 -4
- package/package.json +1 -1
package/dist/src/vue/index.d.ts
CHANGED
|
@@ -7,3 +7,5 @@ export { createTypedIsland } from './createIsland';
|
|
|
7
7
|
export { useIslandStore } from './useIslandStore';
|
|
8
8
|
export { Image } from './components/Image';
|
|
9
9
|
export { StreamSlot, SuspenseSlot } from './components';
|
|
10
|
+
export { useResource } from './useResource';
|
|
11
|
+
export type { Resource, ResourceFetcher, ResourceMutator, ResourceOptions, ResourceStart } from './useResource';
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { type Ref } from 'vue';
|
|
2
|
+
export type ResourceFetcher<T> = (signal: AbortSignal) => Promise<T>;
|
|
3
|
+
/** Controls the resource's startup behavior.
|
|
4
|
+
*
|
|
5
|
+
* - `'immediate'` (default) — fire the fetcher synchronously at creation;
|
|
6
|
+
* `loading.value` starts `true`.
|
|
7
|
+
* - `'pending'` — don't fire the fetcher yet, but render as if a fetch is
|
|
8
|
+
* coming: `loading.value` starts `true`. Pair with a manual `refresh()`
|
|
9
|
+
* call from `onMounted` (or wherever the dependencies become available).
|
|
10
|
+
* Use this when the fetcher depends on state set after setup runs (e.g. a
|
|
11
|
+
* route param resolved asynchronously) — it avoids the blank-frame flash
|
|
12
|
+
* you'd get from `'idle'`.
|
|
13
|
+
* - `'idle'` — don't fire the fetcher and don't pretend you will:
|
|
14
|
+
* `loading.value` starts `false`. The resource is dormant until
|
|
15
|
+
* `refresh()` or `mutate()` is called.
|
|
16
|
+
*/
|
|
17
|
+
export type ResourceStart = 'immediate' | 'pending' | 'idle';
|
|
18
|
+
export type ResourceOptions = {
|
|
19
|
+
/** When and how the fetcher fires on creation. Default: `'immediate'`. */
|
|
20
|
+
start?: ResourceStart;
|
|
21
|
+
};
|
|
22
|
+
export type ResourceMutator<T> = T | null | ((prev: T | null) => T | null);
|
|
23
|
+
export type Resource<T> = {
|
|
24
|
+
/** Latest resolved value, or `null` before the first successful load. */
|
|
25
|
+
data: Ref<T | null>;
|
|
26
|
+
/** Latest rejection reason, or `null` when the resource is healthy. */
|
|
27
|
+
error: Ref<unknown>;
|
|
28
|
+
/** True while a fetch is in flight, or when `start: 'pending'` was set
|
|
29
|
+
* and `refresh()` hasn't been called yet. */
|
|
30
|
+
loading: Ref<boolean>;
|
|
31
|
+
/** Re-runs the fetcher. Any in-flight request is aborted first. */
|
|
32
|
+
refresh: () => Promise<void>;
|
|
33
|
+
/** Aborts the in-flight request, if any. No-op otherwise. */
|
|
34
|
+
cancel: () => void;
|
|
35
|
+
/** Imperatively write the data ref without re-fetching. Accepts a new
|
|
36
|
+
* value or an updater function. Use after an edit action returns the new
|
|
37
|
+
* entity, so you avoid a wasteful re-fetch. Pending fetches are aborted
|
|
38
|
+
* so a slower response can't clobber the mutation. */
|
|
39
|
+
mutate: (next: ResourceMutator<T>) => void;
|
|
40
|
+
};
|
|
41
|
+
/** Ref-backed async data composable for AbsoluteJS Vue pages. Replaces the
|
|
42
|
+
* hand-rolled `onMounted(() => { loading.value = true; data.value = await
|
|
43
|
+
* fetch(); })` + `ref` boilerplate with a single call that also handles
|
|
44
|
+
* abort-on-teardown, refresh, and optimistic mutation.
|
|
45
|
+
*
|
|
46
|
+
* This is a per-component LOADER, not a cross-component cache — every call
|
|
47
|
+
* owns its own state and refetches on creation. For data that should survive
|
|
48
|
+
* navigation / be shared across components (so revisiting a route doesn't
|
|
49
|
+
* refetch), use a cache layer (e.g. TanStack Query) or `@absolutejs/sync`
|
|
50
|
+
* instead. Reach for `useResource` when a one-shot, component-scoped fetch is
|
|
51
|
+
* exactly what you want.
|
|
52
|
+
*
|
|
53
|
+
* ```ts
|
|
54
|
+
* const profile = useResource((signal) => api.profile.me.get({ signal }));
|
|
55
|
+
*
|
|
56
|
+
* // in template:
|
|
57
|
+
* // <Spinner v-if="profile.loading.value" />
|
|
58
|
+
* // <h1 v-else-if="profile.data.value">{{ profile.data.value.name }}</h1>
|
|
59
|
+
* ```
|
|
60
|
+
*
|
|
61
|
+
* The fetcher receives an `AbortSignal` it can pass to `fetch` — the signal
|
|
62
|
+
* aborts when the owning effect scope is disposed (component unmount) or on a
|
|
63
|
+
* new `refresh()` call. Call it during `setup()` so an effect scope is
|
|
64
|
+
* active; teardown won't be wired up otherwise. */
|
|
65
|
+
export declare const useResource: <T>(fetcher: ResourceFetcher<T>, options?: ResourceOptions) => Resource<T>;
|
package/dist/vue/index.js
CHANGED
|
@@ -5237,7 +5237,74 @@ var useIslandStore = (store, selector) => {
|
|
|
5237
5237
|
});
|
|
5238
5238
|
return state;
|
|
5239
5239
|
};
|
|
5240
|
+
// src/vue/useResource.ts
|
|
5241
|
+
import {
|
|
5242
|
+
getCurrentScope,
|
|
5243
|
+
onScopeDispose,
|
|
5244
|
+
ref as ref3,
|
|
5245
|
+
shallowRef
|
|
5246
|
+
} from "vue";
|
|
5247
|
+
var useResource = (fetcher, options = {}) => {
|
|
5248
|
+
const start = options.start ?? "immediate";
|
|
5249
|
+
const data = shallowRef(null);
|
|
5250
|
+
const error = shallowRef(null);
|
|
5251
|
+
const loading = ref3(start !== "idle");
|
|
5252
|
+
let controller = null;
|
|
5253
|
+
let destroyed = false;
|
|
5254
|
+
const cancel = () => {
|
|
5255
|
+
if (controller) {
|
|
5256
|
+
controller.abort();
|
|
5257
|
+
controller = null;
|
|
5258
|
+
}
|
|
5259
|
+
};
|
|
5260
|
+
const refresh = async () => {
|
|
5261
|
+
if (destroyed)
|
|
5262
|
+
return;
|
|
5263
|
+
cancel();
|
|
5264
|
+
const next = new AbortController;
|
|
5265
|
+
controller = next;
|
|
5266
|
+
loading.value = true;
|
|
5267
|
+
error.value = null;
|
|
5268
|
+
try {
|
|
5269
|
+
const result = await fetcher(next.signal);
|
|
5270
|
+
if (next.signal.aborted)
|
|
5271
|
+
return;
|
|
5272
|
+
data.value = result;
|
|
5273
|
+
} catch (cause) {
|
|
5274
|
+
if (next.signal.aborted)
|
|
5275
|
+
return;
|
|
5276
|
+
error.value = cause;
|
|
5277
|
+
} finally {
|
|
5278
|
+
if (controller === next) {
|
|
5279
|
+
controller = null;
|
|
5280
|
+
}
|
|
5281
|
+
if (!next.signal.aborted) {
|
|
5282
|
+
loading.value = false;
|
|
5283
|
+
}
|
|
5284
|
+
}
|
|
5285
|
+
};
|
|
5286
|
+
const mutate = (next) => {
|
|
5287
|
+
if (destroyed)
|
|
5288
|
+
return;
|
|
5289
|
+
cancel();
|
|
5290
|
+
error.value = null;
|
|
5291
|
+
loading.value = false;
|
|
5292
|
+
const resolved = typeof next === "function" ? next(data.value) : next;
|
|
5293
|
+
data.value = resolved;
|
|
5294
|
+
};
|
|
5295
|
+
if (getCurrentScope()) {
|
|
5296
|
+
onScopeDispose(() => {
|
|
5297
|
+
destroyed = true;
|
|
5298
|
+
cancel();
|
|
5299
|
+
});
|
|
5300
|
+
}
|
|
5301
|
+
if (start === "immediate") {
|
|
5302
|
+
refresh();
|
|
5303
|
+
}
|
|
5304
|
+
return { cancel, data, error, loading, mutate, refresh };
|
|
5305
|
+
};
|
|
5240
5306
|
export {
|
|
5307
|
+
useResource,
|
|
5241
5308
|
useIslandStore,
|
|
5242
5309
|
handleVuePageRequest,
|
|
5243
5310
|
defineVueSetupApp,
|
|
@@ -5250,5 +5317,5 @@ export {
|
|
|
5250
5317
|
Image
|
|
5251
5318
|
};
|
|
5252
5319
|
|
|
5253
|
-
//# debugId=
|
|
5320
|
+
//# debugId=CDB2A0DB62376A8D64756E2164756E21
|
|
5254
5321
|
//# sourceMappingURL=index.js.map
|