@confect/js 5.0.0 → 7.0.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 CHANGED
@@ -1,5 +1,141 @@
1
1
  # @confect/js
2
2
 
3
+ ## 7.0.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 90094d0: Add typed errors to Confect functions (queries, mutations, and actions). Declare an optional `error` schema in `FunctionSpec` and recover it as a typed value at every call site—`useQuery`, `useMutation`, `useAction`, `HttpClient`, `WebSocketClient`, and `TestConfect`—without paying for it on functions that don't fail.
8
+
9
+ Typed errors travel across the function boundary as Convex's native [`ConvexError`](https://docs.convex.dev/functions/error-handling/application-errors#throwing-application-errors): the encoded error sits in `ConvexError.data`, leaving the `returns` channel unsullied and preserving native Convex semantics for non-Confect callers of the same API.
10
+
11
+ ### Authoring a function with typed errors
12
+
13
+ `FunctionSpec` constructors now accept an optional `error` schema. To support multiple error shapes, combine them with `Schema.Union`.
14
+
15
+ ```ts
16
+ import { FunctionSpec, GenericId, GroupSpec } from "@confect/core";
17
+ import { Schema } from "effect";
18
+
19
+ export class NoteNotFound extends Schema.TaggedError<NoteNotFound>()(
20
+ "NoteNotFound",
21
+ { noteId: GenericId.GenericId("notes") },
22
+ ) {}
23
+
24
+ export const notes = GroupSpec.make("notes").addFunction(
25
+ FunctionSpec.publicQuery({
26
+ name: "getOrFail",
27
+ args: Schema.Struct({ noteId: GenericId.GenericId("notes") }),
28
+ returns: Notes.Doc,
29
+ error: NoteNotFound,
30
+ }),
31
+ );
32
+ ```
33
+
34
+ The `FunctionImpl` for that ref can now `Effect.fail` (or `mapError` to) any value matching the declared schema. Whichever invocation path the caller takes—`useQuery`/`useMutation`/`useAction`, `HttpClient`, `WebSocketClient`, or `TestConfect`—Confect encodes the failure, transports it via `ConvexError`, and surfaces the decoded value in the appropriate channel for that call site.
35
+
36
+ ```ts
37
+ import { FunctionImpl } from "@confect/server";
38
+ import { Effect } from "effect";
39
+ import api from "../_generated/api";
40
+ import { DatabaseReader } from "../_generated/services";
41
+ import { NoteNotFound } from "./notes.spec";
42
+
43
+ const getOrFail = FunctionImpl.make(api, "notes", "getOrFail", ({ noteId }) =>
44
+ Effect.gen(function* () {
45
+ const reader = yield* DatabaseReader;
46
+ return yield* reader
47
+ .table("notes")
48
+ .get(noteId)
49
+ .pipe(Effect.mapError(() => new NoteNotFound({ noteId })));
50
+ }),
51
+ );
52
+ ```
53
+
54
+ ### Consuming a typed error
55
+
56
+ `@confect/js` (`HttpClient`, `WebSocketClient`) and `@confect/test` (`TestConfect`) surface the decoded error in the `Effect` error channel alongside the existing `HttpClientError`/`WebSocketClientError`/`ParseError`:
57
+
58
+ ```ts
59
+ HttpClient.query(refs.public.notes.getOrFail, { noteId });
60
+ // Effect.Effect<Note, NoteNotFound | HttpClientError | ParseError>
61
+ ```
62
+
63
+ ### `@confect/react`—breaking changes
64
+
65
+ `useQuery`, `useMutation`, and `useAction` now expose typed errors, and `useQuery` returns a tagged result type instead of `Returns | undefined`.
66
+
67
+ **`useQuery` now returns `QueryResult<A, E>`.** Loading and (when an `error` schema is declared) failure are reified as variants alongside success. Match on the result with `QueryResult.match`:
68
+
69
+ Before:
70
+
71
+ ```tsx
72
+ const notes = useQuery(refs.public.notes.list, {});
73
+ if (notes === undefined) return <p>Loading…</p>;
74
+ return <NoteList notes={notes} />;
75
+ ```
76
+
77
+ After:
78
+
79
+ ```tsx
80
+ import { QueryResult, useQuery } from "@confect/react";
81
+
82
+ const notes = useQuery(refs.public.notes.list, {});
83
+ return QueryResult.match(notes, {
84
+ onLoading: (skipped) => (skipped ? null : <p>Loading…</p>),
85
+ onSuccess: (notes) => <NoteList notes={notes} />,
86
+ });
87
+ ```
88
+
89
+ The `Loading` variant carries a `skipped: boolean` flag, exposed as the argument to `onLoading`. It distinguishes a query that is genuinely in flight (`skipped: false`) from one that is sitting idle because `"skip"` was passed as its args (`skipped: true`)—a distinction `convex/react`'s plain `undefined` return value cannot make. Use it to render a loading indicator only when work is actually happening, and an empty/placeholder state otherwise.
90
+
91
+ When the ref declares an `error` schema, `onFailure` becomes required and receives the decoded typed error:
92
+
93
+ ```tsx
94
+ const lookup = useQuery(refs.public.notes.getOrFail, { noteId });
95
+ QueryResult.match(lookup, {
96
+ onLoading: (skipped) => (skipped ? null : "Looking up…"),
97
+ onSuccess: (note) => `Found: ${note.text}`,
98
+ onFailure: (error) => `Note ${error.noteId} not found.`,
99
+ });
100
+ ```
101
+
102
+ `QueryResult` is a Confect-native type exported from `@confect/react`.
103
+
104
+ **`useMutation` and `useAction` return `Promise<Either<A, E>>` when the ref declares an `error` schema.** Refs without an `error` schema continue to resolve to `Promise<A>`, matching the prior shape and `convex/react`'s behavior.
105
+
106
+ ```ts
107
+ const deleteOrFail = useMutation(refs.public.notes.deleteOrFail);
108
+ const result = await deleteOrFail({ noteId });
109
+ // Either.Either<null, NoteNotFound | Forbidden>
110
+ Either.match(result, {
111
+ onLeft: (error) => /* typed error */,
112
+ onRight: (value) => /* success */,
113
+ });
114
+
115
+ const deleteNote = useMutation(refs.public.notes.delete_); // no `error` schema
116
+ await deleteNote({ noteId }); // Promise<null>, as before
117
+ ```
118
+
119
+ Unspecified failures continue to reject the promise.
120
+
121
+ ### Migration
122
+ - 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).
123
+ - 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.
124
+
125
+ ### Patch Changes
126
+
127
+ - Updated dependencies [90094d0]
128
+ - @confect/core@7.0.0
129
+
130
+ ## 6.0.0
131
+
132
+ ### Patch Changes
133
+
134
+ - df95ce7: Add `Ref.OptionalArgs` type utility to `@confect/core` for conditionally optional function args. `QueryRunner`, `MutationRunner`, and `ActionRunner` now accept optional args for no-arg Confect functions. `useQuery`, `useMutation`, and `useAction` now accept optional args for no-arg Confect functions. `TestConfect` `query`/`mutation`/`action` helpers now accept optional args for no-arg Confect functions.
135
+ - Updated dependencies [df95ce7]
136
+ - Updated dependencies [a8083e8]
137
+ - @confect/core@6.0.0
138
+
3
139
  ## 5.0.0
4
140
 
5
141
  ### Minor Changes
@@ -12,7 +12,6 @@ declare const HttpClientError_base: Schema.TaggedErrorClass<HttpClientError, "Ht
12
12
  cause: typeof Schema.Unknown;
13
13
  }>;
14
14
  declare class HttpClientError extends HttpClientError_base {}
15
- type OptionalArgs<R extends Ref.AnyPublicQuery | Ref.AnyPublicMutation | Ref.AnyPublicAction> = keyof Ref.Args<R> extends never ? [args?: Ref.Args<R>] : [args: Ref.Args<R>];
16
15
  /**
17
16
  * A Confect client which uses HTTP to communicate with your Convex backend. Works in any JS runtime that supports `fetch`. Wraps [ConvexHttpClient](https://docs.convex.dev/api/classes/browser.ConvexHttpClient).
18
17
  */
@@ -20,25 +19,25 @@ declare const HttpClient: Context.Tag<{
20
19
  url: string;
21
20
  setAuth: (token: string) => Effect.Effect<void, never, never>;
22
21
  clearAuth: Effect.Effect<void, never, never>;
23
- query: <Query extends Ref.AnyPublicQuery>(ref: Query, ...rest: OptionalArgs<Query>) => Effect.Effect<Ref.Returns<Query>, HttpClientError | ParseResult.ParseError>;
24
- mutation: <Mutation extends Ref.AnyPublicMutation>(ref: Mutation, ...rest: OptionalArgs<Mutation>) => Effect.Effect<Ref.Returns<Mutation>, HttpClientError | ParseResult.ParseError>;
25
- action: <Action extends Ref.AnyPublicAction>(ref: Action, ...rest: OptionalArgs<Action>) => Effect.Effect<Ref.Returns<Action>, HttpClientError | ParseResult.ParseError>;
22
+ query: <Query extends Ref.AnyPublicQuery>(ref: Query, ...rest: Ref.OptionalArgs<Query>) => Effect.Effect<Ref.Returns<Query>, Ref.Error<Query> | HttpClientError | ParseResult.ParseError>;
23
+ mutation: <Mutation extends Ref.AnyPublicMutation>(ref: Mutation, ...rest: Ref.OptionalArgs<Mutation>) => Effect.Effect<Ref.Returns<Mutation>, Ref.Error<Mutation> | HttpClientError | ParseResult.ParseError>;
24
+ action: <Action extends Ref.AnyPublicAction>(ref: Action, ...rest: Ref.OptionalArgs<Action>) => Effect.Effect<Ref.Returns<Action>, Ref.Error<Action> | HttpClientError | ParseResult.ParseError>;
26
25
  }, {
27
26
  url: string;
28
27
  setAuth: (token: string) => Effect.Effect<void, never, never>;
29
28
  clearAuth: Effect.Effect<void, never, never>;
30
- query: <Query extends Ref.AnyPublicQuery>(ref: Query, ...rest: OptionalArgs<Query>) => Effect.Effect<Ref.Returns<Query>, HttpClientError | ParseResult.ParseError>;
31
- mutation: <Mutation extends Ref.AnyPublicMutation>(ref: Mutation, ...rest: OptionalArgs<Mutation>) => Effect.Effect<Ref.Returns<Mutation>, HttpClientError | ParseResult.ParseError>;
32
- action: <Action extends Ref.AnyPublicAction>(ref: Action, ...rest: OptionalArgs<Action>) => Effect.Effect<Ref.Returns<Action>, HttpClientError | ParseResult.ParseError>;
29
+ query: <Query extends Ref.AnyPublicQuery>(ref: Query, ...rest: Ref.OptionalArgs<Query>) => Effect.Effect<Ref.Returns<Query>, Ref.Error<Query> | HttpClientError | ParseResult.ParseError>;
30
+ mutation: <Mutation extends Ref.AnyPublicMutation>(ref: Mutation, ...rest: Ref.OptionalArgs<Mutation>) => Effect.Effect<Ref.Returns<Mutation>, Ref.Error<Mutation> | HttpClientError | ParseResult.ParseError>;
31
+ action: <Action extends Ref.AnyPublicAction>(ref: Action, ...rest: Ref.OptionalArgs<Action>) => Effect.Effect<Ref.Returns<Action>, Ref.Error<Action> | HttpClientError | ParseResult.ParseError>;
33
32
  }>;
34
33
  type HttpClient = typeof HttpClient.Identifier;
35
34
  declare const layer: (address: string, options?: ConstructorParameters<typeof ConvexHttpClient>[1]) => Layer.Layer<{
36
35
  url: string;
37
36
  setAuth: (token: string) => Effect.Effect<void, never, never>;
38
37
  clearAuth: Effect.Effect<void, never, never>;
39
- query: <Query extends Ref.AnyPublicQuery>(ref: Query, ...rest: OptionalArgs<Query>) => Effect.Effect<Ref.Returns<Query>, HttpClientError | ParseResult.ParseError>;
40
- mutation: <Mutation extends Ref.AnyPublicMutation>(ref: Mutation, ...rest: OptionalArgs<Mutation>) => Effect.Effect<Ref.Returns<Mutation>, HttpClientError | ParseResult.ParseError>;
41
- action: <Action extends Ref.AnyPublicAction>(ref: Action, ...rest: OptionalArgs<Action>) => Effect.Effect<Ref.Returns<Action>, HttpClientError | ParseResult.ParseError>;
38
+ query: <Query extends Ref.AnyPublicQuery>(ref: Query, ...rest: Ref.OptionalArgs<Query>) => Effect.Effect<Ref.Returns<Query>, Ref.Error<Query> | HttpClientError | ParseResult.ParseError>;
39
+ mutation: <Mutation extends Ref.AnyPublicMutation>(ref: Mutation, ...rest: Ref.OptionalArgs<Mutation>) => Effect.Effect<Ref.Returns<Mutation>, Ref.Error<Mutation> | HttpClientError | ParseResult.ParseError>;
40
+ action: <Action extends Ref.AnyPublicAction>(ref: Action, ...rest: Ref.OptionalArgs<Action>) => Effect.Effect<Ref.Returns<Action>, Ref.Error<Action> | HttpClientError | ParseResult.ParseError>;
42
41
  }, never, never>;
43
42
  //#endregion
44
43
  export { HttpClient_d_exports };
@@ -1 +1 @@
1
- {"version":3,"file":"HttpClient.d.ts","names":[],"sources":["../src/HttpClient.ts"],"mappings":";;;;;;;;cAGwD,oBAAA;;;;;cAE3C,eAAA,SAAwB,oBAAA;AAAA,KAOhC,YAAA,WACO,GAAA,CAAI,cAAA,GAAiB,GAAA,CAAI,iBAAA,GAAoB,GAAA,CAAI,eAAA,UACnD,GAAA,CAAI,IAAA,CAAK,CAAA,mBACd,IAAA,GAAO,GAAA,CAAI,IAAA,CAAK,CAAA,MAChB,IAAA,EAAM,GAAA,CAAI,IAAA,CAAK,CAAA;;;;cAgFP,UAAA,EAAU,OAAA,CAAA,GAAA;;8BAtES,MAAA,CAAA,MAAA;;wBASD,GAAA,CAAI,cAAA,EAAc,GAAA,EACxC,KAAA,KAAK,IAAA,EACD,YAAA,CAAa,KAAA,MACrB,MAAA,CAAO,MAAA,CACR,GAAA,CAAI,OAAA,CAAQ,KAAA,GACZ,eAAA,GAAkB,WAAA,CAAY,UAAA;8BAWG,GAAA,CAAI,iBAAA,EAAiB,GAAA,EACjD,QAAA,KAAQ,IAAA,EACJ,YAAA,CAAa,QAAA,MACrB,MAAA,CAAO,MAAA,CACR,GAAA,CAAI,OAAA,CAAQ,QAAA,GACZ,eAAA,GAAkB,WAAA,CAAY,UAAA;0BAWD,GAAA,CAAI,eAAA,EAAe,GAAA,EAC3C,MAAA,KAAM,IAAA,EACF,YAAA,CAAa,MAAA,MACrB,MAAA,CAAO,MAAA,CACR,GAAA,CAAI,OAAA,CAAQ,MAAA,GACZ,eAAA,GAAkB,WAAA,CAAY,UAAA;AAAA;;8BA9CF,MAAA,CAAA,MAAA;;wBASD,GAAA,CAAI,cAAA,EAAc,GAAA,EACxC,KAAA,KAAK,IAAA,EACD,YAAA,CAAa,KAAA,MACrB,MAAA,CAAO,MAAA,CACR,GAAA,CAAI,OAAA,CAAQ,KAAA,GACZ,eAAA,GAAkB,WAAA,CAAY,UAAA;8BAWG,GAAA,CAAI,iBAAA,EAAiB,GAAA,EACjD,QAAA,KAAQ,IAAA,EACJ,YAAA,CAAa,QAAA,MACrB,MAAA,CAAO,MAAA,CACR,GAAA,CAAI,OAAA,CAAQ,QAAA,GACZ,eAAA,GAAkB,WAAA,CAAY,UAAA;0BAWD,GAAA,CAAI,eAAA,EAAe,GAAA,EAC3C,MAAA,KAAM,IAAA,EACF,YAAA,CAAa,MAAA,MACrB,MAAA,CAAO,MAAA,CACR,GAAA,CAAI,OAAA,CAAQ,MAAA,GACZ,eAAA,GAAkB,WAAA,CAAY,UAAA;AAAA;AAAA,KA4BtB,UAAA,UAAoB,UAAA,CAAW,UAAA;AAAA,cAE9B,KAAA,GACX,OAAA,UACA,OAAA,GAAU,qBAAA,QAA6B,gBAAA,SAAoB,KAAA,CAAA,KAAA;;8BA9E7B,MAAA,CAAA,MAAA;;wBASD,GAAA,CAAI,cAAA,EAAc,GAAA,EACxC,KAAA,KAAK,IAAA,EACD,YAAA,CAAa,KAAA,MACrB,MAAA,CAAO,MAAA,CACR,GAAA,CAAI,OAAA,CAAQ,KAAA,GACZ,eAAA,GAAkB,WAAA,CAAY,UAAA;8BAWG,GAAA,CAAI,iBAAA,EAAiB,GAAA,EACjD,QAAA,KAAQ,IAAA,EACJ,YAAA,CAAa,QAAA,MACrB,MAAA,CAAO,MAAA,CACR,GAAA,CAAI,OAAA,CAAQ,QAAA,GACZ,eAAA,GAAkB,WAAA,CAAY,UAAA;0BAWD,GAAA,CAAI,eAAA,EAAe,GAAA,EAC3C,MAAA,KAAM,IAAA,EACF,YAAA,CAAa,MAAA,MACrB,MAAA,CAAO,MAAA,CACR,GAAA,CAAI,OAAA,CAAQ,MAAA,GACZ,eAAA,GAAkB,WAAA,CAAY,UAAA;AAAA"}
1
+ {"version":3,"file":"HttpClient.d.ts","names":[],"sources":["../src/HttpClient.ts"],"mappings":"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"}
@@ -19,26 +19,18 @@ const make = (address, options) => {
19
19
  const clearAuth = Effect.sync(() => {
20
20
  client.clearAuth();
21
21
  });
22
+ const mapUnknownError = (cause) => new HttpClientError({ cause });
22
23
  const query = (ref, ...rest) => {
23
24
  const args = rest[0] ?? {};
24
- return Ref.runWithCodec(ref, args, (functionReference, encodedArgs) => Effect.tryPromise({
25
- try: () => client.query(functionReference, encodedArgs),
26
- catch: (cause) => new HttpClientError({ cause })
27
- }));
25
+ return Ref.runWithCodec(ref, args, (functionReference, encodedArgs) => client.query(functionReference, encodedArgs), mapUnknownError);
28
26
  };
29
27
  const mutation = (ref, ...rest) => {
30
28
  const args = rest[0] ?? {};
31
- return Ref.runWithCodec(ref, args, (functionReference, encodedArgs) => Effect.tryPromise({
32
- try: () => client.mutation(functionReference, encodedArgs),
33
- catch: (cause) => new HttpClientError({ cause })
34
- }));
29
+ return Ref.runWithCodec(ref, args, (functionReference, encodedArgs) => client.mutation(functionReference, encodedArgs), mapUnknownError);
35
30
  };
36
31
  const action = (ref, ...rest) => {
37
32
  const args = rest[0] ?? {};
38
- return Ref.runWithCodec(ref, args, (functionReference, encodedArgs) => Effect.tryPromise({
39
- try: () => client.action(functionReference, encodedArgs),
40
- catch: (cause) => new HttpClientError({ cause })
41
- }));
33
+ return Ref.runWithCodec(ref, args, (functionReference, encodedArgs) => client.action(functionReference, encodedArgs), mapUnknownError);
42
34
  };
43
35
  return {
44
36
  url,
@@ -1 +1 @@
1
- {"version":3,"file":"HttpClient.js","names":[],"sources":["../src/HttpClient.ts"],"sourcesContent":["import * as Ref from \"@confect/core/Ref\";\nimport { ConvexHttpClient } from \"convex/browser\";\nimport type { ParseResult } from \"effect\";\nimport { Context, Effect, Layer, Schema } from \"effect\";\n\nexport class HttpClientError extends Schema.TaggedError<HttpClientError>()(\n \"HttpClientError\",\n {\n cause: Schema.Unknown,\n },\n) {}\n\ntype OptionalArgs<\n R extends Ref.AnyPublicQuery | Ref.AnyPublicMutation | Ref.AnyPublicAction,\n> = keyof Ref.Args<R> extends never\n ? [args?: Ref.Args<R>]\n : [args: Ref.Args<R>];\n\nconst make = (\n address: string,\n options?: ConstructorParameters<typeof ConvexHttpClient>[1],\n) => {\n const client = new ConvexHttpClient(address, options);\n\n const url = client.url;\n\n const setAuth = (token: string) =>\n Effect.sync(() => {\n client.setAuth(token);\n });\n\n const clearAuth = Effect.sync(() => {\n client.clearAuth();\n });\n\n const query = <Query extends Ref.AnyPublicQuery>(\n ref: Query,\n ...rest: OptionalArgs<Query>\n ): Effect.Effect<\n Ref.Returns<Query>,\n HttpClientError | ParseResult.ParseError\n > => {\n const args = (rest[0] ?? {}) as Ref.Args<Query>;\n return Ref.runWithCodec(ref, args, (functionReference, encodedArgs) =>\n Effect.tryPromise({\n try: () => client.query(functionReference, encodedArgs),\n catch: (cause) => new HttpClientError({ cause }),\n }),\n );\n };\n\n const mutation = <Mutation extends Ref.AnyPublicMutation>(\n ref: Mutation,\n ...rest: OptionalArgs<Mutation>\n ): Effect.Effect<\n Ref.Returns<Mutation>,\n HttpClientError | ParseResult.ParseError\n > => {\n const args = (rest[0] ?? {}) as Ref.Args<Mutation>;\n return Ref.runWithCodec(ref, args, (functionReference, encodedArgs) =>\n Effect.tryPromise({\n try: () => client.mutation(functionReference, encodedArgs),\n catch: (cause) => new HttpClientError({ cause }),\n }),\n );\n };\n\n const action = <Action extends Ref.AnyPublicAction>(\n ref: Action,\n ...rest: OptionalArgs<Action>\n ): Effect.Effect<\n Ref.Returns<Action>,\n HttpClientError | ParseResult.ParseError\n > => {\n const args = (rest[0] ?? {}) as Ref.Args<Action>;\n return Ref.runWithCodec(ref, args, (functionReference, encodedArgs) =>\n Effect.tryPromise({\n try: () => client.action(functionReference, encodedArgs),\n catch: (cause) => new HttpClientError({ cause }),\n }),\n );\n };\n\n return {\n url,\n setAuth,\n clearAuth,\n query,\n mutation,\n action,\n };\n};\n\n/**\n * A Confect client which uses HTTP to communicate with your Convex backend. Works in any JS runtime that supports `fetch`. Wraps [ConvexHttpClient](https://docs.convex.dev/api/classes/browser.ConvexHttpClient).\n */\nexport const HttpClient = Context.GenericTag<ReturnType<typeof make>>(\n \"@confect/js/HttpClient\",\n);\n\nexport type HttpClient = typeof HttpClient.Identifier;\n\nexport const layer = (\n address: string,\n options?: ConstructorParameters<typeof ConvexHttpClient>[1],\n) => Layer.sync(HttpClient, () => make(address, options));\n"],"mappings":";;;;;;;;;;;AAKA,IAAa,kBAAb,cAAqC,OAAO,aAA8B,CACxE,mBACA,EACE,OAAO,OAAO,SACf,CACF,CAAC;AAQF,MAAM,QACJ,SACA,YACG;CACH,MAAM,SAAS,IAAI,iBAAiB,SAAS,QAAQ;CAErD,MAAM,MAAM,OAAO;CAEnB,MAAM,WAAW,UACf,OAAO,WAAW;AAChB,SAAO,QAAQ,MAAM;GACrB;CAEJ,MAAM,YAAY,OAAO,WAAW;AAClC,SAAO,WAAW;GAClB;CAEF,MAAM,SACJ,KACA,GAAG,SAIA;EACH,MAAM,OAAQ,KAAK,MAAM,EAAE;AAC3B,SAAO,IAAI,aAAa,KAAK,OAAO,mBAAmB,gBACrD,OAAO,WAAW;GAChB,WAAW,OAAO,MAAM,mBAAmB,YAAY;GACvD,QAAQ,UAAU,IAAI,gBAAgB,EAAE,OAAO,CAAC;GACjD,CAAC,CACH;;CAGH,MAAM,YACJ,KACA,GAAG,SAIA;EACH,MAAM,OAAQ,KAAK,MAAM,EAAE;AAC3B,SAAO,IAAI,aAAa,KAAK,OAAO,mBAAmB,gBACrD,OAAO,WAAW;GAChB,WAAW,OAAO,SAAS,mBAAmB,YAAY;GAC1D,QAAQ,UAAU,IAAI,gBAAgB,EAAE,OAAO,CAAC;GACjD,CAAC,CACH;;CAGH,MAAM,UACJ,KACA,GAAG,SAIA;EACH,MAAM,OAAQ,KAAK,MAAM,EAAE;AAC3B,SAAO,IAAI,aAAa,KAAK,OAAO,mBAAmB,gBACrD,OAAO,WAAW;GAChB,WAAW,OAAO,OAAO,mBAAmB,YAAY;GACxD,QAAQ,UAAU,IAAI,gBAAgB,EAAE,OAAO,CAAC;GACjD,CAAC,CACH;;AAGH,QAAO;EACL;EACA;EACA;EACA;EACA;EACA;EACD;;;;;AAMH,MAAa,aAAa,QAAQ,WAChC,yBACD;AAID,MAAa,SACX,SACA,YACG,MAAM,KAAK,kBAAkB,KAAK,SAAS,QAAQ,CAAC"}
1
+ {"version":3,"file":"HttpClient.js","names":[],"sources":["../src/HttpClient.ts"],"sourcesContent":["import * as Ref from \"@confect/core/Ref\";\nimport { ConvexHttpClient } from \"convex/browser\";\nimport type { ParseResult } from \"effect\";\nimport { Context, Effect, Layer, Schema } from \"effect\";\n\nexport class HttpClientError extends Schema.TaggedError<HttpClientError>()(\n \"HttpClientError\",\n {\n cause: Schema.Unknown,\n },\n) {}\n\nconst make = (\n address: string,\n options?: ConstructorParameters<typeof ConvexHttpClient>[1],\n) => {\n const client = new ConvexHttpClient(address, options);\n\n const url = client.url;\n\n const setAuth = (token: string) =>\n Effect.sync(() => {\n client.setAuth(token);\n });\n\n const clearAuth = Effect.sync(() => {\n client.clearAuth();\n });\n\n const mapUnknownError = (cause: unknown) => new HttpClientError({ cause });\n\n const query = <Query extends Ref.AnyPublicQuery>(\n ref: Query,\n ...rest: Ref.OptionalArgs<Query>\n ): Effect.Effect<\n Ref.Returns<Query>,\n Ref.Error<Query> | HttpClientError | ParseResult.ParseError\n > => {\n const args = (rest[0] ?? {}) as Ref.Args<Query>;\n return Ref.runWithCodec(\n ref,\n args,\n (functionReference, encodedArgs) =>\n client.query(functionReference, encodedArgs),\n mapUnknownError,\n );\n };\n\n const mutation = <Mutation extends Ref.AnyPublicMutation>(\n ref: Mutation,\n ...rest: Ref.OptionalArgs<Mutation>\n ): Effect.Effect<\n Ref.Returns<Mutation>,\n Ref.Error<Mutation> | HttpClientError | ParseResult.ParseError\n > => {\n const args = (rest[0] ?? {}) as Ref.Args<Mutation>;\n return Ref.runWithCodec(\n ref,\n args,\n (functionReference, encodedArgs) =>\n client.mutation(functionReference, encodedArgs),\n mapUnknownError,\n );\n };\n\n const action = <Action extends Ref.AnyPublicAction>(\n ref: Action,\n ...rest: Ref.OptionalArgs<Action>\n ): Effect.Effect<\n Ref.Returns<Action>,\n Ref.Error<Action> | HttpClientError | ParseResult.ParseError\n > => {\n const args = (rest[0] ?? {}) as Ref.Args<Action>;\n return Ref.runWithCodec(\n ref,\n args,\n (functionReference, encodedArgs) =>\n client.action(functionReference, encodedArgs),\n mapUnknownError,\n );\n };\n\n return {\n url,\n setAuth,\n clearAuth,\n query,\n mutation,\n action,\n };\n};\n\n/**\n * A Confect client which uses HTTP to communicate with your Convex backend. Works in any JS runtime that supports `fetch`. Wraps [ConvexHttpClient](https://docs.convex.dev/api/classes/browser.ConvexHttpClient).\n */\nexport const HttpClient = Context.GenericTag<ReturnType<typeof make>>(\n \"@confect/js/HttpClient\",\n);\n\nexport type HttpClient = typeof HttpClient.Identifier;\n\nexport const layer = (\n address: string,\n options?: ConstructorParameters<typeof ConvexHttpClient>[1],\n) => Layer.sync(HttpClient, () => make(address, options));\n"],"mappings":";;;;;;;;;;;AAKA,IAAa,kBAAb,cAAqC,OAAO,aAA8B,CACxE,mBACA,EACE,OAAO,OAAO,SACf,CACF,CAAC;AAEF,MAAM,QACJ,SACA,YACG;CACH,MAAM,SAAS,IAAI,iBAAiB,SAAS,QAAQ;CAErD,MAAM,MAAM,OAAO;CAEnB,MAAM,WAAW,UACf,OAAO,WAAW;AAChB,SAAO,QAAQ,MAAM;GACrB;CAEJ,MAAM,YAAY,OAAO,WAAW;AAClC,SAAO,WAAW;GAClB;CAEF,MAAM,mBAAmB,UAAmB,IAAI,gBAAgB,EAAE,OAAO,CAAC;CAE1E,MAAM,SACJ,KACA,GAAG,SAIA;EACH,MAAM,OAAQ,KAAK,MAAM,EAAE;AAC3B,SAAO,IAAI,aACT,KACA,OACC,mBAAmB,gBAClB,OAAO,MAAM,mBAAmB,YAAY,EAC9C,gBACD;;CAGH,MAAM,YACJ,KACA,GAAG,SAIA;EACH,MAAM,OAAQ,KAAK,MAAM,EAAE;AAC3B,SAAO,IAAI,aACT,KACA,OACC,mBAAmB,gBAClB,OAAO,SAAS,mBAAmB,YAAY,EACjD,gBACD;;CAGH,MAAM,UACJ,KACA,GAAG,SAIA;EACH,MAAM,OAAQ,KAAK,MAAM,EAAE;AAC3B,SAAO,IAAI,aACT,KACA,OACC,mBAAmB,gBAClB,OAAO,OAAO,mBAAmB,YAAY,EAC/C,gBACD;;AAGH,QAAO;EACL;EACA;EACA;EACA;EACA;EACA;EACD;;;;;AAMH,MAAa,aAAa,QAAQ,WAChC,yBACD;AAID,MAAa,SACX,SACA,YACG,MAAM,KAAK,kBAAkB,KAAK,SAAS,QAAQ,CAAC"}
@@ -12,7 +12,6 @@ declare const WebSocketClientError_base: Schema.TaggedErrorClass<WebSocketClient
12
12
  cause: typeof Schema.Unknown;
13
13
  }>;
14
14
  declare class WebSocketClientError extends WebSocketClientError_base {}
15
- type OptionalArgs<R extends Ref.AnyPublicQuery | Ref.AnyPublicMutation | Ref.AnyPublicAction> = keyof Ref.Args<R> extends never ? [args?: Ref.Args<R>] : [args: Ref.Args<R>];
16
15
  /**
17
16
  * A Confect client which uses a WebSocket to communicate with your Convex backend and supports reactive query subscriptions. The WebSocket connection is managed by the layer's scope and closed automatically when the scope ends. Wraps [ConvexClient](https://docs.convex.dev/api/classes/browser.ConvexClient).
18
17
  */
@@ -21,19 +20,19 @@ declare const WebSocketClient: Context.Tag<{
21
20
  setAuth: (fetchToken: (args: {
22
21
  forceRefreshToken: boolean;
23
22
  }) => Effect.Effect<string | null | undefined>, onChange?: (isAuthenticated: boolean) => Effect.Effect<void>) => Effect.Effect<void, never, never>;
24
- query: <Query extends Ref.AnyPublicQuery>(ref: Query, ...rest: OptionalArgs<Query>) => Effect.Effect<Ref.Returns<Query>, WebSocketClientError | ParseResult.ParseError>;
25
- mutation: <Mutation extends Ref.AnyPublicMutation>(ref: Mutation, ...rest: OptionalArgs<Mutation>) => Effect.Effect<Ref.Returns<Mutation>, WebSocketClientError | ParseResult.ParseError>;
26
- action: <Action extends Ref.AnyPublicAction>(ref: Action, ...rest: OptionalArgs<Action>) => Effect.Effect<Ref.Returns<Action>, WebSocketClientError | ParseResult.ParseError>;
27
- reactiveQuery: <Query extends Ref.AnyPublicQuery>(ref: Query, ...rest: OptionalArgs<Query>) => Stream.Stream<Ref.Returns<Query>, WebSocketClientError | ParseResult.ParseError>;
23
+ query: <Query extends Ref.AnyPublicQuery>(ref: Query, ...rest: Ref.OptionalArgs<Query>) => Effect.Effect<Ref.Returns<Query>, Ref.Error<Query> | WebSocketClientError | ParseResult.ParseError>;
24
+ mutation: <Mutation extends Ref.AnyPublicMutation>(ref: Mutation, ...rest: Ref.OptionalArgs<Mutation>) => Effect.Effect<Ref.Returns<Mutation>, Ref.Error<Mutation> | WebSocketClientError | ParseResult.ParseError>;
25
+ action: <Action extends Ref.AnyPublicAction>(ref: Action, ...rest: Ref.OptionalArgs<Action>) => Effect.Effect<Ref.Returns<Action>, Ref.Error<Action> | WebSocketClientError | ParseResult.ParseError>;
26
+ reactiveQuery: <Query extends Ref.AnyPublicQuery>(ref: Query, ...rest: Ref.OptionalArgs<Query>) => Stream.Stream<Ref.Returns<Query>, Ref.Error<Query> | WebSocketClientError | ParseResult.ParseError>;
28
27
  }, {
29
28
  url: string;
30
29
  setAuth: (fetchToken: (args: {
31
30
  forceRefreshToken: boolean;
32
31
  }) => Effect.Effect<string | null | undefined>, onChange?: (isAuthenticated: boolean) => Effect.Effect<void>) => Effect.Effect<void, never, never>;
33
- query: <Query extends Ref.AnyPublicQuery>(ref: Query, ...rest: OptionalArgs<Query>) => Effect.Effect<Ref.Returns<Query>, WebSocketClientError | ParseResult.ParseError>;
34
- mutation: <Mutation extends Ref.AnyPublicMutation>(ref: Mutation, ...rest: OptionalArgs<Mutation>) => Effect.Effect<Ref.Returns<Mutation>, WebSocketClientError | ParseResult.ParseError>;
35
- action: <Action extends Ref.AnyPublicAction>(ref: Action, ...rest: OptionalArgs<Action>) => Effect.Effect<Ref.Returns<Action>, WebSocketClientError | ParseResult.ParseError>;
36
- reactiveQuery: <Query extends Ref.AnyPublicQuery>(ref: Query, ...rest: OptionalArgs<Query>) => Stream.Stream<Ref.Returns<Query>, WebSocketClientError | ParseResult.ParseError>;
32
+ query: <Query extends Ref.AnyPublicQuery>(ref: Query, ...rest: Ref.OptionalArgs<Query>) => Effect.Effect<Ref.Returns<Query>, Ref.Error<Query> | WebSocketClientError | ParseResult.ParseError>;
33
+ mutation: <Mutation extends Ref.AnyPublicMutation>(ref: Mutation, ...rest: Ref.OptionalArgs<Mutation>) => Effect.Effect<Ref.Returns<Mutation>, Ref.Error<Mutation> | WebSocketClientError | ParseResult.ParseError>;
34
+ action: <Action extends Ref.AnyPublicAction>(ref: Action, ...rest: Ref.OptionalArgs<Action>) => Effect.Effect<Ref.Returns<Action>, Ref.Error<Action> | WebSocketClientError | ParseResult.ParseError>;
35
+ reactiveQuery: <Query extends Ref.AnyPublicQuery>(ref: Query, ...rest: Ref.OptionalArgs<Query>) => Stream.Stream<Ref.Returns<Query>, Ref.Error<Query> | WebSocketClientError | ParseResult.ParseError>;
37
36
  }>;
38
37
  type WebSocketClient = typeof WebSocketClient.Identifier;
39
38
  declare const layer: (address: string, options?: ConstructorParameters<typeof ConvexClient>[1]) => Layer.Layer<{
@@ -41,10 +40,10 @@ declare const layer: (address: string, options?: ConstructorParameters<typeof Co
41
40
  setAuth: (fetchToken: (args: {
42
41
  forceRefreshToken: boolean;
43
42
  }) => Effect.Effect<string | null | undefined>, onChange?: (isAuthenticated: boolean) => Effect.Effect<void>) => Effect.Effect<void, never, never>;
44
- query: <Query extends Ref.AnyPublicQuery>(ref: Query, ...rest: OptionalArgs<Query>) => Effect.Effect<Ref.Returns<Query>, WebSocketClientError | ParseResult.ParseError>;
45
- mutation: <Mutation extends Ref.AnyPublicMutation>(ref: Mutation, ...rest: OptionalArgs<Mutation>) => Effect.Effect<Ref.Returns<Mutation>, WebSocketClientError | ParseResult.ParseError>;
46
- action: <Action extends Ref.AnyPublicAction>(ref: Action, ...rest: OptionalArgs<Action>) => Effect.Effect<Ref.Returns<Action>, WebSocketClientError | ParseResult.ParseError>;
47
- reactiveQuery: <Query extends Ref.AnyPublicQuery>(ref: Query, ...rest: OptionalArgs<Query>) => Stream.Stream<Ref.Returns<Query>, WebSocketClientError | ParseResult.ParseError>;
43
+ query: <Query extends Ref.AnyPublicQuery>(ref: Query, ...rest: Ref.OptionalArgs<Query>) => Effect.Effect<Ref.Returns<Query>, Ref.Error<Query> | WebSocketClientError | ParseResult.ParseError>;
44
+ mutation: <Mutation extends Ref.AnyPublicMutation>(ref: Mutation, ...rest: Ref.OptionalArgs<Mutation>) => Effect.Effect<Ref.Returns<Mutation>, Ref.Error<Mutation> | WebSocketClientError | ParseResult.ParseError>;
45
+ action: <Action extends Ref.AnyPublicAction>(ref: Action, ...rest: Ref.OptionalArgs<Action>) => Effect.Effect<Ref.Returns<Action>, Ref.Error<Action> | WebSocketClientError | ParseResult.ParseError>;
46
+ reactiveQuery: <Query extends Ref.AnyPublicQuery>(ref: Query, ...rest: Ref.OptionalArgs<Query>) => Stream.Stream<Ref.Returns<Query>, Ref.Error<Query> | WebSocketClientError | ParseResult.ParseError>;
48
47
  }, never, never>;
49
48
  //#endregion
50
49
  export { WebSocketClient_d_exports };
@@ -1 +1 @@
1
- {"version":3,"file":"WebSocketClient.d.ts","names":[],"sources":["../src/WebSocketClient.ts"],"mappings":"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"}
1
+ {"version":3,"file":"WebSocketClient.d.ts","names":[],"sources":["../src/WebSocketClient.ts"],"mappings":"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"}
@@ -15,37 +15,30 @@ const make = (address, options) => Effect.acquireRelease(Effect.sync(() => new C
15
15
  const setAuth = (fetchToken, onChange) => Effect.sync(() => {
16
16
  convexClient.setAuth((args) => Effect.runPromise(fetchToken(args)), ...onChange ? [(isAuthenticated) => Effect.runFork(onChange(isAuthenticated))] : []);
17
17
  });
18
+ const mapUnknownError = (cause) => new WebSocketClientError({ cause });
18
19
  const query = (ref, ...rest) => {
19
20
  const args = rest[0] ?? {};
20
- return Ref.runWithCodec(ref, args, (functionReference, encodedArgs) => Effect.tryPromise({
21
- try: () => convexClient.query(functionReference, encodedArgs),
22
- catch: (cause) => new WebSocketClientError({ cause })
23
- }));
21
+ return Ref.runWithCodec(ref, args, (functionReference, encodedArgs) => convexClient.query(functionReference, encodedArgs), mapUnknownError);
24
22
  };
25
23
  const mutation = (ref, ...rest) => {
26
24
  const args = rest[0] ?? {};
27
- return Ref.runWithCodec(ref, args, (functionReference, encodedArgs) => Effect.tryPromise({
28
- try: () => convexClient.mutation(functionReference, encodedArgs),
29
- catch: (cause) => new WebSocketClientError({ cause })
30
- }));
25
+ return Ref.runWithCodec(ref, args, (functionReference, encodedArgs) => convexClient.mutation(functionReference, encodedArgs), mapUnknownError);
31
26
  };
32
27
  const action = (ref, ...rest) => {
33
28
  const args = rest[0] ?? {};
34
- return Ref.runWithCodec(ref, args, (functionReference, encodedArgs) => Effect.tryPromise({
35
- try: () => convexClient.action(functionReference, encodedArgs),
36
- catch: (cause) => new WebSocketClientError({ cause })
37
- }));
29
+ return Ref.runWithCodec(ref, args, (functionReference, encodedArgs) => convexClient.action(functionReference, encodedArgs), mapUnknownError);
38
30
  };
39
31
  const reactiveQuery = (ref, ...rest) => {
40
32
  const args = rest[0] ?? {};
41
33
  const functionReference = Ref.getFunctionReference(ref);
34
+ const onError = Ref.decodeErrorOrElse(ref, mapUnknownError);
42
35
  return Stream.unwrapScoped(Effect.gen(function* () {
43
36
  const encodedArgs = yield* Ref.encodeArgs(ref, args);
44
37
  return Stream.asyncScoped((emit) => Effect.gen(function* () {
45
38
  const unsubscribe = convexClient.onUpdate(functionReference, encodedArgs, (result) => {
46
39
  emit.single(result);
47
40
  }, (error) => {
48
- emit.fail(new WebSocketClientError({ cause: error }));
41
+ emit.fail(onError(error));
49
42
  });
50
43
  yield* Effect.addFinalizer(() => Effect.sync(() => unsubscribe()));
51
44
  }));
@@ -1 +1 @@
1
- {"version":3,"file":"WebSocketClient.js","names":[],"sources":["../src/WebSocketClient.ts"],"sourcesContent":["import * as Ref from \"@confect/core/Ref\";\nimport { ConvexClient } from \"convex/browser\";\nimport type { ParseResult } from \"effect\";\nimport { Context, Effect, Layer, Schema, Stream } from \"effect\";\n\nexport class WebSocketClientError extends Schema.TaggedError<WebSocketClientError>()(\n \"WebSocketClientError\",\n {\n cause: Schema.Unknown,\n },\n) {}\n\ntype OptionalArgs<\n R extends Ref.AnyPublicQuery | Ref.AnyPublicMutation | Ref.AnyPublicAction,\n> = keyof Ref.Args<R> extends never\n ? [args?: Ref.Args<R>]\n : [args: Ref.Args<R>];\n\nconst make = (\n address: string,\n options?: ConstructorParameters<typeof ConvexClient>[1],\n) =>\n Effect.acquireRelease(\n Effect.sync(() => new ConvexClient(address, options)),\n (convexClient) => Effect.promise(() => convexClient.close()),\n ).pipe(\n Effect.map((convexClient) => {\n const url = address;\n\n const setAuth = (\n fetchToken: (args: {\n forceRefreshToken: boolean;\n }) => Effect.Effect<string | null | undefined>,\n onChange?: (isAuthenticated: boolean) => Effect.Effect<void>,\n ) =>\n Effect.sync(() => {\n convexClient.setAuth(\n (args) => Effect.runPromise(fetchToken(args)),\n ...(onChange\n ? [\n (isAuthenticated: boolean) =>\n Effect.runFork(onChange(isAuthenticated)),\n ]\n : []),\n );\n });\n\n const query = <Query extends Ref.AnyPublicQuery>(\n ref: Query,\n ...rest: OptionalArgs<Query>\n ): Effect.Effect<\n Ref.Returns<Query>,\n WebSocketClientError | ParseResult.ParseError\n > => {\n const args = (rest[0] ?? {}) as Ref.Args<Query>;\n return Ref.runWithCodec(ref, args, (functionReference, encodedArgs) =>\n Effect.tryPromise({\n try: () => convexClient.query(functionReference, encodedArgs),\n catch: (cause) => new WebSocketClientError({ cause }),\n }),\n );\n };\n\n const mutation = <Mutation extends Ref.AnyPublicMutation>(\n ref: Mutation,\n ...rest: OptionalArgs<Mutation>\n ): Effect.Effect<\n Ref.Returns<Mutation>,\n WebSocketClientError | ParseResult.ParseError\n > => {\n const args = (rest[0] ?? {}) as Ref.Args<Mutation>;\n return Ref.runWithCodec(ref, args, (functionReference, encodedArgs) =>\n Effect.tryPromise({\n try: () => convexClient.mutation(functionReference, encodedArgs),\n catch: (cause) => new WebSocketClientError({ cause }),\n }),\n );\n };\n\n const action = <Action extends Ref.AnyPublicAction>(\n ref: Action,\n ...rest: OptionalArgs<Action>\n ): Effect.Effect<\n Ref.Returns<Action>,\n WebSocketClientError | ParseResult.ParseError\n > => {\n const args = (rest[0] ?? {}) as Ref.Args<Action>;\n return Ref.runWithCodec(ref, args, (functionReference, encodedArgs) =>\n Effect.tryPromise({\n try: () => convexClient.action(functionReference, encodedArgs),\n catch: (cause) => new WebSocketClientError({ cause }),\n }),\n );\n };\n\n const reactiveQuery = <Query extends Ref.AnyPublicQuery>(\n ref: Query,\n ...rest: OptionalArgs<Query>\n ): Stream.Stream<\n Ref.Returns<Query>,\n WebSocketClientError | ParseResult.ParseError\n > => {\n const args = (rest[0] ?? {}) as Ref.Args<Query>;\n const functionReference = Ref.getFunctionReference(ref);\n\n return Stream.unwrapScoped(\n Effect.gen(function* () {\n const encodedArgs = yield* Ref.encodeArgs(ref, args);\n\n return Stream.asyncScoped<unknown, WebSocketClientError>((emit) =>\n Effect.gen(function* () {\n const unsubscribe = convexClient.onUpdate(\n functionReference,\n encodedArgs,\n (result) => {\n emit.single(result);\n },\n (error) => {\n emit.fail(new WebSocketClientError({ cause: error }));\n },\n );\n yield* Effect.addFinalizer(() =>\n Effect.sync(() => unsubscribe()),\n );\n }),\n );\n }),\n ).pipe(\n Stream.mapEffect((encodedReturns) =>\n Ref.decodeReturns(ref, encodedReturns),\n ),\n );\n };\n\n return {\n url,\n setAuth,\n query,\n mutation,\n action,\n reactiveQuery,\n };\n }),\n );\n\n/**\n * A Confect client which uses a WebSocket to communicate with your Convex backend and supports reactive query subscriptions. The WebSocket connection is managed by the layer's scope and closed automatically when the scope ends. Wraps [ConvexClient](https://docs.convex.dev/api/classes/browser.ConvexClient).\n */\nexport const WebSocketClient = Context.GenericTag<\n Effect.Effect.Success<ReturnType<typeof make>>\n>(\"@confect/js/WebSocketClient\");\n\nexport type WebSocketClient = typeof WebSocketClient.Identifier;\n\nexport const layer = (\n address: string,\n options?: ConstructorParameters<typeof ConvexClient>[1],\n) => Layer.scoped(WebSocketClient, make(address, options));\n"],"mappings":";;;;;;;;;;;AAKA,IAAa,uBAAb,cAA0C,OAAO,aAAmC,CAClF,wBACA,EACE,OAAO,OAAO,SACf,CACF,CAAC;AAQF,MAAM,QACJ,SACA,YAEA,OAAO,eACL,OAAO,WAAW,IAAI,aAAa,SAAS,QAAQ,CAAC,GACpD,iBAAiB,OAAO,cAAc,aAAa,OAAO,CAAC,CAC7D,CAAC,KACA,OAAO,KAAK,iBAAiB;CAC3B,MAAM,MAAM;CAEZ,MAAM,WACJ,YAGA,aAEA,OAAO,WAAW;AAChB,eAAa,SACV,SAAS,OAAO,WAAW,WAAW,KAAK,CAAC,EAC7C,GAAI,WACA,EACG,oBACC,OAAO,QAAQ,SAAS,gBAAgB,CAAC,CAC5C,GACD,EAAE,CACP;GACD;CAEJ,MAAM,SACJ,KACA,GAAG,SAIA;EACH,MAAM,OAAQ,KAAK,MAAM,EAAE;AAC3B,SAAO,IAAI,aAAa,KAAK,OAAO,mBAAmB,gBACrD,OAAO,WAAW;GAChB,WAAW,aAAa,MAAM,mBAAmB,YAAY;GAC7D,QAAQ,UAAU,IAAI,qBAAqB,EAAE,OAAO,CAAC;GACtD,CAAC,CACH;;CAGH,MAAM,YACJ,KACA,GAAG,SAIA;EACH,MAAM,OAAQ,KAAK,MAAM,EAAE;AAC3B,SAAO,IAAI,aAAa,KAAK,OAAO,mBAAmB,gBACrD,OAAO,WAAW;GAChB,WAAW,aAAa,SAAS,mBAAmB,YAAY;GAChE,QAAQ,UAAU,IAAI,qBAAqB,EAAE,OAAO,CAAC;GACtD,CAAC,CACH;;CAGH,MAAM,UACJ,KACA,GAAG,SAIA;EACH,MAAM,OAAQ,KAAK,MAAM,EAAE;AAC3B,SAAO,IAAI,aAAa,KAAK,OAAO,mBAAmB,gBACrD,OAAO,WAAW;GAChB,WAAW,aAAa,OAAO,mBAAmB,YAAY;GAC9D,QAAQ,UAAU,IAAI,qBAAqB,EAAE,OAAO,CAAC;GACtD,CAAC,CACH;;CAGH,MAAM,iBACJ,KACA,GAAG,SAIA;EACH,MAAM,OAAQ,KAAK,MAAM,EAAE;EAC3B,MAAM,oBAAoB,IAAI,qBAAqB,IAAI;AAEvD,SAAO,OAAO,aACZ,OAAO,IAAI,aAAa;GACtB,MAAM,cAAc,OAAO,IAAI,WAAW,KAAK,KAAK;AAEpD,UAAO,OAAO,aAA4C,SACxD,OAAO,IAAI,aAAa;IACtB,MAAM,cAAc,aAAa,SAC/B,mBACA,cACC,WAAW;AACV,UAAK,OAAO,OAAO;QAEpB,UAAU;AACT,UAAK,KAAK,IAAI,qBAAqB,EAAE,OAAO,OAAO,CAAC,CAAC;MAExD;AACD,WAAO,OAAO,mBACZ,OAAO,WAAW,aAAa,CAAC,CACjC;KACD,CACH;IACD,CACH,CAAC,KACA,OAAO,WAAW,mBAChB,IAAI,cAAc,KAAK,eAAe,CACvC,CACF;;AAGH,QAAO;EACL;EACA;EACA;EACA;EACA;EACA;EACD;EACD,CACH;;;;AAKH,MAAa,kBAAkB,QAAQ,WAErC,8BAA8B;AAIhC,MAAa,SACX,SACA,YACG,MAAM,OAAO,iBAAiB,KAAK,SAAS,QAAQ,CAAC"}
1
+ {"version":3,"file":"WebSocketClient.js","names":[],"sources":["../src/WebSocketClient.ts"],"sourcesContent":["import * as Ref from \"@confect/core/Ref\";\nimport { ConvexClient } from \"convex/browser\";\nimport type { ParseResult } from \"effect\";\nimport { Context, Effect, Layer, Schema, Stream } from \"effect\";\n\nexport class WebSocketClientError extends Schema.TaggedError<WebSocketClientError>()(\n \"WebSocketClientError\",\n {\n cause: Schema.Unknown,\n },\n) {}\n\nconst make = (\n address: string,\n options?: ConstructorParameters<typeof ConvexClient>[1],\n) =>\n Effect.acquireRelease(\n Effect.sync(() => new ConvexClient(address, options)),\n (convexClient) => Effect.promise(() => convexClient.close()),\n ).pipe(\n Effect.map((convexClient) => {\n const url = address;\n\n const setAuth = (\n fetchToken: (args: {\n forceRefreshToken: boolean;\n }) => Effect.Effect<string | null | undefined>,\n onChange?: (isAuthenticated: boolean) => Effect.Effect<void>,\n ) =>\n Effect.sync(() => {\n convexClient.setAuth(\n (args) => Effect.runPromise(fetchToken(args)),\n ...(onChange\n ? [\n (isAuthenticated: boolean) =>\n Effect.runFork(onChange(isAuthenticated)),\n ]\n : []),\n );\n });\n\n const mapUnknownError = (cause: unknown) =>\n new WebSocketClientError({ cause });\n\n const query = <Query extends Ref.AnyPublicQuery>(\n ref: Query,\n ...rest: Ref.OptionalArgs<Query>\n ): Effect.Effect<\n Ref.Returns<Query>,\n Ref.Error<Query> | WebSocketClientError | ParseResult.ParseError\n > => {\n const args = (rest[0] ?? {}) as Ref.Args<Query>;\n return Ref.runWithCodec(\n ref,\n args,\n (functionReference, encodedArgs) =>\n convexClient.query(functionReference, encodedArgs),\n mapUnknownError,\n );\n };\n\n const mutation = <Mutation extends Ref.AnyPublicMutation>(\n ref: Mutation,\n ...rest: Ref.OptionalArgs<Mutation>\n ): Effect.Effect<\n Ref.Returns<Mutation>,\n Ref.Error<Mutation> | WebSocketClientError | ParseResult.ParseError\n > => {\n const args = (rest[0] ?? {}) as Ref.Args<Mutation>;\n return Ref.runWithCodec(\n ref,\n args,\n (functionReference, encodedArgs) =>\n convexClient.mutation(functionReference, encodedArgs),\n mapUnknownError,\n );\n };\n\n const action = <Action extends Ref.AnyPublicAction>(\n ref: Action,\n ...rest: Ref.OptionalArgs<Action>\n ): Effect.Effect<\n Ref.Returns<Action>,\n Ref.Error<Action> | WebSocketClientError | ParseResult.ParseError\n > => {\n const args = (rest[0] ?? {}) as Ref.Args<Action>;\n return Ref.runWithCodec(\n ref,\n args,\n (functionReference, encodedArgs) =>\n convexClient.action(functionReference, encodedArgs),\n mapUnknownError,\n );\n };\n\n const reactiveQuery = <Query extends Ref.AnyPublicQuery>(\n ref: Query,\n ...rest: Ref.OptionalArgs<Query>\n ): Stream.Stream<\n Ref.Returns<Query>,\n Ref.Error<Query> | WebSocketClientError | ParseResult.ParseError\n > => {\n const args = (rest[0] ?? {}) as Ref.Args<Query>;\n const functionReference = Ref.getFunctionReference(ref);\n const onError = Ref.decodeErrorOrElse(ref, mapUnknownError);\n\n return Stream.unwrapScoped(\n Effect.gen(function* () {\n const encodedArgs = yield* Ref.encodeArgs(ref, args);\n\n return Stream.asyncScoped<\n unknown,\n Ref.Error<Query> | WebSocketClientError\n >((emit) =>\n Effect.gen(function* () {\n const unsubscribe = convexClient.onUpdate(\n functionReference,\n encodedArgs,\n (result) => {\n emit.single(result);\n },\n (error) => {\n emit.fail(onError(error));\n },\n );\n yield* Effect.addFinalizer(() =>\n Effect.sync(() => unsubscribe()),\n );\n }),\n );\n }),\n ).pipe(\n Stream.mapEffect((encodedReturns) =>\n Ref.decodeReturns(ref, encodedReturns),\n ),\n );\n };\n\n return {\n url,\n setAuth,\n query,\n mutation,\n action,\n reactiveQuery,\n };\n }),\n );\n\n/**\n * A Confect client which uses a WebSocket to communicate with your Convex backend and supports reactive query subscriptions. The WebSocket connection is managed by the layer's scope and closed automatically when the scope ends. Wraps [ConvexClient](https://docs.convex.dev/api/classes/browser.ConvexClient).\n */\nexport const WebSocketClient = Context.GenericTag<\n Effect.Effect.Success<ReturnType<typeof make>>\n>(\"@confect/js/WebSocketClient\");\n\nexport type WebSocketClient = typeof WebSocketClient.Identifier;\n\nexport const layer = (\n address: string,\n options?: ConstructorParameters<typeof ConvexClient>[1],\n) => Layer.scoped(WebSocketClient, make(address, options));\n"],"mappings":";;;;;;;;;;;AAKA,IAAa,uBAAb,cAA0C,OAAO,aAAmC,CAClF,wBACA,EACE,OAAO,OAAO,SACf,CACF,CAAC;AAEF,MAAM,QACJ,SACA,YAEA,OAAO,eACL,OAAO,WAAW,IAAI,aAAa,SAAS,QAAQ,CAAC,GACpD,iBAAiB,OAAO,cAAc,aAAa,OAAO,CAAC,CAC7D,CAAC,KACA,OAAO,KAAK,iBAAiB;CAC3B,MAAM,MAAM;CAEZ,MAAM,WACJ,YAGA,aAEA,OAAO,WAAW;AAChB,eAAa,SACV,SAAS,OAAO,WAAW,WAAW,KAAK,CAAC,EAC7C,GAAI,WACA,EACG,oBACC,OAAO,QAAQ,SAAS,gBAAgB,CAAC,CAC5C,GACD,EAAE,CACP;GACD;CAEJ,MAAM,mBAAmB,UACvB,IAAI,qBAAqB,EAAE,OAAO,CAAC;CAErC,MAAM,SACJ,KACA,GAAG,SAIA;EACH,MAAM,OAAQ,KAAK,MAAM,EAAE;AAC3B,SAAO,IAAI,aACT,KACA,OACC,mBAAmB,gBAClB,aAAa,MAAM,mBAAmB,YAAY,EACpD,gBACD;;CAGH,MAAM,YACJ,KACA,GAAG,SAIA;EACH,MAAM,OAAQ,KAAK,MAAM,EAAE;AAC3B,SAAO,IAAI,aACT,KACA,OACC,mBAAmB,gBAClB,aAAa,SAAS,mBAAmB,YAAY,EACvD,gBACD;;CAGH,MAAM,UACJ,KACA,GAAG,SAIA;EACH,MAAM,OAAQ,KAAK,MAAM,EAAE;AAC3B,SAAO,IAAI,aACT,KACA,OACC,mBAAmB,gBAClB,aAAa,OAAO,mBAAmB,YAAY,EACrD,gBACD;;CAGH,MAAM,iBACJ,KACA,GAAG,SAIA;EACH,MAAM,OAAQ,KAAK,MAAM,EAAE;EAC3B,MAAM,oBAAoB,IAAI,qBAAqB,IAAI;EACvD,MAAM,UAAU,IAAI,kBAAkB,KAAK,gBAAgB;AAE3D,SAAO,OAAO,aACZ,OAAO,IAAI,aAAa;GACtB,MAAM,cAAc,OAAO,IAAI,WAAW,KAAK,KAAK;AAEpD,UAAO,OAAO,aAGX,SACD,OAAO,IAAI,aAAa;IACtB,MAAM,cAAc,aAAa,SAC/B,mBACA,cACC,WAAW;AACV,UAAK,OAAO,OAAO;QAEpB,UAAU;AACT,UAAK,KAAK,QAAQ,MAAM,CAAC;MAE5B;AACD,WAAO,OAAO,mBACZ,OAAO,WAAW,aAAa,CAAC,CACjC;KACD,CACH;IACD,CACH,CAAC,KACA,OAAO,WAAW,mBAChB,IAAI,cAAc,KAAK,eAAe,CACvC,CACF;;AAGH,QAAO;EACL;EACA;EACA;EACA;EACA;EACA;EACD;EACD,CACH;;;;AAKH,MAAa,kBAAkB,QAAQ,WAErC,8BAA8B;AAIhC,MAAa,SACX,SACA,YACG,MAAM,OAAO,iBAAiB,KAAK,SAAS,QAAQ,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@confect/js",
3
- "version": "5.0.0",
3
+ "version": "7.0.0",
4
4
  "description": "JavaScript client bindings for any JS runtime",
5
5
  "repository": {
6
6
  "type": "git",
@@ -48,7 +48,7 @@
48
48
  "peerDependencies": {
49
49
  "convex": "^1.30.0",
50
50
  "effect": "^3.19.16",
51
- "@confect/core": "5.0.0"
51
+ "@confect/core": "7.0.0"
52
52
  },
53
53
  "engines": {
54
54
  "node": ">=22",
package/src/HttpClient.ts CHANGED
@@ -10,12 +10,6 @@ export class HttpClientError extends Schema.TaggedError<HttpClientError>()(
10
10
  },
11
11
  ) {}
12
12
 
13
- type OptionalArgs<
14
- R extends Ref.AnyPublicQuery | Ref.AnyPublicMutation | Ref.AnyPublicAction,
15
- > = keyof Ref.Args<R> extends never
16
- ? [args?: Ref.Args<R>]
17
- : [args: Ref.Args<R>];
18
-
19
13
  const make = (
20
14
  address: string,
21
15
  options?: ConstructorParameters<typeof ConvexHttpClient>[1],
@@ -33,51 +27,56 @@ const make = (
33
27
  client.clearAuth();
34
28
  });
35
29
 
30
+ const mapUnknownError = (cause: unknown) => new HttpClientError({ cause });
31
+
36
32
  const query = <Query extends Ref.AnyPublicQuery>(
37
33
  ref: Query,
38
- ...rest: OptionalArgs<Query>
34
+ ...rest: Ref.OptionalArgs<Query>
39
35
  ): Effect.Effect<
40
36
  Ref.Returns<Query>,
41
- HttpClientError | ParseResult.ParseError
37
+ Ref.Error<Query> | HttpClientError | ParseResult.ParseError
42
38
  > => {
43
39
  const args = (rest[0] ?? {}) as Ref.Args<Query>;
44
- return Ref.runWithCodec(ref, args, (functionReference, encodedArgs) =>
45
- Effect.tryPromise({
46
- try: () => client.query(functionReference, encodedArgs),
47
- catch: (cause) => new HttpClientError({ cause }),
48
- }),
40
+ return Ref.runWithCodec(
41
+ ref,
42
+ args,
43
+ (functionReference, encodedArgs) =>
44
+ client.query(functionReference, encodedArgs),
45
+ mapUnknownError,
49
46
  );
50
47
  };
51
48
 
52
49
  const mutation = <Mutation extends Ref.AnyPublicMutation>(
53
50
  ref: Mutation,
54
- ...rest: OptionalArgs<Mutation>
51
+ ...rest: Ref.OptionalArgs<Mutation>
55
52
  ): Effect.Effect<
56
53
  Ref.Returns<Mutation>,
57
- HttpClientError | ParseResult.ParseError
54
+ Ref.Error<Mutation> | HttpClientError | ParseResult.ParseError
58
55
  > => {
59
56
  const args = (rest[0] ?? {}) as Ref.Args<Mutation>;
60
- return Ref.runWithCodec(ref, args, (functionReference, encodedArgs) =>
61
- Effect.tryPromise({
62
- try: () => client.mutation(functionReference, encodedArgs),
63
- catch: (cause) => new HttpClientError({ cause }),
64
- }),
57
+ return Ref.runWithCodec(
58
+ ref,
59
+ args,
60
+ (functionReference, encodedArgs) =>
61
+ client.mutation(functionReference, encodedArgs),
62
+ mapUnknownError,
65
63
  );
66
64
  };
67
65
 
68
66
  const action = <Action extends Ref.AnyPublicAction>(
69
67
  ref: Action,
70
- ...rest: OptionalArgs<Action>
68
+ ...rest: Ref.OptionalArgs<Action>
71
69
  ): Effect.Effect<
72
70
  Ref.Returns<Action>,
73
- HttpClientError | ParseResult.ParseError
71
+ Ref.Error<Action> | HttpClientError | ParseResult.ParseError
74
72
  > => {
75
73
  const args = (rest[0] ?? {}) as Ref.Args<Action>;
76
- return Ref.runWithCodec(ref, args, (functionReference, encodedArgs) =>
77
- Effect.tryPromise({
78
- try: () => client.action(functionReference, encodedArgs),
79
- catch: (cause) => new HttpClientError({ cause }),
80
- }),
74
+ return Ref.runWithCodec(
75
+ ref,
76
+ args,
77
+ (functionReference, encodedArgs) =>
78
+ client.action(functionReference, encodedArgs),
79
+ mapUnknownError,
81
80
  );
82
81
  };
83
82
 
@@ -10,12 +10,6 @@ export class WebSocketClientError extends Schema.TaggedError<WebSocketClientErro
10
10
  },
11
11
  ) {}
12
12
 
13
- type OptionalArgs<
14
- R extends Ref.AnyPublicQuery | Ref.AnyPublicMutation | Ref.AnyPublicAction,
15
- > = keyof Ref.Args<R> extends never
16
- ? [args?: Ref.Args<R>]
17
- : [args: Ref.Args<R>];
18
-
19
13
  const make = (
20
14
  address: string,
21
15
  options?: ConstructorParameters<typeof ConvexClient>[1],
@@ -45,69 +39,79 @@ const make = (
45
39
  );
46
40
  });
47
41
 
42
+ const mapUnknownError = (cause: unknown) =>
43
+ new WebSocketClientError({ cause });
44
+
48
45
  const query = <Query extends Ref.AnyPublicQuery>(
49
46
  ref: Query,
50
- ...rest: OptionalArgs<Query>
47
+ ...rest: Ref.OptionalArgs<Query>
51
48
  ): Effect.Effect<
52
49
  Ref.Returns<Query>,
53
- WebSocketClientError | ParseResult.ParseError
50
+ Ref.Error<Query> | WebSocketClientError | ParseResult.ParseError
54
51
  > => {
55
52
  const args = (rest[0] ?? {}) as Ref.Args<Query>;
56
- return Ref.runWithCodec(ref, args, (functionReference, encodedArgs) =>
57
- Effect.tryPromise({
58
- try: () => convexClient.query(functionReference, encodedArgs),
59
- catch: (cause) => new WebSocketClientError({ cause }),
60
- }),
53
+ return Ref.runWithCodec(
54
+ ref,
55
+ args,
56
+ (functionReference, encodedArgs) =>
57
+ convexClient.query(functionReference, encodedArgs),
58
+ mapUnknownError,
61
59
  );
62
60
  };
63
61
 
64
62
  const mutation = <Mutation extends Ref.AnyPublicMutation>(
65
63
  ref: Mutation,
66
- ...rest: OptionalArgs<Mutation>
64
+ ...rest: Ref.OptionalArgs<Mutation>
67
65
  ): Effect.Effect<
68
66
  Ref.Returns<Mutation>,
69
- WebSocketClientError | ParseResult.ParseError
67
+ Ref.Error<Mutation> | WebSocketClientError | ParseResult.ParseError
70
68
  > => {
71
69
  const args = (rest[0] ?? {}) as Ref.Args<Mutation>;
72
- return Ref.runWithCodec(ref, args, (functionReference, encodedArgs) =>
73
- Effect.tryPromise({
74
- try: () => convexClient.mutation(functionReference, encodedArgs),
75
- catch: (cause) => new WebSocketClientError({ cause }),
76
- }),
70
+ return Ref.runWithCodec(
71
+ ref,
72
+ args,
73
+ (functionReference, encodedArgs) =>
74
+ convexClient.mutation(functionReference, encodedArgs),
75
+ mapUnknownError,
77
76
  );
78
77
  };
79
78
 
80
79
  const action = <Action extends Ref.AnyPublicAction>(
81
80
  ref: Action,
82
- ...rest: OptionalArgs<Action>
81
+ ...rest: Ref.OptionalArgs<Action>
83
82
  ): Effect.Effect<
84
83
  Ref.Returns<Action>,
85
- WebSocketClientError | ParseResult.ParseError
84
+ Ref.Error<Action> | WebSocketClientError | ParseResult.ParseError
86
85
  > => {
87
86
  const args = (rest[0] ?? {}) as Ref.Args<Action>;
88
- return Ref.runWithCodec(ref, args, (functionReference, encodedArgs) =>
89
- Effect.tryPromise({
90
- try: () => convexClient.action(functionReference, encodedArgs),
91
- catch: (cause) => new WebSocketClientError({ cause }),
92
- }),
87
+ return Ref.runWithCodec(
88
+ ref,
89
+ args,
90
+ (functionReference, encodedArgs) =>
91
+ convexClient.action(functionReference, encodedArgs),
92
+ mapUnknownError,
93
93
  );
94
94
  };
95
95
 
96
96
  const reactiveQuery = <Query extends Ref.AnyPublicQuery>(
97
97
  ref: Query,
98
- ...rest: OptionalArgs<Query>
98
+ ...rest: Ref.OptionalArgs<Query>
99
99
  ): Stream.Stream<
100
100
  Ref.Returns<Query>,
101
- WebSocketClientError | ParseResult.ParseError
101
+ Ref.Error<Query> | WebSocketClientError | ParseResult.ParseError
102
102
  > => {
103
103
  const args = (rest[0] ?? {}) as Ref.Args<Query>;
104
104
  const functionReference = Ref.getFunctionReference(ref);
105
+ const onError = Ref.decodeErrorOrElse(ref, mapUnknownError);
105
106
 
106
107
  return Stream.unwrapScoped(
107
108
  Effect.gen(function* () {
108
109
  const encodedArgs = yield* Ref.encodeArgs(ref, args);
109
110
 
110
- return Stream.asyncScoped<unknown, WebSocketClientError>((emit) =>
111
+ return Stream.asyncScoped<
112
+ unknown,
113
+ Ref.Error<Query> | WebSocketClientError
114
+ >((emit) =>
111
115
  Effect.gen(function* () {
112
116
  const unsubscribe = convexClient.onUpdate(
113
117
  functionReference,
@@ -116,7 +120,7 @@ const make = (
116
120
  emit.single(result);
117
121
  },
118
122
  (error) => {
119
- emit.fail(new WebSocketClientError({ cause: error }));
123
+ emit.fail(onError(error));
120
124
  },
121
125
  );
122
126
  yield* Effect.addFinalizer(() =>