@simplix-react/react 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +59 -0
- package/dist/index.js +109 -0
- package/package.json +39 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { EntityDefinition, OperationDefinition, ApiContractConfig, QueryKeyFactory } from '@simplix-react/contract';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { UseMutationOptions, UseMutationResult, UseQueryOptions, UseQueryResult } from '@tanstack/react-query';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Derived query hook with options passthrough (C8 fix)
|
|
7
|
+
*/
|
|
8
|
+
type DerivedListHook<TData> = (parentId: string, options?: Omit<UseQueryOptions<TData[], Error>, "queryKey" | "queryFn">) => UseQueryResult<TData[]>;
|
|
9
|
+
type DerivedGetHook<TData> = (id: string, options?: Omit<UseQueryOptions<TData, Error>, "queryKey" | "queryFn">) => UseQueryResult<TData>;
|
|
10
|
+
type DerivedCreateHook<TInput, TOutput> = (parentId?: string, options?: Omit<UseMutationOptions<TOutput, Error, TInput>, "mutationFn">) => UseMutationResult<TOutput, Error, TInput>;
|
|
11
|
+
type DerivedUpdateHook<TInput, TOutput> = (options?: Omit<UseMutationOptions<TOutput, Error, {
|
|
12
|
+
id: string;
|
|
13
|
+
dto: TInput;
|
|
14
|
+
}>, "mutationFn">) => UseMutationResult<TOutput, Error, {
|
|
15
|
+
id: string;
|
|
16
|
+
dto: TInput;
|
|
17
|
+
}>;
|
|
18
|
+
type DerivedDeleteHook = (options?: Omit<UseMutationOptions<void, Error, string>, "mutationFn">) => UseMutationResult<void, Error, string>;
|
|
19
|
+
/**
|
|
20
|
+
* Entity hooks derived from EntityDefinition
|
|
21
|
+
*/
|
|
22
|
+
interface EntityHooks<TSchema extends z.ZodTypeAny, TCreate extends z.ZodTypeAny, TUpdate extends z.ZodTypeAny> {
|
|
23
|
+
useList: DerivedListHook<z.infer<TSchema>>;
|
|
24
|
+
useGet: DerivedGetHook<z.infer<TSchema>>;
|
|
25
|
+
useCreate: DerivedCreateHook<z.infer<TCreate>, z.infer<TSchema>>;
|
|
26
|
+
useUpdate: DerivedUpdateHook<z.infer<TUpdate>, z.infer<TSchema>>;
|
|
27
|
+
useDelete: DerivedDeleteHook;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Operation mutation hook
|
|
31
|
+
*/
|
|
32
|
+
type OperationMutationHook<TInput, TOutput> = (options?: Omit<UseMutationOptions<TOutput, Error, TInput>, "mutationFn">) => UseMutationResult<TOutput, Error, TInput>;
|
|
33
|
+
interface OperationHooks<TInput extends z.ZodTypeAny, TOutput extends z.ZodTypeAny> {
|
|
34
|
+
useMutation: OperationMutationHook<z.infer<TInput>, z.infer<TOutput>>;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
type AnyEntityDef = EntityDefinition<z.ZodTypeAny, z.ZodTypeAny, z.ZodTypeAny>;
|
|
38
|
+
type AnyOperationDef = OperationDefinition<z.ZodTypeAny, z.ZodTypeAny>;
|
|
39
|
+
/**
|
|
40
|
+
* Derive React Query hooks from an API contract.
|
|
41
|
+
*
|
|
42
|
+
* For each entity, generates: useList, useGet, useCreate, useUpdate, useDelete
|
|
43
|
+
* For each operation, generates: useMutation
|
|
44
|
+
*
|
|
45
|
+
* All hooks support options passthrough (C8 fix) and
|
|
46
|
+
* cache invalidation via operations.invalidates (C7 fix).
|
|
47
|
+
*/
|
|
48
|
+
declare function deriveHooks<TEntities extends Record<string, AnyEntityDef>, TOperations extends Record<string, AnyOperationDef>>(contract: {
|
|
49
|
+
config: ApiContractConfig<TEntities, TOperations>;
|
|
50
|
+
client: Record<string, unknown>;
|
|
51
|
+
queryKeys: Record<string, QueryKeyFactory>;
|
|
52
|
+
}): DerivedHooksResult<TEntities, TOperations>;
|
|
53
|
+
type DerivedHooksResult<TEntities extends Record<string, AnyEntityDef>, TOperations extends Record<string, AnyOperationDef>> = {
|
|
54
|
+
[K in keyof TEntities]: EntityHooks<TEntities[K]["schema"], TEntities[K]["createSchema"], TEntities[K]["updateSchema"]>;
|
|
55
|
+
} & {
|
|
56
|
+
[K in keyof TOperations]: TOperations[K] extends OperationDefinition<infer TInput, infer TOutput> ? OperationHooks<TInput, TOutput> : never;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
export { type DerivedCreateHook, type DerivedDeleteHook, type DerivedGetHook, type DerivedListHook, type DerivedUpdateHook, type EntityHooks, type OperationHooks, type OperationMutationHook, deriveHooks };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { useQueryClient, useMutation, useQuery } from '@tanstack/react-query';
|
|
2
|
+
|
|
3
|
+
// src/derive-hooks.ts
|
|
4
|
+
function deriveHooks(contract) {
|
|
5
|
+
const { config, client, queryKeys } = contract;
|
|
6
|
+
const result = {};
|
|
7
|
+
for (const entityName of Object.keys(config.entities)) {
|
|
8
|
+
const entity = config.entities[entityName];
|
|
9
|
+
const entityClient = client[entityName];
|
|
10
|
+
const keys = queryKeys[entityName];
|
|
11
|
+
result[entityName] = createEntityHooks(entity, entityClient, keys);
|
|
12
|
+
}
|
|
13
|
+
if (config.operations) {
|
|
14
|
+
for (const opName of Object.keys(config.operations)) {
|
|
15
|
+
const operation = config.operations[opName];
|
|
16
|
+
const opClient = client[opName];
|
|
17
|
+
result[opName] = createOperationHooks(opClient, operation, queryKeys);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return result;
|
|
21
|
+
}
|
|
22
|
+
function createEntityHooks(entity, entityClient, keys, allQueryKeys) {
|
|
23
|
+
return {
|
|
24
|
+
useList(parentId, options) {
|
|
25
|
+
return useQuery({
|
|
26
|
+
queryKey: keys.list(entity.parent ? { [entity.parent.param]: parentId } : {}),
|
|
27
|
+
queryFn: () => entityClient.list(entity.parent ? parentId : void 0),
|
|
28
|
+
enabled: entity.parent ? !!parentId : true,
|
|
29
|
+
...options
|
|
30
|
+
});
|
|
31
|
+
},
|
|
32
|
+
useGet(id, options) {
|
|
33
|
+
return useQuery({
|
|
34
|
+
queryKey: keys.detail(id),
|
|
35
|
+
queryFn: () => entityClient.get(id),
|
|
36
|
+
enabled: !!id,
|
|
37
|
+
...options
|
|
38
|
+
});
|
|
39
|
+
},
|
|
40
|
+
useCreate(parentId, options) {
|
|
41
|
+
const queryClient = useQueryClient();
|
|
42
|
+
return useMutation({
|
|
43
|
+
mutationFn: (dto) => {
|
|
44
|
+
if (entity.parent && parentId) {
|
|
45
|
+
return entityClient.create(parentId, dto);
|
|
46
|
+
}
|
|
47
|
+
return entityClient.create(dto);
|
|
48
|
+
},
|
|
49
|
+
onSuccess: (...args) => {
|
|
50
|
+
queryClient.invalidateQueries({ queryKey: keys.all });
|
|
51
|
+
options?.onSuccess?.(...args);
|
|
52
|
+
},
|
|
53
|
+
...omit(options, ["onSuccess"])
|
|
54
|
+
});
|
|
55
|
+
},
|
|
56
|
+
useUpdate(options) {
|
|
57
|
+
const queryClient = useQueryClient();
|
|
58
|
+
return useMutation({
|
|
59
|
+
mutationFn: ({ id, dto }) => entityClient.update(id, dto),
|
|
60
|
+
onSuccess: (...args) => {
|
|
61
|
+
queryClient.invalidateQueries({ queryKey: keys.all });
|
|
62
|
+
options?.onSuccess?.(...args);
|
|
63
|
+
},
|
|
64
|
+
...omit(options, ["onSuccess"])
|
|
65
|
+
});
|
|
66
|
+
},
|
|
67
|
+
useDelete(options) {
|
|
68
|
+
const queryClient = useQueryClient();
|
|
69
|
+
return useMutation({
|
|
70
|
+
mutationFn: (id) => entityClient.delete(id),
|
|
71
|
+
onSuccess: (...args) => {
|
|
72
|
+
queryClient.invalidateQueries({ queryKey: keys.all });
|
|
73
|
+
options?.onSuccess?.(...args);
|
|
74
|
+
},
|
|
75
|
+
...omit(options, ["onSuccess"])
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
function createOperationHooks(opClient, operation, allQueryKeys) {
|
|
81
|
+
return {
|
|
82
|
+
useMutation(options) {
|
|
83
|
+
const queryClient = useQueryClient();
|
|
84
|
+
return useMutation({
|
|
85
|
+
mutationFn: (input) => opClient(input),
|
|
86
|
+
onSuccess: (...args) => {
|
|
87
|
+
if (operation.invalidates) {
|
|
88
|
+
const keysToInvalidate = operation.invalidates(allQueryKeys, {});
|
|
89
|
+
for (const key of keysToInvalidate) {
|
|
90
|
+
queryClient.invalidateQueries({ queryKey: key });
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
options?.onSuccess?.(...args);
|
|
94
|
+
},
|
|
95
|
+
...omit(options, ["onSuccess"])
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
function omit(obj, keys) {
|
|
101
|
+
if (!obj) return {};
|
|
102
|
+
const result = { ...obj };
|
|
103
|
+
for (const key of keys) {
|
|
104
|
+
delete result[key];
|
|
105
|
+
}
|
|
106
|
+
return result;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export { deriveHooks };
|
package/package.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@simplix-react/react",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "React Query hooks derived from @simplix-react/contract",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": {
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"import": "./dist/index.js"
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
"files": ["dist"],
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "tsup",
|
|
15
|
+
"dev": "tsup --watch",
|
|
16
|
+
"typecheck": "tsc --noEmit",
|
|
17
|
+
"lint": "eslint src",
|
|
18
|
+
"test": "vitest run --passWithNoTests",
|
|
19
|
+
"clean": "rm -rf dist .turbo"
|
|
20
|
+
},
|
|
21
|
+
"peerDependencies": {
|
|
22
|
+
"@simplix-react/contract": "workspace:*",
|
|
23
|
+
"@tanstack/react-query": ">=5.0.0",
|
|
24
|
+
"react": ">=18.0.0",
|
|
25
|
+
"zod": ">=4.0.0"
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"@simplix-react/config-typescript": "workspace:*",
|
|
29
|
+
"@simplix-react/contract": "workspace:*",
|
|
30
|
+
"@tanstack/react-query": "^5.0.0",
|
|
31
|
+
"@types/react": "^19.0.0",
|
|
32
|
+
"eslint": "^9.39.2",
|
|
33
|
+
"react": "^19.0.0",
|
|
34
|
+
"tsup": "^8.5.1",
|
|
35
|
+
"typescript": "^5.9.3",
|
|
36
|
+
"vitest": "^3.0.0",
|
|
37
|
+
"zod": "^4.0.0"
|
|
38
|
+
}
|
|
39
|
+
}
|