@confect/react 10.0.0-next.20 → 10.0.0-next.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +13 -0
- package/dist/PaginatedQueryResult.js.map +1 -1
- package/dist/QueryResult.d.ts.map +1 -1
- package/dist/QueryResult.js.map +1 -1
- package/dist/index.js +6 -5
- package/dist/index.js.map +1 -1
- package/package.json +9 -9
- package/src/PaginatedQueryResult.ts +1 -1
- package/src/QueryResult.ts +0 -1
- package/src/index.ts +7 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# @confect/react
|
|
2
2
|
|
|
3
|
+
## 10.0.0-next.21
|
|
4
|
+
|
|
5
|
+
### Major Changes
|
|
6
|
+
|
|
7
|
+
- a6425c5: Raise the minimum supported Node.js version to 24.
|
|
8
|
+
|
|
9
|
+
### Breaking Changes
|
|
10
|
+
- `engines.node` is now `>=24` on every `@confect/*` package, raised from `>=22`.
|
|
11
|
+
|
|
12
|
+
Node 22 has entered maintenance, so Confect now targets Node 24, the active LTS line. To migrate, move the Node version your project builds and runs on to 24 or later — on Node 22, installing `@confect/*` now fails your package manager's engine check. No API changes accompany the raise: code already running on Node 24 needs no edits.
|
|
13
|
+
|
|
3
14
|
## 10.0.0-next.20
|
|
4
15
|
|
|
5
16
|
## 10.0.0-next.19
|
|
@@ -335,6 +346,8 @@
|
|
|
335
346
|
- Updated dependencies [70e313e]
|
|
336
347
|
- @confect/core@10.0.0-next.0
|
|
337
348
|
|
|
349
|
+
## 9.4.2
|
|
350
|
+
|
|
338
351
|
## 9.4.1
|
|
339
352
|
|
|
340
353
|
### Patch Changes
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PaginatedQueryResult.js","names":[],"sources":["../src/PaginatedQueryResult.ts"],"sourcesContent":["import * as Equal from \"effect/Equal\";\nimport * as Function from \"effect/Function\";\nimport * as Hash from \"effect/Hash\";\nimport * as Match from \"effect/Match\";\nimport * as Pipeable from \"effect/Pipeable\";\nimport * as Predicate from \"effect/Predicate\";\n\nconst TypeId = \"~@confect/react/PaginatedQueryResult\";\ntype TypeId = typeof TypeId;\n\n/**\n * A `PaginatedQueryResult` represents the result of a Confect paginated query.\n * The non-`Failure` variants mirror the statuses of `usePaginatedQuery` from\n * `convex/react` and all carry `results` and `isLoading`, so the common UI\n * shape — render the list, show a spinner while loading — needs only an\n * {@link isFailure} early-out and plain field access.\n *\n * Every variant carries `results`, including `Failure`: when a later page\n * fails, the pages already loaded are still worth rendering alongside the\n * error, so they are not discarded. `Failure` additionally carries the\n * query's decoded typed error.\n *\n * `loadMore` appears only on `CanLoadMore`, the one state it can make\n * progress from. The underlying Convex hook exposes it on every status, but\n * calling it while a page is in flight, once the list is exhausted, or after\n * a failure is an intentional no-op there; narrowing to `CanLoadMore` — via\n * {@link isCanLoadMore} or {@link match} — makes that statically apparent\n * instead of silently dropping the call.\n *\n * When the query declares no `error` schema (`E` is `never`), the `Failure`\n * variant is excluded from the type entirely, so `isLoading` is accessible\n * without any narrowing.\n *\n * @typeParam Item - The type of a decoded page item.\n * @typeParam E - The type of the decoded typed error in the `Failure` variant.\n */\nexport type PaginatedQueryResult<Item, E = never> = [E] extends [never]\n ?\n | LoadingFirstPage<Item, E>\n | LoadingMore<Item, E>\n | CanLoadMore<Item, E>\n | Exhausted<Item, E>\n :\n | LoadingFirstPage<Item, E>\n | LoadingMore<Item, E>\n | CanLoadMore<Item, E>\n | Exhausted<Item, E>\n | Failure<Item, E>;\n\n/**\n * Every variant regardless of `E` — the parameter type for guards and\n * {@link match}, since `PaginatedQueryResult` itself excludes `Failure` when\n * `E` is `never`.\n */\nexport type Variants<Item, E = never> =\n | LoadingFirstPage<Item, E>\n | LoadingMore<Item, E>\n | CanLoadMore<Item, E>\n | Exhausted<Item, E>\n | Failure<Item, E>;\n\nexport declare namespace PaginatedQueryResult {\n // eslint-disable-next-line @typescript-eslint/no-shadow, import/namespace -- oxlint's namespace resolution misses type-only exports, and `Pipeable` is an interface\n export interface Proto<out Item, out E> extends Pipeable.Pipeable {\n readonly [TypeId]: TypeId;\n readonly \"~Item\": Item;\n readonly \"~E\": E;\n }\n\n export type Item<R> = R extends { readonly \"~Item\": infer Item_ }\n ? Item_\n : never;\n\n // eslint-disable-next-line @typescript-eslint/no-shadow\n export type Failure<R> = R extends { readonly \"~E\": infer E } ? E : never;\n}\n\nexport interface LoadingFirstPage<\n Item,\n E = never,\n> extends PaginatedQueryResult.Proto<Item, E> {\n readonly _tag: \"LoadingFirstPage\";\n readonly skipped: boolean;\n readonly results: ReadonlyArray<Item>;\n readonly isLoading: true;\n}\n\nexport interface LoadingMore<\n Item,\n E = never,\n> extends PaginatedQueryResult.Proto<Item, E> {\n readonly _tag: \"LoadingMore\";\n readonly results: ReadonlyArray<Item>;\n readonly isLoading: true;\n}\n\nexport interface CanLoadMore<\n Item,\n E = never,\n> extends PaginatedQueryResult.Proto<Item, E> {\n readonly _tag: \"CanLoadMore\";\n readonly results: ReadonlyArray<Item>;\n readonly isLoading: false;\n readonly loadMore: (numItems: number) => void;\n}\n\nexport interface Exhausted<Item, E = never> extends PaginatedQueryResult.Proto<\n Item,\n E\n> {\n readonly _tag: \"Exhausted\";\n readonly results: ReadonlyArray<Item>;\n readonly isLoading: false;\n}\n\nexport interface Failure<Item, E = never> extends PaginatedQueryResult.Proto<\n Item,\n E\n> {\n readonly _tag: \"Failure\";\n readonly error: E;\n /** The pages loaded before the failure. */\n readonly results: ReadonlyArray<Item>;\n}\n\nexport const isPaginatedQueryResult = (\n u: unknown,\n): u is Variants<unknown, unknown> => Predicate.hasProperty(u, TypeId);\n\nconst PaginatedQueryResultProto = {\n [TypeId]: TypeId,\n pipe(this: Variants<any, any>, ...args: ReadonlyArray<unknown>) {\n return Pipeable.pipeArguments(\n this,\n args as unknown as Parameters<typeof Pipeable.pipeArguments>[1],\n );\n },\n /**\n * `CanLoadMore`'s `loadMore` is excluded from equality and hashing, like\n * function fields generally: two results that render identically are equal\n * even though their callbacks differ by identity.\n */\n [Equal.symbol](this: Variants<any, any>, that: Variants<any, any>): boolean {\n if (this._tag !== that._tag) {\n return false;\n }\n return Match.value(this).pipe(\n Match.tag(\n \"LoadingFirstPage\",\n (self) => self.skipped === (that as LoadingFirstPage<any, any>).skipped,\n ),\n Match.tag(\"LoadingMore\", \"CanLoadMore\", \"Exhausted\", (self) =>\n Equal.equals(self.results, that.results),\n ),\n Match.tag(\n \"Failure\",\n (self) =>\n Equal.equals(self.error, (that as Failure<any, any>).error) &&\n Equal.equals(self.results, (that as Failure<any, any>).results),\n ),\n Match.exhaustive,\n );\n },\n [Hash.symbol](this: Variants<any, any>): number {\n const tagHash = Hash.string(this._tag);\n return Match.value(this).pipe(\n Match.tag(\"LoadingFirstPage\", (self) =>\n Hash.combine(tagHash)(Hash.hash(self.skipped)),\n ),\n Match.tag(\"LoadingMore\", \"CanLoadMore\", \"Exhausted\", (self) =>\n Hash.combine(tagHash)(Hash.hash(self.results)),\n ),\n Match.tag(\"Failure\", (self) =>\n Hash.combine(tagHash)(\n Hash.combine(Hash.hash(self.error))(Hash.hash(self.results)),\n ),\n ),\n Match.exhaustive,\n );\n },\n};\n\nconst noResults: ReadonlyArray<never> = [];\n\nexport const loadingFirstPage = <Item = never, E = never>(options: {\n skipped: boolean;\n}): LoadingFirstPage<Item, E> =>\n Object.assign(Object.create(PaginatedQueryResultProto), {\n _tag: \"LoadingFirstPage\" as const,\n skipped: options.skipped,\n results: noResults,\n isLoading: true as const,\n });\n\nexport const loadingMore = <Item, E = never>(options: {\n results: ReadonlyArray<Item>;\n}): LoadingMore<Item, E> =>\n Object.assign(Object.create(PaginatedQueryResultProto), {\n _tag: \"LoadingMore\" as const,\n results: options.results,\n isLoading: true as const,\n });\n\nexport const canLoadMore = <Item, E = never>(options: {\n results: ReadonlyArray<Item>;\n loadMore: (numItems: number) => void;\n}): CanLoadMore<Item, E> =>\n Object.assign(Object.create(PaginatedQueryResultProto), {\n _tag: \"CanLoadMore\" as const,\n results: options.results,\n isLoading: false as const,\n loadMore: options.loadMore,\n });\n\nexport const exhausted = <Item, E = never>(options: {\n results: ReadonlyArray<Item>;\n}): Exhausted<Item, E> =>\n Object.assign(Object.create(PaginatedQueryResultProto), {\n _tag: \"Exhausted\" as const,\n results: options.results,\n isLoading: false as const,\n });\n\nexport const failure = <E, Item = never>(options: {\n error: E;\n results: ReadonlyArray<Item>;\n}): Failure<Item, E> =>\n Object.assign(Object.create(PaginatedQueryResultProto), {\n _tag: \"Failure\" as const,\n error: options.error,\n results: options.results,\n });\n\nexport const isLoadingFirstPage = <Item, E>(\n result: Variants<Item, E>,\n): result is LoadingFirstPage<Item, E> => result._tag === \"LoadingFirstPage\";\n\nexport const isLoadingMore = <Item, E>(\n result: Variants<Item, E>,\n): result is LoadingMore<Item, E> => result._tag === \"LoadingMore\";\n\nexport const isCanLoadMore = <Item, E>(\n result: Variants<Item, E>,\n): result is CanLoadMore<Item, E> => result._tag === \"CanLoadMore\";\n\nexport const isExhausted = <Item, E>(\n result: Variants<Item, E>,\n): result is Exhausted<Item, E> => result._tag === \"Exhausted\";\n\nexport const isFailure = <Item, E>(\n result: Variants<Item, E>,\n): result is Failure<Item, E> => result._tag === \"Failure\";\n\nexport const isLoading = <Item, E>(\n result: Variants<Item, E>,\n): result is LoadingFirstPage<Item, E> | LoadingMore<Item, E> =>\n result._tag === \"LoadingFirstPage\" || result._tag === \"LoadingMore\";\n\ntype MatchOptions<Item, E, V, W, X, Y, Z> = {\n readonly onLoadingFirstPage: (skipped: boolean) => V;\n readonly onLoadingMore: (results: ReadonlyArray<Item>) => W;\n readonly onCanLoadMore: (\n results: ReadonlyArray<Item>,\n loadMore: (numItems: number) => void,\n ) => X;\n readonly onExhausted: (results: ReadonlyArray<Item>) => Y;\n} & ([E] extends [never]\n ? {}\n : {\n readonly onFailure: (error: E, results: ReadonlyArray<Item>) => Z;\n });\n\ntype MatchReturns<E, V, W, X, Y, Z> = [E] extends [never]\n ? V | W | X | Y\n : V | W | X | Y | Z;\n\n/**\n * Matches a {@link PaginatedQueryResult} to the appropriate handler based on\n * its tag. If the provided result cannot fail (i.e. `E` is `never`),\n * `onFailure` is not required.\n */\nexport const match: {\n <Item, E, V, W, X, Y, Z = never>(\n options: MatchOptions<Item, E, V, W, X, Y, Z>,\n ): (self: Variants<Item, E>) => MatchReturns<E, V, W, X, Y, Z>;\n <Item, E, V, W, X, Y, Z = never>(\n self: Variants<Item, E>,\n options: MatchOptions<Item, E, V, W, X, Y, Z>,\n ): MatchReturns<E, V, W, X, Y, Z>;\n} = Function.dual(\n 2,\n <Item, E, V, W, X, Y, Z = never>(\n self: Variants<Item, E>,\n options: MatchOptions<Item, E, V, W, X, Y, Z>,\n ): MatchReturns<E, V, W, X, Y, Z> =>\n Match.value(self).pipe(\n Match.tag(\"LoadingFirstPage\", (loadingFirstPage_) =>\n options.onLoadingFirstPage(loadingFirstPage_.skipped),\n ),\n Match.tag(\"LoadingMore\", (loadingMore_) =>\n options.onLoadingMore(loadingMore_.results),\n ),\n Match.tag(\"CanLoadMore\", (canLoadMore_) =>\n options.onCanLoadMore(canLoadMore_.results, canLoadMore_.loadMore),\n ),\n Match.tag(\"Exhausted\", (exhausted_) =>\n options.onExhausted(exhausted_.results),\n ),\n Match.tag(\"Failure\", (failure_) => {\n if (Predicate.hasProperty(options, \"onFailure\")) {\n return options.onFailure(failure_.error, failure_.results);\n }\n throw new Error(\n \"`onFailure` is required when error schema is provided\",\n );\n }),\n Match.exhaustive,\n ) as MatchReturns<E, V, W, X, Y, Z>,\n);\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"PaginatedQueryResult.js","names":[],"sources":["../src/PaginatedQueryResult.ts"],"sourcesContent":["import * as Equal from \"effect/Equal\";\nimport * as Function from \"effect/Function\";\nimport * as Hash from \"effect/Hash\";\nimport * as Match from \"effect/Match\";\nimport * as Pipeable from \"effect/Pipeable\";\nimport * as Predicate from \"effect/Predicate\";\n\nconst TypeId = \"~@confect/react/PaginatedQueryResult\";\ntype TypeId = typeof TypeId;\n\n/**\n * A `PaginatedQueryResult` represents the result of a Confect paginated query.\n * The non-`Failure` variants mirror the statuses of `usePaginatedQuery` from\n * `convex/react` and all carry `results` and `isLoading`, so the common UI\n * shape — render the list, show a spinner while loading — needs only an\n * {@link isFailure} early-out and plain field access.\n *\n * Every variant carries `results`, including `Failure`: when a later page\n * fails, the pages already loaded are still worth rendering alongside the\n * error, so they are not discarded. `Failure` additionally carries the\n * query's decoded typed error.\n *\n * `loadMore` appears only on `CanLoadMore`, the one state it can make\n * progress from. The underlying Convex hook exposes it on every status, but\n * calling it while a page is in flight, once the list is exhausted, or after\n * a failure is an intentional no-op there; narrowing to `CanLoadMore` — via\n * {@link isCanLoadMore} or {@link match} — makes that statically apparent\n * instead of silently dropping the call.\n *\n * When the query declares no `error` schema (`E` is `never`), the `Failure`\n * variant is excluded from the type entirely, so `isLoading` is accessible\n * without any narrowing.\n *\n * @typeParam Item - The type of a decoded page item.\n * @typeParam E - The type of the decoded typed error in the `Failure` variant.\n */\nexport type PaginatedQueryResult<Item, E = never> = [E] extends [never]\n ?\n | LoadingFirstPage<Item, E>\n | LoadingMore<Item, E>\n | CanLoadMore<Item, E>\n | Exhausted<Item, E>\n :\n | LoadingFirstPage<Item, E>\n | LoadingMore<Item, E>\n | CanLoadMore<Item, E>\n | Exhausted<Item, E>\n | Failure<Item, E>;\n\n/**\n * Every variant regardless of `E` — the parameter type for guards and\n * {@link match}, since `PaginatedQueryResult` itself excludes `Failure` when\n * `E` is `never`.\n */\nexport type Variants<Item, E = never> =\n | LoadingFirstPage<Item, E>\n | LoadingMore<Item, E>\n | CanLoadMore<Item, E>\n | Exhausted<Item, E>\n | Failure<Item, E>;\n\nexport declare namespace PaginatedQueryResult {\n // eslint-disable-next-line @typescript-eslint/no-shadow\n export interface Proto<out Item, out E> extends Pipeable.Pipeable {\n readonly [TypeId]: TypeId;\n readonly \"~Item\": Item;\n readonly \"~E\": E;\n }\n\n export type Item<R> = R extends { readonly \"~Item\": infer Item_ }\n ? Item_\n : never;\n\n // eslint-disable-next-line @typescript-eslint/no-shadow\n export type Failure<R> = R extends { readonly \"~E\": infer E } ? E : never;\n}\n\nexport interface LoadingFirstPage<\n Item,\n E = never,\n> extends PaginatedQueryResult.Proto<Item, E> {\n readonly _tag: \"LoadingFirstPage\";\n readonly skipped: boolean;\n readonly results: ReadonlyArray<Item>;\n readonly isLoading: true;\n}\n\nexport interface LoadingMore<\n Item,\n E = never,\n> extends PaginatedQueryResult.Proto<Item, E> {\n readonly _tag: \"LoadingMore\";\n readonly results: ReadonlyArray<Item>;\n readonly isLoading: true;\n}\n\nexport interface CanLoadMore<\n Item,\n E = never,\n> extends PaginatedQueryResult.Proto<Item, E> {\n readonly _tag: \"CanLoadMore\";\n readonly results: ReadonlyArray<Item>;\n readonly isLoading: false;\n readonly loadMore: (numItems: number) => void;\n}\n\nexport interface Exhausted<Item, E = never> extends PaginatedQueryResult.Proto<\n Item,\n E\n> {\n readonly _tag: \"Exhausted\";\n readonly results: ReadonlyArray<Item>;\n readonly isLoading: false;\n}\n\nexport interface Failure<Item, E = never> extends PaginatedQueryResult.Proto<\n Item,\n E\n> {\n readonly _tag: \"Failure\";\n readonly error: E;\n /** The pages loaded before the failure. */\n readonly results: ReadonlyArray<Item>;\n}\n\nexport const isPaginatedQueryResult = (\n u: unknown,\n): u is Variants<unknown, unknown> => Predicate.hasProperty(u, TypeId);\n\nconst PaginatedQueryResultProto = {\n [TypeId]: TypeId,\n pipe(this: Variants<any, any>, ...args: ReadonlyArray<unknown>) {\n return Pipeable.pipeArguments(\n this,\n args as unknown as Parameters<typeof Pipeable.pipeArguments>[1],\n );\n },\n /**\n * `CanLoadMore`'s `loadMore` is excluded from equality and hashing, like\n * function fields generally: two results that render identically are equal\n * even though their callbacks differ by identity.\n */\n [Equal.symbol](this: Variants<any, any>, that: Variants<any, any>): boolean {\n if (this._tag !== that._tag) {\n return false;\n }\n return Match.value(this).pipe(\n Match.tag(\n \"LoadingFirstPage\",\n (self) => self.skipped === (that as LoadingFirstPage<any, any>).skipped,\n ),\n Match.tag(\"LoadingMore\", \"CanLoadMore\", \"Exhausted\", (self) =>\n Equal.equals(self.results, that.results),\n ),\n Match.tag(\n \"Failure\",\n (self) =>\n Equal.equals(self.error, (that as Failure<any, any>).error) &&\n Equal.equals(self.results, (that as Failure<any, any>).results),\n ),\n Match.exhaustive,\n );\n },\n [Hash.symbol](this: Variants<any, any>): number {\n const tagHash = Hash.string(this._tag);\n return Match.value(this).pipe(\n Match.tag(\"LoadingFirstPage\", (self) =>\n Hash.combine(tagHash)(Hash.hash(self.skipped)),\n ),\n Match.tag(\"LoadingMore\", \"CanLoadMore\", \"Exhausted\", (self) =>\n Hash.combine(tagHash)(Hash.hash(self.results)),\n ),\n Match.tag(\"Failure\", (self) =>\n Hash.combine(tagHash)(\n Hash.combine(Hash.hash(self.error))(Hash.hash(self.results)),\n ),\n ),\n Match.exhaustive,\n );\n },\n};\n\nconst noResults: ReadonlyArray<never> = [];\n\nexport const loadingFirstPage = <Item = never, E = never>(options: {\n skipped: boolean;\n}): LoadingFirstPage<Item, E> =>\n Object.assign(Object.create(PaginatedQueryResultProto), {\n _tag: \"LoadingFirstPage\" as const,\n skipped: options.skipped,\n results: noResults,\n isLoading: true as const,\n });\n\nexport const loadingMore = <Item, E = never>(options: {\n results: ReadonlyArray<Item>;\n}): LoadingMore<Item, E> =>\n Object.assign(Object.create(PaginatedQueryResultProto), {\n _tag: \"LoadingMore\" as const,\n results: options.results,\n isLoading: true as const,\n });\n\nexport const canLoadMore = <Item, E = never>(options: {\n results: ReadonlyArray<Item>;\n loadMore: (numItems: number) => void;\n}): CanLoadMore<Item, E> =>\n Object.assign(Object.create(PaginatedQueryResultProto), {\n _tag: \"CanLoadMore\" as const,\n results: options.results,\n isLoading: false as const,\n loadMore: options.loadMore,\n });\n\nexport const exhausted = <Item, E = never>(options: {\n results: ReadonlyArray<Item>;\n}): Exhausted<Item, E> =>\n Object.assign(Object.create(PaginatedQueryResultProto), {\n _tag: \"Exhausted\" as const,\n results: options.results,\n isLoading: false as const,\n });\n\nexport const failure = <E, Item = never>(options: {\n error: E;\n results: ReadonlyArray<Item>;\n}): Failure<Item, E> =>\n Object.assign(Object.create(PaginatedQueryResultProto), {\n _tag: \"Failure\" as const,\n error: options.error,\n results: options.results,\n });\n\nexport const isLoadingFirstPage = <Item, E>(\n result: Variants<Item, E>,\n): result is LoadingFirstPage<Item, E> => result._tag === \"LoadingFirstPage\";\n\nexport const isLoadingMore = <Item, E>(\n result: Variants<Item, E>,\n): result is LoadingMore<Item, E> => result._tag === \"LoadingMore\";\n\nexport const isCanLoadMore = <Item, E>(\n result: Variants<Item, E>,\n): result is CanLoadMore<Item, E> => result._tag === \"CanLoadMore\";\n\nexport const isExhausted = <Item, E>(\n result: Variants<Item, E>,\n): result is Exhausted<Item, E> => result._tag === \"Exhausted\";\n\nexport const isFailure = <Item, E>(\n result: Variants<Item, E>,\n): result is Failure<Item, E> => result._tag === \"Failure\";\n\nexport const isLoading = <Item, E>(\n result: Variants<Item, E>,\n): result is LoadingFirstPage<Item, E> | LoadingMore<Item, E> =>\n result._tag === \"LoadingFirstPage\" || result._tag === \"LoadingMore\";\n\ntype MatchOptions<Item, E, V, W, X, Y, Z> = {\n readonly onLoadingFirstPage: (skipped: boolean) => V;\n readonly onLoadingMore: (results: ReadonlyArray<Item>) => W;\n readonly onCanLoadMore: (\n results: ReadonlyArray<Item>,\n loadMore: (numItems: number) => void,\n ) => X;\n readonly onExhausted: (results: ReadonlyArray<Item>) => Y;\n} & ([E] extends [never]\n ? {}\n : {\n readonly onFailure: (error: E, results: ReadonlyArray<Item>) => Z;\n });\n\ntype MatchReturns<E, V, W, X, Y, Z> = [E] extends [never]\n ? V | W | X | Y\n : V | W | X | Y | Z;\n\n/**\n * Matches a {@link PaginatedQueryResult} to the appropriate handler based on\n * its tag. If the provided result cannot fail (i.e. `E` is `never`),\n * `onFailure` is not required.\n */\nexport const match: {\n <Item, E, V, W, X, Y, Z = never>(\n options: MatchOptions<Item, E, V, W, X, Y, Z>,\n ): (self: Variants<Item, E>) => MatchReturns<E, V, W, X, Y, Z>;\n <Item, E, V, W, X, Y, Z = never>(\n self: Variants<Item, E>,\n options: MatchOptions<Item, E, V, W, X, Y, Z>,\n ): MatchReturns<E, V, W, X, Y, Z>;\n} = Function.dual(\n 2,\n <Item, E, V, W, X, Y, Z = never>(\n self: Variants<Item, E>,\n options: MatchOptions<Item, E, V, W, X, Y, Z>,\n ): MatchReturns<E, V, W, X, Y, Z> =>\n Match.value(self).pipe(\n Match.tag(\"LoadingFirstPage\", (loadingFirstPage_) =>\n options.onLoadingFirstPage(loadingFirstPage_.skipped),\n ),\n Match.tag(\"LoadingMore\", (loadingMore_) =>\n options.onLoadingMore(loadingMore_.results),\n ),\n Match.tag(\"CanLoadMore\", (canLoadMore_) =>\n options.onCanLoadMore(canLoadMore_.results, canLoadMore_.loadMore),\n ),\n Match.tag(\"Exhausted\", (exhausted_) =>\n options.onExhausted(exhausted_.results),\n ),\n Match.tag(\"Failure\", (failure_) => {\n if (Predicate.hasProperty(options, \"onFailure\")) {\n return options.onFailure(failure_.error, failure_.results);\n }\n throw new Error(\n \"`onFailure` is required when error schema is provided\",\n );\n }),\n Match.exhaustive,\n ) as MatchReturns<E, V, W, X, Y, Z>,\n);\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"QueryResult.d.ts","sourceRoot":"","sources":["../src/QueryResult.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,QAAQ,MAAM,iBAAiB,CAAC;AAG5C,QAAA,MAAM,MAAM,gCAAgC,CAAC;AAC7C,KAAK,MAAM,GAAG,OAAO,MAAM,CAAC;AAE5B;;;;;GAKG;AACH,MAAM,MAAM,WAAW,CAAC,CAAC,EAAE,CAAC,GAAG,KAAK,IAChC,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,GACb,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,GACb,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AAElB,MAAM,CAAC,OAAO,WAAW,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"QueryResult.d.ts","sourceRoot":"","sources":["../src/QueryResult.ts"],"names":[],"mappings":"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"}
|
package/dist/QueryResult.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"QueryResult.js","names":[],"sources":["../src/QueryResult.ts"],"sourcesContent":["import * as Equal from \"effect/Equal\";\nimport * as Function from \"effect/Function\";\nimport * as Hash from \"effect/Hash\";\nimport * as Match from \"effect/Match\";\nimport * as Pipeable from \"effect/Pipeable\";\nimport * as Predicate from \"effect/Predicate\";\n\nconst TypeId = \"~@confect/react/QueryResult\";\ntype TypeId = typeof TypeId;\n\n/**\n * A `QueryResult` represents the result of a Confect query.\n *\n * @typeParam A - The type of the decoded `returns` value in the `Success` variant.\n * @typeParam E - The type of the decoded typed error in the `Failure` variant.\n */\nexport type QueryResult<A, E = never> =\n | Loading<A, E>\n | Success<A, E>\n | Failure<A, E>;\n\nexport declare namespace QueryResult {\n
|
|
1
|
+
{"version":3,"file":"QueryResult.js","names":[],"sources":["../src/QueryResult.ts"],"sourcesContent":["import * as Equal from \"effect/Equal\";\nimport * as Function from \"effect/Function\";\nimport * as Hash from \"effect/Hash\";\nimport * as Match from \"effect/Match\";\nimport * as Pipeable from \"effect/Pipeable\";\nimport * as Predicate from \"effect/Predicate\";\n\nconst TypeId = \"~@confect/react/QueryResult\";\ntype TypeId = typeof TypeId;\n\n/**\n * A `QueryResult` represents the result of a Confect query.\n *\n * @typeParam A - The type of the decoded `returns` value in the `Success` variant.\n * @typeParam E - The type of the decoded typed error in the `Failure` variant.\n */\nexport type QueryResult<A, E = never> =\n | Loading<A, E>\n | Success<A, E>\n | Failure<A, E>;\n\nexport declare namespace QueryResult {\n export interface Proto<out A, out E> extends Pipeable.Pipeable {\n readonly [TypeId]: TypeId;\n readonly \"~A\": A;\n readonly \"~E\": E;\n }\n\n // eslint-disable-next-line @typescript-eslint/no-shadow\n export type Success<R> = R extends { readonly \"~A\": infer A } ? A : never;\n\n // eslint-disable-next-line @typescript-eslint/no-shadow\n export type Failure<R> = R extends { readonly \"~E\": infer E } ? E : never;\n}\n\nexport interface Loading<A, E = never> extends QueryResult.Proto<A, E> {\n readonly _tag: \"Loading\";\n readonly skipped: boolean;\n}\n\nexport interface Success<A, E = never> extends QueryResult.Proto<A, E> {\n readonly _tag: \"Success\";\n readonly value: A;\n}\n\nexport interface Failure<A, E = never> extends QueryResult.Proto<A, E> {\n readonly _tag: \"Failure\";\n readonly error: E;\n}\n\nexport const isQueryResult = (u: unknown): u is QueryResult<unknown, unknown> =>\n Predicate.hasProperty(u, TypeId);\n\nconst QueryResultProto = {\n [TypeId]: TypeId,\n pipe(this: QueryResult<any, any>, ...args: ReadonlyArray<unknown>) {\n return Pipeable.pipeArguments(\n this,\n args as unknown as Parameters<typeof Pipeable.pipeArguments>[1],\n );\n },\n [Equal.symbol](\n this: QueryResult<any, any>,\n that: QueryResult<any, any>,\n ): boolean {\n if (this._tag !== that._tag) {\n return false;\n }\n return Match.value(this).pipe(\n Match.tag(\n \"Loading\",\n (self) => self.skipped === (that as Loading<any, any>).skipped,\n ),\n Match.tag(\"Success\", (self) =>\n Equal.equals(self.value, (that as Success<any, any>).value),\n ),\n Match.tag(\"Failure\", (self) =>\n Equal.equals(self.error, (that as Failure<any, any>).error),\n ),\n Match.exhaustive,\n );\n },\n [Hash.symbol](this: QueryResult<any, any>): number {\n const tagHash = Hash.string(this._tag);\n return Match.value(this).pipe(\n Match.tag(\"Loading\", (self) =>\n Hash.combine(tagHash)(Hash.hash(self.skipped)),\n ),\n Match.tag(\"Success\", (self) =>\n Hash.combine(tagHash)(Hash.hash(self.value)),\n ),\n Match.tag(\"Failure\", (self) =>\n Hash.combine(tagHash)(Hash.hash(self.error)),\n ),\n Match.exhaustive,\n );\n },\n};\n\nexport const load = <A = never, E = never>(skipped: boolean): Loading<A, E> =>\n Object.assign(Object.create(QueryResultProto), {\n _tag: \"Loading\" as const,\n skipped,\n });\n\nexport const succeed = <A, E = never>(value: A): Success<A, E> =>\n Object.assign(Object.create(QueryResultProto), {\n _tag: \"Success\" as const,\n value,\n });\n\nexport const fail = <E, A = never>(error: E): Failure<A, E> =>\n Object.assign(Object.create(QueryResultProto), {\n _tag: \"Failure\" as const,\n error,\n });\n\nexport const isLoading = <A, E>(\n queryResult: QueryResult<A, E>,\n): queryResult is Loading<A, E> => queryResult._tag === \"Loading\";\n\nexport const isSuccess = <A, E>(\n queryResult: QueryResult<A, E>,\n): queryResult is Success<A, E> => queryResult._tag === \"Success\";\n\nexport const isFailure = <A, E>(\n queryResult: QueryResult<A, E>,\n): queryResult is Failure<A, E> => queryResult._tag === \"Failure\";\n\ntype MatchOptions<A, E, X, Y, Z> = {\n readonly onLoading: (skipped: boolean) => X;\n readonly onSuccess: (value: A) => Y;\n} & ([E] extends [never] ? {} : { readonly onFailure: (error: E) => Z });\n\ntype MatchReturns<E, X, Y, Z> = [E] extends [never] ? X | Y : X | Y | Z;\n\n/**\n * Matches a {@link QueryResult} to the appropriate handler based on its tag. If\n * the provided `QueryResult` cannot fail (i.e. `E` is `never`), `onFailure` is\n * not required.\n *\n * @example\n * ```tsx\n * const result = QueryResult.match(queryResult, {\n * onLoading: (skipped) => skipped ? null : <p>Loading…</p>,\n * onSuccess: (value) => <p>{value.text}</p>,\n * onFailure: (error) => <p>Error: {error.message}</p>,\n * });\n */\nexport const match: {\n <A, E, X, Y, Z = never>(\n options: MatchOptions<A, E, X, Y, Z>,\n ): (self: QueryResult<A, E>) => MatchReturns<E, X, Y, Z>;\n <A, E, X, Y, Z = never>(\n self: QueryResult<A, E>,\n options: MatchOptions<A, E, X, Y, Z>,\n ): MatchReturns<E, X, Y, Z>;\n} = Function.dual(\n 2,\n <A, E, X, Y, Z = never>(\n self: QueryResult<A, E>,\n options: MatchOptions<A, E, X, Y, Z>,\n ): MatchReturns<E, X, Y, Z> =>\n Match.value(self).pipe(\n Match.tag(\"Loading\", (loading) => options.onLoading(loading.skipped)),\n Match.tag(\"Success\", (success) => options.onSuccess(success.value)),\n Match.tag(\"Failure\", (failure) => {\n if (Predicate.hasProperty(options, \"onFailure\")) {\n return options.onFailure(failure.error);\n }\n throw new Error(\n \"`onFailure` is required when error schema is provided\",\n );\n }),\n Match.exhaustive,\n ) as MatchReturns<E, X, Y, Z>,\n);\n"],"mappings":";;;;;;;;;;;;;;;;;;AAOA,MAAM,SAAS;AA2Cf,MAAa,iBAAiB,MAC5B,UAAU,YAAY,GAAG,MAAM;AAEjC,MAAM,mBAAmB;EACtB,SAAS;CACV,KAAkC,GAAG,MAA8B;EACjE,OAAO,SAAS,cACd,MACA,IACF;CACF;CACA,CAAC,MAAM,QAEL,MACS;EACT,IAAI,KAAK,SAAS,KAAK,MACrB,OAAO;EAET,OAAO,MAAM,MAAM,IAAI,CAAC,CAAC,KACvB,MAAM,IACJ,YACC,SAAS,KAAK,YAAa,KAA2B,OACzD,GACA,MAAM,IAAI,YAAY,SACpB,MAAM,OAAO,KAAK,OAAQ,KAA2B,KAAK,CAC5D,GACA,MAAM,IAAI,YAAY,SACpB,MAAM,OAAO,KAAK,OAAQ,KAA2B,KAAK,CAC5D,GACA,MAAM,UACR;CACF;CACA,CAAC,KAAK,UAA6C;EACjD,MAAM,UAAU,KAAK,OAAO,KAAK,IAAI;EACrC,OAAO,MAAM,MAAM,IAAI,CAAC,CAAC,KACvB,MAAM,IAAI,YAAY,SACpB,KAAK,QAAQ,OAAO,CAAC,CAAC,KAAK,KAAK,KAAK,OAAO,CAAC,CAC/C,GACA,MAAM,IAAI,YAAY,SACpB,KAAK,QAAQ,OAAO,CAAC,CAAC,KAAK,KAAK,KAAK,KAAK,CAAC,CAC7C,GACA,MAAM,IAAI,YAAY,SACpB,KAAK,QAAQ,OAAO,CAAC,CAAC,KAAK,KAAK,KAAK,KAAK,CAAC,CAC7C,GACA,MAAM,UACR;CACF;AACF;AAEA,MAAa,QAA8B,YACzC,OAAO,OAAO,OAAO,OAAO,gBAAgB,GAAG;CAC7C,MAAM;CACN;AACF,CAAC;AAEH,MAAa,WAAyB,UACpC,OAAO,OAAO,OAAO,OAAO,gBAAgB,GAAG;CAC7C,MAAM;CACN;AACF,CAAC;AAEH,MAAa,QAAsB,UACjC,OAAO,OAAO,OAAO,OAAO,gBAAgB,GAAG;CAC7C,MAAM;CACN;AACF,CAAC;AAEH,MAAa,aACX,gBACiC,YAAY,SAAS;AAExD,MAAa,aACX,gBACiC,YAAY,SAAS;AAExD,MAAa,aACX,gBACiC,YAAY,SAAS;;;;;;;;;;;;;;AAsBxD,MAAa,QAQT,SAAS,KACX,IAEE,MACA,YAEA,MAAM,MAAM,IAAI,CAAC,CAAC,KAChB,MAAM,IAAI,YAAY,YAAY,QAAQ,UAAU,QAAQ,OAAO,CAAC,GACpE,MAAM,IAAI,YAAY,YAAY,QAAQ,UAAU,QAAQ,KAAK,CAAC,GAClE,MAAM,IAAI,YAAY,YAAY;CAChC,IAAI,UAAU,YAAY,SAAS,WAAW,GAC5C,OAAO,QAAQ,UAAU,QAAQ,KAAK;CAExC,MAAM,IAAI,MACR,uDACF;AACF,CAAC,GACD,MAAM,UACR,CACJ"}
|
package/dist/index.js
CHANGED
|
@@ -48,7 +48,7 @@ const MINIMUM_CONVEX_VERSION = "1.36.0";
|
|
|
48
48
|
* version is the only reliable signal.
|
|
49
49
|
*/
|
|
50
50
|
const supportsErrorsAsValues = (() => {
|
|
51
|
-
const [major, minor] =
|
|
51
|
+
const [major, minor] = version.split(".").map(Number);
|
|
52
52
|
if (major === void 0 || minor === void 0 || Number.isNaN(major) || Number.isNaN(minor)) return false;
|
|
53
53
|
const [minimumMajor, minimumMinor] = MINIMUM_CONVEX_VERSION.split(".").map(Number);
|
|
54
54
|
return major > minimumMajor || major === minimumMajor && minor >= minimumMinor;
|
|
@@ -149,10 +149,11 @@ const useAction = (ref) => {
|
|
|
149
149
|
const actualAction = useAction$1(Ref.getFunctionReference(ref));
|
|
150
150
|
return useCallback(((...args) => invokeAsResult(ref, (_, encodedArgs) => actualAction(encodedArgs), args).then((result) => Ref.hasErrorSchema(ref) ? result : Result.getOrThrow(result))), [ref, actualAction]);
|
|
151
151
|
};
|
|
152
|
-
const invokeAsResult =
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
152
|
+
const invokeAsResult = (ref, invoke, args) => {
|
|
153
|
+
return Effect.runPromiseExit(Ref.runWithCodec(ref, args[0] ?? {}, invoke).pipe(Effect.catchTag("SchemaError", Effect.die), Effect.result)).then((exit) => {
|
|
154
|
+
if (Exit.isSuccess(exit)) return exit.value;
|
|
155
|
+
throw Cause.squash(exit.cause);
|
|
156
|
+
});
|
|
156
157
|
};
|
|
157
158
|
//#endregion
|
|
158
159
|
export { OptimisticLocalStore_exports as OptimisticLocalStore, PaginatedQueryResult_exports as PaginatedQueryResult, QueryResult_exports as QueryResult, useAction, useMutation, usePaginatedQuery, useQuery };
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["useConvexQuery","QueryResult.load","QueryResult.succeed","QueryResult.fail","convexVersion","PaginatedQueryResult.failure","PaginatedQueryResult.loadingFirstPage","PaginatedQueryResult.loadingMore","PaginatedQueryResult.canLoadMore","PaginatedQueryResult.exhausted","OptimisticLocalStore.make","useConvexMutation","useConvexAction"],"sources":["../src/index.ts"],"sourcesContent":["import { Ref } from \"@confect/core\";\nimport { version as convexVersion } from \"convex\";\nimport type { OptimisticUpdate as ConvexOptimisticUpdate } from \"convex/browser\";\nimport * as ConvexReact from \"convex/react\";\nimport type { usePaginatedQuery as useConvexPaginatedQuery } from \"convex/react\";\nimport {\n useAction as useConvexAction,\n useMutation as useConvexMutation,\n useQuery as useConvexQuery,\n type ReactMutation as ConvexReactMutation,\n} from \"convex/react\";\nimport type { FunctionReference } from \"convex/server\";\nimport type { Value } from \"convex/values\";\nimport * as Cause from \"effect/Cause\";\nimport * as Effect from \"effect/Effect\";\nimport * as Result from \"effect/Result\";\nimport * as Exit from \"effect/Exit\";\nimport * as Match from \"effect/Match\";\nimport * as Option from \"effect/Option\";\nimport { useCallback, useMemo } from \"react\";\n\nimport * as OptimisticLocalStore from \"./OptimisticLocalStore\";\nimport * as PaginatedQueryResult from \"./PaginatedQueryResult\";\nimport * as QueryResult from \"./QueryResult\";\n\nexport { OptimisticLocalStore, PaginatedQueryResult, QueryResult };\n\nexport type InvokeReturn<Ref_ extends Ref.Any> = [Ref.Error<Ref_>] extends [\n never,\n]\n ? Promise<Ref.Returns<Ref_>>\n : Promise<Result.Result<Ref.Returns<Ref_>, Ref.Error<Ref_>>>;\n\ntype UseQueryArgs<Query extends Ref.AnyPublicQuery> =\n keyof Ref.Args<Query> extends never\n ? [args?: Ref.Args<Query> | \"skip\"]\n : [args: Ref.Args<Query> | \"skip\"];\n\nexport const useQuery = <Query extends Ref.AnyPublicQuery>(\n ref: Query,\n ...rest: UseQueryArgs<Query>\n): QueryResult.QueryResult<Ref.Returns<Query>, Ref.Error<Query>> => {\n const functionReference = Ref.getFunctionReference(ref);\n const args = rest[0];\n const skipped = args === \"skip\";\n const encodedArgs = skipped\n ? \"skip\"\n : Ref.encodeArgsSync(ref, (args ?? {}) as Ref.Args<Query>);\n\n // `useConvexQuery` returns a referentially stable value while the underlying\n // Convex result is unchanged, and throws a stable error when the query\n // fails. We capture either outcome as a `Result` and decode/wrap it inside\n // `useMemo` so that the returned `QueryResult` keeps a stable identity across\n // renders when nothing has actually changed. Decoding on every render would\n // hand consumers a fresh object each time, breaking effects and memoization\n // that depend on the result's identity.\n const encodedReturnsOrError: Result.Result<unknown, unknown> = Result.try(\n () => useConvexQuery(functionReference, encodedArgs),\n );\n\n return useMemo(\n () =>\n Result.match(encodedReturnsOrError, {\n onSuccess: (encodedReturnsOrUndefined) =>\n encodedReturnsOrUndefined === undefined\n ? QueryResult.load(skipped)\n : QueryResult.succeed(\n Ref.decodeReturnsSync(ref, encodedReturnsOrUndefined),\n ),\n onFailure: (error) => {\n if (Ref.isConvexError(error)) {\n const decoded = Ref.decodeErrorOption(ref, error.data);\n if (Option.isSome(decoded)) {\n return QueryResult.fail(decoded.value);\n }\n }\n throw error;\n },\n }),\n // `Result.try` allocates a fresh wrapper each render, so we key the memo on\n // the stable value it carries (the Convex result or thrown error) rather\n // than the wrapper itself; the decoded result is a function of that value,\n // `ref`, and `skipped`.\n [ref, skipped, Result.merge(encodedReturnsOrError)],\n );\n};\n\n/**\n * Like `Omit`, but implemented with key remapping so that optional modifiers\n * are preserved and index signatures don't reintroduce the omitted key's\n * literal type. Mirrors `BetterOmit` from `convex/server`.\n */\ntype OmitKey<T, K extends PropertyKey> = {\n [P in keyof T as P extends K ? never : P]: T[P];\n};\n\n/**\n * The args accepted by {@link usePaginatedQuery}: the ref's args without\n * `paginationOpts`, which the underlying Convex hook manages itself. When no\n * args remain, resolves to `Record<string, never>` (only the empty object is\n * accepted) rather than `{}`, which would accept any non-nullish value.\n */\nexport type PaginatedQueryArgs<Query extends Ref.AnyPublicPaginatedQuery> =\n OmitKey<Ref.Args<Query>, \"paginationOpts\"> extends infer Args_\n ? keyof Args_ extends never\n ? Record<string, never>\n : Args_\n : never;\n\n/**\n * The item type for a paginated query: the element type of the `page` field\n * of the ref's returns.\n */\nexport type PaginatedQueryItem<Query extends Ref.AnyPublicPaginatedQuery> =\n Ref.Returns<Query>[\"page\"][number];\n\n/**\n * The args parameter of {@link usePaginatedQuery}: the ref's args without\n * `paginationOpts`, or `\"skip\"` to skip the query.\n */\nexport type UsePaginatedQueryArgs<Query extends Ref.AnyPublicPaginatedQuery> =\n | PaginatedQueryArgs<Query>\n | \"skip\";\n\nexport type PaginatedQueryOptions = Parameters<\n typeof useConvexPaginatedQuery\n>[2];\n\n/**\n * The `user`-facing result of `usePaginatedQueryInternal` from `convex/react`,\n * including the `\"Error\"` status its non-throwing mode can return.\n */\ninterface ConvexPaginatedQueryInternalUser {\n readonly results: ReadonlyArray<unknown>;\n readonly status:\n | \"LoadingFirstPage\"\n | \"LoadingMore\"\n | \"CanLoadMore\"\n | \"Exhausted\"\n | \"Error\";\n readonly isLoading: boolean;\n readonly loadMore: (numItems: number) => void;\n readonly error?: unknown;\n}\n\ntype UseConvexPaginatedQueryInternal = (\n query: FunctionReference<\"query\">,\n args: Record<string, Value> | \"skip\",\n options: PaginatedQueryOptions,\n throwOnError: boolean,\n) => { user: ConvexPaginatedQueryInternalUser };\n\n// `usePaginatedQueryInternal` is runtime-exported by convex/react but absent\n// from its public type declarations. It is the only way to observe query\n// errors as values: the public positional `usePaginatedQuery` hard-codes\n// throwOnError and throws mid-hook-sequence, which cannot be caught without\n// breaking React's hook-order invariant.\nconst useConvexPaginatedQueryInternal = (\n ConvexReact as unknown as Record<string, unknown>\n).usePaginatedQueryInternal as UseConvexPaginatedQueryInternal | undefined;\n\nconst MINIMUM_CONVEX_VERSION = \"1.36.0\";\n\n/**\n * The non-throwing mode of `usePaginatedQueryInternal` — its fourth,\n * `throwOnError` parameter — arrived in convex 1.36.0. Convex 1.32 through\n * 1.35 export the same symbol taking only three parameters, where a fourth\n * argument is silently ignored and errors are always thrown.\n *\n * The function itself cannot be interrogated for this: `Function.length`\n * counts parameters up to the first one with a default, and 1.36.0 declares\n * `throwOnError = true`, so both shapes report an arity of 3. The package\n * version is the only reliable signal.\n */\nconst supportsErrorsAsValues = ((): boolean => {\n const [major, minor] = String(convexVersion).split(\".\").map(Number);\n if (\n major === undefined ||\n minor === undefined ||\n Number.isNaN(major) ||\n Number.isNaN(minor)\n ) {\n return false;\n }\n const [minimumMajor, minimumMinor] = MINIMUM_CONVEX_VERSION.split(\".\").map(\n Number,\n ) as [number, number];\n return (\n major > minimumMajor || (major === minimumMajor && minor >= minimumMinor)\n );\n})();\n\n/**\n * Load data reactively from a paginated query defined with\n * `FunctionSpec.publicPaginatedQuery`, mirroring the ergonomics of\n * `usePaginatedQuery` from `convex/react`.\n *\n * Args are encoded via the ref's user-args schema (`paginationOpts` is managed\n * by the Convex hook, not the caller), and each loaded page is decoded via the\n * ref's item schema.\n *\n * Returns a {@link PaginatedQueryResult.PaginatedQueryResult}: the loaded\n * variants carry `results` and `isLoading`, and `CanLoadMore` additionally\n * carries `loadMore`; if the `Ref` declares an `error` schema and the query\n * fails with that typed error, the decoded error is returned as the `Failure`\n * variant, which also carries the pages loaded before the failure. Unknown\n * errors are thrown, to be caught by an error boundary.\n */\nexport const usePaginatedQuery = <Query extends Ref.AnyPublicPaginatedQuery>(\n ref: Query,\n args: UsePaginatedQueryArgs<Query>,\n options: PaginatedQueryOptions,\n): PaginatedQueryResult.PaginatedQueryResult<\n PaginatedQueryItem<Query>,\n Ref.Error<Query>\n> => {\n if (\n useConvexPaginatedQueryInternal === undefined ||\n !supportsErrorsAsValues\n ) {\n throw new Error(\n `usePaginatedQuery requires convex >= ${MINIMUM_CONVEX_VERSION}, but found ` +\n `${convexVersion}. Earlier versions always throw paginated query errors ` +\n \"instead of returning them, so a declared `error` schema cannot be \" +\n \"surfaced as a `Failure` — upgrade the `convex` package.\",\n );\n }\n\n const functionReference = Ref.getFunctionReference(ref);\n const skipped = args === \"skip\";\n\n // The encoded output is the wire form Convex's hook forwards verbatim, not\n // the ref's decoded args type.\n const encodedArgs = useMemo(\n () =>\n args === \"skip\"\n ? (\"skip\" as const)\n : (Ref.encodePaginatedQueryArgsSync(\n ref,\n args as unknown as Omit<Ref.Args<Query>, \"paginationOpts\">,\n ) as Record<string, Value>),\n [ref, args],\n );\n\n const { user: convexResult } = useConvexPaginatedQueryInternal(\n functionReference,\n encodedArgs,\n options,\n false,\n );\n\n // The Convex hook carries the pages loaded so far on every status,\n // failures included, so results are decoded unconditionally.\n //\n // Decoding allocates fresh items, so key on the referentially stable\n // `results` the Convex hook provides — the same identity-preservation\n // rationale as in `useQuery` above.\n const { results: encodedResults } = convexResult;\n const decodedResults = useMemo(\n () => Ref.decodePaginationPageSync(ref, encodedResults),\n [ref, encodedResults],\n );\n\n const { status, loadMore } = convexResult;\n const error = status === \"Error\" ? convexResult.error : undefined;\n\n return useMemo(\n (): PaginatedQueryResult.Variants<\n PaginatedQueryItem<Query>,\n Ref.Error<Query>\n > =>\n // `status` is a bare string union rather than a tagged one, so the arms\n // match on literals.\n Match.value(status).pipe(\n Match.when(\"Error\", () => {\n if (Ref.isConvexError(error)) {\n const decoded = Ref.decodeErrorOption(ref, error.data);\n if (Option.isSome(decoded)) {\n return PaginatedQueryResult.failure({\n error: decoded.value,\n results: decodedResults,\n });\n }\n }\n // Unknown errors still throw. All hooks have run by this point, so\n // an aborted render here is hook-order-safe.\n throw error;\n }),\n Match.when(\"LoadingFirstPage\", () =>\n PaginatedQueryResult.loadingFirstPage({ skipped }),\n ),\n Match.when(\"LoadingMore\", () =>\n PaginatedQueryResult.loadingMore({ results: decodedResults }),\n ),\n // `CanLoadMore` is the only status whose `loadMore` does anything —\n // the Convex hook returns an intentional no-op for all the others, so\n // they carry no callback at all.\n Match.when(\"CanLoadMore\", () =>\n PaginatedQueryResult.canLoadMore({\n results: decodedResults,\n loadMore,\n }),\n ),\n Match.when(\"Exhausted\", () =>\n PaginatedQueryResult.exhausted({ results: decodedResults }),\n ),\n Match.exhaustive,\n ),\n // The memo produces `Variants`, the conditional return type's superset —\n // when `E` is `never` the `Failure` arm is unreachable at runtime, which\n // is exactly what the conditional encodes.\n [ref, skipped, decodedResults, status, loadMore, error],\n ) as PaginatedQueryResult.PaginatedQueryResult<\n PaginatedQueryItem<Query>,\n Ref.Error<Query>\n >;\n};\n\n/**\n * An optimistic update for a Confect mutation. Mirrors Convex's\n * `OptimisticUpdate`, but receives a Confect {@link OptimisticLocalStore} and\n * the decoded mutation `args`.\n */\nexport type OptimisticUpdate<Mutation extends Ref.AnyPublicMutation> = (\n localStore: OptimisticLocalStore.OptimisticLocalStore,\n args: Ref.Args<Mutation>,\n) => void;\n\n/**\n * The handle returned by {@link useMutation}. It is callable like the function\n * returned by Convex's `useMutation`, and additionally exposes\n * `withOptimisticUpdate` for attaching an optimistic update. Mirrors the\n * `ReactMutation` type from `convex/react`.\n */\nexport interface ReactMutation<Mutation extends Ref.AnyPublicMutation> {\n (...args: Ref.OptionalArgs<Mutation>): InvokeReturn<Mutation>;\n withOptimisticUpdate(\n optimisticUpdate: OptimisticUpdate<Mutation>,\n ): ReactMutation<Mutation>;\n}\n\nconst makeReactMutation = <Mutation extends Ref.AnyPublicMutation>(\n ref: Mutation,\n convexReactMutation: ConvexReactMutation<\n Ref.FunctionReference<Mutation> & FunctionReference<\"mutation\">\n >,\n): ReactMutation<Mutation> => {\n const callable = ((...args: Ref.OptionalArgs<Mutation>) =>\n invokeAsResult(\n ref,\n (_, encodedArgs) => convexReactMutation(encodedArgs as never),\n args,\n ).then((result) =>\n Ref.hasErrorSchema(ref) ? result : Result.getOrThrow(result),\n )) as (...args: Ref.OptionalArgs<Mutation>) => InvokeReturn<Mutation>;\n\n const withOptimisticUpdate = (\n optimisticUpdate: OptimisticUpdate<Mutation>,\n ): ReactMutation<Mutation> => {\n const wrappedUpdate: ConvexOptimisticUpdate<Record<string, Value>> = (\n convexLocalStore,\n encodedArgs,\n ) => {\n const decodedArgs = Ref.decodeArgsSync(ref, encodedArgs);\n optimisticUpdate(\n OptimisticLocalStore.make(convexLocalStore),\n decodedArgs,\n );\n };\n const nextConvexReactMutation =\n convexReactMutation.withOptimisticUpdate(wrappedUpdate);\n return makeReactMutation(ref, nextConvexReactMutation);\n };\n\n return Object.assign(callable, { withOptimisticUpdate });\n};\n\n/**\n * Returns a {@link ReactMutation} handle for the provided `Ref`'s mutation. The\n * handle is callable to invoke the mutation, and exposes `withOptimisticUpdate`\n * for attaching an optimistic update, mirroring `useMutation` from\n * `convex/react`.\n *\n * If the `Ref` declares an `error` schema, the returned promise resolves to a\n * `Result` with the decoded `returns` value in the `Success` and the decoded\n * error in the `Failure`.\n *\n * If the `Ref` does not declare an `error` schema, the promise resolves\n * directly to the decoded `returns` value, matching the behavior of\n * `useMutation` from `convex/react`.\n *\n * Any other failure rejects the promise.\n */\nexport const useMutation = <Mutation extends Ref.AnyPublicMutation>(\n ref: Mutation,\n): ReactMutation<Mutation> => {\n const functionReference = Ref.getFunctionReference(ref);\n const convexReactMutation = useConvexMutation(functionReference);\n\n return useMemo(\n () =>\n makeReactMutation(\n ref,\n convexReactMutation as ConvexReactMutation<\n Ref.FunctionReference<Mutation> & FunctionReference<\"mutation\">\n >,\n ),\n [ref, convexReactMutation],\n );\n};\n\n/**\n * Returns a function that invokes the provided `Ref`'s action.\n *\n * If the `Ref` declares an `error` schema, the returned promise resolves to a\n * `Result` with the decoded `returns` value in the `Success` and the decoded\n * error in the `Failure`.\n *\n * If the `Ref` does not declare an `error` schema, the promise resolves\n * directly to the decoded `returns` value, matching the behavior of\n * `useMutation` from `convex/react`.\n *\n * Any other failure rejects the promise.\n */\nexport const useAction = <Action extends Ref.AnyPublicAction>(\n ref: Action,\n): ((...args: Ref.OptionalArgs<Action>) => InvokeReturn<Action>) => {\n const functionReference = Ref.getFunctionReference(ref);\n const actualAction = useConvexAction(functionReference);\n\n return useCallback(\n ((...args: Ref.OptionalArgs<Action>) =>\n invokeAsResult(\n ref,\n (_, encodedArgs) => actualAction(encodedArgs),\n args,\n ).then((result) =>\n Ref.hasErrorSchema(ref) ? result : Result.getOrThrow(result),\n )) as (...args: Ref.OptionalArgs<Action>) => InvokeReturn<Action>,\n [ref, actualAction],\n );\n};\n\nconst invokeAsResult = async <Ref_ extends Ref.Any>(\n ref: Ref_,\n invoke: (\n fnRef: Ref.FunctionReference<Ref_>,\n encodedArgs: unknown,\n ) => PromiseLike<unknown>,\n args: Ref.OptionalArgs<Ref_>,\n): Promise<Result.Result<Ref.Returns<Ref_>, Ref.Error<Ref_>>> => {\n const exit = await Effect.runPromiseExit(\n Ref.runWithCodec(ref, (args[0] ?? {}) as Ref.Args<Ref_>, invoke).pipe(\n Effect.catchTag(\"SchemaError\", Effect.die),\n Effect.result,\n ),\n );\n if (Exit.isSuccess(exit)) return exit.value;\n throw Cause.squash(exit.cause);\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["useConvexQuery","QueryResult.load","QueryResult.succeed","QueryResult.fail","convexVersion","PaginatedQueryResult.failure","PaginatedQueryResult.loadingFirstPage","PaginatedQueryResult.loadingMore","PaginatedQueryResult.canLoadMore","PaginatedQueryResult.exhausted","OptimisticLocalStore.make","useConvexMutation","useConvexAction"],"sources":["../src/index.ts"],"sourcesContent":["import { Ref } from \"@confect/core\";\nimport { version as convexVersion } from \"convex\";\nimport type { OptimisticUpdate as ConvexOptimisticUpdate } from \"convex/browser\";\nimport * as ConvexReact from \"convex/react\";\nimport type { usePaginatedQuery as useConvexPaginatedQuery } from \"convex/react\";\nimport {\n useAction as useConvexAction,\n useMutation as useConvexMutation,\n useQuery as useConvexQuery,\n type ReactMutation as ConvexReactMutation,\n} from \"convex/react\";\nimport type { FunctionReference } from \"convex/server\";\nimport type { Value } from \"convex/values\";\nimport * as Cause from \"effect/Cause\";\nimport * as Effect from \"effect/Effect\";\nimport * as Result from \"effect/Result\";\nimport * as Exit from \"effect/Exit\";\nimport * as Match from \"effect/Match\";\nimport * as Option from \"effect/Option\";\nimport { useCallback, useMemo } from \"react\";\n\nimport * as OptimisticLocalStore from \"./OptimisticLocalStore\";\nimport * as PaginatedQueryResult from \"./PaginatedQueryResult\";\nimport * as QueryResult from \"./QueryResult\";\n\nexport { OptimisticLocalStore, PaginatedQueryResult, QueryResult };\n\nexport type InvokeReturn<Ref_ extends Ref.Any> = [Ref.Error<Ref_>] extends [\n never,\n]\n ? Promise<Ref.Returns<Ref_>>\n : Promise<Result.Result<Ref.Returns<Ref_>, Ref.Error<Ref_>>>;\n\ntype UseQueryArgs<Query extends Ref.AnyPublicQuery> =\n keyof Ref.Args<Query> extends never\n ? [args?: Ref.Args<Query> | \"skip\"]\n : [args: Ref.Args<Query> | \"skip\"];\n\nexport const useQuery = <Query extends Ref.AnyPublicQuery>(\n ref: Query,\n ...rest: UseQueryArgs<Query>\n): QueryResult.QueryResult<Ref.Returns<Query>, Ref.Error<Query>> => {\n const functionReference = Ref.getFunctionReference(ref);\n const args = rest[0];\n const skipped = args === \"skip\";\n const encodedArgs = skipped\n ? \"skip\"\n : Ref.encodeArgsSync(ref, (args ?? {}) as Ref.Args<Query>);\n\n // `useConvexQuery` returns a referentially stable value while the underlying\n // Convex result is unchanged, and throws a stable error when the query\n // fails. We capture either outcome as a `Result` and decode/wrap it inside\n // `useMemo` so that the returned `QueryResult` keeps a stable identity across\n // renders when nothing has actually changed. Decoding on every render would\n // hand consumers a fresh object each time, breaking effects and memoization\n // that depend on the result's identity.\n const encodedReturnsOrError: Result.Result<unknown, unknown> = Result.try(\n () => useConvexQuery(functionReference, encodedArgs),\n );\n\n return useMemo(\n () =>\n Result.match(encodedReturnsOrError, {\n onSuccess: (encodedReturnsOrUndefined) =>\n encodedReturnsOrUndefined === undefined\n ? QueryResult.load(skipped)\n : QueryResult.succeed(\n Ref.decodeReturnsSync(ref, encodedReturnsOrUndefined),\n ),\n onFailure: (error) => {\n if (Ref.isConvexError(error)) {\n const decoded = Ref.decodeErrorOption(ref, error.data);\n if (Option.isSome(decoded)) {\n return QueryResult.fail(decoded.value);\n }\n }\n throw error;\n },\n }),\n // `Result.try` allocates a fresh wrapper each render, so we key the memo on\n // the stable value it carries (the Convex result or thrown error) rather\n // than the wrapper itself; the decoded result is a function of that value,\n // `ref`, and `skipped`.\n [ref, skipped, Result.merge(encodedReturnsOrError)],\n );\n};\n\n/**\n * Like `Omit`, but implemented with key remapping so that optional modifiers\n * are preserved and index signatures don't reintroduce the omitted key's\n * literal type. Mirrors `BetterOmit` from `convex/server`.\n */\ntype OmitKey<T, K extends PropertyKey> = {\n [P in keyof T as P extends K ? never : P]: T[P];\n};\n\n/**\n * The args accepted by {@link usePaginatedQuery}: the ref's args without\n * `paginationOpts`, which the underlying Convex hook manages itself. When no\n * args remain, resolves to `Record<string, never>` (only the empty object is\n * accepted) rather than `{}`, which would accept any non-nullish value.\n */\nexport type PaginatedQueryArgs<Query extends Ref.AnyPublicPaginatedQuery> =\n OmitKey<Ref.Args<Query>, \"paginationOpts\"> extends infer Args_\n ? keyof Args_ extends never\n ? Record<string, never>\n : Args_\n : never;\n\n/**\n * The item type for a paginated query: the element type of the `page` field\n * of the ref's returns.\n */\nexport type PaginatedQueryItem<Query extends Ref.AnyPublicPaginatedQuery> =\n Ref.Returns<Query>[\"page\"][number];\n\n/**\n * The args parameter of {@link usePaginatedQuery}: the ref's args without\n * `paginationOpts`, or `\"skip\"` to skip the query.\n */\nexport type UsePaginatedQueryArgs<Query extends Ref.AnyPublicPaginatedQuery> =\n | PaginatedQueryArgs<Query>\n | \"skip\";\n\nexport type PaginatedQueryOptions = Parameters<\n typeof useConvexPaginatedQuery\n>[2];\n\n/**\n * The `user`-facing result of `usePaginatedQueryInternal` from `convex/react`,\n * including the `\"Error\"` status its non-throwing mode can return.\n */\ninterface ConvexPaginatedQueryInternalUser {\n readonly results: ReadonlyArray<unknown>;\n readonly status:\n | \"LoadingFirstPage\"\n | \"LoadingMore\"\n | \"CanLoadMore\"\n | \"Exhausted\"\n | \"Error\";\n readonly isLoading: boolean;\n readonly loadMore: (numItems: number) => void;\n readonly error?: unknown;\n}\n\ntype UseConvexPaginatedQueryInternal = (\n query: FunctionReference<\"query\">,\n args: Record<string, Value> | \"skip\",\n options: PaginatedQueryOptions,\n throwOnError: boolean,\n) => { user: ConvexPaginatedQueryInternalUser };\n\n// `usePaginatedQueryInternal` is runtime-exported by convex/react but absent\n// from its public type declarations. It is the only way to observe query\n// errors as values: the public positional `usePaginatedQuery` hard-codes\n// throwOnError and throws mid-hook-sequence, which cannot be caught without\n// breaking React's hook-order invariant.\nconst useConvexPaginatedQueryInternal = (\n ConvexReact as unknown as Record<string, unknown>\n).usePaginatedQueryInternal as UseConvexPaginatedQueryInternal | undefined;\n\nconst MINIMUM_CONVEX_VERSION = \"1.36.0\";\n\n/**\n * The non-throwing mode of `usePaginatedQueryInternal` — its fourth,\n * `throwOnError` parameter — arrived in convex 1.36.0. Convex 1.32 through\n * 1.35 export the same symbol taking only three parameters, where a fourth\n * argument is silently ignored and errors are always thrown.\n *\n * The function itself cannot be interrogated for this: `Function.length`\n * counts parameters up to the first one with a default, and 1.36.0 declares\n * `throwOnError = true`, so both shapes report an arity of 3. The package\n * version is the only reliable signal.\n */\nconst supportsErrorsAsValues = ((): boolean => {\n const [major, minor] = convexVersion.split(\".\").map(Number);\n if (\n major === undefined ||\n minor === undefined ||\n Number.isNaN(major) ||\n Number.isNaN(minor)\n ) {\n return false;\n }\n const [minimumMajor, minimumMinor] = MINIMUM_CONVEX_VERSION.split(\".\").map(\n Number,\n ) as [number, number];\n return (\n major > minimumMajor || (major === minimumMajor && minor >= minimumMinor)\n );\n})();\n\n/**\n * Load data reactively from a paginated query defined with\n * `FunctionSpec.publicPaginatedQuery`, mirroring the ergonomics of\n * `usePaginatedQuery` from `convex/react`.\n *\n * Args are encoded via the ref's user-args schema (`paginationOpts` is managed\n * by the Convex hook, not the caller), and each loaded page is decoded via the\n * ref's item schema.\n *\n * Returns a {@link PaginatedQueryResult.PaginatedQueryResult}: the loaded\n * variants carry `results` and `isLoading`, and `CanLoadMore` additionally\n * carries `loadMore`; if the `Ref` declares an `error` schema and the query\n * fails with that typed error, the decoded error is returned as the `Failure`\n * variant, which also carries the pages loaded before the failure. Unknown\n * errors are thrown, to be caught by an error boundary.\n */\nexport const usePaginatedQuery = <Query extends Ref.AnyPublicPaginatedQuery>(\n ref: Query,\n args: UsePaginatedQueryArgs<Query>,\n options: PaginatedQueryOptions,\n): PaginatedQueryResult.PaginatedQueryResult<\n PaginatedQueryItem<Query>,\n Ref.Error<Query>\n> => {\n if (\n useConvexPaginatedQueryInternal === undefined ||\n !supportsErrorsAsValues\n ) {\n throw new Error(\n `usePaginatedQuery requires convex >= ${MINIMUM_CONVEX_VERSION}, but found ` +\n `${convexVersion}. Earlier versions always throw paginated query errors ` +\n \"instead of returning them, so a declared `error` schema cannot be \" +\n \"surfaced as a `Failure` — upgrade the `convex` package.\",\n );\n }\n\n const functionReference = Ref.getFunctionReference(ref);\n const skipped = args === \"skip\";\n\n // The encoded output is the wire form Convex's hook forwards verbatim, not\n // the ref's decoded args type.\n const encodedArgs = useMemo(\n () =>\n args === \"skip\"\n ? (\"skip\" as const)\n : (Ref.encodePaginatedQueryArgsSync(\n ref,\n args as unknown as Omit<Ref.Args<Query>, \"paginationOpts\">,\n ) as Record<string, Value>),\n [ref, args],\n );\n\n const { user: convexResult } = useConvexPaginatedQueryInternal(\n functionReference,\n encodedArgs,\n options,\n false,\n );\n\n // The Convex hook carries the pages loaded so far on every status,\n // failures included, so results are decoded unconditionally.\n //\n // Decoding allocates fresh items, so key on the referentially stable\n // `results` the Convex hook provides — the same identity-preservation\n // rationale as in `useQuery` above.\n const { results: encodedResults } = convexResult;\n const decodedResults = useMemo(\n () => Ref.decodePaginationPageSync(ref, encodedResults),\n [ref, encodedResults],\n );\n\n const { status, loadMore } = convexResult;\n const error = status === \"Error\" ? convexResult.error : undefined;\n\n return useMemo(\n (): PaginatedQueryResult.Variants<\n PaginatedQueryItem<Query>,\n Ref.Error<Query>\n > =>\n // `status` is a bare string union rather than a tagged one, so the arms\n // match on literals.\n Match.value(status).pipe(\n Match.when(\"Error\", () => {\n if (Ref.isConvexError(error)) {\n const decoded = Ref.decodeErrorOption(ref, error.data);\n if (Option.isSome(decoded)) {\n return PaginatedQueryResult.failure({\n error: decoded.value,\n results: decodedResults,\n });\n }\n }\n // Unknown errors still throw. All hooks have run by this point, so\n // an aborted render here is hook-order-safe.\n throw error;\n }),\n Match.when(\"LoadingFirstPage\", () =>\n PaginatedQueryResult.loadingFirstPage({ skipped }),\n ),\n Match.when(\"LoadingMore\", () =>\n PaginatedQueryResult.loadingMore({ results: decodedResults }),\n ),\n // `CanLoadMore` is the only status whose `loadMore` does anything —\n // the Convex hook returns an intentional no-op for all the others, so\n // they carry no callback at all.\n Match.when(\"CanLoadMore\", () =>\n PaginatedQueryResult.canLoadMore({\n results: decodedResults,\n loadMore,\n }),\n ),\n Match.when(\"Exhausted\", () =>\n PaginatedQueryResult.exhausted({ results: decodedResults }),\n ),\n Match.exhaustive,\n ),\n // The memo produces `Variants`, the conditional return type's superset —\n // when `E` is `never` the `Failure` arm is unreachable at runtime, which\n // is exactly what the conditional encodes.\n [ref, skipped, decodedResults, status, loadMore, error],\n ) as PaginatedQueryResult.PaginatedQueryResult<\n PaginatedQueryItem<Query>,\n Ref.Error<Query>\n >;\n};\n\n/**\n * An optimistic update for a Confect mutation. Mirrors Convex's\n * `OptimisticUpdate`, but receives a Confect {@link OptimisticLocalStore} and\n * the decoded mutation `args`.\n */\nexport type OptimisticUpdate<Mutation extends Ref.AnyPublicMutation> = (\n localStore: OptimisticLocalStore.OptimisticLocalStore,\n args: Ref.Args<Mutation>,\n) => void;\n\n/**\n * The handle returned by {@link useMutation}. It is callable like the function\n * returned by Convex's `useMutation`, and additionally exposes\n * `withOptimisticUpdate` for attaching an optimistic update. Mirrors the\n * `ReactMutation` type from `convex/react`.\n */\nexport interface ReactMutation<Mutation extends Ref.AnyPublicMutation> {\n (...args: Ref.OptionalArgs<Mutation>): InvokeReturn<Mutation>;\n withOptimisticUpdate(\n optimisticUpdate: OptimisticUpdate<Mutation>,\n ): ReactMutation<Mutation>;\n}\n\nconst makeReactMutation = <Mutation extends Ref.AnyPublicMutation>(\n ref: Mutation,\n convexReactMutation: ConvexReactMutation<\n Ref.FunctionReference<Mutation> & FunctionReference<\"mutation\">\n >,\n): ReactMutation<Mutation> => {\n const callable = ((...args: Ref.OptionalArgs<Mutation>) =>\n invokeAsResult(\n ref,\n (_, encodedArgs) => convexReactMutation(encodedArgs as never),\n args,\n ).then((result) =>\n Ref.hasErrorSchema(ref) ? result : Result.getOrThrow(result),\n )) as (...args: Ref.OptionalArgs<Mutation>) => InvokeReturn<Mutation>;\n\n const withOptimisticUpdate = (\n optimisticUpdate: OptimisticUpdate<Mutation>,\n ): ReactMutation<Mutation> => {\n const wrappedUpdate: ConvexOptimisticUpdate<Record<string, Value>> = (\n convexLocalStore,\n encodedArgs,\n ) => {\n const decodedArgs = Ref.decodeArgsSync(ref, encodedArgs);\n optimisticUpdate(\n OptimisticLocalStore.make(convexLocalStore),\n decodedArgs,\n );\n };\n const nextConvexReactMutation =\n convexReactMutation.withOptimisticUpdate(wrappedUpdate);\n return makeReactMutation(ref, nextConvexReactMutation);\n };\n\n return Object.assign(callable, { withOptimisticUpdate });\n};\n\n/**\n * Returns a {@link ReactMutation} handle for the provided `Ref`'s mutation. The\n * handle is callable to invoke the mutation, and exposes `withOptimisticUpdate`\n * for attaching an optimistic update, mirroring `useMutation` from\n * `convex/react`.\n *\n * If the `Ref` declares an `error` schema, the returned promise resolves to a\n * `Result` with the decoded `returns` value in the `Success` and the decoded\n * error in the `Failure`.\n *\n * If the `Ref` does not declare an `error` schema, the promise resolves\n * directly to the decoded `returns` value, matching the behavior of\n * `useMutation` from `convex/react`.\n *\n * Any other failure rejects the promise.\n */\nexport const useMutation = <Mutation extends Ref.AnyPublicMutation>(\n ref: Mutation,\n): ReactMutation<Mutation> => {\n const functionReference = Ref.getFunctionReference(ref);\n const convexReactMutation = useConvexMutation(functionReference);\n\n return useMemo(\n () =>\n makeReactMutation(\n ref,\n convexReactMutation as ConvexReactMutation<\n Ref.FunctionReference<Mutation> & FunctionReference<\"mutation\">\n >,\n ),\n [ref, convexReactMutation],\n );\n};\n\n/**\n * Returns a function that invokes the provided `Ref`'s action.\n *\n * If the `Ref` declares an `error` schema, the returned promise resolves to a\n * `Result` with the decoded `returns` value in the `Success` and the decoded\n * error in the `Failure`.\n *\n * If the `Ref` does not declare an `error` schema, the promise resolves\n * directly to the decoded `returns` value, matching the behavior of\n * `useMutation` from `convex/react`.\n *\n * Any other failure rejects the promise.\n */\nexport const useAction = <Action extends Ref.AnyPublicAction>(\n ref: Action,\n): ((...args: Ref.OptionalArgs<Action>) => InvokeReturn<Action>) => {\n const functionReference = Ref.getFunctionReference(ref);\n const actualAction = useConvexAction(functionReference);\n\n return useCallback(\n ((...args: Ref.OptionalArgs<Action>) =>\n invokeAsResult(\n ref,\n (_, encodedArgs) => actualAction(encodedArgs),\n args,\n ).then((result) =>\n Ref.hasErrorSchema(ref) ? result : Result.getOrThrow(result),\n )) as (...args: Ref.OptionalArgs<Action>) => InvokeReturn<Action>,\n [ref, actualAction],\n );\n};\n\nconst invokeAsResult = <Ref_ extends Ref.Any>(\n ref: Ref_,\n invoke: (\n fnRef: Ref.FunctionReference<Ref_>,\n encodedArgs: unknown,\n ) => PromiseLike<unknown>,\n args: Ref.OptionalArgs<Ref_>,\n): Promise<Result.Result<Ref.Returns<Ref_>, Ref.Error<Ref_>>> => {\n const exitPromise = Effect.runPromiseExit(\n Ref.runWithCodec(ref, (args[0] ?? {}) as Ref.Args<Ref_>, invoke).pipe(\n Effect.catchTag(\"SchemaError\", Effect.die),\n Effect.result,\n ),\n );\n return exitPromise.then((exit) => {\n if (Exit.isSuccess(exit)) return exit.value;\n throw Cause.squash(exit.cause);\n });\n};\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,30 +1,30 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@confect/react",
|
|
3
3
|
"description": "Client-side bindings for React apps",
|
|
4
|
-
"version": "10.0.0-next.
|
|
4
|
+
"version": "10.0.0-next.21",
|
|
5
5
|
"author": "RJ Dellecese",
|
|
6
6
|
"bugs": {
|
|
7
7
|
"url": "https://github.com/rjdellecese/confect/issues"
|
|
8
8
|
},
|
|
9
9
|
"devDependencies": {
|
|
10
10
|
"@effect/vitest": "4.0.0-rc.112",
|
|
11
|
-
"@testing-library/react": "16.3.
|
|
12
|
-
"@types/node": "
|
|
11
|
+
"@testing-library/react": "16.3.3",
|
|
12
|
+
"@types/node": "24.13.3",
|
|
13
13
|
"@types/react": "19.2.18",
|
|
14
14
|
"@types/react-dom": "19.2.4",
|
|
15
15
|
"convex": "1.45.0",
|
|
16
16
|
"effect": "4.0.0-rc.112",
|
|
17
|
-
"happy-dom": "20.
|
|
17
|
+
"happy-dom": "20.12.0",
|
|
18
18
|
"react": "19.2.8",
|
|
19
19
|
"react-dom": "19.2.8",
|
|
20
20
|
"tsdown": "0.22.14",
|
|
21
21
|
"typescript": "7.0.2",
|
|
22
22
|
"unrun": "0.3.1",
|
|
23
|
-
"vite": "8.2.
|
|
24
|
-
"vitest": "4.1.
|
|
23
|
+
"vite": "8.2.2",
|
|
24
|
+
"vitest": "4.1.11"
|
|
25
25
|
},
|
|
26
26
|
"engines": {
|
|
27
|
-
"node": ">=
|
|
27
|
+
"node": ">=24"
|
|
28
28
|
},
|
|
29
29
|
"exports": {
|
|
30
30
|
".": {
|
|
@@ -56,10 +56,10 @@
|
|
|
56
56
|
"main": "./dist/index.js",
|
|
57
57
|
"module": "./dist/index.js",
|
|
58
58
|
"peerDependencies": {
|
|
59
|
+
"@confect/core": "^10.0.0-next.21",
|
|
59
60
|
"convex": "^1.36.0",
|
|
60
61
|
"effect": "^4.0.0-rc.112",
|
|
61
|
-
"react": "^18.0.0 || ^19.0.0"
|
|
62
|
-
"@confect/core": "^10.0.0-next.20"
|
|
62
|
+
"react": "^18.0.0 || ^19.0.0"
|
|
63
63
|
},
|
|
64
64
|
"repository": {
|
|
65
65
|
"type": "git",
|
|
@@ -60,7 +60,7 @@ export type Variants<Item, E = never> =
|
|
|
60
60
|
| Failure<Item, E>;
|
|
61
61
|
|
|
62
62
|
export declare namespace PaginatedQueryResult {
|
|
63
|
-
// eslint-disable-next-line @typescript-eslint/no-shadow
|
|
63
|
+
// eslint-disable-next-line @typescript-eslint/no-shadow
|
|
64
64
|
export interface Proto<out Item, out E> extends Pipeable.Pipeable {
|
|
65
65
|
readonly [TypeId]: TypeId;
|
|
66
66
|
readonly "~Item": Item;
|
package/src/QueryResult.ts
CHANGED
|
@@ -20,7 +20,6 @@ export type QueryResult<A, E = never> =
|
|
|
20
20
|
| Failure<A, E>;
|
|
21
21
|
|
|
22
22
|
export declare namespace QueryResult {
|
|
23
|
-
// eslint-disable-next-line import/namespace -- oxlint's namespace resolution misses type-only exports, and `Pipeable` is an interface
|
|
24
23
|
export interface Proto<out A, out E> extends Pipeable.Pipeable {
|
|
25
24
|
readonly [TypeId]: TypeId;
|
|
26
25
|
readonly "~A": A;
|
package/src/index.ts
CHANGED
|
@@ -173,7 +173,7 @@ const MINIMUM_CONVEX_VERSION = "1.36.0";
|
|
|
173
173
|
* version is the only reliable signal.
|
|
174
174
|
*/
|
|
175
175
|
const supportsErrorsAsValues = ((): boolean => {
|
|
176
|
-
const [major, minor] =
|
|
176
|
+
const [major, minor] = convexVersion.split(".").map(Number);
|
|
177
177
|
if (
|
|
178
178
|
major === undefined ||
|
|
179
179
|
minor === undefined ||
|
|
@@ -441,7 +441,7 @@ export const useAction = <Action extends Ref.AnyPublicAction>(
|
|
|
441
441
|
);
|
|
442
442
|
};
|
|
443
443
|
|
|
444
|
-
const invokeAsResult =
|
|
444
|
+
const invokeAsResult = <Ref_ extends Ref.Any>(
|
|
445
445
|
ref: Ref_,
|
|
446
446
|
invoke: (
|
|
447
447
|
fnRef: Ref.FunctionReference<Ref_>,
|
|
@@ -449,12 +449,14 @@ const invokeAsResult = async <Ref_ extends Ref.Any>(
|
|
|
449
449
|
) => PromiseLike<unknown>,
|
|
450
450
|
args: Ref.OptionalArgs<Ref_>,
|
|
451
451
|
): Promise<Result.Result<Ref.Returns<Ref_>, Ref.Error<Ref_>>> => {
|
|
452
|
-
const
|
|
452
|
+
const exitPromise = Effect.runPromiseExit(
|
|
453
453
|
Ref.runWithCodec(ref, (args[0] ?? {}) as Ref.Args<Ref_>, invoke).pipe(
|
|
454
454
|
Effect.catchTag("SchemaError", Effect.die),
|
|
455
455
|
Effect.result,
|
|
456
456
|
),
|
|
457
457
|
);
|
|
458
|
-
|
|
459
|
-
|
|
458
|
+
return exitPromise.then((exit) => {
|
|
459
|
+
if (Exit.isSuccess(exit)) return exit.value;
|
|
460
|
+
throw Cause.squash(exit.cause);
|
|
461
|
+
});
|
|
460
462
|
};
|