@stiviar/modeled-react 1.0.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.
package/README.md ADDED
@@ -0,0 +1,73 @@
1
+ # @stiviar/react
2
+
3
+ React bindings for [stiviar](https://github.com/szlkeve/stiviar) — a declarative, type-safe API layer.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm i @stiviar/react
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ Define your models once:
14
+
15
+ ```ts
16
+ // api.ts
17
+ import { register } from "@stiviar/core";
18
+ import { Todos, TodosSchema, Users, UsersSchema } from "./types";
19
+
20
+ export const api = register<{
21
+ users: { type: Users };
22
+ todos: { type: Todos };
23
+ }>({
24
+ users: {
25
+ url: "https://api.example.com/users",
26
+ schema: UsersSchema,
27
+ },
28
+ todos: {
29
+ url: "https://api.example.com/todos",
30
+ schema: TodosSchema,
31
+ },
32
+ });
33
+
34
+ export const useData = api.useData;
35
+ export const isContractValid = api.isContractValid;
36
+ ```
37
+
38
+ Use it in a component:
39
+
40
+ ```tsx
41
+ // Component.tsx
42
+ import { useData } from "./api";
43
+
44
+ export function Component() {
45
+ const { data, isLoading, error } = useData("users");
46
+
47
+ if (isLoading) return <p>Loading…</p>;
48
+ if (error) return <p>Something went wrong.</p>;
49
+
50
+ return <div>user count: {data?.length}</div>;
51
+ }
52
+ ```
53
+
54
+ Types declared for a model flow through the whole codebase — hover `data` in your IDE and see the inferred type, with a compile-time error if your schema and type ever drift apart.
55
+
56
+ ## Testing
57
+
58
+ Swap the fetch implementation at registration time so components stay testable without a network:
59
+
60
+ ```ts
61
+ export const api = register<TypeModel>(apiModel, {
62
+ fetchFn: IS_DEV ? mockFetch : fetch,
63
+ });
64
+ ```
65
+
66
+ ## API
67
+
68
+ - `useData(key, params?)` — TanStack Query-backed fetch hook for a registered endpoint
69
+ - `isContractValid(openApiSchema)` — validates a live OpenAPI contract against your registered types
70
+
71
+ ## License
72
+
73
+ MIT
@@ -0,0 +1,37 @@
1
+ import { QueryClient } from '@tanstack/react-query';
2
+ import z from 'zod';
3
+
4
+ type BaseApiTypeMap = {
5
+ [stateName: string]: {
6
+ type: object | string | number | boolean;
7
+ } & ({
8
+ params: {
9
+ [param: string]: string | number;
10
+ };
11
+ } | {
12
+ params?: undefined;
13
+ });
14
+ };
15
+ type ApiModel<ApiTypeMap extends BaseApiTypeMap> = {
16
+ [NAME in keyof ApiTypeMap]: {
17
+ schema: z.ZodType<ApiTypeMap[NAME]["type"]>;
18
+ url: ApiTypeMap[NAME]["params"] extends object ? (params: ApiTypeMap[NAME]["params"]) => string : string;
19
+ };
20
+ };
21
+ type UseDataArgs<ApiTypeMap extends BaseApiTypeMap, NAME extends keyof ApiTypeMap> = ApiTypeMap[NAME]["params"] extends object ? [stateName: NAME, params: ApiTypeMap[NAME]["params"]] : [stateName: NAME, params?: undefined];
22
+ type Options = {
23
+ fetchFn?: (url: string) => Promise<unknown>;
24
+ baseUrl?: string;
25
+ };
26
+
27
+ declare function register<ApiTypeMap extends BaseApiTypeMap>(apiModel: ApiModel<ApiTypeMap>, options?: Options): {
28
+ useData: <NAME extends keyof ApiTypeMap>(...args: UseDataArgs<ApiTypeMap, NAME>) => {
29
+ data: ApiTypeMap[NAME]["type"] | undefined;
30
+ isLoading: boolean;
31
+ error: Error | null;
32
+ };
33
+ client: QueryClient;
34
+ invalidate: <NAME extends string | number>(...args: UseDataArgs<BaseApiTypeMap, NAME>) => Promise<void>;
35
+ };
36
+
37
+ export { register };
@@ -0,0 +1,37 @@
1
+ import { QueryClient } from '@tanstack/react-query';
2
+ import z from 'zod';
3
+
4
+ type BaseApiTypeMap = {
5
+ [stateName: string]: {
6
+ type: object | string | number | boolean;
7
+ } & ({
8
+ params: {
9
+ [param: string]: string | number;
10
+ };
11
+ } | {
12
+ params?: undefined;
13
+ });
14
+ };
15
+ type ApiModel<ApiTypeMap extends BaseApiTypeMap> = {
16
+ [NAME in keyof ApiTypeMap]: {
17
+ schema: z.ZodType<ApiTypeMap[NAME]["type"]>;
18
+ url: ApiTypeMap[NAME]["params"] extends object ? (params: ApiTypeMap[NAME]["params"]) => string : string;
19
+ };
20
+ };
21
+ type UseDataArgs<ApiTypeMap extends BaseApiTypeMap, NAME extends keyof ApiTypeMap> = ApiTypeMap[NAME]["params"] extends object ? [stateName: NAME, params: ApiTypeMap[NAME]["params"]] : [stateName: NAME, params?: undefined];
22
+ type Options = {
23
+ fetchFn?: (url: string) => Promise<unknown>;
24
+ baseUrl?: string;
25
+ };
26
+
27
+ declare function register<ApiTypeMap extends BaseApiTypeMap>(apiModel: ApiModel<ApiTypeMap>, options?: Options): {
28
+ useData: <NAME extends keyof ApiTypeMap>(...args: UseDataArgs<ApiTypeMap, NAME>) => {
29
+ data: ApiTypeMap[NAME]["type"] | undefined;
30
+ isLoading: boolean;
31
+ error: Error | null;
32
+ };
33
+ client: QueryClient;
34
+ invalidate: <NAME extends string | number>(...args: UseDataArgs<BaseApiTypeMap, NAME>) => Promise<void>;
35
+ };
36
+
37
+ export { register };