@effect-app/vue 2.73.2 → 2.74.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/src/makeClient.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  /* eslint-disable @typescript-eslint/no-explicit-any */
2
2
  import * as Result from "@effect-atom/atom/Result"
3
3
  import { type InitialDataFunction, type InvalidateOptions, type InvalidateQueryFilters, isCancelledError, type QueryObserverResult, type RefetchOptions, type UseQueryReturnType } from "@tanstack/vue-query"
4
- import { Cause, Effect, Exit, Layer, ManagedRuntime, Match, Option, Runtime, S, Struct } from "effect-app"
4
+ import { Cause, Effect, Exit, type ManagedRuntime, Match, Option, Runtime, S, Struct } from "effect-app"
5
5
  import type { RequestHandler, RequestHandlers, RequestHandlerWithInput, Requests, TaggedRequestClassAny } from "effect-app/client/clientFor"
6
6
  import { ErrorSilenced, type SupportedErrors } from "effect-app/client/errors"
7
7
  import { constant, identity, pipe, tuple } from "effect-app/Function"
@@ -9,11 +9,10 @@ import { type OperationFailure, OperationSuccess } from "effect-app/Operations"
9
9
  import type { Schema } from "effect-app/Schema"
10
10
  import { dropUndefinedT } from "effect-app/utils"
11
11
  import { type RuntimeFiber } from "effect/Fiber"
12
- import { computed, type ComputedRef, getCurrentInstance, onBeforeUnmount, onUnmounted, type Ref, ref, watch, type WatchSource } from "vue"
12
+ import { computed, type ComputedRef, onBeforeUnmount, type Ref, ref, watch, type WatchSource } from "vue"
13
13
  import { reportMessage } from "./errorReporter.js"
14
14
  import { Commander, CommanderStatic } from "./experimental/commander.js"
15
15
  import { I18n } from "./experimental/intl.js"
16
- import { makeUseCommand } from "./experimental/makeUseCommand.js"
17
16
  import { Toast } from "./experimental/toast.js"
18
17
  import { buildFieldInfoFromFieldsRoot } from "./form.js"
19
18
  import { reportRuntimeError } from "./lib.js"
@@ -215,6 +214,33 @@ export const useMutation: typeof _useMutation = <
215
214
  { id: self.id }
216
215
  )
217
216
 
217
+ /**
218
+ * Pass an Effect or a function that returns an Effect, e.g from a client action
219
+ * Executes query cache invalidation based on default rules or provided option.
220
+ * adds a span with the mutation id
221
+ */
222
+ export const useMutationInt = (): typeof _useMutation => {
223
+ const _useMutation = makeMutation()
224
+ return <
225
+ I,
226
+ E,
227
+ A,
228
+ R,
229
+ Request extends TaggedRequestClassAny,
230
+ Name extends string
231
+ >(
232
+ self: RequestHandlerWithInput<I, A, E, R, Request, Name> | RequestHandler<A, E, R, Request, Name>,
233
+ options?: MutationOptionsBase
234
+ ) =>
235
+ Object.assign(
236
+ mapHandler(
237
+ _useMutation(self as any, options),
238
+ Effect.withSpan(`mutation ${self.id}`, { captureStackTrace: false })
239
+ ) as any,
240
+ { id: self.id }
241
+ )
242
+ }
243
+
218
244
  // @effect-diagnostics-next-line missingEffectServiceDependency:off
219
245
  export class LegacyMutation extends Effect.Service<LegacyMutation>()("LegacyMutation", {
220
246
  effect: Effect.gen(function*() {
@@ -980,62 +1006,36 @@ const mkQuery = <R>(getRuntime: () => Runtime.Runtime<R>) => {
980
1006
  const managedRuntimeRt = <A, E>(mrt: ManagedRuntime.ManagedRuntime<A, E>) => mrt.runSync(Effect.runtime<A>())
981
1007
 
982
1008
  type Base = I18n | Toast
983
- export const makeClient = <RT, RE, RL>(
1009
+ export const makeClient = <RT>(
984
1010
  // global, but only accessible after startup has completed
985
- getBaseMrt: () => ManagedRuntime.ManagedRuntime<RT | ApiClientFactory, never>,
986
- rootLayer: Layer.Layer<RL | Base, RE>,
1011
+ getBaseMrt: () => ManagedRuntime.ManagedRuntime<RT | ApiClientFactory | Commander | LegacyMutation | Base, never>,
987
1012
  clientFor_: ReturnType<typeof ApiClientFactory["makeFor"]>
988
1013
  ) => {
1014
+ const getRt = Effect.runtime<RT | ApiClientFactory | Commander | LegacyMutation | Base>()
989
1015
  const getBaseRt = () => managedRuntimeRt(getBaseMrt())
990
-
991
- // we want to create a managed runtime for query, command and mutation hooks, one per component instance
992
- const getRt = () => {
993
- const instance = getCurrentInstance() as {
994
- __effa?: {
995
- rt: ManagedRuntime.ManagedRuntime<Base, RE>
996
- rts: Map<string, any>
997
- }
998
- }
999
- if (!instance.__effa) {
1000
- const rt = ManagedRuntime.make(rootLayer, getBaseMrt().memoMap)
1001
- instance.__effa = { rt, rts: new Map() }
1002
- onUnmounted(() => rt.dispose())
1016
+ const makeCommand = Effect.gen(function*() {
1017
+ const cmd = yield* Commander
1018
+ const rt = yield* getRt
1019
+ return {
1020
+ fn: cmd.fn(rt),
1021
+ wrap: cmd.wrap(rt),
1022
+ alt: cmd.alt(rt),
1023
+ alt2: cmd.alt2(rt)
1003
1024
  }
1004
- return instance.__effa
1005
- }
1025
+ })
1026
+ const makeMutation = Effect.gen(function*() {
1027
+ const mut = yield* LegacyMutation
1006
1028
 
1007
- const makeRuntime = <A, E>(l: Layer.Layer<A, E, Base>) => {
1008
- const ctx = getRt()
1009
- const rt = ManagedRuntime.make(Layer.mergeAll(l.pipe(Layer.provide(rootLayer)), rootLayer), ctx.rt.memoMap)
1010
- onUnmounted(() => rt.dispose())
1011
- return rt
1012
- }
1029
+ return mut(() => getBaseMrt().runSync(getRt))
1030
+ })
1031
+ let cmd: Effect.Effect.Success<typeof makeCommand>
1032
+ const useCommand = () => cmd ??= getBaseMrt().runSync(makeCommand)
1033
+ let mut: Effect.Effect.Success<typeof makeMutation>
1034
+ const getMutation = () => mut ??= getBaseMrt().runSync(makeMutation)
1013
1035
 
1014
- const get = <A>(key: string, maker: () => A) => {
1015
- const ctx = getRt()
1016
- const existing = ctx.rts.get(key)
1017
- if (existing) {
1018
- return existing as A
1019
- }
1036
+ let m: ReturnType<typeof useMutationInt>
1037
+ const useMutation = () => m ??= useMutationInt()
1020
1038
 
1021
- const made = maker()
1022
- ctx.rts.set(key, made)
1023
- return made
1024
- }
1025
- // const getQuery = () => get("query", LegacyQuery.Default)
1026
- const getMutation = () =>
1027
- get("mutation", () => {
1028
- const mrt = makeRuntime(LegacyMutation.Default)
1029
- const mut = mrt.runSync(LegacyMutation)
1030
- const rt = managedRuntimeRt(mrt)
1031
- return mut(() => rt)
1032
- })
1033
- const useCommand = () =>
1034
- get("command", () => {
1035
- const mrt = makeRuntime(Commander.Default)
1036
- const cmd = mrt.runSync(makeUseCommand())
1037
- return cmd
1038
- })
1039
1039
  const keys: readonly (keyof ReturnType<typeof getMutation>)[] = [
1040
1040
  "useSafeMutationWithState",
1041
1041
  "useAndHandleMutation",
@@ -1058,15 +1058,11 @@ export const makeClient = <RT, RE, RL>(
1058
1058
  },
1059
1059
  {} as { [K in keyof mut]: mut[K] }
1060
1060
  )
1061
+
1061
1062
  const query = mkQuery(getBaseRt)
1062
1063
  const useQuery = query.useQuery
1063
1064
  const useSuspenseQuery = query.useSuspenseQuery
1064
1065
 
1065
- // Glorious rpc client helpers
1066
- // TODO:
1067
- // - reusable; extract to lib
1068
- // - reduce duplication for Types
1069
-
1070
1066
  const mapQuery = <M extends Requests>(
1071
1067
  client: ClientFrom<M>
1072
1068
  ) => {
@@ -1108,9 +1104,10 @@ export const makeClient = <RT, RE, RL>(
1108
1104
  const Command = useCommand()
1109
1105
  const wrap = Command.wrap
1110
1106
  const fn_ = Command.fn
1107
+ const mutation = useMutation()
1111
1108
  const mutations = Struct.keys(client).reduce(
1112
1109
  (acc, key) => {
1113
- const mut = useMutation(client[key] as any)
1110
+ const mut = mutation(client[key] as any)
1114
1111
  const fn = fn_(client[key].id)
1115
1112
  ;(acc as any)[camelCase(key) + "Mutation"] = Object.assign(
1116
1113
  mut,
@@ -1123,7 +1120,7 @@ export const makeClient = <RT, RE, RL>(
1123
1120
  [Key in keyof typeof client as `${ToCamel<string & Key>}Mutation`]:
1124
1121
  & (typeof client[Key] extends
1125
1122
  RequestHandlerWithInput<infer I, infer A, infer E, infer R, infer Request, infer Id> ?
1126
- & ReturnType<typeof useMutation<I, E, A, R, Request, Id>>
1123
+ & ReturnType<typeof mutation<I, E, A, R, Request, Id>>
1127
1124
  & (typeof client[Key] extends
1128
1125
  RequestHandlerWithInput<infer _I, infer _A, infer _E, infer _R, infer _Request, infer Id>
1129
1126
  ? Commander.CommandContextLocal<Id, Id>
@@ -1131,7 +1128,7 @@ export const makeClient = <RT, RE, RL>(
1131
1128
  ? Commander.CommandContextLocal<Id, Id>
1132
1129
  : never)
1133
1130
  : typeof client[Key] extends RequestHandler<infer A, infer E, infer R, infer Request, infer Id> ?
1134
- & ReturnType<typeof useMutation<E, A, R, Request, Id>>
1131
+ & ReturnType<typeof mutation<E, A, R, Request, Id>>
1135
1132
  & (typeof client[Key] extends
1136
1133
  RequestHandlerWithInput<infer _I, infer _A, infer _E, infer _R, infer _Request, infer Id>
1137
1134
  ? Commander.CommandContextLocal<Id, Id>
@@ -1147,9 +1144,9 @@ export const makeClient = <RT, RE, RL>(
1147
1144
  : never)
1148
1145
  & (typeof client[Key] extends
1149
1146
  RequestHandlerWithInput<infer I, infer A, infer E, infer R, infer Request, infer Id>
1150
- ? ReturnType<typeof useMutation<I, E, A, R, Request, Id>>
1147
+ ? ReturnType<typeof mutation<I, E, A, R, Request, Id>>
1151
1148
  : typeof client[Key] extends RequestHandler<infer A, infer E, infer R, infer Request, infer Id>
1152
- ? ReturnType<typeof useMutation<E, A, R, Request, Id>>
1149
+ ? ReturnType<typeof mutation<E, A, R, Request, Id>>
1153
1150
  : never)
1154
1151
  & {
1155
1152
  wrap: typeof client[Key] extends
@@ -1179,6 +1176,7 @@ export const makeClient = <RT, RE, RL>(
1179
1176
  client: ClientFrom<M>
1180
1177
  ) => {
1181
1178
  const Command = useCommand()
1179
+ const mutation = useMutation()
1182
1180
  const wrap = Command.wrap
1183
1181
  const fn_ = Command.fn
1184
1182
  const invalidation = queryInvalidation?.(client)
@@ -1191,7 +1189,7 @@ export const makeClient = <RT, RE, RL>(
1191
1189
  query: useQuery(client[key] as any),
1192
1190
  suspense: useSuspenseQuery(client[key] as any)
1193
1191
  }
1194
- const mutate = useMutation(
1192
+ const mutate = mutation(
1195
1193
  client[key] as any,
1196
1194
  invalidation?.[key] ? { queryInvalidation: invalidation[key] } : undefined
1197
1195
  )
@@ -1214,9 +1212,9 @@ export const makeClient = <RT, RE, RL>(
1214
1212
  : never)
1215
1213
  & (typeof client[Key] extends
1216
1214
  RequestHandlerWithInput<infer I, infer A, infer E, infer R, infer Request, infer Id>
1217
- ? ReturnType<typeof useMutation<I, E, A, R, Request, Id>>
1215
+ ? ReturnType<typeof mutation<I, E, A, R, Request, Id>>
1218
1216
  : typeof client[Key] extends RequestHandler<infer A, infer E, infer R, infer Request, infer Id>
1219
- ? ReturnType<typeof useMutation<E, A, R, Request, Id>>
1217
+ ? ReturnType<typeof mutation<E, A, R, Request, Id>>
1220
1218
  : never)
1221
1219
  & {
1222
1220
  wrap: typeof client[Key] extends
@@ -1304,6 +1302,7 @@ export const makeClient = <RT, RE, RL>(
1304
1302
  const Command = {
1305
1303
  fn: (...args: [any]) => useCommand().fn(...args),
1306
1304
  wrap: (...args: [any]) => useCommand().wrap(...args),
1305
+ alt: (...args: [any]) => useCommand().alt(...args),
1307
1306
  alt2: (...args: [any]) => useCommand().alt2(...args),
1308
1307
  ...CommanderStatic
1309
1308
  } as ReturnType<typeof useCommand>
package/src/mutate.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  /* eslint-disable @typescript-eslint/no-explicit-any */
2
2
  import * as Result from "@effect-atom/atom/Result"
3
- import { type InvalidateOptions, type InvalidateQueryFilters, useQueryClient } from "@tanstack/vue-query"
3
+ import { type InvalidateOptions, type InvalidateQueryFilters, type QueryClient, useQueryClient } from "@tanstack/vue-query"
4
4
  import { type Cause, Effect, type Exit, Option } from "effect-app"
5
5
  import type { ClientForOptions, RequestHandler, RequestHandlerWithInput, TaggedRequestClassAny } from "effect-app/client/clientFor"
6
6
  import { tuple } from "effect-app/Function"
@@ -141,12 +141,11 @@ export const asResult: {
141
141
  return tuple(computed(() => state.value), act) as any
142
142
  }
143
143
 
144
- export const useInvalidateQueries = (
144
+ export const invalidateQueries = (
145
+ queryClient: QueryClient,
145
146
  self: { id: string; options?: ClientForOptions },
146
147
  options?: MutationOptionsBase["queryInvalidation"]
147
148
  ) => {
148
- const queryClient = useQueryClient()
149
-
150
149
  const invalidateQueries = (
151
150
  filters?: InvalidateQueryFilters,
152
151
  options?: InvalidateOptions
@@ -191,6 +190,8 @@ export const useInvalidateQueries = (
191
190
  }
192
191
 
193
192
  export const makeMutation = () => {
193
+ const queryClient = useQueryClient()
194
+
194
195
  const useMutation: {
195
196
  /**
196
197
  * Pass a function that returns an Effect, e.g from a client action
@@ -212,7 +213,7 @@ export const makeMutation = () => {
212
213
  self: RequestHandlerWithInput<I, A, E, R, Request, Id> | RequestHandler<A, E, R, Request, Id>,
213
214
  options?: MutationOptionsBase
214
215
  ) => {
215
- const handle = useInvalidateQueries(self, options?.queryInvalidation)
216
+ const handle = invalidateQueries(queryClient, self, options?.queryInvalidation)
216
217
  const handler = self.handler
217
218
  const r = Effect.isEffect(handler) ? handle(handler) : (i: I) => handle(handler(i))
218
219
 
@@ -26,18 +26,18 @@ export declare const useExperimental: (options?: {
26
26
  fn: <const Id extends string, const I18nKey_1 extends string = Id>(id: Id | {
27
27
  id: Id;
28
28
  }, customI18nKey?: I18nKey_1 | undefined) => Commander.Gen<Toast.Toast | I18n | WithToast, Id, I18nKey_1> & Commander.NonGen<Toast.Toast | I18n | WithToast, Id, I18nKey_1>;
29
- wrap: <const Id extends string, Args_3 extends Array<unknown>, A_1, E_3, R_4, I18nKey_2 extends string = Id>(mutation: (((...args: Args_3) => Effect.Effect<A_1, E_3, R_4>) & {
30
- id: Id;
31
- }) | {
29
+ wrap: <const Id extends string, Args_3 extends Array<unknown>, A_1, E_3, R_4, I18nKey_2 extends string = Id>(mutation: {
32
30
  mutate: (...args: Args_3) => Effect.Effect<A_1, E_3, R_4>;
33
31
  id: Id;
34
- }, customI18nKey?: I18nKey_2 | undefined) => Commander.CommandContextLocal<Id, I18nKey_2> & Commander.GenWrap<Toast.Toast | I18n | WithToast, Id, I18nKey_2, Args_3, A_1, E_3, R_4> & Commander.NonGenWrap<Toast.Toast | I18n | WithToast, Id, I18nKey_2, Args_3, A_1, E_3, R_4>;
35
- alt2: <const Id extends string, MutArgs extends Array<unknown>, MutA, MutE, MutR, const I18nKey_3 extends string = Id>(id: Id | (((...args: MutArgs) => Effect.Effect<MutA, MutE, MutR>) & {
32
+ } | (((...args: Args_3) => Effect.Effect<A_1, E_3, R_4>) & {
36
33
  id: Id;
37
- }) | {
34
+ }), customI18nKey?: I18nKey_2 | undefined) => Commander.CommandContextLocal<Id, I18nKey_2> & Commander.GenWrap<Toast.Toast | I18n | WithToast, Id, I18nKey_2, Args_3, A_1, E_3, R_4> & Commander.NonGenWrap<Toast.Toast | I18n | WithToast, Id, I18nKey_2, Args_3, A_1, E_3, R_4>;
35
+ alt2: <const Id extends string, MutArgs extends Array<unknown>, MutA, MutE, MutR, const I18nKey_3 extends string = Id>(id: Id | {
38
36
  id: Id;
39
37
  mutate: (...args: MutArgs) => Effect.Effect<MutA, MutE, MutR>;
40
- }, customI18nKey?: I18nKey_3 | undefined) => Commander.CommandContextLocal<Id, I18nKey_3> & (<Args_4 extends Array<unknown>, A_2, E_4, R_5 extends Toast.Toast | I18n | WithToast | import("../src/experimental/commander.js").CommandContext>(handler: (ctx: Effect.fn.Gen & Effect.fn.NonGen & Commander.CommandContextLocal<Id, I18nKey_3> & {
38
+ } | (((...args: MutArgs) => Effect.Effect<MutA, MutE, MutR>) & {
39
+ id: Id;
40
+ }), customI18nKey?: I18nKey_3 | undefined) => Commander.CommandContextLocal<Id, I18nKey_3> & (<Args_4 extends Array<unknown>, A_2, E_4, R_5 extends Toast.Toast | I18n | WithToast | import("../src/experimental/commander.js").CommandContext>(handler: (ctx: Effect.fn.Gen & Effect.fn.NonGen & Commander.CommandContextLocal<Id, I18nKey_3> & {
41
41
  mutate: (...args: MutArgs) => Effect.Effect<MutA, MutE, MutR>;
42
42
  }) => (...args: Args_4) => Effect.Effect<A_2, E_4, R_5>) => Commander.CommandOut<Args_4, A_2, E_4, R_5, Id, I18nKey_3>);
43
43
  _tag: "Commander";