@seaverse/data-service-sdk 0.10.2 → 0.11.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 +25 -8
- package/dist/browser.js +49 -18
- package/dist/browser.js.map +1 -1
- package/dist/browser.umd.js +49 -18
- package/dist/browser.umd.js.map +1 -1
- package/dist/index.cjs +49 -18
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1995 -9
- package/dist/index.js +49 -18
- package/dist/index.js.map +1 -1
- package/package.json +9 -1
package/README.md
CHANGED
|
@@ -53,7 +53,7 @@ SeaVerse organizes your Firestore data into three permission levels:
|
|
|
53
53
|
|-----------------|--------------|-------------|--------------|----------|
|
|
54
54
|
| **publicRead** | `appData/{app_id}/publicRead/_data/{collection}/{docId}` | All authenticated users | Admin only | System configs, announcements, static content |
|
|
55
55
|
| **publicData** | `appData/{app_id}/publicData/_data/{collection}/{docId}` | All authenticated users | All authenticated users | User posts, comments, shared content |
|
|
56
|
-
| **userData** | `appData/{app_id}/userData/{user_id}/
|
|
56
|
+
| **userData** | `appData/{app_id}/userData/{user_id}/{collection}/{docId}` | Owner only | Owner only | User settings, private notes, personal data |
|
|
57
57
|
|
|
58
58
|
### 🚨 CRITICAL: Firestore Path Rules (For LLM)
|
|
59
59
|
|
|
@@ -88,7 +88,7 @@ const postsRef = collection(db, `appData/${appId}/publicData/_data/posts`);
|
|
|
88
88
|
await addDoc(postsRef, { ...data }); // Firestore adds document ID
|
|
89
89
|
|
|
90
90
|
// User Private Data (owner only)
|
|
91
|
-
const notesRef = collection(db, `appData/${appId}/userData/${userId}/
|
|
91
|
+
const notesRef = collection(db, `appData/${appId}/userData/${userId}/notes`);
|
|
92
92
|
await addDoc(notesRef, { ...data });
|
|
93
93
|
|
|
94
94
|
// Public Read-Only (everyone can read, admin can write)
|
|
@@ -97,9 +97,9 @@ await getDocs(configRef);
|
|
|
97
97
|
```
|
|
98
98
|
|
|
99
99
|
**The pattern is always:**
|
|
100
|
-
- `appData` → `{app_id}` → `{permission_layer}` → (`{user_id}` for userData) → `
|
|
100
|
+
- `appData` → `{app_id}` → `{permission_layer}` → `_data` (for publicRead/publicData) OR `{user_id}` (for userData) → `{collection}` → (auto-generated doc ID)
|
|
101
101
|
- publicRead/publicData Collection: 5 segments (odd) ✅
|
|
102
|
-
- userData Collection:
|
|
102
|
+
- userData Collection: 5 segments (odd) ✅ (userId replaces _data segment)
|
|
103
103
|
- Document paths: add 1 more segment for docId
|
|
104
104
|
|
|
105
105
|
### Required Fields
|
|
@@ -383,6 +383,23 @@ await helper.addToUserData('notes', {
|
|
|
383
383
|
title: 'Private Note',
|
|
384
384
|
content: 'Only I can see this'
|
|
385
385
|
});
|
|
386
|
+
|
|
387
|
+
// ✅ NEW in v0.11.0: Simple Pagination Support
|
|
388
|
+
// Get first 20 posts
|
|
389
|
+
const first20 = await helper.getPublicData('posts', false, { limit: 20 });
|
|
390
|
+
first20.forEach(doc => {
|
|
391
|
+
console.log(doc.id, doc.data());
|
|
392
|
+
});
|
|
393
|
+
|
|
394
|
+
// Get next page after last document
|
|
395
|
+
const lastDoc = first20.docs[first20.docs.length - 1];
|
|
396
|
+
const next20 = await helper.getPublicData('posts', false, {
|
|
397
|
+
limit: 20,
|
|
398
|
+
startAfter: lastDoc
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
// Also works with getUserData
|
|
402
|
+
const first10Notes = await helper.getUserData('notes', false, { limit: 10 });
|
|
386
403
|
```
|
|
387
404
|
|
|
388
405
|
<details>
|
|
@@ -717,7 +734,7 @@ const comments = await getDocs(
|
|
|
717
734
|
|
|
718
735
|
```typescript
|
|
719
736
|
// Only the user can write to their own settings
|
|
720
|
-
await setDoc(doc(db, `appData/${appId}/userData/${userId}/
|
|
737
|
+
await setDoc(doc(db, `appData/${appId}/userData/${userId}/settings/preferences`), {
|
|
721
738
|
_appId: appId,
|
|
722
739
|
_createdAt: serverTimestamp(),
|
|
723
740
|
_createdBy: userId,
|
|
@@ -728,7 +745,7 @@ await setDoc(doc(db, `appData/${appId}/userData/${userId}/_data/settings/prefere
|
|
|
728
745
|
|
|
729
746
|
// Only the user can read their own settings
|
|
730
747
|
const settings = await getDoc(
|
|
731
|
-
doc(db, `appData/${appId}/userData/${userId}/
|
|
748
|
+
doc(db, `appData/${appId}/userData/${userId}/settings/preferences`)
|
|
732
749
|
);
|
|
733
750
|
```
|
|
734
751
|
|
|
@@ -1230,7 +1247,7 @@ async function completeExample() {
|
|
|
1230
1247
|
|
|
1231
1248
|
// 7. Save user preferences (private)
|
|
1232
1249
|
await addDoc(
|
|
1233
|
-
collection(db, `appData/${appId}/userData/${userId}/
|
|
1250
|
+
collection(db, `appData/${appId}/userData/${userId}/preferences`),
|
|
1234
1251
|
{
|
|
1235
1252
|
_appId: appId,
|
|
1236
1253
|
_createdAt: serverTimestamp(),
|
|
@@ -1316,4 +1333,4 @@ Here's a complete example for using the SDK directly in the browser without any
|
|
|
1316
1333
|
## Related SDKs
|
|
1317
1334
|
|
|
1318
1335
|
- [@seaverse/auth-sdk](../auth-sdk) - User authentication and account management
|
|
1319
|
-
- [@seaverse/
|
|
1336
|
+
- [@seaverse/assets-sdk](../assets-sdk) - Assets and payment processing integration
|
package/dist/browser.js
CHANGED
|
@@ -4248,7 +4248,7 @@ function getPublicDataPath(appId, collectionName) {
|
|
|
4248
4248
|
* ```typescript
|
|
4249
4249
|
* // Write private user notes
|
|
4250
4250
|
* const path = getUserDataPath('my-app', 'user-123', 'notes');
|
|
4251
|
-
* // Returns: 'appData/my-app/userData/user-123/
|
|
4251
|
+
* // Returns: 'appData/my-app/userData/user-123/notes'
|
|
4252
4252
|
*
|
|
4253
4253
|
* await addDoc(collection(db, path), {
|
|
4254
4254
|
* _appId: appId,
|
|
@@ -4262,7 +4262,7 @@ function getUserDataPath(appId, userId, collectionName) {
|
|
|
4262
4262
|
validateSegment('appId', appId);
|
|
4263
4263
|
validateSegment('userId', userId);
|
|
4264
4264
|
validateSegment('collectionName', collectionName);
|
|
4265
|
-
return `appData/${appId}/userData/${userId}
|
|
4265
|
+
return `appData/${appId}/userData/${userId}/${collectionName}`;
|
|
4266
4266
|
}
|
|
4267
4267
|
/**
|
|
4268
4268
|
* Generate path for a specific document in publicRead
|
|
@@ -4320,7 +4320,7 @@ function getPublicDataDocPath(appId, collectionName, docId) {
|
|
|
4320
4320
|
* @example
|
|
4321
4321
|
* ```typescript
|
|
4322
4322
|
* const path = getUserDataDocPath('my-app', 'user-123', 'notes', 'note-456');
|
|
4323
|
-
* // Returns: 'appData/my-app/userData/user-123/
|
|
4323
|
+
* // Returns: 'appData/my-app/userData/user-123/notes/note-456'
|
|
4324
4324
|
*
|
|
4325
4325
|
* const docSnap = await getDoc(doc(db, path));
|
|
4326
4326
|
* ```
|
|
@@ -4330,7 +4330,7 @@ function getUserDataDocPath(appId, userId, collectionName, docId) {
|
|
|
4330
4330
|
validateSegment('userId', userId);
|
|
4331
4331
|
validateSegment('collectionName', collectionName);
|
|
4332
4332
|
validateSegment('docId', docId);
|
|
4333
|
-
return `appData/${appId}/userData/${userId}
|
|
4333
|
+
return `appData/${appId}/userData/${userId}/${collectionName}/${docId}`;
|
|
4334
4334
|
}
|
|
4335
4335
|
/**
|
|
4336
4336
|
* Validate a path segment to ensure it doesn't contain invalid characters
|
|
@@ -4395,7 +4395,7 @@ class PathBuilder {
|
|
|
4395
4395
|
userData(userId, collectionName) {
|
|
4396
4396
|
validateSegment('userId', userId);
|
|
4397
4397
|
validateSegment('collectionName', collectionName);
|
|
4398
|
-
this.segments.push('userData', userId,
|
|
4398
|
+
this.segments.push('userData', userId, collectionName);
|
|
4399
4399
|
return this;
|
|
4400
4400
|
}
|
|
4401
4401
|
/**
|
|
@@ -4782,6 +4782,7 @@ class FirestoreHelper {
|
|
|
4782
4782
|
*
|
|
4783
4783
|
* @param collectionName - Collection name
|
|
4784
4784
|
* @param includeDeleted - Include soft-deleted documents (default: false)
|
|
4785
|
+
* @param options - Optional query options (limit, startAfter)
|
|
4785
4786
|
* @returns QuerySnapshot with documents
|
|
4786
4787
|
*
|
|
4787
4788
|
* @example
|
|
@@ -4794,11 +4795,21 @@ class FirestoreHelper {
|
|
|
4794
4795
|
*
|
|
4795
4796
|
* // Include deleted posts (admin use case)
|
|
4796
4797
|
* const allPosts = await helper.getPublicData('posts', true);
|
|
4798
|
+
*
|
|
4799
|
+
* // Get first 20 posts (simple pagination)
|
|
4800
|
+
* const first20 = await helper.getPublicData('posts', false, { limit: 20 });
|
|
4801
|
+
*
|
|
4802
|
+
* // Get next page after last document
|
|
4803
|
+
* const lastDoc = first20.docs[first20.docs.length - 1];
|
|
4804
|
+
* const next20 = await helper.getPublicData('posts', false, {
|
|
4805
|
+
* limit: 20,
|
|
4806
|
+
* startAfter: lastDoc
|
|
4807
|
+
* });
|
|
4797
4808
|
* ```
|
|
4798
4809
|
*/
|
|
4799
|
-
async getPublicData(collectionName, includeDeleted = false) {
|
|
4810
|
+
async getPublicData(collectionName, includeDeleted = false, options) {
|
|
4800
4811
|
const path = getPublicDataPath(this.appId, collectionName);
|
|
4801
|
-
return this.getDocs(path, includeDeleted);
|
|
4812
|
+
return this.getDocs(path, includeDeleted, options);
|
|
4802
4813
|
}
|
|
4803
4814
|
/**
|
|
4804
4815
|
* Get all documents from userData collection (user's private data)
|
|
@@ -4807,6 +4818,7 @@ class FirestoreHelper {
|
|
|
4807
4818
|
*
|
|
4808
4819
|
* @param collectionName - Collection name
|
|
4809
4820
|
* @param includeDeleted - Include soft-deleted documents (default: false)
|
|
4821
|
+
* @param options - Optional query options (limit, startAfter)
|
|
4810
4822
|
* @returns QuerySnapshot with documents
|
|
4811
4823
|
*
|
|
4812
4824
|
* @example
|
|
@@ -4815,11 +4827,14 @@ class FirestoreHelper {
|
|
|
4815
4827
|
* snapshot.forEach(doc => {
|
|
4816
4828
|
* console.log('My note:', doc.data());
|
|
4817
4829
|
* });
|
|
4830
|
+
*
|
|
4831
|
+
* // Get first 10 notes with pagination
|
|
4832
|
+
* const first10 = await helper.getUserData('notes', false, { limit: 10 });
|
|
4818
4833
|
* ```
|
|
4819
4834
|
*/
|
|
4820
|
-
async getUserData(collectionName, includeDeleted = false) {
|
|
4835
|
+
async getUserData(collectionName, includeDeleted = false, options) {
|
|
4821
4836
|
const path = getUserDataPath(this.appId, this.userId, collectionName);
|
|
4822
|
-
return this.getDocs(path, includeDeleted);
|
|
4837
|
+
return this.getDocs(path, includeDeleted, options);
|
|
4823
4838
|
}
|
|
4824
4839
|
/**
|
|
4825
4840
|
* Get all documents from publicRead collection (read-only for users)
|
|
@@ -5004,21 +5019,36 @@ class FirestoreHelper {
|
|
|
5004
5019
|
/**
|
|
5005
5020
|
* Internal: Get all documents from collection
|
|
5006
5021
|
* Optionally filter out soft-deleted documents
|
|
5022
|
+
* Supports pagination with limit and startAfter options
|
|
5007
5023
|
*/
|
|
5008
|
-
async getDocs(collectionPath, includeDeleted = false) {
|
|
5009
|
-
const { getDocs, collection, query, where } = await this.loadFirestore();
|
|
5024
|
+
async getDocs(collectionPath, includeDeleted = false, options) {
|
|
5025
|
+
const { getDocs, collection, query, where, limit, startAfter } = await this.loadFirestore();
|
|
5010
5026
|
const colRef = collection(this.db, collectionPath);
|
|
5011
|
-
|
|
5012
|
-
|
|
5013
|
-
|
|
5014
|
-
|
|
5015
|
-
else {
|
|
5027
|
+
// Build query constraints
|
|
5028
|
+
const constraints = [];
|
|
5029
|
+
// Add soft-delete filter if needed
|
|
5030
|
+
if (!includeDeleted) {
|
|
5016
5031
|
// Filter out soft-deleted documents
|
|
5017
5032
|
// Use '!=' to include documents without _deleted field (new documents)
|
|
5018
5033
|
// This will return documents where _deleted is missing, null, undefined, or false
|
|
5019
|
-
|
|
5034
|
+
constraints.push(where('_deleted', '!=', true));
|
|
5035
|
+
}
|
|
5036
|
+
// Add pagination options if provided
|
|
5037
|
+
if (options?.startAfter) {
|
|
5038
|
+
constraints.push(startAfter(options.startAfter));
|
|
5039
|
+
}
|
|
5040
|
+
if (options?.limit) {
|
|
5041
|
+
constraints.push(limit(options.limit));
|
|
5042
|
+
}
|
|
5043
|
+
// Execute query
|
|
5044
|
+
if (constraints.length > 0) {
|
|
5045
|
+
const q = query(colRef, ...constraints);
|
|
5020
5046
|
return getDocs(q);
|
|
5021
5047
|
}
|
|
5048
|
+
else {
|
|
5049
|
+
// No constraints, return all documents
|
|
5050
|
+
return getDocs(colRef);
|
|
5051
|
+
}
|
|
5022
5052
|
}
|
|
5023
5053
|
/**
|
|
5024
5054
|
* Internal: Get collection reference
|
|
@@ -5047,7 +5077,8 @@ class FirestoreHelper {
|
|
|
5047
5077
|
query: firestore.query,
|
|
5048
5078
|
where: firestore.where,
|
|
5049
5079
|
orderBy: firestore.orderBy,
|
|
5050
|
-
limit: firestore.limit
|
|
5080
|
+
limit: firestore.limit,
|
|
5081
|
+
startAfter: firestore.startAfter
|
|
5051
5082
|
};
|
|
5052
5083
|
}
|
|
5053
5084
|
}
|