@seaverse/data-service-sdk 0.5.2 → 0.7.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 +188 -34
- package/dist/browser.js +646 -8
- package/dist/browser.js.map +1 -1
- package/dist/browser.umd.js +766 -11
- package/dist/browser.umd.js.map +1 -1
- package/dist/index.cjs +763 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +476 -6
- package/dist/index.js +645 -8
- package/dist/index.js.map +1 -1
- package/package.json +10 -9
package/dist/browser.umd.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
(function (global, factory) {
|
|
2
|
-
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
|
|
3
|
-
typeof define === 'function' && define.amd ? define(['exports'], factory) :
|
|
4
|
-
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.SeaVerseDataService = {}));
|
|
5
|
-
})(this, (function (exports) { 'use strict';
|
|
2
|
+
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('firebase/firestore')) :
|
|
3
|
+
typeof define === 'function' && define.amd ? define(['exports', 'firebase/firestore'], factory) :
|
|
4
|
+
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.SeaVerseDataService = {}, global.firestore));
|
|
5
|
+
})(this, (function (exports, firestore) { 'use strict';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Create a bound version of a function with a specified `this` context
|
|
@@ -4179,6 +4179,628 @@
|
|
|
4179
4179
|
}
|
|
4180
4180
|
}
|
|
4181
4181
|
|
|
4182
|
+
/**
|
|
4183
|
+
* Firestore Path Helper Functions
|
|
4184
|
+
*
|
|
4185
|
+
* These helper functions generate correct Firestore paths that match
|
|
4186
|
+
* the security rules. Use these instead of manually constructing paths
|
|
4187
|
+
* to avoid permission-denied errors.
|
|
4188
|
+
*
|
|
4189
|
+
* 🚨 IMPORTANT: These paths are designed to work with SeaVerse Firestore Rules
|
|
4190
|
+
*
|
|
4191
|
+
* Permission Levels:
|
|
4192
|
+
* - publicRead: Read-only for all users, write for admins only
|
|
4193
|
+
* - publicData: Read/write for all authenticated users
|
|
4194
|
+
* - userData: Read/write only for the data owner
|
|
4195
|
+
*/
|
|
4196
|
+
/**
|
|
4197
|
+
* Generate path for publicRead data (read-only for users, write for admins)
|
|
4198
|
+
*
|
|
4199
|
+
* @param appId - Your application ID
|
|
4200
|
+
* @param collection - Collection name (e.g., 'announcements', 'config')
|
|
4201
|
+
* @returns Firestore path string
|
|
4202
|
+
*
|
|
4203
|
+
* @example
|
|
4204
|
+
* ```typescript
|
|
4205
|
+
* // Read system announcements
|
|
4206
|
+
* const path = getPublicReadPath('my-app', 'announcements');
|
|
4207
|
+
* // Returns: 'appData/my-app/publicRead/announcements'
|
|
4208
|
+
*
|
|
4209
|
+
* const snapshot = await getDocs(collection(db, path));
|
|
4210
|
+
* ```
|
|
4211
|
+
*/
|
|
4212
|
+
function getPublicReadPath(appId, collectionName) {
|
|
4213
|
+
validateSegment('appId', appId);
|
|
4214
|
+
validateSegment('collectionName', collectionName);
|
|
4215
|
+
return `appData/${appId}/publicRead/${collectionName}`;
|
|
4216
|
+
}
|
|
4217
|
+
/**
|
|
4218
|
+
* Generate path for publicData (read/write for all authenticated users)
|
|
4219
|
+
*
|
|
4220
|
+
* @param appId - Your application ID
|
|
4221
|
+
* @param collection - Collection name (e.g., 'posts', 'comments')
|
|
4222
|
+
* @returns Firestore path string
|
|
4223
|
+
*
|
|
4224
|
+
* @example
|
|
4225
|
+
* ```typescript
|
|
4226
|
+
* // Write a public post
|
|
4227
|
+
* const path = getPublicDataPath('my-app', 'posts');
|
|
4228
|
+
* // Returns: 'appData/my-app/publicData/posts'
|
|
4229
|
+
*
|
|
4230
|
+
* await addDoc(collection(db, path), {
|
|
4231
|
+
* _appId: appId,
|
|
4232
|
+
* _createdAt: serverTimestamp(),
|
|
4233
|
+
* _createdBy: userId,
|
|
4234
|
+
* title: 'My Post'
|
|
4235
|
+
* });
|
|
4236
|
+
* ```
|
|
4237
|
+
*/
|
|
4238
|
+
function getPublicDataPath(appId, collectionName) {
|
|
4239
|
+
validateSegment('appId', appId);
|
|
4240
|
+
validateSegment('collectionName', collectionName);
|
|
4241
|
+
return `appData/${appId}/publicData/${collectionName}`;
|
|
4242
|
+
}
|
|
4243
|
+
/**
|
|
4244
|
+
* Generate path for userData (private, read/write only by owner)
|
|
4245
|
+
*
|
|
4246
|
+
* @param appId - Your application ID
|
|
4247
|
+
* @param userId - User ID who owns this data
|
|
4248
|
+
* @param collection - Collection name (e.g., 'notes', 'settings')
|
|
4249
|
+
* @returns Firestore path string
|
|
4250
|
+
*
|
|
4251
|
+
* @example
|
|
4252
|
+
* ```typescript
|
|
4253
|
+
* // Write private user notes
|
|
4254
|
+
* const path = getUserDataPath('my-app', 'user-123', 'notes');
|
|
4255
|
+
* // Returns: 'appData/my-app/userData/user-123/notes'
|
|
4256
|
+
*
|
|
4257
|
+
* await addDoc(collection(db, path), {
|
|
4258
|
+
* _appId: appId,
|
|
4259
|
+
* _createdAt: serverTimestamp(),
|
|
4260
|
+
* _createdBy: userId,
|
|
4261
|
+
* content: 'Private note'
|
|
4262
|
+
* });
|
|
4263
|
+
* ```
|
|
4264
|
+
*/
|
|
4265
|
+
function getUserDataPath(appId, userId, collectionName) {
|
|
4266
|
+
validateSegment('appId', appId);
|
|
4267
|
+
validateSegment('userId', userId);
|
|
4268
|
+
validateSegment('collectionName', collectionName);
|
|
4269
|
+
return `appData/${appId}/userData/${userId}/${collectionName}`;
|
|
4270
|
+
}
|
|
4271
|
+
/**
|
|
4272
|
+
* Generate path for a specific document in publicRead
|
|
4273
|
+
*
|
|
4274
|
+
* @param appId - Your application ID
|
|
4275
|
+
* @param collection - Collection name
|
|
4276
|
+
* @param docId - Document ID
|
|
4277
|
+
* @returns Firestore document path string
|
|
4278
|
+
*
|
|
4279
|
+
* @example
|
|
4280
|
+
* ```typescript
|
|
4281
|
+
* const path = getPublicReadDocPath('my-app', 'announcements', 'announcement-1');
|
|
4282
|
+
* // Returns: 'appData/my-app/publicRead/announcements/announcement-1'
|
|
4283
|
+
*
|
|
4284
|
+
* const docSnap = await getDoc(doc(db, path));
|
|
4285
|
+
* ```
|
|
4286
|
+
*/
|
|
4287
|
+
function getPublicReadDocPath(appId, collectionName, docId) {
|
|
4288
|
+
validateSegment('appId', appId);
|
|
4289
|
+
validateSegment('collectionName', collectionName);
|
|
4290
|
+
validateSegment('docId', docId);
|
|
4291
|
+
return `appData/${appId}/publicRead/${collectionName}/${docId}`;
|
|
4292
|
+
}
|
|
4293
|
+
/**
|
|
4294
|
+
* Generate path for a specific document in publicData
|
|
4295
|
+
*
|
|
4296
|
+
* @param appId - Your application ID
|
|
4297
|
+
* @param collection - Collection name
|
|
4298
|
+
* @param docId - Document ID
|
|
4299
|
+
* @returns Firestore document path string
|
|
4300
|
+
*
|
|
4301
|
+
* @example
|
|
4302
|
+
* ```typescript
|
|
4303
|
+
* const path = getPublicDataDocPath('my-app', 'posts', 'post-123');
|
|
4304
|
+
* // Returns: 'appData/my-app/publicData/posts/post-123'
|
|
4305
|
+
*
|
|
4306
|
+
* const docSnap = await getDoc(doc(db, path));
|
|
4307
|
+
* ```
|
|
4308
|
+
*/
|
|
4309
|
+
function getPublicDataDocPath(appId, collectionName, docId) {
|
|
4310
|
+
validateSegment('appId', appId);
|
|
4311
|
+
validateSegment('collectionName', collectionName);
|
|
4312
|
+
validateSegment('docId', docId);
|
|
4313
|
+
return `appData/${appId}/publicData/${collectionName}/${docId}`;
|
|
4314
|
+
}
|
|
4315
|
+
/**
|
|
4316
|
+
* Generate path for a specific document in userData
|
|
4317
|
+
*
|
|
4318
|
+
* @param appId - Your application ID
|
|
4319
|
+
* @param userId - User ID who owns this data
|
|
4320
|
+
* @param collection - Collection name
|
|
4321
|
+
* @param docId - Document ID
|
|
4322
|
+
* @returns Firestore document path string
|
|
4323
|
+
*
|
|
4324
|
+
* @example
|
|
4325
|
+
* ```typescript
|
|
4326
|
+
* const path = getUserDataDocPath('my-app', 'user-123', 'notes', 'note-456');
|
|
4327
|
+
* // Returns: 'appData/my-app/userData/user-123/notes/note-456'
|
|
4328
|
+
*
|
|
4329
|
+
* const docSnap = await getDoc(doc(db, path));
|
|
4330
|
+
* ```
|
|
4331
|
+
*/
|
|
4332
|
+
function getUserDataDocPath(appId, userId, collectionName, docId) {
|
|
4333
|
+
validateSegment('appId', appId);
|
|
4334
|
+
validateSegment('userId', userId);
|
|
4335
|
+
validateSegment('collectionName', collectionName);
|
|
4336
|
+
validateSegment('docId', docId);
|
|
4337
|
+
return `appData/${appId}/userData/${userId}/${collectionName}/${docId}`;
|
|
4338
|
+
}
|
|
4339
|
+
/**
|
|
4340
|
+
* Validate a path segment to ensure it doesn't contain invalid characters
|
|
4341
|
+
*
|
|
4342
|
+
* @param name - Parameter name for error messages
|
|
4343
|
+
* @param value - The segment value to validate
|
|
4344
|
+
* @throws Error if the segment is invalid
|
|
4345
|
+
*/
|
|
4346
|
+
function validateSegment(name, value) {
|
|
4347
|
+
if (!value || typeof value !== 'string') {
|
|
4348
|
+
throw new Error(`${name} must be a non-empty string`);
|
|
4349
|
+
}
|
|
4350
|
+
if (value.includes('/')) {
|
|
4351
|
+
throw new Error(`${name} cannot contain forward slashes (/). Got: "${value}"`);
|
|
4352
|
+
}
|
|
4353
|
+
if (value.trim() !== value) {
|
|
4354
|
+
throw new Error(`${name} cannot start or end with whitespace. Got: "${value}"`);
|
|
4355
|
+
}
|
|
4356
|
+
}
|
|
4357
|
+
/**
|
|
4358
|
+
* Path builder for advanced use cases
|
|
4359
|
+
* Provides a fluent interface for building Firestore paths
|
|
4360
|
+
*
|
|
4361
|
+
* @example
|
|
4362
|
+
* ```typescript
|
|
4363
|
+
* // Build a path step by step
|
|
4364
|
+
* const builder = new PathBuilder('my-app');
|
|
4365
|
+
* const path = builder.publicData('posts').build();
|
|
4366
|
+
* // Returns: 'appData/my-app/publicData/posts'
|
|
4367
|
+
*
|
|
4368
|
+
* // With document ID
|
|
4369
|
+
* const docPath = builder.publicData('posts').doc('post-123').build();
|
|
4370
|
+
* // Returns: 'appData/my-app/publicData/posts/post-123'
|
|
4371
|
+
* ```
|
|
4372
|
+
*/
|
|
4373
|
+
class PathBuilder {
|
|
4374
|
+
constructor(appId) {
|
|
4375
|
+
this.appId = appId;
|
|
4376
|
+
this.segments = ['appData'];
|
|
4377
|
+
validateSegment('appId', appId);
|
|
4378
|
+
this.segments.push(appId);
|
|
4379
|
+
}
|
|
4380
|
+
/**
|
|
4381
|
+
* Add publicRead collection to path
|
|
4382
|
+
*/
|
|
4383
|
+
publicRead(collectionName) {
|
|
4384
|
+
validateSegment('collectionName', collectionName);
|
|
4385
|
+
this.segments.push('publicRead', collectionName);
|
|
4386
|
+
return this;
|
|
4387
|
+
}
|
|
4388
|
+
/**
|
|
4389
|
+
* Add publicData collection to path
|
|
4390
|
+
*/
|
|
4391
|
+
publicData(collectionName) {
|
|
4392
|
+
validateSegment('collectionName', collectionName);
|
|
4393
|
+
this.segments.push('publicData', collectionName);
|
|
4394
|
+
return this;
|
|
4395
|
+
}
|
|
4396
|
+
/**
|
|
4397
|
+
* Add userData collection to path
|
|
4398
|
+
*/
|
|
4399
|
+
userData(userId, collectionName) {
|
|
4400
|
+
validateSegment('userId', userId);
|
|
4401
|
+
validateSegment('collectionName', collectionName);
|
|
4402
|
+
this.segments.push('userData', userId, collectionName);
|
|
4403
|
+
return this;
|
|
4404
|
+
}
|
|
4405
|
+
/**
|
|
4406
|
+
* Add document ID to path
|
|
4407
|
+
*/
|
|
4408
|
+
doc(docId) {
|
|
4409
|
+
validateSegment('docId', docId);
|
|
4410
|
+
this.segments.push(docId);
|
|
4411
|
+
return this;
|
|
4412
|
+
}
|
|
4413
|
+
/**
|
|
4414
|
+
* Build the final path string
|
|
4415
|
+
*/
|
|
4416
|
+
build() {
|
|
4417
|
+
return this.segments.join('/');
|
|
4418
|
+
}
|
|
4419
|
+
}
|
|
4420
|
+
/**
|
|
4421
|
+
* Common path patterns as constants for frequently used paths
|
|
4422
|
+
*/
|
|
4423
|
+
const PATH_PATTERNS = {
|
|
4424
|
+
/**
|
|
4425
|
+
* Base pattern for all SeaVerse data
|
|
4426
|
+
*/
|
|
4427
|
+
APP_DATA: 'appData',
|
|
4428
|
+
/**
|
|
4429
|
+
* Permission layers
|
|
4430
|
+
*/
|
|
4431
|
+
PUBLIC_READ: 'publicRead',
|
|
4432
|
+
PUBLIC_DATA: 'publicData',
|
|
4433
|
+
USER_DATA: 'userData',
|
|
4434
|
+
};
|
|
4435
|
+
|
|
4436
|
+
/**
|
|
4437
|
+
* Firestore Helper - LLM-Friendly Firestore Operations
|
|
4438
|
+
*
|
|
4439
|
+
* This helper class automatically handles required fields (_appId, _createdAt, _createdBy)
|
|
4440
|
+
* so LLM doesn't need to remember them. It provides a simple, high-level API.
|
|
4441
|
+
*
|
|
4442
|
+
* 🎯 LLM-FIRST DESIGN:
|
|
4443
|
+
* - No need to remember required fields
|
|
4444
|
+
* - No need to construct paths manually
|
|
4445
|
+
* - No need to import serverTimestamp
|
|
4446
|
+
* - One method does everything
|
|
4447
|
+
*/
|
|
4448
|
+
/**
|
|
4449
|
+
* Firestore operations helper with automatic metadata injection
|
|
4450
|
+
*
|
|
4451
|
+
* This class wraps Firestore operations and automatically adds required fields:
|
|
4452
|
+
* - _appId: Application ID (for data isolation)
|
|
4453
|
+
* - _createdAt: Server timestamp (for creation time)
|
|
4454
|
+
* - _createdBy: User ID (for ownership tracking)
|
|
4455
|
+
*
|
|
4456
|
+
* @example
|
|
4457
|
+
* ```typescript
|
|
4458
|
+
* const helper = new FirestoreHelper(db, appId, userId);
|
|
4459
|
+
*
|
|
4460
|
+
* // ✅ LLM-friendly: Just pass your data, required fields auto-injected
|
|
4461
|
+
* await helper.addToPublicData('posts', {
|
|
4462
|
+
* title: 'My Post',
|
|
4463
|
+
* content: 'Hello world'
|
|
4464
|
+
* });
|
|
4465
|
+
*
|
|
4466
|
+
* // ❌ OLD WAY: LLM needs to remember 3 required fields
|
|
4467
|
+
* await addDoc(collection(db, path), {
|
|
4468
|
+
* _appId: appId,
|
|
4469
|
+
* _createdAt: serverTimestamp(),
|
|
4470
|
+
* _createdBy: userId,
|
|
4471
|
+
* title: 'My Post',
|
|
4472
|
+
* content: 'Hello world'
|
|
4473
|
+
* });
|
|
4474
|
+
* ```
|
|
4475
|
+
*/
|
|
4476
|
+
class FirestoreHelper {
|
|
4477
|
+
constructor(db, appId, userId) {
|
|
4478
|
+
this.db = db;
|
|
4479
|
+
this.appId = appId;
|
|
4480
|
+
this.userId = userId;
|
|
4481
|
+
}
|
|
4482
|
+
/**
|
|
4483
|
+
* Add document to publicData (shared, read/write for all users)
|
|
4484
|
+
*
|
|
4485
|
+
* Automatically injects: _appId, _createdAt, _createdBy
|
|
4486
|
+
*
|
|
4487
|
+
* @param collectionName - Collection name (e.g., 'posts', 'comments')
|
|
4488
|
+
* @param data - Your business data
|
|
4489
|
+
* @returns Document reference
|
|
4490
|
+
*
|
|
4491
|
+
* @example
|
|
4492
|
+
* ```typescript
|
|
4493
|
+
* // ✅ LLM-friendly: Simple and clean
|
|
4494
|
+
* const docRef = await helper.addToPublicData('posts', {
|
|
4495
|
+
* title: 'My First Post',
|
|
4496
|
+
* content: 'Hello world'
|
|
4497
|
+
* });
|
|
4498
|
+
* console.log('Created post:', docRef.id);
|
|
4499
|
+
* ```
|
|
4500
|
+
*/
|
|
4501
|
+
async addToPublicData(collectionName, data) {
|
|
4502
|
+
const path = getPublicDataPath(this.appId, collectionName);
|
|
4503
|
+
return this.addDocWithMeta(path, data);
|
|
4504
|
+
}
|
|
4505
|
+
/**
|
|
4506
|
+
* Add document to userData (private, only owner can read/write)
|
|
4507
|
+
*
|
|
4508
|
+
* Automatically injects: _appId, _createdAt, _createdBy
|
|
4509
|
+
*
|
|
4510
|
+
* @param collectionName - Collection name (e.g., 'notes', 'settings')
|
|
4511
|
+
* @param data - Your business data
|
|
4512
|
+
* @returns Document reference
|
|
4513
|
+
*
|
|
4514
|
+
* @example
|
|
4515
|
+
* ```typescript
|
|
4516
|
+
* // ✅ LLM-friendly: Private data, auto-isolated
|
|
4517
|
+
* await helper.addToUserData('notes', {
|
|
4518
|
+
* title: 'Private Note',
|
|
4519
|
+
* content: 'Only I can see this'
|
|
4520
|
+
* });
|
|
4521
|
+
* ```
|
|
4522
|
+
*/
|
|
4523
|
+
async addToUserData(collectionName, data) {
|
|
4524
|
+
const path = getUserDataPath(this.appId, this.userId, collectionName);
|
|
4525
|
+
return this.addDocWithMeta(path, data);
|
|
4526
|
+
}
|
|
4527
|
+
/**
|
|
4528
|
+
* Get all documents from publicData collection
|
|
4529
|
+
*
|
|
4530
|
+
* @param collectionName - Collection name
|
|
4531
|
+
* @returns QuerySnapshot with documents
|
|
4532
|
+
*
|
|
4533
|
+
* @example
|
|
4534
|
+
* ```typescript
|
|
4535
|
+
* const snapshot = await helper.getPublicData('posts');
|
|
4536
|
+
* snapshot.forEach(doc => {
|
|
4537
|
+
* console.log(doc.id, doc.data());
|
|
4538
|
+
* });
|
|
4539
|
+
* ```
|
|
4540
|
+
*/
|
|
4541
|
+
async getPublicData(collectionName) {
|
|
4542
|
+
const path = getPublicDataPath(this.appId, collectionName);
|
|
4543
|
+
return this.getDocs(path);
|
|
4544
|
+
}
|
|
4545
|
+
/**
|
|
4546
|
+
* Get all documents from userData collection (user's private data)
|
|
4547
|
+
*
|
|
4548
|
+
* @param collectionName - Collection name
|
|
4549
|
+
* @returns QuerySnapshot with documents
|
|
4550
|
+
*
|
|
4551
|
+
* @example
|
|
4552
|
+
* ```typescript
|
|
4553
|
+
* const snapshot = await helper.getUserData('notes');
|
|
4554
|
+
* snapshot.forEach(doc => {
|
|
4555
|
+
* console.log('My note:', doc.data());
|
|
4556
|
+
* });
|
|
4557
|
+
* ```
|
|
4558
|
+
*/
|
|
4559
|
+
async getUserData(collectionName) {
|
|
4560
|
+
const path = getUserDataPath(this.appId, this.userId, collectionName);
|
|
4561
|
+
return this.getDocs(path);
|
|
4562
|
+
}
|
|
4563
|
+
/**
|
|
4564
|
+
* Get all documents from publicRead collection (read-only for users)
|
|
4565
|
+
*
|
|
4566
|
+
* @param collectionName - Collection name
|
|
4567
|
+
* @returns QuerySnapshot with documents
|
|
4568
|
+
*
|
|
4569
|
+
* @example
|
|
4570
|
+
* ```typescript
|
|
4571
|
+
* const configs = await helper.getPublicRead('config');
|
|
4572
|
+
* ```
|
|
4573
|
+
*/
|
|
4574
|
+
async getPublicRead(collectionName) {
|
|
4575
|
+
const path = getPublicReadPath(this.appId, collectionName);
|
|
4576
|
+
return this.getDocs(path);
|
|
4577
|
+
}
|
|
4578
|
+
/**
|
|
4579
|
+
* Get collection reference for publicData
|
|
4580
|
+
* Use this for advanced queries with where(), orderBy(), limit()
|
|
4581
|
+
*
|
|
4582
|
+
* @param collectionName - Collection name
|
|
4583
|
+
* @returns Collection reference
|
|
4584
|
+
*
|
|
4585
|
+
* @example
|
|
4586
|
+
* ```typescript
|
|
4587
|
+
* import { query, where, orderBy } from 'firebase/firestore';
|
|
4588
|
+
*
|
|
4589
|
+
* const postsRef = helper.publicDataCollection('posts');
|
|
4590
|
+
* const q = query(
|
|
4591
|
+
* postsRef,
|
|
4592
|
+
* where('_createdBy', '==', userId),
|
|
4593
|
+
* orderBy('_createdAt', 'desc')
|
|
4594
|
+
* );
|
|
4595
|
+
* const snapshot = await getDocs(q);
|
|
4596
|
+
* ```
|
|
4597
|
+
*/
|
|
4598
|
+
publicDataCollection(collectionName) {
|
|
4599
|
+
const path = getPublicDataPath(this.appId, collectionName);
|
|
4600
|
+
return this.getCollection(path);
|
|
4601
|
+
}
|
|
4602
|
+
/**
|
|
4603
|
+
* Get collection reference for userData
|
|
4604
|
+
*
|
|
4605
|
+
* @param collectionName - Collection name
|
|
4606
|
+
* @returns Collection reference
|
|
4607
|
+
*/
|
|
4608
|
+
userDataCollection(collectionName) {
|
|
4609
|
+
const path = getUserDataPath(this.appId, this.userId, collectionName);
|
|
4610
|
+
return this.getCollection(path);
|
|
4611
|
+
}
|
|
4612
|
+
/**
|
|
4613
|
+
* Get collection reference for publicRead
|
|
4614
|
+
*
|
|
4615
|
+
* @param collectionName - Collection name
|
|
4616
|
+
* @returns Collection reference
|
|
4617
|
+
*/
|
|
4618
|
+
publicReadCollection(collectionName) {
|
|
4619
|
+
const path = getPublicReadPath(this.appId, collectionName);
|
|
4620
|
+
return this.getCollection(path);
|
|
4621
|
+
}
|
|
4622
|
+
/**
|
|
4623
|
+
* Update document with automatic metadata update
|
|
4624
|
+
*
|
|
4625
|
+
* Automatically sets: _updatedAt, _updatedBy
|
|
4626
|
+
*
|
|
4627
|
+
* @param collectionPath - Full collection path
|
|
4628
|
+
* @param docId - Document ID
|
|
4629
|
+
* @param data - Data to update
|
|
4630
|
+
*
|
|
4631
|
+
* @example
|
|
4632
|
+
* ```typescript
|
|
4633
|
+
* await helper.updateDoc(
|
|
4634
|
+
* getPublicDataPath(appId, 'posts'),
|
|
4635
|
+
* 'post-123',
|
|
4636
|
+
* { title: 'Updated Title' }
|
|
4637
|
+
* );
|
|
4638
|
+
* ```
|
|
4639
|
+
*/
|
|
4640
|
+
async updateDoc(collectionPath, docId, data) {
|
|
4641
|
+
const { updateDoc, doc, serverTimestamp } = await this.loadFirestore();
|
|
4642
|
+
const docRef = doc(this.db, collectionPath, docId);
|
|
4643
|
+
return updateDoc(docRef, {
|
|
4644
|
+
...data,
|
|
4645
|
+
_updatedAt: serverTimestamp(),
|
|
4646
|
+
_updatedBy: this.userId
|
|
4647
|
+
});
|
|
4648
|
+
}
|
|
4649
|
+
/**
|
|
4650
|
+
* Delete document
|
|
4651
|
+
*
|
|
4652
|
+
* @param collectionPath - Full collection path
|
|
4653
|
+
* @param docId - Document ID
|
|
4654
|
+
*/
|
|
4655
|
+
async deleteDoc(collectionPath, docId) {
|
|
4656
|
+
const { deleteDoc, doc } = await this.loadFirestore();
|
|
4657
|
+
const docRef = doc(this.db, collectionPath, docId);
|
|
4658
|
+
return deleteDoc(docRef);
|
|
4659
|
+
}
|
|
4660
|
+
/**
|
|
4661
|
+
* Get single document by ID
|
|
4662
|
+
*
|
|
4663
|
+
* @param collectionPath - Full collection path
|
|
4664
|
+
* @param docId - Document ID
|
|
4665
|
+
*
|
|
4666
|
+
* @example
|
|
4667
|
+
* ```typescript
|
|
4668
|
+
* const docSnap = await helper.getDoc(
|
|
4669
|
+
* getPublicDataPath(appId, 'posts'),
|
|
4670
|
+
* 'post-123'
|
|
4671
|
+
* );
|
|
4672
|
+
* if (docSnap.exists()) {
|
|
4673
|
+
* console.log(docSnap.data());
|
|
4674
|
+
* }
|
|
4675
|
+
* ```
|
|
4676
|
+
*/
|
|
4677
|
+
async getDoc(collectionPath, docId) {
|
|
4678
|
+
const { getDoc, doc } = await this.loadFirestore();
|
|
4679
|
+
const docRef = doc(this.db, collectionPath, docId);
|
|
4680
|
+
return getDoc(docRef);
|
|
4681
|
+
}
|
|
4682
|
+
// ============================================================================
|
|
4683
|
+
// Private Helper Methods
|
|
4684
|
+
// ============================================================================
|
|
4685
|
+
/**
|
|
4686
|
+
* Internal: Add document with metadata injection
|
|
4687
|
+
*/
|
|
4688
|
+
async addDocWithMeta(collectionPath, data) {
|
|
4689
|
+
const { addDoc, collection, serverTimestamp } = await this.loadFirestore();
|
|
4690
|
+
const colRef = collection(this.db, collectionPath);
|
|
4691
|
+
return addDoc(colRef, {
|
|
4692
|
+
_appId: this.appId,
|
|
4693
|
+
_createdAt: serverTimestamp(),
|
|
4694
|
+
_createdBy: this.userId,
|
|
4695
|
+
...data
|
|
4696
|
+
});
|
|
4697
|
+
}
|
|
4698
|
+
/**
|
|
4699
|
+
* Internal: Get all documents from collection
|
|
4700
|
+
*/
|
|
4701
|
+
async getDocs(collectionPath) {
|
|
4702
|
+
const { getDocs, collection } = await this.loadFirestore();
|
|
4703
|
+
const colRef = collection(this.db, collectionPath);
|
|
4704
|
+
return getDocs(colRef);
|
|
4705
|
+
}
|
|
4706
|
+
/**
|
|
4707
|
+
* Internal: Get collection reference
|
|
4708
|
+
*/
|
|
4709
|
+
getCollection(collectionPath) {
|
|
4710
|
+
// Note: This is sync, so we can't use dynamic import
|
|
4711
|
+
// We assume firebase/firestore is already loaded by initializeWithToken
|
|
4712
|
+
const { collection } = require('firebase/firestore');
|
|
4713
|
+
return collection(this.db, collectionPath);
|
|
4714
|
+
}
|
|
4715
|
+
/**
|
|
4716
|
+
* Internal: Lazy load Firebase Firestore functions
|
|
4717
|
+
*/
|
|
4718
|
+
async loadFirestore() {
|
|
4719
|
+
const firestore = await import('firebase/firestore');
|
|
4720
|
+
return {
|
|
4721
|
+
collection: firestore.collection,
|
|
4722
|
+
doc: firestore.doc,
|
|
4723
|
+
addDoc: firestore.addDoc,
|
|
4724
|
+
setDoc: firestore.setDoc,
|
|
4725
|
+
getDoc: firestore.getDoc,
|
|
4726
|
+
getDocs: firestore.getDocs,
|
|
4727
|
+
updateDoc: firestore.updateDoc,
|
|
4728
|
+
deleteDoc: firestore.deleteDoc,
|
|
4729
|
+
serverTimestamp: firestore.serverTimestamp,
|
|
4730
|
+
query: firestore.query,
|
|
4731
|
+
where: firestore.where,
|
|
4732
|
+
orderBy: firestore.orderBy,
|
|
4733
|
+
limit: firestore.limit
|
|
4734
|
+
};
|
|
4735
|
+
}
|
|
4736
|
+
}
|
|
4737
|
+
/**
|
|
4738
|
+
* Standalone helper function: Add document with automatic metadata injection
|
|
4739
|
+
*
|
|
4740
|
+
* Use this if you don't want to create a FirestoreHelper instance.
|
|
4741
|
+
*
|
|
4742
|
+
* @param db - Firestore instance
|
|
4743
|
+
* @param collectionPath - Full collection path
|
|
4744
|
+
* @param appId - Application ID
|
|
4745
|
+
* @param userId - User ID
|
|
4746
|
+
* @param data - Your business data
|
|
4747
|
+
* @returns Document reference
|
|
4748
|
+
*
|
|
4749
|
+
* @example
|
|
4750
|
+
* ```typescript
|
|
4751
|
+
* import { addDocWithMeta, getPublicDataPath } from '@seaverse/data-service-sdk';
|
|
4752
|
+
*
|
|
4753
|
+
* const docRef = await addDocWithMeta(
|
|
4754
|
+
* db,
|
|
4755
|
+
* getPublicDataPath(appId, 'posts'),
|
|
4756
|
+
* appId,
|
|
4757
|
+
* userId,
|
|
4758
|
+
* { title: 'Post', content: 'Hello' }
|
|
4759
|
+
* );
|
|
4760
|
+
* ```
|
|
4761
|
+
*/
|
|
4762
|
+
async function addDocWithMeta(db, collectionPath, appId, userId, data) {
|
|
4763
|
+
const { addDoc, collection, serverTimestamp } = await import('firebase/firestore');
|
|
4764
|
+
const colRef = collection(db, collectionPath);
|
|
4765
|
+
return addDoc(colRef, {
|
|
4766
|
+
_appId: appId,
|
|
4767
|
+
_createdAt: serverTimestamp(),
|
|
4768
|
+
_createdBy: userId,
|
|
4769
|
+
...data
|
|
4770
|
+
});
|
|
4771
|
+
}
|
|
4772
|
+
/**
|
|
4773
|
+
* Standalone helper function: Update document with automatic metadata
|
|
4774
|
+
*
|
|
4775
|
+
* @param db - Firestore instance
|
|
4776
|
+
* @param collectionPath - Full collection path
|
|
4777
|
+
* @param docId - Document ID
|
|
4778
|
+
* @param userId - User ID (for _updatedBy field)
|
|
4779
|
+
* @param data - Data to update
|
|
4780
|
+
*
|
|
4781
|
+
* @example
|
|
4782
|
+
* ```typescript
|
|
4783
|
+
* import { updateDocWithMeta, getPublicDataPath } from '@seaverse/data-service-sdk';
|
|
4784
|
+
*
|
|
4785
|
+
* await updateDocWithMeta(
|
|
4786
|
+
* db,
|
|
4787
|
+
* getPublicDataPath(appId, 'posts'),
|
|
4788
|
+
* 'post-123',
|
|
4789
|
+
* userId,
|
|
4790
|
+
* { title: 'Updated Title' }
|
|
4791
|
+
* );
|
|
4792
|
+
* ```
|
|
4793
|
+
*/
|
|
4794
|
+
async function updateDocWithMeta(db, collectionPath, docId, userId, data) {
|
|
4795
|
+
const { updateDoc, doc, serverTimestamp } = await import('firebase/firestore');
|
|
4796
|
+
const docRef = doc(db, collectionPath, docId);
|
|
4797
|
+
return updateDoc(docRef, {
|
|
4798
|
+
...data,
|
|
4799
|
+
_updatedAt: serverTimestamp(),
|
|
4800
|
+
_updatedBy: userId
|
|
4801
|
+
});
|
|
4802
|
+
}
|
|
4803
|
+
|
|
4182
4804
|
/**
|
|
4183
4805
|
* Create Firebase configuration from Firestore token response
|
|
4184
4806
|
*
|
|
@@ -4212,23 +4834,32 @@
|
|
|
4212
4834
|
* 1. Creates Firebase config from token response
|
|
4213
4835
|
* 2. Initializes Firebase app
|
|
4214
4836
|
* 3. Signs in with the custom token
|
|
4215
|
-
* 4.
|
|
4837
|
+
* 4. Creates FirestoreHelper for LLM-friendly operations
|
|
4838
|
+
* 5. Returns authenticated Firebase instances
|
|
4216
4839
|
*
|
|
4217
4840
|
* IMPORTANT: This function requires Firebase SDK to be installed separately:
|
|
4218
4841
|
* npm install firebase
|
|
4219
4842
|
*
|
|
4843
|
+
* 🎯 LLM RECOMMENDED: Use the `helper` object for simplified operations
|
|
4844
|
+
*
|
|
4220
4845
|
* @param tokenResponse - The Firestore token response from SDK
|
|
4221
|
-
* @returns Object containing initialized Firebase
|
|
4846
|
+
* @returns Object containing initialized Firebase instances and LLM-friendly helper
|
|
4222
4847
|
*
|
|
4223
4848
|
* @example
|
|
4224
4849
|
* ```typescript
|
|
4225
4850
|
* import { initializeWithToken } from '@seaverse/data-service-sdk';
|
|
4226
4851
|
*
|
|
4227
4852
|
* const tokenResponse = await client.generateGuestFirestoreToken({ app_id: 'my-app' });
|
|
4228
|
-
* const {
|
|
4853
|
+
* const { db, userId, appId, helper } = await initializeWithToken(tokenResponse);
|
|
4229
4854
|
*
|
|
4230
|
-
* //
|
|
4231
|
-
*
|
|
4855
|
+
* // ✅ LLM-FRIENDLY: Use helper (automatic required fields)
|
|
4856
|
+
* await helper.addToPublicData('posts', {
|
|
4857
|
+
* title: 'My Post',
|
|
4858
|
+
* content: 'Hello'
|
|
4859
|
+
* });
|
|
4860
|
+
*
|
|
4861
|
+
* // ❌ OLD WAY: Manual (need to remember required fields)
|
|
4862
|
+
* // await addDoc(collection(db, path), { _appId, _createdAt, _createdBy, ...data });
|
|
4232
4863
|
* ```
|
|
4233
4864
|
*/
|
|
4234
4865
|
async function initializeWithToken(tokenResponse) {
|
|
@@ -4260,21 +4891,145 @@
|
|
|
4260
4891
|
// Get Firestore instance with correct database ID
|
|
4261
4892
|
// IMPORTANT: Must specify database_id, not just use default!
|
|
4262
4893
|
const db = getFirestore(app, tokenResponse.database_id);
|
|
4894
|
+
const userId = tokenResponse.user_id;
|
|
4895
|
+
const appId = tokenResponse.app_id || '';
|
|
4896
|
+
// Create LLM-friendly helper
|
|
4897
|
+
const helper = new FirestoreHelper(db, appId, userId);
|
|
4263
4898
|
return {
|
|
4264
4899
|
app,
|
|
4265
4900
|
auth,
|
|
4266
4901
|
db,
|
|
4267
|
-
userId
|
|
4268
|
-
appId
|
|
4902
|
+
userId,
|
|
4903
|
+
appId,
|
|
4904
|
+
helper,
|
|
4269
4905
|
};
|
|
4270
4906
|
}
|
|
4271
4907
|
|
|
4908
|
+
Object.defineProperty(exports, "addDoc", {
|
|
4909
|
+
enumerable: true,
|
|
4910
|
+
get: function () { return firestore.addDoc; }
|
|
4911
|
+
});
|
|
4912
|
+
Object.defineProperty(exports, "arrayRemove", {
|
|
4913
|
+
enumerable: true,
|
|
4914
|
+
get: function () { return firestore.arrayRemove; }
|
|
4915
|
+
});
|
|
4916
|
+
Object.defineProperty(exports, "arrayUnion", {
|
|
4917
|
+
enumerable: true,
|
|
4918
|
+
get: function () { return firestore.arrayUnion; }
|
|
4919
|
+
});
|
|
4920
|
+
Object.defineProperty(exports, "collection", {
|
|
4921
|
+
enumerable: true,
|
|
4922
|
+
get: function () { return firestore.collection; }
|
|
4923
|
+
});
|
|
4924
|
+
Object.defineProperty(exports, "collectionGroup", {
|
|
4925
|
+
enumerable: true,
|
|
4926
|
+
get: function () { return firestore.collectionGroup; }
|
|
4927
|
+
});
|
|
4928
|
+
Object.defineProperty(exports, "deleteDoc", {
|
|
4929
|
+
enumerable: true,
|
|
4930
|
+
get: function () { return firestore.deleteDoc; }
|
|
4931
|
+
});
|
|
4932
|
+
Object.defineProperty(exports, "deleteField", {
|
|
4933
|
+
enumerable: true,
|
|
4934
|
+
get: function () { return firestore.deleteField; }
|
|
4935
|
+
});
|
|
4936
|
+
Object.defineProperty(exports, "doc", {
|
|
4937
|
+
enumerable: true,
|
|
4938
|
+
get: function () { return firestore.doc; }
|
|
4939
|
+
});
|
|
4940
|
+
Object.defineProperty(exports, "endAt", {
|
|
4941
|
+
enumerable: true,
|
|
4942
|
+
get: function () { return firestore.endAt; }
|
|
4943
|
+
});
|
|
4944
|
+
Object.defineProperty(exports, "endBefore", {
|
|
4945
|
+
enumerable: true,
|
|
4946
|
+
get: function () { return firestore.endBefore; }
|
|
4947
|
+
});
|
|
4948
|
+
Object.defineProperty(exports, "getDoc", {
|
|
4949
|
+
enumerable: true,
|
|
4950
|
+
get: function () { return firestore.getDoc; }
|
|
4951
|
+
});
|
|
4952
|
+
Object.defineProperty(exports, "getDocs", {
|
|
4953
|
+
enumerable: true,
|
|
4954
|
+
get: function () { return firestore.getDocs; }
|
|
4955
|
+
});
|
|
4956
|
+
Object.defineProperty(exports, "getFirestore", {
|
|
4957
|
+
enumerable: true,
|
|
4958
|
+
get: function () { return firestore.getFirestore; }
|
|
4959
|
+
});
|
|
4960
|
+
Object.defineProperty(exports, "increment", {
|
|
4961
|
+
enumerable: true,
|
|
4962
|
+
get: function () { return firestore.increment; }
|
|
4963
|
+
});
|
|
4964
|
+
Object.defineProperty(exports, "limit", {
|
|
4965
|
+
enumerable: true,
|
|
4966
|
+
get: function () { return firestore.limit; }
|
|
4967
|
+
});
|
|
4968
|
+
Object.defineProperty(exports, "limitToLast", {
|
|
4969
|
+
enumerable: true,
|
|
4970
|
+
get: function () { return firestore.limitToLast; }
|
|
4971
|
+
});
|
|
4972
|
+
Object.defineProperty(exports, "onSnapshot", {
|
|
4973
|
+
enumerable: true,
|
|
4974
|
+
get: function () { return firestore.onSnapshot; }
|
|
4975
|
+
});
|
|
4976
|
+
Object.defineProperty(exports, "orderBy", {
|
|
4977
|
+
enumerable: true,
|
|
4978
|
+
get: function () { return firestore.orderBy; }
|
|
4979
|
+
});
|
|
4980
|
+
Object.defineProperty(exports, "query", {
|
|
4981
|
+
enumerable: true,
|
|
4982
|
+
get: function () { return firestore.query; }
|
|
4983
|
+
});
|
|
4984
|
+
Object.defineProperty(exports, "runTransaction", {
|
|
4985
|
+
enumerable: true,
|
|
4986
|
+
get: function () { return firestore.runTransaction; }
|
|
4987
|
+
});
|
|
4988
|
+
Object.defineProperty(exports, "serverTimestamp", {
|
|
4989
|
+
enumerable: true,
|
|
4990
|
+
get: function () { return firestore.serverTimestamp; }
|
|
4991
|
+
});
|
|
4992
|
+
Object.defineProperty(exports, "setDoc", {
|
|
4993
|
+
enumerable: true,
|
|
4994
|
+
get: function () { return firestore.setDoc; }
|
|
4995
|
+
});
|
|
4996
|
+
Object.defineProperty(exports, "startAfter", {
|
|
4997
|
+
enumerable: true,
|
|
4998
|
+
get: function () { return firestore.startAfter; }
|
|
4999
|
+
});
|
|
5000
|
+
Object.defineProperty(exports, "startAt", {
|
|
5001
|
+
enumerable: true,
|
|
5002
|
+
get: function () { return firestore.startAt; }
|
|
5003
|
+
});
|
|
5004
|
+
Object.defineProperty(exports, "updateDoc", {
|
|
5005
|
+
enumerable: true,
|
|
5006
|
+
get: function () { return firestore.updateDoc; }
|
|
5007
|
+
});
|
|
5008
|
+
Object.defineProperty(exports, "where", {
|
|
5009
|
+
enumerable: true,
|
|
5010
|
+
get: function () { return firestore.where; }
|
|
5011
|
+
});
|
|
5012
|
+
Object.defineProperty(exports, "writeBatch", {
|
|
5013
|
+
enumerable: true,
|
|
5014
|
+
get: function () { return firestore.writeBatch; }
|
|
5015
|
+
});
|
|
4272
5016
|
exports.DEFAULT_BASE_URL = DEFAULT_BASE_URL;
|
|
4273
5017
|
exports.DEFAULT_TIMEOUT = DEFAULT_TIMEOUT;
|
|
4274
5018
|
exports.DataServiceClient = DataServiceClient;
|
|
4275
5019
|
exports.ENDPOINTS = ENDPOINTS;
|
|
5020
|
+
exports.FirestoreHelper = FirestoreHelper;
|
|
5021
|
+
exports.PATH_PATTERNS = PATH_PATTERNS;
|
|
5022
|
+
exports.PathBuilder = PathBuilder;
|
|
5023
|
+
exports.addDocWithMeta = addDocWithMeta;
|
|
4276
5024
|
exports.getFirebaseConfig = getFirebaseConfig;
|
|
5025
|
+
exports.getPublicDataDocPath = getPublicDataDocPath;
|
|
5026
|
+
exports.getPublicDataPath = getPublicDataPath;
|
|
5027
|
+
exports.getPublicReadDocPath = getPublicReadDocPath;
|
|
5028
|
+
exports.getPublicReadPath = getPublicReadPath;
|
|
5029
|
+
exports.getUserDataDocPath = getUserDataDocPath;
|
|
5030
|
+
exports.getUserDataPath = getUserDataPath;
|
|
4277
5031
|
exports.initializeWithToken = initializeWithToken;
|
|
5032
|
+
exports.updateDocWithMeta = updateDocWithMeta;
|
|
4278
5033
|
|
|
4279
5034
|
}));
|
|
4280
5035
|
//# sourceMappingURL=browser.umd.js.map
|