@seaverse/data-service-sdk 0.6.0 → 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/dist/browser.js CHANGED
@@ -1,3 +1,5 @@
1
+ export { addDoc, arrayRemove, arrayUnion, collection, collectionGroup, deleteDoc, deleteField, doc, endAt, endBefore, getDoc, getDocs, getFirestore, increment, limit, limitToLast, onSnapshot, orderBy, query, runTransaction, serverTimestamp, setDoc, startAfter, startAt, updateDoc, where, writeBatch } from 'firebase/firestore';
2
+
1
3
  /**
2
4
  * Create a bound version of a function with a specified `this` context
3
5
  *
@@ -4173,96 +4175,6 @@ class DataServiceClient {
4173
4175
  }
4174
4176
  }
4175
4177
 
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 with correct database ID
4255
- // IMPORTANT: Must specify database_id, not just use default!
4256
- const db = getFirestore(app, tokenResponse.database_id);
4257
- return {
4258
- app,
4259
- auth,
4260
- db,
4261
- userId: tokenResponse.user_id,
4262
- appId: tokenResponse.app_id || '',
4263
- };
4264
- }
4265
-
4266
4178
  /**
4267
4179
  * Firestore Path Helper Functions
4268
4180
  *
@@ -4517,5 +4429,477 @@ const PATH_PATTERNS = {
4517
4429
  USER_DATA: 'userData',
4518
4430
  };
4519
4431
 
4520
- export { DEFAULT_BASE_URL, DEFAULT_TIMEOUT, DataServiceClient, ENDPOINTS, PATH_PATTERNS, PathBuilder, getFirebaseConfig, getPublicDataDocPath, getPublicDataPath, getPublicReadDocPath, getPublicReadPath, getUserDataDocPath, getUserDataPath, initializeWithToken };
4432
+ /**
4433
+ * Firestore Helper - LLM-Friendly Firestore Operations
4434
+ *
4435
+ * This helper class automatically handles required fields (_appId, _createdAt, _createdBy)
4436
+ * so LLM doesn't need to remember them. It provides a simple, high-level API.
4437
+ *
4438
+ * 🎯 LLM-FIRST DESIGN:
4439
+ * - No need to remember required fields
4440
+ * - No need to construct paths manually
4441
+ * - No need to import serverTimestamp
4442
+ * - One method does everything
4443
+ */
4444
+ /**
4445
+ * Firestore operations helper with automatic metadata injection
4446
+ *
4447
+ * This class wraps Firestore operations and automatically adds required fields:
4448
+ * - _appId: Application ID (for data isolation)
4449
+ * - _createdAt: Server timestamp (for creation time)
4450
+ * - _createdBy: User ID (for ownership tracking)
4451
+ *
4452
+ * @example
4453
+ * ```typescript
4454
+ * const helper = new FirestoreHelper(db, appId, userId);
4455
+ *
4456
+ * // ✅ LLM-friendly: Just pass your data, required fields auto-injected
4457
+ * await helper.addToPublicData('posts', {
4458
+ * title: 'My Post',
4459
+ * content: 'Hello world'
4460
+ * });
4461
+ *
4462
+ * // ❌ OLD WAY: LLM needs to remember 3 required fields
4463
+ * await addDoc(collection(db, path), {
4464
+ * _appId: appId,
4465
+ * _createdAt: serverTimestamp(),
4466
+ * _createdBy: userId,
4467
+ * title: 'My Post',
4468
+ * content: 'Hello world'
4469
+ * });
4470
+ * ```
4471
+ */
4472
+ class FirestoreHelper {
4473
+ constructor(db, appId, userId) {
4474
+ this.db = db;
4475
+ this.appId = appId;
4476
+ this.userId = userId;
4477
+ }
4478
+ /**
4479
+ * Add document to publicData (shared, read/write for all users)
4480
+ *
4481
+ * Automatically injects: _appId, _createdAt, _createdBy
4482
+ *
4483
+ * @param collectionName - Collection name (e.g., 'posts', 'comments')
4484
+ * @param data - Your business data
4485
+ * @returns Document reference
4486
+ *
4487
+ * @example
4488
+ * ```typescript
4489
+ * // ✅ LLM-friendly: Simple and clean
4490
+ * const docRef = await helper.addToPublicData('posts', {
4491
+ * title: 'My First Post',
4492
+ * content: 'Hello world'
4493
+ * });
4494
+ * console.log('Created post:', docRef.id);
4495
+ * ```
4496
+ */
4497
+ async addToPublicData(collectionName, data) {
4498
+ const path = getPublicDataPath(this.appId, collectionName);
4499
+ return this.addDocWithMeta(path, data);
4500
+ }
4501
+ /**
4502
+ * Add document to userData (private, only owner can read/write)
4503
+ *
4504
+ * Automatically injects: _appId, _createdAt, _createdBy
4505
+ *
4506
+ * @param collectionName - Collection name (e.g., 'notes', 'settings')
4507
+ * @param data - Your business data
4508
+ * @returns Document reference
4509
+ *
4510
+ * @example
4511
+ * ```typescript
4512
+ * // ✅ LLM-friendly: Private data, auto-isolated
4513
+ * await helper.addToUserData('notes', {
4514
+ * title: 'Private Note',
4515
+ * content: 'Only I can see this'
4516
+ * });
4517
+ * ```
4518
+ */
4519
+ async addToUserData(collectionName, data) {
4520
+ const path = getUserDataPath(this.appId, this.userId, collectionName);
4521
+ return this.addDocWithMeta(path, data);
4522
+ }
4523
+ /**
4524
+ * Get all documents from publicData collection
4525
+ *
4526
+ * @param collectionName - Collection name
4527
+ * @returns QuerySnapshot with documents
4528
+ *
4529
+ * @example
4530
+ * ```typescript
4531
+ * const snapshot = await helper.getPublicData('posts');
4532
+ * snapshot.forEach(doc => {
4533
+ * console.log(doc.id, doc.data());
4534
+ * });
4535
+ * ```
4536
+ */
4537
+ async getPublicData(collectionName) {
4538
+ const path = getPublicDataPath(this.appId, collectionName);
4539
+ return this.getDocs(path);
4540
+ }
4541
+ /**
4542
+ * Get all documents from userData collection (user's private data)
4543
+ *
4544
+ * @param collectionName - Collection name
4545
+ * @returns QuerySnapshot with documents
4546
+ *
4547
+ * @example
4548
+ * ```typescript
4549
+ * const snapshot = await helper.getUserData('notes');
4550
+ * snapshot.forEach(doc => {
4551
+ * console.log('My note:', doc.data());
4552
+ * });
4553
+ * ```
4554
+ */
4555
+ async getUserData(collectionName) {
4556
+ const path = getUserDataPath(this.appId, this.userId, collectionName);
4557
+ return this.getDocs(path);
4558
+ }
4559
+ /**
4560
+ * Get all documents from publicRead collection (read-only for users)
4561
+ *
4562
+ * @param collectionName - Collection name
4563
+ * @returns QuerySnapshot with documents
4564
+ *
4565
+ * @example
4566
+ * ```typescript
4567
+ * const configs = await helper.getPublicRead('config');
4568
+ * ```
4569
+ */
4570
+ async getPublicRead(collectionName) {
4571
+ const path = getPublicReadPath(this.appId, collectionName);
4572
+ return this.getDocs(path);
4573
+ }
4574
+ /**
4575
+ * Get collection reference for publicData
4576
+ * Use this for advanced queries with where(), orderBy(), limit()
4577
+ *
4578
+ * @param collectionName - Collection name
4579
+ * @returns Collection reference
4580
+ *
4581
+ * @example
4582
+ * ```typescript
4583
+ * import { query, where, orderBy } from 'firebase/firestore';
4584
+ *
4585
+ * const postsRef = helper.publicDataCollection('posts');
4586
+ * const q = query(
4587
+ * postsRef,
4588
+ * where('_createdBy', '==', userId),
4589
+ * orderBy('_createdAt', 'desc')
4590
+ * );
4591
+ * const snapshot = await getDocs(q);
4592
+ * ```
4593
+ */
4594
+ publicDataCollection(collectionName) {
4595
+ const path = getPublicDataPath(this.appId, collectionName);
4596
+ return this.getCollection(path);
4597
+ }
4598
+ /**
4599
+ * Get collection reference for userData
4600
+ *
4601
+ * @param collectionName - Collection name
4602
+ * @returns Collection reference
4603
+ */
4604
+ userDataCollection(collectionName) {
4605
+ const path = getUserDataPath(this.appId, this.userId, collectionName);
4606
+ return this.getCollection(path);
4607
+ }
4608
+ /**
4609
+ * Get collection reference for publicRead
4610
+ *
4611
+ * @param collectionName - Collection name
4612
+ * @returns Collection reference
4613
+ */
4614
+ publicReadCollection(collectionName) {
4615
+ const path = getPublicReadPath(this.appId, collectionName);
4616
+ return this.getCollection(path);
4617
+ }
4618
+ /**
4619
+ * Update document with automatic metadata update
4620
+ *
4621
+ * Automatically sets: _updatedAt, _updatedBy
4622
+ *
4623
+ * @param collectionPath - Full collection path
4624
+ * @param docId - Document ID
4625
+ * @param data - Data to update
4626
+ *
4627
+ * @example
4628
+ * ```typescript
4629
+ * await helper.updateDoc(
4630
+ * getPublicDataPath(appId, 'posts'),
4631
+ * 'post-123',
4632
+ * { title: 'Updated Title' }
4633
+ * );
4634
+ * ```
4635
+ */
4636
+ async updateDoc(collectionPath, docId, data) {
4637
+ const { updateDoc, doc, serverTimestamp } = await this.loadFirestore();
4638
+ const docRef = doc(this.db, collectionPath, docId);
4639
+ return updateDoc(docRef, {
4640
+ ...data,
4641
+ _updatedAt: serverTimestamp(),
4642
+ _updatedBy: this.userId
4643
+ });
4644
+ }
4645
+ /**
4646
+ * Delete document
4647
+ *
4648
+ * @param collectionPath - Full collection path
4649
+ * @param docId - Document ID
4650
+ */
4651
+ async deleteDoc(collectionPath, docId) {
4652
+ const { deleteDoc, doc } = await this.loadFirestore();
4653
+ const docRef = doc(this.db, collectionPath, docId);
4654
+ return deleteDoc(docRef);
4655
+ }
4656
+ /**
4657
+ * Get single document by ID
4658
+ *
4659
+ * @param collectionPath - Full collection path
4660
+ * @param docId - Document ID
4661
+ *
4662
+ * @example
4663
+ * ```typescript
4664
+ * const docSnap = await helper.getDoc(
4665
+ * getPublicDataPath(appId, 'posts'),
4666
+ * 'post-123'
4667
+ * );
4668
+ * if (docSnap.exists()) {
4669
+ * console.log(docSnap.data());
4670
+ * }
4671
+ * ```
4672
+ */
4673
+ async getDoc(collectionPath, docId) {
4674
+ const { getDoc, doc } = await this.loadFirestore();
4675
+ const docRef = doc(this.db, collectionPath, docId);
4676
+ return getDoc(docRef);
4677
+ }
4678
+ // ============================================================================
4679
+ // Private Helper Methods
4680
+ // ============================================================================
4681
+ /**
4682
+ * Internal: Add document with metadata injection
4683
+ */
4684
+ async addDocWithMeta(collectionPath, data) {
4685
+ const { addDoc, collection, serverTimestamp } = await this.loadFirestore();
4686
+ const colRef = collection(this.db, collectionPath);
4687
+ return addDoc(colRef, {
4688
+ _appId: this.appId,
4689
+ _createdAt: serverTimestamp(),
4690
+ _createdBy: this.userId,
4691
+ ...data
4692
+ });
4693
+ }
4694
+ /**
4695
+ * Internal: Get all documents from collection
4696
+ */
4697
+ async getDocs(collectionPath) {
4698
+ const { getDocs, collection } = await this.loadFirestore();
4699
+ const colRef = collection(this.db, collectionPath);
4700
+ return getDocs(colRef);
4701
+ }
4702
+ /**
4703
+ * Internal: Get collection reference
4704
+ */
4705
+ getCollection(collectionPath) {
4706
+ // Note: This is sync, so we can't use dynamic import
4707
+ // We assume firebase/firestore is already loaded by initializeWithToken
4708
+ const { collection } = require('firebase/firestore');
4709
+ return collection(this.db, collectionPath);
4710
+ }
4711
+ /**
4712
+ * Internal: Lazy load Firebase Firestore functions
4713
+ */
4714
+ async loadFirestore() {
4715
+ const firestore = await import('firebase/firestore');
4716
+ return {
4717
+ collection: firestore.collection,
4718
+ doc: firestore.doc,
4719
+ addDoc: firestore.addDoc,
4720
+ setDoc: firestore.setDoc,
4721
+ getDoc: firestore.getDoc,
4722
+ getDocs: firestore.getDocs,
4723
+ updateDoc: firestore.updateDoc,
4724
+ deleteDoc: firestore.deleteDoc,
4725
+ serverTimestamp: firestore.serverTimestamp,
4726
+ query: firestore.query,
4727
+ where: firestore.where,
4728
+ orderBy: firestore.orderBy,
4729
+ limit: firestore.limit
4730
+ };
4731
+ }
4732
+ }
4733
+ /**
4734
+ * Standalone helper function: Add document with automatic metadata injection
4735
+ *
4736
+ * Use this if you don't want to create a FirestoreHelper instance.
4737
+ *
4738
+ * @param db - Firestore instance
4739
+ * @param collectionPath - Full collection path
4740
+ * @param appId - Application ID
4741
+ * @param userId - User ID
4742
+ * @param data - Your business data
4743
+ * @returns Document reference
4744
+ *
4745
+ * @example
4746
+ * ```typescript
4747
+ * import { addDocWithMeta, getPublicDataPath } from '@seaverse/data-service-sdk';
4748
+ *
4749
+ * const docRef = await addDocWithMeta(
4750
+ * db,
4751
+ * getPublicDataPath(appId, 'posts'),
4752
+ * appId,
4753
+ * userId,
4754
+ * { title: 'Post', content: 'Hello' }
4755
+ * );
4756
+ * ```
4757
+ */
4758
+ async function addDocWithMeta(db, collectionPath, appId, userId, data) {
4759
+ const { addDoc, collection, serverTimestamp } = await import('firebase/firestore');
4760
+ const colRef = collection(db, collectionPath);
4761
+ return addDoc(colRef, {
4762
+ _appId: appId,
4763
+ _createdAt: serverTimestamp(),
4764
+ _createdBy: userId,
4765
+ ...data
4766
+ });
4767
+ }
4768
+ /**
4769
+ * Standalone helper function: Update document with automatic metadata
4770
+ *
4771
+ * @param db - Firestore instance
4772
+ * @param collectionPath - Full collection path
4773
+ * @param docId - Document ID
4774
+ * @param userId - User ID (for _updatedBy field)
4775
+ * @param data - Data to update
4776
+ *
4777
+ * @example
4778
+ * ```typescript
4779
+ * import { updateDocWithMeta, getPublicDataPath } from '@seaverse/data-service-sdk';
4780
+ *
4781
+ * await updateDocWithMeta(
4782
+ * db,
4783
+ * getPublicDataPath(appId, 'posts'),
4784
+ * 'post-123',
4785
+ * userId,
4786
+ * { title: 'Updated Title' }
4787
+ * );
4788
+ * ```
4789
+ */
4790
+ async function updateDocWithMeta(db, collectionPath, docId, userId, data) {
4791
+ const { updateDoc, doc, serverTimestamp } = await import('firebase/firestore');
4792
+ const docRef = doc(db, collectionPath, docId);
4793
+ return updateDoc(docRef, {
4794
+ ...data,
4795
+ _updatedAt: serverTimestamp(),
4796
+ _updatedBy: userId
4797
+ });
4798
+ }
4799
+
4800
+ /**
4801
+ * Create Firebase configuration from Firestore token response
4802
+ *
4803
+ * This helper function extracts the Firebase config from the token response,
4804
+ * making it easy to initialize Firebase app.
4805
+ *
4806
+ * @param tokenResponse - The Firestore token response from SDK
4807
+ * @returns Firebase configuration object ready for initializeApp()
4808
+ *
4809
+ * @example
4810
+ * ```typescript
4811
+ * import { initializeApp } from 'firebase/app';
4812
+ * import { getFirebaseConfig } from '@seaverse/data-service-sdk';
4813
+ *
4814
+ * const tokenResponse = await client.generateGuestFirestoreToken({ app_id: 'my-app' });
4815
+ * const firebaseConfig = getFirebaseConfig(tokenResponse);
4816
+ *
4817
+ * const app = initializeApp(firebaseConfig);
4818
+ * ```
4819
+ */
4820
+ function getFirebaseConfig(tokenResponse) {
4821
+ return {
4822
+ apiKey: tokenResponse.web_api_key,
4823
+ projectId: tokenResponse.project_id,
4824
+ };
4825
+ }
4826
+ /**
4827
+ * Initialize Firebase with Firestore token response (browser only)
4828
+ *
4829
+ * This is a convenience function that automatically:
4830
+ * 1. Creates Firebase config from token response
4831
+ * 2. Initializes Firebase app
4832
+ * 3. Signs in with the custom token
4833
+ * 4. Creates FirestoreHelper for LLM-friendly operations
4834
+ * 5. Returns authenticated Firebase instances
4835
+ *
4836
+ * IMPORTANT: This function requires Firebase SDK to be installed separately:
4837
+ * npm install firebase
4838
+ *
4839
+ * 🎯 LLM RECOMMENDED: Use the `helper` object for simplified operations
4840
+ *
4841
+ * @param tokenResponse - The Firestore token response from SDK
4842
+ * @returns Object containing initialized Firebase instances and LLM-friendly helper
4843
+ *
4844
+ * @example
4845
+ * ```typescript
4846
+ * import { initializeWithToken } from '@seaverse/data-service-sdk';
4847
+ *
4848
+ * const tokenResponse = await client.generateGuestFirestoreToken({ app_id: 'my-app' });
4849
+ * const { db, userId, appId, helper } = await initializeWithToken(tokenResponse);
4850
+ *
4851
+ * // ✅ LLM-FRIENDLY: Use helper (automatic required fields)
4852
+ * await helper.addToPublicData('posts', {
4853
+ * title: 'My Post',
4854
+ * content: 'Hello'
4855
+ * });
4856
+ *
4857
+ * // ❌ OLD WAY: Manual (need to remember required fields)
4858
+ * // await addDoc(collection(db, path), { _appId, _createdAt, _createdBy, ...data });
4859
+ * ```
4860
+ */
4861
+ async function initializeWithToken(tokenResponse) {
4862
+ // Check if Firebase SDK is available
4863
+ let initializeApp;
4864
+ let getAuth;
4865
+ let signInWithCustomToken;
4866
+ let getFirestore;
4867
+ try {
4868
+ // Try to import Firebase modules
4869
+ const firebaseApp = await import('firebase/app');
4870
+ const firebaseAuth = await import('firebase/auth');
4871
+ const firebaseFirestore = await import('firebase/firestore');
4872
+ initializeApp = firebaseApp.initializeApp;
4873
+ getAuth = firebaseAuth.getAuth;
4874
+ signInWithCustomToken = firebaseAuth.signInWithCustomToken;
4875
+ getFirestore = firebaseFirestore.getFirestore;
4876
+ }
4877
+ catch (error) {
4878
+ throw new Error('Firebase SDK not found. Please install it: npm install firebase\n' +
4879
+ 'Or import manually and use getFirebaseConfig() helper instead.');
4880
+ }
4881
+ // Initialize Firebase
4882
+ const config = getFirebaseConfig(tokenResponse);
4883
+ const app = initializeApp(config);
4884
+ // Sign in with custom token
4885
+ const auth = getAuth(app);
4886
+ await signInWithCustomToken(auth, tokenResponse.custom_token);
4887
+ // Get Firestore instance with correct database ID
4888
+ // IMPORTANT: Must specify database_id, not just use default!
4889
+ const db = getFirestore(app, tokenResponse.database_id);
4890
+ const userId = tokenResponse.user_id;
4891
+ const appId = tokenResponse.app_id || '';
4892
+ // Create LLM-friendly helper
4893
+ const helper = new FirestoreHelper(db, appId, userId);
4894
+ return {
4895
+ app,
4896
+ auth,
4897
+ db,
4898
+ userId,
4899
+ appId,
4900
+ helper,
4901
+ };
4902
+ }
4903
+
4904
+ export { DEFAULT_BASE_URL, DEFAULT_TIMEOUT, DataServiceClient, ENDPOINTS, FirestoreHelper, PATH_PATTERNS, PathBuilder, addDocWithMeta, getFirebaseConfig, getPublicDataDocPath, getPublicDataPath, getPublicReadDocPath, getPublicReadPath, getUserDataDocPath, getUserDataPath, initializeWithToken, updateDocWithMeta };
4521
4905
  //# sourceMappingURL=browser.js.map