@confect/react 9.2.3 → 10.0.0-next.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 +15 -5
- package/dist/QueryResult.d.ts.map +1 -1
- package/dist/QueryResult.js +3 -3
- package/dist/QueryResult.js.map +1 -1
- package/dist/index.d.ts +8 -8
- package/dist/index.js +16 -16
- package/dist/index.js.map +1 -1
- package/dist/tsconfig.src.tsbuildinfo +1 -1
- package/package.json +5 -5
- package/src/QueryResult.ts +5 -8
- package/src/index.ts +25 -25
package/package.json
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@confect/react",
|
|
3
3
|
"description": "Client-side bindings for React apps",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "10.0.0-next.0",
|
|
5
5
|
"author": "RJ Dellecese",
|
|
6
6
|
"bugs": {
|
|
7
7
|
"url": "https://github.com/rjdellecese/confect/issues"
|
|
8
8
|
},
|
|
9
9
|
"devDependencies": {
|
|
10
|
-
"@effect/vitest": "0.
|
|
10
|
+
"@effect/vitest": "4.0.0-beta.97",
|
|
11
11
|
"@testing-library/react": "16.3.2",
|
|
12
12
|
"@types/node": "25.3.3",
|
|
13
13
|
"@types/react": "19.2.14",
|
|
14
14
|
"@types/react-dom": "19.2.3",
|
|
15
15
|
"convex": "1.40.0",
|
|
16
|
-
"effect": "
|
|
16
|
+
"effect": "4.0.0-beta.97",
|
|
17
17
|
"happy-dom": "15.11.7",
|
|
18
18
|
"react": "19.2.4",
|
|
19
19
|
"react-dom": "19.2.4",
|
|
@@ -55,9 +55,9 @@
|
|
|
55
55
|
"module": "./dist/index.js",
|
|
56
56
|
"peerDependencies": {
|
|
57
57
|
"convex": "^1.32.0",
|
|
58
|
-
"effect": "^
|
|
58
|
+
"effect": "^4.0.0-beta.97",
|
|
59
59
|
"react": "^18.0.0 || ^19.0.0",
|
|
60
|
-
"@confect/core": "^
|
|
60
|
+
"@confect/core": "^10.0.0-next.0"
|
|
61
61
|
},
|
|
62
62
|
"repository": {
|
|
63
63
|
"type": "git",
|
package/src/QueryResult.ts
CHANGED
|
@@ -27,10 +27,10 @@ export declare namespace QueryResult {
|
|
|
27
27
|
};
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
//
|
|
30
|
+
// oxlint-disable-next-line no-shadow
|
|
31
31
|
export type Success<R> = R extends QueryResult<infer A, infer _E> ? A : never;
|
|
32
32
|
|
|
33
|
-
//
|
|
33
|
+
// oxlint-disable-next-line no-shadow
|
|
34
34
|
export type Failure<R> = R extends QueryResult<infer _A, infer E> ? E : never;
|
|
35
35
|
}
|
|
36
36
|
|
|
@@ -83,14 +83,11 @@ const QueryResultProto = {
|
|
|
83
83
|
const tagHash = Hash.string(this._tag);
|
|
84
84
|
switch (this._tag) {
|
|
85
85
|
case "Loading":
|
|
86
|
-
return Hash.
|
|
87
|
-
this,
|
|
88
|
-
Hash.combine(tagHash)(Hash.hash(this.skipped)),
|
|
89
|
-
);
|
|
86
|
+
return Hash.combine(tagHash)(Hash.hash(this.skipped));
|
|
90
87
|
case "Success":
|
|
91
|
-
return Hash.
|
|
88
|
+
return Hash.combine(tagHash)(Hash.hash(this.value));
|
|
92
89
|
case "Failure":
|
|
93
|
-
return Hash.
|
|
90
|
+
return Hash.combine(tagHash)(Hash.hash(this.error));
|
|
94
91
|
}
|
|
95
92
|
},
|
|
96
93
|
};
|
package/src/index.ts
CHANGED
|
@@ -10,7 +10,7 @@ import type { FunctionReference } from "convex/server";
|
|
|
10
10
|
import type { Value } from "convex/values";
|
|
11
11
|
import * as Cause from "effect/Cause";
|
|
12
12
|
import * as Effect from "effect/Effect";
|
|
13
|
-
import * as
|
|
13
|
+
import * as Result from "effect/Result";
|
|
14
14
|
import * as Exit from "effect/Exit";
|
|
15
15
|
import * as Option from "effect/Option";
|
|
16
16
|
import { useCallback, useMemo } from "react";
|
|
@@ -24,7 +24,7 @@ export type InvokeReturn<Ref_ extends Ref.Any> = [Ref.Error<Ref_>] extends [
|
|
|
24
24
|
never,
|
|
25
25
|
]
|
|
26
26
|
? Promise<Ref.Returns<Ref_>>
|
|
27
|
-
: Promise<
|
|
27
|
+
: Promise<Result.Result<Ref.Returns<Ref_>, Ref.Error<Ref_>>>;
|
|
28
28
|
|
|
29
29
|
type UseQueryArgs<Query extends Ref.AnyPublicQuery> =
|
|
30
30
|
keyof Ref.Args<Query> extends never
|
|
@@ -44,25 +44,25 @@ export const useQuery = <Query extends Ref.AnyPublicQuery>(
|
|
|
44
44
|
|
|
45
45
|
// `useConvexQuery` returns a referentially stable value while the underlying
|
|
46
46
|
// Convex result is unchanged, and throws a stable error when the query
|
|
47
|
-
// fails. We capture either outcome as
|
|
47
|
+
// fails. We capture either outcome as a `Result` and decode/wrap it inside
|
|
48
48
|
// `useMemo` so that the returned `QueryResult` keeps a stable identity across
|
|
49
49
|
// renders when nothing has actually changed. Decoding on every render would
|
|
50
50
|
// hand consumers a fresh object each time, breaking effects and memoization
|
|
51
51
|
// that depend on the result's identity.
|
|
52
|
-
const encodedReturnsOrError:
|
|
52
|
+
const encodedReturnsOrError: Result.Result<unknown, unknown> = Result.try(
|
|
53
53
|
() => useConvexQuery(functionReference, encodedArgs),
|
|
54
54
|
);
|
|
55
55
|
|
|
56
56
|
return useMemo(
|
|
57
57
|
() =>
|
|
58
|
-
|
|
59
|
-
|
|
58
|
+
Result.match(encodedReturnsOrError, {
|
|
59
|
+
onSuccess: (encodedReturnsOrUndefined) =>
|
|
60
60
|
encodedReturnsOrUndefined === undefined
|
|
61
61
|
? QueryResult.load(skipped)
|
|
62
62
|
: QueryResult.succeed(
|
|
63
63
|
Ref.decodeReturnsSync(ref, encodedReturnsOrUndefined),
|
|
64
64
|
),
|
|
65
|
-
|
|
65
|
+
onFailure: (error) => {
|
|
66
66
|
if (Ref.isConvexError(error)) {
|
|
67
67
|
const decoded = Ref.decodeErrorSync(ref, error.data);
|
|
68
68
|
if (Option.isSome(decoded)) {
|
|
@@ -72,11 +72,11 @@ export const useQuery = <Query extends Ref.AnyPublicQuery>(
|
|
|
72
72
|
throw error;
|
|
73
73
|
},
|
|
74
74
|
}),
|
|
75
|
-
// `
|
|
75
|
+
// `Result.try` allocates a fresh wrapper each render, so we key the memo on
|
|
76
76
|
// the stable value it carries (the Convex result or thrown error) rather
|
|
77
77
|
// than the wrapper itself; the decoded result is a function of that value,
|
|
78
78
|
// `ref`, and `skipped`.
|
|
79
|
-
[ref, skipped,
|
|
79
|
+
[ref, skipped, Result.merge(encodedReturnsOrError)],
|
|
80
80
|
);
|
|
81
81
|
};
|
|
82
82
|
|
|
@@ -110,12 +110,12 @@ const makeReactMutation = <Mutation extends Ref.AnyPublicMutation>(
|
|
|
110
110
|
>,
|
|
111
111
|
): ReactMutation<Mutation> => {
|
|
112
112
|
const callable = ((...args: Ref.OptionalArgs<Mutation>) =>
|
|
113
|
-
|
|
113
|
+
invokeAsResult(
|
|
114
114
|
ref,
|
|
115
115
|
(_, encodedArgs) => convexReactMutation(encodedArgs as never),
|
|
116
116
|
args,
|
|
117
|
-
).then((
|
|
118
|
-
Ref.hasErrorSchema(ref) ?
|
|
117
|
+
).then((result) =>
|
|
118
|
+
Ref.hasErrorSchema(ref) ? result : Result.getOrThrow(result),
|
|
119
119
|
)) as (...args: Ref.OptionalArgs<Mutation>) => InvokeReturn<Mutation>;
|
|
120
120
|
|
|
121
121
|
const withOptimisticUpdate = (
|
|
@@ -145,9 +145,9 @@ const makeReactMutation = <Mutation extends Ref.AnyPublicMutation>(
|
|
|
145
145
|
* for attaching an optimistic update, mirroring `useMutation` from
|
|
146
146
|
* `convex/react`.
|
|
147
147
|
*
|
|
148
|
-
* If the `Ref` declares an `error` schema, the returned promise resolves to
|
|
149
|
-
* `
|
|
150
|
-
*
|
|
148
|
+
* If the `Ref` declares an `error` schema, the returned promise resolves to a
|
|
149
|
+
* `Result` with the decoded `returns` value in the `Success` and the decoded
|
|
150
|
+
* error in the `Failure`.
|
|
151
151
|
*
|
|
152
152
|
* If the `Ref` does not declare an `error` schema, the promise resolves
|
|
153
153
|
* directly to the decoded `returns` value, matching the behavior of
|
|
@@ -176,9 +176,9 @@ export const useMutation = <Mutation extends Ref.AnyPublicMutation>(
|
|
|
176
176
|
/**
|
|
177
177
|
* Returns a function that invokes the provided `Ref`'s action.
|
|
178
178
|
*
|
|
179
|
-
* If the `Ref` declares an `error` schema, the returned promise resolves to
|
|
180
|
-
* `
|
|
181
|
-
*
|
|
179
|
+
* If the `Ref` declares an `error` schema, the returned promise resolves to a
|
|
180
|
+
* `Result` with the decoded `returns` value in the `Success` and the decoded
|
|
181
|
+
* error in the `Failure`.
|
|
182
182
|
*
|
|
183
183
|
* If the `Ref` does not declare an `error` schema, the promise resolves
|
|
184
184
|
* directly to the decoded `returns` value, matching the behavior of
|
|
@@ -194,29 +194,29 @@ export const useAction = <Action extends Ref.AnyPublicAction>(
|
|
|
194
194
|
|
|
195
195
|
return useCallback(
|
|
196
196
|
((...args: Ref.OptionalArgs<Action>) =>
|
|
197
|
-
|
|
197
|
+
invokeAsResult(
|
|
198
198
|
ref,
|
|
199
199
|
(_, encodedArgs) => actualAction(encodedArgs),
|
|
200
200
|
args,
|
|
201
|
-
).then((
|
|
202
|
-
Ref.hasErrorSchema(ref) ?
|
|
201
|
+
).then((result) =>
|
|
202
|
+
Ref.hasErrorSchema(ref) ? result : Result.getOrThrow(result),
|
|
203
203
|
)) as (...args: Ref.OptionalArgs<Action>) => InvokeReturn<Action>,
|
|
204
204
|
[ref, actualAction],
|
|
205
205
|
);
|
|
206
206
|
};
|
|
207
207
|
|
|
208
|
-
const
|
|
208
|
+
const invokeAsResult = async <Ref_ extends Ref.Any>(
|
|
209
209
|
ref: Ref_,
|
|
210
210
|
invoke: (
|
|
211
211
|
fnRef: Ref.FunctionReference<Ref_>,
|
|
212
212
|
encodedArgs: unknown,
|
|
213
213
|
) => PromiseLike<unknown>,
|
|
214
214
|
args: Ref.OptionalArgs<Ref_>,
|
|
215
|
-
): Promise<
|
|
215
|
+
): Promise<Result.Result<Ref.Returns<Ref_>, Ref.Error<Ref_>>> => {
|
|
216
216
|
const exit = await Effect.runPromiseExit(
|
|
217
217
|
Ref.runWithCodec(ref, (args[0] ?? {}) as Ref.Args<Ref_>, invoke).pipe(
|
|
218
|
-
Effect.catchTag("
|
|
219
|
-
Effect.
|
|
218
|
+
Effect.catchTag("SchemaError", Effect.die),
|
|
219
|
+
Effect.result,
|
|
220
220
|
),
|
|
221
221
|
);
|
|
222
222
|
if (Exit.isSuccess(exit)) return exit.value;
|