@amityco/ts-sdk 7.12.0 → 7.12.1-8bbe30f.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.
@@ -3,11 +3,15 @@ declare global {
3
3
  namespace Amity {
4
4
  type UsageDataModel = {
5
5
  sessionId: string;
6
- streamId: string;
6
+ roomId?: string;
7
7
  startTime: string;
8
8
  endTime: string;
9
9
  watchSeconds: number;
10
- resolution: string;
10
+ resolution?: string;
11
+ /**
12
+ * @deprecated Use `roomId` instead.
13
+ */
14
+ streamId?: string;
11
15
  };
12
16
  }
13
17
  }
@@ -1 +1 @@
1
- {"version":3,"file":"liveStreamPlayer.d.ts","sourceRoot":"","sources":["../../../src/@types/domains/liveStreamPlayer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC;AAEV,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,KAAK,CAAC;QACd,KAAK,cAAc,GAAG;YACpB,SAAS,EAAE,MAAM,CAAC;YAClB,QAAQ,EAAE,MAAM,CAAC;YACjB,SAAS,EAAE,MAAM,CAAC;YAClB,OAAO,EAAE,MAAM,CAAC;YAChB,YAAY,EAAE,MAAM,CAAC;YACrB,UAAU,EAAE,MAAM,CAAC;SACpB,CAAC;KACH;CACF"}
1
+ {"version":3,"file":"liveStreamPlayer.d.ts","sourceRoot":"","sources":["../../../src/@types/domains/liveStreamPlayer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC;AAEV,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,KAAK,CAAC;QACd,KAAK,cAAc,GAAG;YACpB,SAAS,EAAE,MAAM,CAAC;YAClB,MAAM,CAAC,EAAE,MAAM,CAAC;YAChB,SAAS,EAAE,MAAM,CAAC;YAClB,OAAO,EAAE,MAAM,CAAC;YAChB,YAAY,EAAE,MAAM,CAAC;YACrB,UAAU,CAAC,EAAE,MAAM,CAAC;YACpB;;eAEG;YACH,QAAQ,CAAC,EAAE,MAAM,CAAC;SACnB,CAAC;KACH;CACF"}
@@ -66,6 +66,7 @@ declare global {
66
66
  getLiveChat: () => Promise<Amity.Channel<'live'> | undefined>;
67
67
  createInvitation: (userId: string) => Promise<Amity.Cached<Amity.InternalInvitation[]>>;
68
68
  getInvitations: () => Promise<Amity.Invitation | undefined>;
69
+ analytics: () => Amity.RoomAnalytics;
69
70
  };
70
71
  type Room = Omit<InternalRoom, 'participants'> & RoomLinkedObject;
71
72
  type RoomLiveCollection = {
@@ -105,6 +106,34 @@ declare global {
105
106
  invitation?: Amity.Invitation;
106
107
  actorInternalId?: string;
107
108
  };
109
+ enum WatchSessionSyncStateEnum {
110
+ PENDING = "PENDING",
111
+ SYNCING = "SYNCING",
112
+ SYNCED = "SYNCED"
113
+ }
114
+ type WatchSessionSyncState = `${WatchSessionSyncStateEnum}`;
115
+ type WatchSessionEntity = {
116
+ sessionId: string;
117
+ roomId: string;
118
+ watchSeconds: number;
119
+ startTime: Date;
120
+ endTime?: Date | null;
121
+ syncState: WatchSessionSyncState;
122
+ syncedAt?: Date | null;
123
+ retryCount: number;
124
+ };
125
+ type WatchSessionData = {
126
+ sessionId: string;
127
+ roomId: string;
128
+ watchSeconds: number;
129
+ startTime: string;
130
+ endTime?: string;
131
+ };
132
+ interface RoomAnalytics {
133
+ createWatchSession(startedAt: Date): Promise<string>;
134
+ updateWatchSession(sessionId: string, duration: number, endedAt: Date): Promise<void>;
135
+ syncPendingWatchSessions(): void;
136
+ }
108
137
  }
109
138
  }
110
139
  //# sourceMappingURL=room.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"room.d.ts","sourceRoot":"","sources":["../../../src/@types/domains/room.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"room.d.ts","sourceRoot":"","sources":["../../../src/@types/domains/room.ts"],"names":[],"mappings":"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"}
package/dist/index.cjs.js CHANGED
@@ -12542,6 +12542,413 @@ const getInvitation = async (params) => {
12542
12542
  };
12543
12543
  /* end_public_function */
12544
12544
 
12545
+ /**
12546
+ * WatchSessionStorage manages watch session data in memory
12547
+ * Similar to UsageCollector for stream watch minutes
12548
+ */
12549
+ class WatchSessionStorage {
12550
+ constructor() {
12551
+ this.sessions = new Map();
12552
+ }
12553
+ /**
12554
+ * Add a new watch session
12555
+ */
12556
+ addSession(session) {
12557
+ this.sessions.set(session.sessionId, session);
12558
+ }
12559
+ /**
12560
+ * Get a watch session by sessionId
12561
+ */
12562
+ getSession(sessionId) {
12563
+ return this.sessions.get(sessionId);
12564
+ }
12565
+ /**
12566
+ * Update a watch session
12567
+ */
12568
+ updateSession(sessionId, updates) {
12569
+ const session = this.sessions.get(sessionId);
12570
+ if (session) {
12571
+ this.sessions.set(sessionId, Object.assign(Object.assign({}, session), updates));
12572
+ }
12573
+ }
12574
+ /**
12575
+ * Get all sessions with a specific sync state
12576
+ */
12577
+ getSessionsByState(state) {
12578
+ return Array.from(this.sessions.values()).filter(session => session.syncState === state);
12579
+ }
12580
+ /**
12581
+ * Delete a session
12582
+ */
12583
+ deleteSession(sessionId) {
12584
+ this.sessions.delete(sessionId);
12585
+ }
12586
+ /**
12587
+ * Get all pending sessions
12588
+ */
12589
+ getPendingSessions() {
12590
+ return this.getSessionsByState('PENDING');
12591
+ }
12592
+ /**
12593
+ * Get all syncing sessions
12594
+ */
12595
+ getSyncingSessions() {
12596
+ return this.getSessionsByState('SYNCING');
12597
+ }
12598
+ }
12599
+ // Singleton instance
12600
+ let storageInstance = null;
12601
+ const getWatchSessionStorage = () => {
12602
+ if (!storageInstance) {
12603
+ storageInstance = new WatchSessionStorage();
12604
+ }
12605
+ return storageInstance;
12606
+ };
12607
+
12608
+ const privateKey = "-----BEGIN PRIVATE KEY-----\nMIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDAARz+hmBgi8pJ\nQb8LeY41gtHhk+ACMwRfhsn7GqpqRQNG2qU0755mzZuVDUqjQMGSo8THJB7O+OJs\nflbZRkFXlFoFOVNw1UpNOgwEQZ6wB9oRwzepTJAfF1sVhm/o/ixvXh1zDFNDy6yZ\npXyiiJHUVxqyjllZhxnwdvjoVtDs6hW6awG09bB9nh/TTejlUKXoAgzqVwu/1QMu\nUVViET495elEe19aUarEy+oL2iKeXCEvqda/pWNBdbieFyJvvZ08HN8dPuT88wq2\njZLEAth1vrwQ2IAa4ktaLcBQdLJgIkrbDvAiVZ8lQAjS/bq5vXQikTGvoPlC5bbn\nvuOM/3eLAgMBAAECggEAVZ+peHAghq2QVj71nX5lxsNCKaCyYwixSJBpfouTt7Rz\nE6PpzMOXFi1W1o+I22jDakuSM2SOQKqI/u0QefB0r0O/KVk5NrZHXk0mkrdYtxOp\nUgaGyf8UvmjB+8VqHrNKyZdk9qtmbnNj01kTTcAtmE4H39zPR7eR/8Rul94vaZbs\nwCnKJS3mLT3JxyGug6lxanveKkjG+CKC1nJQYWaxCJxaFSzbwXQPvDhB+TvrIbee\npd5v4EAyEJohpr+T9oDGGJkb/KARBZCtwLyB976PKJwwBA8MRVL1i5QwawuMiMq5\nUtnOnbGKtCeFzaLbNU0Qi8bqyims84EQxC6DOu1fkQKBgQDdvsoBsEhsOXV7hlIJ\naEd0eSJZVkdqimxH8uGoMM2FeNaOrcB6yBXqTSP0R3OIyf8eaY6yjRvP30ZNXcll\n/gD3O1Mu6YmWQdt1W2WA6pKOsUuPXasf0pdOF7IiFZKlSabz5YHXFqwVuqm8loaj\nsXel3YWqPVdHiankE7tz+3ssnQKBgQDdqi4TNdD1MdEpihx19jr0QjUiXW3939FK\nqp30HESPEGDGQzXdmJgif9HhZb+cJSuWaHEbjgBrYahvgCF+y6LbEpOD+D/dmT+s\nDEAQaR84sah6dokwPjV8fjBSrcVFjCS+doxv0d3p/9OUEeyUhFrY03nxtIEYkLIE\n/Zvn37b4RwKBgQCLENVFe9XfsaVhQ5r9dV2iyTlmh7qgMZG5CbTFs12hQGhm8McO\n+Z7s41YSJCFr/yq1WwP4LJDtrBw99vyQr1zRsG35tNLp3gGRNzGQSQyC2uQFVHw2\np+7mNewsfhUK/gbrXNsyFnDz6635rPlhfbII3sWuP2wWXFqkxE9CbMwR7QKBgQC6\nawDMzxmo2/iYArrkyevSuEuPVxvFwpF1RgAI6C0QVCnPE38dmdN4UB7mfHekje4W\nVEercMURidPp0cxZolCYBQtilUjAyL0vqC3In1/Ogjq6oy3FEMxSop1pKxMY5j+Q\nnoqFD+6deLUrddeNH7J3X4LSr4dSbX4JjG+tlgt+yQKBgQCuwTL4hA6KqeInQ0Ta\n9VQX5Qr8hFlqJz1gpymi/k63tW/Ob8yedbg3WWNWyShwRMFYyY9S81ITFWM95uL6\nvF3x9rmRjwElJw9PMwVu6dmf/CO0Z1wzXSp2VVD12gbrUD/0/d7MUoJ9LgC8X8f/\nn0txLHYGHbx+nf95+JUg6lV3hg==\n-----END PRIVATE KEY-----";
12609
+ /*
12610
+ * The crypto algorithm used for importing key and signing string
12611
+ */
12612
+ const ALGORITHM = {
12613
+ name: 'RSASSA-PKCS1-v1_5',
12614
+ hash: { name: 'SHA-256' },
12615
+ };
12616
+ /*
12617
+ * IMPORTANT!
12618
+ * If you are recieving key from other platforms use an online tool to convert
12619
+ * the PKCS1 to PKCS8. For instance the key from Android SDK is of the format
12620
+ * PKCS1.
12621
+ *
12622
+ * If recieving from the platform, verify if it's already in the expected
12623
+ * format. Otherwise the crypto.subtle.importKey will throw a DOMException
12624
+ */
12625
+ const PRIVATE_KEY_SIGNATURE = 'pkcs8';
12626
+ /*
12627
+ * Ensure that the private key in the .env follows this format
12628
+ */
12629
+ const PEM_HEADER = '-----BEGIN PRIVATE KEY-----';
12630
+ const PEM_FOOTER = '-----END PRIVATE KEY-----';
12631
+ /*
12632
+ * The crypto.subtle.sign function returns an ArrayBuffer whereas the server
12633
+ * expects a base64 string. This util helps facilitate that process
12634
+ */
12635
+ function base64FromArrayBuffer(buffer) {
12636
+ const uint8Array = new Uint8Array(buffer);
12637
+ let binary = '';
12638
+ uint8Array.forEach(byte => {
12639
+ binary += String.fromCharCode(byte);
12640
+ });
12641
+ return jsBase64.btoa(binary);
12642
+ }
12643
+ /*
12644
+ * Encode ASN.1 length field
12645
+ */
12646
+ function encodeLength(length) {
12647
+ if (length < 128) {
12648
+ return new Uint8Array([length]);
12649
+ }
12650
+ if (length < 256) {
12651
+ return new Uint8Array([0x81, length]);
12652
+ }
12653
+ // eslint-disable-next-line no-bitwise
12654
+ return new Uint8Array([0x82, (length >> 8) & 0xff, length & 0xff]);
12655
+ }
12656
+ /*
12657
+ * Convert PKCS1 private key to PKCS8 format
12658
+ * PKCS1 is RSA-specific format, PKCS8 is generic format that crypto.subtle requires
12659
+ * Android uses PKCS8EncodedKeySpec which expects PKCS8 format
12660
+ */
12661
+ function pkcs1ToPkcs8(pkcs1) {
12662
+ // Algorithm identifier for RSA
12663
+ const algorithmIdentifier = new Uint8Array([
12664
+ 0x30,
12665
+ 0x0d,
12666
+ 0x06,
12667
+ 0x09,
12668
+ 0x2a,
12669
+ 0x86,
12670
+ 0x48,
12671
+ 0x86,
12672
+ 0xf7,
12673
+ 0x0d,
12674
+ 0x01,
12675
+ 0x01,
12676
+ 0x01,
12677
+ 0x05,
12678
+ 0x00, // NULL
12679
+ ]);
12680
+ // Version (INTEGER 0)
12681
+ const version = new Uint8Array([0x02, 0x01, 0x00]);
12682
+ // OCTET STRING tag + length + pkcs1 data
12683
+ const octetStringTag = 0x04;
12684
+ const octetStringLength = encodeLength(pkcs1.length);
12685
+ // Calculate total content length (version + algorithm + octet string)
12686
+ const contentLength = version.length + algorithmIdentifier.length + 1 + octetStringLength.length + pkcs1.length;
12687
+ // SEQUENCE tag + length
12688
+ const sequenceTag = 0x30;
12689
+ const sequenceLength = encodeLength(contentLength);
12690
+ // Build the PKCS8 structure
12691
+ const pkcs8 = new Uint8Array(1 + sequenceLength.length + contentLength);
12692
+ let offset = 0;
12693
+ pkcs8[offset] = sequenceTag;
12694
+ offset += 1;
12695
+ pkcs8.set(sequenceLength, offset);
12696
+ offset += sequenceLength.length;
12697
+ pkcs8.set(version, offset);
12698
+ offset += version.length;
12699
+ pkcs8.set(algorithmIdentifier, offset);
12700
+ offset += algorithmIdentifier.length;
12701
+ pkcs8[offset] = octetStringTag;
12702
+ offset += 1;
12703
+ pkcs8.set(octetStringLength, offset);
12704
+ offset += octetStringLength.length;
12705
+ pkcs8.set(pkcs1, offset);
12706
+ return pkcs8;
12707
+ }
12708
+ async function importPrivateKey(keyString) {
12709
+ // Remove PEM headers if present and any whitespace
12710
+ let base64Key = keyString;
12711
+ if (keyString.includes(PEM_HEADER)) {
12712
+ base64Key = keyString
12713
+ .substring(PEM_HEADER.length, keyString.length - PEM_FOOTER.length)
12714
+ .replace(/\s/g, '');
12715
+ }
12716
+ else {
12717
+ base64Key = keyString.replace(/\s/g, '');
12718
+ }
12719
+ // Base64 decode to get binary data
12720
+ const binaryDerString = jsBase64.atob(base64Key);
12721
+ // Convert to Uint8Array for manipulation
12722
+ const pkcs1 = new Uint8Array(binaryDerString.length);
12723
+ for (let i = 0; i < binaryDerString.length; i += 1) {
12724
+ pkcs1[i] = binaryDerString.charCodeAt(i);
12725
+ }
12726
+ // Convert PKCS1 to PKCS8 (crypto.subtle requires PKCS8)
12727
+ const pkcs8 = pkcs1ToPkcs8(pkcs1);
12728
+ // Import the key
12729
+ const key = await crypto.subtle.importKey(PRIVATE_KEY_SIGNATURE, pkcs8.buffer, ALGORITHM, false, ['sign']);
12730
+ return key;
12731
+ }
12732
+ async function createSignature({ timestamp, rooms, }) {
12733
+ const dataStr = rooms
12734
+ .map(item => Object.keys(item)
12735
+ .sort()
12736
+ .map(key => `${key}=${item[key]}`)
12737
+ .join('&'))
12738
+ .join(';');
12739
+ /*
12740
+ * nonceStr needs to be unique for each request
12741
+ */
12742
+ const nonceStr = uuid__default["default"].v4();
12743
+ const signStr = `nonceStr=${nonceStr}&timestamp=${timestamp}&data=${dataStr}==`;
12744
+ const encoder = new TextEncoder();
12745
+ const data = encoder.encode(signStr);
12746
+ const key = await importPrivateKey(privateKey);
12747
+ const sign = await crypto.subtle.sign(ALGORITHM, key, data);
12748
+ return { signature: base64FromArrayBuffer(sign), nonceStr };
12749
+ }
12750
+
12751
+ /**
12752
+ * Sync pending watch sessions to backend
12753
+ * This function implements the full sync flow with network resilience
12754
+ */
12755
+ async function syncWatchSessions() {
12756
+ const storage = getWatchSessionStorage();
12757
+ // Get all pending sessions
12758
+ const pendingSessions = storage.getPendingSessions();
12759
+ if (pendingSessions.length === 0) {
12760
+ return true;
12761
+ }
12762
+ try {
12763
+ const timestamp = new Date().toISOString();
12764
+ // Convert sessions to API format - always include all fields like syncUsage does
12765
+ const rooms = pendingSessions.map(session => ({
12766
+ sessionId: session.sessionId,
12767
+ roomId: session.roomId,
12768
+ watchSeconds: session.watchSeconds,
12769
+ startTime: session.startTime.toISOString(),
12770
+ endTime: session.endTime ? session.endTime.toISOString() : '',
12771
+ }));
12772
+ // Create signature (reuse from stream feature) - pass directly like syncUsage
12773
+ const signatureData = await createSignature({
12774
+ timestamp,
12775
+ rooms,
12776
+ });
12777
+ if (!signatureData || !signatureData.signature) {
12778
+ throw new Error('Signature is undefined');
12779
+ }
12780
+ // Update sync state to SYNCING
12781
+ pendingSessions.forEach(session => {
12782
+ storage.updateSession(session.sessionId, { syncState: 'SYNCING' });
12783
+ });
12784
+ const payload = {
12785
+ signature: signatureData.signature,
12786
+ nonceStr: signatureData.nonceStr,
12787
+ timestamp,
12788
+ rooms,
12789
+ };
12790
+ const client = getActiveClient();
12791
+ // Send to backend
12792
+ await client.http.post('/api/v3/user-event/room', payload);
12793
+ // Success - update to SYNCED
12794
+ pendingSessions.forEach(session => {
12795
+ storage.updateSession(session.sessionId, {
12796
+ syncState: 'SYNCED',
12797
+ syncedAt: new Date(),
12798
+ });
12799
+ });
12800
+ return true;
12801
+ }
12802
+ catch (err) {
12803
+ console.error('[SDK syncWatchSessions] ERROR caught:', (err === null || err === void 0 ? void 0 : err.message) || err);
12804
+ // Failure - update back to PENDING and increment retry count
12805
+ pendingSessions.forEach(session => {
12806
+ const currentSession = storage.getSession(session.sessionId);
12807
+ if (currentSession) {
12808
+ const newRetryCount = currentSession.retryCount + 1;
12809
+ if (newRetryCount >= 3) {
12810
+ // Delete session if retry count exceeds 3
12811
+ storage.deleteSession(session.sessionId);
12812
+ }
12813
+ else {
12814
+ // Update to PENDING with incremented retry count
12815
+ storage.updateSession(session.sessionId, {
12816
+ syncState: 'PENDING',
12817
+ retryCount: newRetryCount,
12818
+ });
12819
+ }
12820
+ }
12821
+ });
12822
+ return false;
12823
+ }
12824
+ }
12825
+
12826
+ /**
12827
+ * Room statuses that are considered watchable
12828
+ */
12829
+ const WATCHABLE_ROOM_STATUSES = ['live', 'recorded'];
12830
+ /**
12831
+ * Generate a random jitter delay between 5 and 30 seconds
12832
+ */
12833
+ const getJitterDelay = () => {
12834
+ const minDelay = 5000; // 5 seconds
12835
+ const maxDelay = 30000; // 30 seconds
12836
+ return Math.floor(Math.random() * (maxDelay - minDelay + 1)) + minDelay;
12837
+ };
12838
+ /**
12839
+ * Wait for network connection with timeout
12840
+ * @param maxWaitTime Maximum time to wait in milliseconds (default: 60000 = 60 seconds)
12841
+ * @returns Promise that resolves when network is available or timeout is reached
12842
+ */
12843
+ const waitForNetwork = (maxWaitTime = 60000) => {
12844
+ return new Promise(resolve => {
12845
+ // Simple check - if navigator.onLine is available, use it
12846
+ // Otherwise, assume network is available
12847
+ if (typeof navigator === 'undefined' || typeof navigator.onLine === 'undefined') {
12848
+ resolve();
12849
+ return;
12850
+ }
12851
+ const startTime = Date.now();
12852
+ const checkInterval = 1000; // 1 second
12853
+ const checkConnection = () => {
12854
+ if (navigator.onLine || Date.now() - startTime >= maxWaitTime) {
12855
+ resolve();
12856
+ }
12857
+ else {
12858
+ setTimeout(checkConnection, checkInterval);
12859
+ }
12860
+ };
12861
+ checkConnection();
12862
+ });
12863
+ };
12864
+ /**
12865
+ * AmityRoomAnalytics provides analytics capabilities for room watch sessions
12866
+ */
12867
+ class AmityRoomAnalytics {
12868
+ constructor(room) {
12869
+ this.storage = getWatchSessionStorage();
12870
+ this.room = room;
12871
+ }
12872
+ /**
12873
+ * Create a new watch session for the current room
12874
+ * @param startedAt The timestamp when watching started
12875
+ * @returns Promise<string> sessionId unique identifier for this watch session
12876
+ * @throws ASCApiError if room is not in watchable state (not LIVE or RECORDED)
12877
+ */
12878
+ async createWatchSession(startedAt) {
12879
+ // Validate room status
12880
+ if (!WATCHABLE_ROOM_STATUSES.includes(this.room.status)) {
12881
+ throw new ASCApiError('room is not in watchable state', 500000 /* Amity.ServerError.BUSINESS_ERROR */, "error" /* Amity.ErrorLevel.ERROR */);
12882
+ }
12883
+ // Generate session ID with prefix
12884
+ const prefix = this.room.status === 'live' ? 'live_' : 'playback_';
12885
+ const sessionId = prefix + uuid__default["default"].v4();
12886
+ // Create watch session entity
12887
+ const session = {
12888
+ sessionId,
12889
+ roomId: this.room.roomId,
12890
+ watchSeconds: 0,
12891
+ startTime: startedAt,
12892
+ endTime: null,
12893
+ syncState: 'PENDING',
12894
+ syncedAt: null,
12895
+ retryCount: 0,
12896
+ };
12897
+ // Persist to storage
12898
+ this.storage.addSession(session);
12899
+ return sessionId;
12900
+ }
12901
+ /**
12902
+ * Update an existing watch session with duration
12903
+ * @param sessionId The unique identifier of the watch session
12904
+ * @param duration The total watch duration in seconds
12905
+ * @param endedAt The timestamp when this update occurred
12906
+ * @returns Promise<void> Completion status
12907
+ */
12908
+ async updateWatchSession(sessionId, duration, endedAt) {
12909
+ const session = this.storage.getSession(sessionId);
12910
+ if (!session) {
12911
+ throw new Error(`Watch session ${sessionId} not found`);
12912
+ }
12913
+ // Update session
12914
+ this.storage.updateSession(sessionId, {
12915
+ watchSeconds: duration,
12916
+ endTime: endedAt,
12917
+ });
12918
+ }
12919
+ /**
12920
+ * Sync all pending watch sessions to backend
12921
+ * This function uses jitter delay and handles network resilience
12922
+ */
12923
+ syncPendingWatchSessions() {
12924
+ // Execute with jitter delay (5-30 seconds)
12925
+ const jitterDelay = getJitterDelay();
12926
+ console.log('[SDK AmityRoomAnalytics] syncPendingWatchSessions called, jitter delay:', `${jitterDelay}ms`);
12927
+ setTimeout(async () => {
12928
+ console.log('[SDK AmityRoomAnalytics] Jitter delay completed, starting sync process');
12929
+ try {
12930
+ // Reset any SYNCING sessions back to PENDING
12931
+ const syncingSessions = this.storage.getSyncingSessions();
12932
+ console.log('[SDK AmityRoomAnalytics] SYNCING sessions to reset:', syncingSessions.length);
12933
+ syncingSessions.forEach(session => {
12934
+ this.storage.updateSession(session.sessionId, { syncState: 'PENDING' });
12935
+ });
12936
+ // Wait for network connection (max 60 seconds)
12937
+ await waitForNetwork(60000);
12938
+ console.log('[SDK AmityRoomAnalytics] Network available');
12939
+ // Sync pending sessions
12940
+ console.log('[SDK AmityRoomAnalytics] Calling syncWatchSessions()');
12941
+ await syncWatchSessions();
12942
+ console.log('[SDK AmityRoomAnalytics] syncWatchSessions completed');
12943
+ }
12944
+ catch (error) {
12945
+ // Error is already handled in syncWatchSessions
12946
+ console.error('Failed to sync watch sessions:', error);
12947
+ }
12948
+ }, jitterDelay);
12949
+ }
12950
+ }
12951
+
12545
12952
  const roomLinkedObject = (room) => {
12546
12953
  return Object.assign(Object.assign({}, room), { get post() {
12547
12954
  var _a;
@@ -12588,6 +12995,9 @@ const roomLinkedObject = (room) => {
12588
12995
  type: "livestreamCohostInvite" /* InvitationTypeEnum.LivestreamCohostInvite */,
12589
12996
  });
12590
12997
  return data;
12998
+ }, analytics() {
12999
+ // Use 'this' to avoid creating a new room object
13000
+ return new AmityRoomAnalytics(this);
12591
13001
  } });
12592
13002
  };
12593
13003
 
@@ -28966,6 +29376,10 @@ var index$b = /*#__PURE__*/Object.freeze({
28966
29376
  getRecordedUrl: getRecordedUrl,
28967
29377
  removeParticipant: removeParticipant,
28968
29378
  leaveRoom: leaveRoom,
29379
+ AmityRoomAnalytics: AmityRoomAnalytics,
29380
+ WatchSessionStorage: WatchSessionStorage,
29381
+ getWatchSessionStorage: getWatchSessionStorage,
29382
+ syncWatchSessions: syncWatchSessions,
28969
29383
  onRoomStartBroadcasting: onRoomStartBroadcasting,
28970
29384
  onRoomWaitingReconnect: onRoomWaitingReconnect,
28971
29385
  onRoomEndBroadcasting: onRoomEndBroadcasting,
@@ -30481,85 +30895,6 @@ var index$7 = /*#__PURE__*/Object.freeze({
30481
30895
  getPoll: getPoll
30482
30896
  });
30483
30897
 
30484
- const privateKey = "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDHo80SecH7FuF2\nhFYnb+l26/VN8UMLXAQFLnxciNTEwkGVFMpdezlH8rU2HtUJL4RETogbAOLVY0XM\njs6sPn8G1nALmh9qeDpUtVqFOVtBHxEZ910TLOtQiunjqJKO5nWdqZ71EC3OFluR\niGQkO84BiIFbv37ub7xl3S8XarbtKoLcyVpkDHi+1wx1pgCAn6gtBUgckPL5NR8j\nLseabl3HAXQfhTCKo4tmOFM2Dxwl1IUMmIJrJg/aIU/U0tj/1Eoo7mG0JcNWX19l\nW3EecCbi0ncCJOrkUdwlBrcjaMayaX/ubEwyUeTGiLdyc4L3GRLHjyK8xgVNXRMH\nbZWJ2a5NAgMBAAECggEASxuE+35zTFO/XydKgmvIGcWL9FbgMlXb7Vcf0nBoG945\nbiz0NVc2paraIhJXc608xbYF3qLmtAE1MVBI0ORyRdBHNxY024l/6H6SH60Ed+uI\nM4ysp5ourY6Vj+DLwpdRiI9YDjqYAQDIUmhNxJP7XPhOMoZI6st+xZQBM34ic/bv\nAMSJm9OZphSp3+qXVkFZztr2mxD2EZSJJLYxi8BCdgM2qhazalbcJ6zDKHCZWVWm\n8RRxDGldyMb/237JxETzP40tAlzOZDmBAbUgEnurDJ93RVDIE3rbZUshwgeQd18a\nem096mWgvB1AIKYgsTAR3pw+V19YWAjq/glP6fz8wQKBgQD/oQq+ukKF0PRgBeM5\ngeTjSwsdGppQLmf5ndujvoiz/TpdjDEPu6R8kigQr1rG2t4K/yfdZoI8RdmJD1al\n3Q7N9hofooSy4rj6E3txzWZCHJjHad2cnCp/O26HiReGAl7wTcfTmNdiFHhZQzm5\nJBkvWAiwuvQMNfEbnXxw6/vIDwKBgQDH7fX8gsc77JLvAWgp1MaQN/sbqVb6JeT1\nFQfR8E/WFCSmzQBtNzd5KgYuCeelwr/8DyYytvN2BzCYZXp73gI1jF3YlW5jVn74\nOY6TwQ095digwo6Z0yuxopdIOApKgAkL9PRKgNrqAf3NAyMua6lOGifzjDojC3KU\nfylQmxMn4wKBgHp2B9O/H0dEBw5JQ8W0+JX6yWQz7mEjGiR2/1W+XXb8hQ1zr709\nw1r6Gb+EghRpnZ3fBpYGGbYOMFx8wKHM+N6qW3F0ReX8v2juFGE8aRSa5oYBrWzt\nU16Idjbv8hj84cZ1PJmdyvDtpYn9rpWHOZl4rxEbPvbqkIsOMyNVqdT5AoGAOSge\nmwIIU2le2FVeohbibXiToWTYKMuMmURZ5/r72AgKMmWJKbAPe+Q3wBG01/7FRBpQ\noU8Ma0HC8s6QJbliiEyIx9JwrJWd1vkdecBHONrtA4ibm/5zD2WcOllLF+FitLhi\n3qnX6+6F0IaFGFBPJrTzlv0P4dTz/OAdv52V7GECgYEA2TttOKBAqWllgOaZOkql\nLVMJVmgR7s6tLi1+cEP8ZcapV9aRbRzTAKXm4f8AEhtlG9F9kCOvHYCYGi6JaiWJ\nZkHjeex3T+eE6Di6y5Bm/Ift5jtVhJ4jCVwHOKTMej79NPUFTJfv8hCo29haBDv6\nRXFrv+T21KCcw8k3sJeJWWQ=\n-----END PRIVATE KEY-----";
30485
- /*
30486
- * The crypto algorithm used for importing key and signing string
30487
- */
30488
- const ALGORITHM = {
30489
- name: 'RSASSA-PKCS1-v1_5',
30490
- hash: { name: 'SHA-256' },
30491
- };
30492
- /*
30493
- * IMPORTANT!
30494
- * If you are recieving key from other platforms use an online tool to convert
30495
- * the PKCS1 to PKCS8. For instance the key from Android SDK is of the format
30496
- * PKCS1.
30497
- *
30498
- * If recieving from the platform, verify if it's already in the expected
30499
- * format. Otherwise the crypto.subtle.importKey will throw a DOMException
30500
- */
30501
- const PRIVATE_KEY_SIGNATURE = 'pkcs8';
30502
- /*
30503
- * Ensure that the private key in the .env follows this format
30504
- */
30505
- const PEM_HEADER = '-----BEGIN PRIVATE KEY-----';
30506
- const PEM_FOOTER = '-----END PRIVATE KEY-----';
30507
- /*
30508
- * The crypto.subtle.sign function returns an ArrayBuffer whereas the server
30509
- * expects a base64 string. This util helps facilitate that process
30510
- */
30511
- function base64FromArrayBuffer(buffer) {
30512
- const uint8Array = new Uint8Array(buffer);
30513
- let binary = '';
30514
- uint8Array.forEach(byte => {
30515
- binary += String.fromCharCode(byte);
30516
- });
30517
- return jsBase64.btoa(binary);
30518
- }
30519
- /*
30520
- * Convert a string into an ArrayBuffer
30521
- * from https://developers.google.com/web/updates/2012/06/How-to-convert-ArrayBuffer-to-and-from-String
30522
- *
30523
- * Solely used by the importPrivateKey method
30524
- */
30525
- function str2ab(str) {
30526
- const buf = new ArrayBuffer(str.length);
30527
- const bufView = new Uint8Array(buf);
30528
- for (let i = 0, strLen = str.length; i < strLen; i += 1) {
30529
- bufView[i] = str.charCodeAt(i);
30530
- }
30531
- return buf;
30532
- }
30533
- function importPrivateKey(pem) {
30534
- // fetch the part of the PEM string between header and footer
30535
- const pemContents = pem.substring(PEM_HEADER.length, pem.length - PEM_FOOTER.length);
30536
- /*
30537
- * base64 decode the string to get the binary data
30538
- */
30539
- const binaryDerString = jsBase64.atob(pemContents);
30540
- // convert from a binary string to an ArrayBuffer
30541
- const binaryDer = str2ab(binaryDerString);
30542
- return crypto.subtle.importKey(PRIVATE_KEY_SIGNATURE, binaryDer, ALGORITHM, false, ['sign']);
30543
- }
30544
- async function createSignature({ timestamp, streams, }) {
30545
- const dataStr = streams
30546
- .map(item => Object.keys(item)
30547
- .sort()
30548
- .map(key => `${key}=${item[key]}`)
30549
- .join('&'))
30550
- .join(';');
30551
- /*
30552
- * nonceStr needs to be unique for each request
30553
- */
30554
- const nonceStr = uuid__default["default"].v4();
30555
- const signStr = `nonceStr=${nonceStr}&timestamp=${timestamp}&data=${dataStr}==`;
30556
- const encoder = new TextEncoder();
30557
- const data = encoder.encode(signStr);
30558
- const key = await importPrivateKey(privateKey);
30559
- const sign = await crypto.subtle.sign(ALGORITHM, key, data);
30560
- return { signature: base64FromArrayBuffer(sign), nonceStr };
30561
- }
30562
-
30563
30898
  async function syncUsage({ bufferCurrentUsage, getActiveStreams, updateUsage, dispose, }) {
30564
30899
  const streams = bufferCurrentUsage();
30565
30900
  if (!streams.length)