nexus-platform-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/README.md +329 -0
- package/dist/index.d.mts +760 -0
- package/dist/index.d.ts +760 -0
- package/dist/index.js +488 -0
- package/dist/index.mjs +460 -0
- package/package.json +56 -0
package/README.md
ADDED
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
# Nexus Platform SDK
|
|
2
|
+
|
|
3
|
+
The Nexus Platform SDK provides a JavaScript/TypeScript interface for building apps on the Nexus Platform. When Nexus generates your app via Code Studio, the generated code uses this SDK to authenticate users, manage your app's data, and execute serverless functions. You can use the same SDK to modify and extend your app.
|
|
4
|
+
|
|
5
|
+
## Modules
|
|
6
|
+
|
|
7
|
+
The SDK provides access to Nexus Platform's functionality through the following modules:
|
|
8
|
+
|
|
9
|
+
- **`auth`**: Manage user authentication, registration, and session handling.
|
|
10
|
+
- **`entities`**: Work with your app's data entities using CRUD operations.
|
|
11
|
+
- **`functions`**: Execute serverless backend functions.
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install nexus-platform-sdk
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Quick Start
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
import { createClient } from 'nexus-platform-sdk';
|
|
23
|
+
|
|
24
|
+
const nexus = createClient({
|
|
25
|
+
appId: 'your-app-id',
|
|
26
|
+
tenantId: 'your-tenant-id',
|
|
27
|
+
dataSourceId: 'your-datasource-id',
|
|
28
|
+
apiUrl: 'https://api.nexus.io',
|
|
29
|
+
});
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Example
|
|
33
|
+
|
|
34
|
+
Here's a quick look at working with data in the SDK, using the `entities` module to create, update, and list records. In this example, we're working with a custom `Task` entity:
|
|
35
|
+
|
|
36
|
+
```typescript
|
|
37
|
+
import { nexus } from '@/api/nexusClient';
|
|
38
|
+
|
|
39
|
+
// Create a new task
|
|
40
|
+
const newTask = await nexus.entities.Task.create({
|
|
41
|
+
title: 'Complete project documentation',
|
|
42
|
+
status: 'pending',
|
|
43
|
+
dueDate: '2025-12-31',
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
// Update the task
|
|
47
|
+
await nexus.entities.Task.update(newTask.id, {
|
|
48
|
+
status: 'in-progress',
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
// List all tasks sorted by creation date
|
|
52
|
+
const tasks = await nexus.entities.Task.list('-created_at', 10);
|
|
53
|
+
|
|
54
|
+
// Filter tasks by status
|
|
55
|
+
const pendingTasks = await nexus.entities.Task.filter({ status: 'pending' });
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Authentication
|
|
59
|
+
|
|
60
|
+
The SDK manages authentication state automatically, persisting tokens in localStorage.
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
// Sign up a new user (auto-logs in after registration)
|
|
64
|
+
const user = await nexus.auth.signUp({
|
|
65
|
+
email: 'user@example.com',
|
|
66
|
+
password: 'password123',
|
|
67
|
+
name: 'John Doe',
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
// Sign in existing user
|
|
71
|
+
await nexus.auth.signIn({
|
|
72
|
+
email: 'user@example.com',
|
|
73
|
+
password: 'password123',
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
// Check authentication state
|
|
77
|
+
if (nexus.auth.isAuthenticated) {
|
|
78
|
+
console.log('Logged in as:', nexus.auth.currentUser?.email);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Get fresh user data from server
|
|
82
|
+
const currentUser = await nexus.auth.me();
|
|
83
|
+
|
|
84
|
+
// Validate token with server
|
|
85
|
+
const isValid = await nexus.auth.checkAuth();
|
|
86
|
+
|
|
87
|
+
// Listen for auth state changes
|
|
88
|
+
const unsubscribe = nexus.auth.onAuthStateChange((user) => {
|
|
89
|
+
console.log(user ? 'Logged in' : 'Logged out');
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
// Sign out
|
|
93
|
+
nexus.auth.signOut();
|
|
94
|
+
|
|
95
|
+
// Or sign out with redirect
|
|
96
|
+
nexus.auth.logout('/goodbye');
|
|
97
|
+
|
|
98
|
+
// Redirect unauthenticated users to login
|
|
99
|
+
nexus.auth.redirectToLogin('/dashboard');
|
|
100
|
+
// Redirects to: /login?returnUrl=%2Fdashboard
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Entities
|
|
104
|
+
|
|
105
|
+
The `entities` module provides dynamic access to your database tables with full CRUD support.
|
|
106
|
+
|
|
107
|
+
### Listing and Filtering
|
|
108
|
+
|
|
109
|
+
```typescript
|
|
110
|
+
// Simple list
|
|
111
|
+
const tasks = await nexus.entities.Task.list();
|
|
112
|
+
|
|
113
|
+
// With positional parameters: sort, limit, skip, fields
|
|
114
|
+
const tasks = await nexus.entities.Task.list('-created_at', 10, 0);
|
|
115
|
+
|
|
116
|
+
// Or with options object
|
|
117
|
+
const tasks = await nexus.entities.Task.list({
|
|
118
|
+
sort: '-created_at', // prefix with '-' for descending
|
|
119
|
+
limit: 10,
|
|
120
|
+
skip: 0,
|
|
121
|
+
fields: ['id', 'title', 'status'],
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
// Filter by criteria
|
|
125
|
+
const doneTasks = await nexus.entities.Task.filter({ status: 'done' });
|
|
126
|
+
|
|
127
|
+
// Filter with sorting and pagination
|
|
128
|
+
const tasks = await nexus.entities.Task.filter(
|
|
129
|
+
{ status: 'pending' },
|
|
130
|
+
'-priority', // sort
|
|
131
|
+
10, // limit
|
|
132
|
+
0 // skip
|
|
133
|
+
);
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### CRUD Operations
|
|
137
|
+
|
|
138
|
+
```typescript
|
|
139
|
+
// Get single record by ID
|
|
140
|
+
const task = await nexus.entities.Task.get('task-id');
|
|
141
|
+
|
|
142
|
+
// Create new record
|
|
143
|
+
const newTask = await nexus.entities.Task.create({
|
|
144
|
+
title: 'New Task',
|
|
145
|
+
status: 'pending',
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
// Update existing record
|
|
149
|
+
const updated = await nexus.entities.Task.update(newTask.id, {
|
|
150
|
+
status: 'completed',
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
// Delete single record
|
|
154
|
+
await nexus.entities.Task.delete(newTask.id);
|
|
155
|
+
|
|
156
|
+
// Delete multiple records matching criteria
|
|
157
|
+
const result = await nexus.entities.Task.deleteMany({ status: 'archived' });
|
|
158
|
+
console.log(`Deleted ${result.deleted} records`);
|
|
159
|
+
|
|
160
|
+
// Bulk create multiple records
|
|
161
|
+
const tasks = await nexus.entities.Task.bulkCreate([
|
|
162
|
+
{ title: 'Task 1', status: 'pending' },
|
|
163
|
+
{ title: 'Task 2', status: 'pending' },
|
|
164
|
+
{ title: 'Task 3', status: 'pending' },
|
|
165
|
+
]);
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### TypeScript Support
|
|
169
|
+
|
|
170
|
+
Define interfaces for type-safe entity access:
|
|
171
|
+
|
|
172
|
+
```typescript
|
|
173
|
+
interface Task {
|
|
174
|
+
id: string;
|
|
175
|
+
title: string;
|
|
176
|
+
status: 'pending' | 'in_progress' | 'completed';
|
|
177
|
+
priority: number;
|
|
178
|
+
created_at: string;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// Get typed table accessor
|
|
182
|
+
const tasks = nexus.entities.getTable<Task>('Task');
|
|
183
|
+
|
|
184
|
+
// Now all operations are fully typed
|
|
185
|
+
const pending = await tasks.filter({ status: 'pending' });
|
|
186
|
+
pending.forEach((task) => {
|
|
187
|
+
console.log(task.title); // TypeScript knows this is a string
|
|
188
|
+
console.log(task.priority); // TypeScript knows this is a number
|
|
189
|
+
});
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
## Functions
|
|
193
|
+
|
|
194
|
+
The `functions` module allows you to execute serverless backend functions.
|
|
195
|
+
|
|
196
|
+
```typescript
|
|
197
|
+
// Invoke a function
|
|
198
|
+
const result = await nexus.functions.invoke('sendEmail', {
|
|
199
|
+
to: 'user@example.com',
|
|
200
|
+
subject: 'Hello from Nexus',
|
|
201
|
+
body: 'Welcome to the platform!',
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
// With full type safety
|
|
205
|
+
interface EmailInput {
|
|
206
|
+
to: string;
|
|
207
|
+
subject: string;
|
|
208
|
+
body: string;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
interface EmailOutput {
|
|
212
|
+
messageId: string;
|
|
213
|
+
status: 'sent' | 'queued';
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const result = await nexus.functions.invoke<EmailInput, EmailOutput>('sendEmail', {
|
|
217
|
+
to: 'user@example.com',
|
|
218
|
+
subject: 'Hello',
|
|
219
|
+
body: 'Welcome!',
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
console.log(result.messageId); // Fully typed
|
|
223
|
+
|
|
224
|
+
// List available functions
|
|
225
|
+
const functions = await nexus.functions.list();
|
|
226
|
+
functions.forEach((fn) => {
|
|
227
|
+
console.log(`${fn.name}: ${fn.description}`);
|
|
228
|
+
});
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
## Error Handling
|
|
232
|
+
|
|
233
|
+
The SDK throws `NexusApiError` for all API errors, providing structured error information:
|
|
234
|
+
|
|
235
|
+
```typescript
|
|
236
|
+
import { NexusApiError } from 'nexus-platform-sdk';
|
|
237
|
+
|
|
238
|
+
try {
|
|
239
|
+
await nexus.entities.Task.get('non-existent-id');
|
|
240
|
+
} catch (error) {
|
|
241
|
+
if (error instanceof NexusApiError) {
|
|
242
|
+
console.error('Status:', error.status); // HTTP status code
|
|
243
|
+
console.error('Message:', error.message); // Error message
|
|
244
|
+
console.error('Code:', error.code); // Application error code
|
|
245
|
+
console.error('Details:', error.details); // Additional error details
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
## React Integration
|
|
251
|
+
|
|
252
|
+
Here's a recommended pattern for integrating the SDK with React applications:
|
|
253
|
+
|
|
254
|
+
```typescript
|
|
255
|
+
// src/api/nexusClient.ts
|
|
256
|
+
import { createClient } from 'nexus-platform-sdk';
|
|
257
|
+
|
|
258
|
+
export const nexus = createClient({
|
|
259
|
+
appId: import.meta.env.VITE_NEXUS_APP_ID,
|
|
260
|
+
tenantId: import.meta.env.VITE_NEXUS_TENANT_ID,
|
|
261
|
+
dataSourceId: import.meta.env.VITE_NEXUS_DATASOURCE_ID,
|
|
262
|
+
apiUrl: import.meta.env.VITE_NEXUS_API_URL,
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
// src/hooks/useAuth.ts
|
|
266
|
+
import { useEffect, useState } from 'react';
|
|
267
|
+
import { nexus } from '../api/nexusClient';
|
|
268
|
+
import type { User } from 'nexus-platform-sdk';
|
|
269
|
+
|
|
270
|
+
export function useAuth() {
|
|
271
|
+
const [user, setUser] = useState<User | null>(nexus.auth.currentUser);
|
|
272
|
+
const [loading, setLoading] = useState(true);
|
|
273
|
+
|
|
274
|
+
useEffect(() => {
|
|
275
|
+
// Validate token on mount
|
|
276
|
+
nexus.auth.checkAuth().finally(() => setLoading(false));
|
|
277
|
+
|
|
278
|
+
// Subscribe to auth state changes
|
|
279
|
+
return nexus.auth.onAuthStateChange(setUser);
|
|
280
|
+
}, []);
|
|
281
|
+
|
|
282
|
+
return {
|
|
283
|
+
user,
|
|
284
|
+
loading,
|
|
285
|
+
isAuthenticated: !!user,
|
|
286
|
+
signIn: nexus.auth.signIn.bind(nexus.auth),
|
|
287
|
+
signUp: nexus.auth.signUp.bind(nexus.auth),
|
|
288
|
+
signOut: nexus.auth.signOut.bind(nexus.auth),
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// src/components/ProtectedRoute.tsx
|
|
293
|
+
import { Navigate, useLocation } from 'react-router-dom';
|
|
294
|
+
import { useAuth } from '../hooks/useAuth';
|
|
295
|
+
|
|
296
|
+
export function ProtectedRoute({ children }: { children: React.ReactNode }) {
|
|
297
|
+
const { isAuthenticated, loading } = useAuth();
|
|
298
|
+
const location = useLocation();
|
|
299
|
+
|
|
300
|
+
if (loading) {
|
|
301
|
+
return <div>Loading...</div>;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
if (!isAuthenticated) {
|
|
305
|
+
return <Navigate to={`/login?returnUrl=${location.pathname}`} replace />;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
return <>{children}</>;
|
|
309
|
+
}
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
## Development
|
|
313
|
+
|
|
314
|
+
### Build the SDK
|
|
315
|
+
|
|
316
|
+
```bash
|
|
317
|
+
npm install
|
|
318
|
+
npm run build
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
### Run tests
|
|
322
|
+
|
|
323
|
+
```bash
|
|
324
|
+
npm test
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
## License
|
|
328
|
+
|
|
329
|
+
MIT
|