@confect/react 9.0.2 → 9.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,22 @@
1
1
  # @confect/react
2
2
 
3
+ ## 9.1.1
4
+
5
+ ### Patch Changes
6
+
7
+ - @confect/core@9.1.1
8
+
9
+ ## 9.1.0
10
+
11
+ ### Minor Changes
12
+
13
+ - 4d8a568: Add `withOptimisticUpdate` to `@confect/react`'s `useMutation`, mirroring Convex's API. The mutation handle returned by `useMutation` is now both callable and exposes `.withOptimisticUpdate(fn)` for attaching an optimistic update. Inside the callback, the `OptimisticLocalStore`'s `getQuery`/`setQuery`/`getAllQueries` accept Confect query `Ref`s and operate on decoded (Effect Schema) values wrapped in `Option`; the wrapper handles encoding/decoding against Convex's local store.
14
+
15
+ ### Patch Changes
16
+
17
+ - Updated dependencies [4d8a568]
18
+ - @confect/core@9.1.0
19
+
3
20
  ## 9.0.2
4
21
 
5
22
  ### Patch Changes
@@ -0,0 +1,25 @@
1
+ import { Ref } from "@confect/core";
2
+ import type { OptimisticLocalStore as ConvexOptimisticLocalStore } from "convex/browser";
3
+ import * as Option from "effect/Option";
4
+ /**
5
+ * The Confect counterpart to Convex's `OptimisticLocalStore`.
6
+ *
7
+ * Its methods accept Confect query `Ref`s and operate on decoded (Effect
8
+ * Schema) values rather than the encoded values stored by Convex. Query values
9
+ * are wrapped in `Option`: `Option.none()` represents a query that is not
10
+ * present in the store, and `Option.some(value)` carries the decoded value.
11
+ */
12
+ export interface OptimisticLocalStore {
13
+ getQuery<Query extends Ref.AnyPublicQuery>(queryRef: Query, ...args: Ref.OptionalArgs<Query>): Option.Option<Ref.Returns<Query>>;
14
+ getAllQueries<Query extends Ref.AnyPublicQuery>(queryRef: Query): Array<{
15
+ args: Ref.Args<Query>;
16
+ value: Option.Option<Ref.Returns<Query>>;
17
+ }>;
18
+ setQuery<Query extends Ref.AnyPublicQuery>(queryRef: Query, args: Ref.Args<Query>, value: Option.Option<Ref.Returns<Query>>): void;
19
+ }
20
+ /**
21
+ * Wraps Convex's `OptimisticLocalStore` so that it accepts Confect query `Ref`s
22
+ * and decoded values, handling the encoding/decoding against Convex's store.
23
+ */
24
+ export declare const make: (convexLocalStore: ConvexOptimisticLocalStore) => OptimisticLocalStore;
25
+ //# sourceMappingURL=OptimisticLocalStore.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"OptimisticLocalStore.d.ts","sourceRoot":"","sources":["../src/OptimisticLocalStore.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AACpC,OAAO,KAAK,EAAE,oBAAoB,IAAI,0BAA0B,EAAE,MAAM,gBAAgB,CAAC;AACzF,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAExC;;;;;;;GAOG;AACH,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,KAAK,SAAS,GAAG,CAAC,cAAc,EACvC,QAAQ,EAAE,KAAK,EACf,GAAG,IAAI,EAAE,GAAG,CAAC,YAAY,CAAC,KAAK,CAAC,GAC/B,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;IAErC,aAAa,CAAC,KAAK,SAAS,GAAG,CAAC,cAAc,EAC5C,QAAQ,EAAE,KAAK,GACd,KAAK,CAAC;QACP,IAAI,EAAE,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACtB,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;KAC1C,CAAC,CAAC;IAEH,QAAQ,CAAC,KAAK,SAAS,GAAG,CAAC,cAAc,EACvC,QAAQ,EAAE,KAAK,EACf,IAAI,EAAE,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,EACrB,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,GACvC,IAAI,CAAC;CACT;AAED;;;GAGG;AACH,eAAO,MAAM,IAAI,GACf,kBAAkB,0BAA0B,KAC3C,oBA+BD,CAAC"}
@@ -0,0 +1,39 @@
1
+ import { __exportAll } from "./_virtual/_rolldown/runtime.js";
2
+ import { Ref } from "@confect/core";
3
+ import * as Option from "effect/Option";
4
+
5
+ //#region src/OptimisticLocalStore.ts
6
+ var OptimisticLocalStore_exports = /* @__PURE__ */ __exportAll({ make: () => make });
7
+ /**
8
+ * Wraps Convex's `OptimisticLocalStore` so that it accepts Confect query `Ref`s
9
+ * and decoded values, handling the encoding/decoding against Convex's store.
10
+ */
11
+ const make = (convexLocalStore) => ({
12
+ getQuery: (queryRef, ...rest) => {
13
+ const functionReference = Ref.getFunctionReference(queryRef);
14
+ const args = rest[0] ?? {};
15
+ const encodedArgs = Ref.encodeArgsSync(queryRef, args);
16
+ const encoded = convexLocalStore.getQuery(functionReference, encodedArgs);
17
+ return encoded === void 0 ? Option.none() : Option.some(Ref.decodeReturnsSync(queryRef, encoded));
18
+ },
19
+ getAllQueries: (queryRef) => {
20
+ const functionReference = Ref.getFunctionReference(queryRef);
21
+ return convexLocalStore.getAllQueries(functionReference).map(({ args, value }) => ({
22
+ args: Ref.decodeArgsSync(queryRef, args),
23
+ value: value === void 0 ? Option.none() : Option.some(Ref.decodeReturnsSync(queryRef, value))
24
+ }));
25
+ },
26
+ setQuery: (queryRef, args, value) => {
27
+ const functionReference = Ref.getFunctionReference(queryRef);
28
+ const encodedArgs = Ref.encodeArgsSync(queryRef, args);
29
+ const encodedValue = Option.match(value, {
30
+ onNone: () => void 0,
31
+ onSome: (decoded) => Ref.encodeReturnsSync(queryRef, decoded)
32
+ });
33
+ convexLocalStore.setQuery(functionReference, encodedArgs, encodedValue);
34
+ }
35
+ });
36
+
37
+ //#endregion
38
+ export { OptimisticLocalStore_exports, make };
39
+ //# sourceMappingURL=OptimisticLocalStore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"OptimisticLocalStore.js","names":[],"sources":["../src/OptimisticLocalStore.ts"],"sourcesContent":["import { Ref } from \"@confect/core\";\nimport type { OptimisticLocalStore as ConvexOptimisticLocalStore } from \"convex/browser\";\nimport * as Option from \"effect/Option\";\n\n/**\n * The Confect counterpart to Convex's `OptimisticLocalStore`.\n *\n * Its methods accept Confect query `Ref`s and operate on decoded (Effect\n * Schema) values rather than the encoded values stored by Convex. Query values\n * are wrapped in `Option`: `Option.none()` represents a query that is not\n * present in the store, and `Option.some(value)` carries the decoded value.\n */\nexport interface OptimisticLocalStore {\n getQuery<Query extends Ref.AnyPublicQuery>(\n queryRef: Query,\n ...args: Ref.OptionalArgs<Query>\n ): Option.Option<Ref.Returns<Query>>;\n\n getAllQueries<Query extends Ref.AnyPublicQuery>(\n queryRef: Query,\n ): Array<{\n args: Ref.Args<Query>;\n value: Option.Option<Ref.Returns<Query>>;\n }>;\n\n setQuery<Query extends Ref.AnyPublicQuery>(\n queryRef: Query,\n args: Ref.Args<Query>,\n value: Option.Option<Ref.Returns<Query>>,\n ): void;\n}\n\n/**\n * Wraps Convex's `OptimisticLocalStore` so that it accepts Confect query `Ref`s\n * and decoded values, handling the encoding/decoding against Convex's store.\n */\nexport const make = (\n convexLocalStore: ConvexOptimisticLocalStore,\n): OptimisticLocalStore => ({\n getQuery: (queryRef, ...rest) => {\n const functionReference = Ref.getFunctionReference(queryRef);\n const args = (rest[0] ?? {}) as Ref.Args<typeof queryRef>;\n const encodedArgs = Ref.encodeArgsSync(queryRef, args);\n const encoded = convexLocalStore.getQuery(functionReference, encodedArgs);\n return encoded === undefined\n ? Option.none()\n : Option.some(Ref.decodeReturnsSync(queryRef, encoded));\n },\n getAllQueries: (queryRef) => {\n const functionReference = Ref.getFunctionReference(queryRef);\n return convexLocalStore\n .getAllQueries(functionReference)\n .map(({ args, value }) => ({\n args: Ref.decodeArgsSync(queryRef, args),\n value:\n value === undefined\n ? Option.none()\n : Option.some(Ref.decodeReturnsSync(queryRef, value)),\n }));\n },\n setQuery: (queryRef, args, value) => {\n const functionReference = Ref.getFunctionReference(queryRef);\n const encodedArgs = Ref.encodeArgsSync(queryRef, args);\n const encodedValue = Option.match(value, {\n onNone: () => undefined,\n onSome: (decoded) => Ref.encodeReturnsSync(queryRef, decoded),\n });\n convexLocalStore.setQuery(functionReference, encodedArgs, encodedValue);\n },\n});\n"],"mappings":";;;;;;;;;;AAoCA,MAAa,QACX,sBAC0B;CAC1B,WAAW,UAAU,GAAG,SAAS;EAC/B,MAAM,oBAAoB,IAAI,qBAAqB,SAAS;EAC5D,MAAM,OAAQ,KAAK,MAAM,EAAE;EAC3B,MAAM,cAAc,IAAI,eAAe,UAAU,KAAK;EACtD,MAAM,UAAU,iBAAiB,SAAS,mBAAmB,YAAY;AACzE,SAAO,YAAY,SACf,OAAO,MAAM,GACb,OAAO,KAAK,IAAI,kBAAkB,UAAU,QAAQ,CAAC;;CAE3D,gBAAgB,aAAa;EAC3B,MAAM,oBAAoB,IAAI,qBAAqB,SAAS;AAC5D,SAAO,iBACJ,cAAc,kBAAkB,CAChC,KAAK,EAAE,MAAM,aAAa;GACzB,MAAM,IAAI,eAAe,UAAU,KAAK;GACxC,OACE,UAAU,SACN,OAAO,MAAM,GACb,OAAO,KAAK,IAAI,kBAAkB,UAAU,MAAM,CAAC;GAC1D,EAAE;;CAEP,WAAW,UAAU,MAAM,UAAU;EACnC,MAAM,oBAAoB,IAAI,qBAAqB,SAAS;EAC5D,MAAM,cAAc,IAAI,eAAe,UAAU,KAAK;EACtD,MAAM,eAAe,OAAO,MAAM,OAAO;GACvC,cAAc;GACd,SAAS,YAAY,IAAI,kBAAkB,UAAU,QAAQ;GAC9D,CAAC;AACF,mBAAiB,SAAS,mBAAmB,aAAa,aAAa;;CAE1E"}
package/dist/index.d.ts CHANGED
@@ -1,14 +1,34 @@
1
1
  import { Ref } from "@confect/core";
2
2
  import * as Either from "effect/Either";
3
+ import * as OptimisticLocalStore from "./OptimisticLocalStore";
3
4
  import * as QueryResult from "./QueryResult";
4
- export { QueryResult };
5
+ export { OptimisticLocalStore, QueryResult };
5
6
  export type InvokeReturn<Ref_ extends Ref.Any> = [Ref.Error<Ref_>] extends [
6
7
  never
7
8
  ] ? Promise<Ref.Returns<Ref_>> : Promise<Either.Either<Ref.Returns<Ref_>, Ref.Error<Ref_>>>;
8
9
  type UseQueryArgs<Query extends Ref.AnyPublicQuery> = keyof Ref.Args<Query> extends never ? [args?: Ref.Args<Query> | "skip"] : [args: Ref.Args<Query> | "skip"];
9
10
  export declare const useQuery: <Query extends Ref.AnyPublicQuery>(ref: Query, ...rest: UseQueryArgs<Query>) => QueryResult.QueryResult<Ref.Returns<Query>, Ref.Error<Query>>;
10
11
  /**
11
- * Returns a function that invokes the provided `Ref`'s mutation.
12
+ * An optimistic update for a Confect mutation. Mirrors Convex's
13
+ * `OptimisticUpdate`, but receives a Confect {@link OptimisticLocalStore} and
14
+ * the decoded mutation `args`.
15
+ */
16
+ export type OptimisticUpdate<Mutation extends Ref.AnyPublicMutation> = (localStore: OptimisticLocalStore.OptimisticLocalStore, args: Ref.Args<Mutation>) => void;
17
+ /**
18
+ * The handle returned by {@link useMutation}. It is callable like the function
19
+ * returned by Convex's `useMutation`, and additionally exposes
20
+ * `withOptimisticUpdate` for attaching an optimistic update. Mirrors the
21
+ * `ReactMutation` type from `convex/react`.
22
+ */
23
+ export interface ReactMutation<Mutation extends Ref.AnyPublicMutation> {
24
+ (...args: Ref.OptionalArgs<Mutation>): InvokeReturn<Mutation>;
25
+ withOptimisticUpdate(optimisticUpdate: OptimisticUpdate<Mutation>): ReactMutation<Mutation>;
26
+ }
27
+ /**
28
+ * Returns a {@link ReactMutation} handle for the provided `Ref`'s mutation. The
29
+ * handle is callable to invoke the mutation, and exposes `withOptimisticUpdate`
30
+ * for attaching an optimistic update, mirroring `useMutation` from
31
+ * `convex/react`.
12
32
  *
13
33
  * If the `Ref` declares an `error` schema, the returned promise resolves to an
14
34
  * `Either` with the decoded `returns` value on the right and the decoded error
@@ -20,7 +40,7 @@ export declare const useQuery: <Query extends Ref.AnyPublicQuery>(ref: Query, ..
20
40
  *
21
41
  * Any other failure rejects the promise.
22
42
  */
23
- export declare const useMutation: <Mutation extends Ref.AnyPublicMutation>(ref: Mutation) => ((...args: Ref.OptionalArgs<Mutation>) => InvokeReturn<Mutation>);
43
+ export declare const useMutation: <Mutation extends Ref.AnyPublicMutation>(ref: Mutation) => ReactMutation<Mutation>;
24
44
  /**
25
45
  * Returns a function that invokes the provided `Ref`'s action.
26
46
  *
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AAQpC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAKxC,OAAO,KAAK,WAAW,MAAM,eAAe,CAAC;AAE7C,OAAO,EAAE,WAAW,EAAE,CAAC;AAEvB,MAAM,MAAM,YAAY,CAAC,IAAI,SAAS,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,SAAS;IACzE,KAAK;CACN,GACG,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,GAC1B,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAE/D,KAAK,YAAY,CAAC,KAAK,SAAS,GAAG,CAAC,cAAc,IAChD,MAAM,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,KAAK,GAC/B,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,MAAM,CAAC,GACjC,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,MAAM,CAAC,CAAC;AAEvC,eAAO,MAAM,QAAQ,GAAI,KAAK,SAAS,GAAG,CAAC,cAAc,EACvD,KAAK,KAAK,EACV,GAAG,MAAM,YAAY,CAAC,KAAK,CAAC,KAC3B,WAAW,CAAC,WAAW,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,CA4C9D,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,WAAW,GAAI,QAAQ,SAAS,GAAG,CAAC,iBAAiB,EAChE,KAAK,QAAQ,KACZ,CAAC,CAAC,GAAG,IAAI,EAAE,GAAG,CAAC,YAAY,CAAC,QAAQ,CAAC,KAAK,YAAY,CAAC,QAAQ,CAAC,CAelE,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,SAAS,GAAI,MAAM,SAAS,GAAG,CAAC,eAAe,EAC1D,KAAK,MAAM,KACV,CAAC,CAAC,GAAG,IAAI,EAAE,GAAG,CAAC,YAAY,CAAC,MAAM,CAAC,KAAK,YAAY,CAAC,MAAM,CAAC,CAe9D,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AAYpC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAKxC,OAAO,KAAK,oBAAoB,MAAM,wBAAwB,CAAC;AAC/D,OAAO,KAAK,WAAW,MAAM,eAAe,CAAC;AAE7C,OAAO,EAAE,oBAAoB,EAAE,WAAW,EAAE,CAAC;AAE7C,MAAM,MAAM,YAAY,CAAC,IAAI,SAAS,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,SAAS;IACzE,KAAK;CACN,GACG,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,GAC1B,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAE/D,KAAK,YAAY,CAAC,KAAK,SAAS,GAAG,CAAC,cAAc,IAChD,MAAM,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,KAAK,GAC/B,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,MAAM,CAAC,GACjC,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,MAAM,CAAC,CAAC;AAEvC,eAAO,MAAM,QAAQ,GAAI,KAAK,SAAS,GAAG,CAAC,cAAc,EACvD,KAAK,KAAK,EACV,GAAG,MAAM,YAAY,CAAC,KAAK,CAAC,KAC3B,WAAW,CAAC,WAAW,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,CA4C9D,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,gBAAgB,CAAC,QAAQ,SAAS,GAAG,CAAC,iBAAiB,IAAI,CACrE,UAAU,EAAE,oBAAoB,CAAC,oBAAoB,EACrD,IAAI,EAAE,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,KACrB,IAAI,CAAC;AAEV;;;;;GAKG;AACH,MAAM,WAAW,aAAa,CAAC,QAAQ,SAAS,GAAG,CAAC,iBAAiB;IACnE,CAAC,GAAG,IAAI,EAAE,GAAG,CAAC,YAAY,CAAC,QAAQ,CAAC,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;IAC9D,oBAAoB,CAClB,gBAAgB,EAAE,gBAAgB,CAAC,QAAQ,CAAC,GAC3C,aAAa,CAAC,QAAQ,CAAC,CAAC;CAC5B;AAsCD;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,WAAW,GAAI,QAAQ,SAAS,GAAG,CAAC,iBAAiB,EAChE,KAAK,QAAQ,KACZ,aAAa,CAAC,QAAQ,CAcxB,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,SAAS,GAAI,MAAM,SAAS,GAAG,CAAC,eAAe,EAC1D,KAAK,MAAM,KACV,CAAC,CAAC,GAAG,IAAI,EAAE,GAAG,CAAC,YAAY,CAAC,MAAM,CAAC,KAAK,YAAY,CAAC,MAAM,CAAC,CAe9D,CAAC"}
package/dist/index.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { OptimisticLocalStore_exports, make } from "./OptimisticLocalStore.js";
1
2
  import { QueryResult_exports, fail, load, succeed } from "./QueryResult.js";
2
3
  import { Ref } from "@confect/core";
3
4
  import { useAction as useAction$1, useMutation as useMutation$1, useQuery as useQuery$1 } from "convex/react";
@@ -30,8 +31,22 @@ const useQuery = (ref, ...rest) => {
30
31
  Either.merge(encodedReturnsOrError)
31
32
  ]);
32
33
  };
34
+ const makeReactMutation = (ref, convexReactMutation) => {
35
+ const callable = ((...args) => invokeAsEither(ref, (_, encodedArgs) => convexReactMutation(encodedArgs), args).then((either) => Ref.hasErrorSchema(ref) ? either : Either.getOrThrow(either)));
36
+ const withOptimisticUpdate = (optimisticUpdate) => {
37
+ const wrappedUpdate = (convexLocalStore, encodedArgs) => {
38
+ const decodedArgs = Ref.decodeArgsSync(ref, encodedArgs);
39
+ optimisticUpdate(make(convexLocalStore), decodedArgs);
40
+ };
41
+ return makeReactMutation(ref, convexReactMutation.withOptimisticUpdate(wrappedUpdate));
42
+ };
43
+ return Object.assign(callable, { withOptimisticUpdate });
44
+ };
33
45
  /**
34
- * Returns a function that invokes the provided `Ref`'s mutation.
46
+ * Returns a {@link ReactMutation} handle for the provided `Ref`'s mutation. The
47
+ * handle is callable to invoke the mutation, and exposes `withOptimisticUpdate`
48
+ * for attaching an optimistic update, mirroring `useMutation` from
49
+ * `convex/react`.
35
50
  *
36
51
  * If the `Ref` declares an `error` schema, the returned promise resolves to an
37
52
  * `Either` with the decoded `returns` value on the right and the decoded error
@@ -44,8 +59,8 @@ const useQuery = (ref, ...rest) => {
44
59
  * Any other failure rejects the promise.
45
60
  */
46
61
  const useMutation = (ref) => {
47
- const actualMutation = useMutation$1(Ref.getFunctionReference(ref));
48
- return useCallback(((...args) => invokeAsEither(ref, (_, encodedArgs) => actualMutation(encodedArgs), args).then((either) => Ref.hasErrorSchema(ref) ? either : Either.getOrThrow(either))), [ref, actualMutation]);
62
+ const convexReactMutation = useMutation$1(Ref.getFunctionReference(ref));
63
+ return useMemo(() => makeReactMutation(ref, convexReactMutation), [ref, convexReactMutation]);
49
64
  };
50
65
  /**
51
66
  * Returns a function that invokes the provided `Ref`'s action.
@@ -71,5 +86,5 @@ const invokeAsEither = async (ref, invoke, args) => {
71
86
  };
72
87
 
73
88
  //#endregion
74
- export { QueryResult_exports as QueryResult, useAction, useMutation, useQuery };
89
+ export { OptimisticLocalStore_exports as OptimisticLocalStore, QueryResult_exports as QueryResult, useAction, useMutation, useQuery };
75
90
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["useConvexQuery","QueryResult.load","QueryResult.succeed","QueryResult.fail","useConvexMutation","useConvexAction"],"sources":["../src/index.ts"],"sourcesContent":["import { Ref } from \"@confect/core\";\nimport {\n useAction as useConvexAction,\n useMutation as useConvexMutation,\n useQuery as useConvexQuery,\n} from \"convex/react\";\nimport * as Cause from \"effect/Cause\";\nimport * as Effect from \"effect/Effect\";\nimport * as Either from \"effect/Either\";\nimport * as Exit from \"effect/Exit\";\nimport * as Option from \"effect/Option\";\nimport { useCallback, useMemo } from \"react\";\n\nimport * as QueryResult from \"./QueryResult\";\n\nexport { QueryResult };\n\nexport type InvokeReturn<Ref_ extends Ref.Any> = [Ref.Error<Ref_>] extends [\n never,\n]\n ? Promise<Ref.Returns<Ref_>>\n : Promise<Either.Either<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 an `Either` 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: Either.Either<unknown, unknown> = Either.try(\n () => useConvexQuery(functionReference, encodedArgs),\n );\n\n return useMemo(\n () =>\n Either.match(encodedReturnsOrError, {\n onRight: (encodedReturnsOrUndefined) =>\n encodedReturnsOrUndefined === undefined\n ? QueryResult.load(skipped)\n : QueryResult.succeed(\n Ref.decodeReturnsSync(ref, encodedReturnsOrUndefined),\n ),\n onLeft: (error) => {\n if (Ref.isConvexError(error)) {\n const decoded = Ref.decodeErrorSync(ref, error.data);\n if (Option.isSome(decoded)) {\n return QueryResult.fail(decoded.value);\n }\n }\n throw error;\n },\n }),\n // `Either.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, Either.merge(encodedReturnsOrError)],\n );\n};\n\n/**\n * Returns a function that invokes the provided `Ref`'s mutation.\n *\n * If the `Ref` declares an `error` schema, the returned promise resolves to an\n * `Either` with the decoded `returns` value on the right and the decoded error\n * on the left.\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): ((...args: Ref.OptionalArgs<Mutation>) => InvokeReturn<Mutation>) => {\n const functionReference = Ref.getFunctionReference(ref);\n const actualMutation = useConvexMutation(functionReference);\n\n return useCallback(\n ((...args: Ref.OptionalArgs<Mutation>) =>\n invokeAsEither(\n ref,\n (_, encodedArgs) => actualMutation(encodedArgs),\n args,\n ).then((either) =>\n Ref.hasErrorSchema(ref) ? either : Either.getOrThrow(either),\n )) as (...args: Ref.OptionalArgs<Mutation>) => InvokeReturn<Mutation>,\n [ref, actualMutation],\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 an\n * `Either` with the decoded `returns` value on the right and the decoded error\n * on the left.\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 invokeAsEither(\n ref,\n (_, encodedArgs) => actualAction(encodedArgs),\n args,\n ).then((either) =>\n Ref.hasErrorSchema(ref) ? either : Either.getOrThrow(either),\n )) as (...args: Ref.OptionalArgs<Action>) => InvokeReturn<Action>,\n [ref, actualAction],\n );\n};\n\nconst invokeAsEither = 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<Either.Either<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(\"ParseError\", Effect.die),\n Effect.either,\n ),\n );\n if (Exit.isSuccess(exit)) return exit.value;\n throw Cause.squash(exit.cause);\n};\n"],"mappings":";;;;;;;;;;;AA4BA,MAAa,YACX,KACA,GAAG,SAC+D;CAClE,MAAM,oBAAoB,IAAI,qBAAqB,IAAI;CACvD,MAAM,OAAO,KAAK;CAClB,MAAM,UAAU,SAAS;CACzB,MAAM,cAAc,UAChB,SACA,IAAI,eAAe,KAAM,QAAQ,EAAE,CAAqB;CAS5D,MAAM,wBAAyD,OAAO,UAC9DA,WAAe,mBAAmB,YAAY,CACrD;AAED,QAAO,cAEH,OAAO,MAAM,uBAAuB;EAClC,UAAU,8BACR,8BAA8B,SAC1BC,KAAiB,QAAQ,GACzBC,QACE,IAAI,kBAAkB,KAAK,0BAA0B,CACtD;EACP,SAAS,UAAU;AACjB,OAAI,IAAI,cAAc,MAAM,EAAE;IAC5B,MAAM,UAAU,IAAI,gBAAgB,KAAK,MAAM,KAAK;AACpD,QAAI,OAAO,OAAO,QAAQ,CACxB,QAAOC,KAAiB,QAAQ,MAAM;;AAG1C,SAAM;;EAET,CAAC,EAKJ;EAAC;EAAK;EAAS,OAAO,MAAM,sBAAsB;EAAC,CACpD;;;;;;;;;;;;;;;AAgBH,MAAa,eACX,QACsE;CAEtE,MAAM,iBAAiBC,cADG,IAAI,qBAAqB,IAAI,CACI;AAE3D,QAAO,cACH,GAAG,SACH,eACE,MACC,GAAG,gBAAgB,eAAe,YAAY,EAC/C,KACD,CAAC,MAAM,WACN,IAAI,eAAe,IAAI,GAAG,SAAS,OAAO,WAAW,OAAO,CAC7D,GACH,CAAC,KAAK,eAAe,CACtB;;;;;;;;;;;;;;;AAgBH,MAAa,aACX,QACkE;CAElE,MAAM,eAAeC,YADK,IAAI,qBAAqB,IAAI,CACA;AAEvD,QAAO,cACH,GAAG,SACH,eACE,MACC,GAAG,gBAAgB,aAAa,YAAY,EAC7C,KACD,CAAC,MAAM,WACN,IAAI,eAAe,IAAI,GAAG,SAAS,OAAO,WAAW,OAAO,CAC7D,GACH,CAAC,KAAK,aAAa,CACpB;;AAGH,MAAM,iBAAiB,OACrB,KACA,QAIA,SAC+D;CAC/D,MAAM,OAAO,MAAM,OAAO,eACxB,IAAI,aAAa,KAAM,KAAK,MAAM,EAAE,EAAqB,OAAO,CAAC,KAC/D,OAAO,SAAS,cAAc,OAAO,IAAI,EACzC,OAAO,OACR,CACF;AACD,KAAI,KAAK,UAAU,KAAK,CAAE,QAAO,KAAK;AACtC,OAAM,MAAM,OAAO,KAAK,MAAM"}
1
+ {"version":3,"file":"index.js","names":["useConvexQuery","QueryResult.load","QueryResult.succeed","QueryResult.fail","OptimisticLocalStore.make","useConvexMutation","useConvexAction"],"sources":["../src/index.ts"],"sourcesContent":["import { Ref } from \"@confect/core\";\nimport type { OptimisticUpdate as ConvexOptimisticUpdate } from \"convex/browser\";\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 Either from \"effect/Either\";\nimport * as Exit from \"effect/Exit\";\nimport * as Option from \"effect/Option\";\nimport { useCallback, useMemo } from \"react\";\n\nimport * as OptimisticLocalStore from \"./OptimisticLocalStore\";\nimport * as QueryResult from \"./QueryResult\";\n\nexport { OptimisticLocalStore, QueryResult };\n\nexport type InvokeReturn<Ref_ extends Ref.Any> = [Ref.Error<Ref_>] extends [\n never,\n]\n ? Promise<Ref.Returns<Ref_>>\n : Promise<Either.Either<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 an `Either` 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: Either.Either<unknown, unknown> = Either.try(\n () => useConvexQuery(functionReference, encodedArgs),\n );\n\n return useMemo(\n () =>\n Either.match(encodedReturnsOrError, {\n onRight: (encodedReturnsOrUndefined) =>\n encodedReturnsOrUndefined === undefined\n ? QueryResult.load(skipped)\n : QueryResult.succeed(\n Ref.decodeReturnsSync(ref, encodedReturnsOrUndefined),\n ),\n onLeft: (error) => {\n if (Ref.isConvexError(error)) {\n const decoded = Ref.decodeErrorSync(ref, error.data);\n if (Option.isSome(decoded)) {\n return QueryResult.fail(decoded.value);\n }\n }\n throw error;\n },\n }),\n // `Either.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, Either.merge(encodedReturnsOrError)],\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 invokeAsEither(\n ref,\n (_, encodedArgs) => convexReactMutation(encodedArgs as never),\n args,\n ).then((either) =>\n Ref.hasErrorSchema(ref) ? either : Either.getOrThrow(either),\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 an\n * `Either` with the decoded `returns` value on the right and the decoded error\n * on the left.\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 an\n * `Either` with the decoded `returns` value on the right and the decoded error\n * on the left.\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 invokeAsEither(\n ref,\n (_, encodedArgs) => actualAction(encodedArgs),\n args,\n ).then((either) =>\n Ref.hasErrorSchema(ref) ? either : Either.getOrThrow(either),\n )) as (...args: Ref.OptionalArgs<Action>) => InvokeReturn<Action>,\n [ref, actualAction],\n );\n};\n\nconst invokeAsEither = 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<Either.Either<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(\"ParseError\", Effect.die),\n Effect.either,\n ),\n );\n if (Exit.isSuccess(exit)) return exit.value;\n throw Cause.squash(exit.cause);\n};\n"],"mappings":";;;;;;;;;;;;AAiCA,MAAa,YACX,KACA,GAAG,SAC+D;CAClE,MAAM,oBAAoB,IAAI,qBAAqB,IAAI;CACvD,MAAM,OAAO,KAAK;CAClB,MAAM,UAAU,SAAS;CACzB,MAAM,cAAc,UAChB,SACA,IAAI,eAAe,KAAM,QAAQ,EAAE,CAAqB;CAS5D,MAAM,wBAAyD,OAAO,UAC9DA,WAAe,mBAAmB,YAAY,CACrD;AAED,QAAO,cAEH,OAAO,MAAM,uBAAuB;EAClC,UAAU,8BACR,8BAA8B,SAC1BC,KAAiB,QAAQ,GACzBC,QACE,IAAI,kBAAkB,KAAK,0BAA0B,CACtD;EACP,SAAS,UAAU;AACjB,OAAI,IAAI,cAAc,MAAM,EAAE;IAC5B,MAAM,UAAU,IAAI,gBAAgB,KAAK,MAAM,KAAK;AACpD,QAAI,OAAO,OAAO,QAAQ,CACxB,QAAOC,KAAiB,QAAQ,MAAM;;AAG1C,SAAM;;EAET,CAAC,EAKJ;EAAC;EAAK;EAAS,OAAO,MAAM,sBAAsB;EAAC,CACpD;;AA0BH,MAAM,qBACJ,KACA,wBAG4B;CAC5B,MAAM,aAAa,GAAG,SACpB,eACE,MACC,GAAG,gBAAgB,oBAAoB,YAAqB,EAC7D,KACD,CAAC,MAAM,WACN,IAAI,eAAe,IAAI,GAAG,SAAS,OAAO,WAAW,OAAO,CAC7D;CAEH,MAAM,wBACJ,qBAC4B;EAC5B,MAAM,iBACJ,kBACA,gBACG;GACH,MAAM,cAAc,IAAI,eAAe,KAAK,YAAY;AACxD,oBACEC,KAA0B,iBAAiB,EAC3C,YACD;;AAIH,SAAO,kBAAkB,KADvB,oBAAoB,qBAAqB,cAAc,CACH;;AAGxD,QAAO,OAAO,OAAO,UAAU,EAAE,sBAAsB,CAAC;;;;;;;;;;;;;;;;;;AAmB1D,MAAa,eACX,QAC4B;CAE5B,MAAM,sBAAsBC,cADF,IAAI,qBAAqB,IAAI,CACS;AAEhE,QAAO,cAEH,kBACE,KACA,oBAGD,EACH,CAAC,KAAK,oBAAoB,CAC3B;;;;;;;;;;;;;;;AAgBH,MAAa,aACX,QACkE;CAElE,MAAM,eAAeC,YADK,IAAI,qBAAqB,IAAI,CACA;AAEvD,QAAO,cACH,GAAG,SACH,eACE,MACC,GAAG,gBAAgB,aAAa,YAAY,EAC7C,KACD,CAAC,MAAM,WACN,IAAI,eAAe,IAAI,GAAG,SAAS,OAAO,WAAW,OAAO,CAC7D,GACH,CAAC,KAAK,aAAa,CACpB;;AAGH,MAAM,iBAAiB,OACrB,KACA,QAIA,SAC+D;CAC/D,MAAM,OAAO,MAAM,OAAO,eACxB,IAAI,aAAa,KAAM,KAAK,MAAM,EAAE,EAAqB,OAAO,CAAC,KAC/D,OAAO,SAAS,cAAc,OAAO,IAAI,EACzC,OAAO,OACR,CACF;AACD,KAAI,KAAK,UAAU,KAAK,CAAE,QAAO,KAAK;AACtC,OAAM,MAAM,OAAO,KAAK,MAAM"}