@snackbase/sdk 0.1.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/CHANGELOG.md +61 -0
- package/LICENSE +21 -0
- package/README.md +287 -0
- package/dist/index-Dr6K4PMl.d.mts +2118 -0
- package/dist/index.d.mts +2 -0
- package/dist/index.mjs +2516 -0
- package/dist/react/index.d.mts +63 -0
- package/dist/react/index.mjs +271 -0
- package/package.json +48 -0
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { Ft as PasswordResetRequest, It as RegisterData, Ot as AuthState, Pt as PasswordResetConfirm, _t as BaseRecord, kt as LoginCredentials, s as SnackBaseClient, vt as RecordListParams, yt as RecordListResponse } from "../index-Dr6K4PMl.mjs";
|
|
2
|
+
import React from "react";
|
|
3
|
+
|
|
4
|
+
//#region src/react/SnackBaseContext.d.ts
|
|
5
|
+
interface SnackBaseProviderProps {
|
|
6
|
+
client: SnackBaseClient;
|
|
7
|
+
children: React.ReactNode;
|
|
8
|
+
}
|
|
9
|
+
declare const SnackBaseProvider: React.FC<SnackBaseProviderProps>;
|
|
10
|
+
declare const useSnackBase: () => SnackBaseClient;
|
|
11
|
+
//#endregion
|
|
12
|
+
//#region src/react/hooks/useAuth.d.ts
|
|
13
|
+
interface UseAuthResult extends AuthState {
|
|
14
|
+
login: (credentials: LoginCredentials) => Promise<any>;
|
|
15
|
+
logout: () => Promise<void>;
|
|
16
|
+
register: (data: RegisterData) => Promise<any>;
|
|
17
|
+
forgotPassword: (data: PasswordResetRequest) => Promise<any>;
|
|
18
|
+
resetPassword: (data: PasswordResetConfirm) => Promise<any>;
|
|
19
|
+
isLoading: boolean;
|
|
20
|
+
}
|
|
21
|
+
declare const useAuth: () => UseAuthResult;
|
|
22
|
+
//#endregion
|
|
23
|
+
//#region src/react/hooks/useQuery.d.ts
|
|
24
|
+
interface UseQueryResult<T> {
|
|
25
|
+
data: RecordListResponse<T> | null;
|
|
26
|
+
loading: boolean;
|
|
27
|
+
error: Error | null;
|
|
28
|
+
refetch: () => Promise<void>;
|
|
29
|
+
}
|
|
30
|
+
declare const useQuery: <T = any>(collection: string, params?: RecordListParams) => UseQueryResult<T>;
|
|
31
|
+
//#endregion
|
|
32
|
+
//#region src/react/hooks/useRecord.d.ts
|
|
33
|
+
interface UseRecordResult<T> {
|
|
34
|
+
data: (T & BaseRecord) | null;
|
|
35
|
+
loading: boolean;
|
|
36
|
+
error: Error | null;
|
|
37
|
+
refetch: () => Promise<void>;
|
|
38
|
+
}
|
|
39
|
+
interface UseRecordOptions {
|
|
40
|
+
fields?: string[] | string;
|
|
41
|
+
expand?: string[] | string;
|
|
42
|
+
}
|
|
43
|
+
declare const useRecord: <T = any>(collection: string, id: string, options?: UseRecordOptions) => UseRecordResult<T>;
|
|
44
|
+
//#endregion
|
|
45
|
+
//#region src/react/hooks/useMutation.d.ts
|
|
46
|
+
interface UseMutationResult<T> {
|
|
47
|
+
create: (data: Partial<T>) => Promise<T & BaseRecord>;
|
|
48
|
+
update: (id: string, data: Partial<T>) => Promise<T & BaseRecord>;
|
|
49
|
+
del: (id: string) => Promise<boolean>;
|
|
50
|
+
loading: boolean;
|
|
51
|
+
error: Error | null;
|
|
52
|
+
}
|
|
53
|
+
declare const useMutation: <T = any>(collection: string) => UseMutationResult<T>;
|
|
54
|
+
//#endregion
|
|
55
|
+
//#region src/react/hooks/useSubscription.d.ts
|
|
56
|
+
interface UseSubscriptionResult {
|
|
57
|
+
connected: boolean;
|
|
58
|
+
error: Error | null;
|
|
59
|
+
}
|
|
60
|
+
declare const useSubscription: <T = any>(collection: string, event: string, // e.g., 'create', 'update', 'delete', '*'
|
|
61
|
+
callback: (data: any) => void) => UseSubscriptionResult;
|
|
62
|
+
//#endregion
|
|
63
|
+
export { SnackBaseProvider, SnackBaseProviderProps, UseAuthResult, UseMutationResult, UseQueryResult, UseRecordOptions, UseRecordResult, UseSubscriptionResult, useAuth, useMutation, useQuery, useRecord, useSnackBase, useSubscription };
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
import React, { createContext, useCallback, useContext, useEffect, useRef, useState } from "react";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
|
|
4
|
+
//#region src/react/SnackBaseContext.tsx
|
|
5
|
+
const SnackBaseContext = createContext(null);
|
|
6
|
+
const SnackBaseProvider = ({ client, children }) => {
|
|
7
|
+
return /* @__PURE__ */ jsx(SnackBaseContext.Provider, {
|
|
8
|
+
value: client,
|
|
9
|
+
children
|
|
10
|
+
});
|
|
11
|
+
};
|
|
12
|
+
const useSnackBase = () => {
|
|
13
|
+
const context = useContext(SnackBaseContext);
|
|
14
|
+
if (!context) throw new Error("useSnackBase must be used within a SnackBaseProvider");
|
|
15
|
+
return context;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
//#endregion
|
|
19
|
+
//#region src/react/hooks/useAuth.ts
|
|
20
|
+
const useAuth = () => {
|
|
21
|
+
const client = useSnackBase();
|
|
22
|
+
const [state, setState] = useState({
|
|
23
|
+
user: client.user,
|
|
24
|
+
account: client.account,
|
|
25
|
+
token: client.auth.token,
|
|
26
|
+
refreshToken: client.auth.refreshToken,
|
|
27
|
+
isAuthenticated: client.isAuthenticated,
|
|
28
|
+
expiresAt: null
|
|
29
|
+
});
|
|
30
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
31
|
+
useEffect(() => {
|
|
32
|
+
setState({
|
|
33
|
+
user: client.user,
|
|
34
|
+
account: client.account,
|
|
35
|
+
token: client.auth.token,
|
|
36
|
+
refreshToken: client.auth.refreshToken,
|
|
37
|
+
isAuthenticated: client.isAuthenticated,
|
|
38
|
+
expiresAt: null
|
|
39
|
+
});
|
|
40
|
+
const updateState = (newState) => {
|
|
41
|
+
setState(newState);
|
|
42
|
+
};
|
|
43
|
+
const clearState = () => {
|
|
44
|
+
setState({
|
|
45
|
+
user: null,
|
|
46
|
+
account: null,
|
|
47
|
+
token: null,
|
|
48
|
+
refreshToken: null,
|
|
49
|
+
isAuthenticated: false,
|
|
50
|
+
expiresAt: null
|
|
51
|
+
});
|
|
52
|
+
};
|
|
53
|
+
const unsubscribeLogin = client.on("auth:login", updateState);
|
|
54
|
+
const unsubscribeRefresh = client.on("auth:refresh", updateState);
|
|
55
|
+
const unsubscribeLogout = client.on("auth:logout", clearState);
|
|
56
|
+
return () => {
|
|
57
|
+
unsubscribeLogin();
|
|
58
|
+
unsubscribeRefresh();
|
|
59
|
+
unsubscribeLogout();
|
|
60
|
+
};
|
|
61
|
+
}, [client]);
|
|
62
|
+
const login = useCallback(async (credentials) => {
|
|
63
|
+
setIsLoading(true);
|
|
64
|
+
try {
|
|
65
|
+
return await client.login(credentials);
|
|
66
|
+
} finally {
|
|
67
|
+
setIsLoading(false);
|
|
68
|
+
}
|
|
69
|
+
}, [client]);
|
|
70
|
+
const logout = useCallback(async () => {
|
|
71
|
+
setIsLoading(true);
|
|
72
|
+
try {
|
|
73
|
+
await client.logout();
|
|
74
|
+
} finally {
|
|
75
|
+
setIsLoading(false);
|
|
76
|
+
}
|
|
77
|
+
}, [client]);
|
|
78
|
+
const register = useCallback(async (data) => {
|
|
79
|
+
setIsLoading(true);
|
|
80
|
+
try {
|
|
81
|
+
return await client.register(data);
|
|
82
|
+
} finally {
|
|
83
|
+
setIsLoading(false);
|
|
84
|
+
}
|
|
85
|
+
}, [client]);
|
|
86
|
+
const forgotPassword = useCallback(async (data) => {
|
|
87
|
+
setIsLoading(true);
|
|
88
|
+
try {
|
|
89
|
+
return await client.forgotPassword(data);
|
|
90
|
+
} finally {
|
|
91
|
+
setIsLoading(false);
|
|
92
|
+
}
|
|
93
|
+
}, [client]);
|
|
94
|
+
const resetPassword = useCallback(async (data) => {
|
|
95
|
+
setIsLoading(true);
|
|
96
|
+
try {
|
|
97
|
+
return await client.resetPassword(data);
|
|
98
|
+
} finally {
|
|
99
|
+
setIsLoading(false);
|
|
100
|
+
}
|
|
101
|
+
}, [client]);
|
|
102
|
+
return {
|
|
103
|
+
...state,
|
|
104
|
+
login,
|
|
105
|
+
logout,
|
|
106
|
+
register,
|
|
107
|
+
forgotPassword,
|
|
108
|
+
resetPassword,
|
|
109
|
+
isLoading
|
|
110
|
+
};
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
//#endregion
|
|
114
|
+
//#region src/react/hooks/useQuery.ts
|
|
115
|
+
const useQuery = (collection, params) => {
|
|
116
|
+
const client = useSnackBase();
|
|
117
|
+
const [data, setData] = useState(null);
|
|
118
|
+
const [loading, setLoading] = useState(true);
|
|
119
|
+
const [error, setError] = useState(null);
|
|
120
|
+
const paramsKey = JSON.stringify(params);
|
|
121
|
+
const paramsRef = useRef(params);
|
|
122
|
+
if (JSON.stringify(paramsRef.current) !== paramsKey) paramsRef.current = params;
|
|
123
|
+
const fetchData = useCallback(async () => {
|
|
124
|
+
setLoading(true);
|
|
125
|
+
setError(null);
|
|
126
|
+
try {
|
|
127
|
+
setData(await client.records.list(collection, paramsRef.current));
|
|
128
|
+
} catch (err) {
|
|
129
|
+
setError(err);
|
|
130
|
+
} finally {
|
|
131
|
+
setLoading(false);
|
|
132
|
+
}
|
|
133
|
+
}, [
|
|
134
|
+
client,
|
|
135
|
+
collection,
|
|
136
|
+
paramsKey
|
|
137
|
+
]);
|
|
138
|
+
useEffect(() => {
|
|
139
|
+
fetchData();
|
|
140
|
+
}, [fetchData]);
|
|
141
|
+
return {
|
|
142
|
+
data,
|
|
143
|
+
loading,
|
|
144
|
+
error,
|
|
145
|
+
refetch: fetchData
|
|
146
|
+
};
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
//#endregion
|
|
150
|
+
//#region src/react/hooks/useRecord.ts
|
|
151
|
+
const useRecord = (collection, id, options) => {
|
|
152
|
+
const client = useSnackBase();
|
|
153
|
+
const [data, setData] = useState(null);
|
|
154
|
+
const [loading, setLoading] = useState(true);
|
|
155
|
+
const [error, setError] = useState(null);
|
|
156
|
+
const fetchData = useCallback(async () => {
|
|
157
|
+
if (!id) return;
|
|
158
|
+
setLoading(true);
|
|
159
|
+
setError(null);
|
|
160
|
+
try {
|
|
161
|
+
setData(await client.records.get(collection, id, options));
|
|
162
|
+
} catch (err) {
|
|
163
|
+
setError(err);
|
|
164
|
+
} finally {
|
|
165
|
+
setLoading(false);
|
|
166
|
+
}
|
|
167
|
+
}, [
|
|
168
|
+
client,
|
|
169
|
+
collection,
|
|
170
|
+
id,
|
|
171
|
+
JSON.stringify(options)
|
|
172
|
+
]);
|
|
173
|
+
useEffect(() => {
|
|
174
|
+
fetchData();
|
|
175
|
+
}, [fetchData]);
|
|
176
|
+
return {
|
|
177
|
+
data,
|
|
178
|
+
loading,
|
|
179
|
+
error,
|
|
180
|
+
refetch: fetchData
|
|
181
|
+
};
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
//#endregion
|
|
185
|
+
//#region src/react/hooks/useMutation.ts
|
|
186
|
+
const useMutation = (collection) => {
|
|
187
|
+
const client = useSnackBase();
|
|
188
|
+
const [loading, setLoading] = useState(false);
|
|
189
|
+
const [error, setError] = useState(null);
|
|
190
|
+
return {
|
|
191
|
+
create: useCallback(async (data) => {
|
|
192
|
+
setLoading(true);
|
|
193
|
+
setError(null);
|
|
194
|
+
try {
|
|
195
|
+
return await client.records.create(collection, data);
|
|
196
|
+
} catch (err) {
|
|
197
|
+
setError(err);
|
|
198
|
+
throw err;
|
|
199
|
+
} finally {
|
|
200
|
+
setLoading(false);
|
|
201
|
+
}
|
|
202
|
+
}, [client, collection]),
|
|
203
|
+
update: useCallback(async (id, data) => {
|
|
204
|
+
setLoading(true);
|
|
205
|
+
setError(null);
|
|
206
|
+
try {
|
|
207
|
+
return await client.records.update(collection, id, data);
|
|
208
|
+
} catch (err) {
|
|
209
|
+
setError(err);
|
|
210
|
+
throw err;
|
|
211
|
+
} finally {
|
|
212
|
+
setLoading(false);
|
|
213
|
+
}
|
|
214
|
+
}, [client, collection]),
|
|
215
|
+
del: useCallback(async (id) => {
|
|
216
|
+
setLoading(true);
|
|
217
|
+
setError(null);
|
|
218
|
+
try {
|
|
219
|
+
await client.records.delete(collection, id);
|
|
220
|
+
return true;
|
|
221
|
+
} catch (err) {
|
|
222
|
+
setError(err);
|
|
223
|
+
throw err;
|
|
224
|
+
} finally {
|
|
225
|
+
setLoading(false);
|
|
226
|
+
}
|
|
227
|
+
}, [client, collection]),
|
|
228
|
+
loading,
|
|
229
|
+
error
|
|
230
|
+
};
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
//#endregion
|
|
234
|
+
//#region src/react/hooks/useSubscription.ts
|
|
235
|
+
const useSubscription = (collection, event, callback) => {
|
|
236
|
+
const client = useSnackBase();
|
|
237
|
+
const [connected, setConnected] = useState(false);
|
|
238
|
+
const [error, setError] = useState(null);
|
|
239
|
+
useEffect(() => {
|
|
240
|
+
let unsubscribe;
|
|
241
|
+
const setupSubscription = async () => {
|
|
242
|
+
try {
|
|
243
|
+
await client.realtime.subscribe(collection, event === "*" ? void 0 : [event]);
|
|
244
|
+
setConnected(true);
|
|
245
|
+
const eventType = event === "*" ? `${collection}.*` : `${collection}.${event}`;
|
|
246
|
+
unsubscribe = client.realtime.on(eventType, (e) => {
|
|
247
|
+
callback(e.data);
|
|
248
|
+
});
|
|
249
|
+
} catch (err) {
|
|
250
|
+
setError(err);
|
|
251
|
+
setConnected(false);
|
|
252
|
+
}
|
|
253
|
+
};
|
|
254
|
+
setupSubscription();
|
|
255
|
+
return () => {
|
|
256
|
+
if (unsubscribe) unsubscribe();
|
|
257
|
+
client.realtime.unsubscribe(collection).catch(console.error);
|
|
258
|
+
};
|
|
259
|
+
}, [
|
|
260
|
+
client,
|
|
261
|
+
collection,
|
|
262
|
+
event
|
|
263
|
+
]);
|
|
264
|
+
return {
|
|
265
|
+
connected,
|
|
266
|
+
error
|
|
267
|
+
};
|
|
268
|
+
};
|
|
269
|
+
|
|
270
|
+
//#endregion
|
|
271
|
+
export { SnackBaseProvider, useAuth, useMutation, useQuery, useRecord, useSnackBase, useSubscription };
|
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@snackbase/sdk",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "JavaScript/TypeScript SDK for SnackBase",
|
|
5
|
+
"exports": {
|
|
6
|
+
".": {
|
|
7
|
+
"import": "./dist/index.mjs",
|
|
8
|
+
"require": "./dist/index.js",
|
|
9
|
+
"types": "./dist/index.d.ts"
|
|
10
|
+
},
|
|
11
|
+
"./react": {
|
|
12
|
+
"import": "./dist/react/index.mjs",
|
|
13
|
+
"require": "./dist/react/index.js",
|
|
14
|
+
"types": "./dist/react/index.d.ts"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"scripts": {
|
|
18
|
+
"dev": "tsdown src/index.ts src/react/index.ts --watch",
|
|
19
|
+
"build": "tsdown src/index.ts src/react/index.ts",
|
|
20
|
+
"test": "vitest run",
|
|
21
|
+
"test:watch": "vitest",
|
|
22
|
+
"test:integration": "vitest run --config vitest.integration.config.ts",
|
|
23
|
+
"test:coverage": "vitest run --coverage",
|
|
24
|
+
"typecheck": "tsc --noEmit",
|
|
25
|
+
"lint": "eslint src --ext .ts,.tsx",
|
|
26
|
+
"prepublishOnly": "npm run build && npm run test"
|
|
27
|
+
},
|
|
28
|
+
"peerDependencies": {
|
|
29
|
+
"react": "^18.0.0"
|
|
30
|
+
},
|
|
31
|
+
"peerDependenciesMeta": {
|
|
32
|
+
"react": {
|
|
33
|
+
"optional": true
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@testing-library/jest-dom": "^6.9.1",
|
|
38
|
+
"@testing-library/react": "^16.3.2",
|
|
39
|
+
"@vitejs/plugin-react": "^5.1.2",
|
|
40
|
+
"jsdom": "^27.4.0",
|
|
41
|
+
"react": "^18.2.0",
|
|
42
|
+
"react-dom": "^18.2.0",
|
|
43
|
+
"tsdown": "^0.20.0-beta.4",
|
|
44
|
+
"typescript": "^5.3.3",
|
|
45
|
+
"vite": "^7.3.1",
|
|
46
|
+
"vitest": "^1.2.1"
|
|
47
|
+
}
|
|
48
|
+
}
|