@fragno-dev/core 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/.turbo/turbo-build.log +61 -0
- package/.turbo/turbo-types$colon$check.log +2 -0
- package/dist/api/api.d.ts +2 -0
- package/dist/api/api.js +3 -0
- package/dist/api-CBDGZiLC.d.ts +278 -0
- package/dist/api-CBDGZiLC.d.ts.map +1 -0
- package/dist/api-DgHfYjq2.js +54 -0
- package/dist/api-DgHfYjq2.js.map +1 -0
- package/dist/client/client.d.ts +3 -0
- package/dist/client/client.js +6 -0
- package/dist/client/client.svelte.d.ts +33 -0
- package/dist/client/client.svelte.d.ts.map +1 -0
- package/dist/client/client.svelte.js +123 -0
- package/dist/client/client.svelte.js.map +1 -0
- package/dist/client/react.d.ts +58 -0
- package/dist/client/react.d.ts.map +1 -0
- package/dist/client/react.js +80 -0
- package/dist/client/react.js.map +1 -0
- package/dist/client/vanilla.d.ts +61 -0
- package/dist/client/vanilla.d.ts.map +1 -0
- package/dist/client/vanilla.js +136 -0
- package/dist/client/vanilla.js.map +1 -0
- package/dist/client/vue.d.ts +39 -0
- package/dist/client/vue.d.ts.map +1 -0
- package/dist/client/vue.js +108 -0
- package/dist/client/vue.js.map +1 -0
- package/dist/client-DWjxKDnE.js +703 -0
- package/dist/client-DWjxKDnE.js.map +1 -0
- package/dist/client-XFdAy-IQ.d.ts +287 -0
- package/dist/client-XFdAy-IQ.d.ts.map +1 -0
- package/dist/integrations/astro.d.ts +18 -0
- package/dist/integrations/astro.d.ts.map +1 -0
- package/dist/integrations/astro.js +16 -0
- package/dist/integrations/astro.js.map +1 -0
- package/dist/integrations/next-js.d.ts +15 -0
- package/dist/integrations/next-js.d.ts.map +1 -0
- package/dist/integrations/next-js.js +17 -0
- package/dist/integrations/next-js.js.map +1 -0
- package/dist/integrations/react-ssr.d.ts +19 -0
- package/dist/integrations/react-ssr.d.ts.map +1 -0
- package/dist/integrations/react-ssr.js +38 -0
- package/dist/integrations/react-ssr.js.map +1 -0
- package/dist/integrations/svelte-kit.d.ts +21 -0
- package/dist/integrations/svelte-kit.d.ts.map +1 -0
- package/dist/integrations/svelte-kit.js +18 -0
- package/dist/integrations/svelte-kit.js.map +1 -0
- package/dist/mod.d.ts +3 -0
- package/dist/mod.js +177 -0
- package/dist/mod.js.map +1 -0
- package/dist/route-Bp6eByhz.js +331 -0
- package/dist/route-Bp6eByhz.js.map +1 -0
- package/dist/ssr-tJHqcNSw.js +48 -0
- package/dist/ssr-tJHqcNSw.js.map +1 -0
- package/package.json +127 -0
- package/src/api/api.test.ts +140 -0
- package/src/api/api.ts +106 -0
- package/src/api/error.ts +47 -0
- package/src/api/fragment.test.ts +509 -0
- package/src/api/fragment.ts +277 -0
- package/src/api/internal/path-runtime.test.ts +121 -0
- package/src/api/internal/path-type.test.ts +602 -0
- package/src/api/internal/path.ts +322 -0
- package/src/api/internal/response-stream.ts +118 -0
- package/src/api/internal/route.test.ts +56 -0
- package/src/api/internal/route.ts +9 -0
- package/src/api/request-input-context.test.ts +437 -0
- package/src/api/request-input-context.ts +201 -0
- package/src/api/request-middleware.test.ts +544 -0
- package/src/api/request-middleware.ts +126 -0
- package/src/api/request-output-context.test.ts +626 -0
- package/src/api/request-output-context.ts +175 -0
- package/src/api/route.test.ts +176 -0
- package/src/api/route.ts +152 -0
- package/src/client/client-builder.test.ts +264 -0
- package/src/client/client-error.test.ts +15 -0
- package/src/client/client-error.ts +141 -0
- package/src/client/client-types.test.ts +493 -0
- package/src/client/client.ssr.test.ts +173 -0
- package/src/client/client.svelte.test.ts +837 -0
- package/src/client/client.svelte.ts +278 -0
- package/src/client/client.test.ts +1690 -0
- package/src/client/client.ts +1035 -0
- package/src/client/component.test.svelte +21 -0
- package/src/client/internal/ndjson-streaming.test.ts +457 -0
- package/src/client/internal/ndjson-streaming.ts +248 -0
- package/src/client/react.test.ts +947 -0
- package/src/client/react.ts +241 -0
- package/src/client/vanilla.test.ts +867 -0
- package/src/client/vanilla.ts +265 -0
- package/src/client/vue.test.ts +754 -0
- package/src/client/vue.ts +242 -0
- package/src/http/http-status.ts +60 -0
- package/src/integrations/astro.ts +17 -0
- package/src/integrations/next-js.ts +31 -0
- package/src/integrations/react-ssr.ts +40 -0
- package/src/integrations/svelte-kit.ts +41 -0
- package/src/mod.ts +20 -0
- package/src/util/async.test.ts +85 -0
- package/src/util/async.ts +96 -0
- package/src/util/content-type.test.ts +136 -0
- package/src/util/content-type.ts +84 -0
- package/src/util/nanostores.test.ts +28 -0
- package/src/util/nanostores.ts +65 -0
- package/src/util/ssr.ts +75 -0
- package/src/util/types-util.ts +16 -0
- package/tsconfig.json +10 -0
- package/tsdown.config.ts +21 -0
- package/vitest.config.ts +10 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.svelte.js","names":["pathParams: Record<string, string | ReadableAtom<string>>","queryParams: Record<string, string | ReadableAtom<string>>"],"sources":["../../src/client/client.svelte.ts"],"sourcesContent":["import type { StandardSchemaV1 } from \"@standard-schema/spec\";\nimport { atom, type ReadableAtom } from \"nanostores\";\nimport type { NonGetHTTPMethod } from \"../api/api\";\nimport {\n isGetHook,\n isMutatorHook,\n isStore,\n type FragnoClientHookData,\n type FragnoClientMutatorData,\n type FragnoStoreData,\n} from \"./client\";\nimport type { FragnoClientError } from \"./client-error\";\nimport type { InferOr } from \"../util/types-util\";\nimport type { MaybeExtractPathParamsOrWiden, QueryParamsHint } from \"../api/internal/path\";\n\nimport { writable, type Readable, get } from \"svelte/store\";\nimport { onDestroy } from \"svelte\";\n\nexport type FragnoSvelteHook<\n _TMethod extends \"GET\",\n TPath extends string,\n TOutputSchema extends StandardSchemaV1,\n TErrorCode extends string,\n TQueryParameters extends string,\n> = (args?: {\n path?:\n | MaybeExtractPathParamsOrWiden<TPath, string | Readable<string> | ReadableAtom<string>>\n | (() => string);\n query?: QueryParamsHint<\n TQueryParameters,\n string | Readable<string> | ReadableAtom<string> | (() => string)\n >;\n}) => {\n data: Readable<InferOr<TOutputSchema, undefined>>;\n loading: Readable<boolean>;\n error: Readable<FragnoClientError<TErrorCode[number]> | undefined>;\n};\n\nexport type FragnoSvelteMutator<\n _TMethod extends NonGetHTTPMethod,\n TPath extends string,\n TInputSchema extends StandardSchemaV1 | undefined,\n TOutputSchema extends StandardSchemaV1 | undefined,\n TErrorCode extends string,\n TQueryParameters extends string,\n> = () => {\n mutate: (args: {\n body?: InferOr<TInputSchema, undefined>;\n path?: MaybeExtractPathParamsOrWiden<\n TPath,\n string | Readable<string> | ReadableAtom<string> | (() => string)\n >;\n query?: QueryParamsHint<\n TQueryParameters,\n string | Readable<string> | ReadableAtom<string> | (() => string)\n >;\n }) => Promise<InferOr<TOutputSchema, undefined>>;\n loading: Readable<boolean | undefined>;\n error: Readable<FragnoClientError<TErrorCode[number]> | undefined>;\n data: Readable<InferOr<TOutputSchema, undefined>>;\n};\n\nfunction isReadable(value: unknown): value is Readable<string> {\n return typeof value === \"object\" && value !== null && \"subscribe\" in value;\n}\n\nfunction isCallable(value: unknown): value is () => string {\n return typeof value === \"function\";\n}\n\nexport function readableToAtom<T>(value: Readable<T>): ReadableAtom<T> {\n const a = atom(get(value));\n\n value.subscribe((newVal) => {\n a.set(newVal);\n });\n\n return a;\n}\n\nexport function runeToAtom<T>(value: () => T): ReadableAtom<T> {\n const a = atom(value());\n\n $effect(() => {\n a.set(value());\n });\n\n return a;\n}\n\nfunction createSvelteHook<\n TMethod extends \"GET\",\n TPath extends string,\n TOutputSchema extends StandardSchemaV1,\n TErrorCode extends string,\n TQueryParameters extends string,\n>(\n hook: FragnoClientHookData<TMethod, TPath, TOutputSchema, TErrorCode, TQueryParameters>,\n): FragnoSvelteHook<TMethod, TPath, TOutputSchema, TErrorCode, TQueryParameters> {\n return ({ path, query } = {}) => {\n const pathParams: Record<string, string | ReadableAtom<string>> = {};\n const queryParams: Record<string, string | ReadableAtom<string>> = {};\n\n for (const [key, value] of Object.entries(path ?? {})) {\n const v = value as string | Readable<string> | ReadableAtom<string> | (() => string);\n if (isCallable(v)) {\n pathParams[key] = runeToAtom(v);\n } else {\n pathParams[key] = isReadable(v) ? readableToAtom(v) : v;\n }\n }\n\n for (const [key, value] of Object.entries(query ?? {})) {\n const v = value as string | Readable<string> | ReadableAtom<string> | (() => string);\n if (isCallable(v)) {\n queryParams[key] = runeToAtom(v);\n } else {\n queryParams[key] = isReadable(v) ? readableToAtom(v) : v;\n }\n }\n\n const store = hook.store({\n path: pathParams as MaybeExtractPathParamsOrWiden<TPath, string | ReadableAtom<string>>,\n query: queryParams,\n });\n\n const data = writable<InferOr<TOutputSchema, undefined>>(undefined);\n const loading = writable<boolean>(false);\n const error = writable<FragnoClientError<TErrorCode[number]> | undefined>(undefined);\n\n const unsubscribe = store.subscribe((updatedStoreValue) => {\n data.set(updatedStoreValue.data as InferOr<TOutputSchema, undefined>);\n loading.set(updatedStoreValue.loading);\n error.set(updatedStoreValue.error);\n });\n\n onDestroy(() => {\n unsubscribe();\n });\n\n return {\n data,\n loading,\n error,\n };\n };\n}\n\nfunction createSvelteMutator<\n TMethod extends NonGetHTTPMethod,\n TPath extends string,\n TInputSchema extends StandardSchemaV1 | undefined,\n TOutputSchema extends StandardSchemaV1 | undefined,\n TErrorCode extends string,\n TQueryParameters extends string,\n>(\n hook: FragnoClientMutatorData<\n TMethod,\n TPath,\n TInputSchema,\n TOutputSchema,\n TErrorCode,\n TQueryParameters\n >,\n): FragnoSvelteMutator<TMethod, TPath, TInputSchema, TOutputSchema, TErrorCode, TQueryParameters> {\n return () => {\n const data = writable<InferOr<TOutputSchema, undefined>>(undefined);\n const loading = writable<boolean | undefined>(undefined);\n const error = writable<FragnoClientError<TErrorCode[number]> | undefined>(undefined);\n\n // Subscribe to the mutator store and sync with our Svelte stores\n const unsubscribe = hook.mutatorStore.subscribe((storeValue) => {\n data.set(storeValue.data as InferOr<TOutputSchema, undefined>);\n loading.set(storeValue.loading);\n error.set(storeValue.error);\n });\n\n onDestroy(() => {\n unsubscribe();\n });\n\n // Create a wrapped mutate function that handles Svelte readable stores\n const mutate = async (args: {\n body?: InferOr<TInputSchema, undefined>;\n path?: MaybeExtractPathParamsOrWiden<\n TPath,\n string | Readable<string> | ReadableAtom<string> | (() => string)\n >;\n query?: QueryParamsHint<\n TQueryParameters,\n string | Readable<string> | ReadableAtom<string> | (() => string)\n >;\n }) => {\n const { body, path, query } = args;\n\n const pathParams: Record<string, string | ReadableAtom<string>> = {};\n const queryParams: Record<string, string | ReadableAtom<string>> = {};\n\n for (const [key, value] of Object.entries(path ?? {})) {\n const v = value as string | Readable<string> | ReadableAtom<string>;\n pathParams[key] = isReadable(v) ? readableToAtom(v) : v;\n }\n\n for (const [key, value] of Object.entries(query ?? {})) {\n const v = value as string | Readable<string> | ReadableAtom<string>;\n queryParams[key] = isReadable(v) ? readableToAtom(v) : v;\n }\n\n // Call the store's mutate function with normalized params\n return hook.mutatorStore.mutate({\n body,\n path: pathParams as MaybeExtractPathParamsOrWiden<TPath, string | ReadableAtom<string>>,\n query: queryParams,\n });\n };\n\n return {\n mutate,\n loading,\n error,\n data,\n };\n };\n}\n\nexport function createSvelteStore<T extends object>(hook: FragnoStoreData<T>): T {\n // Since nanostores already implement Svelte's store contract,\n // we can return the store object directly for use with $ syntax\n return hook.obj;\n}\n\nexport function useFragno<T extends Record<string, unknown>>(\n clientObj: T,\n): {\n [K in keyof T]: T[K] extends FragnoClientHookData<\n \"GET\",\n infer TPath,\n infer TOutputSchema,\n infer TErrorCode,\n infer TQueryParameters\n >\n ? FragnoSvelteHook<\"GET\", TPath, TOutputSchema, TErrorCode, TQueryParameters>\n : T[K] extends FragnoClientMutatorData<\n infer M,\n infer TPath,\n infer TInputSchema,\n infer TOutputSchema,\n infer TErrorCode,\n infer TQueryParameters\n >\n ? FragnoSvelteMutator<M, TPath, TInputSchema, TOutputSchema, TErrorCode, TQueryParameters>\n : T[K] extends FragnoStoreData<infer TStoreObj>\n ? TStoreObj\n : T[K];\n} {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const result = {} as any;\n\n for (const key in clientObj) {\n if (!Object.prototype.hasOwnProperty.call(clientObj, key)) {\n continue;\n }\n\n const hook = clientObj[key];\n if (isGetHook(hook)) {\n result[key] = createSvelteHook(hook);\n } else if (isMutatorHook(hook)) {\n result[key] = createSvelteMutator(hook);\n } else if (isStore(hook)) {\n result[key] = createSvelteStore(hook);\n } else {\n // Pass through non-hook values unchanged\n result[key] = hook;\n }\n }\n\n return result;\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { ExtractPathParamsOrWiden, HasPathParams, InferOr, MaybeExtractPathParamsOrWiden, NonGetHTTPMethod, QueryParamsHint } from "../api-CBDGZiLC.js";
|
|
2
|
+
import { FragnoClientError, FragnoClientHookData, FragnoClientMutatorData, FragnoStoreData } from "../client-XFdAy-IQ.js";
|
|
3
|
+
import { ReadableAtom, Store, StoreValue } from "nanostores";
|
|
4
|
+
import { FetcherValue } from "@nanostores/query";
|
|
5
|
+
import * as react0 from "react";
|
|
6
|
+
import { DependencyList } from "react";
|
|
7
|
+
import { StandardSchemaV1 } from "@standard-schema/spec";
|
|
8
|
+
|
|
9
|
+
//#region src/client/react.d.ts
|
|
10
|
+
|
|
11
|
+
type FragnoReactHook<_TMethod extends "GET", TPath extends string, TOutputSchema extends StandardSchemaV1, TErrorCode extends string, TQueryParameters extends string> = (args?: {
|
|
12
|
+
path?: MaybeExtractPathParamsOrWiden<TPath, string | ReadableAtom<string>>;
|
|
13
|
+
query?: QueryParamsHint<TQueryParameters, string | ReadableAtom<string>>;
|
|
14
|
+
}) => FetcherValue<StandardSchemaV1.InferOutput<TOutputSchema>, FragnoClientError<NonNullable<TErrorCode>>>;
|
|
15
|
+
type FragnoReactMutator<_TMethod extends NonGetHTTPMethod, TPath extends string, TInputSchema extends StandardSchemaV1 | undefined, TOutputSchema extends StandardSchemaV1 | undefined, TErrorCode extends string, TQueryParameters extends string> = () => {
|
|
16
|
+
mutate: ({
|
|
17
|
+
body,
|
|
18
|
+
path,
|
|
19
|
+
query
|
|
20
|
+
}: {
|
|
21
|
+
body?: InferOr<TInputSchema, undefined>;
|
|
22
|
+
path?: HasPathParams<TPath> extends true ? ExtractPathParamsOrWiden<TPath, string | ReadableAtom<string>> : undefined;
|
|
23
|
+
query?: QueryParamsHint<TQueryParameters, string | ReadableAtom<string>>;
|
|
24
|
+
}) => Promise<InferOr<TOutputSchema, undefined>>;
|
|
25
|
+
loading?: boolean | undefined;
|
|
26
|
+
error?: FragnoClientError<NonNullable<TErrorCode>[number]> | undefined;
|
|
27
|
+
data?: InferOr<TOutputSchema, undefined> | undefined;
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Type helper that unwraps any Store fields of the object into StoreValues
|
|
31
|
+
*/
|
|
32
|
+
type FragnoReactStore<T extends object> = () => T extends Store<infer TStore> ? StoreValue<TStore> : { [K in keyof T]: T[K] extends Store ? StoreValue<T[K]> : T[K] };
|
|
33
|
+
declare function useFragno<T extends Record<string, unknown>>(clientObj: T): { [K in keyof T]: T[K] extends FragnoClientHookData<"GET", infer TPath, infer TOutputSchema, infer TErrorCode, infer TQueryParameters> ? FragnoReactHook<"GET", TPath, TOutputSchema, TErrorCode, TQueryParameters> : T[K] extends FragnoClientMutatorData<infer TMethod, infer TPath, infer TInput, infer TOutput, infer TError, infer TQueryParameters> ? FragnoReactMutator<TMethod, TPath, TInput, TOutput, TError, TQueryParameters> : T[K] extends FragnoStoreData<infer TStoreObj> ? FragnoReactStore<TStoreObj> : T[K] };
|
|
34
|
+
type StoreKeys<T> = T extends {
|
|
35
|
+
setKey: (k: infer K, v: unknown) => unknown;
|
|
36
|
+
} ? K : never;
|
|
37
|
+
interface UseStoreOptions<SomeStore> {
|
|
38
|
+
/**
|
|
39
|
+
* @default
|
|
40
|
+
* ```ts
|
|
41
|
+
* [store, options.keys]
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
deps?: DependencyList;
|
|
45
|
+
/**
|
|
46
|
+
* Will re-render components only on specific key changes.
|
|
47
|
+
*/
|
|
48
|
+
keys?: StoreKeys<SomeStore>[];
|
|
49
|
+
}
|
|
50
|
+
declare function useStore<SomeStore extends Store>(store: SomeStore, options?: UseStoreOptions<SomeStore>): StoreValue<SomeStore>;
|
|
51
|
+
declare function FragnoHydrator({
|
|
52
|
+
children
|
|
53
|
+
}: {
|
|
54
|
+
children: React.ReactNode;
|
|
55
|
+
}): react0.ReactNode;
|
|
56
|
+
//#endregion
|
|
57
|
+
export { FragnoHydrator, FragnoReactHook, FragnoReactMutator, FragnoReactStore, UseStoreOptions, useFragno, useStore };
|
|
58
|
+
//# sourceMappingURL=react.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"react.d.ts","names":[],"sources":["../../src/client/react.ts"],"sourcesContent":[],"mappings":"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"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import "../api-DgHfYjq2.js";
|
|
2
|
+
import "../route-Bp6eByhz.js";
|
|
3
|
+
import { isGetHook, isMutatorHook, isReadableAtom, isStore } from "../client-DWjxKDnE.js";
|
|
4
|
+
import { hydrateFromWindow } from "../ssr-tJHqcNSw.js";
|
|
5
|
+
import { listenKeys } from "nanostores";
|
|
6
|
+
import { useCallback, useMemo, useRef, useSyncExternalStore } from "react";
|
|
7
|
+
|
|
8
|
+
//#region src/client/react.ts
|
|
9
|
+
function createReactHook(hook) {
|
|
10
|
+
return ({ path, query } = {}) => {
|
|
11
|
+
const pathParamValues = path ? Object.values(path) : [];
|
|
12
|
+
const queryParamValues = query ? Object.values(query) : [];
|
|
13
|
+
const deps = [...pathParamValues, ...queryParamValues];
|
|
14
|
+
const store = useMemo(() => hook.store({
|
|
15
|
+
path,
|
|
16
|
+
query
|
|
17
|
+
}), [hook, ...deps]);
|
|
18
|
+
if (typeof window === "undefined") return store.get();
|
|
19
|
+
return useStore(store);
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
function createReactMutator(hook) {
|
|
23
|
+
return () => {
|
|
24
|
+
const store = useMemo(() => hook.mutatorStore, [hook]);
|
|
25
|
+
return useStore(store);
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
function createReactStore(hook) {
|
|
29
|
+
if (isReadableAtom(hook.obj)) return () => useStore(hook.obj);
|
|
30
|
+
return () => {
|
|
31
|
+
const result = {};
|
|
32
|
+
for (const key in hook.obj) {
|
|
33
|
+
if (!Object.prototype.hasOwnProperty.call(hook.obj, key)) continue;
|
|
34
|
+
const value = hook.obj[key];
|
|
35
|
+
if (isReadableAtom(value)) result[key] = useStore(value);
|
|
36
|
+
else result[key] = value;
|
|
37
|
+
}
|
|
38
|
+
return result;
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
function useFragno(clientObj) {
|
|
42
|
+
const result = {};
|
|
43
|
+
for (const key in clientObj) {
|
|
44
|
+
if (!Object.prototype.hasOwnProperty.call(clientObj, key)) continue;
|
|
45
|
+
const hook = clientObj[key];
|
|
46
|
+
if (isGetHook(hook)) result[key] = createReactHook(hook);
|
|
47
|
+
else if (isMutatorHook(hook)) result[key] = createReactMutator(hook);
|
|
48
|
+
else if (isStore(hook)) result[key] = createReactStore(hook);
|
|
49
|
+
else result[key] = hook;
|
|
50
|
+
}
|
|
51
|
+
return result;
|
|
52
|
+
}
|
|
53
|
+
function useStore(store, options = {}) {
|
|
54
|
+
const snapshotRef = useRef(store.get());
|
|
55
|
+
const { keys, deps = [store, keys] } = options;
|
|
56
|
+
const subscribe = useCallback((onChange) => {
|
|
57
|
+
const emitChange = (value) => {
|
|
58
|
+
if (snapshotRef.current === value) return;
|
|
59
|
+
snapshotRef.current = value;
|
|
60
|
+
onChange();
|
|
61
|
+
};
|
|
62
|
+
emitChange(store.value);
|
|
63
|
+
if (keys?.length) return listenKeys(store, keys, emitChange);
|
|
64
|
+
return store.listen(emitChange);
|
|
65
|
+
}, deps);
|
|
66
|
+
const get = () => snapshotRef.current;
|
|
67
|
+
return useSyncExternalStore(subscribe, get, () => {
|
|
68
|
+
return get();
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
function FragnoHydrator({ children }) {
|
|
72
|
+
useMemo(() => {
|
|
73
|
+
hydrateFromWindow();
|
|
74
|
+
}, []);
|
|
75
|
+
return children;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
//#endregion
|
|
79
|
+
export { FragnoHydrator, useFragno, useStore };
|
|
80
|
+
//# sourceMappingURL=react.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"react.js","names":["result: any"],"sources":["../../src/client/react.ts"],"sourcesContent":["import type { FetcherValue } from \"@nanostores/query\";\nimport type { StandardSchemaV1 } from \"@standard-schema/spec\";\nimport { listenKeys, type ReadableAtom, type Store, type StoreValue } from \"nanostores\";\nimport { useCallback, useMemo, useRef, useSyncExternalStore, type DependencyList } from \"react\";\nimport type { NonGetHTTPMethod } from \"../api/api\";\nimport type { FragnoClientMutatorData, FragnoClientHookData } from \"./client\";\nimport { isGetHook, isMutatorHook, isStore, type FragnoStoreData } from \"./client\";\nimport type { FragnoClientError } from \"./client-error\";\nimport { hydrateFromWindow } from \"../util/ssr\";\nimport type { InferOr } from \"../util/types-util\";\nimport type {\n ExtractPathParamsOrWiden,\n HasPathParams,\n MaybeExtractPathParamsOrWiden,\n QueryParamsHint,\n} from \"../api/internal/path\";\nimport { isReadableAtom } from \"../util/nanostores\";\n\nexport type FragnoReactHook<\n _TMethod extends \"GET\",\n TPath extends string,\n TOutputSchema extends StandardSchemaV1,\n TErrorCode extends string,\n TQueryParameters extends string,\n> = (args?: {\n path?: MaybeExtractPathParamsOrWiden<TPath, string | ReadableAtom<string>>;\n query?: QueryParamsHint<TQueryParameters, string | ReadableAtom<string>>;\n}) => FetcherValue<\n StandardSchemaV1.InferOutput<TOutputSchema>,\n FragnoClientError<NonNullable<TErrorCode>>\n>;\n\nexport type FragnoReactMutator<\n _TMethod extends NonGetHTTPMethod,\n TPath extends string,\n TInputSchema extends StandardSchemaV1 | undefined,\n TOutputSchema extends StandardSchemaV1 | undefined,\n TErrorCode extends string,\n TQueryParameters extends string,\n> = () => {\n mutate: ({\n body,\n path,\n query,\n }: {\n body?: InferOr<TInputSchema, undefined>;\n path?: HasPathParams<TPath> extends true\n ? ExtractPathParamsOrWiden<TPath, string | ReadableAtom<string>>\n : undefined;\n query?: QueryParamsHint<TQueryParameters, string | ReadableAtom<string>>;\n }) => Promise<InferOr<TOutputSchema, undefined>>;\n loading?: boolean | undefined;\n error?: FragnoClientError<NonNullable<TErrorCode>[number]> | undefined;\n data?: InferOr<TOutputSchema, undefined> | undefined;\n};\n\n// Helper function to create a React hook from a GET hook\nfunction createReactHook<\n TMethod extends \"GET\",\n TPath extends string,\n TOutputSchema extends StandardSchemaV1,\n TErrorCode extends string,\n TQueryParameters extends string,\n>(\n hook: FragnoClientHookData<TMethod, TPath, TOutputSchema, TErrorCode, TQueryParameters>,\n): FragnoReactHook<TMethod, TPath, TOutputSchema, TErrorCode, TQueryParameters> {\n return ({ path, query } = {}) => {\n const pathParamValues = path ? Object.values(path) : [];\n const queryParamValues = query ? Object.values(query) : [];\n\n const deps = [...pathParamValues, ...queryParamValues];\n\n const store = useMemo(() => hook.store({ path, query }), [hook, ...deps]);\n\n if (typeof window === \"undefined\") {\n // TODO(Wilco): Handle server-side rendering. In React we have to implement onShellReady\n // and onAllReady in renderToPipable stream.\n const serverSideData = store.get();\n return serverSideData;\n }\n\n return useStore(store);\n };\n}\n\n// Helper function to create a React mutator from a mutator hook\nfunction createReactMutator<\n TMethod extends NonGetHTTPMethod,\n TPath extends string,\n TInput extends StandardSchemaV1 | undefined,\n TOutput extends StandardSchemaV1 | undefined,\n TError extends string,\n TQueryParameters extends string,\n>(\n hook: FragnoClientMutatorData<TMethod, TPath, TInput, TOutput, TError, TQueryParameters>,\n): FragnoReactMutator<TMethod, TPath, TInput, TOutput, TError, TQueryParameters> {\n return () => {\n const store = useMemo(() => hook.mutatorStore, [hook]);\n return useStore(store);\n };\n}\n\n/**\n * Type helper that unwraps any Store fields of the object into StoreValues\n */\nexport type FragnoReactStore<T extends object> = () => T extends Store<infer TStore>\n ? StoreValue<TStore>\n : {\n [K in keyof T]: T[K] extends Store ? StoreValue<T[K]> : T[K];\n };\n\nfunction createReactStore<const T extends object>(hook: FragnoStoreData<T>): FragnoReactStore<T> {\n if (isReadableAtom(hook.obj)) {\n return () => useStore(hook.obj as Store);\n }\n\n return () => {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const result: any = {};\n\n for (const key in hook.obj) {\n if (!Object.prototype.hasOwnProperty.call(hook.obj, key)) {\n continue;\n }\n\n const value = hook.obj[key];\n if (isReadableAtom(value)) {\n result[key] = useStore(value);\n } else {\n result[key] = value;\n }\n }\n\n return result;\n };\n}\n\nexport function useFragno<T extends Record<string, unknown>>(\n clientObj: T,\n): {\n [K in keyof T]: T[K] extends FragnoClientHookData<\n \"GET\",\n infer TPath,\n infer TOutputSchema,\n infer TErrorCode,\n infer TQueryParameters\n >\n ? FragnoReactHook<\"GET\", TPath, TOutputSchema, TErrorCode, TQueryParameters>\n : T[K] extends FragnoClientMutatorData<\n infer TMethod,\n infer TPath,\n infer TInput,\n infer TOutput,\n infer TError,\n infer TQueryParameters\n >\n ? FragnoReactMutator<TMethod, TPath, TInput, TOutput, TError, TQueryParameters>\n : T[K] extends FragnoStoreData<infer TStoreObj>\n ? FragnoReactStore<TStoreObj>\n : T[K];\n} {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const result = {} as any; // We need one any cast here due to TypeScript's limitations with mapped types\n\n for (const key in clientObj) {\n if (!Object.prototype.hasOwnProperty.call(clientObj, key)) {\n continue;\n }\n\n const hook = clientObj[key];\n if (isGetHook(hook)) {\n result[key] = createReactHook(hook);\n } else if (isMutatorHook(hook)) {\n result[key] = createReactMutator(hook);\n } else if (isStore(hook)) {\n result[key] = createReactStore(hook);\n } else {\n // Pass through non-hook values unchanged\n result[key] = hook;\n }\n }\n\n return result;\n}\n\ntype StoreKeys<T> = T extends { setKey: (k: infer K, v: unknown) => unknown } ? K : never;\n\nexport interface UseStoreOptions<SomeStore> {\n /**\n * @default\n * ```ts\n * [store, options.keys]\n * ```\n */\n deps?: DependencyList;\n\n /**\n * Will re-render components only on specific key changes.\n */\n keys?: StoreKeys<SomeStore>[];\n}\n\nexport function useStore<SomeStore extends Store>(\n store: SomeStore,\n options: UseStoreOptions<SomeStore> = {},\n): StoreValue<SomeStore> {\n const snapshotRef = useRef<StoreValue<SomeStore>>(store.get());\n\n const { keys, deps = [store, keys] } = options;\n\n const subscribe = useCallback((onChange: () => void) => {\n const emitChange = (value: StoreValue<SomeStore>) => {\n if (snapshotRef.current === value) return;\n snapshotRef.current = value;\n onChange();\n };\n\n emitChange(store.value);\n if (keys?.length) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return listenKeys(store as any, keys, emitChange);\n }\n return store.listen(emitChange);\n }, deps);\n\n const get = () => snapshotRef.current as StoreValue<SomeStore>;\n\n return useSyncExternalStore(subscribe, get, () => {\n // Server-side rendering\n return get();\n });\n}\n\nexport function FragnoHydrator({ children }: { children: React.ReactNode }) {\n // Ensure initial data is transferred from window before any hooks run\n // Running in useMemo makes this happen during render, ahead of effects\n useMemo(() => {\n hydrateFromWindow();\n }, []);\n return children;\n}\n"],"mappings":";;;;;;;;AAyDA,SAAS,gBAOP,MAC8E;AAC9E,SAAQ,EAAE,MAAM,UAAU,EAAE,KAAK;EAC/B,MAAM,kBAAkB,OAAO,OAAO,OAAO,KAAK,GAAG,EAAE;EACvD,MAAM,mBAAmB,QAAQ,OAAO,OAAO,MAAM,GAAG,EAAE;EAE1D,MAAM,OAAO,CAAC,GAAG,iBAAiB,GAAG,iBAAiB;EAEtD,MAAM,QAAQ,cAAc,KAAK,MAAM;GAAE;GAAM;GAAO,CAAC,EAAE,CAAC,MAAM,GAAG,KAAK,CAAC;AAEzE,MAAI,OAAO,WAAW,YAIpB,QADuB,MAAM,KAAK;AAIpC,SAAO,SAAS,MAAM;;;AAK1B,SAAS,mBAQP,MAC+E;AAC/E,cAAa;EACX,MAAM,QAAQ,cAAc,KAAK,cAAc,CAAC,KAAK,CAAC;AACtD,SAAO,SAAS,MAAM;;;AAa1B,SAAS,iBAAyC,MAA+C;AAC/F,KAAI,eAAe,KAAK,IAAI,CAC1B,cAAa,SAAS,KAAK,IAAa;AAG1C,cAAa;EAEX,MAAMA,SAAc,EAAE;AAEtB,OAAK,MAAM,OAAO,KAAK,KAAK;AAC1B,OAAI,CAAC,OAAO,UAAU,eAAe,KAAK,KAAK,KAAK,IAAI,CACtD;GAGF,MAAM,QAAQ,KAAK,IAAI;AACvB,OAAI,eAAe,MAAM,CACvB,QAAO,OAAO,SAAS,MAAM;OAE7B,QAAO,OAAO;;AAIlB,SAAO;;;AAIX,SAAgB,UACd,WAsBA;CAEA,MAAM,SAAS,EAAE;AAEjB,MAAK,MAAM,OAAO,WAAW;AAC3B,MAAI,CAAC,OAAO,UAAU,eAAe,KAAK,WAAW,IAAI,CACvD;EAGF,MAAM,OAAO,UAAU;AACvB,MAAI,UAAU,KAAK,CACjB,QAAO,OAAO,gBAAgB,KAAK;WAC1B,cAAc,KAAK,CAC5B,QAAO,OAAO,mBAAmB,KAAK;WAC7B,QAAQ,KAAK,CACtB,QAAO,OAAO,iBAAiB,KAAK;MAGpC,QAAO,OAAO;;AAIlB,QAAO;;AAoBT,SAAgB,SACd,OACA,UAAsC,EAAE,EACjB;CACvB,MAAM,cAAc,OAA8B,MAAM,KAAK,CAAC;CAE9D,MAAM,EAAE,MAAM,OAAO,CAAC,OAAO,KAAK,KAAK;CAEvC,MAAM,YAAY,aAAa,aAAyB;EACtD,MAAM,cAAc,UAAiC;AACnD,OAAI,YAAY,YAAY,MAAO;AACnC,eAAY,UAAU;AACtB,aAAU;;AAGZ,aAAW,MAAM,MAAM;AACvB,MAAI,MAAM,OAER,QAAO,WAAW,OAAc,MAAM,WAAW;AAEnD,SAAO,MAAM,OAAO,WAAW;IAC9B,KAAK;CAER,MAAM,YAAY,YAAY;AAE9B,QAAO,qBAAqB,WAAW,WAAW;AAEhD,SAAO,KAAK;GACZ;;AAGJ,SAAgB,eAAe,EAAE,YAA2C;AAG1E,eAAc;AACZ,qBAAmB;IAClB,EAAE,CAAC;AACN,QAAO"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { ExtractPathParamsOrWiden, HasPathParams, InferOr, MaybeExtractPathParamsOrWiden, NonGetHTTPMethod } from "../api-CBDGZiLC.js";
|
|
2
|
+
import { FragnoClientError, FragnoClientHookData, FragnoClientMutatorData } from "../client-XFdAy-IQ.js";
|
|
3
|
+
import { ReadableAtom } from "nanostores";
|
|
4
|
+
import { StandardSchemaV1 } from "@standard-schema/spec";
|
|
5
|
+
|
|
6
|
+
//#region src/client/vanilla.d.ts
|
|
7
|
+
|
|
8
|
+
type StoreData<TOutputSchema extends StandardSchemaV1 | undefined, TErrorCodes extends string> = {
|
|
9
|
+
loading: boolean;
|
|
10
|
+
error?: FragnoClientError<TErrorCodes>;
|
|
11
|
+
data?: InferOr<TOutputSchema, undefined>;
|
|
12
|
+
};
|
|
13
|
+
type FragnoVanillaListeners<_TMethod extends "GET", TPath extends string, TOutputSchema extends StandardSchemaV1, TErrorCode extends string, TQueryParameters extends string> = (args?: {
|
|
14
|
+
path?: MaybeExtractPathParamsOrWiden<TPath, string | ReadableAtom<string>>;
|
|
15
|
+
query?: Record<TQueryParameters, string | ReadableAtom<string>>;
|
|
16
|
+
}) => {
|
|
17
|
+
/** Called for every change in the store. */
|
|
18
|
+
listen: (callback: (value: StoreData<TOutputSchema, TErrorCode[number]>) => void) => () => void;
|
|
19
|
+
/** Called once initially, then called for every change in the store. */
|
|
20
|
+
subscribe: (callback: (value: StoreData<TOutputSchema, TErrorCode[number]>) => void) => () => void;
|
|
21
|
+
get: () => StoreData<TOutputSchema, TErrorCode[number]>;
|
|
22
|
+
refetch: () => void;
|
|
23
|
+
/**
|
|
24
|
+
* Produces an item for every change in the store.
|
|
25
|
+
* Note: the iterator does NOT return.
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```typescript
|
|
29
|
+
* const store = useFragno(clientObj).store;
|
|
30
|
+
* for await (const value of store[Symbol.asyncIterator]()) {
|
|
31
|
+
* console.log(value);
|
|
32
|
+
* }
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
[Symbol.asyncIterator]: () => AsyncGenerator<StoreData<TOutputSchema, TErrorCode[number]>, void, unknown>;
|
|
36
|
+
};
|
|
37
|
+
type FragnoVanillaMutator<_TMethod extends NonGetHTTPMethod, TPath extends string, TInputSchema extends StandardSchemaV1 | undefined, TOutputSchema extends StandardSchemaV1 | undefined, TErrorCode extends string, TQueryParameters extends string> = (args?: {
|
|
38
|
+
path?: MaybeExtractPathParamsOrWiden<TPath, string | ReadableAtom<string>>;
|
|
39
|
+
query?: Record<TQueryParameters, string | ReadableAtom<string>>;
|
|
40
|
+
}) => {
|
|
41
|
+
subscribe: (callback: (value: {
|
|
42
|
+
loading: boolean;
|
|
43
|
+
error?: FragnoClientError<TErrorCode[number]>;
|
|
44
|
+
data?: InferOr<TOutputSchema, undefined>;
|
|
45
|
+
}) => void) => () => void;
|
|
46
|
+
get: () => StoreData<TOutputSchema, TErrorCode[number]>;
|
|
47
|
+
mutate: ({
|
|
48
|
+
body,
|
|
49
|
+
path,
|
|
50
|
+
query
|
|
51
|
+
}: {
|
|
52
|
+
body?: InferOr<TInputSchema, undefined>;
|
|
53
|
+
path?: HasPathParams<TPath> extends true ? ExtractPathParamsOrWiden<TPath, string | ReadableAtom<string>> : undefined;
|
|
54
|
+
query?: Record<string, string | ReadableAtom<string>>;
|
|
55
|
+
}) => Promise<InferOr<TOutputSchema, undefined>>;
|
|
56
|
+
[Symbol.asyncIterator]: () => AsyncGenerator<StoreData<TOutputSchema, TErrorCode[number]>, void, unknown>;
|
|
57
|
+
};
|
|
58
|
+
declare function useFragno<T extends Record<string, unknown>>(clientObj: T): { [K in keyof T]: T[K] extends FragnoClientHookData<"GET", infer TPath, infer TOutputSchema, infer TErrorCode, infer TQueryParameters> ? FragnoVanillaListeners<"GET", TPath, TOutputSchema, TErrorCode, TQueryParameters> : T[K] extends FragnoClientMutatorData<NonGetHTTPMethod, infer TPath, infer TInputSchema, infer TOutputSchema, infer TErrorCode, infer TQueryParameters> ? FragnoVanillaMutator<NonGetHTTPMethod, TPath, TInputSchema, TOutputSchema, TErrorCode, TQueryParameters> : T[K] };
|
|
59
|
+
//#endregion
|
|
60
|
+
export { FragnoVanillaListeners, FragnoVanillaMutator, StoreData, useFragno };
|
|
61
|
+
//# sourceMappingURL=vanilla.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vanilla.d.ts","names":[],"sources":["../../src/client/vanilla.ts"],"sourcesContent":[],"mappings":"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"}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import "../api-DgHfYjq2.js";
|
|
2
|
+
import "../route-Bp6eByhz.js";
|
|
3
|
+
import { isGetHook, isMutatorHook } from "../client-DWjxKDnE.js";
|
|
4
|
+
import "../ssr-tJHqcNSw.js";
|
|
5
|
+
|
|
6
|
+
//#region src/util/async.ts
|
|
7
|
+
/**
|
|
8
|
+
* Creates an async iterator from a subscribe function that follows the observable pattern.
|
|
9
|
+
*
|
|
10
|
+
* @template T The type of values produced by the store.
|
|
11
|
+
* @param subscribe A function that subscribes to store updates. It receives a callback to be
|
|
12
|
+
* called on each update, and returns an unsubscribe function.
|
|
13
|
+
* @returns An async generator that yields store values as they are produced.
|
|
14
|
+
*/
|
|
15
|
+
function createAsyncIteratorFromCallback(subscribe) {
|
|
16
|
+
const queue = [];
|
|
17
|
+
let unsubscribe = null;
|
|
18
|
+
let resolveNext = null;
|
|
19
|
+
const unsubscribeFunc = subscribe((value) => {
|
|
20
|
+
if (resolveNext) {
|
|
21
|
+
resolveNext({
|
|
22
|
+
value,
|
|
23
|
+
done: false
|
|
24
|
+
});
|
|
25
|
+
resolveNext = null;
|
|
26
|
+
} else queue.push(value);
|
|
27
|
+
});
|
|
28
|
+
if (typeof unsubscribeFunc === "function") unsubscribe = unsubscribeFunc;
|
|
29
|
+
return (async function* () {
|
|
30
|
+
try {
|
|
31
|
+
while (true) if (queue.length > 0) yield queue.shift();
|
|
32
|
+
else yield await new Promise((resolve) => {
|
|
33
|
+
resolveNext = (result) => {
|
|
34
|
+
if (!result.done) resolve(result.value);
|
|
35
|
+
};
|
|
36
|
+
});
|
|
37
|
+
} finally {
|
|
38
|
+
if (unsubscribe) unsubscribe();
|
|
39
|
+
}
|
|
40
|
+
})();
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
//#endregion
|
|
44
|
+
//#region src/client/vanilla.ts
|
|
45
|
+
function createVanillaListeners(hook) {
|
|
46
|
+
return ({ path, query } = {}) => {
|
|
47
|
+
const store = hook.store({
|
|
48
|
+
path,
|
|
49
|
+
query
|
|
50
|
+
});
|
|
51
|
+
return {
|
|
52
|
+
listen: (callback) => {
|
|
53
|
+
return store.listen(({ loading, error, data }) => callback({
|
|
54
|
+
loading,
|
|
55
|
+
error,
|
|
56
|
+
data
|
|
57
|
+
}));
|
|
58
|
+
},
|
|
59
|
+
subscribe: (callback) => {
|
|
60
|
+
return store.subscribe(({ loading, error, data }) => callback({
|
|
61
|
+
loading,
|
|
62
|
+
error,
|
|
63
|
+
data
|
|
64
|
+
}));
|
|
65
|
+
},
|
|
66
|
+
refetch: () => {
|
|
67
|
+
return store.revalidate();
|
|
68
|
+
},
|
|
69
|
+
get: () => {
|
|
70
|
+
return store.get();
|
|
71
|
+
},
|
|
72
|
+
[Symbol.asyncIterator]() {
|
|
73
|
+
return createAsyncIteratorFromCallback((callback) => store.listen(({ loading, error, data }) => callback({
|
|
74
|
+
loading,
|
|
75
|
+
error,
|
|
76
|
+
data
|
|
77
|
+
})));
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
function createVanillaMutator(hook) {
|
|
83
|
+
return () => {
|
|
84
|
+
const store = hook.mutatorStore;
|
|
85
|
+
return {
|
|
86
|
+
subscribe: (callback) => {
|
|
87
|
+
return store.subscribe((value) => {
|
|
88
|
+
callback({
|
|
89
|
+
loading: value.loading ?? false,
|
|
90
|
+
error: value.error,
|
|
91
|
+
data: value.data
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
},
|
|
95
|
+
get: () => {
|
|
96
|
+
const { loading, error, data } = store.get();
|
|
97
|
+
return {
|
|
98
|
+
loading: loading ?? false,
|
|
99
|
+
error,
|
|
100
|
+
data
|
|
101
|
+
};
|
|
102
|
+
},
|
|
103
|
+
mutate: ({ body, path, query }) => {
|
|
104
|
+
return store.mutate({
|
|
105
|
+
body,
|
|
106
|
+
path,
|
|
107
|
+
query
|
|
108
|
+
});
|
|
109
|
+
},
|
|
110
|
+
[Symbol.asyncIterator]() {
|
|
111
|
+
return createAsyncIteratorFromCallback((callback) => store.listen((value) => {
|
|
112
|
+
callback({
|
|
113
|
+
loading: value.loading ?? false,
|
|
114
|
+
error: value.error,
|
|
115
|
+
data: value.data
|
|
116
|
+
});
|
|
117
|
+
}));
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
function useFragno(clientObj) {
|
|
123
|
+
const result = {};
|
|
124
|
+
for (const key in clientObj) {
|
|
125
|
+
if (!Object.prototype.hasOwnProperty.call(clientObj, key)) continue;
|
|
126
|
+
const hook = clientObj[key];
|
|
127
|
+
if (isGetHook(hook)) result[key] = createVanillaListeners(hook);
|
|
128
|
+
else if (isMutatorHook(hook)) result[key] = createVanillaMutator(hook);
|
|
129
|
+
else result[key] = hook;
|
|
130
|
+
}
|
|
131
|
+
return result;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
//#endregion
|
|
135
|
+
export { useFragno };
|
|
136
|
+
//# sourceMappingURL=vanilla.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vanilla.js","names":["queue: T[]","unsubscribe: UnsubscribeFn | null","resolveNext: ((value: IteratorResult<T>) => void) | null"],"sources":["../../src/util/async.ts","../../src/client/vanilla.ts"],"sourcesContent":["type SubscribeFn<T> = (callback: (value: T) => void) => UnsubscribeFn | void;\ntype UnsubscribeFn = () => void;\n\n/**\n * Creates an async iterator from a subscribe function that follows the observable pattern.\n *\n * @template T The type of values produced by the store.\n * @param subscribe A function that subscribes to store updates. It receives a callback to be\n * called on each update, and returns an unsubscribe function.\n * @returns An async generator that yields store values as they are produced.\n */\nexport function createAsyncIteratorFromCallback<T>(\n subscribe: SubscribeFn<T>,\n): AsyncGenerator<T, void, unknown> {\n const queue: T[] = [];\n let unsubscribe: UnsubscribeFn | null = null;\n let resolveNext: ((value: IteratorResult<T>) => void) | null = null;\n\n const unsubscribeFunc = subscribe((value) => {\n if (resolveNext) {\n // If there's a pending promise, resolve it immediately\n resolveNext({ value, done: false });\n resolveNext = null;\n } else {\n // Otherwise, queue the value\n queue.push(value);\n }\n });\n\n // Store unsubscribe function if one was returned\n if (typeof unsubscribeFunc === \"function\") {\n unsubscribe = unsubscribeFunc;\n }\n\n return (async function* () {\n try {\n while (true) {\n if (queue.length > 0) {\n // Yield queued values\n yield queue.shift()!;\n } else {\n // Wait for the next value\n yield await new Promise<T>((resolve) => {\n resolveNext = (result) => {\n if (!result.done) {\n resolve(result.value);\n }\n };\n });\n }\n }\n } finally {\n // Clean up subscription on iterator termination\n if (unsubscribe) {\n unsubscribe();\n }\n }\n })();\n}\n\n/**\n * Waits for an async iterator to yield a value that meets a condition.\n *\n * @template T The type of values produced by the iterator.\n * @param iterable The async iterable to wait for.\n * @param condition A function that checks if a value meets the condition.\n * @param options Optional configuration options.\n * @returns A promise that resolves to the first value that meets the condition.\n */\nexport async function waitForAsyncIterator<T>(\n iterable: AsyncIterable<T>,\n condition: (value: T) => boolean,\n options: { timeout?: number } = {},\n): Promise<T> {\n const { timeout = 1000 } = options;\n\n // Create a timeout promise that rejects after the specified time\n const timeoutPromise = new Promise<never>((_, reject) => {\n setTimeout(() => {\n reject(new Error(`waitForAsyncIterator: Timeout after ${timeout}ms`));\n }, timeout);\n });\n\n // Create a promise that resolves when the condition is met\n const iteratorPromise = (async () => {\n for await (const value of iterable) {\n if (condition(value)) {\n return value;\n }\n }\n throw new Error(\"waitForAsyncIterator: Iterator completed without meeting condition\");\n })();\n\n // Race between the timeout and the iterator\n return Promise.race([iteratorPromise, timeoutPromise]);\n}\n","import type { StandardSchemaV1 } from \"@standard-schema/spec\";\nimport type { ReadableAtom } from \"nanostores\";\nimport type { NonGetHTTPMethod } from \"../api/api\";\nimport {\n isGetHook,\n isMutatorHook,\n type FragnoClientMutatorData,\n type FragnoClientHookData,\n} from \"./client\";\nimport type { FragnoClientError } from \"./client-error\";\nimport { createAsyncIteratorFromCallback } from \"../util/async\";\nimport type { InferOr } from \"../util/types-util\";\nimport type {\n ExtractPathParamsOrWiden,\n HasPathParams,\n MaybeExtractPathParamsOrWiden,\n} from \"../api/internal/path\";\n\nexport type StoreData<\n TOutputSchema extends StandardSchemaV1 | undefined,\n TErrorCodes extends string,\n> = {\n loading: boolean;\n error?: FragnoClientError<TErrorCodes>;\n data?: InferOr<TOutputSchema, undefined>;\n};\n\nexport type FragnoVanillaListeners<\n _TMethod extends \"GET\",\n TPath extends string,\n TOutputSchema extends StandardSchemaV1,\n TErrorCode extends string,\n TQueryParameters extends string,\n> = (args?: {\n path?: MaybeExtractPathParamsOrWiden<TPath, string | ReadableAtom<string>>;\n query?: Record<TQueryParameters, string | ReadableAtom<string>>;\n}) => {\n /** Called for every change in the store. */\n listen: (callback: (value: StoreData<TOutputSchema, TErrorCode[number]>) => void) => () => void;\n /** Called once initially, then called for every change in the store. */\n subscribe: (\n callback: (value: StoreData<TOutputSchema, TErrorCode[number]>) => void,\n ) => () => void;\n get: () => StoreData<TOutputSchema, TErrorCode[number]>;\n refetch: () => void;\n /**\n * Produces an item for every change in the store.\n * Note: the iterator does NOT return.\n *\n * @example\n * ```typescript\n * const store = useFragno(clientObj).store;\n * for await (const value of store[Symbol.asyncIterator]()) {\n * console.log(value);\n * }\n * ```\n */\n [Symbol.asyncIterator]: () => AsyncGenerator<\n StoreData<TOutputSchema, TErrorCode[number]>,\n void,\n unknown\n >;\n};\n\nfunction createVanillaListeners<\n TPath extends string,\n TOutputSchema extends StandardSchemaV1,\n TErrorCode extends string,\n TQueryParameters extends string,\n>(\n hook: FragnoClientHookData<\"GET\", TPath, TOutputSchema, TErrorCode, TQueryParameters>,\n): FragnoVanillaListeners<\"GET\", TPath, TOutputSchema, TErrorCode, TQueryParameters> {\n return ({ path, query } = {}) => {\n const store = hook.store({ path, query });\n\n return {\n listen: (callback) => {\n return store.listen(({ loading, error, data }) =>\n callback({\n loading,\n error,\n data: data as InferOr<TOutputSchema, undefined>,\n }),\n );\n },\n subscribe: (callback) => {\n return store.subscribe(({ loading, error, data }) =>\n callback({\n loading,\n error,\n data: data as InferOr<TOutputSchema, undefined>,\n }),\n );\n },\n refetch: () => {\n return store.revalidate();\n },\n get: () => {\n return store.get() as StoreData<TOutputSchema, TErrorCode[number]>;\n },\n [Symbol.asyncIterator]() {\n return createAsyncIteratorFromCallback((callback) =>\n store.listen(({ loading, error, data }) =>\n callback({\n loading,\n error,\n data: data as InferOr<TOutputSchema, undefined>,\n }),\n ),\n );\n },\n };\n };\n}\n\nexport type FragnoVanillaMutator<\n _TMethod extends NonGetHTTPMethod,\n TPath extends string,\n TInputSchema extends StandardSchemaV1 | undefined,\n TOutputSchema extends StandardSchemaV1 | undefined,\n TErrorCode extends string,\n TQueryParameters extends string,\n> = (args?: {\n path?: MaybeExtractPathParamsOrWiden<TPath, string | ReadableAtom<string>>;\n query?: Record<TQueryParameters, string | ReadableAtom<string>>;\n}) => {\n subscribe: (\n callback: (value: {\n loading: boolean;\n error?: FragnoClientError<TErrorCode[number]>;\n data?: InferOr<TOutputSchema, undefined>;\n }) => void,\n ) => () => void;\n get: () => StoreData<TOutputSchema, TErrorCode[number]>;\n mutate: ({\n body,\n path,\n query,\n }: {\n body?: InferOr<TInputSchema, undefined>;\n path?: HasPathParams<TPath> extends true\n ? ExtractPathParamsOrWiden<TPath, string | ReadableAtom<string>>\n : undefined;\n query?: Record<string, string | ReadableAtom<string>>;\n }) => Promise<InferOr<TOutputSchema, undefined>>;\n [Symbol.asyncIterator]: () => AsyncGenerator<\n StoreData<TOutputSchema, TErrorCode[number]>,\n void,\n unknown\n >;\n};\n\nfunction createVanillaMutator<\n _TMethod extends NonGetHTTPMethod,\n TPath extends string,\n TInputSchema extends StandardSchemaV1 | undefined,\n TOutputSchema extends StandardSchemaV1 | undefined,\n TErrorCode extends string,\n TQueryParameters extends string,\n>(\n hook: FragnoClientMutatorData<\n _TMethod,\n TPath,\n TInputSchema,\n TOutputSchema,\n TErrorCode,\n TQueryParameters\n >,\n): FragnoVanillaMutator<\n _TMethod,\n TPath,\n TInputSchema,\n TOutputSchema,\n TErrorCode,\n TQueryParameters\n> {\n return () => {\n // TODO(Wilco): it should be possible for `loading` to be undefined, before a mutation has taken place.\n const store = hook.mutatorStore;\n return {\n subscribe: (callback) => {\n return store.subscribe((value) => {\n callback({\n loading: value.loading ?? false,\n error: value.error,\n data: value.data,\n });\n });\n },\n get: () => {\n const { loading, error, data } = store.get();\n return {\n loading: loading ?? false,\n error,\n data: data,\n };\n },\n mutate: ({ body, path, query }) => {\n return store.mutate({ body, path, query });\n },\n [Symbol.asyncIterator]() {\n return createAsyncIteratorFromCallback((callback) =>\n store.listen((value) => {\n callback({\n loading: value.loading ?? false,\n error: value.error,\n data: value.data,\n });\n }),\n );\n },\n };\n };\n}\n\nexport function useFragno<T extends Record<string, unknown>>(\n clientObj: T,\n): {\n [K in keyof T]: T[K] extends FragnoClientHookData<\n \"GET\",\n infer TPath,\n infer TOutputSchema,\n infer TErrorCode,\n infer TQueryParameters\n >\n ? FragnoVanillaListeners<\"GET\", TPath, TOutputSchema, TErrorCode, TQueryParameters>\n : T[K] extends FragnoClientMutatorData<\n NonGetHTTPMethod,\n infer TPath,\n infer TInputSchema,\n infer TOutputSchema,\n infer TErrorCode,\n infer TQueryParameters\n >\n ? FragnoVanillaMutator<\n NonGetHTTPMethod,\n TPath,\n TInputSchema,\n TOutputSchema,\n TErrorCode,\n TQueryParameters\n >\n : T[K];\n} {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const result = {} as any; // We need one any cast here due to TypeScript's limitations with mapped types\n\n for (const key in clientObj) {\n if (!Object.prototype.hasOwnProperty.call(clientObj, key)) {\n continue;\n }\n\n const hook = clientObj[key];\n if (isGetHook(hook)) {\n result[key] = createVanillaListeners(hook);\n } else if (isMutatorHook(hook)) {\n result[key] = createVanillaMutator(hook);\n } else {\n // Pass through non-hook values unchanged\n result[key] = hook;\n }\n }\n\n return result;\n}\n"],"mappings":";;;;;;;;;;;;;;AAWA,SAAgB,gCACd,WACkC;CAClC,MAAMA,QAAa,EAAE;CACrB,IAAIC,cAAoC;CACxC,IAAIC,cAA2D;CAE/D,MAAM,kBAAkB,WAAW,UAAU;AAC3C,MAAI,aAAa;AAEf,eAAY;IAAE;IAAO,MAAM;IAAO,CAAC;AACnC,iBAAc;QAGd,OAAM,KAAK,MAAM;GAEnB;AAGF,KAAI,OAAO,oBAAoB,WAC7B,eAAc;AAGhB,SAAQ,mBAAmB;AACzB,MAAI;AACF,UAAO,KACL,KAAI,MAAM,SAAS,EAEjB,OAAM,MAAM,OAAO;OAGnB,OAAM,MAAM,IAAI,SAAY,YAAY;AACtC,mBAAe,WAAW;AACxB,SAAI,CAAC,OAAO,KACV,SAAQ,OAAO,MAAM;;KAGzB;YAGE;AAER,OAAI,YACF,cAAa;;KAGf;;;;;ACON,SAAS,uBAMP,MACmF;AACnF,SAAQ,EAAE,MAAM,UAAU,EAAE,KAAK;EAC/B,MAAM,QAAQ,KAAK,MAAM;GAAE;GAAM;GAAO,CAAC;AAEzC,SAAO;GACL,SAAS,aAAa;AACpB,WAAO,MAAM,QAAQ,EAAE,SAAS,OAAO,WACrC,SAAS;KACP;KACA;KACM;KACP,CAAC,CACH;;GAEH,YAAY,aAAa;AACvB,WAAO,MAAM,WAAW,EAAE,SAAS,OAAO,WACxC,SAAS;KACP;KACA;KACM;KACP,CAAC,CACH;;GAEH,eAAe;AACb,WAAO,MAAM,YAAY;;GAE3B,WAAW;AACT,WAAO,MAAM,KAAK;;GAEpB,CAAC,OAAO,iBAAiB;AACvB,WAAO,iCAAiC,aACtC,MAAM,QAAQ,EAAE,SAAS,OAAO,WAC9B,SAAS;KACP;KACA;KACM;KACP,CAAC,CACH,CACF;;GAEJ;;;AAyCL,SAAS,qBAQP,MAeA;AACA,cAAa;EAEX,MAAM,QAAQ,KAAK;AACnB,SAAO;GACL,YAAY,aAAa;AACvB,WAAO,MAAM,WAAW,UAAU;AAChC,cAAS;MACP,SAAS,MAAM,WAAW;MAC1B,OAAO,MAAM;MACb,MAAM,MAAM;MACb,CAAC;MACF;;GAEJ,WAAW;IACT,MAAM,EAAE,SAAS,OAAO,SAAS,MAAM,KAAK;AAC5C,WAAO;KACL,SAAS,WAAW;KACpB;KACM;KACP;;GAEH,SAAS,EAAE,MAAM,MAAM,YAAY;AACjC,WAAO,MAAM,OAAO;KAAE;KAAM;KAAM;KAAO,CAAC;;GAE5C,CAAC,OAAO,iBAAiB;AACvB,WAAO,iCAAiC,aACtC,MAAM,QAAQ,UAAU;AACtB,cAAS;MACP,SAAS,MAAM,WAAW;MAC1B,OAAO,MAAM;MACb,MAAM,MAAM;MACb,CAAC;MACF,CACH;;GAEJ;;;AAIL,SAAgB,UACd,WA2BA;CAEA,MAAM,SAAS,EAAE;AAEjB,MAAK,MAAM,OAAO,WAAW;AAC3B,MAAI,CAAC,OAAO,UAAU,eAAe,KAAK,WAAW,IAAI,CACvD;EAGF,MAAM,OAAO,UAAU;AACvB,MAAI,UAAU,KAAK,CACjB,QAAO,OAAO,uBAAuB,KAAK;WACjC,cAAc,KAAK,CAC5B,QAAO,OAAO,qBAAqB,KAAK;MAGxC,QAAO,OAAO;;AAIlB,QAAO"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { InferOr, MaybeExtractPathParamsOrWiden, NonGetHTTPMethod, QueryParamsHint } from "../api-CBDGZiLC.js";
|
|
2
|
+
import { FragnoClientError, FragnoClientHookData, FragnoClientMutatorData } from "../client-XFdAy-IQ.js";
|
|
3
|
+
import { ReadableAtom, Store, StoreValue } from "nanostores";
|
|
4
|
+
import { DeepReadonly, Ref, ShallowRef, UnwrapNestedRefs } from "vue";
|
|
5
|
+
import { StandardSchemaV1 } from "@standard-schema/spec";
|
|
6
|
+
|
|
7
|
+
//#region src/client/vue.d.ts
|
|
8
|
+
|
|
9
|
+
type FragnoVueHook<_TMethod extends "GET", TPath extends string, TOutputSchema extends StandardSchemaV1, TErrorCode extends string, TQueryParameters extends string> = (args?: {
|
|
10
|
+
path?: MaybeExtractPathParamsOrWiden<TPath, string | Ref<string> | ReadableAtom<string>>;
|
|
11
|
+
query?: QueryParamsHint<TQueryParameters, string | Ref<string> | ReadableAtom<string>>;
|
|
12
|
+
}) => {
|
|
13
|
+
data: Ref<InferOr<TOutputSchema, undefined>>;
|
|
14
|
+
loading: Ref<boolean>;
|
|
15
|
+
error: Ref<FragnoClientError<TErrorCode[number]> | undefined>;
|
|
16
|
+
};
|
|
17
|
+
type FragnoVueMutator<_TMethod extends NonGetHTTPMethod, TPath extends string, TInputSchema extends StandardSchemaV1 | undefined, TOutputSchema extends StandardSchemaV1 | undefined, TErrorCode extends string, TQueryParameters extends string> = () => {
|
|
18
|
+
mutate: (args: {
|
|
19
|
+
body?: InferOr<TInputSchema, undefined>;
|
|
20
|
+
path?: MaybeExtractPathParamsOrWiden<TPath, string | Ref<string> | ReadableAtom<string>>;
|
|
21
|
+
query?: QueryParamsHint<TQueryParameters, string | Ref<string> | ReadableAtom<string>>;
|
|
22
|
+
}) => Promise<InferOr<TOutputSchema, undefined>>;
|
|
23
|
+
loading: Ref<boolean | undefined>;
|
|
24
|
+
error: Ref<FragnoClientError<TErrorCode[number]> | undefined>;
|
|
25
|
+
data: Ref<InferOr<TOutputSchema, undefined>>;
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Converts a Vue Ref to a NanoStore Atom.
|
|
29
|
+
*
|
|
30
|
+
* This is used to convert Vue refs to atoms, so that we can use them in the store.
|
|
31
|
+
*
|
|
32
|
+
* @private
|
|
33
|
+
*/
|
|
34
|
+
declare function refToAtom<T>(ref: Ref<T>): ReadableAtom<T>;
|
|
35
|
+
declare function useFragno<T extends Record<string, unknown>>(clientObj: T): { [K in keyof T]: T[K] extends FragnoClientHookData<"GET", infer TPath, infer TOutputSchema, infer TErrorCode, infer TQueryParameters> ? FragnoVueHook<"GET", TPath, TOutputSchema, TErrorCode, TQueryParameters> : T[K] extends FragnoClientMutatorData<infer M, infer TPath, infer TInputSchema, infer TOutputSchema, infer TErrorCode, infer TQueryParameters> ? FragnoVueMutator<M, TPath, TInputSchema, TOutputSchema, TErrorCode, TQueryParameters> : T[K] };
|
|
36
|
+
declare function useStore<SomeStore extends Store, Value extends StoreValue<SomeStore>>(store: SomeStore): DeepReadonly<UnwrapNestedRefs<ShallowRef<Value>>>;
|
|
37
|
+
//#endregion
|
|
38
|
+
export { FragnoVueHook, FragnoVueMutator, refToAtom, useFragno, useStore };
|
|
39
|
+
//# sourceMappingURL=vue.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vue.d.ts","names":[],"sources":["../../src/client/vue.ts"],"sourcesContent":[],"mappings":"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"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import "../api-DgHfYjq2.js";
|
|
2
|
+
import "../route-Bp6eByhz.js";
|
|
3
|
+
import { isGetHook, isMutatorHook } from "../client-DWjxKDnE.js";
|
|
4
|
+
import "../ssr-tJHqcNSw.js";
|
|
5
|
+
import { atom } from "nanostores";
|
|
6
|
+
import { computed, getCurrentScope, isRef, onScopeDispose, ref, shallowRef, watch } from "vue";
|
|
7
|
+
|
|
8
|
+
//#region src/client/vue.ts
|
|
9
|
+
/**
|
|
10
|
+
* Converts a Vue Ref to a NanoStore Atom.
|
|
11
|
+
*
|
|
12
|
+
* This is used to convert Vue refs to atoms, so that we can use them in the store.
|
|
13
|
+
*
|
|
14
|
+
* @private
|
|
15
|
+
*/
|
|
16
|
+
function refToAtom(ref$1) {
|
|
17
|
+
const a = atom(ref$1.value);
|
|
18
|
+
watch(ref$1, (newVal) => {
|
|
19
|
+
a.set(newVal);
|
|
20
|
+
});
|
|
21
|
+
return a;
|
|
22
|
+
}
|
|
23
|
+
function createVueHook(hook) {
|
|
24
|
+
return ({ path, query } = {}) => {
|
|
25
|
+
const pathParams = {};
|
|
26
|
+
const queryParams = {};
|
|
27
|
+
for (const [key, value] of Object.entries(path ?? {})) {
|
|
28
|
+
const v = value;
|
|
29
|
+
pathParams[key] = isRef(v) ? refToAtom(v) : v;
|
|
30
|
+
}
|
|
31
|
+
for (const [key, value] of Object.entries(query ?? {})) {
|
|
32
|
+
const v = value;
|
|
33
|
+
queryParams[key] = isRef(v) ? refToAtom(v) : v;
|
|
34
|
+
}
|
|
35
|
+
const store = hook.store({
|
|
36
|
+
path: pathParams,
|
|
37
|
+
query: queryParams
|
|
38
|
+
});
|
|
39
|
+
const data = ref();
|
|
40
|
+
const loading = ref();
|
|
41
|
+
const error = ref();
|
|
42
|
+
const unsubscribe = store.subscribe((updatedStoreValue) => {
|
|
43
|
+
data.value = updatedStoreValue.data;
|
|
44
|
+
loading.value = updatedStoreValue.loading;
|
|
45
|
+
error.value = updatedStoreValue.error;
|
|
46
|
+
});
|
|
47
|
+
if (getCurrentScope()) onScopeDispose(() => {
|
|
48
|
+
unsubscribe();
|
|
49
|
+
});
|
|
50
|
+
return {
|
|
51
|
+
data,
|
|
52
|
+
loading,
|
|
53
|
+
error
|
|
54
|
+
};
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
function createVueMutator(hook) {
|
|
58
|
+
return () => {
|
|
59
|
+
const store = useStore(hook.mutatorStore);
|
|
60
|
+
const mutate = async (args) => {
|
|
61
|
+
const { body, path, query } = args;
|
|
62
|
+
const pathParams = {};
|
|
63
|
+
const queryParams = {};
|
|
64
|
+
for (const [key, value] of Object.entries(path ?? {})) {
|
|
65
|
+
const v = value;
|
|
66
|
+
pathParams[key] = isRef(v) ? v.value : v;
|
|
67
|
+
}
|
|
68
|
+
for (const [key, value] of Object.entries(query ?? {})) {
|
|
69
|
+
const v = value;
|
|
70
|
+
queryParams[key] = isRef(v) ? v.value : v;
|
|
71
|
+
}
|
|
72
|
+
return store.value.mutate({
|
|
73
|
+
body,
|
|
74
|
+
path: pathParams,
|
|
75
|
+
query: queryParams
|
|
76
|
+
});
|
|
77
|
+
};
|
|
78
|
+
return {
|
|
79
|
+
mutate,
|
|
80
|
+
loading: computed(() => store.value.loading),
|
|
81
|
+
error: computed(() => store.value.error),
|
|
82
|
+
data: computed(() => store.value.data)
|
|
83
|
+
};
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
function useFragno(clientObj) {
|
|
87
|
+
const result = {};
|
|
88
|
+
for (const key in clientObj) {
|
|
89
|
+
if (!Object.prototype.hasOwnProperty.call(clientObj, key)) continue;
|
|
90
|
+
const hook = clientObj[key];
|
|
91
|
+
if (isGetHook(hook)) result[key] = createVueHook(hook);
|
|
92
|
+
else if (isMutatorHook(hook)) result[key] = createVueMutator(hook);
|
|
93
|
+
else result[key] = hook;
|
|
94
|
+
}
|
|
95
|
+
return result;
|
|
96
|
+
}
|
|
97
|
+
function useStore(store) {
|
|
98
|
+
const state = shallowRef();
|
|
99
|
+
const unsubscribe = store.subscribe((value) => {
|
|
100
|
+
state.value = value;
|
|
101
|
+
});
|
|
102
|
+
if (getCurrentScope()) onScopeDispose(unsubscribe);
|
|
103
|
+
return state;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
//#endregion
|
|
107
|
+
export { refToAtom, useFragno, useStore };
|
|
108
|
+
//# sourceMappingURL=vue.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vue.js","names":["ref","pathParams: Record<string, string | ReadableAtom<string>>","queryParams: Record<string, string | ReadableAtom<string>>"],"sources":["../../src/client/vue.ts"],"sourcesContent":["import type { StandardSchemaV1 } from \"@standard-schema/spec\";\nimport { atom, type ReadableAtom, type Store, type StoreValue } from \"nanostores\";\nimport type { DeepReadonly, Ref, ShallowRef, UnwrapNestedRefs } from \"vue\";\nimport { computed, getCurrentScope, isRef, onScopeDispose, ref, shallowRef, watch } from \"vue\";\nimport type { NonGetHTTPMethod } from \"../api/api\";\nimport {\n isGetHook,\n isMutatorHook,\n type FragnoClientMutatorData,\n type FragnoClientHookData,\n} from \"./client\";\nimport type { FragnoClientError } from \"./client-error\";\nimport type { MaybeExtractPathParamsOrWiden, QueryParamsHint } from \"../api/internal/path\";\nimport type { InferOr } from \"../util/types-util\";\n\nexport type FragnoVueHook<\n _TMethod extends \"GET\",\n TPath extends string,\n TOutputSchema extends StandardSchemaV1,\n TErrorCode extends string,\n TQueryParameters extends string,\n> = (args?: {\n path?: MaybeExtractPathParamsOrWiden<TPath, string | Ref<string> | ReadableAtom<string>>;\n query?: QueryParamsHint<TQueryParameters, string | Ref<string> | ReadableAtom<string>>;\n}) => {\n data: Ref<InferOr<TOutputSchema, undefined>>;\n loading: Ref<boolean>;\n error: Ref<FragnoClientError<TErrorCode[number]> | undefined>;\n};\n\nexport type FragnoVueMutator<\n _TMethod extends NonGetHTTPMethod,\n TPath extends string,\n TInputSchema extends StandardSchemaV1 | undefined,\n TOutputSchema extends StandardSchemaV1 | undefined,\n TErrorCode extends string,\n TQueryParameters extends string,\n> = () => {\n mutate: (args: {\n body?: InferOr<TInputSchema, undefined>;\n path?: MaybeExtractPathParamsOrWiden<TPath, string | Ref<string> | ReadableAtom<string>>;\n query?: QueryParamsHint<TQueryParameters, string | Ref<string> | ReadableAtom<string>>;\n }) => Promise<InferOr<TOutputSchema, undefined>>;\n loading: Ref<boolean | undefined>;\n error: Ref<FragnoClientError<TErrorCode[number]> | undefined>;\n data: Ref<InferOr<TOutputSchema, undefined>>;\n};\n\n/**\n * Converts a Vue Ref to a NanoStore Atom.\n *\n * This is used to convert Vue refs to atoms, so that we can use them in the store.\n *\n * @private\n */\nexport function refToAtom<T>(ref: Ref<T>): ReadableAtom<T> {\n const a = atom(ref.value);\n\n watch(ref, (newVal) => {\n a.set(newVal);\n });\n\n // TODO: Do we need to unsubscribe, or is this handled by `onScopeDispose` below?\n\n return a;\n}\n\n// Helper function to create a Vue composable from a GET hook\n// We want 1 store per hook, so on updates to params, we need to update the store instead of creating a new one.\n// Nanostores only works with atoms (or strings), so we need to convert vue refs to atoms.\nfunction createVueHook<\n TMethod extends \"GET\",\n TPath extends string,\n TOutputSchema extends StandardSchemaV1,\n TErrorCode extends string,\n TQueryParameters extends string,\n>(\n hook: FragnoClientHookData<TMethod, TPath, TOutputSchema, TErrorCode, TQueryParameters>,\n): FragnoVueHook<TMethod, TPath, TOutputSchema, TErrorCode, TQueryParameters> {\n return ({ path, query } = {}) => {\n const pathParams: Record<string, string | ReadableAtom<string>> = {};\n const queryParams: Record<string, string | ReadableAtom<string>> = {};\n\n for (const [key, value] of Object.entries(path ?? {})) {\n const v = value as string | Ref<string> | ReadableAtom<string>;\n pathParams[key] = isRef(v) ? refToAtom(v) : v;\n }\n\n for (const [key, value] of Object.entries(query ?? {})) {\n // Dunno why the cast is necessary\n const v = value as string | Ref<string> | ReadableAtom<string>;\n queryParams[key] = isRef(v) ? (refToAtom(v) as ReadableAtom<string>) : v;\n }\n\n const store = hook.store({\n path: pathParams as MaybeExtractPathParamsOrWiden<TPath, string | ReadableAtom<string>>,\n query: queryParams,\n });\n\n const data = ref();\n const loading = ref();\n const error = ref();\n\n const unsubscribe = store.subscribe((updatedStoreValue) => {\n data.value = updatedStoreValue.data;\n loading.value = updatedStoreValue.loading;\n error.value = updatedStoreValue.error;\n });\n\n if (getCurrentScope()) {\n onScopeDispose(() => {\n unsubscribe();\n });\n }\n\n return {\n data,\n loading,\n error,\n };\n };\n}\n\n// Helper function to create a Vue mutator from a mutator hook\nfunction createVueMutator<\n TMethod extends NonGetHTTPMethod,\n TPath extends string,\n TInputSchema extends StandardSchemaV1 | undefined,\n TOutputSchema extends StandardSchemaV1 | undefined,\n TErrorCode extends string,\n TQueryParameters extends string,\n>(\n hook: FragnoClientMutatorData<\n TMethod,\n TPath,\n TInputSchema,\n TOutputSchema,\n TErrorCode,\n TQueryParameters\n >,\n): FragnoVueMutator<TMethod, TPath, TInputSchema, TOutputSchema, TErrorCode, TQueryParameters> {\n return () => {\n const store = useStore(hook.mutatorStore);\n\n // Create a wrapped mutate function that handles Vue refs\n const mutate = async (args: {\n body?: InferOr<TInputSchema, undefined>;\n path?: MaybeExtractPathParamsOrWiden<TPath, string | Ref<string> | ReadableAtom<string>>;\n query?: QueryParamsHint<TQueryParameters, string | Ref<string> | ReadableAtom<string>>;\n }) => {\n const { body, path, query } = args;\n\n const pathParams: Record<string, string | ReadableAtom<string>> = {};\n const queryParams: Record<string, string | ReadableAtom<string>> = {};\n\n for (const [key, value] of Object.entries(path ?? {})) {\n const v = value as string | Ref<string> | ReadableAtom<string>;\n pathParams[key] = isRef(v) ? v.value : v;\n }\n\n for (const [key, value] of Object.entries(query ?? {})) {\n const v = value as string | Ref<string> | ReadableAtom<string>;\n queryParams[key] = isRef(v) ? v.value : v;\n }\n\n // Call the store's mutate function with normalized params\n return store.value.mutate({\n body,\n path: pathParams as MaybeExtractPathParamsOrWiden<TPath, string | ReadableAtom<string>>,\n query: queryParams,\n });\n };\n\n // Return the store-like object with Vue reactive refs\n return {\n mutate,\n loading: computed(() => store.value.loading),\n error: computed(() => store.value.error),\n data: computed(() => store.value.data) as Ref<InferOr<TOutputSchema, undefined>>,\n };\n };\n}\n\nexport function useFragno<T extends Record<string, unknown>>(\n clientObj: T,\n): {\n [K in keyof T]: T[K] extends FragnoClientHookData<\n \"GET\",\n infer TPath,\n infer TOutputSchema,\n infer TErrorCode,\n infer TQueryParameters\n >\n ? FragnoVueHook<\"GET\", TPath, TOutputSchema, TErrorCode, TQueryParameters>\n : T[K] extends FragnoClientMutatorData<\n infer M,\n infer TPath,\n infer TInputSchema,\n infer TOutputSchema,\n infer TErrorCode,\n infer TQueryParameters\n >\n ? FragnoVueMutator<M, TPath, TInputSchema, TOutputSchema, TErrorCode, TQueryParameters>\n : T[K];\n} {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const result = {} as any;\n\n for (const key in clientObj) {\n if (!Object.prototype.hasOwnProperty.call(clientObj, key)) {\n continue;\n }\n\n const hook = clientObj[key];\n if (isGetHook(hook)) {\n result[key] = createVueHook(hook);\n } else if (isMutatorHook(hook)) {\n result[key] = createVueMutator(hook);\n } else {\n // Pass through non-hook values unchanged\n result[key] = hook;\n }\n }\n\n return result;\n}\n\nexport function useStore<SomeStore extends Store, Value extends StoreValue<SomeStore>>(\n store: SomeStore,\n): DeepReadonly<UnwrapNestedRefs<ShallowRef<Value>>> {\n const state = shallowRef();\n\n const unsubscribe = store.subscribe((value) => {\n state.value = value;\n });\n\n if (getCurrentScope()) {\n onScopeDispose(unsubscribe);\n }\n\n return state;\n}\n"],"mappings":";;;;;;;;;;;;;;;AAuDA,SAAgB,UAAa,OAA8B;CACzD,MAAM,IAAI,KAAKA,MAAI,MAAM;AAEzB,OAAMA,QAAM,WAAW;AACrB,IAAE,IAAI,OAAO;GACb;AAIF,QAAO;;AAMT,SAAS,cAOP,MAC4E;AAC5E,SAAQ,EAAE,MAAM,UAAU,EAAE,KAAK;EAC/B,MAAMC,aAA4D,EAAE;EACpE,MAAMC,cAA6D,EAAE;AAErE,OAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,QAAQ,EAAE,CAAC,EAAE;GACrD,MAAM,IAAI;AACV,cAAW,OAAO,MAAM,EAAE,GAAG,UAAU,EAAE,GAAG;;AAG9C,OAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,SAAS,EAAE,CAAC,EAAE;GAEtD,MAAM,IAAI;AACV,eAAY,OAAO,MAAM,EAAE,GAAI,UAAU,EAAE,GAA4B;;EAGzE,MAAM,QAAQ,KAAK,MAAM;GACvB,MAAM;GACN,OAAO;GACR,CAAC;EAEF,MAAM,OAAO,KAAK;EAClB,MAAM,UAAU,KAAK;EACrB,MAAM,QAAQ,KAAK;EAEnB,MAAM,cAAc,MAAM,WAAW,sBAAsB;AACzD,QAAK,QAAQ,kBAAkB;AAC/B,WAAQ,QAAQ,kBAAkB;AAClC,SAAM,QAAQ,kBAAkB;IAChC;AAEF,MAAI,iBAAiB,CACnB,sBAAqB;AACnB,gBAAa;IACb;AAGJ,SAAO;GACL;GACA;GACA;GACD;;;AAKL,SAAS,iBAQP,MAQ6F;AAC7F,cAAa;EACX,MAAM,QAAQ,SAAS,KAAK,aAAa;EAGzC,MAAM,SAAS,OAAO,SAIhB;GACJ,MAAM,EAAE,MAAM,MAAM,UAAU;GAE9B,MAAMD,aAA4D,EAAE;GACpE,MAAMC,cAA6D,EAAE;AAErE,QAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,QAAQ,EAAE,CAAC,EAAE;IACrD,MAAM,IAAI;AACV,eAAW,OAAO,MAAM,EAAE,GAAG,EAAE,QAAQ;;AAGzC,QAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,SAAS,EAAE,CAAC,EAAE;IACtD,MAAM,IAAI;AACV,gBAAY,OAAO,MAAM,EAAE,GAAG,EAAE,QAAQ;;AAI1C,UAAO,MAAM,MAAM,OAAO;IACxB;IACA,MAAM;IACN,OAAO;IACR,CAAC;;AAIJ,SAAO;GACL;GACA,SAAS,eAAe,MAAM,MAAM,QAAQ;GAC5C,OAAO,eAAe,MAAM,MAAM,MAAM;GACxC,MAAM,eAAe,MAAM,MAAM,KAAK;GACvC;;;AAIL,SAAgB,UACd,WAoBA;CAEA,MAAM,SAAS,EAAE;AAEjB,MAAK,MAAM,OAAO,WAAW;AAC3B,MAAI,CAAC,OAAO,UAAU,eAAe,KAAK,WAAW,IAAI,CACvD;EAGF,MAAM,OAAO,UAAU;AACvB,MAAI,UAAU,KAAK,CACjB,QAAO,OAAO,cAAc,KAAK;WACxB,cAAc,KAAK,CAC5B,QAAO,OAAO,iBAAiB,KAAK;MAGpC,QAAO,OAAO;;AAIlB,QAAO;;AAGT,SAAgB,SACd,OACmD;CACnD,MAAM,QAAQ,YAAY;CAE1B,MAAM,cAAc,MAAM,WAAW,UAAU;AAC7C,QAAM,QAAQ;GACd;AAEF,KAAI,iBAAiB,CACnB,gBAAe,YAAY;AAG7B,QAAO"}
|