@seaverse/data-service-sdk 0.4.0 → 0.5.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/README.md CHANGED
@@ -17,9 +17,56 @@ SeaVerse organizes your Firestore data into three permission levels:
17
17
 
18
18
  | Permission Level | Path Pattern | Read Access | Write Access | Use Case |
19
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 |
20
+ | **publicRead** | `appData/{app_id}/publicRead/{collection}/{docId}` | All authenticated users | Admin only | System configs, announcements, static content |
21
+ | **publicData** | `appData/{app_id}/publicData/{collection}/{docId}` | All authenticated users | All authenticated users | User posts, comments, shared content |
22
+ | **userData** | `appData/{app_id}/userData/{user_id}/{collection}/{docId}` | Owner only | Owner only | User settings, private notes, personal data |
23
+
24
+ ### 🚨 CRITICAL: Firestore Path Rules (For LLM)
25
+
26
+ **Firestore path segments MUST follow these rules:**
27
+
28
+ 1. **Collection paths = ODD number of segments** (1, 3, 5, 7...)
29
+ - Example: `appData/my-app/publicData/posts` (4 segments) ❌ WRONG!
30
+ - Correct: Use collection() function, Firestore handles this automatically
31
+
32
+ 2. **Document paths = EVEN number of segments** (2, 4, 6, 8...)
33
+ - Example: `appData/my-app/publicData/posts/doc123` (5 segments) ✅ CORRECT!
34
+
35
+ 3. **How to use correctly:**
36
+
37
+ ```typescript
38
+ // ✅ CORRECT - Using collection() for collection paths
39
+ collection(db, `appData/${appId}/publicData/posts`) // Firestore handles this as a collection
40
+
41
+ // ✅ CORRECT - Using doc() for document paths
42
+ doc(db, `appData/${appId}/publicData/posts/doc123`) // 5 segments (odd) = document
43
+
44
+ // ❌ WRONG - Manually counting segments
45
+ // Don't worry about counting! Use Firebase functions:
46
+ // - collection() for collections
47
+ // - doc() for documents
48
+ // - addDoc() automatically adds document ID
49
+ ```
50
+
51
+ **Path Structure Examples:**
52
+
53
+ ```typescript
54
+ // Public Data (everyone can read/write)
55
+ const postsRef = collection(db, `appData/${appId}/publicData/posts`);
56
+ await addDoc(postsRef, { ...data }); // Firestore adds document ID
57
+
58
+ // User Private Data (owner only)
59
+ const notesRef = collection(db, `appData/${appId}/userData/${userId}/notes`);
60
+ await addDoc(notesRef, { ...data });
61
+
62
+ // Public Read-Only (everyone can read, admin can write)
63
+ const configRef = collection(db, `appData/${appId}/publicRead/config`);
64
+ await getDocs(configRef);
65
+ ```
66
+
67
+ **The pattern is always:**
68
+ - `appData` → `{app_id}` → `{permission_layer}` → `{collection}` → (auto-generated doc ID)
69
+ - This gives you 5 segments total = document path ✅
23
70
 
24
71
  ### Required Fields
25
72
 
@@ -85,16 +132,14 @@ import { DataServiceClient } from '@seaverse/data-service-sdk';
85
132
 
86
133
  ## Quick Start
87
134
 
88
- ### For Authenticated Users
135
+ ### 🚀 Easiest Way (Recommended - Auto Firebase Setup)
89
136
 
90
137
  ```typescript
91
- import { DataServiceClient } from '@seaverse/data-service-sdk';
138
+ import { DataServiceClient, initializeWithToken } from '@seaverse/data-service-sdk';
92
139
  import { AuthClient } from '@seaverse/auth-sdk';
93
- import { initializeApp } from 'firebase/app';
94
- import { getAuth, signInWithCustomToken } from 'firebase/auth';
95
- import { getFirestore, collection, addDoc, getDocs, serverTimestamp } from 'firebase/firestore';
140
+ import { collection, addDoc, getDocs, serverTimestamp } from 'firebase/firestore';
96
141
 
97
- // Step 1: Login user with Auth SDK
142
+ // Step 1: Login user
98
143
  const authClient = new AuthClient({ appId: 'my-app-123' });
99
144
  const loginResponse = await authClient.loginWithEmail({
100
145
  email: 'user@example.com',
@@ -103,20 +148,15 @@ const loginResponse = await authClient.loginWithEmail({
103
148
 
104
149
  // Step 2: Get Firestore token
105
150
  const dataClient = new DataServiceClient();
106
- const firestoreToken = await dataClient.generateFirestoreToken({
107
- token: loginResponse.token, // JWT from auth
151
+ const tokenResponse = await dataClient.generateFirestoreToken({
152
+ token: loginResponse.token,
108
153
  app_id: 'my-app-123'
109
154
  });
110
155
 
111
- // Step 3: Initialize Firebase
112
- const app = initializeApp({ projectId: firestoreToken.project_id });
113
- const auth = getAuth(app);
114
- await signInWithCustomToken(auth, firestoreToken.custom_token);
115
- const db = getFirestore(app);
156
+ // Step 3: Auto-initialize Firebase (ONE LINE!)
157
+ const { db, appId, userId } = await initializeWithToken(tokenResponse);
116
158
 
117
- // Step 4: Use Firestore with proper paths
118
- const appId = firestoreToken.app_id;
119
- const userId = firestoreToken.user_id;
159
+ // Step 4: Use Firestore directly!
120
160
 
121
161
  // Write to publicData (everyone can write)
122
162
  await addDoc(collection(db, `appData/${appId}/publicData/posts`), {
@@ -143,31 +183,26 @@ await addDoc(collection(db, `appData/${appId}/userData/${userId}/notes`), {
143
183
  });
144
184
  ```
145
185
 
146
- ### For Guest Users
186
+ ### 👤 For Guest Users (Even Simpler!)
147
187
 
148
188
  ```typescript
149
- import { DataServiceClient } from '@seaverse/data-service-sdk';
150
- import { initializeApp } from 'firebase/app';
151
- import { getAuth, signInWithCustomToken } from 'firebase/auth';
152
- import { getFirestore, collection, addDoc, serverTimestamp } from 'firebase/firestore';
189
+ import { DataServiceClient, initializeWithToken } from '@seaverse/data-service-sdk';
190
+ import { collection, addDoc, serverTimestamp } from 'firebase/firestore';
153
191
 
154
192
  // Step 1: Get guest token (no authentication needed!)
155
193
  const dataClient = new DataServiceClient();
156
- const guestToken = await dataClient.generateGuestFirestoreToken({
194
+ const tokenResponse = await dataClient.generateGuestFirestoreToken({
157
195
  app_id: 'my-app-123'
158
196
  });
159
197
 
160
- // Step 2: Initialize Firebase
161
- const app = initializeApp({ projectId: guestToken.project_id });
162
- const auth = getAuth(app);
163
- await signInWithCustomToken(auth, guestToken.custom_token);
164
- const db = getFirestore(app);
198
+ // Step 2: Auto-initialize Firebase (ONE LINE!)
199
+ const { db, appId, userId } = await initializeWithToken(tokenResponse);
165
200
 
166
201
  // Step 3: Guest can write to publicData
167
- await addDoc(collection(db, `appData/${guestToken.app_id}/publicData/comments`), {
168
- _appId: guestToken.app_id,
202
+ await addDoc(collection(db, `appData/${appId}/publicData/comments`), {
203
+ _appId: appId,
169
204
  _createdAt: serverTimestamp(),
170
- _createdBy: guestToken.user_id, // Guest user ID (e.g., 'guest-abc123')
205
+ _createdBy: userId, // Guest user ID (e.g., 'guest-abc123')
171
206
  comment: 'Great app!',
172
207
  rating: 5
173
208
  });
@@ -175,6 +210,36 @@ await addDoc(collection(db, `appData/${guestToken.app_id}/publicData/comments`),
175
210
  // Note: Guests CANNOT access userData
176
211
  ```
177
212
 
213
+ ### 🔧 Manual Way (If you need more control)
214
+
215
+ If you prefer to initialize Firebase manually:
216
+
217
+ ```typescript
218
+ import { DataServiceClient, getFirebaseConfig } from '@seaverse/data-service-sdk';
219
+ import { initializeApp } from 'firebase/app';
220
+ import { getAuth, signInWithCustomToken } from 'firebase/auth';
221
+ import { getFirestore } from 'firebase/firestore';
222
+
223
+ const dataClient = new DataServiceClient();
224
+ const tokenResponse = await dataClient.generateGuestFirestoreToken({
225
+ app_id: 'my-app-123'
226
+ });
227
+
228
+ // Option 1: Use getFirebaseConfig helper
229
+ const firebaseConfig = getFirebaseConfig(tokenResponse);
230
+ const app = initializeApp(firebaseConfig);
231
+
232
+ // Option 2: Manual config
233
+ const app = initializeApp({
234
+ apiKey: tokenResponse.web_api_key, // ✅ Provided automatically!
235
+ projectId: tokenResponse.project_id
236
+ });
237
+
238
+ const auth = getAuth(app);
239
+ await signInWithCustomToken(auth, tokenResponse.custom_token);
240
+ const db = getFirestore(app);
241
+ ```
242
+
178
243
  ## API Reference
179
244
 
180
245
  ### DataServiceClient
@@ -232,11 +297,12 @@ interface GenerateFirestoreTokenRequest {
232
297
  ```typescript
233
298
  interface FirestoreTokenResponse {
234
299
  custom_token: string; // Firebase Custom Token - use with signInWithCustomToken()
300
+ web_api_key: string; // Firebase Web API Key - use with initializeApp()
235
301
  project_id: string; // Firebase Project ID for initializeApp()
236
302
  database_id: string; // Firestore Database ID
237
303
  app_id?: string; // Application ID (use in Firestore paths)
238
304
  user_id: string; // User ID (use in Firestore paths)
239
- role?: string; // User role ('guest', 'user', 'admin')
305
+ user_type: string; // User type ('guest', 'user', 'admin', 'appadmin')
240
306
  expires_in: number; // Token expiration in seconds (typically 3600)
241
307
  }
242
308
  ```
@@ -286,7 +352,63 @@ const guestToken = await client.generateGuestFirestoreToken({
286
352
 
287
353
  console.log('Guest Custom Token:', guestToken.custom_token);
288
354
  console.log('Guest User ID:', guestToken.user_id);
289
- console.log('Role:', guestToken.role); // 'guest'
355
+ console.log('User Type:', guestToken.user_type); // 'guest'
356
+ ```
357
+
358
+ ### Helper Functions
359
+
360
+ #### getFirebaseConfig
361
+
362
+ Extract Firebase configuration from token response.
363
+
364
+ ```typescript
365
+ getFirebaseConfig(tokenResponse: FirestoreTokenResponse): FirebaseConfig
366
+ ```
367
+
368
+ **Example:**
369
+
370
+ ```typescript
371
+ import { getFirebaseConfig } from '@seaverse/data-service-sdk';
372
+ import { initializeApp } from 'firebase/app';
373
+
374
+ const tokenResponse = await client.generateGuestFirestoreToken({ app_id: 'my-app' });
375
+ const firebaseConfig = getFirebaseConfig(tokenResponse);
376
+ // Returns: { apiKey: '...', projectId: '...' }
377
+
378
+ const app = initializeApp(firebaseConfig);
379
+ ```
380
+
381
+ #### initializeWithToken
382
+
383
+ Automatically initialize Firebase and sign in with token (one-line setup).
384
+
385
+ ```typescript
386
+ initializeWithToken(tokenResponse: FirestoreTokenResponse): Promise<{
387
+ app: FirebaseApp;
388
+ auth: Auth;
389
+ db: Firestore;
390
+ userId: string;
391
+ appId: string;
392
+ }>
393
+ ```
394
+
395
+ **Example:**
396
+
397
+ ```typescript
398
+ import { initializeWithToken } from '@seaverse/data-service-sdk';
399
+
400
+ const tokenResponse = await client.generateGuestFirestoreToken({ app_id: 'my-app' });
401
+
402
+ // One line to get everything!
403
+ const { db, appId, userId } = await initializeWithToken(tokenResponse);
404
+
405
+ // Ready to use Firestore
406
+ await addDoc(collection(db, `appData/${appId}/publicData/posts`), { ... });
407
+ ```
408
+
409
+ **Note:** This function requires Firebase SDK to be installed separately:
410
+ ```bash
411
+ npm install firebase
290
412
  ```
291
413
 
292
414
  ## Common Use Cases
package/dist/browser.js CHANGED
@@ -4173,5 +4173,94 @@ class DataServiceClient {
4173
4173
  }
4174
4174
  }
4175
4175
 
4176
- export { DEFAULT_BASE_URL, DEFAULT_TIMEOUT, DataServiceClient, ENDPOINTS };
4176
+ /**
4177
+ * Create Firebase configuration from Firestore token response
4178
+ *
4179
+ * This helper function extracts the Firebase config from the token response,
4180
+ * making it easy to initialize Firebase app.
4181
+ *
4182
+ * @param tokenResponse - The Firestore token response from SDK
4183
+ * @returns Firebase configuration object ready for initializeApp()
4184
+ *
4185
+ * @example
4186
+ * ```typescript
4187
+ * import { initializeApp } from 'firebase/app';
4188
+ * import { getFirebaseConfig } from '@seaverse/data-service-sdk';
4189
+ *
4190
+ * const tokenResponse = await client.generateGuestFirestoreToken({ app_id: 'my-app' });
4191
+ * const firebaseConfig = getFirebaseConfig(tokenResponse);
4192
+ *
4193
+ * const app = initializeApp(firebaseConfig);
4194
+ * ```
4195
+ */
4196
+ function getFirebaseConfig(tokenResponse) {
4197
+ return {
4198
+ apiKey: tokenResponse.web_api_key,
4199
+ projectId: tokenResponse.project_id,
4200
+ };
4201
+ }
4202
+ /**
4203
+ * Initialize Firebase with Firestore token response (browser only)
4204
+ *
4205
+ * This is a convenience function that automatically:
4206
+ * 1. Creates Firebase config from token response
4207
+ * 2. Initializes Firebase app
4208
+ * 3. Signs in with the custom token
4209
+ * 4. Returns authenticated Firebase instances
4210
+ *
4211
+ * IMPORTANT: This function requires Firebase SDK to be installed separately:
4212
+ * npm install firebase
4213
+ *
4214
+ * @param tokenResponse - The Firestore token response from SDK
4215
+ * @returns Object containing initialized Firebase app, auth, and db instances
4216
+ *
4217
+ * @example
4218
+ * ```typescript
4219
+ * import { initializeWithToken } from '@seaverse/data-service-sdk';
4220
+ *
4221
+ * const tokenResponse = await client.generateGuestFirestoreToken({ app_id: 'my-app' });
4222
+ * const { app, auth, db, userId, appId } = await initializeWithToken(tokenResponse);
4223
+ *
4224
+ * // Ready to use Firestore!
4225
+ * const snapshot = await getDocs(collection(db, `appData/${appId}/publicData/posts`));
4226
+ * ```
4227
+ */
4228
+ async function initializeWithToken(tokenResponse) {
4229
+ // Check if Firebase SDK is available
4230
+ let initializeApp;
4231
+ let getAuth;
4232
+ let signInWithCustomToken;
4233
+ let getFirestore;
4234
+ try {
4235
+ // Try to import Firebase modules
4236
+ const firebaseApp = await import('firebase/app');
4237
+ const firebaseAuth = await import('firebase/auth');
4238
+ const firebaseFirestore = await import('firebase/firestore');
4239
+ initializeApp = firebaseApp.initializeApp;
4240
+ getAuth = firebaseAuth.getAuth;
4241
+ signInWithCustomToken = firebaseAuth.signInWithCustomToken;
4242
+ getFirestore = firebaseFirestore.getFirestore;
4243
+ }
4244
+ catch (error) {
4245
+ throw new Error('Firebase SDK not found. Please install it: npm install firebase\n' +
4246
+ 'Or import manually and use getFirebaseConfig() helper instead.');
4247
+ }
4248
+ // Initialize Firebase
4249
+ const config = getFirebaseConfig(tokenResponse);
4250
+ const app = initializeApp(config);
4251
+ // Sign in with custom token
4252
+ const auth = getAuth(app);
4253
+ await signInWithCustomToken(auth, tokenResponse.custom_token);
4254
+ // Get Firestore instance
4255
+ const db = getFirestore(app);
4256
+ return {
4257
+ app,
4258
+ auth,
4259
+ db,
4260
+ userId: tokenResponse.user_id,
4261
+ appId: tokenResponse.app_id || '',
4262
+ };
4263
+ }
4264
+
4265
+ export { DEFAULT_BASE_URL, DEFAULT_TIMEOUT, DataServiceClient, ENDPOINTS, getFirebaseConfig, initializeWithToken };
4177
4266
  //# sourceMappingURL=browser.js.map