@zenstackhq/tanstack-query 1.1.1 → 1.2.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.
Files changed (54) hide show
  1. package/generator.js +70 -37
  2. package/generator.js.map +1 -1
  3. package/package.json +40 -9
  4. package/runtime/common-5e18c135.d.ts +32 -0
  5. package/runtime/index.d.mts +1 -1
  6. package/runtime/index.d.ts +1 -1
  7. package/runtime/index.js +34 -0
  8. package/runtime/index.js.map +1 -1
  9. package/runtime/index.mjs +15 -0
  10. package/runtime/index.mjs.map +1 -1
  11. package/runtime/react.d.mts +17 -26
  12. package/runtime/react.d.ts +17 -26
  13. package/runtime/react.js +105 -72
  14. package/runtime/react.js.map +1 -1
  15. package/runtime/react.mjs +102 -68
  16. package/runtime/react.mjs.map +1 -1
  17. package/runtime/svelte.d.mts +16 -25
  18. package/runtime/svelte.d.ts +16 -25
  19. package/runtime/svelte.js +97 -71
  20. package/runtime/svelte.js.map +1 -1
  21. package/runtime/svelte.mjs +93 -66
  22. package/runtime/svelte.mjs.map +1 -1
  23. package/runtime/vue.d.mts +17 -27
  24. package/runtime/vue.d.ts +17 -27
  25. package/runtime/vue.js +105 -77
  26. package/runtime/vue.js.map +1 -1
  27. package/runtime/vue.mjs +101 -71
  28. package/runtime/vue.mjs.map +1 -1
  29. package/runtime-v5/common-5e18c135.d.ts +32 -0
  30. package/runtime-v5/index.d.mts +20 -0
  31. package/runtime-v5/index.d.ts +20 -0
  32. package/runtime-v5/index.js +53 -0
  33. package/runtime-v5/index.js.map +1 -0
  34. package/runtime-v5/index.mjs +16 -0
  35. package/runtime-v5/index.mjs.map +1 -0
  36. package/runtime-v5/react.d.mts +45 -0
  37. package/runtime-v5/react.d.ts +45 -0
  38. package/runtime-v5/react.js +269 -0
  39. package/runtime-v5/react.js.map +1 -0
  40. package/runtime-v5/react.mjs +237 -0
  41. package/runtime-v5/react.mjs.map +1 -0
  42. package/runtime-v5/svelte.d.mts +56 -0
  43. package/runtime-v5/svelte.d.ts +56 -0
  44. package/runtime-v5/svelte.js +296 -0
  45. package/runtime-v5/svelte.js.map +1 -0
  46. package/runtime-v5/svelte.mjs +264 -0
  47. package/runtime-v5/svelte.mjs.map +1 -0
  48. package/runtime-v5/vue.d.mts +52 -0
  49. package/runtime-v5/vue.d.ts +52 -0
  50. package/runtime-v5/vue.js +274 -0
  51. package/runtime-v5/vue.js.map +1 -0
  52. package/runtime-v5/vue.mjs +240 -0
  53. package/runtime-v5/vue.mjs.map +1 -0
  54. package/runtime/common-83308e88.d.ts +0 -19
package/runtime/vue.js CHANGED
@@ -22,6 +22,18 @@ var __spreadValues = (a, b) => {
22
22
  return a;
23
23
  };
24
24
  var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
25
+ var __objRest = (source, exclude) => {
26
+ var target = {};
27
+ for (var prop in source)
28
+ if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
29
+ target[prop] = source[prop];
30
+ if (source != null && __getOwnPropSymbols)
31
+ for (var prop of __getOwnPropSymbols(source)) {
32
+ if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
33
+ target[prop] = source[prop];
34
+ }
35
+ return target;
36
+ };
25
37
  var __export = (target, all) => {
26
38
  for (var name in all)
27
39
  __defProp(target, name, { get: all[name], enumerable: true });
@@ -68,13 +80,11 @@ var __async = (__this, __arguments, generator) => {
68
80
  var vue_exports = {};
69
81
  __export(vue_exports, {
70
82
  VueQueryContextKey: () => VueQueryContextKey,
71
- deleteMutation: () => deleteMutation,
72
- getContext: () => getContext,
73
- infiniteQuery: () => infiniteQuery,
74
- postMutation: () => postMutation,
83
+ getHooksContext: () => getHooksContext,
75
84
  provideHooksContext: () => provideHooksContext,
76
- putMutation: () => putMutation,
77
- query: () => query
85
+ useInfiniteModelQuery: () => useInfiniteModelQuery,
86
+ useModelMutation: () => useModelMutation,
87
+ useModelQuery: () => useModelQuery
78
88
  });
79
89
  module.exports = __toCommonJS(vue_exports);
80
90
  var import_vue_query = require("@tanstack/vue-query");
@@ -82,9 +92,10 @@ var import_vue = require("vue");
82
92
 
83
93
  // src/runtime/common.ts
84
94
  var import_browser = require("@zenstackhq/runtime/browser");
95
+ var import_cross = require("@zenstackhq/runtime/cross");
85
96
  var crossFetch = __toESM(require("cross-fetch"));
86
97
  var DEFAULT_QUERY_ENDPOINT = "/api/model";
87
- var QUERY_KEY_PREFIX = "zenstack:";
98
+ var QUERY_KEY_PREFIX = "zenstack";
88
99
  function fetcher(url, options, fetch2, checkReadBack) {
89
100
  return __async(this, null, function* () {
90
101
  var _a, _b, _c;
@@ -111,6 +122,13 @@ function fetcher(url, options, fetch2, checkReadBack) {
111
122
  }
112
123
  });
113
124
  }
125
+ function getQueryKey(model, urlOrOperation, args) {
126
+ if (!urlOrOperation) {
127
+ throw new Error("Invalid urlOrOperation");
128
+ }
129
+ const operation = urlOrOperation.split("/").pop();
130
+ return [QUERY_KEY_PREFIX, model, operation, args];
131
+ }
114
132
  function marshal(value) {
115
133
  const { data, meta } = (0, import_browser.serialize)(value);
116
134
  if (meta) {
@@ -140,105 +158,115 @@ function makeUrl(url, args) {
140
158
  }
141
159
  return result;
142
160
  }
161
+ function setupInvalidation(model, operation, modelMeta, options, invalidate, logging = false) {
162
+ const origOnSuccess = options == null ? void 0 : options.onSuccess;
163
+ options.onSuccess = (...args) => __async(this, null, function* () {
164
+ const [_, variables] = args;
165
+ const predicate = yield getInvalidationPredicate(
166
+ model,
167
+ operation,
168
+ variables,
169
+ modelMeta,
170
+ logging
171
+ );
172
+ yield invalidate(predicate);
173
+ return origOnSuccess == null ? void 0 : origOnSuccess(...args);
174
+ });
175
+ }
176
+ function getInvalidationPredicate(model, operation, mutationArgs, modelMeta, logging = false) {
177
+ return __async(this, null, function* () {
178
+ const mutatedModels = yield (0, import_cross.getMutatedModels)(model, operation, mutationArgs, modelMeta);
179
+ return ({ queryKey }) => {
180
+ const [_model, queryModel, queryOp, args] = queryKey;
181
+ if (mutatedModels.includes(queryModel)) {
182
+ if (logging) {
183
+ console.log(`Invalidating query [${queryKey}] due to mutation "${model}.${operation}"`);
184
+ }
185
+ return true;
186
+ }
187
+ if (args) {
188
+ if (findNestedRead(queryModel, mutatedModels, modelMeta, args)) {
189
+ if (logging) {
190
+ console.log(`Invalidating query [${queryKey}] due to mutation "${model}.${operation}"`);
191
+ }
192
+ return true;
193
+ }
194
+ }
195
+ return false;
196
+ };
197
+ });
198
+ }
199
+ function findNestedRead(visitingModel, targetModels, modelMeta, args) {
200
+ const modelsRead = (0, import_cross.getReadModels)(visitingModel, modelMeta, args);
201
+ return targetModels.some((m) => modelsRead.includes(m));
202
+ }
143
203
 
144
204
  // src/runtime/vue.ts
145
205
  var VueQueryContextKey = "zenstack-vue-query-context";
146
206
  function provideHooksContext(context) {
147
207
  (0, import_vue.provide)(VueQueryContextKey, context);
148
208
  }
149
- function getContext() {
150
- return (0, import_vue.inject)(VueQueryContextKey, {
209
+ function getHooksContext() {
210
+ const _a = (0, import_vue.inject)(VueQueryContextKey, {
151
211
  endpoint: DEFAULT_QUERY_ENDPOINT,
152
- fetch: void 0
153
- });
212
+ fetch: void 0,
213
+ logging: false
214
+ }), { endpoint } = _a, rest = __objRest(_a, ["endpoint"]);
215
+ return __spreadValues({ endpoint: endpoint != null ? endpoint : DEFAULT_QUERY_ENDPOINT }, rest);
154
216
  }
155
- function query(model, url, args, options, fetch2) {
217
+ function useModelQuery(model, url, args, options, fetch2) {
156
218
  const reqUrl = makeUrl(url, args);
157
219
  return (0, import_vue_query.useQuery)(__spreadValues({
158
- queryKey: [QUERY_KEY_PREFIX + model, url, args],
220
+ queryKey: getQueryKey(model, url, args),
159
221
  queryFn: () => fetcher(reqUrl, void 0, fetch2, false)
160
222
  }, options));
161
223
  }
162
- function infiniteQuery(model, url, args, options, fetch2) {
224
+ function useInfiniteModelQuery(model, url, args, options, fetch2) {
163
225
  return (0, import_vue_query.useInfiniteQuery)(__spreadValues({
164
- queryKey: [QUERY_KEY_PREFIX + model, url, args],
226
+ queryKey: getQueryKey(model, url, args),
165
227
  queryFn: ({ pageParam }) => {
166
228
  return fetcher(makeUrl(url, pageParam != null ? pageParam : args), void 0, fetch2, false);
167
229
  }
168
230
  }, options));
169
231
  }
170
- function postMutation(model, url, options, fetch2, invalidateQueries = true, checkReadBack) {
232
+ function useModelMutation(model, method, url, modelMeta, options, fetch2, invalidateQueries = true, checkReadBack) {
171
233
  const queryClient = (0, import_vue_query.useQueryClient)();
172
- const mutationFn = (data) => fetcher(
173
- url,
174
- {
175
- method: "POST",
234
+ const mutationFn = (data) => {
235
+ const reqUrl = method === "DELETE" ? makeUrl(url, data) : url;
236
+ const fetchInit = __spreadValues({
237
+ method
238
+ }, method !== "DELETE" && {
176
239
  headers: {
177
240
  "content-type": "application/json"
178
241
  },
179
242
  body: marshal(data)
180
- },
181
- fetch2,
182
- checkReadBack
183
- );
184
- const finalOptions = mergeOptions(model, options, invalidateQueries, mutationFn, queryClient);
185
- const mutation = (0, import_vue_query.useMutation)(finalOptions);
186
- return mutation;
187
- }
188
- function putMutation(model, url, options, fetch2, invalidateQueries = true, checkReadBack) {
189
- const queryClient = (0, import_vue_query.useQueryClient)();
190
- const mutationFn = (data) => fetcher(
191
- url,
192
- {
193
- method: "PUT",
194
- headers: {
195
- "content-type": "application/json"
196
- },
197
- body: marshal(data)
198
- },
199
- fetch2,
200
- checkReadBack
201
- );
202
- const finalOptions = mergeOptions(model, options, invalidateQueries, mutationFn, queryClient);
203
- const mutation = (0, import_vue_query.useMutation)(finalOptions);
204
- return mutation;
205
- }
206
- function deleteMutation(model, url, options, fetch2, invalidateQueries = true, checkReadBack) {
207
- const queryClient = (0, import_vue_query.useQueryClient)();
208
- const mutationFn = (data) => fetcher(
209
- makeUrl(url, data),
210
- {
211
- method: "DELETE"
212
- },
213
- fetch2,
214
- checkReadBack
215
- );
216
- const finalOptions = mergeOptions(model, options, invalidateQueries, mutationFn, queryClient);
217
- const mutation = (0, import_vue_query.useMutation)(finalOptions);
218
- return mutation;
219
- }
220
- function mergeOptions(model, options, invalidateQueries, mutationFn, queryClient) {
221
- const result = __spreadProps(__spreadValues({}, options), { mutationFn });
222
- if ((options == null ? void 0 : options.onSuccess) || invalidateQueries) {
223
- result.onSuccess = (...args) => {
224
- var _a;
225
- if (invalidateQueries) {
226
- queryClient.invalidateQueries([QUERY_KEY_PREFIX + model]);
227
- }
228
- return (_a = options == null ? void 0 : options.onSuccess) == null ? void 0 : _a.call(options, ...args);
229
- };
243
+ });
244
+ return fetcher(reqUrl, fetchInit, fetch2, checkReadBack);
245
+ };
246
+ const finalOptions = __spreadProps(__spreadValues({}, options), { mutationFn });
247
+ if (invalidateQueries) {
248
+ const { logging } = getHooksContext();
249
+ const operation = url.split("/").pop();
250
+ if (operation) {
251
+ setupInvalidation(
252
+ model,
253
+ operation,
254
+ modelMeta,
255
+ finalOptions,
256
+ (predicate) => queryClient.invalidateQueries({ predicate }),
257
+ logging
258
+ );
259
+ }
230
260
  }
231
- return result;
261
+ return (0, import_vue_query.useMutation)(finalOptions);
232
262
  }
233
263
  // Annotate the CommonJS export names for ESM import in node:
234
264
  0 && (module.exports = {
235
265
  VueQueryContextKey,
236
- deleteMutation,
237
- getContext,
238
- infiniteQuery,
239
- postMutation,
266
+ getHooksContext,
240
267
  provideHooksContext,
241
- putMutation,
242
- query
268
+ useInfiniteModelQuery,
269
+ useModelMutation,
270
+ useModelQuery
243
271
  });
244
272
  //# sourceMappingURL=vue.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/runtime/vue.ts","../../src/runtime/common.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/ban-types */\n/* eslint-disable @typescript-eslint/no-explicit-any */\nimport {\n useInfiniteQuery,\n useMutation,\n useQuery,\n useQueryClient,\n type MutateFunction,\n type QueryClient,\n type UseInfiniteQueryOptions,\n type UseMutationOptions,\n type UseQueryOptions,\n} from '@tanstack/vue-query';\nimport { inject, provide } from 'vue';\nimport { APIContext, DEFAULT_QUERY_ENDPOINT, FetchFn, QUERY_KEY_PREFIX, fetcher, makeUrl, marshal } from './common';\n\nexport { APIContext as RequestHandlerContext } from './common';\n\nexport const VueQueryContextKey = 'zenstack-vue-query-context';\n\n/**\n * Provide context for the generated TanStack Query hooks.\n */\nexport function provideHooksContext(context: APIContext) {\n provide<APIContext>(VueQueryContextKey, context);\n}\n\nexport function getContext() {\n return inject<APIContext>(VueQueryContextKey, {\n endpoint: DEFAULT_QUERY_ENDPOINT,\n fetch: undefined,\n });\n}\n\n/**\n * Creates a vue-query query.\n *\n * @param model The name of the model under query.\n * @param url The request URL.\n * @param args The request args object, URL-encoded and appended as \"?q=\" parameter\n * @param options The vue-query options object\n * @returns useQuery hook\n */\nexport function query<R>(model: string, url: string, args?: unknown, options?: UseQueryOptions<R>, fetch?: FetchFn) {\n const reqUrl = makeUrl(url, args);\n return useQuery<R>({\n queryKey: [QUERY_KEY_PREFIX + model, url, args],\n queryFn: () => fetcher<R, false>(reqUrl, undefined, fetch, false),\n ...options,\n });\n}\n\n/**\n * Creates a vue-query infinite query.\n *\n * @param model The name of the model under query.\n * @param url The request URL.\n * @param args The initial request args object, URL-encoded and appended as \"?q=\" parameter\n * @param options The vue-query infinite query options object\n * @returns useInfiniteQuery hook\n */\nexport function infiniteQuery<R>(\n model: string,\n url: string,\n args?: unknown,\n options?: UseInfiniteQueryOptions<R>,\n fetch?: FetchFn\n) {\n return useInfiniteQuery<R>({\n queryKey: [QUERY_KEY_PREFIX + model, url, args],\n queryFn: ({ pageParam }) => {\n return fetcher<R, false>(makeUrl(url, pageParam ?? args), undefined, fetch, false);\n },\n ...options,\n });\n}\n\n/**\n * Creates a POST mutation with vue-query.\n *\n * @param model The name of the model under mutation.\n * @param url The request URL.\n * @param options The vue-query options.\n * @param invalidateQueries Whether to invalidate queries after mutation.\n * @returns useMutation hooks\n */\nexport function postMutation<T, R = any, C extends boolean = boolean, Result = C extends true ? R | undefined : R>(\n model: string,\n url: string,\n options?: Omit<UseMutationOptions<Result, unknown, T, unknown>, 'mutationFn'>,\n fetch?: FetchFn,\n invalidateQueries = true,\n checkReadBack?: C\n) {\n const queryClient = useQueryClient();\n const mutationFn = (data: any) =>\n fetcher<R, C>(\n url,\n {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n },\n body: marshal(data),\n },\n fetch,\n checkReadBack\n ) as Promise<Result>;\n\n // TODO: figure out the typing problem\n const finalOptions: any = mergeOptions<T, Result>(model, options, invalidateQueries, mutationFn, queryClient);\n const mutation = useMutation<Result, unknown, T>(finalOptions);\n return mutation;\n}\n\n/**\n * Creates a PUT mutation with vue-query.\n *\n * @param model The name of the model under mutation.\n * @param url The request URL.\n * @param options The vue-query options.\n * @param invalidateQueries Whether to invalidate queries after mutation.\n * @returns useMutation hooks\n */\nexport function putMutation<T, R = any, C extends boolean = boolean, Result = C extends true ? R | undefined : R>(\n model: string,\n url: string,\n options?: Omit<UseMutationOptions<Result, unknown, T, unknown>, 'mutationFn'>,\n fetch?: FetchFn,\n invalidateQueries = true,\n checkReadBack?: C\n) {\n const queryClient = useQueryClient();\n const mutationFn = (data: any) =>\n fetcher<R, C>(\n url,\n {\n method: 'PUT',\n headers: {\n 'content-type': 'application/json',\n },\n body: marshal(data),\n },\n fetch,\n checkReadBack\n ) as Promise<Result>;\n\n // TODO: figure out the typing problem\n const finalOptions: any = mergeOptions<T, Result>(model, options, invalidateQueries, mutationFn, queryClient);\n const mutation = useMutation<Result, unknown, T>(finalOptions);\n return mutation;\n}\n\n/**\n * Creates a DELETE mutation with vue-query.\n *\n * @param model The name of the model under mutation.\n * @param url The request URL.\n * @param options The vue-query options.\n * @param invalidateQueries Whether to invalidate queries after mutation.\n * @returns useMutation hooks\n */\nexport function deleteMutation<T, R = any, C extends boolean = boolean, Result = C extends true ? R | undefined : R>(\n model: string,\n url: string,\n options?: Omit<UseMutationOptions<Result, unknown, T, unknown>, 'mutationFn'>,\n fetch?: FetchFn,\n invalidateQueries = true,\n checkReadBack?: C\n) {\n const queryClient = useQueryClient();\n const mutationFn = (data: any) =>\n fetcher<R, C>(\n makeUrl(url, data),\n {\n method: 'DELETE',\n },\n fetch,\n checkReadBack\n ) as Promise<Result>;\n\n // TODO: figure out the typing problem\n const finalOptions: any = mergeOptions<T, Result>(model, options, invalidateQueries, mutationFn, queryClient);\n const mutation = useMutation<Result, unknown, T>(finalOptions);\n return mutation;\n}\n\nfunction mergeOptions<T, R = any>(\n model: string,\n options: Omit<UseMutationOptions<R, unknown, T, unknown>, 'mutationFn'> | undefined,\n invalidateQueries: boolean,\n mutationFn: MutateFunction<R, unknown, T>,\n queryClient: QueryClient\n): UseMutationOptions<R, unknown, T, unknown> {\n const result = { ...options, mutationFn };\n if (options?.onSuccess || invalidateQueries) {\n result.onSuccess = (...args) => {\n if (invalidateQueries) {\n queryClient.invalidateQueries([QUERY_KEY_PREFIX + model]);\n }\n return options?.onSuccess?.(...args);\n };\n }\n return result;\n}\n","/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { deserialize, serialize } from '@zenstackhq/runtime/browser';\nimport * as crossFetch from 'cross-fetch';\n\n/**\n * The default query endpoint.\n */\nexport const DEFAULT_QUERY_ENDPOINT = '/api/model';\n\n/**\n * Prefix for react-query keys.\n */\nexport const QUERY_KEY_PREFIX = 'zenstack:';\n\n/**\n * Function signature for `fetch`.\n */\nexport type FetchFn = (url: string, options?: RequestInit) => Promise<Response>;\n\n/**\n * Context type for configuring the hooks.\n */\nexport type APIContext = {\n /**\n * The endpoint to use for the queries.\n */\n endpoint?: string;\n\n /**\n * A custom fetch function for sending the HTTP requests.\n */\n fetch?: FetchFn;\n};\n\nexport async function fetcher<R, C extends boolean>(\n url: string,\n options?: RequestInit,\n fetch?: FetchFn,\n checkReadBack?: C\n): Promise<C extends true ? R | undefined : R> {\n const _fetch = fetch ?? crossFetch.fetch;\n const res = await _fetch(url, options);\n if (!res.ok) {\n const errData = unmarshal(await res.text());\n if (\n checkReadBack !== false &&\n errData.error?.prisma &&\n errData.error?.code === 'P2004' &&\n errData.error?.reason === 'RESULT_NOT_READABLE'\n ) {\n // policy doesn't allow mutation result to be read back, just return undefined\n return undefined as any;\n }\n const error: Error & { info?: unknown; status?: number } = new Error(\n 'An error occurred while fetching the data.'\n );\n error.info = errData.error;\n error.status = res.status;\n throw error;\n }\n\n const textResult = await res.text();\n try {\n return unmarshal(textResult).data as R;\n } catch (err) {\n console.error(`Unable to deserialize data:`, textResult);\n throw err;\n }\n}\n\nexport function marshal(value: unknown) {\n const { data, meta } = serialize(value);\n if (meta) {\n return JSON.stringify({ ...(data as any), meta: { serialization: meta } });\n } else {\n return JSON.stringify(data);\n }\n}\n\nexport function unmarshal(value: string) {\n const parsed = JSON.parse(value);\n if (parsed.data && parsed.meta?.serialization) {\n const deserializedData = deserialize(parsed.data, parsed.meta.serialization);\n return { ...parsed, data: deserializedData };\n } else {\n return parsed;\n }\n}\n\nexport function makeUrl(url: string, args: unknown) {\n if (!args) {\n return url;\n }\n\n const { data, meta } = serialize(args);\n let result = `${url}?q=${encodeURIComponent(JSON.stringify(data))}`;\n if (meta) {\n result += `&meta=${encodeURIComponent(JSON.stringify({ serialization: meta }))}`;\n }\n return result;\n}\n"],"mappings":"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","names":["fetch","fetch"]}
1
+ {"version":3,"sources":["../../src/runtime/vue.ts","../../src/runtime/common.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/ban-types */\n/* eslint-disable @typescript-eslint/no-explicit-any */\nimport {\n useInfiniteQuery,\n useMutation,\n useQuery,\n useQueryClient,\n type UseInfiniteQueryOptions,\n type UseMutationOptions,\n type UseQueryOptions,\n} from '@tanstack/vue-query';\nimport type { ModelMeta } from '@zenstackhq/runtime/cross';\nimport { inject, provide } from 'vue';\nimport {\n APIContext,\n DEFAULT_QUERY_ENDPOINT,\n FetchFn,\n fetcher,\n getQueryKey,\n makeUrl,\n marshal,\n setupInvalidation,\n} from './common';\n\nexport { APIContext as RequestHandlerContext } from './common';\n\nexport const VueQueryContextKey = 'zenstack-vue-query-context';\n\n/**\n * Provide context for the generated TanStack Query hooks.\n */\nexport function provideHooksContext(context: APIContext) {\n provide<APIContext>(VueQueryContextKey, context);\n}\n\n/**\n * Hooks context.\n */\nexport function getHooksContext() {\n const { endpoint, ...rest } = inject<APIContext>(VueQueryContextKey, {\n endpoint: DEFAULT_QUERY_ENDPOINT,\n fetch: undefined,\n logging: false,\n });\n return { endpoint: endpoint ?? DEFAULT_QUERY_ENDPOINT, ...rest };\n}\n\n/**\n * Creates a vue-query query.\n *\n * @param model The name of the model under query.\n * @param url The request URL.\n * @param args The request args object, URL-encoded and appended as \"?q=\" parameter\n * @param options The vue-query options object\n * @returns useQuery hook\n */\nexport function useModelQuery<R>(\n model: string,\n url: string,\n args?: unknown,\n options?: UseQueryOptions<R>,\n fetch?: FetchFn\n) {\n const reqUrl = makeUrl(url, args);\n return useQuery<R>({\n queryKey: getQueryKey(model, url, args),\n queryFn: () => fetcher<R, false>(reqUrl, undefined, fetch, false),\n ...options,\n });\n}\n\n/**\n * Creates a vue-query infinite query.\n *\n * @param model The name of the model under query.\n * @param url The request URL.\n * @param args The initial request args object, URL-encoded and appended as \"?q=\" parameter\n * @param options The vue-query infinite query options object\n * @returns useInfiniteQuery hook\n */\nexport function useInfiniteModelQuery<R>(\n model: string,\n url: string,\n args?: unknown,\n options?: UseInfiniteQueryOptions<R>,\n fetch?: FetchFn\n) {\n return useInfiniteQuery<R>({\n queryKey: getQueryKey(model, url, args),\n queryFn: ({ pageParam }) => {\n return fetcher<R, false>(makeUrl(url, pageParam ?? args), undefined, fetch, false);\n },\n ...options,\n });\n}\n\n/**\n * Creates a mutation with vue-query.\n *\n * @param model The name of the model under mutation.\n * @param method The HTTP method.\n * @param modelMeta The model metadata.\n * @param url The request URL.\n * @param options The vue-query options.\n * @param invalidateQueries Whether to invalidate queries after mutation.\n * @returns useMutation hooks\n */\nexport function useModelMutation<T, R = any, C extends boolean = boolean, Result = C extends true ? R | undefined : R>(\n model: string,\n method: 'POST' | 'PUT' | 'DELETE',\n url: string,\n modelMeta: ModelMeta,\n options?: Omit<UseMutationOptions<Result, unknown, T, unknown>, 'mutationFn'>,\n fetch?: FetchFn,\n invalidateQueries = true,\n checkReadBack?: C\n) {\n const queryClient = useQueryClient();\n const mutationFn = (data: any) => {\n const reqUrl = method === 'DELETE' ? makeUrl(url, data) : url;\n const fetchInit: RequestInit = {\n method,\n ...(method !== 'DELETE' && {\n headers: {\n 'content-type': 'application/json',\n },\n body: marshal(data),\n }),\n };\n return fetcher<R, C>(reqUrl, fetchInit, fetch, checkReadBack) as Promise<Result>;\n };\n\n // TODO: figure out the typing problem\n const finalOptions: any = { ...options, mutationFn };\n if (invalidateQueries) {\n const { logging } = getHooksContext();\n const operation = url.split('/').pop();\n if (operation) {\n setupInvalidation(\n model,\n operation,\n modelMeta,\n finalOptions,\n (predicate) => queryClient.invalidateQueries({ predicate }),\n logging\n );\n }\n }\n return useMutation<Result, unknown, T>(finalOptions);\n}\n","/* eslint-disable @typescript-eslint/no-unused-vars */\n/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { deserialize, serialize } from '@zenstackhq/runtime/browser';\nimport { getMutatedModels, getReadModels, type ModelMeta, type PrismaWriteActionType } from '@zenstackhq/runtime/cross';\nimport * as crossFetch from 'cross-fetch';\n\n/**\n * The default query endpoint.\n */\nexport const DEFAULT_QUERY_ENDPOINT = '/api/model';\n\n/**\n * Prefix for react-query keys.\n */\nexport const QUERY_KEY_PREFIX = 'zenstack';\n\n/**\n * Function signature for `fetch`.\n */\nexport type FetchFn = (url: string, options?: RequestInit) => Promise<Response>;\n\n/**\n * Context type for configuring the hooks.\n */\nexport type APIContext = {\n /**\n * The endpoint to use for the queries.\n */\n endpoint?: string;\n\n /**\n * A custom fetch function for sending the HTTP requests.\n */\n fetch?: FetchFn;\n\n /**\n * If logging is enabled.\n */\n logging?: boolean;\n};\n\nexport async function fetcher<R, C extends boolean>(\n url: string,\n options?: RequestInit,\n fetch?: FetchFn,\n checkReadBack?: C\n): Promise<C extends true ? R | undefined : R> {\n const _fetch = fetch ?? crossFetch.fetch;\n const res = await _fetch(url, options);\n if (!res.ok) {\n const errData = unmarshal(await res.text());\n if (\n checkReadBack !== false &&\n errData.error?.prisma &&\n errData.error?.code === 'P2004' &&\n errData.error?.reason === 'RESULT_NOT_READABLE'\n ) {\n // policy doesn't allow mutation result to be read back, just return undefined\n return undefined as any;\n }\n const error: Error & { info?: unknown; status?: number } = new Error(\n 'An error occurred while fetching the data.'\n );\n error.info = errData.error;\n error.status = res.status;\n throw error;\n }\n\n const textResult = await res.text();\n try {\n return unmarshal(textResult).data as R;\n } catch (err) {\n console.error(`Unable to deserialize data:`, textResult);\n throw err;\n }\n}\n\ntype QueryKey = [string /* prefix */, string /* model */, string /* operation */, unknown /* args */];\n\n/**\n * Computes query key for the given model, operation and query args.\n * @param model Model name.\n * @param urlOrOperation Prisma operation (e.g, `findMany`) or request URL. If it's a URL, the last path segment will be used as the operation name.\n * @param args Prisma query arguments.\n * @returns Query key\n */\nexport function getQueryKey(model: string, urlOrOperation: string, args: unknown): QueryKey {\n if (!urlOrOperation) {\n throw new Error('Invalid urlOrOperation');\n }\n const operation = urlOrOperation.split('/').pop();\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n return [QUERY_KEY_PREFIX, model, operation!, args];\n}\n\nexport function marshal(value: unknown) {\n const { data, meta } = serialize(value);\n if (meta) {\n return JSON.stringify({ ...(data as any), meta: { serialization: meta } });\n } else {\n return JSON.stringify(data);\n }\n}\n\nexport function unmarshal(value: string) {\n const parsed = JSON.parse(value);\n if (parsed.data && parsed.meta?.serialization) {\n const deserializedData = deserialize(parsed.data, parsed.meta.serialization);\n return { ...parsed, data: deserializedData };\n } else {\n return parsed;\n }\n}\n\nexport function makeUrl(url: string, args: unknown) {\n if (!args) {\n return url;\n }\n\n const { data, meta } = serialize(args);\n let result = `${url}?q=${encodeURIComponent(JSON.stringify(data))}`;\n if (meta) {\n result += `&meta=${encodeURIComponent(JSON.stringify({ serialization: meta }))}`;\n }\n return result;\n}\n\ntype InvalidationPredicate = ({ queryKey }: { queryKey: readonly unknown[] }) => boolean;\n\n// sets up invalidation hook for a mutation\nexport function setupInvalidation(\n model: string,\n operation: string,\n modelMeta: ModelMeta,\n options: { onSuccess?: (...args: any[]) => any },\n invalidate: (predicate: InvalidationPredicate) => Promise<void>,\n logging = false\n) {\n const origOnSuccess = options?.onSuccess;\n options.onSuccess = async (...args: unknown[]) => {\n const [_, variables] = args;\n const predicate = await getInvalidationPredicate(\n model,\n operation as PrismaWriteActionType,\n variables,\n modelMeta,\n logging\n );\n await invalidate(predicate);\n return origOnSuccess?.(...args);\n };\n}\n\n// gets a predicate for evaluating whether a query should be invalidated\nasync function getInvalidationPredicate(\n model: string,\n operation: PrismaWriteActionType,\n mutationArgs: any,\n modelMeta: ModelMeta,\n logging = false\n) {\n const mutatedModels = await getMutatedModels(model, operation, mutationArgs, modelMeta);\n\n return ({ queryKey }: { queryKey: readonly unknown[] }) => {\n const [_model, queryModel, queryOp, args] = queryKey as QueryKey;\n\n if (mutatedModels.includes(queryModel)) {\n // direct match\n if (logging) {\n console.log(`Invalidating query [${queryKey}] due to mutation \"${model}.${operation}\"`);\n }\n return true;\n }\n\n if (args) {\n // traverse query args to find nested reads that match the model under mutation\n if (findNestedRead(queryModel, mutatedModels, modelMeta, args)) {\n if (logging) {\n console.log(`Invalidating query [${queryKey}] due to mutation \"${model}.${operation}\"`);\n }\n return true;\n }\n }\n\n return false;\n };\n}\n\n// find nested reads that match the given models\nfunction findNestedRead(visitingModel: string, targetModels: string[], modelMeta: ModelMeta, args: any) {\n const modelsRead = getReadModels(visitingModel, modelMeta, args);\n return targetModels.some((m) => modelsRead.includes(m));\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA,uBAQO;AAEP,iBAAgC;;;ACVhC,qBAAuC;AACvC,mBAA4F;AAC5F,iBAA4B;AAKrB,IAAM,yBAAyB;AAK/B,IAAM,mBAAmB;AA2BhC,SAAsB,QAClB,KACA,SACAA,QACA,eAC2C;AAAA;AA9C/C;AA+CI,UAAM,SAASA,UAAA,OAAAA,SAAoB;AACnC,UAAM,MAAM,MAAM,OAAO,KAAK,OAAO;AACrC,QAAI,CAAC,IAAI,IAAI;AACT,YAAM,UAAU,UAAU,MAAM,IAAI,KAAK,CAAC;AAC1C,UACI,kBAAkB,WAClB,aAAQ,UAAR,mBAAe,aACf,aAAQ,UAAR,mBAAe,UAAS,aACxB,aAAQ,UAAR,mBAAe,YAAW,uBAC5B;AAEE,eAAO;AAAA,MACX;AACA,YAAM,QAAqD,IAAI;AAAA,QAC3D;AAAA,MACJ;AACA,YAAM,OAAO,QAAQ;AACrB,YAAM,SAAS,IAAI;AACnB,YAAM;AAAA,IACV;AAEA,UAAM,aAAa,MAAM,IAAI,KAAK;AAClC,QAAI;AACA,aAAO,UAAU,UAAU,EAAE;AAAA,IACjC,SAAS,KAAK;AACV,cAAQ,MAAM,+BAA+B,UAAU;AACvD,YAAM;AAAA,IACV;AAAA,EACJ;AAAA;AAWO,SAAS,YAAY,OAAe,gBAAwB,MAAyB;AACxF,MAAI,CAAC,gBAAgB;AACjB,UAAM,IAAI,MAAM,wBAAwB;AAAA,EAC5C;AACA,QAAM,YAAY,eAAe,MAAM,GAAG,EAAE,IAAI;AAEhD,SAAO,CAAC,kBAAkB,OAAO,WAAY,IAAI;AACrD;AAEO,SAAS,QAAQ,OAAgB;AACpC,QAAM,EAAE,MAAM,KAAK,QAAI,0BAAU,KAAK;AACtC,MAAI,MAAM;AACN,WAAO,KAAK,UAAU,iCAAM,OAAN,EAAoB,MAAM,EAAE,eAAe,KAAK,EAAE,EAAC;AAAA,EAC7E,OAAO;AACH,WAAO,KAAK,UAAU,IAAI;AAAA,EAC9B;AACJ;AAEO,SAAS,UAAU,OAAe;AAxGzC;AAyGI,QAAM,SAAS,KAAK,MAAM,KAAK;AAC/B,MAAI,OAAO,UAAQ,YAAO,SAAP,mBAAa,gBAAe;AAC3C,UAAM,uBAAmB,4BAAY,OAAO,MAAM,OAAO,KAAK,aAAa;AAC3E,WAAO,iCAAK,SAAL,EAAa,MAAM,iBAAiB;AAAA,EAC/C,OAAO;AACH,WAAO;AAAA,EACX;AACJ;AAEO,SAAS,QAAQ,KAAa,MAAe;AAChD,MAAI,CAAC,MAAM;AACP,WAAO;AAAA,EACX;AAEA,QAAM,EAAE,MAAM,KAAK,QAAI,0BAAU,IAAI;AACrC,MAAI,SAAS,GAAG,GAAG,MAAM,mBAAmB,KAAK,UAAU,IAAI,CAAC,CAAC;AACjE,MAAI,MAAM;AACN,cAAU,SAAS,mBAAmB,KAAK,UAAU,EAAE,eAAe,KAAK,CAAC,CAAC,CAAC;AAAA,EAClF;AACA,SAAO;AACX;AAKO,SAAS,kBACZ,OACA,WACA,WACA,SACA,YACA,UAAU,OACZ;AACE,QAAM,gBAAgB,mCAAS;AAC/B,UAAQ,YAAY,IAAU,SAAoB;AAC9C,UAAM,CAAC,GAAG,SAAS,IAAI;AACvB,UAAM,YAAY,MAAM;AAAA,MACpB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACJ;AACA,UAAM,WAAW,SAAS;AAC1B,WAAO,+CAAgB,GAAG;AAAA,EAC9B;AACJ;AAGA,SAAe,yBACX,OACA,WACA,cACA,WACA,UAAU,OACZ;AAAA;AACE,UAAM,gBAAgB,UAAM,+BAAiB,OAAO,WAAW,cAAc,SAAS;AAEtF,WAAO,CAAC,EAAE,SAAS,MAAwC;AACvD,YAAM,CAAC,QAAQ,YAAY,SAAS,IAAI,IAAI;AAE5C,UAAI,cAAc,SAAS,UAAU,GAAG;AAEpC,YAAI,SAAS;AACT,kBAAQ,IAAI,uBAAuB,QAAQ,sBAAsB,KAAK,IAAI,SAAS,GAAG;AAAA,QAC1F;AACA,eAAO;AAAA,MACX;AAEA,UAAI,MAAM;AAEN,YAAI,eAAe,YAAY,eAAe,WAAW,IAAI,GAAG;AAC5D,cAAI,SAAS;AACT,oBAAQ,IAAI,uBAAuB,QAAQ,sBAAsB,KAAK,IAAI,SAAS,GAAG;AAAA,UAC1F;AACA,iBAAO;AAAA,QACX;AAAA,MACJ;AAEA,aAAO;AAAA,IACX;AAAA,EACJ;AAAA;AAGA,SAAS,eAAe,eAAuB,cAAwB,WAAsB,MAAW;AACpG,QAAM,iBAAa,4BAAc,eAAe,WAAW,IAAI;AAC/D,SAAO,aAAa,KAAK,CAAC,MAAM,WAAW,SAAS,CAAC,CAAC;AAC1D;;;ADtKO,IAAM,qBAAqB;AAK3B,SAAS,oBAAoB,SAAqB;AACrD,0BAAoB,oBAAoB,OAAO;AACnD;AAKO,SAAS,kBAAkB;AAC9B,QAA8B,4BAAmB,oBAAoB;AAAA,IACjE,UAAU;AAAA,IACV,OAAO;AAAA,IACP,SAAS;AAAA,EACb,CAAC,GAJO,WAvCZ,IAuCkC,IAAT,iBAAS,IAAT,CAAb;AAKR,SAAO,iBAAE,UAAU,8BAAY,0BAA2B;AAC9D;AAWO,SAAS,cACZ,OACA,KACA,MACA,SACAC,QACF;AACE,QAAM,SAAS,QAAQ,KAAK,IAAI;AAChC,aAAO,2BAAY;AAAA,IACf,UAAU,YAAY,OAAO,KAAK,IAAI;AAAA,IACtC,SAAS,MAAM,QAAkB,QAAQ,QAAWA,QAAO,KAAK;AAAA,KAC7D,QACN;AACL;AAWO,SAAS,sBACZ,OACA,KACA,MACA,SACAA,QACF;AACE,aAAO,mCAAoB;AAAA,IACvB,UAAU,YAAY,OAAO,KAAK,IAAI;AAAA,IACtC,SAAS,CAAC,EAAE,UAAU,MAAM;AACxB,aAAO,QAAkB,QAAQ,KAAK,gCAAa,IAAI,GAAG,QAAWA,QAAO,KAAK;AAAA,IACrF;AAAA,KACG,QACN;AACL;AAaO,SAAS,iBACZ,OACA,QACA,KACA,WACA,SACAA,QACA,oBAAoB,MACpB,eACF;AACE,QAAM,kBAAc,iCAAe;AACnC,QAAM,aAAa,CAAC,SAAc;AAC9B,UAAM,SAAS,WAAW,WAAW,QAAQ,KAAK,IAAI,IAAI;AAC1D,UAAM,YAAyB;AAAA,MAC3B;AAAA,OACI,WAAW,YAAY;AAAA,MACvB,SAAS;AAAA,QACL,gBAAgB;AAAA,MACpB;AAAA,MACA,MAAM,QAAQ,IAAI;AAAA,IACtB;AAEJ,WAAO,QAAc,QAAQ,WAAWA,QAAO,aAAa;AAAA,EAChE;AAGA,QAAM,eAAoB,iCAAK,UAAL,EAAc,WAAW;AACnD,MAAI,mBAAmB;AACnB,UAAM,EAAE,QAAQ,IAAI,gBAAgB;AACpC,UAAM,YAAY,IAAI,MAAM,GAAG,EAAE,IAAI;AACrC,QAAI,WAAW;AACX;AAAA,QACI;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,CAAC,cAAc,YAAY,kBAAkB,EAAE,UAAU,CAAC;AAAA,QAC1D;AAAA,MACJ;AAAA,IACJ;AAAA,EACJ;AACA,aAAO,8BAAgC,YAAY;AACvD;","names":["fetch","fetch"]}
package/runtime/vue.mjs CHANGED
@@ -17,6 +17,18 @@ var __spreadValues = (a, b) => {
17
17
  return a;
18
18
  };
19
19
  var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
20
+ var __objRest = (source, exclude) => {
21
+ var target = {};
22
+ for (var prop in source)
23
+ if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
24
+ target[prop] = source[prop];
25
+ if (source != null && __getOwnPropSymbols)
26
+ for (var prop of __getOwnPropSymbols(source)) {
27
+ if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
28
+ target[prop] = source[prop];
29
+ }
30
+ return target;
31
+ };
20
32
  var __async = (__this, __arguments, generator) => {
21
33
  return new Promise((resolve, reject) => {
22
34
  var fulfilled = (value) => {
@@ -49,9 +61,10 @@ import { inject, provide } from "vue";
49
61
 
50
62
  // src/runtime/common.ts
51
63
  import { deserialize, serialize } from "@zenstackhq/runtime/browser";
64
+ import { getMutatedModels, getReadModels } from "@zenstackhq/runtime/cross";
52
65
  import * as crossFetch from "cross-fetch";
53
66
  var DEFAULT_QUERY_ENDPOINT = "/api/model";
54
- var QUERY_KEY_PREFIX = "zenstack:";
67
+ var QUERY_KEY_PREFIX = "zenstack";
55
68
  function fetcher(url, options, fetch2, checkReadBack) {
56
69
  return __async(this, null, function* () {
57
70
  var _a, _b, _c;
@@ -78,6 +91,13 @@ function fetcher(url, options, fetch2, checkReadBack) {
78
91
  }
79
92
  });
80
93
  }
94
+ function getQueryKey(model, urlOrOperation, args) {
95
+ if (!urlOrOperation) {
96
+ throw new Error("Invalid urlOrOperation");
97
+ }
98
+ const operation = urlOrOperation.split("/").pop();
99
+ return [QUERY_KEY_PREFIX, model, operation, args];
100
+ }
81
101
  function marshal(value) {
82
102
  const { data, meta } = serialize(value);
83
103
  if (meta) {
@@ -107,104 +127,114 @@ function makeUrl(url, args) {
107
127
  }
108
128
  return result;
109
129
  }
130
+ function setupInvalidation(model, operation, modelMeta, options, invalidate, logging = false) {
131
+ const origOnSuccess = options == null ? void 0 : options.onSuccess;
132
+ options.onSuccess = (...args) => __async(this, null, function* () {
133
+ const [_, variables] = args;
134
+ const predicate = yield getInvalidationPredicate(
135
+ model,
136
+ operation,
137
+ variables,
138
+ modelMeta,
139
+ logging
140
+ );
141
+ yield invalidate(predicate);
142
+ return origOnSuccess == null ? void 0 : origOnSuccess(...args);
143
+ });
144
+ }
145
+ function getInvalidationPredicate(model, operation, mutationArgs, modelMeta, logging = false) {
146
+ return __async(this, null, function* () {
147
+ const mutatedModels = yield getMutatedModels(model, operation, mutationArgs, modelMeta);
148
+ return ({ queryKey }) => {
149
+ const [_model, queryModel, queryOp, args] = queryKey;
150
+ if (mutatedModels.includes(queryModel)) {
151
+ if (logging) {
152
+ console.log(`Invalidating query [${queryKey}] due to mutation "${model}.${operation}"`);
153
+ }
154
+ return true;
155
+ }
156
+ if (args) {
157
+ if (findNestedRead(queryModel, mutatedModels, modelMeta, args)) {
158
+ if (logging) {
159
+ console.log(`Invalidating query [${queryKey}] due to mutation "${model}.${operation}"`);
160
+ }
161
+ return true;
162
+ }
163
+ }
164
+ return false;
165
+ };
166
+ });
167
+ }
168
+ function findNestedRead(visitingModel, targetModels, modelMeta, args) {
169
+ const modelsRead = getReadModels(visitingModel, modelMeta, args);
170
+ return targetModels.some((m) => modelsRead.includes(m));
171
+ }
110
172
 
111
173
  // src/runtime/vue.ts
112
174
  var VueQueryContextKey = "zenstack-vue-query-context";
113
175
  function provideHooksContext(context) {
114
176
  provide(VueQueryContextKey, context);
115
177
  }
116
- function getContext() {
117
- return inject(VueQueryContextKey, {
178
+ function getHooksContext() {
179
+ const _a = inject(VueQueryContextKey, {
118
180
  endpoint: DEFAULT_QUERY_ENDPOINT,
119
- fetch: void 0
120
- });
181
+ fetch: void 0,
182
+ logging: false
183
+ }), { endpoint } = _a, rest = __objRest(_a, ["endpoint"]);
184
+ return __spreadValues({ endpoint: endpoint != null ? endpoint : DEFAULT_QUERY_ENDPOINT }, rest);
121
185
  }
122
- function query(model, url, args, options, fetch2) {
186
+ function useModelQuery(model, url, args, options, fetch2) {
123
187
  const reqUrl = makeUrl(url, args);
124
188
  return useQuery(__spreadValues({
125
- queryKey: [QUERY_KEY_PREFIX + model, url, args],
189
+ queryKey: getQueryKey(model, url, args),
126
190
  queryFn: () => fetcher(reqUrl, void 0, fetch2, false)
127
191
  }, options));
128
192
  }
129
- function infiniteQuery(model, url, args, options, fetch2) {
193
+ function useInfiniteModelQuery(model, url, args, options, fetch2) {
130
194
  return useInfiniteQuery(__spreadValues({
131
- queryKey: [QUERY_KEY_PREFIX + model, url, args],
195
+ queryKey: getQueryKey(model, url, args),
132
196
  queryFn: ({ pageParam }) => {
133
197
  return fetcher(makeUrl(url, pageParam != null ? pageParam : args), void 0, fetch2, false);
134
198
  }
135
199
  }, options));
136
200
  }
137
- function postMutation(model, url, options, fetch2, invalidateQueries = true, checkReadBack) {
201
+ function useModelMutation(model, method, url, modelMeta, options, fetch2, invalidateQueries = true, checkReadBack) {
138
202
  const queryClient = useQueryClient();
139
- const mutationFn = (data) => fetcher(
140
- url,
141
- {
142
- method: "POST",
203
+ const mutationFn = (data) => {
204
+ const reqUrl = method === "DELETE" ? makeUrl(url, data) : url;
205
+ const fetchInit = __spreadValues({
206
+ method
207
+ }, method !== "DELETE" && {
143
208
  headers: {
144
209
  "content-type": "application/json"
145
210
  },
146
211
  body: marshal(data)
147
- },
148
- fetch2,
149
- checkReadBack
150
- );
151
- const finalOptions = mergeOptions(model, options, invalidateQueries, mutationFn, queryClient);
152
- const mutation = useMutation(finalOptions);
153
- return mutation;
154
- }
155
- function putMutation(model, url, options, fetch2, invalidateQueries = true, checkReadBack) {
156
- const queryClient = useQueryClient();
157
- const mutationFn = (data) => fetcher(
158
- url,
159
- {
160
- method: "PUT",
161
- headers: {
162
- "content-type": "application/json"
163
- },
164
- body: marshal(data)
165
- },
166
- fetch2,
167
- checkReadBack
168
- );
169
- const finalOptions = mergeOptions(model, options, invalidateQueries, mutationFn, queryClient);
170
- const mutation = useMutation(finalOptions);
171
- return mutation;
172
- }
173
- function deleteMutation(model, url, options, fetch2, invalidateQueries = true, checkReadBack) {
174
- const queryClient = useQueryClient();
175
- const mutationFn = (data) => fetcher(
176
- makeUrl(url, data),
177
- {
178
- method: "DELETE"
179
- },
180
- fetch2,
181
- checkReadBack
182
- );
183
- const finalOptions = mergeOptions(model, options, invalidateQueries, mutationFn, queryClient);
184
- const mutation = useMutation(finalOptions);
185
- return mutation;
186
- }
187
- function mergeOptions(model, options, invalidateQueries, mutationFn, queryClient) {
188
- const result = __spreadProps(__spreadValues({}, options), { mutationFn });
189
- if ((options == null ? void 0 : options.onSuccess) || invalidateQueries) {
190
- result.onSuccess = (...args) => {
191
- var _a;
192
- if (invalidateQueries) {
193
- queryClient.invalidateQueries([QUERY_KEY_PREFIX + model]);
194
- }
195
- return (_a = options == null ? void 0 : options.onSuccess) == null ? void 0 : _a.call(options, ...args);
196
- };
212
+ });
213
+ return fetcher(reqUrl, fetchInit, fetch2, checkReadBack);
214
+ };
215
+ const finalOptions = __spreadProps(__spreadValues({}, options), { mutationFn });
216
+ if (invalidateQueries) {
217
+ const { logging } = getHooksContext();
218
+ const operation = url.split("/").pop();
219
+ if (operation) {
220
+ setupInvalidation(
221
+ model,
222
+ operation,
223
+ modelMeta,
224
+ finalOptions,
225
+ (predicate) => queryClient.invalidateQueries({ predicate }),
226
+ logging
227
+ );
228
+ }
197
229
  }
198
- return result;
230
+ return useMutation(finalOptions);
199
231
  }
200
232
  export {
201
233
  VueQueryContextKey,
202
- deleteMutation,
203
- getContext,
204
- infiniteQuery,
205
- postMutation,
234
+ getHooksContext,
206
235
  provideHooksContext,
207
- putMutation,
208
- query
236
+ useInfiniteModelQuery,
237
+ useModelMutation,
238
+ useModelQuery
209
239
  };
210
240
  //# sourceMappingURL=vue.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/runtime/vue.ts","../../src/runtime/common.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/ban-types */\n/* eslint-disable @typescript-eslint/no-explicit-any */\nimport {\n useInfiniteQuery,\n useMutation,\n useQuery,\n useQueryClient,\n type MutateFunction,\n type QueryClient,\n type UseInfiniteQueryOptions,\n type UseMutationOptions,\n type UseQueryOptions,\n} from '@tanstack/vue-query';\nimport { inject, provide } from 'vue';\nimport { APIContext, DEFAULT_QUERY_ENDPOINT, FetchFn, QUERY_KEY_PREFIX, fetcher, makeUrl, marshal } from './common';\n\nexport { APIContext as RequestHandlerContext } from './common';\n\nexport const VueQueryContextKey = 'zenstack-vue-query-context';\n\n/**\n * Provide context for the generated TanStack Query hooks.\n */\nexport function provideHooksContext(context: APIContext) {\n provide<APIContext>(VueQueryContextKey, context);\n}\n\nexport function getContext() {\n return inject<APIContext>(VueQueryContextKey, {\n endpoint: DEFAULT_QUERY_ENDPOINT,\n fetch: undefined,\n });\n}\n\n/**\n * Creates a vue-query query.\n *\n * @param model The name of the model under query.\n * @param url The request URL.\n * @param args The request args object, URL-encoded and appended as \"?q=\" parameter\n * @param options The vue-query options object\n * @returns useQuery hook\n */\nexport function query<R>(model: string, url: string, args?: unknown, options?: UseQueryOptions<R>, fetch?: FetchFn) {\n const reqUrl = makeUrl(url, args);\n return useQuery<R>({\n queryKey: [QUERY_KEY_PREFIX + model, url, args],\n queryFn: () => fetcher<R, false>(reqUrl, undefined, fetch, false),\n ...options,\n });\n}\n\n/**\n * Creates a vue-query infinite query.\n *\n * @param model The name of the model under query.\n * @param url The request URL.\n * @param args The initial request args object, URL-encoded and appended as \"?q=\" parameter\n * @param options The vue-query infinite query options object\n * @returns useInfiniteQuery hook\n */\nexport function infiniteQuery<R>(\n model: string,\n url: string,\n args?: unknown,\n options?: UseInfiniteQueryOptions<R>,\n fetch?: FetchFn\n) {\n return useInfiniteQuery<R>({\n queryKey: [QUERY_KEY_PREFIX + model, url, args],\n queryFn: ({ pageParam }) => {\n return fetcher<R, false>(makeUrl(url, pageParam ?? args), undefined, fetch, false);\n },\n ...options,\n });\n}\n\n/**\n * Creates a POST mutation with vue-query.\n *\n * @param model The name of the model under mutation.\n * @param url The request URL.\n * @param options The vue-query options.\n * @param invalidateQueries Whether to invalidate queries after mutation.\n * @returns useMutation hooks\n */\nexport function postMutation<T, R = any, C extends boolean = boolean, Result = C extends true ? R | undefined : R>(\n model: string,\n url: string,\n options?: Omit<UseMutationOptions<Result, unknown, T, unknown>, 'mutationFn'>,\n fetch?: FetchFn,\n invalidateQueries = true,\n checkReadBack?: C\n) {\n const queryClient = useQueryClient();\n const mutationFn = (data: any) =>\n fetcher<R, C>(\n url,\n {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n },\n body: marshal(data),\n },\n fetch,\n checkReadBack\n ) as Promise<Result>;\n\n // TODO: figure out the typing problem\n const finalOptions: any = mergeOptions<T, Result>(model, options, invalidateQueries, mutationFn, queryClient);\n const mutation = useMutation<Result, unknown, T>(finalOptions);\n return mutation;\n}\n\n/**\n * Creates a PUT mutation with vue-query.\n *\n * @param model The name of the model under mutation.\n * @param url The request URL.\n * @param options The vue-query options.\n * @param invalidateQueries Whether to invalidate queries after mutation.\n * @returns useMutation hooks\n */\nexport function putMutation<T, R = any, C extends boolean = boolean, Result = C extends true ? R | undefined : R>(\n model: string,\n url: string,\n options?: Omit<UseMutationOptions<Result, unknown, T, unknown>, 'mutationFn'>,\n fetch?: FetchFn,\n invalidateQueries = true,\n checkReadBack?: C\n) {\n const queryClient = useQueryClient();\n const mutationFn = (data: any) =>\n fetcher<R, C>(\n url,\n {\n method: 'PUT',\n headers: {\n 'content-type': 'application/json',\n },\n body: marshal(data),\n },\n fetch,\n checkReadBack\n ) as Promise<Result>;\n\n // TODO: figure out the typing problem\n const finalOptions: any = mergeOptions<T, Result>(model, options, invalidateQueries, mutationFn, queryClient);\n const mutation = useMutation<Result, unknown, T>(finalOptions);\n return mutation;\n}\n\n/**\n * Creates a DELETE mutation with vue-query.\n *\n * @param model The name of the model under mutation.\n * @param url The request URL.\n * @param options The vue-query options.\n * @param invalidateQueries Whether to invalidate queries after mutation.\n * @returns useMutation hooks\n */\nexport function deleteMutation<T, R = any, C extends boolean = boolean, Result = C extends true ? R | undefined : R>(\n model: string,\n url: string,\n options?: Omit<UseMutationOptions<Result, unknown, T, unknown>, 'mutationFn'>,\n fetch?: FetchFn,\n invalidateQueries = true,\n checkReadBack?: C\n) {\n const queryClient = useQueryClient();\n const mutationFn = (data: any) =>\n fetcher<R, C>(\n makeUrl(url, data),\n {\n method: 'DELETE',\n },\n fetch,\n checkReadBack\n ) as Promise<Result>;\n\n // TODO: figure out the typing problem\n const finalOptions: any = mergeOptions<T, Result>(model, options, invalidateQueries, mutationFn, queryClient);\n const mutation = useMutation<Result, unknown, T>(finalOptions);\n return mutation;\n}\n\nfunction mergeOptions<T, R = any>(\n model: string,\n options: Omit<UseMutationOptions<R, unknown, T, unknown>, 'mutationFn'> | undefined,\n invalidateQueries: boolean,\n mutationFn: MutateFunction<R, unknown, T>,\n queryClient: QueryClient\n): UseMutationOptions<R, unknown, T, unknown> {\n const result = { ...options, mutationFn };\n if (options?.onSuccess || invalidateQueries) {\n result.onSuccess = (...args) => {\n if (invalidateQueries) {\n queryClient.invalidateQueries([QUERY_KEY_PREFIX + model]);\n }\n return options?.onSuccess?.(...args);\n };\n }\n return result;\n}\n","/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { deserialize, serialize } from '@zenstackhq/runtime/browser';\nimport * as crossFetch from 'cross-fetch';\n\n/**\n * The default query endpoint.\n */\nexport const DEFAULT_QUERY_ENDPOINT = '/api/model';\n\n/**\n * Prefix for react-query keys.\n */\nexport const QUERY_KEY_PREFIX = 'zenstack:';\n\n/**\n * Function signature for `fetch`.\n */\nexport type FetchFn = (url: string, options?: RequestInit) => Promise<Response>;\n\n/**\n * Context type for configuring the hooks.\n */\nexport type APIContext = {\n /**\n * The endpoint to use for the queries.\n */\n endpoint?: string;\n\n /**\n * A custom fetch function for sending the HTTP requests.\n */\n fetch?: FetchFn;\n};\n\nexport async function fetcher<R, C extends boolean>(\n url: string,\n options?: RequestInit,\n fetch?: FetchFn,\n checkReadBack?: C\n): Promise<C extends true ? R | undefined : R> {\n const _fetch = fetch ?? crossFetch.fetch;\n const res = await _fetch(url, options);\n if (!res.ok) {\n const errData = unmarshal(await res.text());\n if (\n checkReadBack !== false &&\n errData.error?.prisma &&\n errData.error?.code === 'P2004' &&\n errData.error?.reason === 'RESULT_NOT_READABLE'\n ) {\n // policy doesn't allow mutation result to be read back, just return undefined\n return undefined as any;\n }\n const error: Error & { info?: unknown; status?: number } = new Error(\n 'An error occurred while fetching the data.'\n );\n error.info = errData.error;\n error.status = res.status;\n throw error;\n }\n\n const textResult = await res.text();\n try {\n return unmarshal(textResult).data as R;\n } catch (err) {\n console.error(`Unable to deserialize data:`, textResult);\n throw err;\n }\n}\n\nexport function marshal(value: unknown) {\n const { data, meta } = serialize(value);\n if (meta) {\n return JSON.stringify({ ...(data as any), meta: { serialization: meta } });\n } else {\n return JSON.stringify(data);\n }\n}\n\nexport function unmarshal(value: string) {\n const parsed = JSON.parse(value);\n if (parsed.data && parsed.meta?.serialization) {\n const deserializedData = deserialize(parsed.data, parsed.meta.serialization);\n return { ...parsed, data: deserializedData };\n } else {\n return parsed;\n }\n}\n\nexport function makeUrl(url: string, args: unknown) {\n if (!args) {\n return url;\n }\n\n const { data, meta } = serialize(args);\n let result = `${url}?q=${encodeURIComponent(JSON.stringify(data))}`;\n if (meta) {\n result += `&meta=${encodeURIComponent(JSON.stringify({ serialization: meta }))}`;\n }\n return result;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEA;AAAA,EACI;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAMG;AACP,SAAS,QAAQ,eAAe;;;ACZhC,SAAS,aAAa,iBAAiB;AACvC,YAAY,gBAAgB;AAKrB,IAAM,yBAAyB;AAK/B,IAAM,mBAAmB;AAsBhC,SAAsB,QAClB,KACA,SACAA,QACA,eAC2C;AAAA;AAvC/C;AAwCI,UAAM,SAASA,UAAA,OAAAA,SAAoB;AACnC,UAAM,MAAM,MAAM,OAAO,KAAK,OAAO;AACrC,QAAI,CAAC,IAAI,IAAI;AACT,YAAM,UAAU,UAAU,MAAM,IAAI,KAAK,CAAC;AAC1C,UACI,kBAAkB,WAClB,aAAQ,UAAR,mBAAe,aACf,aAAQ,UAAR,mBAAe,UAAS,aACxB,aAAQ,UAAR,mBAAe,YAAW,uBAC5B;AAEE,eAAO;AAAA,MACX;AACA,YAAM,QAAqD,IAAI;AAAA,QAC3D;AAAA,MACJ;AACA,YAAM,OAAO,QAAQ;AACrB,YAAM,SAAS,IAAI;AACnB,YAAM;AAAA,IACV;AAEA,UAAM,aAAa,MAAM,IAAI,KAAK;AAClC,QAAI;AACA,aAAO,UAAU,UAAU,EAAE;AAAA,IACjC,SAAS,KAAK;AACV,cAAQ,MAAM,+BAA+B,UAAU;AACvD,YAAM;AAAA,IACV;AAAA,EACJ;AAAA;AAEO,SAAS,QAAQ,OAAgB;AACpC,QAAM,EAAE,MAAM,KAAK,IAAI,UAAU,KAAK;AACtC,MAAI,MAAM;AACN,WAAO,KAAK,UAAU,iCAAM,OAAN,EAAoB,MAAM,EAAE,eAAe,KAAK,EAAE,EAAC;AAAA,EAC7E,OAAO;AACH,WAAO,KAAK,UAAU,IAAI;AAAA,EAC9B;AACJ;AAEO,SAAS,UAAU,OAAe;AA/EzC;AAgFI,QAAM,SAAS,KAAK,MAAM,KAAK;AAC/B,MAAI,OAAO,UAAQ,YAAO,SAAP,mBAAa,gBAAe;AAC3C,UAAM,mBAAmB,YAAY,OAAO,MAAM,OAAO,KAAK,aAAa;AAC3E,WAAO,iCAAK,SAAL,EAAa,MAAM,iBAAiB;AAAA,EAC/C,OAAO;AACH,WAAO;AAAA,EACX;AACJ;AAEO,SAAS,QAAQ,KAAa,MAAe;AAChD,MAAI,CAAC,MAAM;AACP,WAAO;AAAA,EACX;AAEA,QAAM,EAAE,MAAM,KAAK,IAAI,UAAU,IAAI;AACrC,MAAI,SAAS,GAAG,GAAG,MAAM,mBAAmB,KAAK,UAAU,IAAI,CAAC,CAAC;AACjE,MAAI,MAAM;AACN,cAAU,SAAS,mBAAmB,KAAK,UAAU,EAAE,eAAe,KAAK,CAAC,CAAC,CAAC;AAAA,EAClF;AACA,SAAO;AACX;;;ADlFO,IAAM,qBAAqB;AAK3B,SAAS,oBAAoB,SAAqB;AACrD,UAAoB,oBAAoB,OAAO;AACnD;AAEO,SAAS,aAAa;AACzB,SAAO,OAAmB,oBAAoB;AAAA,IAC1C,UAAU;AAAA,IACV,OAAO;AAAA,EACX,CAAC;AACL;AAWO,SAAS,MAAS,OAAe,KAAa,MAAgB,SAA8BC,QAAiB;AAChH,QAAM,SAAS,QAAQ,KAAK,IAAI;AAChC,SAAO,SAAY;AAAA,IACf,UAAU,CAAC,mBAAmB,OAAO,KAAK,IAAI;AAAA,IAC9C,SAAS,MAAM,QAAkB,QAAQ,QAAWA,QAAO,KAAK;AAAA,KAC7D,QACN;AACL;AAWO,SAAS,cACZ,OACA,KACA,MACA,SACAA,QACF;AACE,SAAO,iBAAoB;AAAA,IACvB,UAAU,CAAC,mBAAmB,OAAO,KAAK,IAAI;AAAA,IAC9C,SAAS,CAAC,EAAE,UAAU,MAAM;AACxB,aAAO,QAAkB,QAAQ,KAAK,gCAAa,IAAI,GAAG,QAAWA,QAAO,KAAK;AAAA,IACrF;AAAA,KACG,QACN;AACL;AAWO,SAAS,aACZ,OACA,KACA,SACAA,QACA,oBAAoB,MACpB,eACF;AACE,QAAM,cAAc,eAAe;AACnC,QAAM,aAAa,CAAC,SAChB;AAAA,IACI;AAAA,IACA;AAAA,MACI,QAAQ;AAAA,MACR,SAAS;AAAA,QACL,gBAAgB;AAAA,MACpB;AAAA,MACA,MAAM,QAAQ,IAAI;AAAA,IACtB;AAAA,IACAA;AAAA,IACA;AAAA,EACJ;AAGJ,QAAM,eAAoB,aAAwB,OAAO,SAAS,mBAAmB,YAAY,WAAW;AAC5G,QAAM,WAAW,YAAgC,YAAY;AAC7D,SAAO;AACX;AAWO,SAAS,YACZ,OACA,KACA,SACAA,QACA,oBAAoB,MACpB,eACF;AACE,QAAM,cAAc,eAAe;AACnC,QAAM,aAAa,CAAC,SAChB;AAAA,IACI;AAAA,IACA;AAAA,MACI,QAAQ;AAAA,MACR,SAAS;AAAA,QACL,gBAAgB;AAAA,MACpB;AAAA,MACA,MAAM,QAAQ,IAAI;AAAA,IACtB;AAAA,IACAA;AAAA,IACA;AAAA,EACJ;AAGJ,QAAM,eAAoB,aAAwB,OAAO,SAAS,mBAAmB,YAAY,WAAW;AAC5G,QAAM,WAAW,YAAgC,YAAY;AAC7D,SAAO;AACX;AAWO,SAAS,eACZ,OACA,KACA,SACAA,QACA,oBAAoB,MACpB,eACF;AACE,QAAM,cAAc,eAAe;AACnC,QAAM,aAAa,CAAC,SAChB;AAAA,IACI,QAAQ,KAAK,IAAI;AAAA,IACjB;AAAA,MACI,QAAQ;AAAA,IACZ;AAAA,IACAA;AAAA,IACA;AAAA,EACJ;AAGJ,QAAM,eAAoB,aAAwB,OAAO,SAAS,mBAAmB,YAAY,WAAW;AAC5G,QAAM,WAAW,YAAgC,YAAY;AAC7D,SAAO;AACX;AAEA,SAAS,aACL,OACA,SACA,mBACA,YACA,aAC0C;AAC1C,QAAM,SAAS,iCAAK,UAAL,EAAc,WAAW;AACxC,OAAI,mCAAS,cAAa,mBAAmB;AACzC,WAAO,YAAY,IAAI,SAAS;AApMxC;AAqMY,UAAI,mBAAmB;AACnB,oBAAY,kBAAkB,CAAC,mBAAmB,KAAK,CAAC;AAAA,MAC5D;AACA,cAAO,wCAAS,cAAT,iCAAqB,GAAG;AAAA,IACnC;AAAA,EACJ;AACA,SAAO;AACX;","names":["fetch","fetch"]}
1
+ {"version":3,"sources":["../../src/runtime/vue.ts","../../src/runtime/common.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/ban-types */\n/* eslint-disable @typescript-eslint/no-explicit-any */\nimport {\n useInfiniteQuery,\n useMutation,\n useQuery,\n useQueryClient,\n type UseInfiniteQueryOptions,\n type UseMutationOptions,\n type UseQueryOptions,\n} from '@tanstack/vue-query';\nimport type { ModelMeta } from '@zenstackhq/runtime/cross';\nimport { inject, provide } from 'vue';\nimport {\n APIContext,\n DEFAULT_QUERY_ENDPOINT,\n FetchFn,\n fetcher,\n getQueryKey,\n makeUrl,\n marshal,\n setupInvalidation,\n} from './common';\n\nexport { APIContext as RequestHandlerContext } from './common';\n\nexport const VueQueryContextKey = 'zenstack-vue-query-context';\n\n/**\n * Provide context for the generated TanStack Query hooks.\n */\nexport function provideHooksContext(context: APIContext) {\n provide<APIContext>(VueQueryContextKey, context);\n}\n\n/**\n * Hooks context.\n */\nexport function getHooksContext() {\n const { endpoint, ...rest } = inject<APIContext>(VueQueryContextKey, {\n endpoint: DEFAULT_QUERY_ENDPOINT,\n fetch: undefined,\n logging: false,\n });\n return { endpoint: endpoint ?? DEFAULT_QUERY_ENDPOINT, ...rest };\n}\n\n/**\n * Creates a vue-query query.\n *\n * @param model The name of the model under query.\n * @param url The request URL.\n * @param args The request args object, URL-encoded and appended as \"?q=\" parameter\n * @param options The vue-query options object\n * @returns useQuery hook\n */\nexport function useModelQuery<R>(\n model: string,\n url: string,\n args?: unknown,\n options?: UseQueryOptions<R>,\n fetch?: FetchFn\n) {\n const reqUrl = makeUrl(url, args);\n return useQuery<R>({\n queryKey: getQueryKey(model, url, args),\n queryFn: () => fetcher<R, false>(reqUrl, undefined, fetch, false),\n ...options,\n });\n}\n\n/**\n * Creates a vue-query infinite query.\n *\n * @param model The name of the model under query.\n * @param url The request URL.\n * @param args The initial request args object, URL-encoded and appended as \"?q=\" parameter\n * @param options The vue-query infinite query options object\n * @returns useInfiniteQuery hook\n */\nexport function useInfiniteModelQuery<R>(\n model: string,\n url: string,\n args?: unknown,\n options?: UseInfiniteQueryOptions<R>,\n fetch?: FetchFn\n) {\n return useInfiniteQuery<R>({\n queryKey: getQueryKey(model, url, args),\n queryFn: ({ pageParam }) => {\n return fetcher<R, false>(makeUrl(url, pageParam ?? args), undefined, fetch, false);\n },\n ...options,\n });\n}\n\n/**\n * Creates a mutation with vue-query.\n *\n * @param model The name of the model under mutation.\n * @param method The HTTP method.\n * @param modelMeta The model metadata.\n * @param url The request URL.\n * @param options The vue-query options.\n * @param invalidateQueries Whether to invalidate queries after mutation.\n * @returns useMutation hooks\n */\nexport function useModelMutation<T, R = any, C extends boolean = boolean, Result = C extends true ? R | undefined : R>(\n model: string,\n method: 'POST' | 'PUT' | 'DELETE',\n url: string,\n modelMeta: ModelMeta,\n options?: Omit<UseMutationOptions<Result, unknown, T, unknown>, 'mutationFn'>,\n fetch?: FetchFn,\n invalidateQueries = true,\n checkReadBack?: C\n) {\n const queryClient = useQueryClient();\n const mutationFn = (data: any) => {\n const reqUrl = method === 'DELETE' ? makeUrl(url, data) : url;\n const fetchInit: RequestInit = {\n method,\n ...(method !== 'DELETE' && {\n headers: {\n 'content-type': 'application/json',\n },\n body: marshal(data),\n }),\n };\n return fetcher<R, C>(reqUrl, fetchInit, fetch, checkReadBack) as Promise<Result>;\n };\n\n // TODO: figure out the typing problem\n const finalOptions: any = { ...options, mutationFn };\n if (invalidateQueries) {\n const { logging } = getHooksContext();\n const operation = url.split('/').pop();\n if (operation) {\n setupInvalidation(\n model,\n operation,\n modelMeta,\n finalOptions,\n (predicate) => queryClient.invalidateQueries({ predicate }),\n logging\n );\n }\n }\n return useMutation<Result, unknown, T>(finalOptions);\n}\n","/* eslint-disable @typescript-eslint/no-unused-vars */\n/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { deserialize, serialize } from '@zenstackhq/runtime/browser';\nimport { getMutatedModels, getReadModels, type ModelMeta, type PrismaWriteActionType } from '@zenstackhq/runtime/cross';\nimport * as crossFetch from 'cross-fetch';\n\n/**\n * The default query endpoint.\n */\nexport const DEFAULT_QUERY_ENDPOINT = '/api/model';\n\n/**\n * Prefix for react-query keys.\n */\nexport const QUERY_KEY_PREFIX = 'zenstack';\n\n/**\n * Function signature for `fetch`.\n */\nexport type FetchFn = (url: string, options?: RequestInit) => Promise<Response>;\n\n/**\n * Context type for configuring the hooks.\n */\nexport type APIContext = {\n /**\n * The endpoint to use for the queries.\n */\n endpoint?: string;\n\n /**\n * A custom fetch function for sending the HTTP requests.\n */\n fetch?: FetchFn;\n\n /**\n * If logging is enabled.\n */\n logging?: boolean;\n};\n\nexport async function fetcher<R, C extends boolean>(\n url: string,\n options?: RequestInit,\n fetch?: FetchFn,\n checkReadBack?: C\n): Promise<C extends true ? R | undefined : R> {\n const _fetch = fetch ?? crossFetch.fetch;\n const res = await _fetch(url, options);\n if (!res.ok) {\n const errData = unmarshal(await res.text());\n if (\n checkReadBack !== false &&\n errData.error?.prisma &&\n errData.error?.code === 'P2004' &&\n errData.error?.reason === 'RESULT_NOT_READABLE'\n ) {\n // policy doesn't allow mutation result to be read back, just return undefined\n return undefined as any;\n }\n const error: Error & { info?: unknown; status?: number } = new Error(\n 'An error occurred while fetching the data.'\n );\n error.info = errData.error;\n error.status = res.status;\n throw error;\n }\n\n const textResult = await res.text();\n try {\n return unmarshal(textResult).data as R;\n } catch (err) {\n console.error(`Unable to deserialize data:`, textResult);\n throw err;\n }\n}\n\ntype QueryKey = [string /* prefix */, string /* model */, string /* operation */, unknown /* args */];\n\n/**\n * Computes query key for the given model, operation and query args.\n * @param model Model name.\n * @param urlOrOperation Prisma operation (e.g, `findMany`) or request URL. If it's a URL, the last path segment will be used as the operation name.\n * @param args Prisma query arguments.\n * @returns Query key\n */\nexport function getQueryKey(model: string, urlOrOperation: string, args: unknown): QueryKey {\n if (!urlOrOperation) {\n throw new Error('Invalid urlOrOperation');\n }\n const operation = urlOrOperation.split('/').pop();\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n return [QUERY_KEY_PREFIX, model, operation!, args];\n}\n\nexport function marshal(value: unknown) {\n const { data, meta } = serialize(value);\n if (meta) {\n return JSON.stringify({ ...(data as any), meta: { serialization: meta } });\n } else {\n return JSON.stringify(data);\n }\n}\n\nexport function unmarshal(value: string) {\n const parsed = JSON.parse(value);\n if (parsed.data && parsed.meta?.serialization) {\n const deserializedData = deserialize(parsed.data, parsed.meta.serialization);\n return { ...parsed, data: deserializedData };\n } else {\n return parsed;\n }\n}\n\nexport function makeUrl(url: string, args: unknown) {\n if (!args) {\n return url;\n }\n\n const { data, meta } = serialize(args);\n let result = `${url}?q=${encodeURIComponent(JSON.stringify(data))}`;\n if (meta) {\n result += `&meta=${encodeURIComponent(JSON.stringify({ serialization: meta }))}`;\n }\n return result;\n}\n\ntype InvalidationPredicate = ({ queryKey }: { queryKey: readonly unknown[] }) => boolean;\n\n// sets up invalidation hook for a mutation\nexport function setupInvalidation(\n model: string,\n operation: string,\n modelMeta: ModelMeta,\n options: { onSuccess?: (...args: any[]) => any },\n invalidate: (predicate: InvalidationPredicate) => Promise<void>,\n logging = false\n) {\n const origOnSuccess = options?.onSuccess;\n options.onSuccess = async (...args: unknown[]) => {\n const [_, variables] = args;\n const predicate = await getInvalidationPredicate(\n model,\n operation as PrismaWriteActionType,\n variables,\n modelMeta,\n logging\n );\n await invalidate(predicate);\n return origOnSuccess?.(...args);\n };\n}\n\n// gets a predicate for evaluating whether a query should be invalidated\nasync function getInvalidationPredicate(\n model: string,\n operation: PrismaWriteActionType,\n mutationArgs: any,\n modelMeta: ModelMeta,\n logging = false\n) {\n const mutatedModels = await getMutatedModels(model, operation, mutationArgs, modelMeta);\n\n return ({ queryKey }: { queryKey: readonly unknown[] }) => {\n const [_model, queryModel, queryOp, args] = queryKey as QueryKey;\n\n if (mutatedModels.includes(queryModel)) {\n // direct match\n if (logging) {\n console.log(`Invalidating query [${queryKey}] due to mutation \"${model}.${operation}\"`);\n }\n return true;\n }\n\n if (args) {\n // traverse query args to find nested reads that match the model under mutation\n if (findNestedRead(queryModel, mutatedModels, modelMeta, args)) {\n if (logging) {\n console.log(`Invalidating query [${queryKey}] due to mutation \"${model}.${operation}\"`);\n }\n return true;\n }\n }\n\n return false;\n };\n}\n\n// find nested reads that match the given models\nfunction findNestedRead(visitingModel: string, targetModels: string[], modelMeta: ModelMeta, args: any) {\n const modelsRead = getReadModels(visitingModel, modelMeta, args);\n return targetModels.some((m) => modelsRead.includes(m));\n}\n"],"mappings":"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","names":["fetch","fetch"]}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Function signature for `fetch`.
3
+ */
4
+ type FetchFn = (url: string, options?: RequestInit) => Promise<Response>;
5
+ /**
6
+ * Context type for configuring the hooks.
7
+ */
8
+ type APIContext = {
9
+ /**
10
+ * The endpoint to use for the queries.
11
+ */
12
+ endpoint?: string;
13
+ /**
14
+ * A custom fetch function for sending the HTTP requests.
15
+ */
16
+ fetch?: FetchFn;
17
+ /**
18
+ * If logging is enabled.
19
+ */
20
+ logging?: boolean;
21
+ };
22
+ type QueryKey = [string, string, string, unknown];
23
+ /**
24
+ * Computes query key for the given model, operation and query args.
25
+ * @param model Model name.
26
+ * @param urlOrOperation Prisma operation (e.g, `findMany`) or request URL. If it's a URL, the last path segment will be used as the operation name.
27
+ * @param args Prisma query arguments.
28
+ * @returns Query key
29
+ */
30
+ declare function getQueryKey(model: string, urlOrOperation: string, args: unknown): QueryKey;
31
+
32
+ export { APIContext as A, FetchFn as F, getQueryKey as g };