@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.
@@ -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
+ }