elliott/resources
Elliott Johnson 6 days ago
parent cc74b6dfd5
commit 85abdbdd54

@ -143,7 +143,7 @@ This restriction only applies when using the `experimental.async` option, which
### fn_unavailable_on_client
```
`%name%`(...) is unavailable on the client.
`%name%`(...) is unavailable in the browser.
```
### fork_discarded

@ -29,7 +29,7 @@ First set occurred at:
%stack%
```
This error occurs when using `hydratable` or `setHydratableValue` multiple times with the same key. To avoid this, you can combine `hydratable` with `cache`, or check whether the value has already been set with `hasHydratableValue`.
This error occurs when using `hydratable` or `hydratable.set` multiple times with the same key. To avoid this, you can combine `hydratable` with `cache`, or check whether the value has already been set with `hydratable.has`.
```svelte
<script>

@ -246,13 +246,13 @@ export function flush_sync_in_effect() {
}
/**
* `%name%`(...) is unavailable on the client.
* `%name%`(...) is unavailable in the browser.
* @param {string} name
* @returns {never}
*/
export function fn_unavailable_on_client(name) {
if (DEV) {
const error = new Error(`fn_unavailable_on_client\n\`${name}\`(...) is unavailable on the client.\nhttps://svelte.dev/e/fn_unavailable_on_client`);
const error = new Error(`fn_unavailable_on_client\n\`${name}\`(...) is unavailable in the browser.\nhttps://svelte.dev/e/fn_unavailable_on_client`);
error.name = 'Svelte error';

@ -1,6 +1,6 @@
/** @import { Source, Derived } from '#client' */
/** @import { Resource as ResourceType } from '#shared' */
import { state, derived, set, get, tick } from '../index.js';
import { state, derived, set, get, tick, proxy } from '../index.js';
import { deferred } from '../../shared/utils.js';
import { async_mode_flag } from '../../flags/index.js';
import * as e from '../errors.js';
@ -49,10 +49,24 @@ class Resource {
/** {@type Source<any>} */
#error = state(undefined);
/** @type {Source<((oldValue: T) => T)[]>} */
#overrides = state(proxy([]));
/** @type {Derived<T | undefined>} */
#current = derived(() => {
return get(this.#ready)
? get(this.#overrides).reduce((v, r) => r(v), /** @type {T} */ (get(this.#raw)))
: undefined;
});
/** @type {Derived<Promise<T>['then']>} */
// @ts-ignore
#then = derived(() => {
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
get(this.#overrides).length;
const p = get(this.#promise);
return (resolve, reject) => p.then(resolve, reject);
return (resolve, reject) =>
p.then(() => resolve?.(/** @type {T} */ (get(this.#current))), reject);
});
/**
@ -126,7 +140,7 @@ class Resource {
}
get current() {
return get(this.#ready) ? get(this.#raw) : undefined;
return get(this.#current);
}
get error() {
@ -166,6 +180,26 @@ class Resource {
set(this.#raw, value);
set(this.#promise, Promise.resolve(value));
};
/**
* @param {(oldValue: T) => T} fn
* @param {Promise<T>} promise
*/
withOverride(fn, promise) {
get(this.#overrides).push(fn);
const rollback = () => {
const i = get(this.#overrides).indexOf(fn);
if (i !== -1) {
get(this.#overrides).splice(i, 1);
}
};
promise.then((result) => {
this.set(result);
rollback();
}, rollback);
}
}
/** @returns {Promise<void>} */

@ -99,6 +99,10 @@ class Resource {
this.#current = value;
this.#promise = Promise.resolve();
};
withOverride = () => {
throw new Error('TODO Cannot override a resource on the server');
};
}
export function refreshAll() {

@ -40,6 +40,7 @@ export type Resource<T> = {
set: (value: Awaited<T>) => void;
loading: boolean;
error: any;
withOverride(fn: (oldValue: Awaited<T>) => Awaited<T>, promise: Promise<Awaited<T>>): void;
} & (
| {
ready: false;

@ -2203,6 +2203,7 @@ declare module 'svelte/reactivity' {
set: (value: Awaited<T>) => void;
loading: boolean;
error: any;
withOverride(fn: (oldValue: Awaited<T>) => Awaited<T>, promise: Promise<Awaited<T>>): void;
} & (
| {
ready: false;
@ -2215,8 +2216,6 @@ declare module 'svelte/reactivity' {
);
type GetRequestInit = Omit<RequestInit, 'method' | 'body'> & { method?: 'GET' };
type CacheEntry = { count: number; item: any };
/**
* A reactive version of the built-in [`Date`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date) object.
* Reading the date (whether with methods like `date.getTime()` or `date.toString()`, or via things like [`Intl.DateTimeFormat`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat))
@ -2480,35 +2479,22 @@ declare module 'svelte/reactivity' {
* @since 5.7.0
*/
export function createSubscriber(start: (update: () => void) => (() => void) | void): () => void;
export function resource<T>(fn: () => T): Resource<T>;
export class ReactiveCache<K = any, V = any> {
register(key: K, fn: () => V): V;
[Symbol.iterator](): Generator<V, void, unknown>;
#private;
}
export function fetcher<TReturn>(url: string | URL, init?: GetRequestInit | undefined): Resource<TReturn>;
export function cache<TFn extends (...args: any[]) => any>(key: string, fn: TFn): ReturnType<TFn>;
export function resource<T>(fn: () => T): Resource<T>;
export class CacheObserver<T> extends BaseCacheObserver<T> {
constructor(prefix?: string);
}
export function refreshAll(): Promise<void>;
class ReactiveValue<T> {
constructor(fn: () => T, onsubscribe: (update: () => void) => void);
get current(): T;
#private;
}
class BaseCacheObserver<T> implements ReadonlyMap<string, T> {
constructor(get_cache: () => Map<string, CacheEntry>, prefix?: string | undefined);
get(key: string): any;
has(key: string): boolean;
get size(): number;
forEach(cb: (item: T, key: string, map: ReadonlyMap<string, T>) => void): void;
entries(): Generator<[string, T], undefined, unknown>;
keys(): Generator<string, undefined, unknown>;
values(): Generator<T, undefined, unknown>;
[Symbol.iterator](): Generator<[string, T], undefined, unknown>;
#private;
}
export {};
}

Loading…
Cancel
Save