@openapi-qraft/react 1.0.0-beta.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 (107) hide show
  1. package/README.md +287 -0
  2. package/dist/QraftContext.d.ts +8 -0
  3. package/dist/QraftContext.d.ts.map +1 -0
  4. package/dist/QraftContext.js +3 -0
  5. package/dist/QraftContext.js.map +1 -0
  6. package/dist/RequestClient.d.ts +19 -0
  7. package/dist/RequestClient.d.ts.map +1 -0
  8. package/dist/RequestClient.js +2 -0
  9. package/dist/RequestClient.js.map +1 -0
  10. package/dist/ServiceOperation.d.ts +122 -0
  11. package/dist/ServiceOperation.d.ts.map +1 -0
  12. package/dist/ServiceOperation.js +2 -0
  13. package/dist/ServiceOperation.js.map +1 -0
  14. package/dist/callbacks/getInfiniteQueryData.d.ts +6 -0
  15. package/dist/callbacks/getInfiniteQueryData.d.ts.map +1 -0
  16. package/dist/callbacks/getInfiniteQueryData.js +8 -0
  17. package/dist/callbacks/getInfiniteQueryData.js.map +1 -0
  18. package/dist/callbacks/getInfiniteQueryKey.d.ts +8 -0
  19. package/dist/callbacks/getInfiniteQueryKey.d.ts.map +1 -0
  20. package/dist/callbacks/getInfiniteQueryKey.js +7 -0
  21. package/dist/callbacks/getInfiniteQueryKey.js.map +1 -0
  22. package/dist/callbacks/getMutationKey.d.ts +5 -0
  23. package/dist/callbacks/getMutationKey.d.ts.map +1 -0
  24. package/dist/callbacks/getMutationKey.js +22 -0
  25. package/dist/callbacks/getMutationKey.js.map +1 -0
  26. package/dist/callbacks/getQueryData.d.ts +5 -0
  27. package/dist/callbacks/getQueryData.d.ts.map +1 -0
  28. package/dist/callbacks/getQueryData.js +8 -0
  29. package/dist/callbacks/getQueryData.js.map +1 -0
  30. package/dist/callbacks/getQueryKey.d.ts +7 -0
  31. package/dist/callbacks/getQueryKey.d.ts.map +1 -0
  32. package/dist/callbacks/getQueryKey.js +4 -0
  33. package/dist/callbacks/getQueryKey.js.map +1 -0
  34. package/dist/callbacks/mutationFn.d.ts +4 -0
  35. package/dist/callbacks/mutationFn.d.ts.map +1 -0
  36. package/dist/callbacks/mutationFn.js +8 -0
  37. package/dist/callbacks/mutationFn.js.map +1 -0
  38. package/dist/callbacks/queryFn.d.ts +15 -0
  39. package/dist/callbacks/queryFn.d.ts.map +1 -0
  40. package/dist/callbacks/queryFn.js +10 -0
  41. package/dist/callbacks/queryFn.js.map +1 -0
  42. package/dist/callbacks/setInfiniteQueryData.d.ts +6 -0
  43. package/dist/callbacks/setInfiniteQueryData.d.ts.map +1 -0
  44. package/dist/callbacks/setInfiniteQueryData.js +6 -0
  45. package/dist/callbacks/setInfiniteQueryData.js.map +1 -0
  46. package/dist/callbacks/setQueryData.d.ts +5 -0
  47. package/dist/callbacks/setQueryData.d.ts.map +1 -0
  48. package/dist/callbacks/setQueryData.js +9 -0
  49. package/dist/callbacks/setQueryData.js.map +1 -0
  50. package/dist/callbacks/useInfiniteQuery.d.ts +13 -0
  51. package/dist/callbacks/useInfiniteQuery.d.ts.map +1 -0
  52. package/dist/callbacks/useInfiniteQuery.js +50 -0
  53. package/dist/callbacks/useInfiniteQuery.js.map +1 -0
  54. package/dist/callbacks/useMutation.d.ts +7 -0
  55. package/dist/callbacks/useMutation.d.ts.map +1 -0
  56. package/dist/callbacks/useMutation.js +51 -0
  57. package/dist/callbacks/useMutation.js.map +1 -0
  58. package/dist/callbacks/useQuery.d.ts +9 -0
  59. package/dist/callbacks/useQuery.d.ts.map +1 -0
  60. package/dist/callbacks/useQuery.js +27 -0
  61. package/dist/callbacks/useQuery.js.map +1 -0
  62. package/dist/index.d.ts +9 -0
  63. package/dist/index.d.ts.map +1 -0
  64. package/dist/index.js +4 -0
  65. package/dist/index.js.map +1 -0
  66. package/dist/lib/createCallbackProxyDecoration.d.ts +5 -0
  67. package/dist/lib/createCallbackProxyDecoration.d.ts.map +1 -0
  68. package/dist/lib/createCallbackProxyDecoration.js +21 -0
  69. package/dist/lib/createCallbackProxyDecoration.js.map +1 -0
  70. package/dist/lib/createRecursiveProxy.d.ts +7 -0
  71. package/dist/lib/createRecursiveProxy.d.ts.map +1 -0
  72. package/dist/lib/createRecursiveProxy.js +24 -0
  73. package/dist/lib/createRecursiveProxy.js.map +1 -0
  74. package/dist/lib/request.d.ts +32 -0
  75. package/dist/lib/request.d.ts.map +1 -0
  76. package/dist/lib/request.js +167 -0
  77. package/dist/lib/request.js.map +1 -0
  78. package/dist/qraftAPIClient.d.ts +25 -0
  79. package/dist/qraftAPIClient.d.ts.map +1 -0
  80. package/dist/qraftAPIClient.js +22 -0
  81. package/dist/qraftAPIClient.js.map +1 -0
  82. package/package.json +79 -0
  83. package/src/QraftContext.ts +12 -0
  84. package/src/RequestClient.ts +32 -0
  85. package/src/ServiceOperation.ts +306 -0
  86. package/src/callbacks/getInfiniteQueryData.ts +26 -0
  87. package/src/callbacks/getInfiniteQueryKey.ts +23 -0
  88. package/src/callbacks/getMutationKey.ts +47 -0
  89. package/src/callbacks/getQueryData.ts +20 -0
  90. package/src/callbacks/getQueryKey.ts +19 -0
  91. package/src/callbacks/mutationFn.ts +22 -0
  92. package/src/callbacks/queryFn.ts +21 -0
  93. package/src/callbacks/setInfiniteQueryData.ts +29 -0
  94. package/src/callbacks/setQueryData.ts +23 -0
  95. package/src/callbacks/shelfMerge.test.ts +94 -0
  96. package/src/callbacks/useInfiniteQuery.ts +88 -0
  97. package/src/callbacks/useMutation.ts +100 -0
  98. package/src/callbacks/useQuery.ts +56 -0
  99. package/src/index.ts +11 -0
  100. package/src/lib/createCallbackProxyDecoration.ts +34 -0
  101. package/src/lib/createRecursiveProxy.ts +27 -0
  102. package/src/lib/request.ts +252 -0
  103. package/src/mocks/handlers.ts +252 -0
  104. package/src/mocks/node.ts +5 -0
  105. package/src/qraftAPIClient.test.tsx +595 -0
  106. package/src/qraftAPIClient.ts +77 -0
  107. package/src/setupTests.ts +17 -0
@@ -0,0 +1,29 @@
1
+ import { InfiniteData } from '@tanstack/query-core';
2
+
3
+ import type { QraftClientOptions } from '../qraftAPIClient.js';
4
+ import type { RequestClientSchema } from '../RequestClient.js';
5
+ import type {
6
+ ServiceOperationInfiniteQueryKey,
7
+ ServiceOperationQuery,
8
+ } from '../ServiceOperation.js';
9
+
10
+ export function setInfiniteQueryData<TData>(
11
+ qraftOptions: QraftClientOptions | undefined,
12
+ schema: RequestClientSchema,
13
+ args: Parameters<
14
+ ServiceOperationQuery<
15
+ RequestClientSchema,
16
+ unknown,
17
+ TData
18
+ >['setInfiniteQueryData']
19
+ >
20
+ ): InfiniteData<TData> | undefined {
21
+ const [params, updater, queryClient, options] = args;
22
+
23
+ const queryKey: ServiceOperationInfiniteQueryKey<
24
+ RequestClientSchema,
25
+ unknown
26
+ > = [{ url: schema.url, infinite: true }, params];
27
+
28
+ return queryClient.setQueryData(queryKey, updater as never, options);
29
+ }
@@ -0,0 +1,23 @@
1
+ import type { QraftClientOptions } from '../qraftAPIClient.js';
2
+ import type { RequestClientSchema } from '../RequestClient.js';
3
+ import {
4
+ ServiceOperationQuery,
5
+ ServiceOperationQueryKey,
6
+ } from '../ServiceOperation.js';
7
+
8
+ export function setQueryData<TData>(
9
+ qraftOptions: QraftClientOptions | undefined,
10
+ schema: RequestClientSchema,
11
+ args: Parameters<
12
+ ServiceOperationQuery<RequestClientSchema, unknown, TData>['setQueryData']
13
+ >
14
+ ): TData | undefined {
15
+ const [params, updater, queryClient, options] = args;
16
+
17
+ const queryKey: ServiceOperationQueryKey<RequestClientSchema, unknown> = [
18
+ { url: schema.url },
19
+ params,
20
+ ];
21
+
22
+ return queryClient.setQueryData(queryKey, updater as never, options);
23
+ }
@@ -0,0 +1,94 @@
1
+ import { shelfMerge } from './useInfiniteQuery.js';
2
+
3
+ describe('shelfMerge', () => {
4
+ it('merges simple objects', async () => {
5
+ expect(shelfMerge(1, { path: 1 }, { query: 2 }, { header: 3 })).toEqual({
6
+ path: 1,
7
+ query: 2,
8
+ header: 3,
9
+ });
10
+ });
11
+
12
+ it('merges simple objects with overlapping', async () => {
13
+ expect(
14
+ shelfMerge(2, { path: 1 }, { path: { id: 22 } }, { header: 3 })
15
+ ).toEqual({
16
+ path: { id: 22 },
17
+ header: 3,
18
+ });
19
+ });
20
+
21
+ it('merges objects with overlapping in child objects', async () => {
22
+ expect(
23
+ shelfMerge(
24
+ 2,
25
+ { query: { id: 11, page: 22 } },
26
+ { query: { id: 44, limit: 33 } },
27
+ { header: 3 }
28
+ )
29
+ ).toEqual({
30
+ query: { id: 44, page: 22, limit: 33 },
31
+ header: 3,
32
+ });
33
+ });
34
+
35
+ it('merges objects with overlapping in child objects on specific depth (1)', async () => {
36
+ expect(
37
+ shelfMerge(
38
+ 1,
39
+ { query: { id: 11, page: 22 } },
40
+ { query: { id: 44, limit: 33 } },
41
+ { header: 3 }
42
+ )
43
+ ).toEqual({
44
+ query: { id: 44, limit: 33 },
45
+ header: 3,
46
+ });
47
+ });
48
+
49
+ it('merges objects with overlapping in child objects on specific depth (2)', async () => {
50
+ expect(
51
+ shelfMerge(
52
+ 2,
53
+ { query: { id: 11, page: 22 } },
54
+ { query: { id: 44, limit: 33 } },
55
+ { header: 3 }
56
+ )
57
+ ).toEqual({
58
+ query: { id: 44, limit: 33, page: 22 },
59
+ header: 3,
60
+ });
61
+ });
62
+
63
+ it('merges arrays without nesting', async () => {
64
+ expect(
65
+ shelfMerge(
66
+ 2,
67
+ { query: [{ id: 11, page: 22 }] },
68
+ { query: [{ id: 44, limit: 33 }] },
69
+ { header: 3 }
70
+ )
71
+ ).toEqual({
72
+ query: [{ id: 44, limit: 33 }],
73
+ header: 3,
74
+ });
75
+ });
76
+
77
+ it('merges objects with overlapping in child objects and depth', async () => {
78
+ expect(
79
+ shelfMerge(
80
+ 3,
81
+ { query: { one: { id: 11, page: 22 }, two: { ids: [55] } } },
82
+ { query: { one: { id: 44, limit: 33 }, three: { filter: 66 } } },
83
+ { header: 3 }
84
+ )
85
+ ).toEqual({
86
+ query: {
87
+ one: { id: 44, page: 22, limit: 33 },
88
+ two: { ids: [55] },
89
+ three: { filter: 66 },
90
+ },
91
+ header: 3,
92
+ });
93
+ });
94
+ });
@@ -0,0 +1,88 @@
1
+ import { useContext } from 'react';
2
+
3
+ import type { DefaultError, InfiniteData } from '@tanstack/query-core';
4
+ import {
5
+ useInfiniteQuery as useInfiniteQueryBase,
6
+ UseInfiniteQueryResult,
7
+ } from '@tanstack/react-query';
8
+
9
+ import type { QraftClientOptions } from '../qraftAPIClient.js';
10
+ import { QraftContext } from '../QraftContext.js';
11
+ import type { RequestClientSchema } from '../RequestClient.js';
12
+ import { ServiceOperationQuery } from '../ServiceOperation.js';
13
+
14
+ export const useInfiniteQuery: <
15
+ TQueryFnData,
16
+ TError = DefaultError,
17
+ TData = InfiniteData<TQueryFnData>,
18
+ >(
19
+ qraftOptions: QraftClientOptions | undefined,
20
+ schema: RequestClientSchema,
21
+ args: Parameters<
22
+ ServiceOperationQuery<
23
+ RequestClientSchema,
24
+ unknown,
25
+ unknown
26
+ >['useInfiniteQuery']
27
+ >
28
+ ) => UseInfiniteQueryResult<TData, TError> = (qraftOptions, schema, args) => {
29
+ const [params, options, ...restArgs] = args;
30
+
31
+ const requestClient = useContext(qraftOptions?.context ?? QraftContext)
32
+ ?.requestClient;
33
+
34
+ if (!requestClient) throw new Error(`QraftContext.requestClient not found`);
35
+
36
+ return useInfiniteQueryBase(
37
+ {
38
+ ...options,
39
+ queryKey: [{ url: schema.url, infinite: true }, params as never] as const,
40
+ queryFn:
41
+ options?.queryFn ??
42
+ function ({ queryKey: [, queryParams], signal, meta, pageParam }) {
43
+ return requestClient(schema, {
44
+ parameters: shelfMerge(2, queryParams, pageParam) as never,
45
+ signal,
46
+ meta,
47
+ });
48
+ },
49
+ },
50
+ ...restArgs
51
+ ) as never;
52
+ };
53
+
54
+ /**
55
+ * Merges objects with provided depth
56
+ * @param depth
57
+ * @param args
58
+ */
59
+ export function shelfMerge<T>(depth = 2, ...args: T[]): T {
60
+ return args.reduce((acc, arg) => {
61
+ if (!arg || typeof arg !== 'object') return acc;
62
+
63
+ Object.entries(arg).forEach(([key, value]) => {
64
+ if (typeof value !== 'object') {
65
+ acc[key as never] = value as never;
66
+ return;
67
+ }
68
+
69
+ if (Array.isArray(value)) {
70
+ acc[key as never] = value as never;
71
+ return;
72
+ }
73
+
74
+ if (depth > 1) {
75
+ acc[key as never] = shelfMerge(
76
+ depth - 1,
77
+ acc[key as never],
78
+ value
79
+ ) as never;
80
+ return;
81
+ }
82
+
83
+ acc[key as never] = value as never;
84
+ });
85
+
86
+ return acc;
87
+ }, {} as T);
88
+ }
@@ -0,0 +1,100 @@
1
+ import { useContext } from 'react';
2
+
3
+ import type { DefaultError } from '@tanstack/query-core';
4
+ import type { UseMutationResult } from '@tanstack/react-query';
5
+ import { useMutation as useMutationBase } from '@tanstack/react-query';
6
+
7
+ import type { QraftClientOptions } from '../qraftAPIClient.js';
8
+ import { QraftContext } from '../QraftContext.js';
9
+ import type { RequestClientSchema } from '../RequestClient.js';
10
+ import {
11
+ ServiceOperationMutation,
12
+ ServiceOperationMutationKey,
13
+ } from '../ServiceOperation.js';
14
+
15
+ export const useMutation: <
16
+ TData = unknown,
17
+ TError = DefaultError,
18
+ TVariables = void,
19
+ TContext = unknown,
20
+ >(
21
+ qraftOptions: QraftClientOptions | undefined,
22
+ schema: RequestClientSchema,
23
+ args: Parameters<
24
+ ServiceOperationMutation<
25
+ RequestClientSchema,
26
+ object | undefined,
27
+ TVariables,
28
+ TData
29
+ >['useMutation']
30
+ >
31
+ ) => UseMutationResult<TData, TError, TVariables, TContext> = (
32
+ qraftOptions,
33
+ schema,
34
+ args
35
+ ) => {
36
+ const [parameters, options, ...restArgs] = args;
37
+
38
+ if (
39
+ parameters &&
40
+ typeof parameters === 'object' &&
41
+ options &&
42
+ 'mutationKey' in options
43
+ )
44
+ throw new Error(
45
+ `'useMutation': parameters and 'options.mutationKey' cannot be used together`
46
+ );
47
+
48
+ const requestClient = useContext(qraftOptions?.context ?? QraftContext)
49
+ ?.requestClient;
50
+
51
+ if (!requestClient) throw new Error(`QraftContext.requestClient not found`);
52
+
53
+ const mutationKey =
54
+ parameters && typeof parameters === 'object'
55
+ ? ([
56
+ {
57
+ url: schema.url,
58
+ method: schema.method,
59
+ },
60
+ parameters,
61
+ ] as const)
62
+ : options && 'mutationKey' in options
63
+ ? (options.mutationKey as ServiceOperationMutationKey<
64
+ typeof schema,
65
+ unknown
66
+ >)
67
+ : ([
68
+ {
69
+ url: schema.url,
70
+ method: schema.method,
71
+ },
72
+ ] as const);
73
+
74
+ return useMutationBase(
75
+ {
76
+ ...options,
77
+ mutationKey,
78
+ mutationFn:
79
+ options?.mutationFn ??
80
+ (parameters
81
+ ? function (bodyPayload) {
82
+ return requestClient(schema, {
83
+ parameters,
84
+ body: bodyPayload as never,
85
+ });
86
+ }
87
+ : function (parametersAndBodyPayload) {
88
+ const { body, ...parameters } = parametersAndBodyPayload as {
89
+ body: unknown;
90
+ };
91
+
92
+ return requestClient(schema, {
93
+ body,
94
+ parameters,
95
+ } as never);
96
+ }),
97
+ },
98
+ ...restArgs
99
+ ) as never;
100
+ };
@@ -0,0 +1,56 @@
1
+ import { useContext } from 'react';
2
+
3
+ import type { DefaultError } from '@tanstack/query-core';
4
+ import type { UseQueryResult } from '@tanstack/react-query';
5
+ import { useQuery as useQueryBase } from '@tanstack/react-query';
6
+
7
+ import type { QraftClientOptions } from '../qraftAPIClient.js';
8
+ import { QraftContext } from '../QraftContext.js';
9
+ import type { RequestClientSchema } from '../RequestClient.js';
10
+ import {
11
+ ServiceOperationQuery,
12
+ ServiceOperationQueryKey,
13
+ } from '../ServiceOperation.js';
14
+
15
+ export const useQuery: <
16
+ TQueryFnData = unknown,
17
+ TError = DefaultError,
18
+ TData = TQueryFnData,
19
+ >(
20
+ qraftOptions: QraftClientOptions | undefined,
21
+ schema: RequestClientSchema,
22
+ args: Parameters<
23
+ ServiceOperationQuery<RequestClientSchema, unknown, unknown>['useQuery']
24
+ >
25
+ ) => UseQueryResult<TData, TError> & {
26
+ queryKey: ServiceOperationQueryKey<RequestClientSchema, unknown>;
27
+ } = (qraftOptions, schema, args) => {
28
+ const [params, options, ...restArgs] = args;
29
+
30
+ const requestClient = useContext(qraftOptions?.context ?? QraftContext)
31
+ ?.requestClient;
32
+
33
+ if (!requestClient) throw new Error(`QraftContext.requestClient not found`);
34
+
35
+ const queryKey: ServiceOperationQueryKey<RequestClientSchema, unknown> = [
36
+ { url: schema.url },
37
+ params,
38
+ ];
39
+
40
+ return useQueryBase(
41
+ {
42
+ ...options,
43
+ queryKey,
44
+ queryFn:
45
+ options?.queryFn ??
46
+ function ({ queryKey: [, queryParams], signal, meta }) {
47
+ return requestClient(schema, {
48
+ parameters: queryParams as never,
49
+ signal,
50
+ meta,
51
+ });
52
+ },
53
+ },
54
+ ...restArgs
55
+ ) as never;
56
+ };
package/src/index.ts ADDED
@@ -0,0 +1,11 @@
1
+ export { qraftAPIClient } from './qraftAPIClient.js';
2
+ export type { QraftClientOptions } from './qraftAPIClient.js';
3
+ export { QraftContext } from './QraftContext.js';
4
+ export type { QraftContextValue } from './QraftContext.js';
5
+ export { request, urlSerializer, bodySerializer } from './lib/request.js';
6
+ export type { APIRequestInit, HeadersOptions } from './lib/request.js';
7
+ export type {
8
+ ServiceOperationQuery,
9
+ ServiceOperationMutation,
10
+ } from './ServiceOperation.js';
11
+ export type { RequestClient } from './RequestClient.js';
@@ -0,0 +1,34 @@
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
+ }
@@ -0,0 +1,27 @@
1
+ type ProxyCallback = (opts: { path: string[]; args: unknown[] }) => unknown;
2
+
3
+ export function createRecursiveProxy(callback: ProxyCallback, path: string[]) {
4
+ const proxy: unknown = new Proxy(noop, {
5
+ get(_obj, key) {
6
+ if (typeof key !== 'string' || key === 'then') {
7
+ // special case for if the proxy is accidentally treated
8
+ // like a PromiseLike (like in `Promise.resolve(proxy)`)
9
+ return undefined;
10
+ }
11
+ return createRecursiveProxy(callback, [...path, key]);
12
+ },
13
+ 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
+ });
19
+ },
20
+ });
21
+
22
+ return proxy;
23
+ }
24
+
25
+ function noop() {
26
+ // noop
27
+ }