@ahoo-wang/wow-react 9.2.0-rc.0

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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.es.js","names":["QueryStatus","QueryState","status","result","R","error","E","QueryEvent","type","initialQueryState","runsOnMount","undefined","queryTransition","state","event","dequal","useCallback","useEffect","useLayoutEffect","useRef","useState","QueryHookOptions","QueryHookReturn","initialQueryState","queryTransition","QueryEvent","QueryState","useContentStable","value","kept","setKept","notify","name","callback","T","Promise","thrown","console","warn","isAbortError","error","Error","useQueryRunner","options","Q","R","E","identity","retainResult","autoExecute","query","state","setState","initialQuery","undefined","latest","current","request","id","controller","AbortController","mounted","settle","event","cancel","abort","execute","type","attributes","result","signal","aborted","onSuccess","onError","reset","getQuery","setQuery","previousQuery","cleared","status","loading","FilterExpression","Condition","useQueryRunner","QueryHookOptions","QueryHookReturn","UseCountQueryOptions","Error","FIELDS","Q","E","UseCountQueryReturn","useCountQuery","options","Fetcher","DEFAULT_FETCHER_NAME","getFetcher","JsonResultExtractor","QUERY_STREAM_ENDPOINT","ListStreamExecutor","QueryExecutor","Endpoint","url","fetcher","postQuery","Q","R","query","attributes","abortController","post","body","resultExtractor","postQueryStream","ReadableStream","headers","endpointIdentity","by","undefined","name","urlBuilder","baseURL","JSON","stringify","QueryHookOptions","QueryHookReturn","Endpoint","endpointIdentity","postQuery","useQueryRunner","useEndpointRunner","options","$","_c","fetcher","rest","url","t0","t1","execute","t2","_c","FilterExpression","Condition","Endpoint","useEndpointRunner","QueryHookOptions","QueryHookReturn","UseFetcherCountQueryOptions","Error","FIELDS","Omit","Q","E","UseFetcherCountQueryReturn","useFetcherCountQuery","options","FilterListQuery","ListQuery","ListQueryRequest","Endpoint","useEndpointRunner","QueryHookOptions","QueryHookReturn","UseFetcherListQueryOptions","Error","FIELDS","Omit","Q","R","E","UseFetcherListQueryReturn","useFetcherListQuery","options","PUBLISH_INTERVAL_MS","readStreamRows","stream","ReadableStream","R","signal","AbortSignal","publish","rows","Promise","reader","getReader","published","publishedAt","Infinity","timer","ReturnType","setTimeout","flush","undefined","clearTimeout","aborted","length","Date","now","slice","schedule","wait","Math","max","cancel","reason","catch","addEventListener","once","done","value","read","push","error","removeEventListener","releaseLock","useCallback","useState","ListQueryRequest","UseListStreamQueryOptions","UseListStreamQueryReturn","readStreamRows","useQueryRunner","useListStream","options","identity","$","_c","items","setItems","_temp","openStream","execute","t0","query","attributes","abortController","stream","signal","t1","status","loading","error","abort","reset","getQuery","setQuery","t2","resetRows","t3","t4","done","_c","FilterListQuery","ListQuery","ListQueryRequest","Endpoint","endpointIdentity","postQueryStream","useListStream","UseListStreamQueryOptions","UseListStreamQueryReturn","UseFetcherListStreamQueryOptions","Error","FIELDS","Omit","R","E","Q","UseFetcherListStreamQueryReturn","useFetcherListStreamQuery","options","$","_c","fetcher","rest","url","t0","t1","execute","t2","_c","FilterPagedQuery","PagedList","PagedQuery","PagedQueryRequest","Endpoint","useEndpointRunner","QueryHookOptions","QueryHookReturn","UseFetcherPagedQueryOptions","Error","FIELDS","Omit","Q","R","E","UseFetcherPagedQueryReturn","useFetcherPagedQuery","options","FilterSingleQuery","SingleQuery","SingleQueryRequest","Endpoint","useEndpointRunner","QueryHookOptions","QueryHookReturn","UseFetcherSingleQueryOptions","Error","FIELDS","Omit","Q","R","E","UseFetcherSingleQueryReturn","useFetcherSingleQuery","options","FilterListQuery","ListQuery","ListQueryRequest","useQueryRunner","QueryHookOptions","QueryHookReturn","UseListQueryOptions","Error","FIELDS","Q","R","E","UseListQueryReturn","useListQuery","options","FilterListQuery","ListQuery","ListQueryRequest","useListStream","ListStreamExecutor","QueryHookOptions","QueryHookReturn","UseListStreamQueryOptions","Error","FIELDS","Omit","Q","R","E","execute","UseListStreamQueryReturn","items","done","useListStreamQuery","options","FilterPagedQuery","PagedList","PagedQuery","PagedQueryRequest","useQueryRunner","QueryHookOptions","QueryHookReturn","UsePagedQueryOptions","Error","FIELDS","Q","R","E","UsePagedQueryReturn","usePagedQuery","options","FilterSingleQuery","SingleQuery","SingleQueryRequest","useQueryRunner","QueryHookOptions","QueryHookReturn","UseSingleQueryOptions","Error","FIELDS","Q","R","E","UseSingleQueryReturn","useSingleQuery","options","runsOnMount","event","state","kept","setKept","useState","value","dequal","callback","thrown","name","error","autoExecute","options","query","setState","latest","useRef","current","request","mounted","settle","useCallback","id","state_0","cancel","controller","execute_0","query_0","controller_0","id_0","state_1","result","execute","attributes","retainResult","abort","state_2","reset","state_3","getQuery","setQuery","query_1","previousQuery","useEffect","cleared","identity","getFetcher","fetcher","url","JsonResultExtractor","QUERY_STREAM_ENDPOINT","by","DEFAULT_FETCHER_NAME","$","c","rest","t0","t1","t2","reader","stream","rows","published","publishedAt","timer","publish","wait","signal","done","items","setItems","openStream","abortController","resetRows","t3","status","t4","loading"],"sources":["../src/internal/queryTransitions.ts","../src/internal/useQueryRunner.ts","../src/hooks/useCountQuery.ts","../src/internal/endpoint.ts","../src/internal/useEndpointRunner.ts","../src/hooks/useFetcherCountQuery.ts","../src/hooks/useFetcherListQuery.ts","../src/internal/readStreamRows.ts","../src/internal/useListStream.ts","../src/hooks/useFetcherListStreamQuery.ts","../src/hooks/useFetcherPagedQuery.ts","../src/hooks/useFetcherSingleQuery.ts","../src/hooks/useListQuery.ts","../src/hooks/useListStreamQuery.ts","../src/hooks/usePagedQuery.ts","../src/hooks/useSingleQuery.ts"],"sourcesContent":["/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/*\n * What a query hook shows, and how each event changes it: section 3 of\n * docs/design/architecture.md as pure functions, with no React. The\n * request itself (aborting it, ignoring a late answer) is useQueryRunner's.\n */\n\nimport type { QueryStatus } from '../types.js';\n\n/** What a query hook shows at one moment. */\nexport interface QueryState<R, E> {\n status: QueryStatus;\n result: R | undefined;\n error: E | undefined;\n}\n\n/** Something that happens to a query hook. */\nexport type QueryEvent<R, E> =\n | { type: 'start' }\n | { type: 'succeed'; result: R | undefined }\n | { type: 'fail'; error: E }\n | { type: 'abort' }\n | { type: 'reset' };\n\n/**\n * The first state. A hook that will run its query as soon as it mounts\n * starts `loading`, so the server and the first client frame already show\n * what the next frames show; any other starts `idle`.\n */\nexport function initialQueryState<R, E>(\n runsOnMount: boolean,\n): QueryState<R, E> {\n return {\n status: runsOnMount ? 'loading' : 'idle',\n result: undefined,\n error: undefined,\n };\n}\n\n/**\n * The state after one event:\n *\n * - `start`: `loading`; the last result stays until the new one arrives, the\n * error goes.\n * - `succeed`: `success` with the new result (`undefined` for a hook that\n * keeps its own, as the list-stream hooks keep `items`).\n * - `fail`: `error`; the last result stays, so a failed refresh does not\n * blank what was shown.\n * - `abort`: `idle`; the last result stays, the error goes.\n * - `reset`: `idle`, with neither result nor error.\n */\nexport function queryTransition<R, E>(\n state: QueryState<R, E>,\n event: QueryEvent<R, E>,\n): QueryState<R, E> {\n switch (event.type) {\n case 'start':\n return { status: 'loading', result: state.result, error: undefined };\n case 'succeed':\n return { status: 'success', result: event.result, error: undefined };\n case 'fail':\n return { status: 'error', result: state.result, error: event.error };\n case 'abort':\n return { status: 'idle', result: state.result, error: undefined };\n case 'reset':\n return { status: 'idle', result: undefined, error: undefined };\n }\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { dequal } from 'dequal';\nimport {\n useCallback,\n useEffect,\n useLayoutEffect,\n useRef,\n useState,\n} from 'react';\nimport type { QueryHookOptions, QueryHookReturn } from '../types.js';\nimport {\n initialQueryState,\n queryTransition,\n type QueryEvent,\n type QueryState,\n} from './queryTransitions.js';\n\n/**\n * `value`, or the one of an earlier render when that one has the same\n * content, so that an object rebuilt on every render keeps one identity.\n */\nfunction useContentStable<T>(value: T): T {\n const [kept, setKept] = useState(value);\n if (kept === value || dequal(kept, value)) return kept;\n setKept(value);\n return value;\n}\n\n/** Hands a callback its argument; one that throws never breaks the state. */\nasync function notify<T>(\n name: string,\n callback: ((value: T) => void | Promise<void>) | undefined,\n value: T,\n): Promise<void> {\n try {\n await callback?.(value);\n } catch (thrown) {\n // The state already shows the outcome; the host learns of its broken\n // callback without the hook swallowing it.\n // eslint-disable-next-line no-console\n console.warn(`wow-react: ${name} threw`, thrown);\n }\n}\n\nfunction isAbortError(error: unknown): boolean {\n return error instanceof Error && error.name === 'AbortError';\n}\n\n/**\n * The one request state machine every hook runs on.\n *\n * - Latest wins: every run takes a new number and aborts the one before; an\n * answer that is no longer the latest, arrives after `abort()` or\n * `reset()`, or arrives after unmount, changes nothing.\n * - A run starts on mount, whenever the query changes by content or through\n * `setQuery()`, whenever `identity` changes, and when `autoExecute` turns\n * on; `execute()` starts one by hand.\n * - `abort()`, `reset()` and unmount abort the request in flight.\n * - StrictMode's second mount aborts the first run and starts one more, so\n * exactly one answer lands.\n *\n * `identity` is what else a run depends on besides the query: the endpoint\n * of a `useFetcher…` hook. With `retainResult` off the runner hands a run's\n * result to `onSuccess` but does not keep it as `result`: the list-stream\n * hooks keep their rows as `items` already. `execute`, `attributes` and the callbacks are read\n * when a run starts or settles, so a change to them never starts one.\n */\nexport function useQueryRunner<Q, R, E>(\n options: QueryHookOptions<Q, R, E>,\n identity?: string,\n retainResult = true,\n): QueryHookReturn<Q, R, E> {\n const autoExecute = options.autoExecute ?? true;\n const query = useContentStable(options.query);\n const [state, setState] = useState<QueryState<R, E>>(() =>\n initialQueryState(\n autoExecute && (options.query ?? options.initialQuery) !== undefined,\n ),\n );\n const latest = useRef(options);\n const current = useRef<Q | undefined>(options.query ?? options.initialQuery);\n const request = useRef<{ id: number; controller?: AbortController }>({\n id: 0,\n });\n const mounted = useRef(false);\n\n useLayoutEffect(() => {\n latest.current = options;\n });\n\n /** Applies an event unless run `id` is no longer the one that counts. */\n const settle = useCallback((id: number, event: QueryEvent<R, E>) => {\n if (!mounted.current || request.current.id !== id) return false;\n setState(state => queryTransition(state, event));\n return true;\n }, []);\n\n /** Stops the run in flight: no answer of it changes anything any more. */\n const cancel = useCallback(() => {\n const { controller } = request.current;\n request.current = { id: request.current.id + 1 };\n controller?.abort();\n }, []);\n\n const execute = useCallback(async () => {\n const query = current.current;\n if (!mounted.current || query === undefined) return;\n request.current.controller?.abort();\n const controller = new AbortController();\n const id = request.current.id + 1;\n request.current = { id, controller };\n setState(state => queryTransition(state, { type: 'start' }));\n const { execute, attributes } = latest.current;\n try {\n const result = await execute(query, attributes, controller);\n if (controller.signal.aborted) {\n settle(id, { type: 'abort' });\n } else if (\n settle(id, {\n type: 'succeed',\n result: retainResult ? result : undefined,\n })\n ) {\n await notify('onSuccess', latest.current.onSuccess, result);\n }\n } catch (error) {\n if (controller.signal.aborted || isAbortError(error)) {\n settle(id, { type: 'abort' });\n } else if (settle(id, { type: 'fail', error: error as E })) {\n await notify('onError', latest.current.onError, error as E);\n }\n } finally {\n if (request.current.controller === controller)\n request.current = { id: request.current.id };\n }\n }, [settle, retainResult]);\n\n const abort = useCallback(() => {\n cancel();\n setState(state => queryTransition(state, { type: 'abort' }));\n }, [cancel]);\n\n const reset = useCallback(() => {\n cancel();\n setState(state => queryTransition(state, { type: 'reset' }));\n }, [cancel]);\n\n const getQuery = useCallback(() => current.current, []);\n\n const setQuery = useCallback(\n (query: Q) => {\n current.current = query;\n if (latest.current.autoExecute ?? true) void execute();\n },\n [execute],\n );\n\n useEffect(() => {\n mounted.current = true;\n return () => {\n mounted.current = false;\n cancel();\n };\n }, [cancel]);\n\n const previousQuery = useRef(query);\n useEffect(() => {\n const cleared = query === undefined && previousQuery.current !== undefined;\n previousQuery.current = query;\n if (cleared) {\n // A controlled query set to `undefined` (`id ? singleQuery(…) :\n // undefined`) means nothing to run: stop, keep what was shown.\n current.current = undefined;\n abort();\n return;\n }\n if (query !== undefined) current.current = query;\n if (autoExecute) void execute();\n }, [query, identity, autoExecute, execute, abort]);\n\n return {\n status: state.status,\n loading: state.status === 'loading',\n result: state.result,\n error: state.error,\n execute,\n abort,\n reset,\n getQuery,\n setQuery,\n };\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { FilterExpression } from '@ahoo-wang/wow-client';\n// compat(wow<9): the hook also takes the Condition-based queries of `@ahoo-wang/wow-client/legacy`, which Wow < 8.11 needs; drop that overload in v10.\nimport type { Condition } from '@ahoo-wang/wow-client/legacy';\nimport { useQueryRunner } from '../internal/useQueryRunner.js';\nimport type { QueryHookOptions, QueryHookReturn } from '../types.js';\n\n/**\n * Options of {@link useCountQuery}: a filter and an `execute` that resolves to\n * how many rows it matches.\n *\n * @template FIELDS - The field names the filter may use\n * @template E - The error type, `Error` by default\n * @template Q - The filter type: `FilterExpression` by default\n */\nexport interface UseCountQueryOptions<\n FIELDS extends string = string,\n E = Error,\n Q extends Condition<FIELDS> | FilterExpression<FIELDS> =\n FilterExpression<FIELDS>,\n> extends QueryHookOptions<Q, number, E> {}\n\n/**\n * What {@link useCountQuery} returns: the count as `result`.\n *\n * @template FIELDS - The field names the filter may use\n * @template E - The error type, `Error` by default\n * @template Q - The filter type: `FilterExpression` by default\n */\nexport interface UseCountQueryReturn<\n FIELDS extends string = string,\n E = Error,\n Q extends Condition<FIELDS> | FilterExpression<FIELDS> =\n FilterExpression<FIELDS>,\n> extends QueryHookReturn<Q, number, E> {}\n\n/**\n * Counts what a filter matches through your own `execute` function and keeps\n * the count as state: typically a query client's `count`.\n *\n * `execute` receives the filter, the `attributes` option and an\n * `AbortController`; hand the controller on so that a newer query, `abort()`\n * or an unmount cancels the request. The count runs on mount and whenever\n * `query` or `setQuery()` changes the filter; set `autoExecute: false` to run\n * it only through `execute()`.\n *\n * Returns `result` (the count, or `undefined` before the first success),\n * `loading`, `error`, `status`, `execute`, `abort`, `reset`, `getQuery` and\n * `setQuery`.\n *\n * @template FIELDS - The field names the filter may use. With a client whose\n * fields are narrower than `string`, as a generated client's are, pass\n * them here; inferred from the first filter, they would admit only its\n * fields in `setQuery()`\n * @template E - The error type, `Error` by default\n *\n * @example\n * ```tsx\n * import { filter, type SnapshotQueryClient } from '@ahoo-wang/wow-client';\n * import { useCountQuery } from '@ahoo-wang/wow-react';\n *\n * function PaidCount({ client }: { client: SnapshotQueryClient<OrderState, OrderFields> }) {\n * const { result, error } = useCountQuery<OrderFields>({\n * initialQuery: filter.eq('state.status', 'PAID'),\n * execute: (query, attributes, abortController) =>\n * client.count(query, attributes, abortController),\n * });\n * if (error) return <p role=\"alert\">{error.message}</p>;\n * return <p>{result ?? '…'} paid orders</p>;\n * }\n * ```\n */\nexport function useCountQuery<FIELDS extends string = string, E = Error>(\n options: UseCountQueryOptions<FIELDS, E, FilterExpression<FIELDS>>,\n): UseCountQueryReturn<FIELDS, E, FilterExpression<FIELDS>>;\nexport function useCountQuery<FIELDS extends string = string, E = Error>(\n options: UseCountQueryOptions<FIELDS, E, Condition<FIELDS>>,\n): UseCountQueryReturn<FIELDS, E, Condition<FIELDS>>;\nexport function useCountQuery<\n FIELDS extends string = string,\n E = Error,\n Q extends Condition<FIELDS> | FilterExpression<FIELDS> =\n FilterExpression<FIELDS>,\n>(\n options: UseCountQueryOptions<FIELDS, E, Q>,\n): UseCountQueryReturn<FIELDS, E, Q>;\nexport function useCountQuery<\n FIELDS extends string,\n E,\n Q extends Condition<FIELDS> | FilterExpression<FIELDS>,\n>(\n options: UseCountQueryOptions<FIELDS, E, Q>,\n): UseCountQueryReturn<FIELDS, E, Q> {\n return useQueryRunner<Q, number, E>(options);\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/*\n * The Wow query endpoint protocol, in one place: a query is POSTed as the\n * JSON body to its endpoint; the answer is JSON, or, for a list stream, an\n * event stream the server sends only when asked with\n * `Accept: text/event-stream`. The `useFetcher…` hooks are the matching\n * `use…Query` hook with one of these executors as `execute`.\n */\n\nimport type { Fetcher } from '@ahoo-wang/fetcher';\nimport {\n DEFAULT_FETCHER_NAME,\n getFetcher,\n JsonResultExtractor,\n} from '@ahoo-wang/fetcher';\nimport { QUERY_STREAM_ENDPOINT } from '@ahoo-wang/wow-client';\nimport type { ListStreamExecutor, QueryExecutor } from '../types.js';\n\n/**\n * Where a `useFetcher…` hook sends its query. Every `useFetcher…Options`\n * extends it, so the two members are declared, and documented, once.\n */\nexport interface Endpoint {\n /**\n * The query endpoint, resolved against the Fetcher's `baseURL`: for example\n * `order/snapshot/list/state` for the states of an `order` aggregate, or\n * `order/snapshot/count` for the count of its snapshots.\n */\n url: string;\n /**\n * The Fetcher that sends the request, or the name of a registered one; the\n * default Fetcher when omitted.\n */\n fetcher?: string | Fetcher;\n}\n\n/**\n * Runs a query by POSTing it to the endpoint and reading the JSON answer.\n * The Fetcher is resolved when the request is sent, so a name that is not\n * registered fails that request, and the hook reports it as its `error`.\n */\nexport function postQuery<Q extends object, R>({\n url,\n fetcher,\n}: Endpoint): QueryExecutor<Q, R> {\n return (query, attributes, abortController) =>\n getFetcher(fetcher).post<R>(\n url,\n { body: query, abortController },\n { attributes, resultExtractor: JsonResultExtractor },\n );\n}\n\n/**\n * Opens the stream of a list query by POSTing it to the endpoint with\n * wow-client's `QUERY_STREAM_ENDPOINT`: `Accept: text/event-stream`, and an\n * extractor that answers the rows and ends the stream with a `WowError` at\n * the server's error event.\n */\nexport function postQueryStream<R, Q extends object>({\n url,\n fetcher,\n}: Endpoint): ListStreamExecutor<R, Q> {\n return (query, attributes, abortController) =>\n getFetcher(fetcher).post<ReadableStream<R>>(\n url,\n {\n body: query,\n // A copy: the Fetcher may add headers to the request it sends.\n headers: { ...QUERY_STREAM_ENDPOINT.headers },\n abortController,\n },\n { attributes, resultExtractor: QUERY_STREAM_ENDPOINT.resultExtractor },\n );\n}\n\n/**\n * What identifies an endpoint across renders: the url, and the Fetcher by\n * its name, or by its `baseURL` when it has none. A hook runs its query\n * again when this changes; a `new Fetcher({ baseURL })` written inline in\n * render keeps the same identity, so it does not run the query on every\n * render. Two unnamed Fetchers with one `baseURL` but different\n * interceptors count as the same; name them to tell them apart.\n */\nexport function endpointIdentity({ url, fetcher }: Endpoint): string {\n let by: string;\n if (fetcher === undefined) by = `name:${DEFAULT_FETCHER_NAME}`;\n else if (typeof fetcher === 'string') by = `name:${fetcher}`;\n else if ('name' in fetcher && typeof fetcher.name === 'string')\n by = `name:${fetcher.name}`;\n else by = `baseURL:${fetcher.urlBuilder.baseURL}`;\n return JSON.stringify([url, by]);\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { QueryHookOptions, QueryHookReturn } from '../types.js';\nimport { type Endpoint, endpointIdentity, postQuery } from './endpoint.js';\nimport { useQueryRunner } from './useQueryRunner.js';\n\n/**\n * The request `useFetcher…` hooks: the runner with the endpoint's executor as\n * `execute`, and the endpoint as part of the request's identity, so a change\n * of `url` or `fetcher` runs the query again.\n */\nexport function useEndpointRunner<Q extends object, R, E>(\n options: Omit<QueryHookOptions<Q, R, E>, 'execute'> & Endpoint,\n): QueryHookReturn<Q, R, E> {\n const { url, fetcher, ...rest } = options;\n return useQueryRunner<Q, R, E>(\n { ...rest, execute: postQuery<Q, R>({ url, fetcher }) },\n endpointIdentity({ url, fetcher }),\n );\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { FilterExpression } from '@ahoo-wang/wow-client';\n// compat(wow<9): the hook also takes the Condition-based queries of `@ahoo-wang/wow-client/legacy`, which Wow < 8.11 needs; drop that overload in v10.\nimport type { Condition } from '@ahoo-wang/wow-client/legacy';\nimport type { Endpoint } from '../internal/endpoint.js';\nimport { useEndpointRunner } from '../internal/useEndpointRunner.js';\nimport type { QueryHookOptions, QueryHookReturn } from '../types.js';\n\n/**\n * Options of {@link useFetcherCountQuery}: those of every query hook, with\n * the endpoint and the Fetcher in place of `execute`.\n *\n * @template FIELDS - The field names the filter may use\n * @template E - The error type, `Error` by default\n * @template Q - The filter type: `FilterExpression` by default\n */\nexport interface UseFetcherCountQueryOptions<\n FIELDS extends string = string,\n E = Error,\n Q extends Condition<FIELDS> | FilterExpression<FIELDS> =\n FilterExpression<FIELDS>,\n>\n extends Omit<QueryHookOptions<Q, number, E>, 'execute'>, Endpoint {}\n\n/**\n * What {@link useFetcherCountQuery} returns: the count as `result`.\n *\n * @template FIELDS - The field names the filter may use\n * @template E - The error type, `Error` by default\n * @template Q - The filter type: `FilterExpression` by default\n */\nexport interface UseFetcherCountQueryReturn<\n FIELDS extends string = string,\n E = Error,\n Q extends Condition<FIELDS> | FilterExpression<FIELDS> =\n FilterExpression<FIELDS>,\n> extends QueryHookReturn<Q, number, E> {}\n\n/**\n * POSTs a filter to a Wow count endpoint through a Fetcher and keeps the\n * count as state.\n *\n * `url` is resolved against the Fetcher's `baseURL`; `fetcher` is a Fetcher\n * or the name of a registered one, the default Fetcher when omitted. The\n * count runs on mount and whenever `query` or `setQuery()` changes the\n * filter; set `autoExecute: false` to run it only through `execute()`. A\n * newer filter aborts the request in flight, so a late response never\n * overwrites a newer one; an unmount aborts it too.\n *\n * A change of `url`, or of `fetcher`, runs the query again. A Fetcher is\n * compared by its name, or by its `baseURL` when it has none, so one created\n * inline in render does not run it on every render.\n *\n * Returns `result` (the count, or `undefined` before the first success),\n * `loading`, `error`, `status`, `execute`, `abort`, `reset`, `getQuery` and\n * `setQuery`. A failed request sets `error` to a `FetcherError`;\n * `toWowError(error)` from `@ahoo-wang/wow-client` reads the server's\n * `errorCode` from it.\n *\n * @template FIELDS - The field names the filter may use\n * @template E - The error type, `Error` by default\n *\n * @example\n * ```tsx\n * import { filter } from '@ahoo-wang/wow-client';\n * import { useFetcherCountQuery } from '@ahoo-wang/wow-react';\n *\n * function PaidCount() {\n * const { result, error } = useFetcherCountQuery({\n * url: 'order/snapshot/count',\n * initialQuery: filter.eq('state.status', 'PAID'),\n * });\n * if (error) return <p role=\"alert\">{error.message}</p>;\n * return <p>{result ?? '…'} paid orders</p>;\n * }\n * ```\n */\nexport function useFetcherCountQuery<FIELDS extends string = string, E = Error>(\n options: UseFetcherCountQueryOptions<FIELDS, E, FilterExpression<FIELDS>>,\n): UseFetcherCountQueryReturn<FIELDS, E, FilterExpression<FIELDS>>;\nexport function useFetcherCountQuery<FIELDS extends string = string, E = Error>(\n options: UseFetcherCountQueryOptions<FIELDS, E, Condition<FIELDS>>,\n): UseFetcherCountQueryReturn<FIELDS, E, Condition<FIELDS>>;\nexport function useFetcherCountQuery<\n FIELDS extends string = string,\n E = Error,\n Q extends Condition<FIELDS> | FilterExpression<FIELDS> =\n FilterExpression<FIELDS>,\n>(\n options: UseFetcherCountQueryOptions<FIELDS, E, Q>,\n): UseFetcherCountQueryReturn<FIELDS, E, Q>;\nexport function useFetcherCountQuery<\n FIELDS extends string,\n E,\n Q extends Condition<FIELDS> | FilterExpression<FIELDS>,\n>(\n options: UseFetcherCountQueryOptions<FIELDS, E, Q>,\n): UseFetcherCountQueryReturn<FIELDS, E, Q> {\n return useEndpointRunner<Q, number, E>(options);\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { FilterListQuery } from '@ahoo-wang/wow-client';\n// compat(wow<9): the hook also takes the Condition-based queries of `@ahoo-wang/wow-client/legacy`, which Wow < 8.11 needs; drop that overload in v10.\nimport type { ListQuery, ListQueryRequest } from '@ahoo-wang/wow-client/legacy';\nimport type { Endpoint } from '../internal/endpoint.js';\nimport { useEndpointRunner } from '../internal/useEndpointRunner.js';\nimport type { QueryHookOptions, QueryHookReturn } from '../types.js';\n\n/**\n * Options of {@link useFetcherListQuery}: those of every query hook, with the\n * endpoint and the Fetcher in place of `execute`.\n *\n * @template R - One row of the list\n * @template FIELDS - The field names the query may use\n * @template E - The error type, `Error` by default\n * @template Q - The query type: `FilterListQuery` by default\n */\nexport interface UseFetcherListQueryOptions<\n R,\n FIELDS extends string = string,\n E = Error,\n Q extends ListQueryRequest<FIELDS> = FilterListQuery<FIELDS>,\n>\n extends Omit<QueryHookOptions<Q, R[], E>, 'execute'>, Endpoint {}\n\n/**\n * What {@link useFetcherListQuery} returns: the rows as `result`.\n *\n * @template R - One row of the list\n * @template FIELDS - The field names the query may use\n * @template E - The error type, `Error` by default\n * @template Q - The query type: `FilterListQuery` by default\n */\nexport interface UseFetcherListQueryReturn<\n R,\n FIELDS extends string = string,\n E = Error,\n Q extends ListQueryRequest<FIELDS> = FilterListQuery<FIELDS>,\n> extends QueryHookReturn<Q, R[], E> {}\n\n/**\n * POSTs a list query to a Wow endpoint through a Fetcher and keeps the rows\n * as state.\n *\n * `url` is resolved against the Fetcher's `baseURL`; `fetcher` is a Fetcher\n * or the name of a registered one, the default Fetcher when omitted. The\n * query runs on mount and whenever `query` or `setQuery()` changes it; set\n * `autoExecute: false` to run it only through `execute()`. A newer query\n * aborts the request in flight, so a late response never overwrites a newer\n * one; an unmount aborts it too.\n *\n * A change of `url`, or of `fetcher`, runs the query again. A Fetcher is\n * compared by its name, or by its `baseURL` when it has none, so one created\n * inline in render does not run it on every render.\n *\n * Returns `result` (the rows, or `undefined` before the first success),\n * `loading`, `error`, `status`, `execute`, `abort`, `reset`, `getQuery` and\n * `setQuery`. A failed request sets `error` to a `FetcherError`;\n * `toWowError(error)` from `@ahoo-wang/wow-client` reads the server's\n * `errorCode` from it.\n *\n * @template R - One row of the list\n * @template FIELDS - The field names the query may use\n * @template E - The error type, `Error` by default\n *\n * @example\n * ```tsx\n * import { desc, filter, listQuery } from '@ahoo-wang/wow-client';\n * import { useFetcherListQuery } from '@ahoo-wang/wow-react';\n *\n * function LatestOrders() {\n * const { result, loading, error, execute } = useFetcherListQuery<OrderState>({\n * url: 'order/snapshot/list/state',\n * initialQuery: listQuery({\n * filter: filter.eq('state.status', 'PAID'),\n * sort: [desc('createTime')],\n * limit: 20,\n * }),\n * });\n * if (error) return <p role=\"alert\">{error.message}</p>;\n * if (loading || !result) return <p>Loading…</p>;\n * return (\n * <>\n * <ul>{result.map(order => <li key={order.id}>{order.id}</li>)}</ul>\n * <button onClick={execute}>Refresh</button>\n * </>\n * );\n * }\n * ```\n */\nexport function useFetcherListQuery<\n R,\n FIELDS extends string = string,\n E = Error,\n>(\n options: UseFetcherListQueryOptions<R, FIELDS, E, FilterListQuery<FIELDS>>,\n): UseFetcherListQueryReturn<R, FIELDS, E, FilterListQuery<FIELDS>>;\nexport function useFetcherListQuery<\n R,\n FIELDS extends string = string,\n E = Error,\n>(\n options: UseFetcherListQueryOptions<R, FIELDS, E, ListQuery<FIELDS>>,\n): UseFetcherListQueryReturn<R, FIELDS, E, ListQuery<FIELDS>>;\nexport function useFetcherListQuery<\n R,\n FIELDS extends string = string,\n E = Error,\n Q extends ListQueryRequest<FIELDS> = FilterListQuery<FIELDS>,\n>(\n options: UseFetcherListQueryOptions<R, FIELDS, E, Q>,\n): UseFetcherListQueryReturn<R, FIELDS, E, Q>;\nexport function useFetcherListQuery<\n R,\n FIELDS extends string,\n E,\n Q extends ListQueryRequest<FIELDS>,\n>(\n options: UseFetcherListQueryOptions<R, FIELDS, E, Q>,\n): UseFetcherListQueryReturn<R, FIELDS, E, Q> {\n return useEndpointRunner<Q, R[], E>(options);\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * The least time between two publishes while a stream is read: about one\n * frame, so the rows keep up with the screen while a long stream costs a\n * bounded number of renders.\n */\nexport const PUBLISH_INTERVAL_MS = 16;\n\n/**\n * Reads a stream of rows to its end and resolves to every row, in order.\n *\n * While it reads, it hands the rows received so far to `publish`: the first\n * rows on the next macrotask, then at most once every\n * {@link PUBLISH_INTERVAL_MS}. Publishing by time, not by network chunk,\n * bounds how often a long stream renders and copies its rows: one render per\n * interval however many chunks arrive in it, and each `publish` still gets a\n * new array. It publishes the last rows before it\n * resolves or rejects, so the rows before a failure stay visible.\n *\n * `signal` aborting cancels the stream — a fake or already-buffered body\n * does not end with the request — and stops every later `publish`: a newer\n * query or an unmount has taken over, and its rows must not be overwritten.\n * The reader is always released, so the stream never stays locked.\n *\n * Internal: not exported from the package.\n */\nexport async function readStreamRows<R>(\n stream: ReadableStream<R>,\n signal: AbortSignal,\n publish: (rows: R[]) => void,\n): Promise<R[]> {\n const reader = stream.getReader();\n const rows: R[] = [];\n let published = 0;\n let publishedAt = -Infinity;\n let timer: ReturnType<typeof setTimeout> | undefined;\n const flush = () => {\n if (timer !== undefined) clearTimeout(timer);\n timer = undefined;\n if (signal.aborted || published === rows.length) return;\n published = rows.length;\n publishedAt = Date.now();\n publish(rows.slice());\n };\n const schedule = () => {\n if (timer !== undefined) return;\n const wait = Math.max(0, publishedAt + PUBLISH_INTERVAL_MS - Date.now());\n timer = setTimeout(flush, wait);\n };\n const cancel = () => {\n reader.cancel(signal.reason).catch(() => {\n // The stream had already failed; that failure is the one reported.\n });\n };\n if (signal.aborted) cancel();\n else signal.addEventListener('abort', cancel, { once: true });\n try {\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n rows.push(value);\n schedule();\n }\n flush();\n return rows;\n } catch (error) {\n flush();\n throw error;\n } finally {\n if (timer !== undefined) clearTimeout(timer);\n signal.removeEventListener('abort', cancel);\n reader.releaseLock();\n }\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { useCallback, useState } from 'react';\n// compat(wow<9): the stream hooks also take the Condition-based list query of `@ahoo-wang/wow-client/legacy`; narrow to FilterListQuery in v10.\nimport type { ListQueryRequest } from '@ahoo-wang/wow-client/legacy';\nimport type {\n UseListStreamQueryOptions,\n UseListStreamQueryReturn,\n} from '../hooks/useListStreamQuery.js';\nimport { readStreamRows } from './readStreamRows.js';\nimport { useQueryRunner } from './useQueryRunner.js';\n\n/**\n * The list-stream hooks on the request state machine: a run opens the\n * stream and reads it into `items`. Each run starts from no rows; `abort()`\n * and an error keep the rows received; `reset()` empties them. The runner\n * aborts the run's controller whenever the run stops counting, and\n * readStreamRows stops publishing then, so rows of a stale stream never\n * reach `items`.\n */\nexport function useListStream<\n R,\n FIELDS extends string,\n E,\n Q extends ListQueryRequest<FIELDS>,\n>(\n options: UseListStreamQueryOptions<R, FIELDS, E, Q>,\n identity?: string,\n): UseListStreamQueryReturn<R, FIELDS, E, Q> {\n const [items, setItems] = useState<R[]>(() => []);\n const openStream = options.execute;\n const { status, loading, error, execute, abort, reset, getQuery, setQuery } =\n useQueryRunner<Q, R[], E>(\n {\n ...options,\n execute: async (query, attributes, abortController) => {\n setItems([]);\n const stream = await openStream(query, attributes, abortController);\n return readStreamRows(stream, abortController.signal, setItems);\n },\n },\n identity,\n false,\n );\n const resetRows = useCallback(() => {\n reset();\n setItems([]);\n }, [reset]);\n return {\n items,\n done: status === 'success',\n loading,\n error,\n status,\n execute,\n abort,\n reset: resetRows,\n getQuery,\n setQuery,\n };\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { FilterListQuery } from '@ahoo-wang/wow-client';\n// compat(wow<9): the hook also takes the Condition-based queries of `@ahoo-wang/wow-client/legacy`, which Wow < 8.11 needs; drop that overload in v10.\nimport type { ListQuery, ListQueryRequest } from '@ahoo-wang/wow-client/legacy';\nimport {\n type Endpoint,\n endpointIdentity,\n postQueryStream,\n} from '../internal/endpoint.js';\nimport { useListStream } from '../internal/useListStream.js';\nimport {\n type UseListStreamQueryOptions,\n type UseListStreamQueryReturn,\n} from './useListStreamQuery.js';\n\n/**\n * Options of {@link useFetcherListStreamQuery}: those of `useListStreamQuery`,\n * with the endpoint and the Fetcher in place of `execute`.\n *\n * @template R - One row of the stream: the `data` of each event\n * @template FIELDS - The field names the query may use\n * @template E - The error type, `Error` by default: a failed request\n * rejects with a `FetcherError`, an error event in the stream with a\n * `WowError`\n * @template Q - The query type: `FilterListQuery` by default\n */\nexport interface UseFetcherListStreamQueryOptions<\n R,\n FIELDS extends string = string,\n E = Error,\n Q extends ListQueryRequest<FIELDS> = FilterListQuery<FIELDS>,\n>\n extends\n Omit<UseListStreamQueryOptions<R, FIELDS, E, Q>, 'execute'>,\n Endpoint {}\n\n/**\n * What {@link useFetcherListStreamQuery} returns; see\n * {@link UseListStreamQueryReturn}.\n */\nexport interface UseFetcherListStreamQueryReturn<\n R,\n FIELDS extends string = string,\n E = Error,\n Q extends ListQueryRequest<FIELDS> = FilterListQuery<FIELDS>,\n> extends UseListStreamQueryReturn<R, FIELDS, E, Q> {}\n\n/**\n * Streams the rows of a list query from a Wow list endpoint and keeps them as\n * state; see `useListStreamQuery` for the state it returns.\n *\n * It POSTs the query to `url` through `fetcher` (the default Fetcher when\n * omitted) with `Accept: text/event-stream`, the header a Wow server needs to\n * answer with an event stream rather than JSON. An error event in the stream\n * ends it with a `WowError` in `error`.\n *\n * A change of `url`, or of `fetcher`, runs the query again. A Fetcher is\n * compared by its name, or by its `baseURL` when it has none, so one created\n * inline in render does not run it on every render.\n *\n * @template R - One row of the stream: the `data` of each event\n * @template FIELDS - The field names the query may use\n * @template E - The error type\n *\n * @example\n * ```tsx\n * import { filter, listQuery } from '@ahoo-wang/wow-client';\n * import { useFetcherListStreamQuery } from '@ahoo-wang/wow-react';\n *\n * function PaidOrders() {\n * const { items, done, loading, error } = useFetcherListStreamQuery<OrderState>({\n * url: 'order/snapshot/list/state',\n * initialQuery: listQuery({ filter: filter.eq('state.status', 'PAID') }),\n * });\n * if (error) return <p role=\"alert\">{error.message}</p>;\n * return (\n * <>\n * <ul>{items.map(order => <li key={order.id}>{order.id}</li>)}</ul>\n * {loading ? <p>Loading…</p> : done && <p>{items.length} orders</p>}\n * </>\n * );\n * }\n * ```\n */\nexport function useFetcherListStreamQuery<\n R,\n FIELDS extends string = string,\n E = Error,\n>(\n options: UseFetcherListStreamQueryOptions<\n R,\n FIELDS,\n E,\n FilterListQuery<FIELDS>\n >,\n): UseFetcherListStreamQueryReturn<R, FIELDS, E, FilterListQuery<FIELDS>>;\nexport function useFetcherListStreamQuery<\n R,\n FIELDS extends string = string,\n E = Error,\n>(\n options: UseFetcherListStreamQueryOptions<R, FIELDS, E, ListQuery<FIELDS>>,\n): UseFetcherListStreamQueryReturn<R, FIELDS, E, ListQuery<FIELDS>>;\nexport function useFetcherListStreamQuery<\n R,\n FIELDS extends string = string,\n E = Error,\n Q extends ListQueryRequest<FIELDS> = FilterListQuery<FIELDS>,\n>(\n options: UseFetcherListStreamQueryOptions<R, FIELDS, E, Q>,\n): UseFetcherListStreamQueryReturn<R, FIELDS, E, Q>;\nexport function useFetcherListStreamQuery<\n R,\n FIELDS extends string,\n E,\n Q extends ListQueryRequest<FIELDS>,\n>(\n options: UseFetcherListStreamQueryOptions<R, FIELDS, E, Q>,\n): UseFetcherListStreamQueryReturn<R, FIELDS, E, Q> {\n const { url, fetcher, ...rest } = options;\n return useListStream<R, FIELDS, E, Q>(\n { ...rest, execute: postQueryStream<R, Q>({ url, fetcher }) },\n endpointIdentity({ url, fetcher }),\n );\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { FilterPagedQuery, PagedList } from '@ahoo-wang/wow-client';\n// compat(wow<9): the hook also takes the Condition-based queries of `@ahoo-wang/wow-client/legacy`, which Wow < 8.11 needs; drop that overload in v10.\nimport type {\n PagedQuery,\n PagedQueryRequest,\n} from '@ahoo-wang/wow-client/legacy';\nimport type { Endpoint } from '../internal/endpoint.js';\nimport { useEndpointRunner } from '../internal/useEndpointRunner.js';\nimport type { QueryHookOptions, QueryHookReturn } from '../types.js';\n\n/**\n * Options of {@link useFetcherPagedQuery}: those of every query hook, with\n * the endpoint and the Fetcher in place of `execute`.\n *\n * @template R - One row of the page\n * @template FIELDS - The field names the query may use\n * @template E - The error type, `Error` by default\n * @template Q - The query type: `FilterPagedQuery` by default\n */\nexport interface UseFetcherPagedQueryOptions<\n R,\n FIELDS extends string = string,\n E = Error,\n Q extends PagedQueryRequest<FIELDS> = FilterPagedQuery<FIELDS>,\n>\n extends Omit<QueryHookOptions<Q, PagedList<R>, E>, 'execute'>, Endpoint {}\n\n/**\n * What {@link useFetcherPagedQuery} returns: the page (`total` and `list`)\n * as `result`.\n *\n * @template R - One row of the page\n * @template FIELDS - The field names the query may use\n * @template E - The error type, `Error` by default\n * @template Q - The query type: `FilterPagedQuery` by default\n */\nexport interface UseFetcherPagedQueryReturn<\n R,\n FIELDS extends string = string,\n E = Error,\n Q extends PagedQueryRequest<FIELDS> = FilterPagedQuery<FIELDS>,\n> extends QueryHookReturn<Q, PagedList<R>, E> {}\n\n/**\n * POSTs a paged query to a Wow endpoint through a Fetcher and keeps the page\n * as state.\n *\n * `url` is resolved against the Fetcher's `baseURL`; `fetcher` is a Fetcher\n * or the name of a registered one, the default Fetcher when omitted. The\n * query runs on mount and whenever `query` or `setQuery()` changes it — turn\n * pages with `setQuery()`; set `autoExecute: false` to run it only through\n * `execute()`. A newer query aborts the request in flight, so a late response\n * never overwrites a newer one; an unmount aborts it too.\n *\n * A change of `url`, or of `fetcher`, runs the query again. A Fetcher is\n * compared by its name, or by its `baseURL` when it has none, so one created\n * inline in render does not run it on every render.\n *\n * Returns `result` (`{ total, list }`, or `undefined` before the first\n * success), `loading`, `error`, `status`, `execute`, `abort`, `reset`,\n * `getQuery` and `setQuery`. A failed request sets `error` to a\n * `FetcherError`; `toWowError(error)` from `@ahoo-wang/wow-client` reads the\n * server's `errorCode` from it.\n *\n * @template R - One row of the page\n * @template FIELDS - The field names the query may use\n * @template E - The error type, `Error` by default\n *\n * @example\n * ```tsx\n * import { filter, pagedQuery } from '@ahoo-wang/wow-client';\n * import { useFetcherPagedQuery } from '@ahoo-wang/wow-react';\n *\n * function PaidOrders({ page }: { page: number }) {\n * const { result, loading, error } = useFetcherPagedQuery<OrderState>({\n * url: 'order/snapshot/paged/state',\n * query: pagedQuery({\n * filter: filter.eq('state.status', 'PAID'),\n * pagination: { index: page, size: 20 },\n * }),\n * });\n * if (error) return <p role=\"alert\">{error.message}</p>;\n * if (loading || !result) return <p>Loading…</p>;\n * return <p>{result.list.length} of {result.total}</p>;\n * }\n * ```\n */\nexport function useFetcherPagedQuery<\n R,\n FIELDS extends string = string,\n E = Error,\n>(\n options: UseFetcherPagedQueryOptions<R, FIELDS, E, FilterPagedQuery<FIELDS>>,\n): UseFetcherPagedQueryReturn<R, FIELDS, E, FilterPagedQuery<FIELDS>>;\nexport function useFetcherPagedQuery<\n R,\n FIELDS extends string = string,\n E = Error,\n>(\n options: UseFetcherPagedQueryOptions<R, FIELDS, E, PagedQuery<FIELDS>>,\n): UseFetcherPagedQueryReturn<R, FIELDS, E, PagedQuery<FIELDS>>;\nexport function useFetcherPagedQuery<\n R,\n FIELDS extends string = string,\n E = Error,\n Q extends PagedQueryRequest<FIELDS> = FilterPagedQuery<FIELDS>,\n>(\n options: UseFetcherPagedQueryOptions<R, FIELDS, E, Q>,\n): UseFetcherPagedQueryReturn<R, FIELDS, E, Q>;\nexport function useFetcherPagedQuery<\n R,\n FIELDS extends string,\n E,\n Q extends PagedQueryRequest<FIELDS>,\n>(\n options: UseFetcherPagedQueryOptions<R, FIELDS, E, Q>,\n): UseFetcherPagedQueryReturn<R, FIELDS, E, Q> {\n return useEndpointRunner<Q, PagedList<R>, E>(options);\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { FilterSingleQuery } from '@ahoo-wang/wow-client';\n// compat(wow<9): the hook also takes the Condition-based queries of `@ahoo-wang/wow-client/legacy`, which Wow < 8.11 needs; drop that overload in v10.\nimport type {\n SingleQuery,\n SingleQueryRequest,\n} from '@ahoo-wang/wow-client/legacy';\nimport type { Endpoint } from '../internal/endpoint.js';\nimport { useEndpointRunner } from '../internal/useEndpointRunner.js';\nimport type { QueryHookOptions, QueryHookReturn } from '../types.js';\n\n/**\n * Options of {@link useFetcherSingleQuery}: those of every query hook, with\n * the endpoint and the Fetcher in place of `execute`.\n *\n * @template R - The item the query returns\n * @template FIELDS - The field names the query may use\n * @template E - The error type, `Error` by default\n * @template Q - The query type: `FilterSingleQuery` by default\n */\nexport interface UseFetcherSingleQueryOptions<\n R,\n FIELDS extends string = string,\n E = Error,\n Q extends SingleQueryRequest<FIELDS> = FilterSingleQuery<FIELDS>,\n>\n extends Omit<QueryHookOptions<Q, R, E>, 'execute'>, Endpoint {}\n\n/**\n * What {@link useFetcherSingleQuery} returns: the item as `result`.\n *\n * @template R - The item the query returns\n * @template FIELDS - The field names the query may use\n * @template E - The error type, `Error` by default\n * @template Q - The query type: `FilterSingleQuery` by default\n */\nexport interface UseFetcherSingleQueryReturn<\n R,\n FIELDS extends string = string,\n E = Error,\n Q extends SingleQueryRequest<FIELDS> = FilterSingleQuery<FIELDS>,\n> extends QueryHookReturn<Q, R, E> {}\n\n/**\n * POSTs a single query to a Wow endpoint through a Fetcher and keeps the\n * result as state.\n *\n * `url` is resolved against the Fetcher's `baseURL`; `fetcher` is a Fetcher\n * or the name of a registered one, the default Fetcher when omitted. The\n * query runs on mount and whenever `query` or `setQuery()` changes it; set\n * `autoExecute: false` to run it only through `execute()`. A newer query\n * aborts the request in flight, so a late response never overwrites a newer\n * one; an unmount aborts it too.\n *\n * A change of `url`, or of `fetcher`, runs the query again. A Fetcher is\n * compared by its name, or by its `baseURL` when it has none, so one created\n * inline in render does not run it on every render.\n *\n * Returns `result` (the item, or `undefined` before the first success),\n * `loading`, `error`, `status`, `execute`, `abort`, `reset`, `getQuery` and\n * `setQuery`. A failed request sets `error` to a `FetcherError`;\n * `toWowError(error)` from `@ahoo-wang/wow-client` reads the server's\n * `errorCode` from it.\n *\n * @template R - The item the query returns\n * @template FIELDS - The field names the query may use\n * @template E - The error type, `Error` by default\n *\n * @example\n * ```tsx\n * import { filter, singleQuery } from '@ahoo-wang/wow-client';\n * import { useFetcherSingleQuery } from '@ahoo-wang/wow-react';\n *\n * function OrderStatus({ id }: { id: string }) {\n * const { result, loading, error } = useFetcherSingleQuery<OrderState>({\n * url: 'order/snapshot/single/state',\n * query: singleQuery({ filter: filter.id(id) }),\n * });\n * if (error) return <p role=\"alert\">{error.message}</p>;\n * if (loading || !result) return <p>Loading…</p>;\n * return <p>{result.status}</p>;\n * }\n * ```\n */\nexport function useFetcherSingleQuery<\n R,\n FIELDS extends string = string,\n E = Error,\n>(\n options: UseFetcherSingleQueryOptions<\n R,\n FIELDS,\n E,\n FilterSingleQuery<FIELDS>\n >,\n): UseFetcherSingleQueryReturn<R, FIELDS, E, FilterSingleQuery<FIELDS>>;\nexport function useFetcherSingleQuery<\n R,\n FIELDS extends string = string,\n E = Error,\n>(\n options: UseFetcherSingleQueryOptions<R, FIELDS, E, SingleQuery<FIELDS>>,\n): UseFetcherSingleQueryReturn<R, FIELDS, E, SingleQuery<FIELDS>>;\nexport function useFetcherSingleQuery<\n R,\n FIELDS extends string = string,\n E = Error,\n Q extends SingleQueryRequest<FIELDS> = FilterSingleQuery<FIELDS>,\n>(\n options: UseFetcherSingleQueryOptions<R, FIELDS, E, Q>,\n): UseFetcherSingleQueryReturn<R, FIELDS, E, Q>;\nexport function useFetcherSingleQuery<\n R,\n FIELDS extends string,\n E,\n Q extends SingleQueryRequest<FIELDS>,\n>(\n options: UseFetcherSingleQueryOptions<R, FIELDS, E, Q>,\n): UseFetcherSingleQueryReturn<R, FIELDS, E, Q> {\n return useEndpointRunner<Q, R, E>(options);\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { FilterListQuery } from '@ahoo-wang/wow-client';\n// compat(wow<9): the hook also takes the Condition-based queries of `@ahoo-wang/wow-client/legacy`, which Wow < 8.11 needs; drop that overload in v10.\nimport type { ListQuery, ListQueryRequest } from '@ahoo-wang/wow-client/legacy';\nimport { useQueryRunner } from '../internal/useQueryRunner.js';\nimport type { QueryHookOptions, QueryHookReturn } from '../types.js';\n\n/**\n * Options of {@link useListQuery}: a list query and an `execute` that resolves\n * to its rows.\n *\n * @template R - One row of the list\n * @template FIELDS - The field names the query may use\n * @template E - The error type, `Error` by default\n * @template Q - The query type: `FilterListQuery` by default\n */\nexport interface UseListQueryOptions<\n R,\n FIELDS extends string = string,\n E = Error,\n Q extends ListQueryRequest<FIELDS> = FilterListQuery<FIELDS>,\n> extends QueryHookOptions<Q, R[], E> {}\n\n/**\n * What {@link useListQuery} returns: the rows as `result`.\n *\n * @template R - One row of the list\n * @template FIELDS - The field names the query may use\n * @template E - The error type, `Error` by default\n * @template Q - The query type: `FilterListQuery` by default\n */\nexport interface UseListQueryReturn<\n R,\n FIELDS extends string = string,\n E = Error,\n Q extends ListQueryRequest<FIELDS> = FilterListQuery<FIELDS>,\n> extends QueryHookReturn<Q, R[], E> {}\n\n/**\n * Runs a list query through your own `execute` function and keeps the rows\n * as state: typically a query client's `list` or `listState`.\n *\n * `execute` receives the query, the `attributes` option and an\n * `AbortController`; hand the controller on so that a newer query, `abort()`\n * or an unmount cancels the request. The query runs on mount and whenever\n * `query` or `setQuery()` changes it; set `autoExecute: false` to run it only\n * through `execute()`.\n *\n * Returns `result` (the rows, or `undefined` before the first success),\n * `loading`, `error`, `status`, `execute`, `abort`, `reset`, `getQuery` and\n * `setQuery`.\n *\n * @template R - One row of the list\n * @template FIELDS - The field names the query may use. With a client whose\n * fields are narrower than `string`, as a generated client's are, pass\n * them here: TypeScript does not infer them from `execute` once `R` is given\n * @template E - The error type, `Error` by default\n *\n * @example\n * ```tsx\n * import { desc, filter, listQuery, type SnapshotQueryClient } from '@ahoo-wang/wow-client';\n * import { useListQuery } from '@ahoo-wang/wow-react';\n *\n * function LatestOrders({ client }: { client: SnapshotQueryClient<OrderState, OrderFields> }) {\n * const { result, loading, error } = useListQuery<OrderState, OrderFields>({\n * initialQuery: listQuery({\n * filter: filter.eq('state.status', 'PAID'),\n * sort: [desc('createTime')],\n * limit: 20,\n * }),\n * execute: (query, attributes, abortController) =>\n * client.listState(query, attributes, abortController),\n * });\n * if (error) return <p role=\"alert\">{error.message}</p>;\n * if (loading || !result) return <p>Loading…</p>;\n * return <ul>{result.map(order => <li key={order.id}>{order.id}</li>)}</ul>;\n * }\n * ```\n */\nexport function useListQuery<R, FIELDS extends string = string, E = Error>(\n options: UseListQueryOptions<R, FIELDS, E, FilterListQuery<FIELDS>>,\n): UseListQueryReturn<R, FIELDS, E, FilterListQuery<FIELDS>>;\nexport function useListQuery<R, FIELDS extends string = string, E = Error>(\n options: UseListQueryOptions<R, FIELDS, E, ListQuery<FIELDS>>,\n): UseListQueryReturn<R, FIELDS, E, ListQuery<FIELDS>>;\nexport function useListQuery<\n R,\n FIELDS extends string = string,\n E = Error,\n Q extends ListQueryRequest<FIELDS> = FilterListQuery<FIELDS>,\n>(\n options: UseListQueryOptions<R, FIELDS, E, Q>,\n): UseListQueryReturn<R, FIELDS, E, Q>;\nexport function useListQuery<\n R,\n FIELDS extends string,\n E,\n Q extends ListQueryRequest<FIELDS>,\n>(\n options: UseListQueryOptions<R, FIELDS, E, Q>,\n): UseListQueryReturn<R, FIELDS, E, Q> {\n return useQueryRunner<Q, R[], E>(options);\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { FilterListQuery } from '@ahoo-wang/wow-client';\n// compat(wow<9): the hook also takes the Condition-based queries of `@ahoo-wang/wow-client/legacy`, which Wow < 8.11 needs; drop that overload in v10.\nimport type { ListQuery, ListQueryRequest } from '@ahoo-wang/wow-client/legacy';\nimport { useListStream } from '../internal/useListStream.js';\nimport type {\n ListStreamExecutor,\n QueryHookOptions,\n QueryHookReturn,\n} from '../types.js';\n\n/**\n * Options of {@link useListStreamQuery}: those of every query hook, with an\n * `execute` that opens the stream.\n *\n * `onSuccess` receives every row once the stream has ended.\n *\n * @template R - One row of the stream: the `data` of each event\n * @template FIELDS - The field names the query may use\n * @template E - The error type, `Error` by default: a failed request\n * rejects with a `FetcherError`, an error event in the stream with a\n * `WowError`\n * @template Q - The query type: `FilterListQuery` by default\n */\nexport interface UseListStreamQueryOptions<\n R,\n FIELDS extends string = string,\n E = Error,\n Q extends ListQueryRequest<FIELDS> = FilterListQuery<FIELDS>,\n> extends Omit<QueryHookOptions<Q, R[], E>, 'execute'> {\n /** Opens the stream for a query. */\n execute: ListStreamExecutor<R, Q>;\n}\n\n/**\n * What {@link useListStreamQuery} and `useFetcherListStreamQuery` return: the\n * rows as they arrive, and whether the stream has ended.\n *\n * - `items` — the rows of the current query received so far, in order,\n * updated at most about once a frame (every 16 ms) while they arrive. A new\n * query starts from an empty list; `reset()` empties it; `abort()` and an\n * error keep the rows received before them.\n * - `done` — the stream ended normally and `items` holds every row.\n * - `loading` — from the request until the stream ends, fails or is aborted.\n * - `error` — the request failed (`FetcherError`), or the server sent an error\n * event in the stream (`WowError`, with its `errorCode`).\n * - `status` — `idle`, `loading`, `success` (the same as `done`) or `error`.\n * - `execute()` runs the current query again and aborts the stream in flight;\n * `abort()` stops the stream; `reset()` stops it and empties `items`.\n */\nexport interface UseListStreamQueryReturn<\n R,\n FIELDS extends string = string,\n E = Error,\n Q extends ListQueryRequest<FIELDS> = FilterListQuery<FIELDS>,\n> extends Omit<QueryHookReturn<Q, R[], E>, 'result'> {\n /**\n * The rows of the current query received so far, a new array at every\n * update.\n */\n items: R[];\n /** Whether the stream ended normally, so `items` holds every row. */\n done: boolean;\n}\n\n/**\n * Streams the rows of a list query as server-sent events and keeps them as\n * state.\n *\n * The hook owns the stream: it reads it, collects the rows into `items`, and\n * cancels it when a newer query starts, on `abort()` or `reset()`, and on\n * unmount. Components render `items` and never hold a reader, so the hook is\n * safe under StrictMode. `autoExecute` defaults to `true`.\n *\n * Pass a query client method as `execute` — it sends\n * `Accept: text/event-stream` and turns error events into a `WowError` — or\n * use `useFetcherListStreamQuery` with a URL.\n *\n * @template R - One row of the stream: the `data` of each event\n * @template FIELDS - The field names the query may use. With a client whose\n * fields are narrower than `string`, as a generated client's are, pass\n * them here: TypeScript does not infer them from `execute` once `R` is given\n * @template E - The error type\n *\n * @example\n * ```tsx\n * import { filter, listQuery, type SnapshotQueryClient } from '@ahoo-wang/wow-client';\n * import { useListStreamQuery } from '@ahoo-wang/wow-react';\n *\n * function PaidOrders({ client }: { client: SnapshotQueryClient<OrderState, OrderFields> }) {\n * const { items, done, loading, error, abort } = useListStreamQuery<OrderState, OrderFields>({\n * initialQuery: listQuery({ filter: filter.eq('state.status', 'PAID') }),\n * execute: (query, attributes, abortController) =>\n * client.listStateStream(query, attributes, abortController),\n * });\n * if (error) return <p role=\"alert\">{error.message}</p>;\n * return (\n * <>\n * <ul>{items.map(order => <li key={order.id}>{order.id}</li>)}</ul>\n * {loading && <button onClick={abort}>Stop</button>}\n * {done && <p>{items.length} orders</p>}\n * </>\n * );\n * }\n * ```\n */\nexport function useListStreamQuery<\n R,\n FIELDS extends string = string,\n E = Error,\n>(\n options: UseListStreamQueryOptions<R, FIELDS, E, FilterListQuery<FIELDS>>,\n): UseListStreamQueryReturn<R, FIELDS, E, FilterListQuery<FIELDS>>;\nexport function useListStreamQuery<\n R,\n FIELDS extends string = string,\n E = Error,\n>(\n options: UseListStreamQueryOptions<R, FIELDS, E, ListQuery<FIELDS>>,\n): UseListStreamQueryReturn<R, FIELDS, E, ListQuery<FIELDS>>;\nexport function useListStreamQuery<\n R,\n FIELDS extends string = string,\n E = Error,\n Q extends ListQueryRequest<FIELDS> = FilterListQuery<FIELDS>,\n>(\n options: UseListStreamQueryOptions<R, FIELDS, E, Q>,\n): UseListStreamQueryReturn<R, FIELDS, E, Q>;\nexport function useListStreamQuery<\n R,\n FIELDS extends string,\n E,\n Q extends ListQueryRequest<FIELDS>,\n>(\n options: UseListStreamQueryOptions<R, FIELDS, E, Q>,\n): UseListStreamQueryReturn<R, FIELDS, E, Q> {\n return useListStream<R, FIELDS, E, Q>(options);\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { FilterPagedQuery, PagedList } from '@ahoo-wang/wow-client';\n// compat(wow<9): the hook also takes the Condition-based queries of `@ahoo-wang/wow-client/legacy`, which Wow < 8.11 needs; drop that overload in v10.\nimport type {\n PagedQuery,\n PagedQueryRequest,\n} from '@ahoo-wang/wow-client/legacy';\nimport { useQueryRunner } from '../internal/useQueryRunner.js';\nimport type { QueryHookOptions, QueryHookReturn } from '../types.js';\n\n/**\n * Options of {@link usePagedQuery}: a paged query and an `execute` that\n * resolves to one page.\n *\n * @template R - One row of the page\n * @template FIELDS - The field names the query may use\n * @template E - The error type, `Error` by default\n * @template Q - The query type: `FilterPagedQuery` by default\n */\nexport interface UsePagedQueryOptions<\n R,\n FIELDS extends string = string,\n E = Error,\n Q extends PagedQueryRequest<FIELDS> = FilterPagedQuery<FIELDS>,\n> extends QueryHookOptions<Q, PagedList<R>, E> {}\n\n/**\n * What {@link usePagedQuery} returns: the page (`total` and `list`) as\n * `result`.\n *\n * @template R - One row of the page\n * @template FIELDS - The field names the query may use\n * @template E - The error type, `Error` by default\n * @template Q - The query type: `FilterPagedQuery` by default\n */\nexport interface UsePagedQueryReturn<\n R,\n FIELDS extends string = string,\n E = Error,\n Q extends PagedQueryRequest<FIELDS> = FilterPagedQuery<FIELDS>,\n> extends QueryHookReturn<Q, PagedList<R>, E> {}\n\n/**\n * Runs a paged query through your own `execute` function and keeps the page\n * as state: typically a query client's `paged` or `pagedState`.\n *\n * `execute` receives the query, the `attributes` option and an\n * `AbortController`; hand the controller on so that a newer query, `abort()`\n * or an unmount cancels the request. The query runs on mount and whenever\n * `query` or `setQuery()` changes it — turn pages with `setQuery()`; set\n * `autoExecute: false` to run it only through `execute()`.\n *\n * Returns `result` (`{ total, list }`, or `undefined` before the first\n * success), `loading`, `error`, `status`, `execute`, `abort`, `reset`,\n * `getQuery` and `setQuery`.\n *\n * @template R - One row of the page\n * @template FIELDS - The field names the query may use. With a client whose\n * fields are narrower than `string`, as a generated client's are, pass\n * them here: TypeScript does not infer them from `execute` once `R` is given\n * @template E - The error type, `Error` by default\n *\n * @example\n * ```tsx\n * import { filter, pagedQuery, type SnapshotQueryClient } from '@ahoo-wang/wow-client';\n * import { usePagedQuery } from '@ahoo-wang/wow-react';\n *\n * function PaidOrders({ client, page }: { client: SnapshotQueryClient<OrderState, OrderFields>; page: number }) {\n * const { result, loading, error } = usePagedQuery<OrderState, OrderFields>({\n * query: pagedQuery({\n * filter: filter.eq('state.status', 'PAID'),\n * pagination: { index: page, size: 20 },\n * }),\n * execute: (query, attributes, abortController) =>\n * client.pagedState(query, attributes, abortController),\n * });\n * if (error) return <p role=\"alert\">{error.message}</p>;\n * if (loading || !result) return <p>Loading…</p>;\n * return <p>{result.list.length} of {result.total}</p>;\n * }\n * ```\n */\nexport function usePagedQuery<R, FIELDS extends string = string, E = Error>(\n options: UsePagedQueryOptions<R, FIELDS, E, FilterPagedQuery<FIELDS>>,\n): UsePagedQueryReturn<R, FIELDS, E, FilterPagedQuery<FIELDS>>;\nexport function usePagedQuery<R, FIELDS extends string = string, E = Error>(\n options: UsePagedQueryOptions<R, FIELDS, E, PagedQuery<FIELDS>>,\n): UsePagedQueryReturn<R, FIELDS, E, PagedQuery<FIELDS>>;\nexport function usePagedQuery<\n R,\n FIELDS extends string = string,\n E = Error,\n Q extends PagedQueryRequest<FIELDS> = FilterPagedQuery<FIELDS>,\n>(\n options: UsePagedQueryOptions<R, FIELDS, E, Q>,\n): UsePagedQueryReturn<R, FIELDS, E, Q>;\nexport function usePagedQuery<\n R,\n FIELDS extends string,\n E,\n Q extends PagedQueryRequest<FIELDS>,\n>(\n options: UsePagedQueryOptions<R, FIELDS, E, Q>,\n): UsePagedQueryReturn<R, FIELDS, E, Q> {\n return useQueryRunner<Q, PagedList<R>, E>(options);\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { FilterSingleQuery } from '@ahoo-wang/wow-client';\n// compat(wow<9): the hook also takes the Condition-based queries of `@ahoo-wang/wow-client/legacy`, which Wow < 8.11 needs; drop that overload in v10.\nimport type {\n SingleQuery,\n SingleQueryRequest,\n} from '@ahoo-wang/wow-client/legacy';\nimport { useQueryRunner } from '../internal/useQueryRunner.js';\nimport type { QueryHookOptions, QueryHookReturn } from '../types.js';\n\n/**\n * Options of {@link useSingleQuery}: a single query and an `execute` that\n * resolves to one item.\n *\n * @template R - The item the query returns\n * @template FIELDS - The field names the query may use\n * @template E - The error type, `Error` by default\n * @template Q - The query type: `FilterSingleQuery` by default\n */\nexport interface UseSingleQueryOptions<\n R,\n FIELDS extends string = string,\n E = Error,\n Q extends SingleQueryRequest<FIELDS> = FilterSingleQuery<FIELDS>,\n> extends QueryHookOptions<Q, R, E> {}\n\n/**\n * What {@link useSingleQuery} returns: the item as `result`.\n *\n * @template R - The item the query returns\n * @template FIELDS - The field names the query may use\n * @template E - The error type, `Error` by default\n * @template Q - The query type: `FilterSingleQuery` by default\n */\nexport interface UseSingleQueryReturn<\n R,\n FIELDS extends string = string,\n E = Error,\n Q extends SingleQueryRequest<FIELDS> = FilterSingleQuery<FIELDS>,\n> extends QueryHookReturn<Q, R, E> {}\n\n/**\n * Runs a single query through your own `execute` function and keeps the\n * result as state: typically a query client's `single` or `singleState`.\n *\n * `execute` receives the query, the `attributes` option and an\n * `AbortController`; hand the controller on so that a newer query, `abort()`\n * or an unmount cancels the request. The query runs on mount and whenever\n * `query` or `setQuery()` changes it; set `autoExecute: false` to run it only\n * through `execute()`.\n *\n * Returns `result` (the item, or `undefined` before the first success),\n * `loading`, `error`, `status`, `execute`, `abort`, `reset`, `getQuery` and\n * `setQuery`.\n *\n * @template R - The item the query returns\n * @template FIELDS - The field names the query may use. With a client whose\n * fields are narrower than `string`, as a generated client's are, pass\n * them here: TypeScript does not infer them from `execute` once `R` is given\n * @template E - The error type, `Error` by default\n *\n * @example\n * ```tsx\n * import { filter, singleQuery, type SnapshotQueryClient } from '@ahoo-wang/wow-client';\n * import { useSingleQuery } from '@ahoo-wang/wow-react';\n *\n * function OrderStatus({ client, id }: { client: SnapshotQueryClient<OrderState, OrderFields>; id: string }) {\n * const { result, loading, error } = useSingleQuery<OrderState, OrderFields>({\n * query: singleQuery({ filter: filter.id(id) }),\n * execute: (query, attributes, abortController) =>\n * client.singleState(query, attributes, abortController),\n * });\n * if (error) return <p role=\"alert\">{error.message}</p>;\n * if (loading || !result) return <p>Loading…</p>;\n * return <p>{result.status}</p>;\n * }\n * ```\n */\nexport function useSingleQuery<R, FIELDS extends string = string, E = Error>(\n options: UseSingleQueryOptions<R, FIELDS, E, FilterSingleQuery<FIELDS>>,\n): UseSingleQueryReturn<R, FIELDS, E, FilterSingleQuery<FIELDS>>;\nexport function useSingleQuery<R, FIELDS extends string = string, E = Error>(\n options: UseSingleQueryOptions<R, FIELDS, E, SingleQuery<FIELDS>>,\n): UseSingleQueryReturn<R, FIELDS, E, SingleQuery<FIELDS>>;\nexport function useSingleQuery<\n R,\n FIELDS extends string = string,\n E = Error,\n Q extends SingleQueryRequest<FIELDS> = FilterSingleQuery<FIELDS>,\n>(\n options: UseSingleQueryOptions<R, FIELDS, E, Q>,\n): UseSingleQueryReturn<R, FIELDS, E, Q>;\nexport function useSingleQuery<\n R,\n FIELDS extends string,\n E,\n Q extends SingleQueryRequest<FIELDS>,\n>(\n options: UseSingleQueryOptions<R, FIELDS, E, Q>,\n): UseSingleQueryReturn<R, FIELDS, E, Q> {\n return useQueryRunner<Q, R, E>(options);\n}\n"],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ import { Fetcher } from '@ahoo-wang/fetcher';
2
+ import { ListStreamExecutor, QueryExecutor } from '../types.js';
3
+ /**
4
+ * Where a `useFetcher…` hook sends its query. Every `useFetcher…Options`
5
+ * extends it, so the two members are declared, and documented, once.
6
+ */
7
+ export interface Endpoint {
8
+ /**
9
+ * The query endpoint, resolved against the Fetcher's `baseURL`: for example
10
+ * `order/snapshot/list/state` for the states of an `order` aggregate, or
11
+ * `order/snapshot/count` for the count of its snapshots.
12
+ */
13
+ url: string;
14
+ /**
15
+ * The Fetcher that sends the request, or the name of a registered one; the
16
+ * default Fetcher when omitted.
17
+ */
18
+ fetcher?: string | Fetcher;
19
+ }
20
+ /**
21
+ * Runs a query by POSTing it to the endpoint and reading the JSON answer.
22
+ * The Fetcher is resolved when the request is sent, so a name that is not
23
+ * registered fails that request, and the hook reports it as its `error`.
24
+ */
25
+ export declare function postQuery<Q extends object, R>({ url, fetcher, }: Endpoint): QueryExecutor<Q, R>;
26
+ /**
27
+ * Opens the stream of a list query by POSTing it to the endpoint with
28
+ * wow-client's `QUERY_STREAM_ENDPOINT`: `Accept: text/event-stream`, and an
29
+ * extractor that answers the rows and ends the stream with a `WowError` at
30
+ * the server's error event.
31
+ */
32
+ export declare function postQueryStream<R, Q extends object>({ url, fetcher, }: Endpoint): ListStreamExecutor<R, Q>;
33
+ /**
34
+ * What identifies an endpoint across renders: the url, and the Fetcher by
35
+ * its name, or by its `baseURL` when it has none. A hook runs its query
36
+ * again when this changes; a `new Fetcher({ baseURL })` written inline in
37
+ * render keeps the same identity, so it does not run the query on every
38
+ * render. Two unnamed Fetchers with one `baseURL` but different
39
+ * interceptors count as the same; name them to tell them apart.
40
+ */
41
+ export declare function endpointIdentity({ url, fetcher }: Endpoint): string;
@@ -0,0 +1,40 @@
1
+ import { QueryStatus } from '../types.js';
2
+ /** What a query hook shows at one moment. */
3
+ export interface QueryState<R, E> {
4
+ status: QueryStatus;
5
+ result: R | undefined;
6
+ error: E | undefined;
7
+ }
8
+ /** Something that happens to a query hook. */
9
+ export type QueryEvent<R, E> = {
10
+ type: 'start';
11
+ } | {
12
+ type: 'succeed';
13
+ result: R | undefined;
14
+ } | {
15
+ type: 'fail';
16
+ error: E;
17
+ } | {
18
+ type: 'abort';
19
+ } | {
20
+ type: 'reset';
21
+ };
22
+ /**
23
+ * The first state. A hook that will run its query as soon as it mounts
24
+ * starts `loading`, so the server and the first client frame already show
25
+ * what the next frames show; any other starts `idle`.
26
+ */
27
+ export declare function initialQueryState<R, E>(runsOnMount: boolean): QueryState<R, E>;
28
+ /**
29
+ * The state after one event:
30
+ *
31
+ * - `start`: `loading`; the last result stays until the new one arrives, the
32
+ * error goes.
33
+ * - `succeed`: `success` with the new result (`undefined` for a hook that
34
+ * keeps its own, as the list-stream hooks keep `items`).
35
+ * - `fail`: `error`; the last result stays, so a failed refresh does not
36
+ * blank what was shown.
37
+ * - `abort`: `idle`; the last result stays, the error goes.
38
+ * - `reset`: `idle`, with neither result nor error.
39
+ */
40
+ export declare function queryTransition<R, E>(state: QueryState<R, E>, event: QueryEvent<R, E>): QueryState<R, E>;
@@ -0,0 +1,25 @@
1
+ /**
2
+ * The least time between two publishes while a stream is read: about one
3
+ * frame, so the rows keep up with the screen while a long stream costs a
4
+ * bounded number of renders.
5
+ */
6
+ export declare const PUBLISH_INTERVAL_MS = 16;
7
+ /**
8
+ * Reads a stream of rows to its end and resolves to every row, in order.
9
+ *
10
+ * While it reads, it hands the rows received so far to `publish`: the first
11
+ * rows on the next macrotask, then at most once every
12
+ * {@link PUBLISH_INTERVAL_MS}. Publishing by time, not by network chunk,
13
+ * bounds how often a long stream renders and copies its rows: one render per
14
+ * interval however many chunks arrive in it, and each `publish` still gets a
15
+ * new array. It publishes the last rows before it
16
+ * resolves or rejects, so the rows before a failure stay visible.
17
+ *
18
+ * `signal` aborting cancels the stream — a fake or already-buffered body
19
+ * does not end with the request — and stops every later `publish`: a newer
20
+ * query or an unmount has taken over, and its rows must not be overwritten.
21
+ * The reader is always released, so the stream never stays locked.
22
+ *
23
+ * Internal: not exported from the package.
24
+ */
25
+ export declare function readStreamRows<R>(stream: ReadableStream<R>, signal: AbortSignal, publish: (rows: R[]) => void): Promise<R[]>;
@@ -0,0 +1,8 @@
1
+ import { QueryHookOptions, QueryHookReturn } from '../types.js';
2
+ import { Endpoint } from './endpoint.js';
3
+ /**
4
+ * The request `useFetcher…` hooks: the runner with the endpoint's executor as
5
+ * `execute`, and the endpoint as part of the request's identity, so a change
6
+ * of `url` or `fetcher` runs the query again.
7
+ */
8
+ export declare function useEndpointRunner<Q extends object, R, E>(options: Omit<QueryHookOptions<Q, R, E>, 'execute'> & Endpoint): QueryHookReturn<Q, R, E>;
@@ -0,0 +1,11 @@
1
+ import { ListQueryRequest } from '@ahoo-wang/wow-client/legacy';
2
+ import { UseListStreamQueryOptions, UseListStreamQueryReturn } from '../hooks/useListStreamQuery.js';
3
+ /**
4
+ * The list-stream hooks on the request state machine: a run opens the
5
+ * stream and reads it into `items`. Each run starts from no rows; `abort()`
6
+ * and an error keep the rows received; `reset()` empties them. The runner
7
+ * aborts the run's controller whenever the run stops counting, and
8
+ * readStreamRows stops publishing then, so rows of a stale stream never
9
+ * reach `items`.
10
+ */
11
+ export declare function useListStream<R, FIELDS extends string, E, Q extends ListQueryRequest<FIELDS>>(options: UseListStreamQueryOptions<R, FIELDS, E, Q>, identity?: string): UseListStreamQueryReturn<R, FIELDS, E, Q>;
@@ -0,0 +1,21 @@
1
+ import { QueryHookOptions, QueryHookReturn } from '../types.js';
2
+ /**
3
+ * The one request state machine every hook runs on.
4
+ *
5
+ * - Latest wins: every run takes a new number and aborts the one before; an
6
+ * answer that is no longer the latest, arrives after `abort()` or
7
+ * `reset()`, or arrives after unmount, changes nothing.
8
+ * - A run starts on mount, whenever the query changes by content or through
9
+ * `setQuery()`, whenever `identity` changes, and when `autoExecute` turns
10
+ * on; `execute()` starts one by hand.
11
+ * - `abort()`, `reset()` and unmount abort the request in flight.
12
+ * - StrictMode's second mount aborts the first run and starts one more, so
13
+ * exactly one answer lands.
14
+ *
15
+ * `identity` is what else a run depends on besides the query: the endpoint
16
+ * of a `useFetcher…` hook. With `retainResult` off the runner hands a run's
17
+ * result to `onSuccess` but does not keep it as `result`: the list-stream
18
+ * hooks keep their rows as `items` already. `execute`, `attributes` and the callbacks are read
19
+ * when a run starts or settles, so a change to them never starts one.
20
+ */
21
+ export declare function useQueryRunner<Q, R, E>(options: QueryHookOptions<Q, R, E>, identity?: string, retainResult?: boolean): QueryHookReturn<Q, R, E>;
@@ -0,0 +1,114 @@
1
+ /**
2
+ * Where a query hook stands:
3
+ *
4
+ * - `idle` — nothing has run yet, or `abort()` or `reset()` stopped it;
5
+ * - `loading` — a request is in flight, or is about to be: a hook that runs
6
+ * its query on mount already renders its first frame, on the server too,
7
+ * as `loading`;
8
+ * - `success` — the latest request answered, and `result` holds its answer;
9
+ * - `error` — the latest request failed, and `error` says why.
10
+ *
11
+ * A plain string union, so a literal such as `'success'` can be written
12
+ * wherever a status is expected: a component's props, a test, a story.
13
+ */
14
+ export type QueryStatus = 'idle' | 'loading' | 'success' | 'error';
15
+ /**
16
+ * Runs one query: a query client method such as `pagedState`, or any function
17
+ * that resolves to the result.
18
+ *
19
+ * wow-client's clients, generated ones included, bind their methods, so
20
+ * `execute: client.pagedState` works as is. A method of an object of your own
21
+ * loses its `this` when handed over: pass `method.bind(object)` or an arrow
22
+ * function instead.
23
+ *
24
+ * It receives the query, the hook's `attributes` option, and the
25
+ * `AbortController` of this run. Hand the controller on to the request, so
26
+ * that a newer query, `abort()`, `reset()` or an unmount cancels it; every
27
+ * wow-client query method takes it as its last parameter.
28
+ *
29
+ * @template Q - The query
30
+ * @template R - What the query resolves to
31
+ */
32
+ export type QueryExecutor<Q, R> = (query: Q, attributes: Record<string, unknown> | undefined, abortController: AbortController) => Promise<R>;
33
+ /**
34
+ * Opens the event stream of one query: a query client's `listStream` or
35
+ * `listStateStream`, or any function that resolves to a stream of rows. It
36
+ * receives what a {@link QueryExecutor} receives.
37
+ *
38
+ * @template R - One row of the stream
39
+ * @template Q - The query
40
+ */
41
+ export type ListStreamExecutor<R, Q> = QueryExecutor<Q, ReadableStream<R>>;
42
+ /**
43
+ * The options every query hook takes. Each `Use…QueryOptions` extends it with
44
+ * its own query and result types; the `useFetcher…` hooks take `url` and
45
+ * `fetcher` in place of `execute`.
46
+ *
47
+ * @template Q - The query
48
+ * @template R - What the query resolves to
49
+ * @template E - The error the hook reports, `Error` by default
50
+ */
51
+ export interface QueryHookOptions<Q, R, E = Error> {
52
+ /**
53
+ * The query, controlled: the hook runs it again whenever it changes by
54
+ * content, so a new object with the same content does not. Set to
55
+ * `undefined` after a query (`id ? singleQuery(…) : undefined`), it aborts
56
+ * the request in flight and goes `idle`, keeping the last result, as
57
+ * `abort()` does; nothing runs until a query is given again.
58
+ */
59
+ query?: Q;
60
+ /** The first query, uncontrolled: change it later with `setQuery()`. */
61
+ initialQuery?: Q;
62
+ /**
63
+ * Whether the query runs on mount and whenever it changes; `true` by
64
+ * default. With `false` it runs only through `execute()`.
65
+ */
66
+ autoExecute?: boolean;
67
+ /** Handed to `execute` with every run; not part of what identifies a run. */
68
+ attributes?: Record<string, unknown>;
69
+ /** Runs one query. */
70
+ execute: QueryExecutor<Q, R>;
71
+ /** Called with the result of each run that succeeds. */
72
+ onSuccess?: (result: R) => void | Promise<void>;
73
+ /** Called with the error of each run that fails. */
74
+ onError?: (error: E) => void | Promise<void>;
75
+ }
76
+ /**
77
+ * What every query hook returns. Each `Use…QueryReturn` extends it with its own
78
+ * query and result types; the list-stream hooks return `items` and `done` in
79
+ * place of `result`.
80
+ *
81
+ * @template Q - The query
82
+ * @template R - What the query resolves to
83
+ * @template E - The error the hook reports, `Error` by default
84
+ */
85
+ export interface QueryHookReturn<Q, R, E = Error> {
86
+ /** Where the hook stands; see {@link QueryStatus}. */
87
+ status: QueryStatus;
88
+ /** Whether a request is in flight: the same as `status === 'loading'`. */
89
+ loading: boolean;
90
+ /**
91
+ * The result of the latest successful run, or `undefined`. A failed run,
92
+ * `abort()` and a new run keep it until a new result arrives; only
93
+ * `reset()` clears it.
94
+ */
95
+ result: R | undefined;
96
+ /** Why the latest run failed, or `undefined`. */
97
+ error: E | undefined;
98
+ /** Runs the current query again, aborting the request in flight. */
99
+ execute: () => Promise<void>;
100
+ /**
101
+ * Aborts the request in flight and returns to `idle`, keeping `result`;
102
+ * a late answer to that request is dropped.
103
+ */
104
+ abort: () => void;
105
+ /**
106
+ * Aborts the request in flight, returns to `idle`, and clears `result` and
107
+ * `error`; a late answer to that request is dropped.
108
+ */
109
+ reset: () => void;
110
+ /** The current query. */
111
+ getQuery: () => Q | undefined;
112
+ /** Replaces the query; it runs when `autoExecute` is on. */
113
+ setQuery: (query: Q) => void;
114
+ }
package/package.json ADDED
@@ -0,0 +1,86 @@
1
+ {
2
+ "name": "@ahoo-wang/wow-react",
3
+ "version": "9.2.0-rc.0",
4
+ "description": "React hooks for Wow (https://github.com/Ahoo-Wang/Wow) queries: single, list, paged, count and list-stream. Requires React 19.3 or later.",
5
+ "keywords": [
6
+ "wow",
7
+ "wow-react",
8
+ "react",
9
+ "hooks",
10
+ "cqrs",
11
+ "event-sourcing",
12
+ "query",
13
+ "typescript"
14
+ ],
15
+ "author": "Ahoo-Wang",
16
+ "license": "Apache-2.0",
17
+ "homepage": "https://wow.ahoo.me/reference/typescript/wow-react/",
18
+ "repository": {
19
+ "type": "git",
20
+ "url": "git+https://github.com/Ahoo-Wang/Wow.git",
21
+ "directory": "typescript/wow-react"
22
+ },
23
+ "bugs": {
24
+ "url": "https://github.com/Ahoo-Wang/Wow/issues"
25
+ },
26
+ "type": "module",
27
+ "engines": {
28
+ "node": ">=22.12.0"
29
+ },
30
+ "module": "./dist/index.es.js",
31
+ "types": "./dist/index.d.ts",
32
+ "exports": {
33
+ ".": {
34
+ "types": "./dist/index.d.ts",
35
+ "import": "./dist/index.es.js",
36
+ "default": "./dist/index.es.js"
37
+ },
38
+ "./package.json": "./package.json"
39
+ },
40
+ "files": [
41
+ "dist",
42
+ "README.md",
43
+ "README.zh-CN.md"
44
+ ],
45
+ "sideEffects": false,
46
+ "dependencies": {
47
+ "dequal": "^2.0.3"
48
+ },
49
+ "peerDependencies": {
50
+ "@ahoo-wang/fetcher": "^5.1.5",
51
+ "react": "^19.3.0",
52
+ "@ahoo-wang/wow-client": "~9.2.0-rc.0"
53
+ },
54
+ "devDependencies": {
55
+ "@ahoo-wang/fetcher": "^5.1.5",
56
+ "@eslint/js": "^10.0.1",
57
+ "@rolldown/plugin-babel": "^0.2.4",
58
+ "@testing-library/react": "^16.3.3",
59
+ "@types/react": "^19.3.0",
60
+ "@types/react-dom": "^19.3.0",
61
+ "@vitejs/plugin-react": "6.1.1",
62
+ "@vitest/coverage-v8": "4.1.11",
63
+ "babel-plugin-react-compiler": "1.0.0",
64
+ "eslint": "^10.11.0",
65
+ "eslint-plugin-react-compiler": "19.1.0-rc.2",
66
+ "eslint-plugin-react-hooks": "^7.1.1",
67
+ "globals": "^17.12.0",
68
+ "jsdom": "^29.1.1",
69
+ "react": "^19.3.0",
70
+ "react-dom": "^19.3.0",
71
+ "typescript": "~6.0.3",
72
+ "typescript-eslint": "^8.70.1",
73
+ "unplugin-dts": "1.1.1",
74
+ "vite": "8.3.1",
75
+ "vitest": "^4.1.11",
76
+ "@ahoo-wang/wow-client": "~9.2.0-rc.0"
77
+ },
78
+ "scripts": {
79
+ "build": "vite build && pnpm test:package",
80
+ "test:package": "node scripts/verify-package.mjs",
81
+ "test": "vitest run --coverage && pnpm test:type",
82
+ "test:type": "tsc --noEmit -p test/tsconfig.types.json",
83
+ "lint": "eslint . --fix",
84
+ "clean": "rm -rf dist"
85
+ }
86
+ }