@openapi-qraft/react 1.0.10 → 1.1.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 (89) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/ServiceOperation.d.ts +98 -22
  3. package/dist/ServiceOperation.d.ts.map +1 -1
  4. package/dist/callbacks/getInfiniteQueryData.d.ts.map +1 -1
  5. package/dist/callbacks/getInfiniteQueryData.js +4 -4
  6. package/dist/callbacks/getInfiniteQueryData.js.map +1 -1
  7. package/dist/callbacks/getInfiniteQueryKey.d.ts +1 -5
  8. package/dist/callbacks/getInfiniteQueryKey.d.ts.map +1 -1
  9. package/dist/callbacks/getInfiniteQueryKey.js +2 -4
  10. package/dist/callbacks/getInfiniteQueryKey.js.map +1 -1
  11. package/dist/callbacks/getQueryData.d.ts.map +1 -1
  12. package/dist/callbacks/getQueryData.js +2 -4
  13. package/dist/callbacks/getQueryData.js.map +1 -1
  14. package/dist/callbacks/getQueryKey.d.ts +1 -4
  15. package/dist/callbacks/getQueryKey.d.ts.map +1 -1
  16. package/dist/callbacks/getQueryKey.js +2 -4
  17. package/dist/callbacks/getQueryKey.js.map +1 -1
  18. package/dist/callbacks/invalidateQueries.d.ts +5 -0
  19. package/dist/callbacks/invalidateQueries.d.ts.map +1 -0
  20. package/dist/callbacks/invalidateQueries.js +36 -0
  21. package/dist/callbacks/invalidateQueries.js.map +1 -0
  22. package/dist/callbacks/setInfiniteQueryData.d.ts.map +1 -1
  23. package/dist/callbacks/setInfiniteQueryData.js +4 -1
  24. package/dist/callbacks/setInfiniteQueryData.js.map +1 -1
  25. package/dist/callbacks/setQueryData.d.ts.map +1 -1
  26. package/dist/callbacks/setQueryData.js +4 -4
  27. package/dist/callbacks/setQueryData.js.map +1 -1
  28. package/dist/callbacks/useInfiniteQuery.d.ts.map +1 -1
  29. package/dist/callbacks/useInfiniteQuery.js +5 -4
  30. package/dist/callbacks/useInfiniteQuery.js.map +1 -1
  31. package/dist/callbacks/useQueries.d.ts.map +1 -1
  32. package/dist/callbacks/useQueries.js +23 -15
  33. package/dist/callbacks/useQueries.js.map +1 -1
  34. package/dist/callbacks/useQuery.d.ts +1 -1
  35. package/dist/callbacks/useQuery.d.ts.map +1 -1
  36. package/dist/callbacks/useQuery.js +4 -4
  37. package/dist/callbacks/useQuery.js.map +1 -1
  38. package/dist/callbacks/useSuspenseInfiniteQuery.d.ts.map +1 -1
  39. package/dist/callbacks/useSuspenseInfiniteQuery.js +5 -4
  40. package/dist/callbacks/useSuspenseInfiniteQuery.js.map +1 -1
  41. package/dist/callbacks/useSuspenseQueries.d.ts.map +1 -1
  42. package/dist/callbacks/useSuspenseQueries.js +23 -15
  43. package/dist/callbacks/useSuspenseQueries.js.map +1 -1
  44. package/dist/callbacks/useSuspenseQuery.d.ts.map +1 -1
  45. package/dist/callbacks/useSuspenseQuery.js +4 -4
  46. package/dist/callbacks/useSuspenseQuery.js.map +1 -1
  47. package/dist/lib/composeInfiniteQueryKey.d.ts +4 -0
  48. package/dist/lib/composeInfiniteQueryKey.d.ts.map +1 -0
  49. package/dist/lib/composeInfiniteQueryKey.js +4 -0
  50. package/dist/lib/composeInfiniteQueryKey.js.map +1 -0
  51. package/dist/lib/composeQueryKey.d.ts +4 -0
  52. package/dist/lib/composeQueryKey.d.ts.map +1 -0
  53. package/dist/lib/composeQueryKey.js +4 -0
  54. package/dist/lib/composeQueryKey.js.map +1 -0
  55. package/dist/lib/createRecursiveProxy.d.ts +7 -5
  56. package/dist/lib/createRecursiveProxy.d.ts.map +1 -1
  57. package/dist/lib/createRecursiveProxy.js +14 -9
  58. package/dist/lib/createRecursiveProxy.js.map +1 -1
  59. package/dist/lib/request.d.ts.map +1 -1
  60. package/dist/lib/request.js +15 -3
  61. package/dist/lib/request.js.map +1 -1
  62. package/dist/qraftAPIClient.d.ts.map +1 -1
  63. package/dist/qraftAPIClient.js +16 -7
  64. package/dist/qraftAPIClient.js.map +1 -1
  65. package/package.json +3 -2
  66. package/src/ServiceOperation.ts +152 -25
  67. package/src/callbacks/getInfiniteQueryData.ts +6 -4
  68. package/src/callbacks/getInfiniteQueryKey.ts +3 -8
  69. package/src/callbacks/getQueryData.ts +5 -8
  70. package/src/callbacks/getQueryKey.ts +3 -8
  71. package/src/callbacks/invalidateQueries.ts +70 -0
  72. package/src/callbacks/setInfiniteQueryData.ts +4 -1
  73. package/src/callbacks/setQueryData.ts +5 -4
  74. package/src/callbacks/useInfiniteQuery.ts +13 -5
  75. package/src/callbacks/useQueries.ts +30 -20
  76. package/src/callbacks/useQuery.ts +6 -9
  77. package/src/callbacks/useSuspenseInfiniteQuery.ts +13 -5
  78. package/src/callbacks/useSuspenseQueries.ts +30 -20
  79. package/src/callbacks/useSuspenseQuery.ts +5 -4
  80. package/src/lib/composeInfiniteQueryKey.ts +12 -0
  81. package/src/lib/composeQueryKey.ts +9 -0
  82. package/src/lib/createRecursiveProxy.ts +32 -11
  83. package/src/lib/request.ts +20 -2
  84. package/src/qraftAPIClient.ts +25 -13
  85. package/dist/lib/createCallbackProxyDecoration.d.ts +0 -5
  86. package/dist/lib/createCallbackProxyDecoration.d.ts.map +0 -1
  87. package/dist/lib/createCallbackProxyDecoration.js +0 -21
  88. package/dist/lib/createCallbackProxyDecoration.js.map +0 -1
  89. package/src/lib/createCallbackProxyDecoration.ts +0 -34
@@ -8,13 +8,11 @@ import {
8
8
  useSuspenseQueries as useSuspenseQueriesTanstack,
9
9
  } from '@tanstack/react-query';
10
10
 
11
+ import { composeQueryKey } from '../lib/composeQueryKey.js';
11
12
  import type { QraftClientOptions } from '../qraftAPIClient.js';
12
13
  import { QraftContext } from '../QraftContext.js';
13
14
  import type { RequestClientSchema } from '../RequestClient.js';
14
- import {
15
- ServiceOperationQuery,
16
- ServiceOperationQueryKey,
17
- } from '../ServiceOperation.js';
15
+ import { ServiceOperationQuery } from '../ServiceOperation.js';
18
16
 
19
17
  export const useSuspenseQueries: (
20
18
  qraftOptions: QraftClientOptions | undefined,
@@ -37,22 +35,34 @@ export const useSuspenseQueries: (
37
35
  return useSuspenseQueriesTanstack(
38
36
  {
39
37
  ...options,
40
- queries: options.queries.map(({ parameters, ...queryOptions }) => ({
41
- ...queryOptions,
42
- queryKey: [
43
- { url: schema.url, method: schema.method },
44
- parameters,
45
- ] satisfies ServiceOperationQueryKey<RequestClientSchema, unknown>,
46
- queryFn:
47
- queryOptions.queryFn ??
48
- function ({ queryKey: [, queryParams], signal, meta }) {
49
- return requestClient(schema, {
50
- parameters: queryParams as never,
51
- signal,
52
- meta,
53
- });
54
- },
55
- })),
38
+ queries: options.queries.map((queryOptions) => {
39
+ const optionsWithQueryKey =
40
+ 'parameters' in queryOptions
41
+ ? (() => {
42
+ const queryOptionsCopy = Object.assign(
43
+ {
44
+ queryKey: composeQueryKey(schema, queryOptions.parameters),
45
+ },
46
+ queryOptions
47
+ );
48
+ delete queryOptionsCopy.parameters;
49
+ return queryOptionsCopy;
50
+ })()
51
+ : queryOptions;
52
+
53
+ return {
54
+ ...optionsWithQueryKey,
55
+ queryFn:
56
+ optionsWithQueryKey.queryFn ??
57
+ function ({ queryKey: [, queryParams], signal, meta }) {
58
+ return requestClient(schema, {
59
+ parameters: queryParams as never,
60
+ signal,
61
+ meta,
62
+ });
63
+ },
64
+ };
65
+ }),
56
66
  },
57
67
  useQueryClient(queryClientByArg ?? queryClientByContext)
58
68
  ) as never;
@@ -9,6 +9,7 @@ import {
9
9
  useSuspenseQuery as useSuspenseQueryTanstack,
10
10
  } from '@tanstack/react-query';
11
11
 
12
+ import { composeQueryKey } from '../lib/composeQueryKey.js';
12
13
  import type { QraftClientOptions } from '../qraftAPIClient.js';
13
14
  import { QraftContext } from '../QraftContext.js';
14
15
  import type { RequestClientSchema } from '../RequestClient.js';
@@ -39,10 +40,10 @@ export const useSuspenseQuery: <
39
40
 
40
41
  if (!requestClient) throw new Error(`QraftContext.requestClient not found`);
41
42
 
42
- const queryKey: ServiceOperationQueryKey<RequestClientSchema, unknown> = [
43
- { url: schema.url, method: schema.method },
44
- parameters,
45
- ];
43
+ const queryKey: ServiceOperationQueryKey<RequestClientSchema, unknown> =
44
+ Array.isArray(parameters)
45
+ ? (parameters as never)
46
+ : composeQueryKey(schema, parameters);
46
47
 
47
48
  return useSuspenseQueryTanstack(
48
49
  {
@@ -0,0 +1,12 @@
1
+ import type { RequestClientSchema } from '../RequestClient.js';
2
+ import { ServiceOperationInfiniteQueryKey } from '../ServiceOperation.js';
3
+
4
+ export function composeInfiniteQueryKey<
5
+ TSchema extends RequestClientSchema,
6
+ TParams,
7
+ >(
8
+ schema: TSchema,
9
+ parameters: TParams | undefined
10
+ ): ServiceOperationInfiniteQueryKey<TSchema, TParams> {
11
+ return [{ ...schema, infinite: true }, parameters ?? ({} as TParams)];
12
+ }
@@ -0,0 +1,9 @@
1
+ import type { RequestClientSchema } from '../RequestClient.js';
2
+ import { ServiceOperationQueryKey } from '../ServiceOperation.js';
3
+
4
+ export function composeQueryKey<TSchema extends RequestClientSchema, TParams>(
5
+ schema: TSchema,
6
+ parameters: TParams | undefined
7
+ ): ServiceOperationQueryKey<TSchema, TParams> {
8
+ return [schema, parameters ?? ({} as TParams)];
9
+ }
@@ -1,25 +1,46 @@
1
- type ProxyCallback = (opts: { path: string[]; args: unknown[] }) => unknown;
1
+ type ProxyApplyCallback = (path: string[], args: unknown[]) => unknown;
2
+ /**
3
+ * @internal
4
+ * If returns `undefined | null`, the proxy will continue to create a new proxy for the next key.
5
+ */
6
+ type ProxyGetCallback = (path: string[], key: string) => unknown | undefined;
2
7
 
3
- export function createRecursiveProxy(callback: ProxyCallback, path: string[]) {
4
- const proxy: unknown = new Proxy(noop, {
8
+ export function createRecursiveProxy(
9
+ getCallback: ProxyGetCallback,
10
+ applyCallback: ProxyApplyCallback,
11
+ path: string[]
12
+ ): unknown {
13
+ return new Proxy(noop, {
5
14
  get(_obj, key) {
6
15
  if (typeof key !== 'string' || key === 'then') {
7
16
  // special case for if the proxy is accidentally treated
8
17
  // like a PromiseLike (like in `Promise.resolve(proxy)`)
9
18
  return undefined;
10
19
  }
11
- return createRecursiveProxy(callback, [...path, key]);
20
+
21
+ return (
22
+ getCallback(path, key) ??
23
+ createRecursiveProxy(getCallback, applyCallback, [...path, key])
24
+ );
12
25
  },
13
26
  apply(_1, _2, args) {
14
- const isApply = path[path.length - 1] === 'apply';
15
- return callback({
16
- args: isApply ? (args.length >= 2 ? args[1] : []) : args,
17
- path: isApply ? path.slice(0, -1) : path,
18
- });
27
+ const functionName = path[path.length - 1];
28
+
29
+ const isCall = functionName === 'call';
30
+ const isApply = isCall ? false : functionName === 'apply';
31
+
32
+ return applyCallback(
33
+ isApply || isCall ? path.slice(0, -1) : path,
34
+ isApply
35
+ ? args.length >= 2
36
+ ? args[1]
37
+ : []
38
+ : isCall
39
+ ? args.slice(1)
40
+ : args
41
+ );
19
42
  },
20
43
  });
21
-
22
- return proxy;
23
44
  }
24
45
 
25
46
  function noop() {
@@ -218,8 +218,26 @@ async function getResponseBody<T>(response: Response): Promise<T | undefined> {
218
218
  const isJSON =
219
219
  contentType?.includes('/json') || contentType?.includes('+json');
220
220
 
221
- // parse response (falling back to .text() when necessary)
222
- if (isJSON) return response.json();
221
+ if (isJSON) {
222
+ // attempt to parse JSON for successful responses, otherwise fail
223
+ if (response.ok) return response.json();
224
+
225
+ const errorFallbackResponse = response.clone(); // clone to allow multiple reads
226
+
227
+ return response.json().catch(() => {
228
+ if (
229
+ typeof process !== 'undefined' &&
230
+ typeof process.env !== 'undefined' &&
231
+ process.env.NODE_ENV === 'development'
232
+ ) {
233
+ console.warn(
234
+ 'Failed to parse response body as JSON. Falling back to .text()'
235
+ );
236
+ }
237
+ // falling back to .text() when necessary for error messages
238
+ return errorFallbackResponse.text();
239
+ });
240
+ }
223
241
 
224
242
  return response.text() as Promise<T>;
225
243
  }
@@ -1,6 +1,6 @@
1
1
  import { Context } from 'react';
2
2
 
3
- import { createCallbackProxyDecoration } from './lib/createCallbackProxyDecoration.js';
3
+ import { createRecursiveProxy } from './lib/createRecursiveProxy.js';
4
4
  import { QraftContextValue } from './QraftContext.js';
5
5
  import type { RequestClientSchema } from './RequestClient.js';
6
6
 
@@ -16,23 +16,35 @@ export const qraftAPIClient = <
16
16
  callbacks: Callbacks,
17
17
  options?: QraftClientOptions
18
18
  ): ServicesCallbacksFilter<Services, keyof Callbacks> => {
19
- return createCallbackProxyDecoration(
20
- Object.keys(callbacks),
21
- (path, functionName, args) => {
19
+ return createRecursiveProxy(
20
+ (getPath, key) => {
21
+ if (getPath.length !== 2 || key !== 'schema') return;
22
+
23
+ const serviceOperation = getByPath(services, getPath);
24
+ if (!isServiceOperation(serviceOperation))
25
+ throw new Error(`Service operation not found: ${getPath.join('.')}`);
26
+ return serviceOperation.schema;
27
+ },
28
+ (applyPath, args) => {
29
+ const path = applyPath.slice(0, -1);
22
30
  const serviceOperation = getByPath(services, path);
31
+
23
32
  if (!isServiceOperation(serviceOperation))
24
33
  throw new Error(`Service operation not found: ${path.join('.')}`);
25
34
 
26
- if (functionName in callbacks) {
27
- return callbacks[functionName as keyof Callbacks](
28
- options,
29
- serviceOperation.schema,
30
- args
31
- );
32
- }
35
+ // The last arg is for instance `.useMutation` or `.useQuery()`
36
+ const functionName = applyPath[applyPath.length - 1];
33
37
 
34
- throw new Error(`Not supported API method: ${String(functionName)}`);
35
- }
38
+ if (!(functionName in callbacks))
39
+ throw new Error(`Function ${functionName} is not supported`);
40
+
41
+ return callbacks[functionName as keyof Callbacks](
42
+ options,
43
+ serviceOperation.schema,
44
+ args
45
+ );
46
+ },
47
+ []
36
48
  ) as never;
37
49
  };
38
50
 
@@ -1,5 +0,0 @@
1
- /**
2
- * Create proxy for decorating procedures
3
- */
4
- export declare function createCallbackProxyDecoration<Functions extends string[] | Readonly<string[]>>(functions: Functions, callback: (path: string[], functionName: Functions[number], args: unknown[]) => unknown): unknown;
5
- //# sourceMappingURL=createCallbackProxyDecoration.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"createCallbackProxyDecoration.d.ts","sourceRoot":"","sources":["../../src/lib/createCallbackProxyDecoration.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,wBAAgB,6BAA6B,CAC3C,SAAS,SAAS,MAAM,EAAE,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,EAE/C,SAAS,EAAE,SAAS,EACpB,QAAQ,EAAE,CACR,IAAI,EAAE,MAAM,EAAE,EACd,YAAY,EAAE,SAAS,CAAC,MAAM,CAAC,EAC/B,IAAI,EAAE,OAAO,EAAE,KACZ,OAAO,WAoBb"}
@@ -1,21 +0,0 @@
1
- import { createRecursiveProxy } from './createRecursiveProxy.js';
2
- /**
3
- * Create proxy for decorating procedures
4
- */
5
- export function createCallbackProxyDecoration(functions, callback) {
6
- return createRecursiveProxy((opts) => {
7
- const path = opts.path.slice(0, -1);
8
- // The last arg is for instance `.useMutation` or `.useQuery()`
9
- const functionName = opts.path[opts.path.length - 1];
10
- if (functionName === '_def') {
11
- return {
12
- path: path,
13
- };
14
- }
15
- if (!functions.includes(functionName)) {
16
- throw new Error(`Function ${functionName} is not supported`);
17
- }
18
- return callback(path, functionName, opts.args);
19
- }, []);
20
- }
21
- //# sourceMappingURL=createCallbackProxyDecoration.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"createCallbackProxyDecoration.js","sourceRoot":"","sources":["../../src/lib/createCallbackProxyDecoration.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AAEjE;;GAEG;AACH,MAAM,UAAU,6BAA6B,CAG3C,SAAoB,EACpB,QAIY;IAEZ,OAAO,oBAAoB,CAAC,CAAC,IAAI,EAAE,EAAE;QACnC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QAEpC,+DAA+D;QAC/D,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAErD,IAAI,YAAY,KAAK,MAAM,EAAE,CAAC;YAC5B,OAAO;gBACL,IAAI,EAAE,IAAI;aACX,CAAC;QACJ,CAAC;QAED,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC;YACtC,MAAM,IAAI,KAAK,CAAC,YAAY,YAAY,mBAAmB,CAAC,CAAC;QAC/D,CAAC;QAED,OAAO,QAAQ,CAAC,IAAI,EAAE,YAAY,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;IACjD,CAAC,EAAE,EAAE,CAAC,CAAC;AACT,CAAC"}
@@ -1,34 +0,0 @@
1
- import { createRecursiveProxy } from './createRecursiveProxy.js';
2
-
3
- /**
4
- * Create proxy for decorating procedures
5
- */
6
- export function createCallbackProxyDecoration<
7
- Functions extends string[] | Readonly<string[]>,
8
- >(
9
- functions: Functions,
10
- callback: (
11
- path: string[],
12
- functionName: Functions[number],
13
- args: unknown[]
14
- ) => unknown
15
- ) {
16
- return createRecursiveProxy((opts) => {
17
- const path = opts.path.slice(0, -1);
18
-
19
- // The last arg is for instance `.useMutation` or `.useQuery()`
20
- const functionName = opts.path[opts.path.length - 1];
21
-
22
- if (functionName === '_def') {
23
- return {
24
- path: path,
25
- };
26
- }
27
-
28
- if (!functions.includes(functionName)) {
29
- throw new Error(`Function ${functionName} is not supported`);
30
- }
31
-
32
- return callback(path, functionName, opts.args);
33
- }, []);
34
- }