@objectstack/client-react 0.6.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.js ADDED
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ /**
3
+ * @objectstack/client-react
4
+ *
5
+ * React hooks for ObjectStack Client SDK
6
+ *
7
+ * Provides type-safe React hooks for:
8
+ * - Data queries (useQuery, useMutation, usePagination, useInfiniteQuery)
9
+ * - Metadata access (useObject, useView, useFields, useMetadata)
10
+ * - Client context (ObjectStackProvider, useClient)
11
+ */
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.ObjectStackClient = exports.useMetadata = exports.useFields = exports.useView = exports.useObject = exports.useInfiniteQuery = exports.usePagination = exports.useMutation = exports.useQuery = exports.useClient = exports.ObjectStackContext = exports.ObjectStackProvider = void 0;
14
+ // Context & Provider
15
+ var context_1 = require("./context");
16
+ Object.defineProperty(exports, "ObjectStackProvider", { enumerable: true, get: function () { return context_1.ObjectStackProvider; } });
17
+ Object.defineProperty(exports, "ObjectStackContext", { enumerable: true, get: function () { return context_1.ObjectStackContext; } });
18
+ Object.defineProperty(exports, "useClient", { enumerable: true, get: function () { return context_1.useClient; } });
19
+ // Data Hooks
20
+ var data_hooks_1 = require("./data-hooks");
21
+ Object.defineProperty(exports, "useQuery", { enumerable: true, get: function () { return data_hooks_1.useQuery; } });
22
+ Object.defineProperty(exports, "useMutation", { enumerable: true, get: function () { return data_hooks_1.useMutation; } });
23
+ Object.defineProperty(exports, "usePagination", { enumerable: true, get: function () { return data_hooks_1.usePagination; } });
24
+ Object.defineProperty(exports, "useInfiniteQuery", { enumerable: true, get: function () { return data_hooks_1.useInfiniteQuery; } });
25
+ // Metadata Hooks
26
+ var metadata_hooks_1 = require("./metadata-hooks");
27
+ Object.defineProperty(exports, "useObject", { enumerable: true, get: function () { return metadata_hooks_1.useObject; } });
28
+ Object.defineProperty(exports, "useView", { enumerable: true, get: function () { return metadata_hooks_1.useView; } });
29
+ Object.defineProperty(exports, "useFields", { enumerable: true, get: function () { return metadata_hooks_1.useFields; } });
30
+ Object.defineProperty(exports, "useMetadata", { enumerable: true, get: function () { return metadata_hooks_1.useMetadata; } });
31
+ // Re-export ObjectStackClient and types from @objectstack/client
32
+ var client_1 = require("@objectstack/client");
33
+ Object.defineProperty(exports, "ObjectStackClient", { enumerable: true, get: function () { return client_1.ObjectStackClient; } });
@@ -0,0 +1,121 @@
1
+ /**
2
+ * Metadata Hooks
3
+ *
4
+ * React hooks for accessing ObjectStack metadata (schemas, views, fields)
5
+ */
6
+ import { useClient } from './context';
7
+ /**
8
+ * Metadata query options
9
+ */
10
+ export interface UseMetadataOptions {
11
+ /** Enable/disable automatic query execution */
12
+ enabled?: boolean;
13
+ /** Use cached metadata if available */
14
+ useCache?: boolean;
15
+ /** ETag for conditional requests */
16
+ ifNoneMatch?: string;
17
+ /** If-Modified-Since header for conditional requests */
18
+ ifModifiedSince?: string;
19
+ /** Callback on successful query */
20
+ onSuccess?: (data: any) => void;
21
+ /** Callback on error */
22
+ onError?: (error: Error) => void;
23
+ }
24
+ /**
25
+ * Metadata query result
26
+ */
27
+ export interface UseMetadataResult<T = any> {
28
+ /** Metadata data */
29
+ data: T | null;
30
+ /** Loading state */
31
+ isLoading: boolean;
32
+ /** Error state */
33
+ error: Error | null;
34
+ /** Refetch the metadata */
35
+ refetch: () => Promise<void>;
36
+ /** ETag from last fetch */
37
+ etag?: string;
38
+ /** Whether data came from cache (304 Not Modified) */
39
+ fromCache: boolean;
40
+ }
41
+ /**
42
+ * Hook for fetching object schema/metadata
43
+ *
44
+ * @example
45
+ * ```tsx
46
+ * function ObjectSchemaViewer({ objectName }: { objectName: string }) {
47
+ * const { data: schema, isLoading, error } = useObject(objectName);
48
+ *
49
+ * if (isLoading) return <div>Loading schema...</div>;
50
+ * if (error) return <div>Error: {error.message}</div>;
51
+ *
52
+ * return (
53
+ * <div>
54
+ * <h2>{schema.label}</h2>
55
+ * <p>Fields: {Object.keys(schema.fields).length}</p>
56
+ * </div>
57
+ * );
58
+ * }
59
+ * ```
60
+ */
61
+ export declare function useObject(objectName: string, options?: UseMetadataOptions): UseMetadataResult;
62
+ /**
63
+ * Hook for fetching view configuration
64
+ *
65
+ * @example
66
+ * ```tsx
67
+ * function ViewConfiguration({ objectName }: { objectName: string }) {
68
+ * const { data: view, isLoading } = useView(objectName, 'list');
69
+ *
70
+ * if (isLoading) return <div>Loading view...</div>;
71
+ *
72
+ * return (
73
+ * <div>
74
+ * <h3>List View for {objectName}</h3>
75
+ * <p>Columns: {view?.columns?.length}</p>
76
+ * </div>
77
+ * );
78
+ * }
79
+ * ```
80
+ */
81
+ export declare function useView(objectName: string, viewType?: 'list' | 'form', options?: UseMetadataOptions): UseMetadataResult;
82
+ /**
83
+ * Hook for extracting fields from object schema
84
+ *
85
+ * @example
86
+ * ```tsx
87
+ * function FieldList({ objectName }: { objectName: string }) {
88
+ * const { data: fields, isLoading } = useFields(objectName);
89
+ *
90
+ * if (isLoading) return <div>Loading fields...</div>;
91
+ *
92
+ * return (
93
+ * <ul>
94
+ * {fields?.map(field => (
95
+ * <li key={field.name}>{field.label} ({field.type})</li>
96
+ * ))}
97
+ * </ul>
98
+ * );
99
+ * }
100
+ * ```
101
+ */
102
+ export declare function useFields(objectName: string, options?: UseMetadataOptions): UseMetadataResult<any[]>;
103
+ /**
104
+ * Generic metadata hook for custom metadata queries
105
+ *
106
+ * @example
107
+ * ```tsx
108
+ * function CustomMetadata() {
109
+ * const { data, isLoading } = useMetadata(async (client) => {
110
+ * // Custom metadata fetching logic
111
+ * const object = await client.meta.getObject('custom_object');
112
+ * const view = await client.meta.getView('custom_object', 'list');
113
+ * return { object, view };
114
+ * });
115
+ *
116
+ * return <pre>{JSON.stringify(data, null, 2)}</pre>;
117
+ * }
118
+ * ```
119
+ */
120
+ export declare function useMetadata<T = any>(fetcher: (client: ReturnType<typeof useClient>) => Promise<T>, options?: Omit<UseMetadataOptions, 'useCache' | 'ifNoneMatch' | 'ifModifiedSince'>): UseMetadataResult<T>;
121
+ //# sourceMappingURL=metadata-hooks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metadata-hooks.d.ts","sourceRoot":"","sources":["../src/metadata-hooks.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEtC;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,+CAA+C;IAC/C,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,uCAAuC;IACvC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,oCAAoC;IACpC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,wDAAwD;IACxD,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,mCAAmC;IACnC,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK,IAAI,CAAC;IAChC,wBAAwB;IACxB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CAClC;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB,CAAC,CAAC,GAAG,GAAG;IACxC,oBAAoB;IACpB,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC;IACf,oBAAoB;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,kBAAkB;IAClB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,2BAA2B;IAC3B,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7B,2BAA2B;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,sDAAsD;IACtD,SAAS,EAAE,OAAO,CAAC;CACpB;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,SAAS,CACvB,UAAU,EAAE,MAAM,EAClB,OAAO,GAAE,kBAAuB,GAC/B,iBAAiB,CAyEnB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,OAAO,CACrB,UAAU,EAAE,MAAM,EAClB,QAAQ,GAAE,MAAM,GAAG,MAAe,EAClC,OAAO,GAAE,kBAAuB,GAC/B,iBAAiB,CA0CnB;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,SAAS,CACvB,UAAU,EAAE,MAAM,EAClB,OAAO,GAAE,kBAAuB,GAC/B,iBAAiB,CAAC,GAAG,EAAE,CAAC,CAc1B;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,WAAW,CAAC,CAAC,GAAG,GAAG,EACjC,OAAO,EAAE,CAAC,MAAM,EAAE,UAAU,CAAC,OAAO,SAAS,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,EAC7D,OAAO,GAAE,IAAI,CAAC,kBAAkB,EAAE,UAAU,GAAG,aAAa,GAAG,iBAAiB,CAAM,GACrF,iBAAiB,CAAC,CAAC,CAAC,CA0CtB"}
@@ -0,0 +1,243 @@
1
+ "use strict";
2
+ /**
3
+ * Metadata Hooks
4
+ *
5
+ * React hooks for accessing ObjectStack metadata (schemas, views, fields)
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.useObject = useObject;
9
+ exports.useView = useView;
10
+ exports.useFields = useFields;
11
+ exports.useMetadata = useMetadata;
12
+ const react_1 = require("react");
13
+ const context_1 = require("./context");
14
+ /**
15
+ * Hook for fetching object schema/metadata
16
+ *
17
+ * @example
18
+ * ```tsx
19
+ * function ObjectSchemaViewer({ objectName }: { objectName: string }) {
20
+ * const { data: schema, isLoading, error } = useObject(objectName);
21
+ *
22
+ * if (isLoading) return <div>Loading schema...</div>;
23
+ * if (error) return <div>Error: {error.message}</div>;
24
+ *
25
+ * return (
26
+ * <div>
27
+ * <h2>{schema.label}</h2>
28
+ * <p>Fields: {Object.keys(schema.fields).length}</p>
29
+ * </div>
30
+ * );
31
+ * }
32
+ * ```
33
+ */
34
+ function useObject(objectName, options = {}) {
35
+ const client = (0, context_1.useClient)();
36
+ const [data, setData] = (0, react_1.useState)(null);
37
+ const [isLoading, setIsLoading] = (0, react_1.useState)(true);
38
+ const [error, setError] = (0, react_1.useState)(null);
39
+ const [etag, setEtag] = (0, react_1.useState)();
40
+ const [fromCache, setFromCache] = (0, react_1.useState)(false);
41
+ const { enabled = true, useCache = true, ifNoneMatch, ifModifiedSince, onSuccess, onError } = options;
42
+ const fetchMetadata = (0, react_1.useCallback)(async () => {
43
+ if (!enabled)
44
+ return;
45
+ try {
46
+ setIsLoading(true);
47
+ setError(null);
48
+ setFromCache(false);
49
+ if (useCache) {
50
+ // Use cached metadata endpoint
51
+ const result = await client.meta.getCached(objectName, {
52
+ ifNoneMatch: ifNoneMatch || etag,
53
+ ifModifiedSince
54
+ });
55
+ if (result.notModified) {
56
+ setFromCache(true);
57
+ }
58
+ else {
59
+ setData(result.data);
60
+ if (result.etag) {
61
+ setEtag(result.etag.value);
62
+ }
63
+ }
64
+ onSuccess?.(result.data || data);
65
+ }
66
+ else {
67
+ // Direct fetch without cache
68
+ const result = await client.meta.getObject(objectName);
69
+ setData(result);
70
+ onSuccess?.(result);
71
+ }
72
+ }
73
+ catch (err) {
74
+ const error = err instanceof Error ? err : new Error('Failed to fetch object metadata');
75
+ setError(error);
76
+ onError?.(error);
77
+ }
78
+ finally {
79
+ setIsLoading(false);
80
+ }
81
+ }, [client, objectName, enabled, useCache, ifNoneMatch, ifModifiedSince, etag, data, onSuccess, onError]);
82
+ (0, react_1.useEffect)(() => {
83
+ fetchMetadata();
84
+ }, [fetchMetadata]);
85
+ const refetch = (0, react_1.useCallback)(async () => {
86
+ await fetchMetadata();
87
+ }, [fetchMetadata]);
88
+ return {
89
+ data,
90
+ isLoading,
91
+ error,
92
+ refetch,
93
+ etag,
94
+ fromCache
95
+ };
96
+ }
97
+ /**
98
+ * Hook for fetching view configuration
99
+ *
100
+ * @example
101
+ * ```tsx
102
+ * function ViewConfiguration({ objectName }: { objectName: string }) {
103
+ * const { data: view, isLoading } = useView(objectName, 'list');
104
+ *
105
+ * if (isLoading) return <div>Loading view...</div>;
106
+ *
107
+ * return (
108
+ * <div>
109
+ * <h3>List View for {objectName}</h3>
110
+ * <p>Columns: {view?.columns?.length}</p>
111
+ * </div>
112
+ * );
113
+ * }
114
+ * ```
115
+ */
116
+ function useView(objectName, viewType = 'list', options = {}) {
117
+ const client = (0, context_1.useClient)();
118
+ const [data, setData] = (0, react_1.useState)(null);
119
+ const [isLoading, setIsLoading] = (0, react_1.useState)(true);
120
+ const [error, setError] = (0, react_1.useState)(null);
121
+ const { enabled = true, onSuccess, onError } = options;
122
+ const fetchView = (0, react_1.useCallback)(async () => {
123
+ if (!enabled)
124
+ return;
125
+ try {
126
+ setIsLoading(true);
127
+ setError(null);
128
+ const result = await client.meta.getView(objectName, viewType);
129
+ setData(result);
130
+ onSuccess?.(result);
131
+ }
132
+ catch (err) {
133
+ const error = err instanceof Error ? err : new Error('Failed to fetch view configuration');
134
+ setError(error);
135
+ onError?.(error);
136
+ }
137
+ finally {
138
+ setIsLoading(false);
139
+ }
140
+ }, [client, objectName, viewType, enabled, onSuccess, onError]);
141
+ (0, react_1.useEffect)(() => {
142
+ fetchView();
143
+ }, [fetchView]);
144
+ const refetch = (0, react_1.useCallback)(async () => {
145
+ await fetchView();
146
+ }, [fetchView]);
147
+ return {
148
+ data,
149
+ isLoading,
150
+ error,
151
+ refetch,
152
+ fromCache: false
153
+ };
154
+ }
155
+ /**
156
+ * Hook for extracting fields from object schema
157
+ *
158
+ * @example
159
+ * ```tsx
160
+ * function FieldList({ objectName }: { objectName: string }) {
161
+ * const { data: fields, isLoading } = useFields(objectName);
162
+ *
163
+ * if (isLoading) return <div>Loading fields...</div>;
164
+ *
165
+ * return (
166
+ * <ul>
167
+ * {fields?.map(field => (
168
+ * <li key={field.name}>{field.label} ({field.type})</li>
169
+ * ))}
170
+ * </ul>
171
+ * );
172
+ * }
173
+ * ```
174
+ */
175
+ function useFields(objectName, options = {}) {
176
+ const objectResult = useObject(objectName, options);
177
+ const fields = objectResult.data?.fields
178
+ ? Object.entries(objectResult.data.fields).map(([name, field]) => ({
179
+ name,
180
+ ...field
181
+ }))
182
+ : null;
183
+ return {
184
+ ...objectResult,
185
+ data: fields
186
+ };
187
+ }
188
+ /**
189
+ * Generic metadata hook for custom metadata queries
190
+ *
191
+ * @example
192
+ * ```tsx
193
+ * function CustomMetadata() {
194
+ * const { data, isLoading } = useMetadata(async (client) => {
195
+ * // Custom metadata fetching logic
196
+ * const object = await client.meta.getObject('custom_object');
197
+ * const view = await client.meta.getView('custom_object', 'list');
198
+ * return { object, view };
199
+ * });
200
+ *
201
+ * return <pre>{JSON.stringify(data, null, 2)}</pre>;
202
+ * }
203
+ * ```
204
+ */
205
+ function useMetadata(fetcher, options = {}) {
206
+ const client = (0, context_1.useClient)();
207
+ const [data, setData] = (0, react_1.useState)(null);
208
+ const [isLoading, setIsLoading] = (0, react_1.useState)(true);
209
+ const [error, setError] = (0, react_1.useState)(null);
210
+ const { enabled = true, onSuccess, onError } = options;
211
+ const fetchMetadata = (0, react_1.useCallback)(async () => {
212
+ if (!enabled)
213
+ return;
214
+ try {
215
+ setIsLoading(true);
216
+ setError(null);
217
+ const result = await fetcher(client);
218
+ setData(result);
219
+ onSuccess?.(result);
220
+ }
221
+ catch (err) {
222
+ const error = err instanceof Error ? err : new Error('Failed to fetch metadata');
223
+ setError(error);
224
+ onError?.(error);
225
+ }
226
+ finally {
227
+ setIsLoading(false);
228
+ }
229
+ }, [client, fetcher, enabled, onSuccess, onError]);
230
+ (0, react_1.useEffect)(() => {
231
+ fetchMetadata();
232
+ }, [fetchMetadata]);
233
+ const refetch = (0, react_1.useCallback)(async () => {
234
+ await fetchMetadata();
235
+ }, [fetchMetadata]);
236
+ return {
237
+ data,
238
+ isLoading,
239
+ error,
240
+ refetch,
241
+ fromCache: false
242
+ };
243
+ }
package/package.json ADDED
@@ -0,0 +1,22 @@
1
+ {
2
+ "name": "@objectstack/client-react",
3
+ "version": "0.6.1",
4
+ "description": "React hooks for ObjectStack Client SDK",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "peerDependencies": {
8
+ "react": ">=18.0.0"
9
+ },
10
+ "dependencies": {
11
+ "@objectstack/client": "0.6.1",
12
+ "@objectstack/spec": "0.6.1",
13
+ "@objectstack/core": "0.6.1"
14
+ },
15
+ "devDependencies": {
16
+ "@types/react": "^18.0.0",
17
+ "typescript": "^5.0.0"
18
+ },
19
+ "scripts": {
20
+ "build": "tsc"
21
+ }
22
+ }
@@ -0,0 +1,66 @@
1
+ /**
2
+ * ObjectStack React Context
3
+ *
4
+ * Provides ObjectStackClient instance to React components via Context API
5
+ */
6
+
7
+ import * as React from 'react';
8
+ import { createContext, useContext, ReactNode } from 'react';
9
+ import { ObjectStackClient } from '@objectstack/client';
10
+
11
+ export interface ObjectStackProviderProps {
12
+ client: ObjectStackClient;
13
+ children: ReactNode;
14
+ }
15
+
16
+ export const ObjectStackContext = createContext<ObjectStackClient | null>(null);
17
+
18
+ /**
19
+ * Provider component that makes ObjectStackClient available to all child components
20
+ *
21
+ * @example
22
+ * ```tsx
23
+ * const client = new ObjectStackClient({ baseUrl: 'http://localhost:3000' });
24
+ *
25
+ * function App() {
26
+ * return (
27
+ * <ObjectStackProvider client={client}>
28
+ * <YourComponents />
29
+ * </ObjectStackProvider>
30
+ * );
31
+ * }
32
+ * ```
33
+ */
34
+ export function ObjectStackProvider({ client, children }: ObjectStackProviderProps) {
35
+ return (
36
+ <ObjectStackContext.Provider value={client}>
37
+ {children}
38
+ </ObjectStackContext.Provider>
39
+ );
40
+ }
41
+
42
+ /**
43
+ * Hook to access the ObjectStackClient instance from context
44
+ *
45
+ * @throws Error if used outside of ObjectStackProvider
46
+ *
47
+ * @example
48
+ * ```tsx
49
+ * function MyComponent() {
50
+ * const client = useClient();
51
+ * // Use client.data.find(), etc.
52
+ * }
53
+ * ```
54
+ */
55
+ export function useClient(): ObjectStackClient {
56
+ const client = useContext(ObjectStackContext);
57
+
58
+ if (!client) {
59
+ throw new Error(
60
+ 'useClient must be used within an ObjectStackProvider. ' +
61
+ 'Make sure your component is wrapped with <ObjectStackProvider client={...}>.'
62
+ );
63
+ }
64
+
65
+ return client;
66
+ }