wellcrafted 0.41.0 → 0.42.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/README.md CHANGED
@@ -210,7 +210,7 @@ getUser(orderId); // type error
210
210
 
211
211
  ### Query Integration
212
212
 
213
- TanStack Query factories with a dual interface: `.options` for reactive components, callable for imperative use in event handlers.
213
+ TanStack Query factories with `.options` for reactive components and explicit imperative helpers for event handlers.
214
214
 
215
215
  ```typescript
216
216
  import { createQueryFactories } from "wellcrafted/query";
@@ -222,10 +222,10 @@ const userQuery = defineQuery({
222
222
  queryFn: () => getUser(userId), // returns Result<User, UserError>
223
223
  });
224
224
 
225
- // Reactive pass to useQuery (React) or createQuery (Svelte)
225
+ // Reactive: pass to useQuery (React) or createQuery (Svelte)
226
226
  const query = createQuery(() => userQuery.options);
227
227
 
228
- // Imperative direct execution for event handlers
228
+ // Imperative: choose the query read policy explicitly
229
229
  const { data, error } = await userQuery.fetch();
230
230
  ```
231
231
 
@@ -273,8 +273,8 @@ The same principle applies throughout: async/await instead of generators, `switc
273
273
  ### Query functions
274
274
 
275
275
  - **`createQueryFactories(client)`** — create query/mutation factories for TanStack Query
276
- - **`defineQuery(options)`** define a query with dual interface (`.options` for reactive, callable for imperative)
277
- - **`defineMutation(options)`** define a mutation with dual interface
276
+ - **`defineQuery(options)`**: define a query with `.options`, `.fetch()`, and `.ensure()`
277
+ - **`defineMutation(options)`**: define a callable mutation with `.options` for hooks
278
278
 
279
279
  ### Standard Schema
280
280
 
@@ -299,7 +299,7 @@ This installs 5 skills that teach your agent the patterns, anti-patterns, and AP
299
299
  | --- | --- |
300
300
  | `define-errors` | `defineErrors` variants, `extractErrorMessage`, `InferErrors`/`InferError` type extraction |
301
301
  | `result-types` | `Ok`, `Err`, `trySync`/`tryAsync`, the `{ data, error }` destructuring pattern |
302
- | `query-factories` | `createQueryFactories`, `defineQuery`/`defineMutation`, dual interface (reactive + imperative) |
302
+ | `query-factories` | `createQueryFactories`, `defineQuery`/`defineMutation`, reactive options, and imperative helpers |
303
303
  | `branded-types` | `Brand<T>`, brand constructor pattern, when to add runtime validation |
304
304
  | `patterns` | Architectural style guide: control flow, factory composition, service layers, error composition |
305
305
 
@@ -1,7 +1,7 @@
1
1
  import { Result } from "../result-DKwq9BCr.js";
2
2
  import "../tap-err-CFhHBPfH.js";
3
3
  import "../index-DnoV2ZDO.js";
4
- import { DefaultError, MutationKey, MutationOptions, QueryClient, QueryFunction, QueryKey, QueryObserverOptions } from "@tanstack/query-core";
4
+ import { DefaultError, MutationKey, MutationObserverOptions, QueryClient, QueryFunction, QueryKey, QueryObserverOptions } from "@tanstack/query-core";
5
5
 
6
6
  //#region src/query/utils.d.ts
7
7
 
@@ -25,8 +25,8 @@ type QueryOptionsInput<TQueryFnData = unknown, TError = DefaultError, TData = TQ
25
25
  /**
26
26
  * Input for `mutationOptions` and `defineMutation`.
27
27
  *
28
- * Mirrors TanStack Query's `MutationOptions` but expects `mutationFn` to
29
- * return a Wellcrafted `Result`. The Result is unwrapped into TanStack's
28
+ * Mirrors TanStack Query's `MutationObserverOptions` but expects `mutationFn`
29
+ * to return a Wellcrafted `Result`. The Result is unwrapped into TanStack's
30
30
  * throwing data/error contract by `mutationOptions`.
31
31
  *
32
32
  * @template TData - The success type produced by `mutationFn`
@@ -35,7 +35,7 @@ type QueryOptionsInput<TQueryFnData = unknown, TError = DefaultError, TData = TQ
35
35
  * @template TContext - The context type for optimistic updates
36
36
  * @template TMutationKey - The literal mutation key tuple
37
37
  */
38
- type MutationOptionsInput<TData, TError, TVariables = void, TContext = unknown, TMutationKey extends MutationKey = MutationKey> = Omit<MutationOptions<TData, TError, TVariables, TContext>, "mutationFn"> & {
38
+ type MutationOptionsInput<TData, TError, TVariables = void, TContext = unknown, TMutationKey extends MutationKey = MutationKey> = Omit<MutationObserverOptions<TData, TError, TVariables, TContext>, "mutationFn"> & {
39
39
  mutationKey: TMutationKey;
40
40
  mutationFn: (variables: TVariables) => Result<TData, TError> | Promise<Result<TData, TError>>;
41
41
  };
@@ -85,22 +85,20 @@ declare function queryOptions<TQueryFnData = unknown, TError = DefaultError, TDa
85
85
  * returns is the same shape `mutationOptions` produces.
86
86
  *
87
87
  * @param input - Result-aware mutation configuration
88
- * @returns TanStack Query `MutationOptions` with `mutationFn` rewired to
89
- * resolve `Ok` and throw `Err`
88
+ * @returns TanStack Query `MutationObserverOptions` with `mutationFn` rewired
89
+ * to resolve `Ok` and throw `Err`
90
90
  */
91
- declare function mutationOptions<TData, TError, TVariables = void, TContext = unknown, const TMutationKey extends MutationKey = MutationKey>(input: MutationOptionsInput<TData, TError, TVariables, TContext, TMutationKey>): MutationOptions<TData, TError, TVariables, TContext>;
91
+ declare function mutationOptions<TData, TError, TVariables = void, TContext = unknown, const TMutationKey extends MutationKey = MutationKey>(input: MutationOptionsInput<TData, TError, TVariables, TContext, TMutationKey>): MutationObserverOptions<TData, TError, TVariables, TContext>;
92
92
  /**
93
93
  * Output of `defineQuery`.
94
94
  *
95
- * The returned object is directly callable and defaults to `ensure()` behavior,
96
- * which is recommended for most imperative use cases like preloaders.
95
+ * Query imperative reads require an explicit cache policy.
97
96
  *
98
- * - `()` (callable): Same as `ensure()`. Returns cached data if available.
99
97
  * - `options`: Options shape produced by `queryOptions`, ready for hooks.
100
98
  * - `fetch()`: Always evaluates freshness; refetches if stale.
101
99
  * - `ensure()`: Prefers cached data; fetches only when missing.
102
100
  */
103
- type DefineQueryOutput<TQueryFnData = unknown, TError = DefaultError, TData = TQueryFnData, TQueryData = TQueryFnData, TQueryKey extends QueryKey = QueryKey> = (() => Promise<Result<TQueryData, TError>>) & {
101
+ type DefineQueryOutput<TQueryFnData = unknown, TError = DefaultError, TData = TQueryFnData, TQueryData = TQueryFnData, TQueryKey extends QueryKey = QueryKey> = {
104
102
  options: QueryObserverOptions<TQueryFnData, TError, TData, TQueryData, TQueryKey>;
105
103
  fetch: () => Promise<Result<TQueryData, TError>>;
106
104
  ensure: () => Promise<Result<TQueryData, TError>>;
@@ -108,23 +106,20 @@ type DefineQueryOutput<TQueryFnData = unknown, TError = DefaultError, TData = TQ
108
106
  /**
109
107
  * Output of `defineMutation`.
110
108
  *
111
- * The returned object is directly callable and executes the mutation,
112
- * equivalent to calling `.execute()`.
109
+ * The returned function directly executes the mutation.
113
110
  *
114
- * - `(variables)` (callable): Same as `execute(variables)`.
111
+ * - `(variables)` (callable): Imperatively runs the mutation, returning a Result.
115
112
  * - `options`: Options shape produced by `mutationOptions`, ready for hooks.
116
- * - `execute(variables)`: Imperatively runs the mutation, returning a Result.
117
113
  */
118
114
  type DefineMutationOutput<TData, TError, TVariables = void, TContext = unknown> = ((variables: TVariables) => Promise<Result<TData, TError>>) & {
119
- options: MutationOptions<TData, TError, TVariables, TContext>;
120
- execute: (variables: TVariables) => Promise<Result<TData, TError>>;
115
+ options: MutationObserverOptions<TData, TError, TVariables, TContext>;
121
116
  };
122
117
  /**
123
118
  * Creates `defineQuery` and `defineMutation` bound to a specific `QueryClient`.
124
119
  *
125
120
  * Use this when you want a reusable query/mutation definition that carries
126
- * its own imperative helpers (`.fetch`, `.ensure`, `.execute`, callable form)
127
- * powered by a specific client. For local one-shot options that only need
121
+ * its own imperative query helpers (`.fetch`, `.ensure`) and callable mutation
122
+ * execution powered by a specific client. For local one-shot options that only need
128
123
  * to flow into a framework hook, prefer `queryOptions` / `mutationOptions`
129
124
  * directly: those are platform-agnostic and do not require a `QueryClient`.
130
125
  *
@@ -185,5 +180,5 @@ declare function createQueryFactories(queryClient: QueryClient): {
185
180
  */
186
181
  declare function defineKeys<const TKeys extends Record<string, readonly [unknown, ...unknown[]] | ((...args: never[]) => readonly [unknown, ...unknown[]])>>(keys: TKeys): TKeys;
187
182
  //#endregion
188
- export { MutationOptionsInput, QueryOptionsInput, createQueryFactories, defineKeys, mutationOptions, queryOptions };
183
+ export { createQueryFactories, defineKeys, mutationOptions, queryOptions };
189
184
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../../src/query/utils.ts"],"sourcesContent":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../src/query/utils.ts"],"sourcesContent":[],"mappings":"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"}
@@ -54,8 +54,8 @@ function queryOptions(input) {
54
54
  * returns is the same shape `mutationOptions` produces.
55
55
  *
56
56
  * @param input - Result-aware mutation configuration
57
- * @returns TanStack Query `MutationOptions` with `mutationFn` rewired to
58
- * resolve `Ok` and throw `Err`
57
+ * @returns TanStack Query `MutationObserverOptions` with `mutationFn` rewired
58
+ * to resolve `Ok` and throw `Err`
59
59
  */
60
60
  function mutationOptions(input) {
61
61
  return {
@@ -67,8 +67,8 @@ function mutationOptions(input) {
67
67
  * Creates `defineQuery` and `defineMutation` bound to a specific `QueryClient`.
68
68
  *
69
69
  * Use this when you want a reusable query/mutation definition that carries
70
- * its own imperative helpers (`.fetch`, `.ensure`, `.execute`, callable form)
71
- * powered by a specific client. For local one-shot options that only need
70
+ * its own imperative query helpers (`.fetch`, `.ensure`) and callable mutation
71
+ * execution powered by a specific client. For local one-shot options that only need
72
72
  * to flow into a framework hook, prefer `queryOptions` / `mutationOptions`
73
73
  * directly: those are platform-agnostic and do not require a `QueryClient`.
74
74
  *
@@ -100,43 +100,34 @@ function createQueryFactories(queryClient) {
100
100
  const options = queryOptions(input);
101
101
  async function fetch() {
102
102
  try {
103
- return Ok(await queryClient.fetchQuery({
104
- queryKey: options.queryKey,
105
- queryFn: options.queryFn
106
- }));
103
+ return Ok(await queryClient.fetchQuery(options));
107
104
  } catch (error) {
108
105
  return Err(error);
109
106
  }
110
107
  }
111
108
  async function ensure() {
112
109
  try {
113
- return Ok(await queryClient.ensureQueryData({
114
- queryKey: options.queryKey,
115
- queryFn: options.queryFn
116
- }));
110
+ return Ok(await queryClient.ensureQueryData(options));
117
111
  } catch (error) {
118
112
  return Err(error);
119
113
  }
120
114
  }
121
- return Object.assign(ensure, {
115
+ return {
122
116
  options,
123
117
  fetch,
124
118
  ensure
125
- });
119
+ };
126
120
  };
127
121
  const defineMutation = (input) => {
128
122
  const options = mutationOptions(input);
129
- async function execute(variables) {
123
+ async function run(variables) {
130
124
  try {
131
125
  return Ok(await runMutation(queryClient, options, variables));
132
126
  } catch (error) {
133
127
  return Err(error);
134
128
  }
135
129
  }
136
- return Object.assign(execute, {
137
- options,
138
- execute
139
- });
130
+ return Object.assign(run, { options });
140
131
  };
141
132
  return {
142
133
  defineQuery,
@@ -145,8 +136,8 @@ function createQueryFactories(queryClient) {
145
136
  }
146
137
  /**
147
138
  * Internal helper that executes a mutation directly using the query client's
148
- * mutation cache. Powers the callable behavior and `.execute()` method on
149
- * mutations returned from `defineMutation`.
139
+ * mutation cache. Powers the callable behavior on mutations returned from
140
+ * `defineMutation`.
150
141
  *
151
142
  * @internal
152
143
  */
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["input: QueryOptionsInput<TQueryFnData, TError, TData, TQueryData, TQueryKey>","input: MutationOptionsInput<\n\t\tTData,\n\t\tTError,\n\t\tTVariables,\n\t\tTContext,\n\t\tTMutationKey\n\t>","variables: TVariables","queryClient: QueryClient","input: QueryOptionsInput<\n\t\t\tTQueryFnData,\n\t\t\tTError,\n\t\t\tTData,\n\t\t\tTQueryData,\n\t\t\tTQueryKey\n\t\t>","input: MutationOptionsInput<\n\t\t\tTData,\n\t\t\tTError,\n\t\t\tTVariables,\n\t\t\tTContext,\n\t\t\tTMutationKey\n\t\t>","options: MutationOptions<TData, TError, TVariables, TContext>","keys: TKeys"],"sources":["../../src/query/utils.ts"],"sourcesContent":["import type {\n\tDefaultError,\n\tMutationKey,\n\tMutationOptions,\n\tQueryClient,\n\tQueryFunction,\n\tQueryKey,\n\tQueryObserverOptions,\n} from \"@tanstack/query-core\";\nimport { Err, Ok, type Result, resolve } from \"../result/index.js\";\n\n/**\n * Input for `queryOptions` and `defineQuery`.\n *\n * Mirrors TanStack Query's `QueryObserverOptions` but expects `queryFn` to\n * return a Wellcrafted `Result`. The Result is unwrapped into TanStack's\n * throwing data/error contract by `queryOptions`.\n *\n * @template TQueryFnData - The success type produced by `queryFn`\n * @template TError - The error type carried by the Result\n * @template TData - The type seen by consumers after `select`\n * @template TQueryData - The type stored in the cache (usually `TQueryFnData`)\n * @template TQueryKey - The literal query key tuple\n */\nexport type QueryOptionsInput<\n\tTQueryFnData = unknown,\n\tTError = DefaultError,\n\tTData = TQueryFnData,\n\tTQueryData = TQueryFnData,\n\tTQueryKey extends QueryKey = QueryKey,\n> = Omit<\n\tQueryObserverOptions<TQueryFnData, TError, TData, TQueryData, TQueryKey>,\n\t\"queryFn\"\n> & {\n\tqueryKey: TQueryKey;\n\tqueryFn: QueryFunction<Result<TQueryFnData, TError>, TQueryKey>;\n};\n\n/**\n * Input for `mutationOptions` and `defineMutation`.\n *\n * Mirrors TanStack Query's `MutationOptions` but expects `mutationFn` to\n * return a Wellcrafted `Result`. The Result is unwrapped into TanStack's\n * throwing data/error contract by `mutationOptions`.\n *\n * @template TData - The success type produced by `mutationFn`\n * @template TError - The error type carried by the Result\n * @template TVariables - The variables passed to `mutationFn`\n * @template TContext - The context type for optimistic updates\n * @template TMutationKey - The literal mutation key tuple\n */\nexport type MutationOptionsInput<\n\tTData,\n\tTError,\n\tTVariables = void,\n\tTContext = unknown,\n\tTMutationKey extends MutationKey = MutationKey,\n> = Omit<MutationOptions<TData, TError, TVariables, TContext>, \"mutationFn\"> & {\n\tmutationKey: TMutationKey;\n\tmutationFn: (\n\t\tvariables: TVariables,\n\t) => Result<TData, TError> | Promise<Result<TData, TError>>;\n};\n\n/**\n * Adapter from a Result-returning query function to TanStack Query options.\n *\n * This is the single canonical place where `Result<TQueryFnData, TError>`\n * is converted into TanStack's contract: `Ok(data)` resolves with `data`,\n * `Err(error)` throws `error` into the query error channel.\n *\n * Use this directly with framework hooks when you do not need the\n * `QueryClient`-bound imperative helpers from `defineQuery`:\n *\n * ```ts\n * const query = createQuery(() => queryOptions({\n * queryKey: ['user', userId],\n * queryFn: () => services.getUser(userId),\n * }));\n * ```\n *\n * `defineQuery` composes through this helper, so the `.options` it returns\n * is the same shape `queryOptions` produces.\n *\n * @param input - Result-aware query configuration\n * @returns TanStack Query `QueryObserverOptions` with `queryFn` rewired to\n * resolve `Ok` and throw `Err`\n */\nexport function queryOptions<\n\tTQueryFnData = unknown,\n\tTError = DefaultError,\n\tTData = TQueryFnData,\n\tTQueryData = TQueryFnData,\n\tconst TQueryKey extends QueryKey = QueryKey,\n>(\n\tinput: QueryOptionsInput<TQueryFnData, TError, TData, TQueryData, TQueryKey>,\n): QueryObserverOptions<TQueryFnData, TError, TData, TQueryData, TQueryKey> {\n\treturn {\n\t\t...input,\n\t\tqueryFn: async (context) => resolve(await input.queryFn(context)),\n\t} satisfies QueryObserverOptions<\n\t\tTQueryFnData,\n\t\tTError,\n\t\tTData,\n\t\tTQueryData,\n\t\tTQueryKey\n\t>;\n}\n\n/**\n * Adapter from a Result-returning mutation function to TanStack Query options.\n *\n * This is the single canonical place where `Result<TData, TError>` is\n * converted into TanStack's contract: `Ok(data)` resolves with `data`,\n * `Err(error)` throws `error` into the mutation error channel.\n *\n * Use this directly with framework hooks when you do not need the\n * `QueryClient`-bound imperative helpers from `defineMutation`:\n *\n * ```ts\n * const save = createMutation(() => mutationOptions({\n * mutationKey: ['saveUser'],\n * mutationFn: (input: SaveUserInput) => services.saveUser(input),\n * }));\n * ```\n *\n * `defineMutation` composes through this helper, so the `.options` it\n * returns is the same shape `mutationOptions` produces.\n *\n * @param input - Result-aware mutation configuration\n * @returns TanStack Query `MutationOptions` with `mutationFn` rewired to\n * resolve `Ok` and throw `Err`\n */\nexport function mutationOptions<\n\tTData,\n\tTError,\n\tTVariables = void,\n\tTContext = unknown,\n\tconst TMutationKey extends MutationKey = MutationKey,\n>(\n\tinput: MutationOptionsInput<\n\t\tTData,\n\t\tTError,\n\t\tTVariables,\n\t\tTContext,\n\t\tTMutationKey\n\t>,\n): MutationOptions<TData, TError, TVariables, TContext> {\n\treturn {\n\t\t...input,\n\t\tmutationFn: async (variables: TVariables) =>\n\t\t\tresolve(await input.mutationFn(variables)),\n\t} satisfies MutationOptions<TData, TError, TVariables, TContext>;\n}\n\n/**\n * Output of `defineQuery`.\n *\n * The returned object is directly callable and defaults to `ensure()` behavior,\n * which is recommended for most imperative use cases like preloaders.\n *\n * - `()` (callable): Same as `ensure()`. Returns cached data if available.\n * - `options`: Options shape produced by `queryOptions`, ready for hooks.\n * - `fetch()`: Always evaluates freshness; refetches if stale.\n * - `ensure()`: Prefers cached data; fetches only when missing.\n */\ntype DefineQueryOutput<\n\tTQueryFnData = unknown,\n\tTError = DefaultError,\n\tTData = TQueryFnData,\n\tTQueryData = TQueryFnData,\n\tTQueryKey extends QueryKey = QueryKey,\n> = (() => Promise<Result<TQueryData, TError>>) & {\n\toptions: QueryObserverOptions<\n\t\tTQueryFnData,\n\t\tTError,\n\t\tTData,\n\t\tTQueryData,\n\t\tTQueryKey\n\t>;\n\tfetch: () => Promise<Result<TQueryData, TError>>;\n\tensure: () => Promise<Result<TQueryData, TError>>;\n};\n\n/**\n * Output of `defineMutation`.\n *\n * The returned object is directly callable and executes the mutation,\n * equivalent to calling `.execute()`.\n *\n * - `(variables)` (callable): Same as `execute(variables)`.\n * - `options`: Options shape produced by `mutationOptions`, ready for hooks.\n * - `execute(variables)`: Imperatively runs the mutation, returning a Result.\n */\ntype DefineMutationOutput<\n\tTData,\n\tTError,\n\tTVariables = void,\n\tTContext = unknown,\n> = ((variables: TVariables) => Promise<Result<TData, TError>>) & {\n\toptions: MutationOptions<TData, TError, TVariables, TContext>;\n\texecute: (variables: TVariables) => Promise<Result<TData, TError>>;\n};\n\n/**\n * Creates `defineQuery` and `defineMutation` bound to a specific `QueryClient`.\n *\n * Use this when you want a reusable query/mutation definition that carries\n * its own imperative helpers (`.fetch`, `.ensure`, `.execute`, callable form)\n * powered by a specific client. For local one-shot options that only need\n * to flow into a framework hook, prefer `queryOptions` / `mutationOptions`\n * directly: those are platform-agnostic and do not require a `QueryClient`.\n *\n * Both `defineQuery` and `defineMutation` compose through `queryOptions` and\n * `mutationOptions`, so there is exactly one place that unwraps `Result`\n * into TanStack's throwing contract.\n *\n * @param queryClient - The TanStack `QueryClient` to bind imperative helpers to\n *\n * @example\n * ```ts\n * const queryClient = new QueryClient();\n * const { defineQuery, defineMutation } = createQueryFactories(queryClient);\n *\n * const userQuery = defineQuery({\n * queryKey: ['user', userId],\n * queryFn: () => services.getUser(userId),\n * });\n *\n * // Reactive\n * const query = createQuery(() => userQuery.options);\n *\n * // Imperative\n * const { data, error } = await userQuery.fetch();\n * ```\n */\nexport function createQueryFactories(queryClient: QueryClient) {\n\tconst defineQuery = <\n\t\tTQueryFnData = unknown,\n\t\tTError = DefaultError,\n\t\tTData = TQueryFnData,\n\t\tTQueryData = TQueryFnData,\n\t\tconst TQueryKey extends QueryKey = QueryKey,\n\t>(\n\t\tinput: QueryOptionsInput<\n\t\t\tTQueryFnData,\n\t\t\tTError,\n\t\t\tTData,\n\t\t\tTQueryData,\n\t\t\tTQueryKey\n\t\t>,\n\t): DefineQueryOutput<TQueryFnData, TError, TData, TQueryData, TQueryKey> => {\n\t\tconst options = queryOptions(input);\n\n\t\tasync function fetch(): Promise<Result<TQueryData, TError>> {\n\t\t\ttry {\n\t\t\t\treturn Ok(\n\t\t\t\t\tawait queryClient.fetchQuery<\n\t\t\t\t\t\tTQueryFnData,\n\t\t\t\t\t\tTError,\n\t\t\t\t\t\tTQueryData,\n\t\t\t\t\t\tTQueryKey\n\t\t\t\t\t>({\n\t\t\t\t\t\tqueryKey: options.queryKey,\n\t\t\t\t\t\tqueryFn: options.queryFn,\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t} catch (error) {\n\t\t\t\treturn Err(error as TError);\n\t\t\t}\n\t\t}\n\n\t\tasync function ensure(): Promise<Result<TQueryData, TError>> {\n\t\t\ttry {\n\t\t\t\treturn Ok(\n\t\t\t\t\tawait queryClient.ensureQueryData<\n\t\t\t\t\t\tTQueryFnData,\n\t\t\t\t\t\tTError,\n\t\t\t\t\t\tTQueryData,\n\t\t\t\t\t\tTQueryKey\n\t\t\t\t\t>({\n\t\t\t\t\t\tqueryKey: options.queryKey,\n\t\t\t\t\t\tqueryFn: options.queryFn,\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t} catch (error) {\n\t\t\t\treturn Err(error as TError);\n\t\t\t}\n\t\t}\n\n\t\treturn Object.assign(ensure, {\n\t\t\toptions,\n\t\t\tfetch,\n\t\t\tensure,\n\t\t});\n\t};\n\n\tconst defineMutation = <\n\t\tTData,\n\t\tTError,\n\t\tTVariables = void,\n\t\tTContext = unknown,\n\t\tconst TMutationKey extends MutationKey = MutationKey,\n\t>(\n\t\tinput: MutationOptionsInput<\n\t\t\tTData,\n\t\t\tTError,\n\t\t\tTVariables,\n\t\t\tTContext,\n\t\t\tTMutationKey\n\t\t>,\n\t): DefineMutationOutput<TData, TError, TVariables, TContext> => {\n\t\tconst options = mutationOptions(input);\n\n\t\tasync function execute(variables: TVariables) {\n\t\t\ttry {\n\t\t\t\treturn Ok(await runMutation(queryClient, options, variables));\n\t\t\t} catch (error) {\n\t\t\t\treturn Err(error as TError);\n\t\t\t}\n\t\t}\n\n\t\treturn Object.assign(execute, {\n\t\t\toptions,\n\t\t\texecute,\n\t\t});\n\t};\n\n\treturn {\n\t\tdefineQuery,\n\t\tdefineMutation,\n\t};\n}\n\n/**\n * Internal helper that executes a mutation directly using the query client's\n * mutation cache. Powers the callable behavior and `.execute()` method on\n * mutations returned from `defineMutation`.\n *\n * @internal\n */\nfunction runMutation<TData, TError, TVariables, TContext>(\n\tqueryClient: QueryClient,\n\toptions: MutationOptions<TData, TError, TVariables, TContext>,\n\tvariables: TVariables,\n) {\n\tconst mutation = queryClient.getMutationCache().build(queryClient, options);\n\treturn mutation.execute(variables);\n}\n\n/**\n * Identity helper for declaring a TanStack Query key map while preserving\n * tuple types.\n *\n * - **Static entries** like `['users', 'active']` are narrowed to readonly\n * tuples with full literal precision (e.g. `readonly ['users', 'active']`)\n * via the `const` type parameter modifier. No per-line `as const` needed.\n *\n * - **Factory entries** like `(id: string) => ['users', id]` are narrowed to\n * tuple SHAPE (e.g. `[string, string]` with correct arity), not widened to\n * `string[]`. This happens because the strict tuple constraint provides\n * contextual typing into the function body. Literal positions still widen\n * without `as const` (TS does not propagate literal narrowing through\n * contextual typing). Add `as const` to the body when you need the literal:\n * `(id) => ['users', id] as const` -> `readonly ['users', string]`.\n *\n * Empty arrays and non-key values are rejected at the type level.\n *\n * @example\n * ```ts\n * const userKeys = defineKeys({\n * all: ['users'], // readonly ['users']\n * active: ['users', 'active'], // readonly ['users', 'active']\n * detail: (id: string) => ['users', id], // [string, string] (tuple shape kept)\n * page: (n: number) => ['users', n] as const, // readonly ['users', number]\n * });\n * ```\n */\nexport function defineKeys<\n\tconst TKeys extends Record<\n\t\tstring,\n\t\t| readonly [unknown, ...unknown[]]\n\t\t| ((...args: never[]) => readonly [unknown, ...unknown[]])\n\t>,\n>(keys: TKeys): TKeys {\n\treturn keys;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwFA,SAAgB,aAOfA,OAC2E;AAC3E,QAAO;EACN,GAAG;EACH,SAAS,OAAO,YAAY,QAAQ,MAAM,MAAM,QAAQ,QAAQ,CAAC;CACjE;AAOD;;;;;;;;;;;;;;;;;;;;;;;;;AA0BD,SAAgB,gBAOfC,OAOuD;AACvD,QAAO;EACN,GAAG;EACH,YAAY,OAAOC,cAClB,QAAQ,MAAM,MAAM,WAAW,UAAU,CAAC;CAC3C;AACD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmFD,SAAgB,qBAAqBC,aAA0B;CAC9D,MAAM,cAAc,CAOnBC,UAO2E;EAC3E,MAAM,UAAU,aAAa,MAAM;EAEnC,eAAe,QAA6C;AAC3D,OAAI;AACH,WAAO,GACN,MAAM,YAAY,WAKhB;KACD,UAAU,QAAQ;KAClB,SAAS,QAAQ;IACjB,EAAC,CACF;GACD,SAAQ,OAAO;AACf,WAAO,IAAI,MAAgB;GAC3B;EACD;EAED,eAAe,SAA8C;AAC5D,OAAI;AACH,WAAO,GACN,MAAM,YAAY,gBAKhB;KACD,UAAU,QAAQ;KAClB,SAAS,QAAQ;IACjB,EAAC,CACF;GACD,SAAQ,OAAO;AACf,WAAO,IAAI,MAAgB;GAC3B;EACD;AAED,SAAO,OAAO,OAAO,QAAQ;GAC5B;GACA;GACA;EACA,EAAC;CACF;CAED,MAAM,iBAAiB,CAOtBC,UAO+D;EAC/D,MAAM,UAAU,gBAAgB,MAAM;EAEtC,eAAe,QAAQH,WAAuB;AAC7C,OAAI;AACH,WAAO,GAAG,MAAM,YAAY,aAAa,SAAS,UAAU,CAAC;GAC7D,SAAQ,OAAO;AACf,WAAO,IAAI,MAAgB;GAC3B;EACD;AAED,SAAO,OAAO,OAAO,SAAS;GAC7B;GACA;EACA,EAAC;CACF;AAED,QAAO;EACN;EACA;CACA;AACD;;;;;;;;AASD,SAAS,YACRC,aACAG,SACAJ,WACC;CACD,MAAM,WAAW,YAAY,kBAAkB,CAAC,MAAM,aAAa,QAAQ;AAC3E,QAAO,SAAS,QAAQ,UAAU;AAClC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8BD,SAAgB,WAMdK,MAAoB;AACrB,QAAO;AACP"}
1
+ {"version":3,"file":"index.js","names":["input: QueryOptionsInput<TQueryFnData, TError, TData, TQueryData, TQueryKey>","input: MutationOptionsInput<\n\t\tTData,\n\t\tTError,\n\t\tTVariables,\n\t\tTContext,\n\t\tTMutationKey\n\t>","variables: TVariables","queryClient: QueryClient","input: QueryOptionsInput<\n\t\t\tTQueryFnData,\n\t\t\tTError,\n\t\t\tTData,\n\t\t\tTQueryData,\n\t\t\tTQueryKey\n\t\t>","input: MutationOptionsInput<\n\t\t\tTData,\n\t\t\tTError,\n\t\t\tTVariables,\n\t\t\tTContext,\n\t\t\tTMutationKey\n\t\t>","options: MutationOptions<TData, TError, TVariables, TContext>","keys: TKeys"],"sources":["../../src/query/utils.ts"],"sourcesContent":["import type {\n\tDefaultError,\n\tMutationKey,\n\tMutationObserverOptions,\n\tMutationOptions,\n\tQueryClient,\n\tQueryFunction,\n\tQueryKey,\n\tQueryObserverOptions,\n} from \"@tanstack/query-core\";\nimport { Err, Ok, type Result, resolve } from \"../result/index.js\";\n\n/**\n * Input for `queryOptions` and `defineQuery`.\n *\n * Mirrors TanStack Query's `QueryObserverOptions` but expects `queryFn` to\n * return a Wellcrafted `Result`. The Result is unwrapped into TanStack's\n * throwing data/error contract by `queryOptions`.\n *\n * @template TQueryFnData - The success type produced by `queryFn`\n * @template TError - The error type carried by the Result\n * @template TData - The type seen by consumers after `select`\n * @template TQueryData - The type stored in the cache (usually `TQueryFnData`)\n * @template TQueryKey - The literal query key tuple\n */\ntype QueryOptionsInput<\n\tTQueryFnData = unknown,\n\tTError = DefaultError,\n\tTData = TQueryFnData,\n\tTQueryData = TQueryFnData,\n\tTQueryKey extends QueryKey = QueryKey,\n> = Omit<\n\tQueryObserverOptions<TQueryFnData, TError, TData, TQueryData, TQueryKey>,\n\t\"queryFn\"\n> & {\n\tqueryKey: TQueryKey;\n\tqueryFn: QueryFunction<Result<TQueryFnData, TError>, TQueryKey>;\n};\n\n/**\n * Input for `mutationOptions` and `defineMutation`.\n *\n * Mirrors TanStack Query's `MutationObserverOptions` but expects `mutationFn`\n * to return a Wellcrafted `Result`. The Result is unwrapped into TanStack's\n * throwing data/error contract by `mutationOptions`.\n *\n * @template TData - The success type produced by `mutationFn`\n * @template TError - The error type carried by the Result\n * @template TVariables - The variables passed to `mutationFn`\n * @template TContext - The context type for optimistic updates\n * @template TMutationKey - The literal mutation key tuple\n */\ntype MutationOptionsInput<\n\tTData,\n\tTError,\n\tTVariables = void,\n\tTContext = unknown,\n\tTMutationKey extends MutationKey = MutationKey,\n> = Omit<\n\tMutationObserverOptions<TData, TError, TVariables, TContext>,\n\t\"mutationFn\"\n> & {\n\tmutationKey: TMutationKey;\n\tmutationFn: (\n\t\tvariables: TVariables,\n\t) => Result<TData, TError> | Promise<Result<TData, TError>>;\n};\n\n/**\n * Adapter from a Result-returning query function to TanStack Query options.\n *\n * This is the single canonical place where `Result<TQueryFnData, TError>`\n * is converted into TanStack's contract: `Ok(data)` resolves with `data`,\n * `Err(error)` throws `error` into the query error channel.\n *\n * Use this directly with framework hooks when you do not need the\n * `QueryClient`-bound imperative helpers from `defineQuery`:\n *\n * ```ts\n * const query = createQuery(() => queryOptions({\n * queryKey: ['user', userId],\n * queryFn: () => services.getUser(userId),\n * }));\n * ```\n *\n * `defineQuery` composes through this helper, so the `.options` it returns\n * is the same shape `queryOptions` produces.\n *\n * @param input - Result-aware query configuration\n * @returns TanStack Query `QueryObserverOptions` with `queryFn` rewired to\n * resolve `Ok` and throw `Err`\n */\nexport function queryOptions<\n\tTQueryFnData = unknown,\n\tTError = DefaultError,\n\tTData = TQueryFnData,\n\tTQueryData = TQueryFnData,\n\tconst TQueryKey extends QueryKey = QueryKey,\n>(\n\tinput: QueryOptionsInput<TQueryFnData, TError, TData, TQueryData, TQueryKey>,\n): QueryObserverOptions<TQueryFnData, TError, TData, TQueryData, TQueryKey> {\n\treturn {\n\t\t...input,\n\t\tqueryFn: async (context) => resolve(await input.queryFn(context)),\n\t} satisfies QueryObserverOptions<\n\t\tTQueryFnData,\n\t\tTError,\n\t\tTData,\n\t\tTQueryData,\n\t\tTQueryKey\n\t>;\n}\n\n/**\n * Adapter from a Result-returning mutation function to TanStack Query options.\n *\n * This is the single canonical place where `Result<TData, TError>` is\n * converted into TanStack's contract: `Ok(data)` resolves with `data`,\n * `Err(error)` throws `error` into the mutation error channel.\n *\n * Use this directly with framework hooks when you do not need the\n * `QueryClient`-bound imperative helpers from `defineMutation`:\n *\n * ```ts\n * const save = createMutation(() => mutationOptions({\n * mutationKey: ['saveUser'],\n * mutationFn: (input: SaveUserInput) => services.saveUser(input),\n * }));\n * ```\n *\n * `defineMutation` composes through this helper, so the `.options` it\n * returns is the same shape `mutationOptions` produces.\n *\n * @param input - Result-aware mutation configuration\n * @returns TanStack Query `MutationObserverOptions` with `mutationFn` rewired\n * to resolve `Ok` and throw `Err`\n */\nexport function mutationOptions<\n\tTData,\n\tTError,\n\tTVariables = void,\n\tTContext = unknown,\n\tconst TMutationKey extends MutationKey = MutationKey,\n>(\n\tinput: MutationOptionsInput<\n\t\tTData,\n\t\tTError,\n\t\tTVariables,\n\t\tTContext,\n\t\tTMutationKey\n\t>,\n): MutationObserverOptions<TData, TError, TVariables, TContext> {\n\treturn {\n\t\t...input,\n\t\tmutationFn: async (variables: TVariables) =>\n\t\t\tresolve(await input.mutationFn(variables)),\n\t} satisfies MutationObserverOptions<TData, TError, TVariables, TContext>;\n}\n\n/**\n * Output of `defineQuery`.\n *\n * Query imperative reads require an explicit cache policy.\n *\n * - `options`: Options shape produced by `queryOptions`, ready for hooks.\n * - `fetch()`: Always evaluates freshness; refetches if stale.\n * - `ensure()`: Prefers cached data; fetches only when missing.\n */\ntype DefineQueryOutput<\n\tTQueryFnData = unknown,\n\tTError = DefaultError,\n\tTData = TQueryFnData,\n\tTQueryData = TQueryFnData,\n\tTQueryKey extends QueryKey = QueryKey,\n> = {\n\toptions: QueryObserverOptions<\n\t\tTQueryFnData,\n\t\tTError,\n\t\tTData,\n\t\tTQueryData,\n\t\tTQueryKey\n\t>;\n\tfetch: () => Promise<Result<TQueryData, TError>>;\n\tensure: () => Promise<Result<TQueryData, TError>>;\n};\n\n/**\n * Output of `defineMutation`.\n *\n * The returned function directly executes the mutation.\n *\n * - `(variables)` (callable): Imperatively runs the mutation, returning a Result.\n * - `options`: Options shape produced by `mutationOptions`, ready for hooks.\n */\ntype DefineMutationOutput<\n\tTData,\n\tTError,\n\tTVariables = void,\n\tTContext = unknown,\n> = ((variables: TVariables) => Promise<Result<TData, TError>>) & {\n\toptions: MutationObserverOptions<TData, TError, TVariables, TContext>;\n};\n\n/**\n * Creates `defineQuery` and `defineMutation` bound to a specific `QueryClient`.\n *\n * Use this when you want a reusable query/mutation definition that carries\n * its own imperative query helpers (`.fetch`, `.ensure`) and callable mutation\n * execution powered by a specific client. For local one-shot options that only need\n * to flow into a framework hook, prefer `queryOptions` / `mutationOptions`\n * directly: those are platform-agnostic and do not require a `QueryClient`.\n *\n * Both `defineQuery` and `defineMutation` compose through `queryOptions` and\n * `mutationOptions`, so there is exactly one place that unwraps `Result`\n * into TanStack's throwing contract.\n *\n * @param queryClient - The TanStack `QueryClient` to bind imperative helpers to\n *\n * @example\n * ```ts\n * const queryClient = new QueryClient();\n * const { defineQuery, defineMutation } = createQueryFactories(queryClient);\n *\n * const userQuery = defineQuery({\n * queryKey: ['user', userId],\n * queryFn: () => services.getUser(userId),\n * });\n *\n * // Reactive\n * const query = createQuery(() => userQuery.options);\n *\n * // Imperative\n * const { data, error } = await userQuery.fetch();\n * ```\n */\nexport function createQueryFactories(queryClient: QueryClient) {\n\tconst defineQuery = <\n\t\tTQueryFnData = unknown,\n\t\tTError = DefaultError,\n\t\tTData = TQueryFnData,\n\t\tTQueryData = TQueryFnData,\n\t\tconst TQueryKey extends QueryKey = QueryKey,\n\t>(\n\t\tinput: QueryOptionsInput<\n\t\t\tTQueryFnData,\n\t\t\tTError,\n\t\t\tTData,\n\t\t\tTQueryData,\n\t\t\tTQueryKey\n\t\t>,\n\t): DefineQueryOutput<TQueryFnData, TError, TData, TQueryData, TQueryKey> => {\n\t\tconst options = queryOptions(input);\n\n\t\tasync function fetch(): Promise<Result<TQueryData, TError>> {\n\t\t\ttry {\n\t\t\t\treturn Ok(\n\t\t\t\t\tawait queryClient.fetchQuery<\n\t\t\t\t\t\tTQueryFnData,\n\t\t\t\t\t\tTError,\n\t\t\t\t\t\tTQueryData,\n\t\t\t\t\t\tTQueryKey\n\t\t\t\t\t>(options),\n\t\t\t\t);\n\t\t\t} catch (error) {\n\t\t\t\treturn Err(error as TError);\n\t\t\t}\n\t\t}\n\n\t\tasync function ensure(): Promise<Result<TQueryData, TError>> {\n\t\t\ttry {\n\t\t\t\treturn Ok(\n\t\t\t\t\tawait queryClient.ensureQueryData<\n\t\t\t\t\t\tTQueryFnData,\n\t\t\t\t\t\tTError,\n\t\t\t\t\t\tTQueryData,\n\t\t\t\t\t\tTQueryKey\n\t\t\t\t\t>(options),\n\t\t\t\t);\n\t\t\t} catch (error) {\n\t\t\t\treturn Err(error as TError);\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\toptions,\n\t\t\tfetch,\n\t\t\tensure,\n\t\t};\n\t};\n\n\tconst defineMutation = <\n\t\tTData,\n\t\tTError,\n\t\tTVariables = void,\n\t\tTContext = unknown,\n\t\tconst TMutationKey extends MutationKey = MutationKey,\n\t>(\n\t\tinput: MutationOptionsInput<\n\t\t\tTData,\n\t\t\tTError,\n\t\t\tTVariables,\n\t\t\tTContext,\n\t\t\tTMutationKey\n\t\t>,\n\t): DefineMutationOutput<TData, TError, TVariables, TContext> => {\n\t\tconst options = mutationOptions(input);\n\n\t\tasync function run(variables: TVariables) {\n\t\t\ttry {\n\t\t\t\treturn Ok(await runMutation(queryClient, options, variables));\n\t\t\t} catch (error) {\n\t\t\t\treturn Err(error as TError);\n\t\t\t}\n\t\t}\n\n\t\treturn Object.assign(run, {\n\t\t\toptions,\n\t\t});\n\t};\n\n\treturn {\n\t\tdefineQuery,\n\t\tdefineMutation,\n\t};\n}\n\n/**\n * Internal helper that executes a mutation directly using the query client's\n * mutation cache. Powers the callable behavior on mutations returned from\n * `defineMutation`.\n *\n * @internal\n */\nfunction runMutation<TData, TError, TVariables, TContext>(\n\tqueryClient: QueryClient,\n\toptions: MutationOptions<TData, TError, TVariables, TContext>,\n\tvariables: TVariables,\n) {\n\tconst mutation = queryClient.getMutationCache().build(queryClient, options);\n\treturn mutation.execute(variables);\n}\n\n/**\n * Identity helper for declaring a TanStack Query key map while preserving\n * tuple types.\n *\n * - **Static entries** like `['users', 'active']` are narrowed to readonly\n * tuples with full literal precision (e.g. `readonly ['users', 'active']`)\n * via the `const` type parameter modifier. No per-line `as const` needed.\n *\n * - **Factory entries** like `(id: string) => ['users', id]` are narrowed to\n * tuple SHAPE (e.g. `[string, string]` with correct arity), not widened to\n * `string[]`. This happens because the strict tuple constraint provides\n * contextual typing into the function body. Literal positions still widen\n * without `as const` (TS does not propagate literal narrowing through\n * contextual typing). Add `as const` to the body when you need the literal:\n * `(id) => ['users', id] as const` -> `readonly ['users', string]`.\n *\n * Empty arrays and non-key values are rejected at the type level.\n *\n * @example\n * ```ts\n * const userKeys = defineKeys({\n * all: ['users'], // readonly ['users']\n * active: ['users', 'active'], // readonly ['users', 'active']\n * detail: (id: string) => ['users', id], // [string, string] (tuple shape kept)\n * page: (n: number) => ['users', n] as const, // readonly ['users', number]\n * });\n * ```\n */\nexport function defineKeys<\n\tconst TKeys extends Record<\n\t\tstring,\n\t\t| readonly [unknown, ...unknown[]]\n\t\t| ((...args: never[]) => readonly [unknown, ...unknown[]])\n\t>,\n>(keys: TKeys): TKeys {\n\treturn keys;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4FA,SAAgB,aAOfA,OAC2E;AAC3E,QAAO;EACN,GAAG;EACH,SAAS,OAAO,YAAY,QAAQ,MAAM,MAAM,QAAQ,QAAQ,CAAC;CACjE;AAOD;;;;;;;;;;;;;;;;;;;;;;;;;AA0BD,SAAgB,gBAOfC,OAO+D;AAC/D,QAAO;EACN,GAAG;EACH,YAAY,OAAOC,cAClB,QAAQ,MAAM,MAAM,WAAW,UAAU,CAAC;CAC3C;AACD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8ED,SAAgB,qBAAqBC,aAA0B;CAC9D,MAAM,cAAc,CAOnBC,UAO2E;EAC3E,MAAM,UAAU,aAAa,MAAM;EAEnC,eAAe,QAA6C;AAC3D,OAAI;AACH,WAAO,GACN,MAAM,YAAY,WAKhB,QAAQ,CACV;GACD,SAAQ,OAAO;AACf,WAAO,IAAI,MAAgB;GAC3B;EACD;EAED,eAAe,SAA8C;AAC5D,OAAI;AACH,WAAO,GACN,MAAM,YAAY,gBAKhB,QAAQ,CACV;GACD,SAAQ,OAAO;AACf,WAAO,IAAI,MAAgB;GAC3B;EACD;AAED,SAAO;GACN;GACA;GACA;EACA;CACD;CAED,MAAM,iBAAiB,CAOtBC,UAO+D;EAC/D,MAAM,UAAU,gBAAgB,MAAM;EAEtC,eAAe,IAAIH,WAAuB;AACzC,OAAI;AACH,WAAO,GAAG,MAAM,YAAY,aAAa,SAAS,UAAU,CAAC;GAC7D,SAAQ,OAAO;AACf,WAAO,IAAI,MAAgB;GAC3B;EACD;AAED,SAAO,OAAO,OAAO,KAAK,EACzB,QACA,EAAC;CACF;AAED,QAAO;EACN;EACA;CACA;AACD;;;;;;;;AASD,SAAS,YACRC,aACAG,SACAJ,WACC;CACD,MAAM,WAAW,YAAY,kBAAkB,CAAC,MAAM,aAAa,QAAQ;AAC3E,QAAO,SAAS,QAAQ,UAAU;AAClC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8BD,SAAgB,WAMdK,MAAoB;AACrB,QAAO;AACP"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wellcrafted",
3
- "version": "0.41.0",
3
+ "version": "0.42.0",
4
4
  "description": "Delightful TypeScript patterns for elegant, type-safe applications",
5
5
  "type": "module",
6
6
  "files": [