@seaverse/data-service-sdk 0.10.0 → 0.10.2
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 +313 -16
- package/dist/browser.js +80 -21
- package/dist/browser.js.map +1 -1
- package/dist/browser.umd.js +80 -21
- package/dist/browser.umd.js.map +1 -1
- package/dist/index.cjs +80 -21
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +20 -11
- package/dist/index.js +80 -21
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/browser.umd.js
CHANGED
|
@@ -3945,9 +3945,9 @@
|
|
|
3945
3945
|
* ---------------------------
|
|
3946
3946
|
* Your Firestore data is organized in three permission levels:
|
|
3947
3947
|
*
|
|
3948
|
-
* 1. publicRead/ - System configs, announcements (Read: Everyone, Write: Admin only)
|
|
3949
|
-
* 2. publicData/ - User posts, shared content (Read: Everyone, Write: Everyone)
|
|
3950
|
-
* 3. userData/{userId}/ - Private user data (Read/Write: Owner only)
|
|
3948
|
+
* 1. publicRead/_data/ - System configs, announcements (Read: Everyone, Write: Admin only)
|
|
3949
|
+
* 2. publicData/_data/ - User posts, shared content (Read: Everyone, Write: Everyone)
|
|
3950
|
+
* 3. userData/{userId}/_data/ - Private user data (Read/Write: Owner only)
|
|
3951
3951
|
*
|
|
3952
3952
|
* QUICK START FOR LLM:
|
|
3953
3953
|
* -------------------
|
|
@@ -3999,7 +3999,7 @@
|
|
|
3999
3999
|
* const snapshot = await getDocs(collection(db, `appData/${appId}/publicData/posts`));
|
|
4000
4000
|
*
|
|
4001
4001
|
* // Write to userData (only owner can write)
|
|
4002
|
-
* await addDoc(collection(db, `appData/${appId}/userData/${userId}/notes`), {
|
|
4002
|
+
* await addDoc(collection(db, `appData/${appId}/userData/${userId}/_data/notes`), {
|
|
4003
4003
|
* _appId: appId, // REQUIRED
|
|
4004
4004
|
* _createdAt: serverTimestamp(), // REQUIRED
|
|
4005
4005
|
* _createdBy: userId, // REQUIRED
|
|
@@ -4252,7 +4252,7 @@
|
|
|
4252
4252
|
* ```typescript
|
|
4253
4253
|
* // Write private user notes
|
|
4254
4254
|
* const path = getUserDataPath('my-app', 'user-123', 'notes');
|
|
4255
|
-
* // Returns: 'appData/my-app/userData/user-123/notes'
|
|
4255
|
+
* // Returns: 'appData/my-app/userData/user-123/_data/notes'
|
|
4256
4256
|
*
|
|
4257
4257
|
* await addDoc(collection(db, path), {
|
|
4258
4258
|
* _appId: appId,
|
|
@@ -4266,7 +4266,7 @@
|
|
|
4266
4266
|
validateSegment('appId', appId);
|
|
4267
4267
|
validateSegment('userId', userId);
|
|
4268
4268
|
validateSegment('collectionName', collectionName);
|
|
4269
|
-
return `appData/${appId}/userData/${userId}/${collectionName}`;
|
|
4269
|
+
return `appData/${appId}/userData/${userId}/_data/${collectionName}`;
|
|
4270
4270
|
}
|
|
4271
4271
|
/**
|
|
4272
4272
|
* Generate path for a specific document in publicRead
|
|
@@ -4324,7 +4324,7 @@
|
|
|
4324
4324
|
* @example
|
|
4325
4325
|
* ```typescript
|
|
4326
4326
|
* const path = getUserDataDocPath('my-app', 'user-123', 'notes', 'note-456');
|
|
4327
|
-
* // Returns: 'appData/my-app/userData/user-123/notes/note-456'
|
|
4327
|
+
* // Returns: 'appData/my-app/userData/user-123/_data/notes/note-456'
|
|
4328
4328
|
*
|
|
4329
4329
|
* const docSnap = await getDoc(doc(db, path));
|
|
4330
4330
|
* ```
|
|
@@ -4334,7 +4334,7 @@
|
|
|
4334
4334
|
validateSegment('userId', userId);
|
|
4335
4335
|
validateSegment('collectionName', collectionName);
|
|
4336
4336
|
validateSegment('docId', docId);
|
|
4337
|
-
return `appData/${appId}/userData/${userId}/${collectionName}/${docId}`;
|
|
4337
|
+
return `appData/${appId}/userData/${userId}/_data/${collectionName}/${docId}`;
|
|
4338
4338
|
}
|
|
4339
4339
|
/**
|
|
4340
4340
|
* Validate a path segment to ensure it doesn't contain invalid characters
|
|
@@ -4399,7 +4399,7 @@
|
|
|
4399
4399
|
userData(userId, collectionName) {
|
|
4400
4400
|
validateSegment('userId', userId);
|
|
4401
4401
|
validateSegment('collectionName', collectionName);
|
|
4402
|
-
this.segments.push('userData', userId, collectionName);
|
|
4402
|
+
this.segments.push('userData', userId, '_data', collectionName);
|
|
4403
4403
|
return this;
|
|
4404
4404
|
}
|
|
4405
4405
|
/**
|
|
@@ -5018,7 +5018,9 @@
|
|
|
5018
5018
|
}
|
|
5019
5019
|
else {
|
|
5020
5020
|
// Filter out soft-deleted documents
|
|
5021
|
-
|
|
5021
|
+
// Use '!=' to include documents without _deleted field (new documents)
|
|
5022
|
+
// This will return documents where _deleted is missing, null, undefined, or false
|
|
5023
|
+
const q = query(colRef, where('_deleted', '!=', true));
|
|
5022
5024
|
return getDocs(q);
|
|
5023
5025
|
}
|
|
5024
5026
|
}
|
|
@@ -5151,7 +5153,7 @@
|
|
|
5151
5153
|
*
|
|
5152
5154
|
* This is a convenience function that automatically:
|
|
5153
5155
|
* 1. Creates Firebase config from token response
|
|
5154
|
-
* 2. Initializes Firebase app
|
|
5156
|
+
* 2. Initializes Firebase app (or reuses existing one)
|
|
5155
5157
|
* 3. Signs in with the custom token
|
|
5156
5158
|
* 4. Creates FirestoreHelper for LLM-friendly operations
|
|
5157
5159
|
* 5. Returns authenticated Firebase instances
|
|
@@ -5159,11 +5161,20 @@
|
|
|
5159
5161
|
* IMPORTANT: This function requires Firebase SDK to be installed separately:
|
|
5160
5162
|
* npm install firebase
|
|
5161
5163
|
*
|
|
5164
|
+
* ⚠️ IMPORTANT: This function can be called multiple times safely. It will:
|
|
5165
|
+
* - Reuse existing Firebase app if already initialized
|
|
5166
|
+
* - Re-authenticate with new token if needed
|
|
5167
|
+
* - Handle token refresh scenarios
|
|
5168
|
+
*
|
|
5162
5169
|
* 🎯 LLM RECOMMENDED: Use the `helper` object for simplified operations
|
|
5163
5170
|
*
|
|
5164
5171
|
* @param tokenResponse - The Firestore token response from SDK
|
|
5165
5172
|
* @returns Object containing initialized Firebase instances and LLM-friendly helper
|
|
5166
5173
|
*
|
|
5174
|
+
* @throws {Error} If app_id is missing from token response
|
|
5175
|
+
* @throws {Error} If Firebase SDK is not installed
|
|
5176
|
+
* @throws {Error} If authentication fails
|
|
5177
|
+
*
|
|
5167
5178
|
* @example
|
|
5168
5179
|
* ```typescript
|
|
5169
5180
|
* import { initializeWithToken } from '@seaverse/data-service-sdk';
|
|
@@ -5182,17 +5193,25 @@
|
|
|
5182
5193
|
* ```
|
|
5183
5194
|
*/
|
|
5184
5195
|
async function initializeWithToken(tokenResponse) {
|
|
5196
|
+
// ✅ FIX #3: Validate appId FIRST before any initialization
|
|
5197
|
+
const appId = tokenResponse.app_id;
|
|
5198
|
+
if (!appId) {
|
|
5199
|
+
throw new Error('app_id is required in token response. ' +
|
|
5200
|
+
'Make sure your token response includes a valid app_id field.');
|
|
5201
|
+
}
|
|
5185
5202
|
// Check if Firebase SDK is available
|
|
5186
5203
|
let initializeApp;
|
|
5187
5204
|
let getAuth;
|
|
5188
5205
|
let signInWithCustomToken;
|
|
5189
5206
|
let getFirestore;
|
|
5207
|
+
let getApps;
|
|
5190
5208
|
try {
|
|
5191
5209
|
// Try to import Firebase modules
|
|
5192
5210
|
const firebaseApp = await import('firebase/app');
|
|
5193
5211
|
const firebaseAuth = await import('firebase/auth');
|
|
5194
5212
|
const firebaseFirestore = await import('firebase/firestore');
|
|
5195
5213
|
initializeApp = firebaseApp.initializeApp;
|
|
5214
|
+
getApps = firebaseApp.getApps;
|
|
5196
5215
|
getAuth = firebaseAuth.getAuth;
|
|
5197
5216
|
signInWithCustomToken = firebaseAuth.signInWithCustomToken;
|
|
5198
5217
|
getFirestore = firebaseFirestore.getFirestore;
|
|
@@ -5201,17 +5220,57 @@
|
|
|
5201
5220
|
throw new Error('Firebase SDK not found. Please install it: npm install firebase\n' +
|
|
5202
5221
|
'Or import manually and use getFirebaseConfig() helper instead.');
|
|
5203
5222
|
}
|
|
5204
|
-
//
|
|
5205
|
-
const
|
|
5206
|
-
const
|
|
5207
|
-
|
|
5208
|
-
|
|
5209
|
-
|
|
5210
|
-
|
|
5211
|
-
|
|
5212
|
-
|
|
5223
|
+
// ✅ FIX #1: Check if Firebase app already exists
|
|
5224
|
+
const existingApps = getApps();
|
|
5225
|
+
const existingApp = existingApps.find((app) => app.name === '[DEFAULT]');
|
|
5226
|
+
let app;
|
|
5227
|
+
let auth;
|
|
5228
|
+
let db;
|
|
5229
|
+
if (existingApp) {
|
|
5230
|
+
// ✅ FIX #2: Reuse existing app instead of creating new one
|
|
5231
|
+
console.log('[SeaVerse SDK] Reusing existing Firebase app');
|
|
5232
|
+
app = existingApp;
|
|
5233
|
+
auth = getAuth(app);
|
|
5234
|
+
db = getFirestore(app, tokenResponse.database_id);
|
|
5235
|
+
// ✅ FIX #4: Re-authenticate with new token (for token refresh scenarios)
|
|
5236
|
+
try {
|
|
5237
|
+
await signInWithCustomToken(auth, tokenResponse.custom_token);
|
|
5238
|
+
console.log('[SeaVerse SDK] Re-authenticated with new token');
|
|
5239
|
+
}
|
|
5240
|
+
catch (error) {
|
|
5241
|
+
// If already signed in with same token, ignore error
|
|
5242
|
+
// Only throw if it's a real authentication failure
|
|
5243
|
+
if (error?.code !== 'auth/invalid-credential' && error?.code !== 'auth/network-request-failed') {
|
|
5244
|
+
console.warn('[SeaVerse SDK] Re-authentication warning:', error?.message || error);
|
|
5245
|
+
}
|
|
5246
|
+
}
|
|
5247
|
+
}
|
|
5248
|
+
else {
|
|
5249
|
+
// ✅ FIX #4: First-time initialization with proper error handling
|
|
5250
|
+
console.log('[SeaVerse SDK] Initializing new Firebase app');
|
|
5251
|
+
try {
|
|
5252
|
+
const config = getFirebaseConfig(tokenResponse);
|
|
5253
|
+
app = initializeApp(config);
|
|
5254
|
+
auth = getAuth(app);
|
|
5255
|
+
await signInWithCustomToken(auth, tokenResponse.custom_token);
|
|
5256
|
+
// IMPORTANT: Must specify database_id, not just use default!
|
|
5257
|
+
db = getFirestore(app, tokenResponse.database_id);
|
|
5258
|
+
}
|
|
5259
|
+
catch (error) {
|
|
5260
|
+
// ✅ FIX #4: Cleanup on failure to prevent half-initialized state
|
|
5261
|
+
if (app) {
|
|
5262
|
+
try {
|
|
5263
|
+
await app.delete();
|
|
5264
|
+
console.log('[SeaVerse SDK] Cleaned up failed Firebase app initialization');
|
|
5265
|
+
}
|
|
5266
|
+
catch (cleanupError) {
|
|
5267
|
+
console.warn('[SeaVerse SDK] Failed to cleanup app:', cleanupError);
|
|
5268
|
+
}
|
|
5269
|
+
}
|
|
5270
|
+
throw new Error(`Failed to initialize Firebase: ${error instanceof Error ? error.message : String(error)}`);
|
|
5271
|
+
}
|
|
5272
|
+
}
|
|
5213
5273
|
const userId = tokenResponse.user_id;
|
|
5214
|
-
const appId = tokenResponse.app_id || '';
|
|
5215
5274
|
// Create LLM-friendly helper
|
|
5216
5275
|
const helper = new FirestoreHelper(db, appId, userId);
|
|
5217
5276
|
return {
|