@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/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": "9.2.3",
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.29.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": "3.21.2",
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": "^3.21.2",
58
+ "effect": "^4.0.0-beta.97",
59
59
  "react": "^18.0.0 || ^19.0.0",
60
- "@confect/core": "^9.2.3"
60
+ "@confect/core": "^10.0.0-next.0"
61
61
  },
62
62
  "repository": {
63
63
  "type": "git",
@@ -27,10 +27,10 @@ export declare namespace QueryResult {
27
27
  };
28
28
  }
29
29
 
30
- // eslint-disable-next-line @typescript-eslint/no-shadow
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
- // eslint-disable-next-line @typescript-eslint/no-shadow
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.cached(
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.cached(this, Hash.combine(tagHash)(Hash.hash(this.value)));
88
+ return Hash.combine(tagHash)(Hash.hash(this.value));
92
89
  case "Failure":
93
- return Hash.cached(this, Hash.combine(tagHash)(Hash.hash(this.error)));
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 Either from "effect/Either";
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<Either.Either<Ref.Returns<Ref_>, Ref.Error<Ref_>>>;
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 an `Either` and decode/wrap it inside
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: Either.Either<unknown, unknown> = Either.try(
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
- Either.match(encodedReturnsOrError, {
59
- onRight: (encodedReturnsOrUndefined) =>
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
- onLeft: (error) => {
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
- // `Either.try` allocates a fresh wrapper each render, so we key the memo on
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, Either.merge(encodedReturnsOrError)],
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
- invokeAsEither(
113
+ invokeAsResult(
114
114
  ref,
115
115
  (_, encodedArgs) => convexReactMutation(encodedArgs as never),
116
116
  args,
117
- ).then((either) =>
118
- Ref.hasErrorSchema(ref) ? either : Either.getOrThrow(either),
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 an
149
- * `Either` with the decoded `returns` value on the right and the decoded error
150
- * on the left.
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 an
180
- * `Either` with the decoded `returns` value on the right and the decoded error
181
- * on the left.
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
- invokeAsEither(
197
+ invokeAsResult(
198
198
  ref,
199
199
  (_, encodedArgs) => actualAction(encodedArgs),
200
200
  args,
201
- ).then((either) =>
202
- Ref.hasErrorSchema(ref) ? either : Either.getOrThrow(either),
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 invokeAsEither = async <Ref_ extends Ref.Any>(
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<Either.Either<Ref.Returns<Ref_>, Ref.Error<Ref_>>> => {
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("ParseError", Effect.die),
219
- Effect.either,
218
+ Effect.catchTag("SchemaError", Effect.die),
219
+ Effect.result,
220
220
  ),
221
221
  );
222
222
  if (Exit.isSuccess(exit)) return exit.value;