@seaverse/data-service-sdk 0.1.0 → 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/README.md +345 -114
- package/dist/index.cjs +140 -25
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +255 -40
- package/dist/index.js +140 -25
- package/dist/index.js.map +1 -1
- package/package.json +10 -11
package/README.md
CHANGED
|
@@ -1,14 +1,39 @@
|
|
|
1
1
|
# @seaverse/data-service-sdk
|
|
2
2
|
|
|
3
|
-
SeaVerse Data Service SDK for
|
|
3
|
+
SeaVerse Data Service SDK for accessing Firestore with secure token management and three-tier permission model.
|
|
4
4
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
7
|
+
- 🔐 Secure Firestore token generation for authenticated users and guests
|
|
8
|
+
- 🎯 Three-tier permission model (publicRead, publicData, userData)
|
|
9
|
+
- 🚀 Direct Firestore access - no proxy server needed
|
|
10
|
+
- 🔒 Automatic data isolation by app_id
|
|
11
|
+
- 📝 TypeScript support with full type definitions
|
|
12
|
+
- 🤖 LLM-friendly documentation with clear examples
|
|
13
|
+
|
|
14
|
+
## Three-Tier Permission Model
|
|
15
|
+
|
|
16
|
+
SeaVerse organizes your Firestore data into three permission levels:
|
|
17
|
+
|
|
18
|
+
| Permission Level | Path Pattern | Read Access | Write Access | Use Case |
|
|
19
|
+
|-----------------|--------------|-------------|--------------|----------|
|
|
20
|
+
| **publicRead** | `appData/{app_id}/publicRead/...` | All authenticated users | Admin only | System configs, announcements, static content |
|
|
21
|
+
| **publicData** | `appData/{app_id}/publicData/...` | All authenticated users | All authenticated users | User posts, comments, shared content |
|
|
22
|
+
| **userData** | `appData/{app_id}/userData/{user_id}/...` | Owner only | Owner only | User settings, private notes, personal data |
|
|
23
|
+
|
|
24
|
+
### Required Fields
|
|
25
|
+
|
|
26
|
+
All Firestore documents MUST include these three fields:
|
|
27
|
+
|
|
28
|
+
```typescript
|
|
29
|
+
{
|
|
30
|
+
_appId: string, // Your application ID (for data isolation)
|
|
31
|
+
_createdAt: timestamp, // Server timestamp (use serverTimestamp())
|
|
32
|
+
_createdBy: string // User ID who created the document
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
These fields are enforced by Firestore Security Rules and ensure proper data isolation.
|
|
12
37
|
|
|
13
38
|
## Installation
|
|
14
39
|
|
|
@@ -18,29 +43,101 @@ npm install @seaverse/data-service-sdk
|
|
|
18
43
|
|
|
19
44
|
## Quick Start
|
|
20
45
|
|
|
46
|
+
### For Authenticated Users
|
|
47
|
+
|
|
21
48
|
```typescript
|
|
22
49
|
import { DataServiceClient } from '@seaverse/data-service-sdk';
|
|
50
|
+
import { AuthClient } from '@seaverse/auth-sdk';
|
|
51
|
+
import { initializeApp } from 'firebase/app';
|
|
52
|
+
import { getAuth, signInWithCustomToken } from 'firebase/auth';
|
|
53
|
+
import { getFirestore, collection, addDoc, getDocs, serverTimestamp } from 'firebase/firestore';
|
|
54
|
+
|
|
55
|
+
// Step 1: Login user with Auth SDK
|
|
56
|
+
const authClient = new AuthClient({ appId: 'my-app-123' });
|
|
57
|
+
const loginResponse = await authClient.loginWithEmail({
|
|
58
|
+
email: 'user@example.com',
|
|
59
|
+
password: 'password123'
|
|
60
|
+
});
|
|
23
61
|
|
|
24
|
-
//
|
|
25
|
-
const
|
|
62
|
+
// Step 2: Get Firestore token
|
|
63
|
+
const dataClient = new DataServiceClient();
|
|
64
|
+
const firestoreToken = await dataClient.generateFirestoreToken({
|
|
65
|
+
token: loginResponse.token, // JWT from auth
|
|
66
|
+
app_id: 'my-app-123'
|
|
67
|
+
});
|
|
26
68
|
|
|
27
|
-
//
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
69
|
+
// Step 3: Initialize Firebase
|
|
70
|
+
const app = initializeApp({ projectId: firestoreToken.project_id });
|
|
71
|
+
const auth = getAuth(app);
|
|
72
|
+
await signInWithCustomToken(auth, firestoreToken.custom_token);
|
|
73
|
+
const db = getFirestore(app);
|
|
74
|
+
|
|
75
|
+
// Step 4: Use Firestore with proper paths
|
|
76
|
+
const appId = firestoreToken.app_id;
|
|
77
|
+
const userId = firestoreToken.user_id;
|
|
78
|
+
|
|
79
|
+
// Write to publicData (everyone can write)
|
|
80
|
+
await addDoc(collection(db, `appData/${appId}/publicData/posts`), {
|
|
81
|
+
_appId: appId, // REQUIRED
|
|
82
|
+
_createdAt: serverTimestamp(), // REQUIRED
|
|
83
|
+
_createdBy: userId, // REQUIRED
|
|
84
|
+
title: 'My First Post',
|
|
85
|
+
content: 'Hello world!'
|
|
31
86
|
});
|
|
32
87
|
|
|
33
|
-
//
|
|
34
|
-
const
|
|
35
|
-
|
|
88
|
+
// Read from publicData
|
|
89
|
+
const snapshot = await getDocs(collection(db, `appData/${appId}/publicData/posts`));
|
|
90
|
+
snapshot.forEach(doc => {
|
|
91
|
+
console.log(doc.id, doc.data());
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
// Write to userData (private)
|
|
95
|
+
await addDoc(collection(db, `appData/${appId}/userData/${userId}/notes`), {
|
|
96
|
+
_appId: appId, // REQUIRED
|
|
97
|
+
_createdAt: serverTimestamp(), // REQUIRED
|
|
98
|
+
_createdBy: userId, // REQUIRED
|
|
99
|
+
title: 'Private Note',
|
|
100
|
+
content: 'Only I can see this'
|
|
101
|
+
});
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### For Guest Users
|
|
105
|
+
|
|
106
|
+
```typescript
|
|
107
|
+
import { DataServiceClient } from '@seaverse/data-service-sdk';
|
|
108
|
+
import { initializeApp } from 'firebase/app';
|
|
109
|
+
import { getAuth, signInWithCustomToken } from 'firebase/auth';
|
|
110
|
+
import { getFirestore, collection, addDoc, serverTimestamp } from 'firebase/firestore';
|
|
111
|
+
|
|
112
|
+
// Step 1: Get guest token (no authentication needed!)
|
|
113
|
+
const dataClient = new DataServiceClient();
|
|
114
|
+
const guestToken = await dataClient.generateGuestFirestoreToken({
|
|
115
|
+
app_id: 'my-app-123'
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
// Step 2: Initialize Firebase
|
|
119
|
+
const app = initializeApp({ projectId: guestToken.project_id });
|
|
120
|
+
const auth = getAuth(app);
|
|
121
|
+
await signInWithCustomToken(auth, guestToken.custom_token);
|
|
122
|
+
const db = getFirestore(app);
|
|
123
|
+
|
|
124
|
+
// Step 3: Guest can write to publicData
|
|
125
|
+
await addDoc(collection(db, `appData/${guestToken.app_id}/publicData/comments`), {
|
|
126
|
+
_appId: guestToken.app_id,
|
|
127
|
+
_createdAt: serverTimestamp(),
|
|
128
|
+
_createdBy: guestToken.user_id, // Guest user ID (e.g., 'guest-abc123')
|
|
129
|
+
comment: 'Great app!',
|
|
130
|
+
rating: 5
|
|
36
131
|
});
|
|
132
|
+
|
|
133
|
+
// Note: Guests CANNOT access userData
|
|
37
134
|
```
|
|
38
135
|
|
|
39
136
|
## API Reference
|
|
40
137
|
|
|
41
138
|
### DataServiceClient
|
|
42
139
|
|
|
43
|
-
The main client for
|
|
140
|
+
The main client for generating Firestore tokens.
|
|
44
141
|
|
|
45
142
|
#### Constructor
|
|
46
143
|
|
|
@@ -61,8 +158,8 @@ const client = new DataServiceClient({
|
|
|
61
158
|
baseURL: 'https://auth.seaverse.ai',
|
|
62
159
|
timeout: 15000,
|
|
63
160
|
headers: {
|
|
64
|
-
'X-Custom-Header': 'value'
|
|
65
|
-
}
|
|
161
|
+
'X-Custom-Header': 'value'
|
|
162
|
+
}
|
|
66
163
|
});
|
|
67
164
|
```
|
|
68
165
|
|
|
@@ -83,7 +180,7 @@ generateFirestoreToken(
|
|
|
83
180
|
|
|
84
181
|
```typescript
|
|
85
182
|
interface GenerateFirestoreTokenRequest {
|
|
86
|
-
token: string; // User's JWT token
|
|
183
|
+
token: string; // User's JWT token from Auth SDK
|
|
87
184
|
app_id: string; // Application ID
|
|
88
185
|
}
|
|
89
186
|
```
|
|
@@ -92,32 +189,27 @@ interface GenerateFirestoreTokenRequest {
|
|
|
92
189
|
|
|
93
190
|
```typescript
|
|
94
191
|
interface FirestoreTokenResponse {
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
project_id: string; // Firebase Project ID
|
|
192
|
+
custom_token: string; // Firebase Custom Token - use with signInWithCustomToken()
|
|
193
|
+
project_id: string; // Firebase Project ID for initializeApp()
|
|
98
194
|
database_id: string; // Firestore Database ID
|
|
99
|
-
app_id?: string; // Application ID
|
|
100
|
-
user_id: string; // User ID
|
|
101
|
-
role?: string; // User role
|
|
102
|
-
expires_in: number; //
|
|
195
|
+
app_id?: string; // Application ID (use in Firestore paths)
|
|
196
|
+
user_id: string; // User ID (use in Firestore paths)
|
|
197
|
+
role?: string; // User role ('guest', 'user', 'admin')
|
|
198
|
+
expires_in: number; // Token expiration in seconds (typically 3600)
|
|
103
199
|
}
|
|
104
200
|
```
|
|
105
201
|
|
|
106
202
|
**Example:**
|
|
107
203
|
|
|
108
204
|
```typescript
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
});
|
|
205
|
+
const firestoreToken = await client.generateFirestoreToken({
|
|
206
|
+
token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...',
|
|
207
|
+
app_id: 'my-app-123'
|
|
208
|
+
});
|
|
114
209
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
} catch (error) {
|
|
119
|
-
console.error('Failed to generate Firestore token:', error);
|
|
120
|
-
}
|
|
210
|
+
console.log('Custom Token:', firestoreToken.custom_token);
|
|
211
|
+
console.log('User ID:', firestoreToken.user_id);
|
|
212
|
+
console.log('App ID:', firestoreToken.app_id);
|
|
121
213
|
```
|
|
122
214
|
|
|
123
215
|
#### generateGuestFirestoreToken
|
|
@@ -141,126 +233,141 @@ interface GenerateGuestFirestoreTokenRequest {
|
|
|
141
233
|
|
|
142
234
|
**Response:**
|
|
143
235
|
|
|
144
|
-
Same as `FirestoreTokenResponse` above, with `role`
|
|
236
|
+
Same as `FirestoreTokenResponse` above, with `role` set to `'guest'`.
|
|
145
237
|
|
|
146
238
|
**Example:**
|
|
147
239
|
|
|
148
240
|
```typescript
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
});
|
|
241
|
+
const guestToken = await client.generateGuestFirestoreToken({
|
|
242
|
+
app_id: 'my-app-123'
|
|
243
|
+
});
|
|
153
244
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
} catch (error) {
|
|
158
|
-
console.error('Failed to generate guest Firestore token:', error);
|
|
159
|
-
}
|
|
245
|
+
console.log('Guest Custom Token:', guestToken.custom_token);
|
|
246
|
+
console.log('Guest User ID:', guestToken.user_id);
|
|
247
|
+
console.log('Role:', guestToken.role); // 'guest'
|
|
160
248
|
```
|
|
161
249
|
|
|
162
|
-
##
|
|
250
|
+
## Common Use Cases
|
|
163
251
|
|
|
164
|
-
###
|
|
252
|
+
### Use Case 1: Public Forum with Comments
|
|
165
253
|
|
|
166
254
|
```typescript
|
|
167
|
-
|
|
255
|
+
// Anyone (including guests) can post comments
|
|
256
|
+
await addDoc(collection(db, `appData/${appId}/publicData/comments`), {
|
|
257
|
+
_appId: appId,
|
|
258
|
+
_createdAt: serverTimestamp(),
|
|
259
|
+
_createdBy: userId,
|
|
260
|
+
postId: 'post-123',
|
|
261
|
+
comment: 'Great post!',
|
|
262
|
+
likes: 0
|
|
263
|
+
});
|
|
168
264
|
|
|
169
|
-
|
|
265
|
+
// Anyone can read comments
|
|
266
|
+
const comments = await getDocs(
|
|
267
|
+
collection(db, `appData/${appId}/publicData/comments`)
|
|
268
|
+
);
|
|
269
|
+
```
|
|
170
270
|
|
|
171
|
-
|
|
172
|
-
const userToken = localStorage.getItem('authToken');
|
|
271
|
+
### Use Case 2: User Private Settings
|
|
173
272
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
273
|
+
```typescript
|
|
274
|
+
// Only the user can write to their own settings
|
|
275
|
+
await setDoc(doc(db, `appData/${appId}/userData/${userId}/settings/preferences`), {
|
|
276
|
+
_appId: appId,
|
|
277
|
+
_createdAt: serverTimestamp(),
|
|
278
|
+
_createdBy: userId,
|
|
279
|
+
theme: 'dark',
|
|
280
|
+
notifications: true,
|
|
281
|
+
language: 'en'
|
|
178
282
|
});
|
|
179
283
|
|
|
180
|
-
//
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
const firebaseApp = initializeApp({
|
|
186
|
-
projectId: firestoreToken.project_id,
|
|
187
|
-
// ... other Firebase config
|
|
188
|
-
});
|
|
284
|
+
// Only the user can read their own settings
|
|
285
|
+
const settings = await getDoc(
|
|
286
|
+
doc(db, `appData/${appId}/userData/${userId}/settings/preferences`)
|
|
287
|
+
);
|
|
288
|
+
```
|
|
189
289
|
|
|
190
|
-
|
|
191
|
-
await signInWithCustomToken(auth, firestoreToken.id_token);
|
|
290
|
+
### Use Case 3: System Announcements (Admin Only)
|
|
192
291
|
|
|
193
|
-
|
|
194
|
-
//
|
|
292
|
+
```typescript
|
|
293
|
+
// Only admins can write to publicRead
|
|
294
|
+
// Regular users and guests can only read
|
|
295
|
+
const announcements = await getDocs(
|
|
296
|
+
collection(db, `appData/${appId}/publicRead/announcements`)
|
|
297
|
+
);
|
|
298
|
+
|
|
299
|
+
announcements.forEach(doc => {
|
|
300
|
+
console.log('Announcement:', doc.data().message);
|
|
301
|
+
});
|
|
195
302
|
```
|
|
196
303
|
|
|
197
|
-
###
|
|
304
|
+
### Use Case 4: Querying Public Data
|
|
198
305
|
|
|
199
306
|
```typescript
|
|
200
|
-
import {
|
|
307
|
+
import { query, where, orderBy, limit } from 'firebase/firestore';
|
|
201
308
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
return {
|
|
212
|
-
token: response.id_token,
|
|
213
|
-
projectId: response.project_id,
|
|
214
|
-
databaseId: response.database_id,
|
|
215
|
-
userId: response.user_id,
|
|
216
|
-
expiresIn: response.expires_in,
|
|
217
|
-
};
|
|
218
|
-
} catch (error) {
|
|
219
|
-
console.error('Error getting Firestore access:', error);
|
|
220
|
-
throw error;
|
|
221
|
-
}
|
|
222
|
-
}
|
|
309
|
+
// Query posts created by a specific user
|
|
310
|
+
const userPosts = query(
|
|
311
|
+
collection(db, `appData/${appId}/publicData/posts`),
|
|
312
|
+
where('_createdBy', '==', userId),
|
|
313
|
+
orderBy('_createdAt', 'desc'),
|
|
314
|
+
limit(10)
|
|
315
|
+
);
|
|
316
|
+
|
|
317
|
+
const snapshot = await getDocs(userPosts);
|
|
223
318
|
```
|
|
224
319
|
|
|
225
|
-
|
|
320
|
+
## Permission Examples
|
|
226
321
|
|
|
227
|
-
|
|
228
|
-
import { DataServiceClient } from '@seaverse/data-service-sdk';
|
|
322
|
+
### What Users CAN Do
|
|
229
323
|
|
|
230
|
-
|
|
324
|
+
✅ **Authenticated Users:**
|
|
325
|
+
- Read `publicRead` data
|
|
326
|
+
- Read and write `publicData` (all users' data)
|
|
327
|
+
- Read and write their own `userData/{userId}` only
|
|
328
|
+
- Update/delete documents where `_createdBy == userId`
|
|
231
329
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
});
|
|
330
|
+
✅ **Guest Users:**
|
|
331
|
+
- Read `publicRead` data
|
|
332
|
+
- Read and write `publicData`
|
|
333
|
+
- **Cannot** access any `userData`
|
|
237
334
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
335
|
+
✅ **Admin Users:**
|
|
336
|
+
- Everything regular users can do
|
|
337
|
+
- Write to `publicRead` data
|
|
241
338
|
|
|
242
|
-
|
|
243
|
-
}
|
|
244
|
-
```
|
|
339
|
+
### What Users CANNOT Do
|
|
245
340
|
|
|
246
|
-
|
|
341
|
+
❌ **All Users:**
|
|
342
|
+
- Access data from a different `app_id`
|
|
343
|
+
- Create documents without required fields (`_appId`, `_createdAt`, `_createdBy`)
|
|
344
|
+
- Modify documents created by other users (except in special cases)
|
|
345
|
+
- Access another user's `userData`
|
|
346
|
+
|
|
347
|
+
❌ **Guest Users:**
|
|
348
|
+
- Access any `userData` paths
|
|
247
349
|
|
|
248
|
-
|
|
350
|
+
## Error Handling
|
|
249
351
|
|
|
250
352
|
```typescript
|
|
251
353
|
try {
|
|
252
354
|
const token = await client.generateFirestoreToken({
|
|
253
355
|
token: 'invalid-token',
|
|
254
|
-
app_id: 'my-app'
|
|
356
|
+
app_id: 'my-app'
|
|
255
357
|
});
|
|
256
358
|
} catch (error) {
|
|
257
359
|
if (error instanceof Error) {
|
|
258
360
|
console.error('Error:', error.message);
|
|
259
|
-
//
|
|
361
|
+
// Handle error (e.g., invalid token, network error)
|
|
260
362
|
}
|
|
261
363
|
}
|
|
262
364
|
```
|
|
263
365
|
|
|
366
|
+
Common errors:
|
|
367
|
+
- `Invalid token` - JWT token is invalid or expired
|
|
368
|
+
- `permission-denied` - Missing required fields or insufficient permissions
|
|
369
|
+
- `Missing or insufficient permissions` - Trying to access unauthorized data
|
|
370
|
+
|
|
264
371
|
## TypeScript Support
|
|
265
372
|
|
|
266
373
|
This SDK is written in TypeScript and provides full type definitions:
|
|
@@ -273,10 +380,129 @@ import type {
|
|
|
273
380
|
GenerateGuestFirestoreTokenRequest,
|
|
274
381
|
FirestoreTokenResponse,
|
|
275
382
|
ApiResponse,
|
|
276
|
-
ApiError
|
|
383
|
+
ApiError
|
|
277
384
|
} from '@seaverse/data-service-sdk';
|
|
278
385
|
```
|
|
279
386
|
|
|
387
|
+
## Best Practices for LLM
|
|
388
|
+
|
|
389
|
+
When using this SDK with LLM-generated code:
|
|
390
|
+
|
|
391
|
+
1. **Always include required fields:**
|
|
392
|
+
```typescript
|
|
393
|
+
{
|
|
394
|
+
_appId: appId, // From token response
|
|
395
|
+
_createdAt: serverTimestamp(), // Use serverTimestamp()
|
|
396
|
+
_createdBy: userId // From token response
|
|
397
|
+
}
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
2. **Use correct data paths:**
|
|
401
|
+
- publicRead: `appData/${appId}/publicRead/{collection}/{docId}`
|
|
402
|
+
- publicData: `appData/${appId}/publicData/{collection}/{docId}`
|
|
403
|
+
- userData: `appData/${appId}/userData/${userId}/{collection}/{docId}`
|
|
404
|
+
|
|
405
|
+
3. **Handle token expiration:**
|
|
406
|
+
- Tokens expire after 1 hour (3600 seconds)
|
|
407
|
+
- Check `expires_in` field and refresh when needed
|
|
408
|
+
|
|
409
|
+
4. **Use serverTimestamp() for timestamps:**
|
|
410
|
+
```typescript
|
|
411
|
+
import { serverTimestamp } from 'firebase/firestore';
|
|
412
|
+
|
|
413
|
+
{
|
|
414
|
+
_createdAt: serverTimestamp() // Not new Date()!
|
|
415
|
+
}
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
5. **Separate guest and authenticated flows:**
|
|
419
|
+
- Use `generateGuestFirestoreToken()` for anonymous users
|
|
420
|
+
- Use `generateFirestoreToken()` for logged-in users
|
|
421
|
+
|
|
422
|
+
## Complete Example
|
|
423
|
+
|
|
424
|
+
Here's a complete example combining authentication and data access:
|
|
425
|
+
|
|
426
|
+
```typescript
|
|
427
|
+
import { DataServiceClient } from '@seaverse/data-service-sdk';
|
|
428
|
+
import { AuthClient } from '@seaverse/auth-sdk';
|
|
429
|
+
import { initializeApp } from 'firebase/app';
|
|
430
|
+
import { getAuth, signInWithCustomToken } from 'firebase/auth';
|
|
431
|
+
import { getFirestore, collection, addDoc, getDocs, query, where, serverTimestamp } from 'firebase/firestore';
|
|
432
|
+
|
|
433
|
+
async function completeExample() {
|
|
434
|
+
const appId = 'my-app-123';
|
|
435
|
+
|
|
436
|
+
// 1. Authenticate user
|
|
437
|
+
const authClient = new AuthClient({ appId });
|
|
438
|
+
const loginResponse = await authClient.loginWithEmail({
|
|
439
|
+
email: 'user@example.com',
|
|
440
|
+
password: 'password123'
|
|
441
|
+
});
|
|
442
|
+
|
|
443
|
+
// 2. Get Firestore token
|
|
444
|
+
const dataClient = new DataServiceClient();
|
|
445
|
+
const firestoreToken = await dataClient.generateFirestoreToken({
|
|
446
|
+
token: loginResponse.token,
|
|
447
|
+
app_id: appId
|
|
448
|
+
});
|
|
449
|
+
|
|
450
|
+
// 3. Initialize Firebase
|
|
451
|
+
const app = initializeApp({ projectId: firestoreToken.project_id });
|
|
452
|
+
const auth = getAuth(app);
|
|
453
|
+
await signInWithCustomToken(auth, firestoreToken.custom_token);
|
|
454
|
+
const db = getFirestore(app);
|
|
455
|
+
|
|
456
|
+
const userId = firestoreToken.user_id;
|
|
457
|
+
|
|
458
|
+
// 4. Create a post (publicData)
|
|
459
|
+
const postRef = await addDoc(
|
|
460
|
+
collection(db, `appData/${appId}/publicData/posts`),
|
|
461
|
+
{
|
|
462
|
+
_appId: appId,
|
|
463
|
+
_createdAt: serverTimestamp(),
|
|
464
|
+
_createdBy: userId,
|
|
465
|
+
title: 'My First Post',
|
|
466
|
+
content: 'Hello world!',
|
|
467
|
+
tags: ['introduction', 'first-post']
|
|
468
|
+
}
|
|
469
|
+
);
|
|
470
|
+
console.log('Created post:', postRef.id);
|
|
471
|
+
|
|
472
|
+
// 5. Read all posts
|
|
473
|
+
const postsSnapshot = await getDocs(
|
|
474
|
+
collection(db, `appData/${appId}/publicData/posts`)
|
|
475
|
+
);
|
|
476
|
+
postsSnapshot.forEach(doc => {
|
|
477
|
+
console.log('Post:', doc.id, doc.data());
|
|
478
|
+
});
|
|
479
|
+
|
|
480
|
+
// 6. Query user's own posts
|
|
481
|
+
const myPostsQuery = query(
|
|
482
|
+
collection(db, `appData/${appId}/publicData/posts`),
|
|
483
|
+
where('_createdBy', '==', userId)
|
|
484
|
+
);
|
|
485
|
+
const myPosts = await getDocs(myPostsQuery);
|
|
486
|
+
console.log('My posts count:', myPosts.size);
|
|
487
|
+
|
|
488
|
+
// 7. Save user preferences (private)
|
|
489
|
+
await addDoc(
|
|
490
|
+
collection(db, `appData/${appId}/userData/${userId}/preferences`),
|
|
491
|
+
{
|
|
492
|
+
_appId: appId,
|
|
493
|
+
_createdAt: serverTimestamp(),
|
|
494
|
+
_createdBy: userId,
|
|
495
|
+
theme: 'dark',
|
|
496
|
+
language: 'en',
|
|
497
|
+
notifications: true
|
|
498
|
+
}
|
|
499
|
+
);
|
|
500
|
+
console.log('Saved user preferences');
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
completeExample();
|
|
504
|
+
```
|
|
505
|
+
|
|
280
506
|
## API Endpoints
|
|
281
507
|
|
|
282
508
|
The SDK connects to the following endpoints by default:
|
|
@@ -294,3 +520,8 @@ MIT
|
|
|
294
520
|
For issues and questions, please visit:
|
|
295
521
|
- GitHub: https://github.com/seaverseai/sv-sdk
|
|
296
522
|
- Email: support@seaverse.com
|
|
523
|
+
|
|
524
|
+
## Related SDKs
|
|
525
|
+
|
|
526
|
+
- [@seaverse/auth-sdk](../auth-sdk) - User authentication and account management
|
|
527
|
+
- [@seaverse/payment-sdk](../payment-sdk) - Payment processing integration
|