chore: temporarily remove fetcher

pull/17124/head
Elliott Johnson 1 month ago
parent bca87b92bf
commit 82be3881b2

@ -1,66 +0,0 @@
/** @import { Resource } from './resource.js' */
/** @import { StandardSchemaV1 } from '@standard-schema/spec' */
import { compile } from 'path-to-regexp';
import { create_resource } from './define-resource.js';
/**
* @template {Record<string, unknown>} TPathParams
* @typedef {{ searchParams?: ConstructorParameters<typeof URLSearchParams>[0], pathParams?: TPathParams } & RequestInit} FetcherInit
*/
/**
* @template TReturn
* @template {Record<string, unknown>} TPathParams
* @typedef {(init: FetcherInit<TPathParams>) => Resource<TReturn>} Fetcher
*/
/**
* @template {Record<string, unknown>} TPathParams
* @template {typeof Resource} TResource
* @overload
* @param {string} url
* @param {{ Resource?: TResource, schema?: undefined }} [options] - TODO what options should we support?
* @returns {Fetcher<string | number | Record<string, unknown> | unknown[] | boolean | null, TPathParams>} - TODO this return type has to be gnarly unless we do schema validation, as it could be any JSON value (including string, number, etc)
*/
/**
* @template {Record<string, unknown>} TPathParams
* @template {StandardSchemaV1} TSchema
* @template {typeof Resource} TResource
* @overload
* @param {string} url
* @param {{ Resource?: TResource, schema: StandardSchemaV1 }} options
* @returns {Fetcher<StandardSchemaV1.InferOutput<TSchema>, TPathParams>} - TODO this return type has to be gnarly unless we do schema validation, as it could be any JSON value (including string, number, etc)
*/
/**
* @template {Record<string, unknown>} TPathParams
* @template {typeof Resource} TResource
* @template {StandardSchemaV1} TSchema
* @param {string} url
* @param {{ Resource?: TResource, schema?: StandardSchemaV1 }} [options]
*/
export function create_fetcher(url, options) {
const raw_pathname = url.split('//')[1].match(/(\/[^?#]*)/)?.[1] ?? '';
const populate_path = compile(raw_pathname);
/**
* @param {Parameters<Fetcher<any, any>>[0]} args
* @returns {Promise<any>}
*/
const fn = async (args) => {
const cloned_url = new URL(url);
const new_params = new URLSearchParams(args.searchParams);
const combined_params = new URLSearchParams([...cloned_url.searchParams, ...new_params]);
cloned_url.search = combined_params.toString();
cloned_url.pathname = populate_path(args.pathParams ?? {}); // TODO we definitely should get rid of this lib for launch, I just wanted to play with the API
// TODO how to populate path params
const resp = await fetch(cloned_url, args);
if (!resp.ok) {
throw new Error(`Fetch error: ${resp.status} ${resp.statusText}`);
}
const json = await resp.json();
if (options?.schema) {
return options.schema['~standard'].validate(json);
}
return json;
};
return create_resource(url.toString(), fn, options);
}

@ -132,8 +132,8 @@ export async function save(promise) {
* @param {{ transport?: Transport }} [options]
* @returns {Promise<T>}
*/
export async function hydratable(key, fn, { transport } = {}) {
const store = await get_render_store();
export function hydratable(key, fn, { transport } = {}) {
const store = get_render_store();
if (store.hydratables.has(key)) {
// TODO error
@ -142,7 +142,7 @@ export async function hydratable(key, fn, { transport } = {}) {
const result = fn();
store.hydratables.set(key, { value: result, transport });
return result;
return Promise.resolve(result);
}
/** @type {ALSContext | null} */
@ -153,28 +153,30 @@ export function set_sync_store(store) {
sync_store = store;
}
/** @type {Promise<AsyncLocalStorage<ALSContext | null> | null>} */
const als = import('node:async_hooks')
.then((hooks) => new hooks.AsyncLocalStorage())
/** @type {AsyncLocalStorage<ALSContext | null> | null} */
let als = null;
import('node:async_hooks')
.then((hooks) => (als = new hooks.AsyncLocalStorage()))
.catch(() => {
// can't use ALS but can still use manual context preservation
return null;
});
/** @returns {Promise<ALSContext | null>} */
async function try_get_render_store() {
return sync_store ?? (await als)?.getStore() ?? null;
/** @returns {ALSContext | null} */
function try_get_render_store() {
return sync_store ?? als?.getStore() ?? null;
}
/** @returns {Promise<ALSContext>} */
export async function get_render_store() {
const store = await try_get_render_store();
/** @returns {ALSContext} */
export function get_render_store() {
const store = try_get_render_store();
if (!store) {
// TODO make this a proper e.error
let message = 'Could not get rendering context.';
if (await als) {
if (als) {
message += ' This is an internal error.';
} else {
message +=
@ -194,10 +196,10 @@ export async function get_render_store() {
* @param {() => Promise<T>} fn
* @returns {Promise<T>}
*/
export async function with_render_store(store, fn) {
export function with_render_store(store, fn) {
try {
sync_store = store;
const storage = await als;
const storage = als;
return storage ? storage.run(store, fn) : fn();
} finally {
sync_store = null;

@ -375,7 +375,7 @@ export class Renderer {
});
return Promise.resolve(user_result);
}
async ??= with_render_store({ hydratables: new Map() }, () =>
async ??= with_render_store({ hydratables: new Map(), resources: new Map() }, () =>
Renderer.#render_async(component, options)
);
return async.then((result) => {
@ -523,7 +523,7 @@ export class Renderer {
}
async #collect_hydratables() {
const map = (await get_render_store()).hydratables;
const map = get_render_store().hydratables;
/** @type {(value: unknown) => string} */
let default_stringify;

@ -1,4 +1,5 @@
import type { MaybePromise, Transport } from '#shared';
import type { Resource } from '../../reactivity/index-server';
import type { Element } from './dev';
import type { Renderer } from './renderer';
@ -23,6 +24,7 @@ export interface ALSContext {
transport: Transport | undefined;
}
>;
resources: Map<string, Resource<any>>;
}
export interface SyncRenderOutput {

@ -7,4 +7,3 @@ export { MediaQuery } from './media-query.js';
export { createSubscriber } from './create-subscriber.js';
export { Resource } from '../internal/client/reactivity/resources/resource.js';
export { define_resource as defineResource } from '../internal/client/reactivity/resources/define-resource.js';
export { create_fetcher as createFetcher } from '../internal/client/reactivity/resources/create-fetcher.js';

@ -1,7 +1,7 @@
/** @import { StandardSchemaV1 } from '@standard-schema/spec' */
/** @import { Transport } from '#shared' */
import { uneval } from 'devalue';
import { hydratable } from '../internal/server/context.js';
import { get_render_store, hydratable } from '../internal/server/context.js';
export const SvelteDate = globalThis.Date;
export const SvelteSet = globalThis.Set;
@ -114,10 +114,6 @@ export class Resource {
};
}
/** @type {Map<string, Resource<any>>} */
// TODO scope to render, clear after render
const cache = new Map();
/**
* @template TReturn
* @template {unknown[]} [TArgs=[]]
@ -130,6 +126,7 @@ const cache = new Map();
export function defineResource(name, fn, options = {}) {
const ResolvedResource = options?.Resource ?? Resource;
return (...args) => {
const cache = get_render_store().resources;
const stringified_args = (options.transport?.stringify ?? JSON.stringify)(args);
const cache_key = `${name}:${stringified_args}`;
const entry = cache.get(cache_key);
@ -143,64 +140,3 @@ export function defineResource(name, fn, options = {}) {
return resource;
};
}
/**
* @template {Record<string, unknown>} TPathParams
* @typedef {{ searchParams?: ConstructorParameters<typeof URLSearchParams>[0], pathParams?: TPathParams } & RequestInit} FetcherInit
*/
/**
* @template TReturn
* @template {Record<string, unknown>} TPathParams
* @typedef {(init: FetcherInit<TPathParams>) => Resource<TReturn>} Fetcher
*/
/**
* @template {Record<string, unknown>} TPathParams
* @template {typeof Resource} TResource
* @overload
* @param {string} url
* @param {{ Resource?: TResource, schema?: undefined }} [options] - TODO what options should we support?
* @returns {Fetcher<string | number | Record<string, unknown> | unknown[] | boolean | null, TPathParams>} - TODO this return type has to be gnarly unless we do schema validation, as it could be any JSON value (including string, number, etc)
*/
/**
* @template {Record<string, unknown>} TPathParams
* @template {StandardSchemaV1} TSchema
* @template {typeof Resource} TResource
* @overload
* @param {string} url
* @param {{ Resource?: TResource, schema: StandardSchemaV1 }} options
* @returns {Fetcher<StandardSchemaV1.InferOutput<TSchema>, TPathParams>} - TODO this return type has to be gnarly unless we do schema validation, as it could be any JSON value (including string, number, etc)
*/
/**
* @template {Record<string, unknown>} TPathParams
* @template {typeof Resource} TResource
* @template {StandardSchemaV1} TSchema
* @param {string} url
* @param {{ Resource?: TResource, schema?: StandardSchemaV1 }} [options]
*/
export function createFetcher(url, options) {
const raw_pathname = url.split('//')[1].match(/(\/[^?#]*)/)?.[1] ?? '';
const populate_path = compile(raw_pathname);
/**
* @param {Parameters<Fetcher<any, any>>[0]} args
* @returns {Promise<any>}
*/
const fn = async (args) => {
const cloned_url = new URL(url);
const new_params = new URLSearchParams(args.searchParams);
const combined_params = new URLSearchParams([...cloned_url.searchParams, ...new_params]);
cloned_url.search = combined_params.toString();
cloned_url.pathname = populate_path(args.pathParams ?? {}); // TODO we definitely should get rid of this lib for launch, I just wanted to play with the API
// TODO how to populate path params
const resp = await fetch(cloned_url, args);
if (!resp.ok) {
throw new Error(`Fetch error: ${resp.status} ${resp.statusText}`);
}
const json = await resp.json();
if (options?.schema) {
return options.schema['~standard'].validate(json);
}
return json;
};
return createResource(url.toString(), fn, options);
}

@ -448,8 +448,6 @@ declare module 'svelte' {
}): Snippet<Params>;
/** Anything except a function */
type NotFunction<T> = T extends Function ? never : T;
type MaybePromise<T> = T | Promise<T>;
/**
* Returns a `[get, set]` pair of functions for working with context in a type-safe way.
*
@ -491,7 +489,9 @@ declare module 'svelte' {
* */
export function getAllContexts<T extends Map<any, any> = Map<any, any>>(): T;
export function hydratable<T>(key: string, fn: () => T): MaybePromise<T>;
export function hydratable<T>(key: string, fn: () => T, { transport }?: {
transport?: Transport;
} | undefined): Promise<T>;
/**
* Mounts a component to the given target and returns the exports and potentially the props (if compiled with `accessors: true`) of the component.
* Transitions will play during the initial render unless the `intro` option is set to `false`.
@ -565,6 +565,11 @@ declare module 'svelte' {
[K in keyof T]: () => T[K];
};
type Transport = {
stringify: (value: unknown) => string;
parse: (value: string) => unknown;
};
export {};
}
@ -2143,7 +2148,6 @@ declare module 'svelte/motion' {
}
declare module 'svelte/reactivity' {
import type { StandardSchemaV1 } from '@standard-schema/spec';
/**
* 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))
@ -2429,29 +2433,20 @@ declare module 'svelte/reactivity' {
set: (value: T) => void;
#private;
}
export function createResource<TReturn, TArgs extends unknown[] = [], TResource extends typeof Resource = typeof Resource>(name: string, fn: (...args: TArgs) => Promise<TReturn>, options?: {
export function defineResource<TReturn, TArgs extends unknown[] = [], TResource extends typeof Resource = typeof Resource>(name: string, fn: (...args: TArgs) => TReturn, options?: {
Resource?: TResource;
transport?: Transport;
} | undefined): (...args: TArgs) => Resource<TReturn>;
export function createFetcher<TPathParams extends Record<string, unknown>, TResource extends typeof Resource>(url: string, options?: {
Resource?: TResource;
schema?: undefined;
} | undefined): Fetcher<string | number | Record<string, unknown> | unknown[] | boolean | null, TPathParams>;
export function createFetcher<TPathParams extends Record<string, unknown>, TSchema extends StandardSchemaV1, TResource extends typeof Resource>(url: string, options: {
Resource?: TResource;
schema: StandardSchemaV1;
}): Fetcher<StandardSchemaV1.InferOutput<TSchema>, TPathParams>;
type FetcherInit<TPathParams extends Record<string, unknown>> = {
searchParams?: ConstructorParameters<typeof URLSearchParams>[0];
pathParams?: TPathParams;
} & RequestInit;
type Fetcher<TReturn, TPathParams extends Record<string, unknown>> = (init: FetcherInit<TPathParams>) => Resource<TReturn>;
class ReactiveValue<T> {
constructor(fn: () => T, onsubscribe: (update: () => void) => void);
get current(): T;
#private;
}
type Transport = {
stringify: (value: unknown) => string;
parse: (value: string) => unknown;
};
export {};
}

Loading…
Cancel
Save