@confect/react 9.0.0-next.7 → 9.0.0-next.8
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 +30 -0
- package/dist/QueryResult.d.ts +1 -1
- package/dist/QueryResult.d.ts.map +1 -1
- package/dist/QueryResult.js +6 -1
- package/dist/QueryResult.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/QueryResult.ts +6 -1
- package/src/index.ts +5 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,35 @@
|
|
|
1
1
|
# @confect/react
|
|
2
2
|
|
|
3
|
+
## 9.0.0-next.8
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 3fec285: Import Effect from its submodule paths internally to shrink per-function cold-start bundles.
|
|
8
|
+
|
|
9
|
+
Confect's packages now import Effect modules from their submodule paths (`import * as Schema from "effect/Schema"`) instead of the `"effect"` barrel (`import { Schema } from "effect"`).
|
|
10
|
+
|
|
11
|
+
### Why
|
|
12
|
+
|
|
13
|
+
A barrel import of a namespace re-export defeats esbuild's tree-shaking: accessing `Schema.X` from `import { Schema } from "effect"` retains the _entire_ `Schema` namespace, because the bundler can't prune property access on the barrel's `export * as Schema`. So every Convex function's cold-start bundle was pulling all of `effect/Schema` and `effect/Stream` — and, transitively through Schema's `Arbitrary`, `fast-check` — whether the function used them or not.
|
|
14
|
+
|
|
15
|
+
Importing from the submodule path tree-shakes normally. On a minimal function this cut the bundle esbuild produces by ~54% (the `effect/Schema` module alone by ~75%) and its cold-start module-evaluation time by ~35%, with `fast-check` dropped entirely. This is also the import style Effect v4 recommends, so it's forward-compatible. A `no-restricted-imports` ESLint rule now enforces it across the codebase (type-only imports and `@effect/vitest` are exempt).
|
|
16
|
+
|
|
17
|
+
No API changes — your existing code keeps working.
|
|
18
|
+
|
|
19
|
+
### Getting the full win in your own code
|
|
20
|
+
|
|
21
|
+
This change shrinks the Confect code in every function bundle, but a function's bundle also includes your own `confect/tables/*` and `*.spec.ts` files. esbuild retains the union across all importers, so a single barrel import anywhere in a function's module graph re-pins the whole `effect/Schema` namespace and undoes the reduction. To get the full bundle/cold-start savings, import Effect from its submodule paths in your own Confect files too:
|
|
22
|
+
|
|
23
|
+
```diff
|
|
24
|
+
- import { Schema } from "effect";
|
|
25
|
+
+ import * as Schema from "effect/Schema";
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Bare helpers (`pipe`, `flow`, `identity`) come from `"effect/Function"`.
|
|
29
|
+
|
|
30
|
+
- Updated dependencies [3fec285]
|
|
31
|
+
- @confect/core@9.0.0-next.8
|
|
32
|
+
|
|
3
33
|
## 9.0.0-next.7
|
|
4
34
|
|
|
5
35
|
### Patch Changes
|
package/dist/QueryResult.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"QueryResult.d.ts","names":[],"sources":["../src/QueryResult.ts"],"mappings":";;;;;;
|
|
1
|
+
{"version":3,"file":"QueryResult.d.ts","names":[],"sources":["../src/QueryResult.ts"],"mappings":";;;;;;cAOM,MAAA;AAAA,KACD,MAAA,UAAgB,MAAA;;;;;;;KAQT,WAAA,iBACR,OAAA,CAAQ,CAAA,EAAG,CAAA,IACX,OAAA,CAAQ,CAAA,EAAG,CAAA,IACX,OAAA,CAAQ,CAAA,EAAG,CAAA;AAAA,kBAEU,WAAA;EAAA,UACN,KAAA,eAAoB,QAAA,CAAS,QAAA;IAAA,UAClC,MAAA;MAAA,SACC,CAAA,GAAI,CAAA,YAAa,CAAA;MAAA,SACjB,CAAA,GAAI,CAAA,YAAa,CAAA;IAAA;EAAA;EAAA,KAKlB,OAAA,MAAa,CAAA,SAAU,WAAA,sBAAiC,CAAA;EAAA,KAGxD,OAAA,MAAa,CAAA,SAAU,WAAA,sBAAiC,CAAA;AAAA;AAAA,UAGrD,OAAA,uBAA8B,WAAA,CAAY,KAAA,CAAM,CAAA,EAAG,CAAA;EAAA,SACzD,IAAA;EAAA,SACA,OAAA;AAAA;AAAA,UAGM,OAAA,uBAA8B,WAAA,CAAY,KAAA,CAAM,CAAA,EAAG,CAAA;EAAA,SACzD,IAAA;EAAA,SACA,KAAA,EAAO,CAAA;AAAA;AAAA,UAGD,OAAA,uBAA8B,WAAA,CAAY,KAAA,CAAM,CAAA,EAAG,CAAA;EAAA,SACzD,IAAA;EAAA,SACA,KAAA,EAAO,CAAA;AAAA;AAAA,cAGL,aAAA,GAAiB,CAAA,cAAa,CAAA,IAAK,WAAA;AAAA,cA8CnC,IAAA,yBAA8B,OAAA,cAAmB,OAAA,CAAQ,CAAA,EAAG,CAAA;AAAA,cAM5D,OAAA,iBAAyB,KAAA,EAAO,CAAA,KAAI,OAAA,CAAQ,CAAA,EAAG,CAAA;AAAA,cAM/C,IAAA,iBAAsB,KAAA,EAAO,CAAA,KAAI,OAAA,CAAQ,CAAA,EAAG,CAAA;AAAA,cAM5C,SAAA,SACX,WAAA,EAAa,WAAA,CAAY,CAAA,EAAG,CAAA,MAC3B,WAAA,IAAe,OAAA,CAAQ,CAAA,EAAG,CAAA;AAAA,cAEhB,SAAA,SACX,WAAA,EAAa,WAAA,CAAY,CAAA,EAAG,CAAA,MAC3B,WAAA,IAAe,OAAA,CAAQ,CAAA,EAAG,CAAA;AAAA,cAEhB,SAAA,SACX,WAAA,EAAa,WAAA,CAAY,CAAA,EAAG,CAAA,MAC3B,WAAA,IAAe,OAAA,CAAQ,CAAA,EAAG,CAAA;AAAA,KAExB,YAAA;EAAA,SACM,SAAA,GAAY,OAAA,cAAqB,CAAA;EAAA,SACjC,SAAA,GAAY,KAAA,EAAO,CAAA,KAAM,CAAA;AAAA,MAC9B,CAAA;EAAA,SAAqC,SAAA,GAAY,KAAA,EAAO,CAAA,KAAM,CAAA;AAAA;AAAA,KAE/D,YAAA,gBAA4B,CAAA,oBAAqB,CAAA,GAAI,CAAA,GAAI,CAAA,GAAI,CAAA,GAAI,CAAA;;;;;;;;;;AA/GtE;;;;cA8Ha,KAAA;EAAA,wBAET,OAAA,EAAS,YAAA,CAAa,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,CAAA,KAChC,IAAA,EAAM,WAAA,CAAY,CAAA,EAAG,CAAA,MAAO,YAAA,CAAa,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,CAAA;EAAA,wBAEpD,IAAA,EAAM,WAAA,CAAY,CAAA,EAAG,CAAA,GACrB,OAAA,EAAS,YAAA,CAAa,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,CAAA,IACjC,YAAA,CAAa,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,CAAA;AAAA"}
|
package/dist/QueryResult.js
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import { __exportAll } from "./_virtual/_rolldown/runtime.js";
|
|
2
|
-
import
|
|
2
|
+
import * as Function from "effect/Function";
|
|
3
|
+
import { identity } from "effect/Function";
|
|
4
|
+
import * as Equal from "effect/Equal";
|
|
5
|
+
import * as Hash from "effect/Hash";
|
|
6
|
+
import * as Pipeable from "effect/Pipeable";
|
|
7
|
+
import * as Predicate from "effect/Predicate";
|
|
3
8
|
|
|
4
9
|
//#region src/QueryResult.ts
|
|
5
10
|
var QueryResult_exports = /* @__PURE__ */ __exportAll({
|
package/dist/QueryResult.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"QueryResult.js","names":[],"sources":["../src/QueryResult.ts"],"sourcesContent":["import { Equal
|
|
1
|
+
{"version":3,"file":"QueryResult.js","names":[],"sources":["../src/QueryResult.ts"],"sourcesContent":["import { identity } from \"effect/Function\";\nimport * as Equal from \"effect/Equal\";\nimport * as Function from \"effect/Function\";\nimport * as Hash from \"effect/Hash\";\nimport * as Pipeable from \"effect/Pipeable\";\nimport * as Predicate from \"effect/Predicate\";\n\nconst TypeId = \"@confect/react/QueryResult\";\ntype TypeId = typeof TypeId;\n\n/**\n * A `QueryResult` represents the result of a Confect query.\n *\n * @typeParam A - The type of the decoded `returns` value in the `Success` variant.\n * @typeParam E - The type of the decoded typed error in the `Failure` variant.\n */\nexport type QueryResult<A, E = never> =\n | Loading<A, E>\n | Success<A, E>\n | Failure<A, E>;\n\nexport declare namespace QueryResult {\n export interface Proto<A, E> extends Pipeable.Pipeable {\n readonly [TypeId]: {\n readonly E: (_: never) => E;\n readonly A: (_: never) => A;\n };\n }\n\n // eslint-disable-next-line @typescript-eslint/no-shadow\n export type Success<R> = R extends QueryResult<infer A, infer _E> ? A : never;\n\n // eslint-disable-next-line @typescript-eslint/no-shadow\n export type Failure<R> = R extends QueryResult<infer _A, infer E> ? E : never;\n}\n\nexport interface Loading<A, E = never> extends QueryResult.Proto<A, E> {\n readonly _tag: \"Loading\";\n readonly skipped: boolean;\n}\n\nexport interface Success<A, E = never> extends QueryResult.Proto<A, E> {\n readonly _tag: \"Success\";\n readonly value: A;\n}\n\nexport interface Failure<A, E = never> extends QueryResult.Proto<A, E> {\n readonly _tag: \"Failure\";\n readonly error: E;\n}\n\nexport const isQueryResult = (u: unknown): u is QueryResult<unknown, unknown> =>\n Predicate.hasProperty(u, TypeId);\n\nconst QueryResultProto = {\n [TypeId]: {\n E: identity,\n A: identity,\n },\n pipe(this: QueryResult<any, any>, ...args: ReadonlyArray<unknown>) {\n return Pipeable.pipeArguments(\n this,\n args as unknown as Parameters<typeof Pipeable.pipeArguments>[1],\n );\n },\n [Equal.symbol](\n this: QueryResult<any, any>,\n that: QueryResult<any, any>,\n ): boolean {\n if (this._tag !== that._tag) {\n return false;\n }\n switch (this._tag) {\n case \"Loading\":\n return this.skipped === (that as Loading<any, any>).skipped;\n case \"Success\":\n return Equal.equals(this.value, (that as Success<any, any>).value);\n case \"Failure\":\n return Equal.equals(this.error, (that as Failure<any, any>).error);\n }\n },\n [Hash.symbol](this: QueryResult<any, any>): number {\n const tagHash = Hash.string(this._tag);\n switch (this._tag) {\n case \"Loading\":\n return Hash.cached(\n this,\n Hash.combine(tagHash)(Hash.hash(this.skipped)),\n );\n case \"Success\":\n return Hash.cached(this, Hash.combine(tagHash)(Hash.hash(this.value)));\n case \"Failure\":\n return Hash.cached(this, Hash.combine(tagHash)(Hash.hash(this.error)));\n }\n },\n};\n\nexport const load = <A = never, E = never>(skipped: boolean): Loading<A, E> =>\n Object.assign(Object.create(QueryResultProto), {\n _tag: \"Loading\" as const,\n skipped,\n });\n\nexport const succeed = <A, E = never>(value: A): Success<A, E> =>\n Object.assign(Object.create(QueryResultProto), {\n _tag: \"Success\" as const,\n value,\n });\n\nexport const fail = <E, A = never>(error: E): Failure<A, E> =>\n Object.assign(Object.create(QueryResultProto), {\n _tag: \"Failure\" as const,\n error,\n });\n\nexport const isLoading = <A, E>(\n queryResult: QueryResult<A, E>,\n): queryResult is Loading<A, E> => queryResult._tag === \"Loading\";\n\nexport const isSuccess = <A, E>(\n queryResult: QueryResult<A, E>,\n): queryResult is Success<A, E> => queryResult._tag === \"Success\";\n\nexport const isFailure = <A, E>(\n queryResult: QueryResult<A, E>,\n): queryResult is Failure<A, E> => queryResult._tag === \"Failure\";\n\ntype MatchOptions<A, E, X, Y, Z> = {\n readonly onLoading: (skipped: boolean) => X;\n readonly onSuccess: (value: A) => Y;\n} & ([E] extends [never] ? {} : { readonly onFailure: (error: E) => Z });\n\ntype MatchReturns<E, X, Y, Z> = [E] extends [never] ? X | Y : X | Y | Z;\n\n/**\n * Matches a {@link QueryResult} to the appropriate handler based on its tag. If\n * the provided `QueryResult` cannot fail (i.e. `E` is `never`), `onFailure` is\n * not required.\n *\n * @example\n * ```tsx\n * const result = QueryResult.match(queryResult, {\n * onLoading: (skipped) => skipped ? null : <p>Loading…</p>,\n * onSuccess: (value) => <p>{value.text}</p>,\n * onFailure: (error) => <p>Error: {error.message}</p>,\n * });\n */\nexport const match: {\n <A, E, X, Y, Z = never>(\n options: MatchOptions<A, E, X, Y, Z>,\n ): (self: QueryResult<A, E>) => MatchReturns<E, X, Y, Z>;\n <A, E, X, Y, Z = never>(\n self: QueryResult<A, E>,\n options: MatchOptions<A, E, X, Y, Z>,\n ): MatchReturns<E, X, Y, Z>;\n} = Function.dual(\n 2,\n <A, E, X, Y, Z = never>(\n self: QueryResult<A, E>,\n options: MatchOptions<A, E, X, Y, Z>,\n ): MatchReturns<E, X, Y, Z> => {\n switch (self._tag) {\n case \"Loading\":\n return options.onLoading(self.skipped);\n case \"Success\":\n return options.onSuccess(self.value);\n case \"Failure\": {\n if (Predicate.hasProperty(options, \"onFailure\")) {\n return options.onFailure(self.error) as MatchReturns<E, X, Y, Z>;\n }\n throw new Error(\n \"`onFailure` is required when error schema is provided\",\n );\n }\n }\n },\n);\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAOA,MAAM,SAAS;AA4Cf,MAAa,iBAAiB,MAC5B,UAAU,YAAY,GAAG,OAAO;AAElC,MAAM,mBAAmB;EACtB,SAAS;EACR,GAAG;EACH,GAAG;EACJ;CACD,KAAkC,GAAG,MAA8B;AACjE,SAAO,SAAS,cACd,MACA,KACD;;CAEH,CAAC,MAAM,QAEL,MACS;AACT,MAAI,KAAK,SAAS,KAAK,KACrB,QAAO;AAET,UAAQ,KAAK,MAAb;GACE,KAAK,UACH,QAAO,KAAK,YAAa,KAA2B;GACtD,KAAK,UACH,QAAO,MAAM,OAAO,KAAK,OAAQ,KAA2B,MAAM;GACpE,KAAK,UACH,QAAO,MAAM,OAAO,KAAK,OAAQ,KAA2B,MAAM;;;CAGxE,CAAC,KAAK,UAA6C;EACjD,MAAM,UAAU,KAAK,OAAO,KAAK,KAAK;AACtC,UAAQ,KAAK,MAAb;GACE,KAAK,UACH,QAAO,KAAK,OACV,MACA,KAAK,QAAQ,QAAQ,CAAC,KAAK,KAAK,KAAK,QAAQ,CAAC,CAC/C;GACH,KAAK,UACH,QAAO,KAAK,OAAO,MAAM,KAAK,QAAQ,QAAQ,CAAC,KAAK,KAAK,KAAK,MAAM,CAAC,CAAC;GACxE,KAAK,UACH,QAAO,KAAK,OAAO,MAAM,KAAK,QAAQ,QAAQ,CAAC,KAAK,KAAK,KAAK,MAAM,CAAC,CAAC;;;CAG7E;AAED,MAAa,QAA8B,YACzC,OAAO,OAAO,OAAO,OAAO,iBAAiB,EAAE;CAC7C,MAAM;CACN;CACD,CAAC;AAEJ,MAAa,WAAyB,UACpC,OAAO,OAAO,OAAO,OAAO,iBAAiB,EAAE;CAC7C,MAAM;CACN;CACD,CAAC;AAEJ,MAAa,QAAsB,UACjC,OAAO,OAAO,OAAO,OAAO,iBAAiB,EAAE;CAC7C,MAAM;CACN;CACD,CAAC;AAEJ,MAAa,aACX,gBACiC,YAAY,SAAS;AAExD,MAAa,aACX,gBACiC,YAAY,SAAS;AAExD,MAAa,aACX,gBACiC,YAAY,SAAS;;;;;;;;;;;;;;AAsBxD,MAAa,QAQT,SAAS,KACX,IAEE,MACA,YAC6B;AAC7B,SAAQ,KAAK,MAAb;EACE,KAAK,UACH,QAAO,QAAQ,UAAU,KAAK,QAAQ;EACxC,KAAK,UACH,QAAO,QAAQ,UAAU,KAAK,MAAM;EACtC,KAAK;AACH,OAAI,UAAU,YAAY,SAAS,YAAY,CAC7C,QAAO,QAAQ,UAAU,KAAK,MAAM;AAEtC,SAAM,IAAI,MACR,wDACD;;EAIR"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { QueryResult, QueryResult_d_exports } from "./QueryResult.js";
|
|
2
2
|
import { Ref } from "@confect/core";
|
|
3
|
-
import
|
|
3
|
+
import * as Either from "effect/Either";
|
|
4
4
|
|
|
5
5
|
//#region src/index.d.ts
|
|
6
6
|
type InvokeReturn<Ref_ extends Ref.Any> = [Ref.Error<Ref_>] extends [never] ? Promise<Ref.Returns<Ref_>> : Promise<Either.Either<Ref.Returns<Ref_>, Ref.Error<Ref_>>>;
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/index.ts"],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/index.ts"],"mappings":";;;;;KAiBY,YAAA,cAA0B,GAAA,CAAI,GAAA,KAAQ,GAAA,CAAI,KAAA,CAAM,IAAA,qBAGxD,OAAA,CAAQ,GAAA,CAAI,OAAA,CAAQ,IAAA,KACpB,OAAA,CAAQ,MAAA,CAAO,MAAA,CAAO,GAAA,CAAI,OAAA,CAAQ,IAAA,GAAO,GAAA,CAAI,KAAA,CAAM,IAAA;AAAA,KAElD,YAAA,eAA2B,GAAA,CAAI,cAAA,UAC5B,GAAA,CAAI,IAAA,CAAK,KAAA,mBACV,IAAA,GAAO,GAAA,CAAI,IAAA,CAAK,KAAA,eAChB,IAAA,EAAM,GAAA,CAAI,IAAA,CAAK,KAAA;AAAA,cAET,QAAA,iBAA0B,GAAA,CAAI,cAAA,EACzC,GAAA,EAAK,KAAA,KACF,IAAA,EAAM,YAAA,CAAa,KAAA,MACrB,WAAA,CAAwB,GAAA,CAAI,OAAA,CAAQ,KAAA,GAAQ,GAAA,CAAI,KAAA,CAAM,KAAA;;;;;;;;;;;;;;cA2D5C,WAAA,oBAAgC,GAAA,CAAI,iBAAA,EAC/C,GAAA,EAAK,QAAA,UACC,IAAA,EAAM,GAAA,CAAI,YAAA,CAAa,QAAA,MAAc,YAAA,CAAa,QAAA;;;;;;;;;;;;;;cA8B7C,SAAA,kBAA4B,GAAA,CAAI,eAAA,EAC3C,GAAA,EAAK,MAAA,UACC,IAAA,EAAM,GAAA,CAAI,YAAA,CAAa,MAAA,MAAY,YAAA,CAAa,MAAA"}
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import { QueryResult_exports, fail, load, succeed } from "./QueryResult.js";
|
|
2
2
|
import { Ref } from "@confect/core";
|
|
3
3
|
import { useAction as useAction$1, useMutation as useMutation$1, useQuery as useQuery$1 } from "convex/react";
|
|
4
|
-
import
|
|
4
|
+
import * as Cause from "effect/Cause";
|
|
5
|
+
import * as Effect from "effect/Effect";
|
|
6
|
+
import * as Either from "effect/Either";
|
|
7
|
+
import * as Exit from "effect/Exit";
|
|
8
|
+
import * as Option from "effect/Option";
|
|
5
9
|
import { useCallback, useMemo } from "react";
|
|
6
10
|
|
|
7
11
|
//#region src/index.ts
|
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
|
|
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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@confect/react",
|
|
3
3
|
"description": "Client-side bindings for React apps",
|
|
4
|
-
"version": "9.0.0-next.
|
|
4
|
+
"version": "9.0.0-next.8",
|
|
5
5
|
"author": "RJ Dellecese",
|
|
6
6
|
"bugs": {
|
|
7
7
|
"url": "https://github.com/rjdellecese/confect/issues"
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
"convex": "^1.30.0",
|
|
62
62
|
"effect": "^3.21.2",
|
|
63
63
|
"react": "^18.0.0 || ^19.0.0",
|
|
64
|
-
"@confect/core": "^9.0.0-next.
|
|
64
|
+
"@confect/core": "^9.0.0-next.8"
|
|
65
65
|
},
|
|
66
66
|
"repository": {
|
|
67
67
|
"type": "git",
|
package/src/QueryResult.ts
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { identity } from "effect/Function";
|
|
2
|
+
import * as Equal from "effect/Equal";
|
|
3
|
+
import * as Function from "effect/Function";
|
|
4
|
+
import * as Hash from "effect/Hash";
|
|
5
|
+
import * as Pipeable from "effect/Pipeable";
|
|
6
|
+
import * as Predicate from "effect/Predicate";
|
|
2
7
|
|
|
3
8
|
const TypeId = "@confect/react/QueryResult";
|
|
4
9
|
type TypeId = typeof TypeId;
|
package/src/index.ts
CHANGED
|
@@ -4,7 +4,11 @@ import {
|
|
|
4
4
|
useMutation as useConvexMutation,
|
|
5
5
|
useQuery as useConvexQuery,
|
|
6
6
|
} from "convex/react";
|
|
7
|
-
import
|
|
7
|
+
import * as Cause from "effect/Cause";
|
|
8
|
+
import * as Effect from "effect/Effect";
|
|
9
|
+
import * as Either from "effect/Either";
|
|
10
|
+
import * as Exit from "effect/Exit";
|
|
11
|
+
import * as Option from "effect/Option";
|
|
8
12
|
import { useCallback, useMemo } from "react";
|
|
9
13
|
|
|
10
14
|
import * as QueryResult from "./QueryResult";
|