@snackbase/sdk 0.1.1 → 0.3.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 DELETED
@@ -1,61 +0,0 @@
1
- # Changelog
2
-
3
- All notable changes to this project will be documented in this file.
4
-
5
- The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
- and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
-
8
- ## [Unreleased]
9
-
10
- ### Added
11
- - Initial release of SnackBase SDK for JavaScript/TypeScript
12
-
13
- ### Features
14
- - **Core Client**: `SnackBaseClient` with configuration validation
15
- - **HTTP Client**: Fetch-based HTTP client with interceptors
16
- - **Authentication**: Email/password, OAuth, SAML, and API key authentication
17
- - **Services**: 17+ service classes for all SnackBase resources
18
- - Accounts, Users, Collections, Records
19
- - Roles, Collection Rules (Permission System V2)
20
- - Groups, Invitations, Macros
21
- - API Keys, Audit Logs, Dashboard, Admin
22
- - Email Templates, Files
23
- - **Real-Time**: WebSocket/SSE support with automatic reconnection
24
- - **Query Builder**: Fluent API for complex queries
25
- - **React Integration**: Context provider and hooks
26
- - `useAuth`, `useQuery`, `useRecord`, `useMutation`, `useSubscription`
27
- - **Type Safety**: Complete TypeScript definitions
28
- - **Error Handling**: Typed error hierarchy
29
- - **Storage Abstraction**: Platform-agnostic storage backends
30
- - **Logging**: Structured logging system with configurable levels
31
-
32
- ### Package Exports
33
- - `@snackbase/sdk` - Core SDK
34
- - `@snackbase/sdk/react` - React integration
35
-
36
- ### Build Output
37
- - ESM (`.mjs`) - 14.87 KB gzipped
38
- - CommonJS (`.js`)
39
- - TypeScript declarations (`.d.ts`)
40
-
41
- ## [0.1.0] - 2025-01-XX
42
-
43
- ### Added
44
- - Initial beta release
45
- - Complete Phase 1-4 implementation
46
- - Core SDK features
47
- - React hooks
48
- - Real-time subscriptions
49
- - Query builder
50
- - 231 tests passing
51
-
52
- ## [Future Releases]
53
-
54
- ### Planned
55
- - Integration tests with test server
56
- - Performance benchmarks
57
- - Request deduplication
58
- - Advanced caching strategies
59
- - Vue 3 integration
60
- - Angular integration
61
- - Svelte integration
package/README.md DELETED
@@ -1,287 +0,0 @@
1
- # SnackBase SDK
2
-
3
- [![npm version](https://badge.fury.io/js/%40snackbase%2Fsdk.svg)](https://www.npmjs.com/package/@snackbase/sdk)
4
- [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
- [![Build Status](https://github.com/snackbase/snackbase-js/workflows/CI/badge.svg)](https://github.com/snackbase/snackbase-js/actions)
6
-
7
- The official JavaScript/TypeScript SDK for [SnackBase](https://snackbase.dev) - a powerful backend-as-a-service platform.
8
-
9
- ## Features
10
-
11
- - **Type-Safe**: Built with TypeScript for full type safety and excellent developer experience
12
- - **Authentication**: Support for JWT tokens, OAuth, SAML, and API keys
13
- - **Real-Time**: WebSocket and SSE support for real-time data synchronization
14
- - **React Integration**: Dedicated React hooks and context for seamless integration
15
- - **Query Builder**: Fluent API for building complex queries with filtering, sorting, and pagination
16
- - **Platform Agnostic**: Works in browsers, React Native, and Node.js
17
- - **Lightweight**: Only 14.87 KB gzipped for the core SDK
18
-
19
- ## Installation
20
-
21
- ```bash
22
- # npm
23
- npm install @snackbase/sdk
24
-
25
- # yarn
26
- yarn add @snackbase/sdk
27
-
28
- # pnpm
29
- pnpm add @snackbase/sdk
30
- ```
31
-
32
- ### React Integration
33
-
34
- ```bash
35
- # npm
36
- npm install @snackbase/sdk react
37
-
38
- # yarn
39
- yarn add @snackbase/sdk react
40
-
41
- # pnpm
42
- pnpm add @snackbase/sdk react
43
- ```
44
-
45
- ## Quick Start
46
-
47
- ### Basic Usage
48
-
49
- ```typescript
50
- import { SnackBaseClient } from "@snackbase/sdk";
51
-
52
- // Initialize the client
53
- const client = new SnackBaseClient({
54
- baseUrl: "https://your-project.snackbase.dev",
55
- apiKey: "your-api-key", // Optional for public access
56
- });
57
-
58
- // Authenticate with email/password
59
- const auth = await client.auth.authenticateWithPassword({
60
- email: "user@example.com",
61
- password: "password123",
62
- });
63
-
64
- console.log("Logged in as:", auth.user.email);
65
-
66
- // List records from a collection
67
- const records = await client.records.list("posts", {
68
- filter: { status: "published" },
69
- sort: "-createdAt",
70
- });
71
-
72
- // Subscribe to real-time updates
73
- client.realtime.subscribe("posts", (event) => {
74
- console.log("New event:", event.action, event.record);
75
- });
76
- ```
77
-
78
- ### React Integration
79
-
80
- ```tsx
81
- import { SnackBaseProvider, useAuth, useRecord } from "@snackbase/sdk/react";
82
-
83
- function App() {
84
- return (
85
- <SnackBaseProvider
86
- baseUrl="https://your-project.snackbase.dev"
87
- apiKey="your-api-key"
88
- >
89
- <Posts />
90
- </SnackBaseProvider>
91
- );
92
- }
93
-
94
- function Posts() {
95
- const { user, login, logout } = useAuth();
96
- const { data: posts, loading } = useRecord("posts", {
97
- filter: { status: "published" },
98
- });
99
-
100
- if (!user) {
101
- return <button onClick={() => login(email, password)}>Login</button>;
102
- }
103
-
104
- return (
105
- <div>
106
- <button onClick={logout}>Logout</button>
107
- {loading ? <p>Loading...</p> : <PostList posts={posts?.items} />}
108
- </div>
109
- );
110
- }
111
- ```
112
-
113
- ## Documentation
114
-
115
- - [Getting Started Guide](./docs/getting-started.md)
116
- - [Authentication Guide](./docs/authentication.md)
117
- - [Real-Time Features](./docs/realtime.md)
118
- - [React Integration](./docs/react-integration.md)
119
- - [API Reference](./docs/api-reference.md)
120
- - [Migration Guides](./docs/migration/)
121
-
122
- ## Platform Support
123
-
124
- | Platform | Support |
125
- | --------------------------------------- | ------- |
126
- | Browser (Chrome, Firefox, Safari, Edge) | ✅ Full |
127
- | React Native | ✅ Full |
128
- | Node.js | ✅ Full |
129
- | Next.js | ✅ Full |
130
- | Vue/Nuxt | ✅ Full |
131
-
132
- ## Authentication Methods
133
-
134
- | Method | Description |
135
- | ------------------ | -------------------------------------------------- |
136
- | **Email/Password** | Traditional authentication with email and password |
137
- | **OAuth** | Sign in with Google, GitHub, etc. |
138
- | **SAML** | Enterprise SSO support |
139
- | **API Key** | Server-to-server authentication |
140
-
141
- ## Core Services
142
-
143
- The SDK provides 17+ services for interacting with SnackBase:
144
-
145
- - `client.auth` - Authentication and user management
146
- - `client.users` - User CRUD operations
147
- - `client.accounts` - Account management
148
- - `client.collections` - Collection/schema management
149
- - `client.records` - Dynamic record operations (CRUD, queries)
150
- - `client.roles` - Role-based access control
151
- - `client.groups` - Group management
152
- - `client.invitations` - User invitations
153
- - `client.macros` - Macro operations
154
- - `client.apiKeys` - API key management
155
- - `client.auditLogs` - Audit log access
156
- - `client.dashboard` - Dashboard metrics
157
- - `client.admin` - Admin operations
158
- - `client.emailTemplates` - Email template management
159
- - `client.files` - File upload/download
160
- - `client.realtime` - Real-time subscriptions
161
- - `client.query` - Query builder
162
-
163
- ## Query Builder
164
-
165
- Build complex queries with a fluent API:
166
-
167
- ```typescript
168
- const results = await client
169
- .query("posts")
170
- .select("id", "title", "author.name")
171
- .expand("author", "comments")
172
- .filter("status", "=", "published")
173
- .filter("createdAt", ">", "2024-01-01")
174
- .sort("createdAt", "desc")
175
- .page(1)
176
- .perPage(20)
177
- .execute();
178
- ```
179
-
180
- ## Real-Time Subscriptions
181
-
182
- Subscribe to record changes in real-time:
183
-
184
- ```typescript
185
- // Subscribe to a collection
186
- const unsubscribe = client.realtime.subscribe("posts", (event) => {
187
- switch (event.action) {
188
- case "create":
189
- console.log("New post created:", event.record);
190
- break;
191
- case "update":
192
- console.log("Post updated:", event.record);
193
- break;
194
- case "delete":
195
- console.log("Post deleted:", event.record);
196
- break;
197
- }
198
- });
199
-
200
- // Unsubscribe when done
201
- unsubscribe();
202
- ```
203
-
204
- ## Error Handling
205
-
206
- The SDK provides typed errors for comprehensive error handling:
207
-
208
- ```typescript
209
- import {
210
- SnackBaseError,
211
- AuthenticationError,
212
- ValidationError,
213
- NetworkError,
214
- } from "@snackbase/sdk";
215
-
216
- try {
217
- await client.records.create("posts", data);
218
- } catch (error) {
219
- if (error instanceof ValidationError) {
220
- console.error("Validation failed:", error.fields);
221
- } else if (error instanceof AuthenticationError) {
222
- console.error("Authentication failed:", error.message);
223
- } else if (error instanceof NetworkError) {
224
- console.error("Network error:", error.message);
225
- }
226
- }
227
- ```
228
-
229
- ## TypeScript Support
230
-
231
- The SDK is written in TypeScript and provides full type definitions:
232
-
233
- ```typescript
234
- import type { User, Post, Comment } from "@snackbase/sdk";
235
-
236
- // Type-safe record operations
237
- const post: Post = await client.records.get<Post>("posts", "record-id");
238
-
239
- // Type-safe auth state
240
- const user: User = await client.auth.getCurrentUser();
241
- ```
242
-
243
- ## Development
244
-
245
- ```bash
246
- # Clone the repository
247
- git clone https://github.com/snackbase/snackbase-js.git
248
- cd snackbase-js
249
-
250
- # Install dependencies
251
- npm install
252
-
253
- # Build
254
- npm run build
255
-
256
- # Run tests
257
- npm test
258
-
259
- # Watch mode
260
- npm run dev
261
- ```
262
-
263
- ## Bundle Size
264
-
265
- - Core SDK: **14.87 KB** (gzipped)
266
- - React Integration: **1.42 KB** (gzipped)
267
- - Total: **16.29 KB** (gzipped)
268
-
269
- ## License
270
-
271
- MIT © [SnackBase](https://snackbase.dev)
272
-
273
- ## Contributing
274
-
275
- We welcome contributions! Please see our [Contributing Guide](./CONTRIBUTING.md) for details.
276
-
277
- ## Support
278
-
279
- - Documentation: [https://docs.snackbase.dev](https://docs.snackbase.dev)
280
- - GitHub Issues: [https://github.com/snackbase/snackbase-js/issues](https://github.com/snackbase/snackbase-js/issues)
281
- - Discord: [https://discord.gg/snackbase](https://discord.gg/snackbase)
282
-
283
- ## Related Projects
284
-
285
- - [SnackBase](https://snackbase.dev) - The official SnackBase platform
286
- - [snackbase-python](https://github.com/snackbase/snackbase-python) - Python SDK
287
- - [snackbase-go](https://github.com/snackbase/snackbase-go) - Go SDK
@@ -1,63 +0,0 @@
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 };
@@ -1,271 +0,0 @@
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 };