@confect/react 9.0.1 → 9.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +24 -13
- package/dist/OptimisticLocalStore.d.ts +25 -0
- package/dist/OptimisticLocalStore.d.ts.map +1 -0
- package/dist/OptimisticLocalStore.js +39 -0
- package/dist/OptimisticLocalStore.js.map +1 -0
- package/dist/index.d.ts +23 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +19 -4
- package/dist/index.js.map +1 -1
- package/dist/tsconfig.src.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/src/OptimisticLocalStore.ts +70 -0
- package/src/index.ts +79 -13
package/CHANGELOG.md
CHANGED
|
@@ -1,11 +1,27 @@
|
|
|
1
1
|
# @confect/react
|
|
2
2
|
|
|
3
|
+
## 9.1.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 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.
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- Updated dependencies [4d8a568]
|
|
12
|
+
- @confect/core@9.1.0
|
|
13
|
+
|
|
14
|
+
## 9.0.2
|
|
15
|
+
|
|
16
|
+
### Patch Changes
|
|
17
|
+
|
|
18
|
+
- @confect/core@9.0.2
|
|
19
|
+
|
|
3
20
|
## 9.0.1
|
|
4
21
|
|
|
5
22
|
### Patch Changes
|
|
6
23
|
|
|
7
24
|
- 445ea9b: Loosen and align dependency ranges across all packages:
|
|
8
|
-
|
|
9
25
|
- The `convex` peer dependency is now `^1.32.0` in every package (previously pinned exactly to `1.39.1`, or `^1.30.0` in `@confect/react`). The range is validated against convex 1.32.0 through 1.40.0.
|
|
10
26
|
- `@confect/server`'s `@effect/platform-node` peer dependency is now optional — it is only needed when using the `@confect/server/node` entrypoint.
|
|
11
27
|
- `@confect/cli` now uses caret ranges for its `@effect/platform` and `@effect/platform-node` dependencies so they can deduplicate with the versions resolved for `@confect/server`, and no longer declares an unused direct dependency on `@effect/platform-node-shared`.
|
|
@@ -25,7 +41,6 @@
|
|
|
25
41
|
### Filesystem-driven groups
|
|
26
42
|
|
|
27
43
|
Your API is now authored as colocated `*.spec.ts`/`*.impl.ts` pairs, one pair per group, and **the file's path within `confect/` is the group's name** (its stem for top-level groups, the dot-joined directory path for nested groups). `GroupSpec.make()` and `GroupSpec.makeNode()` no longer take a name argument.
|
|
28
|
-
|
|
29
44
|
- Each `*.spec.ts` `export default`s its `GroupSpec` (named co-exports like error classes are still allowed).
|
|
30
45
|
- Each `*.impl.ts` default-imports its sibling spec, passes it to `FunctionImpl.make` / `GroupImpl.make`, and ends the layer pipeline with `GroupImpl.finalize`—a compile-time completeness check that only typechecks once every function the spec declares has a `FunctionImpl` provided.
|
|
31
46
|
- The root `confect/spec.ts`, `confect/impl.ts`, `confect/nodeSpec.ts`, and `confect/nodeImpl.ts` files are gone, along with `Impl.make` and `Impl.finalize`. `confect codegen` deletes any of these (and the stale aggregate `_generated/registeredFunctions.ts` / `_generated/nodeRegisteredFunctions.ts`) on upgrade.
|
|
@@ -45,12 +60,11 @@
|
|
|
45
60
|
Schema.Struct({
|
|
46
61
|
userId: Schema.optional(Id("users")),
|
|
47
62
|
text: Schema.String,
|
|
48
|
-
})
|
|
63
|
+
}),
|
|
49
64
|
);
|
|
50
65
|
```
|
|
51
66
|
|
|
52
67
|
Codegen emits, alongside it:
|
|
53
|
-
|
|
54
68
|
- `_generated/schema.ts`—the runtime `DatabaseSchema`. Never imports `convex/server`, so a runtime cold start no longer evaluates `defineSchema(...)`.
|
|
55
69
|
- `_generated/convexSchema.ts`—the Convex deploy `SchemaDefinition`, re-exported from `convex/schema.ts`.
|
|
56
70
|
- `_generated/id.ts`—a type-safe `Id` constructor whose argument is constrained to your table names. Use `Id("notes")` everywhere you previously wrote `GenericId.GenericId("notes")`; cross-table `_id` typos are now caught at compile time.
|
|
@@ -70,7 +84,7 @@
|
|
|
70
84
|
name: "list",
|
|
71
85
|
args: Schema.Struct({}),
|
|
72
86
|
returns: Schema.Array(Notes.Doc),
|
|
73
|
-
})
|
|
87
|
+
}),
|
|
74
88
|
);
|
|
75
89
|
```
|
|
76
90
|
|
|
@@ -89,7 +103,7 @@
|
|
|
89
103
|
name: "list",
|
|
90
104
|
args: () => Schema.Struct({}),
|
|
91
105
|
returns: () => Schema.Array(notes.Doc),
|
|
92
|
-
})
|
|
106
|
+
}),
|
|
93
107
|
);
|
|
94
108
|
```
|
|
95
109
|
|
|
@@ -100,14 +114,13 @@
|
|
|
100
114
|
const list = FunctionImpl.make(databaseSchema, notes, "list", handler);
|
|
101
115
|
export default GroupImpl.make(databaseSchema, notes).pipe(
|
|
102
116
|
Layer.provide(list),
|
|
103
|
-
GroupImpl.finalize
|
|
117
|
+
GroupImpl.finalize,
|
|
104
118
|
);
|
|
105
119
|
```
|
|
106
120
|
|
|
107
121
|
### Node functions are first-class
|
|
108
122
|
|
|
109
123
|
A group's runtime is now declared solely by its spec—`GroupSpec.makeNode()` for a Node action group, `GroupSpec.make()` otherwise—mirroring vanilla Convex's per-file `"use node"` directive. The separate `node` namespace is gone: Node specs/impls are ordinary colocated pairs that can live anywhere in `confect/`, and codegen emits the `"use node"` directive based on the spec.
|
|
110
|
-
|
|
111
124
|
- A Node group at `confect/email.spec.ts` is now reached at `refs.public.email.send` instead of `refs.public.node.email.send`.
|
|
112
125
|
- `@confect/core` removes `Spec.makeNode`, `Spec.merge`, and `Spec.isConvexSpec` / `Spec.isNodeSpec`; `Spec.make()` is a single mixed-runtime container and `Refs.make(spec)` takes one argument. `GroupSpec.makeNode()`, `FunctionSpec.publicNodeAction()` / `internalNodeAction()` are unchanged.
|
|
113
126
|
|
|
@@ -124,7 +137,6 @@
|
|
|
124
137
|
The codegen bundler now uses [`bundle-require`](https://github.com/egoist/bundle-require), so impls may import third-party packages and use `tsconfig.json` `paths` aliases (`~/*`, `@/*`, …) for their own source. A parent `confect/{path}.spec.ts` may now declare functions alongside a sibling `confect/{path}/` subdirectory of further specs, and codegen reports a clear error on a name collision between the two.
|
|
125
138
|
|
|
126
139
|
### Migration
|
|
127
|
-
|
|
128
140
|
1. **Tables.** Delete `confect/schema.ts`. Rename each table file to a valid JS identifier (e.g. `confect/tables/notes.ts`); the basename becomes the table name. Drop the name argument from `Table.make`, wrap the field struct in `() =>`, and replace `GenericId.GenericId("x")` with `Id("x")` from `_generated/id`. If you read `table.name` off a bound table, rename it to `table.tableName`.
|
|
129
141
|
2. **Specs.** Split each group into a colocated `*.spec.ts` that `export default`s `GroupSpec.make()` (no name). Wrap every `args`/`returns`/`error` in `() =>`. Import a table's `Doc`/`Fields` from its wrapper, `import notes from "./_generated/tables/notes"`.
|
|
130
142
|
3. **Impls.** In each `*.impl.ts`, default-import the sibling spec, import `databaseSchema` from `_generated/schema`, pass it to `FunctionImpl.make` / `GroupImpl.make` in place of `api`, end the pipeline with `GroupImpl.finalize`, and `export default` it. Delete the root `confect/spec.ts`, `impl.ts`, `nodeSpec.ts`, and `nodeImpl.ts` (codegen will also remove them).
|
|
@@ -288,7 +300,7 @@
|
|
|
288
300
|
|
|
289
301
|
export class NoteNotFound extends Schema.TaggedError<NoteNotFound>()(
|
|
290
302
|
"NoteNotFound",
|
|
291
|
-
{ noteId: GenericId.GenericId("notes") }
|
|
303
|
+
{ noteId: GenericId.GenericId("notes") },
|
|
292
304
|
) {}
|
|
293
305
|
|
|
294
306
|
export const notes = GroupSpec.make("notes").addFunction(
|
|
@@ -297,7 +309,7 @@
|
|
|
297
309
|
args: Schema.Struct({ noteId: GenericId.GenericId("notes") }),
|
|
298
310
|
returns: Notes.Doc,
|
|
299
311
|
error: NoteNotFound,
|
|
300
|
-
})
|
|
312
|
+
}),
|
|
301
313
|
);
|
|
302
314
|
```
|
|
303
315
|
|
|
@@ -317,7 +329,7 @@
|
|
|
317
329
|
.table("notes")
|
|
318
330
|
.get(noteId)
|
|
319
331
|
.pipe(Effect.mapError(() => new NoteNotFound({ noteId })));
|
|
320
|
-
})
|
|
332
|
+
}),
|
|
321
333
|
);
|
|
322
334
|
```
|
|
323
335
|
|
|
@@ -389,7 +401,6 @@
|
|
|
389
401
|
Unspecified failures continue to reject the promise.
|
|
390
402
|
|
|
391
403
|
### Migration
|
|
392
|
-
|
|
393
404
|
- For each `useQuery` call site, replace `result === undefined` checks and direct property access with `QueryResult.match` (or the lower-level `QueryResult.isLoading`/`isSuccess`/`isFailure` predicates).
|
|
394
405
|
- For each `useMutation`/`useAction` call site whose ref now declares an `error` schema, unwrap the resolved `Either` (e.g. with `Either.match`); call sites against refs without an `error` schema need no change.
|
|
395
406
|
|
|
@@ -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
|
-
*
|
|
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) =>
|
|
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
|
*
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,eAAe,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
|
|
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
|
|
48
|
-
return
|
|
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"}
|