synxed-sdk 0.1.0 → 0.1.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 +86 -38
- package/dist/index.d.mts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +39 -17
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +39 -17
- package/dist/index.mjs.map +1 -1
- package/package.json +7 -6
package/README.md
CHANGED
|
@@ -7,11 +7,12 @@ The official Synxed SDK for frontend developers to integrate high-quality music
|
|
|
7
7
|
|
|
8
8
|
## Features
|
|
9
9
|
|
|
10
|
-
- **Simple Integration**: Play songs or playlists with just a few lines of code.
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
10
|
+
- ** Simple Integration**: Play songs or playlists with just a few lines of code.
|
|
11
|
+
- **🎧 High-Fidelity Streaming**: Robust HLS support via `hls.js` for seamless playback across all browsers.
|
|
12
|
+
- **📊 Built-in Analytics**: Automatic session tracking and stream event reporting.
|
|
13
|
+
- **🛠 Framework Agnostic**: Works with React, Vue, Angular, or Vanilla JS.
|
|
14
|
+
- **🔒 Secure**: Designed for private, signed-URL streaming with backend proxy support.
|
|
15
|
+
- **💪 Type Safe**: Fully written in TypeScript with comprehensive definitions.
|
|
15
16
|
|
|
16
17
|
## Installation
|
|
17
18
|
|
|
@@ -19,28 +20,79 @@ The official Synxed SDK for frontend developers to integrate high-quality music
|
|
|
19
20
|
npm install synxed-sdk
|
|
20
21
|
```
|
|
21
22
|
|
|
23
|
+
> **Note**: For HLS streaming support in browsers like Chrome, Firefox, and Edge, please ensure `hls.js` is installed in your project.
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npm install hls.js
|
|
27
|
+
```
|
|
28
|
+
|
|
22
29
|
## Quick Start
|
|
23
30
|
|
|
31
|
+
### Initialize the Player
|
|
32
|
+
|
|
24
33
|
```typescript
|
|
25
|
-
import { SynxedPlayer } from
|
|
34
|
+
import { SynxedPlayer } from "synxed-sdk";
|
|
26
35
|
|
|
27
36
|
const player = new SynxedPlayer({
|
|
28
|
-
apiKey:
|
|
29
|
-
serverUrl:
|
|
30
|
-
autoConnect: true
|
|
37
|
+
apiKey: "YOUR_SYNXED_API_KEY",
|
|
38
|
+
serverUrl: "https://api.synxed.com", // or your local backend URL
|
|
39
|
+
autoConnect: true,
|
|
40
|
+
});
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Play a Playlist
|
|
44
|
+
|
|
45
|
+
Provide a playlist code generated from the Synxed platform.
|
|
46
|
+
|
|
47
|
+
```typescript
|
|
48
|
+
// Start playback from a playlist
|
|
49
|
+
player.playPlaylist({
|
|
50
|
+
playlistCode: "sxpl_VZCCGQAQJV",
|
|
31
51
|
});
|
|
52
|
+
```
|
|
32
53
|
|
|
33
|
-
|
|
34
|
-
player.playSong({ catalogTrackId: 'track-uuid-here' });
|
|
54
|
+
### Play a Single Song
|
|
35
55
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
56
|
+
```typescript
|
|
57
|
+
// Play a song from the global catalog
|
|
58
|
+
player.playSong({
|
|
59
|
+
catalogTrackId: "2dcad8e0-3695-4971-9e35-f762f3f9d3a5",
|
|
39
60
|
});
|
|
40
61
|
|
|
41
|
-
//
|
|
42
|
-
player.
|
|
43
|
-
|
|
62
|
+
// Or an internal track from your own library
|
|
63
|
+
player.playSong({
|
|
64
|
+
internalTrackId: "track-uuid-here",
|
|
65
|
+
});
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Control Playback
|
|
69
|
+
|
|
70
|
+
```typescript
|
|
71
|
+
player.pause();
|
|
72
|
+
player.resume();
|
|
73
|
+
player.stop();
|
|
74
|
+
player.seek(30000); // Seek to 30 seconds
|
|
75
|
+
player.setVolume(0.8);
|
|
76
|
+
player.skip(); // Skip to next track in playlist
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Listening for Events
|
|
80
|
+
|
|
81
|
+
```typescript
|
|
82
|
+
// Track state changes (idle, loading, playing, paused, error)
|
|
83
|
+
player.on("stateChange", (state) => {
|
|
84
|
+
console.log("Player status:", state.status);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
// High-resolution time updates (60fps)
|
|
88
|
+
player.on("timeUpdate", ({ currentTime, duration }) => {
|
|
89
|
+
const progress = (currentTime / duration) * 100;
|
|
90
|
+
console.log(`Progress: ${progress.toFixed(2)}%`);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
// Error handling
|
|
94
|
+
player.on("error", (err) => {
|
|
95
|
+
console.error("Playback Error:", err.message);
|
|
44
96
|
});
|
|
45
97
|
```
|
|
46
98
|
|
|
@@ -48,33 +100,29 @@ player.on('timeUpdate', ({ currentTime, duration }) => {
|
|
|
48
100
|
|
|
49
101
|
### `new SynxedPlayer(config)`
|
|
50
102
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
- `
|
|
54
|
-
- `serverUrl`: The Synxed backend URL.
|
|
55
|
-
- `autoConnect`: (Optional) Whether to connect immediately.
|
|
103
|
+
- `apiKey`: `string` (Required) Your developer API key.
|
|
104
|
+
- `serverUrl`: `string` (Required) Your Synxed backend URL.
|
|
105
|
+
- `autoConnect`: `boolean` (Default: `true`) Connect to the streaming socket immediately.
|
|
56
106
|
|
|
57
107
|
### Methods
|
|
58
108
|
|
|
59
|
-
- `playSong(options)`: Plays a single track
|
|
60
|
-
- `playPlaylist(options)`: Starts playback from a
|
|
61
|
-
- `pause()`: Pauses the current
|
|
62
|
-
- `resume()`: Resumes
|
|
63
|
-
- `stop()`: Stops playback and
|
|
64
|
-
- `skip()`: Skips to the next track in the
|
|
65
|
-
- `seek(ms)`: Seeks to a specific position in milliseconds.
|
|
66
|
-
- `setVolume(0-1)`:
|
|
67
|
-
- `destroy()`: Cleans up the player and disconnects
|
|
109
|
+
- `playSong(options)`: `Promise<void>` Plays a single track by `catalogTrackId` or `internalTrackId`.
|
|
110
|
+
- `playPlaylist(options)`: `Promise<void>` Starts playback from a `playlistCode`.
|
|
111
|
+
- `pause()`: `void` Pauses the current stream.
|
|
112
|
+
- `resume()`: `void` Resumes a paused stream.
|
|
113
|
+
- `stop()`: `void` Stops playback and releases audio resources.
|
|
114
|
+
- `skip()`: `void` Skips to the next track in the playlist.
|
|
115
|
+
- `seek(ms)`: `void` Seeks to a specific position in milliseconds.
|
|
116
|
+
- `setVolume(0-1)`: `void` Sets the volume.
|
|
117
|
+
- `destroy()`: `void` Cleans up the player, listeners, and disconnects.
|
|
68
118
|
|
|
69
119
|
### Events
|
|
70
120
|
|
|
71
|
-
- `stateChange`: Fired when the
|
|
72
|
-
- `timeUpdate`:
|
|
73
|
-
- `trackChange`: Fired when
|
|
74
|
-
- `
|
|
75
|
-
- `disconnected`: Fired when the socket disconnects.
|
|
76
|
-
- `error`: Fired on any player or connection error.
|
|
121
|
+
- `stateChange`: `(state: PlayerState)` Fired when the engine state changes.
|
|
122
|
+
- `timeUpdate`: `({ currentTime, duration })` Fired during playback.
|
|
123
|
+
- `trackChange`: `(track: any)` Fired when a new track starts playing in a playlist.
|
|
124
|
+
- `error`: `(error: Error)` Fired on playback or connection failures.
|
|
77
125
|
|
|
78
126
|
## License
|
|
79
127
|
|
|
80
|
-
MIT
|
|
128
|
+
MIT © [Synxed](https://synxed.com)
|
package/dist/index.d.mts
CHANGED
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
'use strict';var socket_ioClient=require('socket.io-client'),k=require('protobufjs'),howler=require('howler');function _interopNamespace(e){if(e&&e.__esModule)return e;var n=Object.create(null);if(e){Object.keys(e).forEach(function(k){if(k!=='default'){var d=Object.getOwnPropertyDescriptor(e,k);Object.defineProperty(n,k,d.get?d:{enumerable:true,get:function(){return e[k]}});}})}n.default=e;return Object.freeze(n)}var k__namespace=/*#__PURE__*/_interopNamespace(k);var
|
|
1
|
+
'use strict';var socket_ioClient=require('socket.io-client'),k=require('protobufjs'),howler=require('howler');function _interopNamespace(e){if(e&&e.__esModule)return e;var n=Object.create(null);if(e){Object.keys(e).forEach(function(k){if(k!=='default'){var d=Object.getOwnPropertyDescriptor(e,k);Object.defineProperty(n,k,d.get?d:{enumerable:true,get:function(){return e[k]}});}})}n.default=e;return Object.freeze(n)}var k__namespace=/*#__PURE__*/_interopNamespace(k);var C=`
|
|
2
2
|
syntax = "proto3";
|
|
3
3
|
|
|
4
4
|
enum ContentKind {
|
|
@@ -18,30 +18,52 @@ enum ErrorCode {
|
|
|
18
18
|
BAD_PROTOBUF = 6;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
+
enum SdkControlAction {
|
|
22
|
+
CONTROL_UNSPECIFIED = 0;
|
|
23
|
+
CONTROL_PLAY = 1;
|
|
24
|
+
CONTROL_PAUSE = 2;
|
|
25
|
+
CONTROL_STOP = 3;
|
|
26
|
+
CONTROL_SEEK = 4;
|
|
27
|
+
}
|
|
28
|
+
|
|
21
29
|
message SdkClientInit {
|
|
22
|
-
ContentKind
|
|
23
|
-
string
|
|
24
|
-
string
|
|
25
|
-
string
|
|
26
|
-
string
|
|
27
|
-
string
|
|
28
|
-
string
|
|
29
|
-
string
|
|
30
|
-
string
|
|
30
|
+
ContentKind contentKind = 1;
|
|
31
|
+
string catalogTrackId = 2;
|
|
32
|
+
string internalTrackId = 3;
|
|
33
|
+
string playlistCode = 4;
|
|
34
|
+
string categoryQuery = 5;
|
|
35
|
+
string listenerId = 6;
|
|
36
|
+
string deviceType = 7;
|
|
37
|
+
string countryCode = 8;
|
|
38
|
+
string region = 9;
|
|
39
|
+
string protocolVersion = 10;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
message SdkClientControl {
|
|
43
|
+
SdkControlAction action = 1;
|
|
44
|
+
uint32 positionMs = 2;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
message SdkClientAnalytics {
|
|
48
|
+
string eventType = 1;
|
|
49
|
+
uint32 positionMs = 2;
|
|
50
|
+
string extraJson = 3;
|
|
31
51
|
}
|
|
32
52
|
|
|
33
53
|
message SdkClientEnvelope {
|
|
34
54
|
oneof payload {
|
|
35
55
|
SdkClientInit init = 1;
|
|
56
|
+
SdkClientControl control = 2;
|
|
57
|
+
SdkClientAnalytics analytics = 3;
|
|
36
58
|
}
|
|
37
59
|
}
|
|
38
60
|
|
|
39
61
|
message SdkServerInitAck {
|
|
40
|
-
string
|
|
41
|
-
string
|
|
42
|
-
bool
|
|
43
|
-
uint32
|
|
44
|
-
string
|
|
62
|
+
string sessionId = 1;
|
|
63
|
+
string playbackUrl = 2;
|
|
64
|
+
bool isHls = 3;
|
|
65
|
+
uint32 heartbeatIntervalMs = 4;
|
|
66
|
+
string contentSummary = 5;
|
|
45
67
|
}
|
|
46
68
|
|
|
47
69
|
message SdkServerError {
|
|
@@ -51,9 +73,9 @@ message SdkServerError {
|
|
|
51
73
|
|
|
52
74
|
message SdkServerEnvelope {
|
|
53
75
|
oneof payload {
|
|
54
|
-
SdkServerInitAck
|
|
76
|
+
SdkServerInitAck initAck = 1;
|
|
55
77
|
SdkServerError error = 2;
|
|
56
78
|
}
|
|
57
79
|
}
|
|
58
|
-
`,
|
|
80
|
+
`,T=k__namespace.parse(C).root,f=T.lookupType("SdkClientEnvelope"),S=T.lookupType("SdkServerEnvelope"),E=(i=>(i[i.UNSPECIFIED=0]="UNSPECIFIED",i[i.SONG=1]="SONG",i[i.PLAYLIST=2]="PLAYLIST",i[i.CATEGORY=3]="CATEGORY",i))(E||{}),x=(o=>(o[o.UNSPECIFIED=0]="UNSPECIFIED",o[o.UNAUTHORIZED=1]="UNAUTHORIZED",o[o.VALIDATION_ERROR=2]="VALIDATION_ERROR",o[o.NOT_FOUND=3]="NOT_FOUND",o[o.PROCESSING=4]="PROCESSING",o[o.SERVICE_UNAVAILABLE=5]="SERVICE_UNAVAILABLE",o[o.BAD_PROTOBUF=6]="BAD_PROTOBUF",o))(x||{});var l=class{static encodeClientEnvelope(n){let t=f.create(n);return f.encode(t).finish()}static decodeServerEnvelope(n){let t=S.decode(n);return S.toObject(t,{enums:String,longs:String,bytes:String,defaults:true,oneofs:true})}};var a=class{constructor(){this.listeners=new Map;}on(n,t){this.listeners.has(n)||this.listeners.set(n,new Set),this.listeners.get(n).add(t);}off(n,t){let e=this.listeners.get(n);e&&e.delete(t);}once(n,t){let e=((...i)=>{t(...i),this.off(n,e);});this.on(n,e);}emit(n,...t){let e=this.listeners.get(n);e&&e.forEach(i=>i(...t));}removeAllListeners(){this.listeners.clear();}};var u=class extends a{constructor(){super();this.socket=null;this.apiKey=null;this.serverUrl=null;}connect(t,e){if(this.socket?.connected)return;this.apiKey=t,this.serverUrl=e;let i=e.endsWith("/")?e.slice(0,-1):e;this.socket=socket_ioClient.io(`${i}/sdk`,{auth:{apiKey:t},transports:["websocket"]}),this.socket.on("connect",()=>{this.emit("connected");}),this.socket.on("disconnect",s=>{this.emit("disconnected",s);}),this.socket.on("connect_error",s=>{this.emit("error",s);}),this.socket.on("d",s=>{try{let r=s instanceof Uint8Array?s:new Uint8Array(s),o=l.decodeServerEnvelope(r);this.emit("message",o);}catch(r){this.emit("error",new Error(`Failed to decode message: ${r}`));}});}async waitForConnection(){if(console.log("[Synxed] Waiting for connection..."),this.socket?.connected){console.log("[Synxed] Already connected");return}return new Promise((t,e)=>{let i=()=>{console.log("[Synxed] Socket connected event fired"),r(),t();},s=o=>{console.error("[Synxed] Socket connection error:",o),r(),e(o);},r=()=>{this.socket?.off("connect",i),this.socket?.off("connect_error",s);};this.socket?.once("connect",i),this.socket?.once("connect_error",s),this.socket||(console.error("[Synxed] No socket instance found"),e(new Error("Socket not initialized. Call connect() first.")));})}disconnect(){this.socket&&(this.socket.disconnect(),this.socket=null);}sendInit(t){if(!this.socket?.connected)throw new Error("Socket not connected");console.log("[Synxed] Sending init packet:",t);let e={init:t},i=l.encodeClientEnvelope(e);this.socket.emit("d",i);}sendControl(t){if(!this.socket?.connected)return;let e={control:t},i=l.encodeClientEnvelope(e);this.socket.emit("d",i);}sendAnalytics(t){if(!this.socket?.connected)return;let e={analytics:t},i=l.encodeClientEnvelope(e);this.socket.emit("d",i);}get isConnected(){return this.socket?.connected||false}};var h=class extends a{constructor(){super();this.howl=null;this.hls=null;this.audioEl=null;this.updateTimer=null;}async load(t,e){this.stop(),this.emit("loading"),console.log("[Synxed] AudioEngine loading URL:",t,"isHls:",e);let i=/^((?!chrome|android).)*safari/i.test(navigator.userAgent);if(e&&!i)try{let{default:s}=await import('hls.js');if(s.isSupported()){console.log("[Synxed] Using Hls.js for playback");let o=new URL(t).search;this.hls=new s,this.audioEl=new Audio,this.hls.loadSource(t),this.hls.attachMedia(this.audioEl),this.audioEl.onplay=()=>{this.emit("playing"),this.startTimeUpdateLoop();},this.audioEl.onpause=()=>{this.emit("paused"),this.stopTimeUpdateLoop();},this.audioEl.onended=()=>{this.emit("ended"),this.stopTimeUpdateLoop();},this.audioEl.onerror=v=>{console.error("[Synxed] HLS Audio error:",v),this.emit("error",v);},this.audioEl.onloadedmetadata=()=>{this.emit("loaded");},this.hls.on(s.Events.ERROR,(v,g)=>{g.fatal&&(console.error("[Synxed] Fatal HLS error:",g),this.emit("error",g));});return}}catch{console.warn("[Synxed] hls.js not found or error loading, falling back to native");}this.howl=new howler.Howl({src:[t],html5:true,format:e?["m3u8"]:void 0,onload:()=>{console.log("[Synxed] AudioEngine loaded successfully"),this.emit("loaded");},onloaderror:(s,r)=>{console.error("[Synxed] AudioEngine load error:",r,"ID:",s),this.emit("error",r);},onplay:()=>{this.emit("playing"),this.startTimeUpdateLoop();},onpause:()=>{this.emit("paused"),this.stopTimeUpdateLoop();},onstop:()=>{this.emit("stopped"),this.stopTimeUpdateLoop();},onend:()=>{this.emit("ended"),this.stopTimeUpdateLoop();}});}play(){this.audioEl?this.audioEl.play().catch(t=>console.error("[Synxed] Play failed:",t)):this.howl?.play();}pause(){this.audioEl?this.audioEl.pause():this.howl?.pause();}stop(){this.hls&&(this.hls.destroy(),this.hls=null),this.audioEl&&(this.audioEl.pause(),this.audioEl.src="",this.audioEl=null),this.howl&&(this.howl.stop(),this.howl.unload(),this.howl=null),this.stopTimeUpdateLoop();}seek(t){this.audioEl?this.audioEl.currentTime=t/1e3:this.howl?.seek(t/1e3);}setVolume(t){this.audioEl&&(this.audioEl.volume=t),this.howl&&this.howl.volume(t);}get duration(){return this.audioEl?this.audioEl.duration*1e3:(this.howl?.duration()||0)*1e3}get currentTime(){return this.audioEl?this.audioEl.currentTime*1e3:(this.howl?.seek()||0)*1e3}startTimeUpdateLoop(){this.stopTimeUpdateLoop();let t=()=>{(this.audioEl?!this.audioEl.paused:this.howl?.playing())&&(this.emit("timeupdate",{currentTime:this.currentTime,duration:this.duration}),this.updateTimer=requestAnimationFrame(t));};this.updateTimer=requestAnimationFrame(t);}stopTimeUpdateLoop(){this.updateTimer!==null&&(cancelAnimationFrame(this.updateTimer),this.updateTimer=null);}};var p=class extends a{constructor(){super();this.queue=[];this.currentIndex=-1;}setQueue(t){this.queue=t,this.currentIndex=t.length>0?0:-1,this.emit("queueUpdated",this.queue);}getCurrentTrack(){return this.currentIndex>=0&&this.currentIndex<this.queue.length?this.queue[this.currentIndex]:null}next(){if(this.currentIndex<this.queue.length-1){this.currentIndex++;let t=this.getCurrentTrack();return this.emit("trackChanged",t),t}return null}previous(){if(this.currentIndex>0){this.currentIndex--;let t=this.getCurrentTrack();return this.emit("trackChanged",t),t}return null}skipTo(t){if(t>=0&&t<this.queue.length){this.currentIndex=t;let e=this.getCurrentTrack();return this.emit("trackChanged",e),e}return null}get hasNext(){return this.currentIndex<this.queue.length-1}get hasPrevious(){return this.currentIndex>0}};var c=class extends Error{constructor(t,e){super(t);this.code=e;this.name="SynxedError";}},m=class extends c{constructor(n){super(n),this.name="SynxedConnectionError";}},y=class extends c{constructor(n){super(typeof n=="string"?n:"Playback failed"),this.name="SynxedPlaybackError";}},I=class extends c{constructor(n){super(n),this.name="SynxedProtocolError";}};var A=class extends a{constructor(t){super();this.status="idle";this.config=t,this.transport=new u,this.audio=new h,this.playlist=new p,this.setupListeners(),t.autoConnect&&this.connect();}setupListeners(){this.transport.on("connected",()=>this.emit("connected")),this.transport.on("disconnected",t=>this.emit("disconnected",t)),this.transport.on("error",t=>this.emit("error",new m(t.message))),this.transport.on("message",t=>this.handleServerMessage(t)),this.audio.on("playing",()=>this.updateStatus("playing")),this.audio.on("paused",()=>this.updateStatus("paused")),this.audio.on("stopped",()=>this.updateStatus("idle")),this.audio.on("loading",()=>this.updateStatus("loading")),this.audio.on("error",t=>this.emit("error",new y(t))),this.audio.on("timeupdate",t=>this.emit("timeUpdate",t)),this.audio.on("ended",()=>this.handleTrackEnded());}connect(){this.transport.connect(this.config.apiKey,this.config.serverUrl);}async playSong(t){this.transport.isConnected||this.connect(),await this.transport.waitForConnection(),this.transport.sendInit({contentKind:1,catalogTrackId:t.catalogTrackId,internalTrackId:t.internalTrackId,listenerId:t.listenerId});}async playPlaylist(t){this.transport.isConnected||this.connect(),await this.transport.waitForConnection(),this.transport.sendInit({contentKind:2,playlistCode:t.playlistCode,listenerId:t.listenerId});}pause(){this.audio.pause(),this.transport.sendControl({action:2,positionMs:Math.floor(this.audio.currentTime*1e3)});}resume(){this.audio.play(),this.transport.sendControl({action:1,positionMs:Math.floor(this.audio.currentTime*1e3)});}stop(){this.audio.stop(),this.transport.sendControl({action:3,positionMs:Math.floor(this.audio.currentTime*1e3)});}skip(){let t=this.playlist.next();t&&this.playSong({catalogTrackId:t.id});}seek(t){this.audio.seek(t),this.transport.sendControl({action:4,positionMs:t});}setVolume(t){this.audio.setVolume(t);}emitAnalytics(t,e,i){this.transport.sendAnalytics({eventType:t,positionMs:e??Math.floor(this.audio.currentTime*1e3),extraJson:i?JSON.stringify(i):void 0});}async handleServerMessage(t){if(console.log("[Synxed] Received server message:",t),t.initAck){let e=t.initAck;if(console.log("[Synxed] Loading playback URL:",e.playbackUrl,"isHls:",e.isHls),await this.audio.load(e.playbackUrl,e.isHls),this.audio.play(),this.emitAnalytics("stream_start"),e.contentSummary)try{let i=JSON.parse(e.contentSummary);i.tracks&&this.playlist.setQueue(i.tracks);}catch{}}else t.error&&this.emit("error",new c(t.error.message,t.error.code));}handleTrackEnded(){this.playlist.hasNext?this.skip():this.updateStatus("idle");}updateStatus(t){this.status=t,this.emit("stateChange",{status:t,currentTime:this.audio.currentTime,duration:this.audio.duration,volume:1});}destroy(){this.audio.stop(),this.transport.disconnect(),this.removeAllListeners();}};exports.ContentKind=E;exports.ErrorCode=x;exports.SynxedConnectionError=m;exports.SynxedError=c;exports.SynxedPlaybackError=y;exports.SynxedPlayer=A;exports.SynxedProtocolError=I;//# sourceMappingURL=index.js.map
|
|
59
81
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/proto/sdk-streaming.ts","../src/transport/ProtocolCodec.ts","../src/core/EventEmitter.ts","../src/transport/TransportManager.ts","../src/audio/AudioEngine.ts","../src/playlist/PlaylistManager.ts","../src/core/errors.ts","../src/core/SynxedPlayer.ts"],"names":["schema","root","k","SdkClientEnvelope","SdkServerEnvelope","ContentKind","ErrorCode","ProtocolCodec","payload","message","data","decoded","EventEmitter","event","handler","set","onceHandler","args","TransportManager","apiKey","serverUrl","io","reason","error","uint8Array","err","params","bytes","AudioEngine","url","isHls","Howl","id","ms","volume","update","PlaylistManager","tracks","track","index","SynxedError","code","SynxedConnectionError","SynxedPlaybackError","SynxedProtocolError","SynxedPlayer","config","time","options","nextTrack","ack","summary","status"],"mappings":"wdAMMA,CAAAA,CAAS;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAAA,CA2DTC,CAAAA,CAAgBC,YAAA,CAAA,KAAA,CAAMF,CAAM,CAAA,CAAE,KAEvBG,CAAAA,CAAoBF,CAAAA,CAAK,UAAA,CAAW,mBAAmB,EACvDG,CAAAA,CAAoBH,CAAAA,CAAK,UAAA,CAAW,mBAAmB,EAExDI,CAAAA,CAAAA,CAAAA,CAAAA,GACVA,CAAAA,CAAAA,CAAAA,CAAA,WAAA,CAAc,CAAA,CAAA,CAAd,cACAA,CAAAA,CAAAA,CAAAA,CAAA,IAAA,CAAO,CAAA,CAAA,CAAP,MAAA,CACAA,IAAA,QAAA,CAAW,CAAA,CAAA,CAAX,UAAA,CACAA,CAAAA,CAAAA,CAAAA,CAAA,SAAW,CAAA,CAAA,CAAX,UAAA,CAJUA,CAAAA,CAAAA,EAAAA,CAAAA,EAAA,EAAA,CAAA,CAOAC,OACVA,CAAAA,CAAAA,CAAAA,CAAA,WAAA,CAAc,CAAA,CAAA,CAAd,aAAA,CACAA,CAAAA,CAAAA,CAAAA,CAAA,YAAA,CAAe,CAAA,CAAA,CAAf,cAAA,CACAA,IAAA,gBAAA,CAAmB,CAAA,CAAA,CAAnB,kBAAA,CACAA,CAAAA,CAAAA,CAAAA,CAAA,UAAY,CAAA,CAAA,CAAZ,WAAA,CACAA,CAAAA,CAAAA,CAAAA,CAAA,UAAA,CAAa,GAAb,YAAA,CACAA,CAAAA,CAAAA,CAAAA,CAAA,mBAAA,CAAsB,CAAA,CAAA,CAAtB,sBACAA,CAAAA,CAAAA,CAAAA,CAAA,YAAA,CAAe,CAAA,CAAA,CAAf,cAAA,CAPUA,OAAA,EAAA,EC3EL,IAAMC,CAAAA,CAAN,KAAoB,CAIzB,OAAO,oBAAA,CAAqBC,CAAAA,CAA0B,CACpD,IAAMC,CAAAA,CAAUN,CAAAA,CAAkB,MAAA,CAAOK,CAAO,CAAA,CAChD,OAAOL,CAAAA,CAAkB,MAAA,CAAOM,CAAO,CAAA,CAAE,MAAA,EAC3C,CAKA,OAAO,oBAAA,CAAqBC,CAAAA,CAAuB,CACjD,IAAMC,EAAUP,CAAAA,CAAkB,MAAA,CAAOM,CAAI,CAAA,CAC7C,OAAON,CAAAA,CAAkB,QAAA,CAASO,CAAAA,CAAS,CACzC,MAAO,MAAA,CACP,KAAA,CAAO,MAAA,CACP,KAAA,CAAO,OACP,QAAA,CAAU,IAAA,CACV,MAAA,CAAQ,IACV,CAAC,CACH,CACF,CAAA,CCtBO,IAAMC,EAAN,KAAuD,CAAvD,WAAA,EAAA,CACL,IAAA,CAAQ,UAA6C,IAAI,IAAA,CAEzD,EAAA,CAA2BC,CAAAA,CAAUC,EAA0B,CACxD,IAAA,CAAK,SAAA,CAAU,GAAA,CAAID,CAAK,CAAA,EAC3B,IAAA,CAAK,SAAA,CAAU,GAAA,CAAIA,EAAO,IAAI,GAAK,CAAA,CAErC,IAAA,CAAK,UAAU,GAAA,CAAIA,CAAK,CAAA,CAAG,GAAA,CAAIC,CAAO,EACxC,CAEA,GAAA,CAA4BD,CAAAA,CAAUC,EAA0B,CAC9D,IAAMC,CAAAA,CAAM,IAAA,CAAK,SAAA,CAAU,GAAA,CAAIF,CAAK,CAAA,CAChCE,GACFA,CAAAA,CAAI,MAAA,CAAOD,CAAO,EAEtB,CAEA,IAAA,CAA6BD,CAAAA,CAAUC,CAAAA,CAA0B,CAC/D,IAAME,CAAAA,EAAe,CAAA,GAAIC,CAAAA,GAAgB,CACvCH,EAAQ,GAAGG,CAAI,CAAA,CACf,IAAA,CAAK,IAAIJ,CAAAA,CAAOG,CAAwB,EAC1C,CAAA,CAAA,CACA,KAAK,EAAA,CAAGH,CAAAA,CAAOG,CAAW,EAC5B,CAEU,IAAA,CAA6BH,CAAAA,CAAAA,GAAaI,CAAAA,CAAmC,CACrF,IAAMF,CAAAA,CAAM,IAAA,CAAK,SAAA,CAAU,GAAA,CAAIF,CAAK,CAAA,CAChCE,CAAAA,EACFA,CAAAA,CAAI,OAAA,CAASD,GAAYA,CAAAA,CAAQ,GAAGG,CAAI,CAAC,EAE7C,CAEA,kBAAA,EAA2B,CACzB,IAAA,CAAK,UAAU,KAAA,GACjB,CACF,CAAA,CC1BO,IAAMC,CAAAA,CAAN,cAA+BN,CAA8B,CAKlE,aAAc,CACZ,KAAA,EAAM,CALR,IAAA,CAAQ,OAAwB,IAAA,CAChC,IAAA,CAAQ,MAAA,CAAwB,IAAA,CAChC,IAAA,CAAQ,SAAA,CAA2B,KAInC,CAKA,QAAQO,CAAAA,CAAgBC,CAAAA,CAAyB,CAC3C,IAAA,CAAK,QAAQ,SAAA,GAEjB,IAAA,CAAK,MAAA,CAASD,CAAAA,CACd,KAAK,SAAA,CAAYC,CAAAA,CAEjB,IAAA,CAAK,MAAA,CAASC,mBAAG,CAAA,EAAGD,CAAS,CAAA,IAAA,CAAA,CAAQ,CACnC,KAAM,CAAE,MAAA,CAAAD,CAAO,CAAA,CACf,WAAY,CAAC,WAAW,CAC1B,CAAC,EAED,IAAA,CAAK,MAAA,CAAO,EAAA,CAAG,SAAA,CAAW,IAAM,CAC9B,IAAA,CAAK,IAAA,CAAK,WAAW,EACvB,CAAC,CAAA,CAED,IAAA,CAAK,MAAA,CAAO,GAAG,YAAA,CAAeG,CAAAA,EAAW,CACvC,IAAA,CAAK,KAAK,cAAA,CAAgBA,CAAM,EAClC,CAAC,EAED,IAAA,CAAK,MAAA,CAAO,EAAA,CAAG,eAAA,CAAkBC,GAAU,CACzC,IAAA,CAAK,IAAA,CAAK,OAAA,CAASA,CAAK,EAC1B,CAAC,CAAA,CAED,IAAA,CAAK,OAAO,EAAA,CAAG,GAAA,CAAMb,CAAAA,EAAmC,CACtD,GAAI,CACF,IAAMc,CAAAA,CAAad,aAAgB,UAAA,CAAaA,CAAAA,CAAO,IAAI,UAAA,CAAWA,CAAI,CAAA,CACpEF,CAAAA,CAAUD,CAAAA,CAAc,oBAAA,CAAqBiB,CAAU,CAAA,CAC7D,IAAA,CAAK,IAAA,CAAK,SAAA,CAAWhB,CAAO,EAC9B,CAAA,MAASiB,CAAAA,CAAK,CACZ,KAAK,IAAA,CAAK,OAAA,CAAS,IAAI,KAAA,CAAM,6BAA6BA,CAAG,CAAA,CAAE,CAAC,EAClE,CACF,CAAC,CAAA,EACH,CAKA,UAAA,EAAmB,CACb,IAAA,CAAK,MAAA,GACP,IAAA,CAAK,MAAA,CAAO,YAAW,CACvB,IAAA,CAAK,MAAA,CAAS,IAAA,EAElB,CAKA,QAAA,CAASC,CAAAA,CAAmB,CAC1B,GAAI,CAAC,IAAA,CAAK,MAAA,EAAQ,SAAA,CAChB,MAAM,IAAI,KAAA,CAAM,sBAAsB,CAAA,CAGxC,IAAMlB,EAAU,CAAE,IAAA,CAAMkB,CAAO,CAAA,CACzBC,EAAQpB,CAAAA,CAAc,oBAAA,CAAqBC,CAAO,CAAA,CACxD,KAAK,MAAA,CAAO,IAAA,CAAK,GAAA,CAAKmB,CAAK,EAC7B,CAKA,IAAI,WAAA,EAAuB,CACzB,OAAO,IAAA,CAAK,MAAA,EAAQ,SAAA,EAAa,KACnC,CACF,CAAA,CCxEO,IAAMC,CAAAA,CAAN,cAA0BhB,CAA0B,CAIzD,WAAA,EAAc,CACZ,KAAA,GAJF,IAAA,CAAQ,IAAA,CAAoB,IAAA,CAC5B,IAAA,CAAQ,YAA6B,KAIrC,CAKA,IAAA,CAAKiB,CAAAA,CAAaC,EAAsB,CACtC,IAAA,CAAK,IAAA,EAAK,CACV,KAAK,IAAA,CAAK,SAAS,CAAA,CAKnB,IAAA,CAAK,KAAO,IAAIC,WAAAA,CAAK,CACnB,GAAA,CAAK,CAACF,CAAG,CAAA,CACT,KAAA,CAAO,IAAA,CACP,OAAQC,CAAAA,CAAQ,CAAC,MAAM,CAAA,CAAI,OAC3B,MAAA,CAAQ,IAAM,CACZ,IAAA,CAAK,KAAK,QAAQ,EACpB,CAAA,CACA,WAAA,CAAa,CAACE,CAAAA,CAAIP,CAAAA,GAAQ,CACxB,IAAA,CAAK,KAAK,OAAA,CAASA,CAAG,EACxB,CAAA,CACA,MAAA,CAAQ,IAAM,CACZ,IAAA,CAAK,KAAK,SAAS,CAAA,CACnB,IAAA,CAAK,mBAAA,GACP,CAAA,CACA,OAAA,CAAS,IAAM,CACb,KAAK,IAAA,CAAK,QAAQ,CAAA,CAClB,IAAA,CAAK,qBACP,CAAA,CACA,MAAA,CAAQ,IAAM,CACZ,IAAA,CAAK,IAAA,CAAK,SAAS,CAAA,CACnB,KAAK,kBAAA,GACP,CAAA,CACA,KAAA,CAAO,IAAM,CACX,IAAA,CAAK,IAAA,CAAK,OAAO,EACjB,IAAA,CAAK,kBAAA,GACP,CACF,CAAC,EACH,CAEA,IAAA,EAAa,CACX,KAAK,IAAA,EAAM,IAAA,GACb,CAEA,OAAc,CACZ,IAAA,CAAK,IAAA,EAAM,KAAA,GACb,CAEA,IAAA,EAAa,CACX,IAAA,CAAK,MAAM,IAAA,EAAK,CAChB,IAAA,CAAK,IAAA,EAAM,QAAO,CAClB,IAAA,CAAK,IAAA,CAAO,KACd,CAEA,IAAA,CAAKQ,CAAAA,CAAkB,CACrB,IAAA,CAAK,IAAA,EAAM,IAAA,CAAKA,CAAAA,CAAK,GAAI,EAC3B,CAEA,SAAA,CAAUC,CAAAA,CAAsB,CAC9B,KAAK,IAAA,EAAM,MAAA,CAAOA,CAAM,EAC1B,CAEA,IAAI,QAAA,EAAmB,CACrB,OAAA,CAAQ,KAAK,IAAA,EAAM,QAAA,EAAS,EAAK,CAAA,EAAK,GACxC,CAEA,IAAI,WAAA,EAAsB,CACxB,QAAQ,IAAA,CAAK,IAAA,EAAM,IAAA,EAAK,EAAe,GAAK,GAC9C,CAEQ,mBAAA,EAA4B,CAClC,KAAK,kBAAA,EAAmB,CACxB,IAAMC,CAAAA,CAAS,IAAM,CACf,IAAA,CAAK,IAAA,EAAM,OAAA,KACb,IAAA,CAAK,IAAA,CAAK,YAAA,CAAc,CACtB,YAAa,IAAA,CAAK,WAAA,CAClB,QAAA,CAAU,IAAA,CAAK,QACjB,CAAC,CAAA,CACD,IAAA,CAAK,WAAA,CAAc,sBAAsBA,CAAM,CAAA,EAEnD,CAAA,CACA,IAAA,CAAK,YAAc,qBAAA,CAAsBA,CAAM,EACjD,CAEQ,oBAA2B,CAC7B,IAAA,CAAK,WAAA,GAAgB,IAAA,GACvB,oBAAA,CAAqB,IAAA,CAAK,WAAW,CAAA,CACrC,KAAK,WAAA,CAAc,IAAA,EAEvB,CACF,CAAA,CCxGO,IAAMC,CAAAA,CAAN,cAA8BxB,CAA6B,CAIhE,aAAc,CACZ,KAAA,EAAM,CAJR,IAAA,CAAQ,MAAe,EAAC,CACxB,IAAA,CAAQ,YAAA,CAAuB,GAI/B,CAEA,QAAA,CAASyB,CAAAA,CAAqB,CAC5B,KAAK,KAAA,CAAQA,CAAAA,CACb,IAAA,CAAK,YAAA,CAAeA,EAAO,MAAA,CAAS,CAAA,CAAI,CAAA,CAAI,EAAA,CAC5C,IAAA,CAAK,IAAA,CAAK,cAAA,CAAgB,IAAA,CAAK,KAAK,EACtC,CAEA,eAAA,EAA8B,CAC5B,OAAI,IAAA,CAAK,YAAA,EAAgB,CAAA,EAAK,IAAA,CAAK,aAAe,IAAA,CAAK,KAAA,CAAM,MAAA,CACpD,IAAA,CAAK,MAAM,IAAA,CAAK,YAAY,CAAA,CAE9B,IACT,CAEA,IAAA,EAAmB,CACjB,GAAI,IAAA,CAAK,aAAe,IAAA,CAAK,KAAA,CAAM,MAAA,CAAS,CAAA,CAAG,CAC7C,IAAA,CAAK,YAAA,EAAA,CACL,IAAMC,CAAAA,CAAQ,IAAA,CAAK,eAAA,EAAgB,CACnC,OAAA,IAAA,CAAK,KAAK,cAAA,CAAgBA,CAAK,CAAA,CACxBA,CACT,CACA,OAAO,IACT,CAEA,QAAA,EAAuB,CACrB,GAAI,IAAA,CAAK,YAAA,CAAe,CAAA,CAAG,CACzB,IAAA,CAAK,YAAA,EAAA,CACL,IAAMA,CAAAA,CAAQ,KAAK,eAAA,EAAgB,CACnC,OAAA,IAAA,CAAK,IAAA,CAAK,eAAgBA,CAAK,CAAA,CACxBA,CACT,CACA,OAAO,IACT,CAEA,MAAA,CAAOC,CAAAA,CAA2B,CAChC,GAAIA,CAAAA,EAAS,CAAA,EAAKA,CAAAA,CAAQ,KAAK,KAAA,CAAM,MAAA,CAAQ,CAC3C,IAAA,CAAK,aAAeA,CAAAA,CACpB,IAAMD,CAAAA,CAAQ,IAAA,CAAK,iBAAgB,CACnC,OAAA,IAAA,CAAK,IAAA,CAAK,cAAA,CAAgBA,CAAK,CAAA,CACxBA,CACT,CACA,OAAO,IACT,CAEA,IAAI,OAAA,EAAmB,CACrB,OAAO,IAAA,CAAK,YAAA,CAAe,IAAA,CAAK,KAAA,CAAM,OAAS,CACjD,CAEA,IAAI,WAAA,EAAuB,CACzB,OAAO,IAAA,CAAK,YAAA,CAAe,CAC7B,CACF,CAAA,CCjEO,IAAME,CAAAA,CAAN,cAA0B,KAAM,CACrC,WAAA,CAAY/B,CAAAA,CAAwBgC,EAAe,CACjD,KAAA,CAAMhC,CAAO,CAAA,CADqB,UAAAgC,CAAAA,CAElC,IAAA,CAAK,IAAA,CAAO,cACd,CACF,CAAA,CAEaC,CAAAA,CAAN,cAAoCF,CAAY,CACrD,WAAA,CAAY/B,CAAAA,CAAiB,CAC3B,KAAA,CAAMA,CAAO,CAAA,CACb,IAAA,CAAK,IAAA,CAAO,wBACd,CACF,CAAA,CAEakC,CAAAA,CAAN,cAAkCH,CAAY,CACnD,WAAA,CAAYjB,CAAAA,CAAY,CACtB,KAAA,CAAM,OAAOA,CAAAA,EAAU,QAAA,CAAWA,CAAAA,CAAQ,iBAAiB,EAC3D,IAAA,CAAK,IAAA,CAAO,sBACd,CACF,EAEaqB,CAAAA,CAAN,cAAkCJ,CAAY,CACnD,YAAY/B,CAAAA,CAAiB,CAC3B,KAAA,CAAMA,CAAO,EACb,IAAA,CAAK,IAAA,CAAO,sBACd,CACF,EClBO,IAAMoC,CAAAA,CAAN,cAA2BjC,CAA2B,CAO3D,WAAA,CAAYkC,CAAAA,CAAsB,CAChC,OAAM,CAHR,IAAA,CAAQ,MAAA,CAAgC,MAAA,CAItC,KAAK,MAAA,CAASA,CAAAA,CACd,IAAA,CAAK,SAAA,CAAY,IAAI5B,CAAAA,CACrB,IAAA,CAAK,KAAA,CAAQ,IAAIU,EACjB,IAAA,CAAK,QAAA,CAAW,IAAIQ,CAAAA,CAEpB,KAAK,cAAA,EAAe,CAEhBU,CAAAA,CAAO,WAAA,EACT,KAAK,OAAA,GAET,CAEQ,cAAA,EAAuB,CAE7B,IAAA,CAAK,SAAA,CAAU,EAAA,CAAG,WAAA,CAAa,IAAM,IAAA,CAAK,IAAA,CAAK,WAAW,CAAC,EAC3D,IAAA,CAAK,SAAA,CAAU,EAAA,CAAG,cAAA,CAAiBxB,GAAW,IAAA,CAAK,IAAA,CAAK,cAAA,CAAgBA,CAAM,CAAC,CAAA,CAC/E,IAAA,CAAK,SAAA,CAAU,EAAA,CAAG,QAAUC,CAAAA,EAAU,IAAA,CAAK,IAAA,CAAK,OAAA,CAAS,IAAImB,CAAAA,CAAsBnB,CAAAA,CAAM,OAAO,CAAC,CAAC,CAAA,CAClG,IAAA,CAAK,SAAA,CAAU,EAAA,CAAG,UAAYf,CAAAA,EAAY,IAAA,CAAK,mBAAA,CAAoBA,CAAO,CAAC,CAAA,CAG3E,IAAA,CAAK,KAAA,CAAM,GAAG,SAAA,CAAW,IAAM,IAAA,CAAK,YAAA,CAAa,SAAS,CAAC,CAAA,CAC3D,IAAA,CAAK,KAAA,CAAM,GAAG,QAAA,CAAU,IAAM,IAAA,CAAK,YAAA,CAAa,QAAQ,CAAC,CAAA,CACzD,IAAA,CAAK,KAAA,CAAM,GAAG,SAAA,CAAW,IAAM,IAAA,CAAK,YAAA,CAAa,MAAM,CAAC,CAAA,CACxD,IAAA,CAAK,KAAA,CAAM,GAAG,SAAA,CAAW,IAAM,IAAA,CAAK,YAAA,CAAa,SAAS,CAAC,CAAA,CAC3D,IAAA,CAAK,KAAA,CAAM,GAAG,OAAA,CAAUe,CAAAA,EAAU,IAAA,CAAK,IAAA,CAAK,QAAS,IAAIoB,CAAAA,CAAoBpB,CAAK,CAAC,CAAC,CAAA,CACpF,IAAA,CAAK,KAAA,CAAM,EAAA,CAAG,aAAewB,CAAAA,EAAS,IAAA,CAAK,IAAA,CAAK,YAAA,CAAcA,CAAI,CAAC,CAAA,CACnE,IAAA,CAAK,KAAA,CAAM,GAAG,OAAA,CAAS,IAAM,IAAA,CAAK,gBAAA,EAAkB,EACtD,CAEQ,OAAA,EAAgB,CACtB,IAAA,CAAK,SAAA,CAAU,OAAA,CAAQ,IAAA,CAAK,OAAO,MAAA,CAAQ,IAAA,CAAK,MAAA,CAAO,SAAS,EAClE,CAEA,MAAM,QAAA,CAASC,CAAAA,CAAyC,CACjD,IAAA,CAAK,SAAA,CAAU,WAAA,EAAa,IAAA,CAAK,SAAQ,CAE9C,IAAA,CAAK,SAAA,CAAU,QAAA,CAAS,CACtB,YAAA,CAAA,CAAA,CACA,gBAAA,CAAkBA,CAAAA,CAAQ,cAAA,CAC1B,kBAAmBA,CAAAA,CAAQ,eAAA,CAC3B,WAAA,CAAaA,CAAAA,CAAQ,UACvB,CAAC,EACH,CAEA,MAAM,aAAaA,CAAAA,CAA6C,CACzD,IAAA,CAAK,SAAA,CAAU,aAAa,IAAA,CAAK,OAAA,EAAQ,CAE9C,IAAA,CAAK,UAAU,QAAA,CAAS,CACtB,YAAA,CAAA,CAAA,CACA,aAAA,CAAeA,EAAQ,YAAA,CACvB,WAAA,CAAaA,CAAAA,CAAQ,UACvB,CAAC,EACH,CAEA,KAAA,EAAc,CACZ,KAAK,KAAA,CAAM,KAAA,GACb,CAEA,QAAe,CACb,IAAA,CAAK,KAAA,CAAM,IAAA,GACb,CAEA,IAAA,EAAa,CACX,IAAA,CAAK,KAAA,CAAM,IAAA,GACb,CAEA,MAAa,CACX,IAAMC,CAAAA,CAAY,IAAA,CAAK,SAAS,IAAA,EAAK,CACjCA,CAAAA,EAGF,IAAA,CAAK,SAAS,CAAE,cAAA,CAAgBA,CAAAA,CAAU,EAAG,CAAC,EAElD,CAEA,IAAA,CAAKhB,CAAAA,CAAkB,CACrB,IAAA,CAAK,KAAA,CAAM,IAAA,CAAKA,CAAE,EACpB,CAEA,SAAA,CAAUC,CAAAA,CAAsB,CAC9B,KAAK,KAAA,CAAM,SAAA,CAAUA,CAAM,EAC7B,CAEQ,mBAAA,CAAoB1B,CAAAA,CAAoB,CAC9C,GAAIA,EAAQ,QAAA,CAAU,CACpB,IAAM0C,CAAAA,CAAM1C,EAAQ,QAAA,CAKpB,GAJA,IAAA,CAAK,KAAA,CAAM,KAAK0C,CAAAA,CAAI,YAAA,CAAcA,CAAAA,CAAI,MAAM,EAC5C,IAAA,CAAK,KAAA,CAAM,IAAA,EAAK,CAGZA,EAAI,eAAA,CACN,GAAI,CACF,IAAMC,EAAU,IAAA,CAAK,KAAA,CAAMD,CAAAA,CAAI,eAAe,EAC1CC,CAAAA,CAAQ,MAAA,EACV,IAAA,CAAK,QAAA,CAAS,QAAA,CAASA,CAAAA,CAAQ,MAAM,EAEzC,MAAY,CAEZ,CAEJ,CAAA,KAAW3C,CAAAA,CAAQ,OACjB,IAAA,CAAK,IAAA,CAAK,OAAA,CAAS,IAAIgC,EAAYhC,CAAAA,CAAQ,KAAA,CAAM,OAAA,CAASA,CAAAA,CAAQ,MAAM,IAAI,CAAC,EAEjF,CAEQ,kBAAyB,CAC3B,IAAA,CAAK,QAAA,CAAS,OAAA,CAChB,KAAK,IAAA,EAAK,CAEV,IAAA,CAAK,YAAA,CAAa,MAAM,EAE5B,CAEQ,YAAA,CAAa4C,CAAAA,CAAqC,CACxD,IAAA,CAAK,MAAA,CAASA,CAAAA,CACd,IAAA,CAAK,KAAK,aAAA,CAAe,CACvB,MAAA,CAAAA,CAAAA,CACA,YAAa,IAAA,CAAK,KAAA,CAAM,WAAA,CACxB,QAAA,CAAU,KAAK,KAAA,CAAM,QAAA,CACrB,MAAA,CAAQ,CACV,CAAC,EACH,CAEA,OAAA,EAAgB,CACd,KAAK,KAAA,CAAM,IAAA,EAAK,CAChB,IAAA,CAAK,UAAU,UAAA,EAAW,CAC1B,IAAA,CAAK,kBAAA,GACP,CACF","file":"index.js","sourcesContent":["import * as protobuf from 'protobufjs';\n\n/**\n * Protobuf schema definition for the SDK.\n * Matches the backend contract in src/modules/streaming/sdk-streaming.proto\n */\nconst schema = `\nsyntax = \"proto3\";\n\nenum ContentKind {\n CONTENT_KIND_UNSPECIFIED = 0;\n CONTENT_KIND_SONG = 1;\n CONTENT_KIND_PLAYLIST = 2;\n CONTENT_KIND_CATEGORY = 3;\n}\n\nenum ErrorCode {\n ERROR_CODE_UNSPECIFIED = 0;\n UNAUTHORIZED = 1;\n VALIDATION_ERROR = 2;\n NOT_FOUND = 3;\n PROCESSING = 4;\n SERVICE_UNAVAILABLE = 5;\n BAD_PROTOBUF = 6;\n}\n\nmessage SdkClientInit {\n ContentKind content_kind = 1;\n string catalog_track_id = 2;\n string internal_track_id = 3;\n string playlist_code = 4;\n string listener_id = 5;\n string device_type = 6;\n string country_code = 7;\n string region = 8;\n string protocol_version = 9;\n}\n\nmessage SdkClientEnvelope {\n oneof payload {\n SdkClientInit init = 1;\n }\n}\n\nmessage SdkServerInitAck {\n string session_id = 1;\n string playback_url = 2;\n bool is_hls = 3;\n uint32 heartbeat_interval_ms = 4;\n string content_summary = 5;\n}\n\nmessage SdkServerError {\n ErrorCode code = 1;\n string message = 2;\n}\n\nmessage SdkServerEnvelope {\n oneof payload {\n SdkServerInitAck init_ack = 1;\n SdkServerError error = 2;\n }\n}\n`;\n\nconst root = protobuf.parse(schema).root;\n\nexport const SdkClientEnvelope = root.lookupType('SdkClientEnvelope');\nexport const SdkServerEnvelope = root.lookupType('SdkServerEnvelope');\n\nexport enum ContentKind {\n UNSPECIFIED = 0,\n SONG = 1,\n PLAYLIST = 2,\n CATEGORY = 3,\n}\n\nexport enum ErrorCode {\n UNSPECIFIED = 0,\n UNAUTHORIZED = 1,\n VALIDATION_ERROR = 2,\n NOT_FOUND = 3,\n PROCESSING = 4,\n SERVICE_UNAVAILABLE = 5,\n BAD_PROTOBUF = 6,\n}\n","import { SdkClientEnvelope, SdkServerEnvelope } from '../proto/sdk-streaming';\n\nexport class ProtocolCodec {\n /**\n * Encodes a client envelope into a binary payload.\n */\n static encodeClientEnvelope(payload: any): Uint8Array {\n const message = SdkClientEnvelope.create(payload);\n return SdkClientEnvelope.encode(message).finish();\n }\n\n /**\n * Decodes a binary payload into a server envelope.\n */\n static decodeServerEnvelope(data: Uint8Array): any {\n const decoded = SdkServerEnvelope.decode(data);\n return SdkServerEnvelope.toObject(decoded, {\n enums: String,\n longs: String,\n bytes: String,\n defaults: true,\n oneofs: true,\n });\n }\n}\n","type Handler = (...args: any[]) => void;\n\nexport class EventEmitter<Events extends Record<string, any>> {\n private listeners: Map<keyof Events, Set<Handler>> = new Map();\n\n on<K extends keyof Events>(event: K, handler: Events[K]): void {\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set());\n }\n this.listeners.get(event)!.add(handler);\n }\n\n off<K extends keyof Events>(event: K, handler: Events[K]): void {\n const set = this.listeners.get(event);\n if (set) {\n set.delete(handler);\n }\n }\n\n once<K extends keyof Events>(event: K, handler: Events[K]): void {\n const onceHandler = ((...args: any[]) => {\n handler(...args);\n this.off(event, onceHandler as Events[K]);\n }) as Events[K];\n this.on(event, onceHandler);\n }\n\n protected emit<K extends keyof Events>(event: K, ...args: Parameters<Events[K]>): void {\n const set = this.listeners.get(event);\n if (set) {\n set.forEach((handler) => handler(...args));\n }\n }\n\n removeAllListeners(): void {\n this.listeners.clear();\n }\n}\n","import { io, Socket } from 'socket.io-client';\nimport { ProtocolCodec } from './ProtocolCodec';\nimport { EventEmitter } from '../core/EventEmitter';\n\nexport interface TransportEvents {\n connected: () => void;\n disconnected: (reason: string) => void;\n error: (error: any) => void;\n message: (payload: any) => void;\n}\n\nexport class TransportManager extends EventEmitter<TransportEvents> {\n private socket: Socket | null = null;\n private apiKey: string | null = null;\n private serverUrl: string | null = null;\n\n constructor() {\n super();\n }\n\n /**\n * Connects to the Synxed SDK namespace.\n */\n connect(apiKey: string, serverUrl: string): void {\n if (this.socket?.connected) return;\n\n this.apiKey = apiKey;\n this.serverUrl = serverUrl;\n\n this.socket = io(`${serverUrl}/sdk`, {\n auth: { apiKey },\n transports: ['websocket'],\n });\n\n this.socket.on('connect', () => {\n this.emit('connected');\n });\n\n this.socket.on('disconnect', (reason) => {\n this.emit('disconnected', reason);\n });\n\n this.socket.on('connect_error', (error) => {\n this.emit('error', error);\n });\n\n this.socket.on('d', (data: ArrayBuffer | Uint8Array) => {\n try {\n const uint8Array = data instanceof Uint8Array ? data : new Uint8Array(data);\n const payload = ProtocolCodec.decodeServerEnvelope(uint8Array);\n this.emit('message', payload);\n } catch (err) {\n this.emit('error', new Error(`Failed to decode message: ${err}`));\n }\n });\n }\n\n /**\n * Disconnects from the server.\n */\n disconnect(): void {\n if (this.socket) {\n this.socket.disconnect();\n this.socket = null;\n }\n }\n\n /**\n * Sends an init message to the backend.\n */\n sendInit(params: any): void {\n if (!this.socket?.connected) {\n throw new Error('Socket not connected');\n }\n\n const payload = { init: params };\n const bytes = ProtocolCodec.encodeClientEnvelope(payload);\n this.socket.emit('d', bytes);\n }\n\n /**\n * Checks if the socket is connected.\n */\n get isConnected(): boolean {\n return this.socket?.connected || false;\n }\n}\n","import { Howl } from 'howler';\nimport { EventEmitter } from '../core/EventEmitter';\n\nexport interface AudioEvents {\n playing: () => void;\n paused: () => void;\n stopped: () => void;\n ended: () => void;\n loading: () => void;\n loaded: () => void;\n error: (error: any) => void;\n timeupdate: (data: { currentTime: number; duration: number }) => void;\n}\n\nexport class AudioEngine extends EventEmitter<AudioEvents> {\n private howl: Howl | null = null;\n private updateTimer: number | null = null;\n\n constructor() {\n super();\n }\n\n /**\n * Loads a track URL.\n */\n load(url: string, isHls: boolean): void {\n this.stop();\n this.emit('loading');\n\n // For HLS, we'd ideally use hls.js. \n // Howler doesn't natively support HLS streams well without custom logic.\n // For now, we'll use HTML5 audio mode which works for some HLS streams natively.\n this.howl = new Howl({\n src: [url],\n html5: true, // Required for streaming large files\n format: isHls ? ['m3u8'] : undefined,\n onload: () => {\n this.emit('loaded');\n },\n onloaderror: (id, err) => {\n this.emit('error', err);\n },\n onplay: () => {\n this.emit('playing');\n this.startTimeUpdateLoop();\n },\n onpause: () => {\n this.emit('paused');\n this.stopTimeUpdateLoop();\n },\n onstop: () => {\n this.emit('stopped');\n this.stopTimeUpdateLoop();\n },\n onend: () => {\n this.emit('ended');\n this.stopTimeUpdateLoop();\n },\n });\n }\n\n play(): void {\n this.howl?.play();\n }\n\n pause(): void {\n this.howl?.pause();\n }\n\n stop(): void {\n this.howl?.stop();\n this.howl?.unload();\n this.howl = null;\n }\n\n seek(ms: number): void {\n this.howl?.seek(ms / 1000);\n }\n\n setVolume(volume: number): void {\n this.howl?.volume(volume);\n }\n\n get duration(): number {\n return (this.howl?.duration() || 0) * 1000;\n }\n\n get currentTime(): number {\n return (this.howl?.seek() as number || 0) * 1000;\n }\n\n private startTimeUpdateLoop(): void {\n this.stopTimeUpdateLoop();\n const update = () => {\n if (this.howl?.playing()) {\n this.emit('timeupdate', {\n currentTime: this.currentTime,\n duration: this.duration,\n });\n this.updateTimer = requestAnimationFrame(update);\n }\n };\n this.updateTimer = requestAnimationFrame(update);\n }\n\n private stopTimeUpdateLoop(): void {\n if (this.updateTimer !== null) {\n cancelAnimationFrame(this.updateTimer);\n this.updateTimer = null;\n }\n }\n}\n","import { EventEmitter } from '../core/EventEmitter';\n\nexport interface PlaylistEvents {\n trackChanged: (track: any) => void;\n queueUpdated: (tracks: any[]) => void;\n}\n\nexport class PlaylistManager extends EventEmitter<PlaylistEvents> {\n private queue: any[] = [];\n private currentIndex: number = -1;\n\n constructor() {\n super();\n }\n\n setQueue(tracks: any[]): void {\n this.queue = tracks;\n this.currentIndex = tracks.length > 0 ? 0 : -1;\n this.emit('queueUpdated', this.queue);\n }\n\n getCurrentTrack(): any | null {\n if (this.currentIndex >= 0 && this.currentIndex < this.queue.length) {\n return this.queue[this.currentIndex];\n }\n return null;\n }\n\n next(): any | null {\n if (this.currentIndex < this.queue.length - 1) {\n this.currentIndex++;\n const track = this.getCurrentTrack();\n this.emit('trackChanged', track);\n return track;\n }\n return null;\n }\n\n previous(): any | null {\n if (this.currentIndex > 0) {\n this.currentIndex--;\n const track = this.getCurrentTrack();\n this.emit('trackChanged', track);\n return track;\n }\n return null;\n }\n\n skipTo(index: number): any | null {\n if (index >= 0 && index < this.queue.length) {\n this.currentIndex = index;\n const track = this.getCurrentTrack();\n this.emit('trackChanged', track);\n return track;\n }\n return null;\n }\n\n get hasNext(): boolean {\n return this.currentIndex < this.queue.length - 1;\n }\n\n get hasPrevious(): boolean {\n return this.currentIndex > 0;\n }\n}\n","export class SynxedError extends Error {\n constructor(message: string, public code?: string) {\n super(message);\n this.name = 'SynxedError';\n }\n}\n\nexport class SynxedConnectionError extends SynxedError {\n constructor(message: string) {\n super(message);\n this.name = 'SynxedConnectionError';\n }\n}\n\nexport class SynxedPlaybackError extends SynxedError {\n constructor(error: any) {\n super(typeof error === 'string' ? error : 'Playback failed');\n this.name = 'SynxedPlaybackError';\n }\n}\n\nexport class SynxedProtocolError extends SynxedError {\n constructor(message: string) {\n super(message);\n this.name = 'SynxedProtocolError';\n }\n}\n","import { TransportManager } from '../transport/TransportManager';\nimport { AudioEngine } from '../audio/AudioEngine';\nimport { PlaylistManager } from '../playlist/PlaylistManager';\nimport { EventEmitter } from './EventEmitter';\nimport { ContentKind } from '../proto/sdk-streaming';\nimport { SynxedConfig, PlayerState, PlaySongOptions, PlayPlaylistOptions, SynxedEvents } from '../types';\nimport { SynxedError, SynxedPlaybackError, SynxedConnectionError } from './errors';\n\nexport class SynxedPlayer extends EventEmitter<SynxedEvents> {\n private transport: TransportManager;\n private audio: AudioEngine;\n private playlist: PlaylistManager;\n private config: SynxedConfig;\n private status: PlayerState['status'] = 'idle';\n\n constructor(config: SynxedConfig) {\n super();\n this.config = config;\n this.transport = new TransportManager();\n this.audio = new AudioEngine();\n this.playlist = new PlaylistManager();\n\n this.setupListeners();\n\n if (config.autoConnect) {\n this.connect();\n }\n }\n\n private setupListeners(): void {\n // Transport Listeners\n this.transport.on('connected', () => this.emit('connected'));\n this.transport.on('disconnected', (reason) => this.emit('disconnected', reason));\n this.transport.on('error', (error) => this.emit('error', new SynxedConnectionError(error.message)));\n this.transport.on('message', (payload) => this.handleServerMessage(payload));\n\n // Audio Listeners\n this.audio.on('playing', () => this.updateStatus('playing'));\n this.audio.on('paused', () => this.updateStatus('paused'));\n this.audio.on('stopped', () => this.updateStatus('idle'));\n this.audio.on('loading', () => this.updateStatus('loading'));\n this.audio.on('error', (error) => this.emit('error', new SynxedPlaybackError(error)));\n this.audio.on('timeupdate', (time) => this.emit('timeUpdate', time));\n this.audio.on('ended', () => this.handleTrackEnded());\n }\n\n private connect(): void {\n this.transport.connect(this.config.apiKey, this.config.serverUrl);\n }\n\n async playSong(options: PlaySongOptions): Promise<void> {\n if (!this.transport.isConnected) this.connect();\n \n this.transport.sendInit({\n content_kind: ContentKind.SONG,\n catalog_track_id: options.catalogTrackId,\n internal_track_id: options.internalTrackId,\n listener_id: options.listenerId,\n });\n }\n\n async playPlaylist(options: PlayPlaylistOptions): Promise<void> {\n if (!this.transport.isConnected) this.connect();\n\n this.transport.sendInit({\n content_kind: ContentKind.PLAYLIST,\n playlist_code: options.playlistCode,\n listener_id: options.listenerId,\n });\n }\n\n pause(): void {\n this.audio.pause();\n }\n\n resume(): void {\n this.audio.play();\n }\n\n stop(): void {\n this.audio.stop();\n }\n\n skip(): void {\n const nextTrack = this.playlist.next();\n if (nextTrack) {\n // In current backend, we need to re-init for each track\n // This logic will be refined once backend handles queues\n this.playSong({ catalogTrackId: nextTrack.id }); \n }\n }\n\n seek(ms: number): void {\n this.audio.seek(ms);\n }\n\n setVolume(volume: number): void {\n this.audio.setVolume(volume);\n }\n\n private handleServerMessage(payload: any): void {\n if (payload.init_ack) {\n const ack = payload.init_ack;\n this.audio.load(ack.playback_url, ack.is_hls);\n this.audio.play();\n \n // Parse content_summary if it's a playlist\n if (ack.content_summary) {\n try {\n const summary = JSON.parse(ack.content_summary);\n if (summary.tracks) {\n this.playlist.setQueue(summary.tracks);\n }\n } catch (e) {\n // Ignore parse errors for now\n }\n }\n } else if (payload.error) {\n this.emit('error', new SynxedError(payload.error.message, payload.error.code));\n }\n }\n\n private handleTrackEnded(): void {\n if (this.playlist.hasNext) {\n this.skip();\n } else {\n this.updateStatus('idle');\n }\n }\n\n private updateStatus(status: PlayerState['status']): void {\n this.status = status;\n this.emit('stateChange', {\n status,\n currentTime: this.audio.currentTime,\n duration: this.audio.duration,\n volume: 1, // Store volume locally if needed\n });\n }\n\n destroy(): void {\n this.audio.stop();\n this.transport.disconnect();\n this.removeAllListeners();\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/proto/sdk-streaming.ts","../src/transport/ProtocolCodec.ts","../src/core/EventEmitter.ts","../src/transport/TransportManager.ts","../src/audio/AudioEngine.ts","../src/playlist/PlaylistManager.ts","../src/core/errors.ts","../src/core/SynxedPlayer.ts"],"names":["schema","root","k","SdkClientEnvelope","SdkServerEnvelope","ContentKind","ErrorCode","ProtocolCodec","payload","message","data","decoded","EventEmitter","event","handler","set","onceHandler","args","TransportManager","apiKey","serverUrl","normalizedUrl","io","reason","error","uint8Array","err","resolve","reject","onConnect","cleanup","onError","params","bytes","AudioEngine","url","isHls","isSafari","Hls","searchParams","e","Howl","id","ms","volume","update","PlaylistManager","tracks","track","index","SynxedError","code","SynxedConnectionError","SynxedPlaybackError","SynxedProtocolError","SynxedPlayer","config","time","options","nextTrack","eventType","positionMs","extra","ack","summary","status"],"mappings":"wdAMMA,CAAAA,CAAS;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAAA,CAiFTC,CAAAA,CAAgBC,YAAA,CAAA,KAAA,CAAMF,CAAM,CAAA,CAAE,IAAA,CAEvBG,EAAoBF,CAAAA,CAAK,UAAA,CAAW,mBAAmB,CAAA,CACvDG,CAAAA,CAAoBH,CAAAA,CAAK,WAAW,mBAAmB,CAAA,CAExDI,CAAAA,CAAAA,CAAAA,CAAAA,GACVA,CAAAA,CAAAA,CAAAA,CAAA,WAAA,CAAc,CAAA,CAAA,CAAd,cACAA,CAAAA,CAAAA,CAAAA,CAAA,IAAA,CAAO,CAAA,CAAA,CAAP,MAAA,CACAA,CAAAA,CAAAA,CAAAA,CAAA,QAAA,CAAW,GAAX,UAAA,CACAA,CAAAA,CAAAA,CAAAA,CAAA,QAAA,CAAW,CAAA,CAAA,CAAX,UAAA,CAJUA,CAAAA,CAAAA,EAAAA,CAAAA,EAAA,IAOAC,CAAAA,CAAAA,CAAAA,CAAAA,GACVA,CAAAA,CAAAA,CAAAA,CAAA,WAAA,CAAc,CAAA,CAAA,CAAd,aAAA,CACAA,CAAAA,CAAAA,CAAAA,CAAA,aAAe,CAAA,CAAA,CAAf,cAAA,CACAA,CAAAA,CAAAA,CAAAA,CAAA,gBAAA,CAAmB,CAAA,CAAA,CAAnB,kBAAA,CACAA,IAAA,SAAA,CAAY,CAAA,CAAA,CAAZ,WAAA,CACAA,CAAAA,CAAAA,CAAAA,CAAA,UAAA,CAAa,CAAA,CAAA,CAAb,aACAA,CAAAA,CAAAA,CAAAA,CAAA,mBAAA,CAAsB,CAAA,CAAA,CAAtB,qBAAA,CACAA,CAAAA,CAAAA,CAAAA,CAAA,YAAA,CAAe,GAAf,cAAA,CAPUA,CAAAA,CAAAA,EAAAA,CAAAA,EAAA,EAAA,ECjGL,IAAMC,CAAAA,CAAN,KAAoB,CAIzB,OAAO,oBAAA,CAAqBC,CAAAA,CAA0B,CACpD,IAAMC,CAAAA,CAAUN,EAAkB,MAAA,CAAOK,CAAO,CAAA,CAChD,OAAOL,CAAAA,CAAkB,MAAA,CAAOM,CAAO,CAAA,CAAE,MAAA,EAC3C,CAKA,OAAO,oBAAA,CAAqBC,EAAuB,CACjD,IAAMC,CAAAA,CAAUP,CAAAA,CAAkB,MAAA,CAAOM,CAAI,EAC7C,OAAON,CAAAA,CAAkB,QAAA,CAASO,CAAAA,CAAS,CACzC,KAAA,CAAO,MAAA,CACP,KAAA,CAAO,MAAA,CACP,KAAA,CAAO,MAAA,CACP,QAAA,CAAU,IAAA,CACV,MAAA,CAAQ,IACV,CAAC,CACH,CACF,CAAA,CCtBO,IAAMC,CAAAA,CAAN,KAAuD,CAAvD,WAAA,EAAA,CACL,IAAA,CAAQ,SAAA,CAA6C,IAAI,IAAA,CAEzD,GAA2BC,CAAAA,CAAUC,CAAAA,CAA0B,CACxD,IAAA,CAAK,SAAA,CAAU,GAAA,CAAID,CAAK,CAAA,EAC3B,IAAA,CAAK,SAAA,CAAU,GAAA,CAAIA,CAAAA,CAAO,IAAI,GAAK,CAAA,CAErC,IAAA,CAAK,SAAA,CAAU,GAAA,CAAIA,CAAK,CAAA,CAAG,IAAIC,CAAO,EACxC,CAEA,GAAA,CAA4BD,CAAAA,CAAUC,CAAAA,CAA0B,CAC9D,IAAMC,CAAAA,CAAM,IAAA,CAAK,SAAA,CAAU,GAAA,CAAIF,CAAK,EAChCE,CAAAA,EACFA,CAAAA,CAAI,MAAA,CAAOD,CAAO,EAEtB,CAEA,KAA6BD,CAAAA,CAAUC,CAAAA,CAA0B,CAC/D,IAAME,CAAAA,EAAe,CAAA,GAAIC,IAAgB,CACvCH,CAAAA,CAAQ,GAAGG,CAAI,CAAA,CACf,IAAA,CAAK,IAAIJ,CAAAA,CAAOG,CAAwB,EAC1C,CAAA,CAAA,CACA,IAAA,CAAK,EAAA,CAAGH,EAAOG,CAAW,EAC5B,CAEU,IAAA,CAA6BH,CAAAA,CAAAA,GAAaI,CAAAA,CAAmC,CACrF,IAAMF,CAAAA,CAAM,IAAA,CAAK,SAAA,CAAU,GAAA,CAAIF,CAAK,EAChCE,CAAAA,EACFA,CAAAA,CAAI,OAAA,CAASD,CAAAA,EAAYA,CAAAA,CAAQ,GAAGG,CAAI,CAAC,EAE7C,CAEA,kBAAA,EAA2B,CACzB,IAAA,CAAK,SAAA,CAAU,KAAA,GACjB,CACF,CAAA,CC1BO,IAAMC,CAAAA,CAAN,cAA+BN,CAA8B,CAKlE,WAAA,EAAc,CACZ,KAAA,EAAM,CALR,IAAA,CAAQ,OAAwB,IAAA,CAChC,IAAA,CAAQ,MAAA,CAAwB,IAAA,CAChC,IAAA,CAAQ,SAAA,CAA2B,KAInC,CAKA,OAAA,CAAQO,CAAAA,CAAgBC,CAAAA,CAAyB,CAC/C,GAAI,KAAK,MAAA,EAAQ,SAAA,CAAW,OAE5B,IAAA,CAAK,MAAA,CAASD,CAAAA,CACd,KAAK,SAAA,CAAYC,CAAAA,CAEjB,IAAMC,CAAAA,CAAgBD,CAAAA,CAAU,QAAA,CAAS,GAAG,CAAA,CAAIA,CAAAA,CAAU,KAAA,CAAM,CAAA,CAAG,EAAE,CAAA,CAAIA,EAEzE,IAAA,CAAK,MAAA,CAASE,kBAAAA,CAAG,CAAA,EAAGD,CAAa,CAAA,IAAA,CAAA,CAAQ,CACvC,IAAA,CAAM,CAAE,MAAA,CAAAF,CAAO,CAAA,CACf,UAAA,CAAY,CAAC,WAAW,CAC1B,CAAC,CAAA,CAED,IAAA,CAAK,MAAA,CAAO,GAAG,SAAA,CAAW,IAAM,CAC9B,IAAA,CAAK,IAAA,CAAK,WAAW,EACvB,CAAC,CAAA,CAED,IAAA,CAAK,MAAA,CAAO,EAAA,CAAG,YAAA,CAAeI,GAAW,CACvC,IAAA,CAAK,IAAA,CAAK,cAAA,CAAgBA,CAAM,EAClC,CAAC,CAAA,CAED,IAAA,CAAK,MAAA,CAAO,EAAA,CAAG,eAAA,CAAkBC,CAAAA,EAAU,CACzC,IAAA,CAAK,IAAA,CAAK,OAAA,CAASA,CAAK,EAC1B,CAAC,EAED,IAAA,CAAK,MAAA,CAAO,EAAA,CAAG,GAAA,CAAMd,CAAAA,EAAmC,CACtD,GAAI,CACF,IAAMe,CAAAA,CAAaf,CAAAA,YAAgB,UAAA,CAAaA,CAAAA,CAAO,IAAI,WAAWA,CAAI,CAAA,CACpEF,CAAAA,CAAUD,CAAAA,CAAc,oBAAA,CAAqBkB,CAAU,EAC7D,IAAA,CAAK,IAAA,CAAK,SAAA,CAAWjB,CAAO,EAC9B,CAAA,MAASkB,EAAK,CACZ,IAAA,CAAK,IAAA,CAAK,OAAA,CAAS,IAAI,KAAA,CAAM,6BAA6BA,CAAG,CAAA,CAAE,CAAC,EAClE,CACF,CAAC,EACH,CAKA,MAAM,iBAAA,EAAmC,CAEvC,GADA,OAAA,CAAQ,IAAI,oCAAoC,CAAA,CAC5C,IAAA,CAAK,MAAA,EAAQ,SAAA,CAAW,CAC1B,QAAQ,GAAA,CAAI,4BAA4B,CAAA,CACxC,MACF,CAEA,OAAO,IAAI,OAAA,CAAQ,CAACC,CAAAA,CAASC,CAAAA,GAAW,CACtC,IAAMC,EAAY,IAAM,CACtB,OAAA,CAAQ,GAAA,CAAI,uCAAuC,CAAA,CACnDC,GAAQ,CACRH,CAAAA,GACF,CAAA,CAEMI,CAAAA,CAAWL,CAAAA,EAAa,CAC5B,OAAA,CAAQ,KAAA,CAAM,mCAAA,CAAqCA,CAAG,CAAA,CACtDI,CAAAA,GACAF,CAAAA,CAAOF,CAAG,EACZ,CAAA,CAEMI,CAAAA,CAAU,IAAM,CACpB,IAAA,CAAK,MAAA,EAAQ,GAAA,CAAI,SAAA,CAAWD,CAAS,CAAA,CACrC,KAAK,MAAA,EAAQ,GAAA,CAAI,eAAA,CAAiBE,CAAO,EAC3C,CAAA,CAEA,KAAK,MAAA,EAAQ,IAAA,CAAK,SAAA,CAAWF,CAAS,CAAA,CACtC,IAAA,CAAK,MAAA,EAAQ,IAAA,CAAK,eAAA,CAAiBE,CAAO,CAAA,CAErC,IAAA,CAAK,MAAA,GACR,OAAA,CAAQ,MAAM,mCAAmC,CAAA,CACjDH,CAAAA,CAAO,IAAI,KAAA,CAAM,+CAA+C,CAAC,CAAA,EAErE,CAAC,CACH,CAKA,UAAA,EAAmB,CACb,KAAK,MAAA,GACP,IAAA,CAAK,MAAA,CAAO,UAAA,EAAW,CACvB,IAAA,CAAK,OAAS,IAAA,EAElB,CAKA,QAAA,CAASI,CAAAA,CAAmB,CAC1B,GAAI,CAAC,IAAA,CAAK,MAAA,EAAQ,SAAA,CAChB,MAAM,IAAI,KAAA,CAAM,sBAAsB,CAAA,CAGxC,OAAA,CAAQ,GAAA,CAAI,+BAAA,CAAiCA,CAAM,CAAA,CACnD,IAAMxB,CAAAA,CAAU,CAAE,IAAA,CAAMwB,CAAO,CAAA,CACzBC,CAAAA,CAAQ1B,EAAc,oBAAA,CAAqBC,CAAO,CAAA,CACxD,IAAA,CAAK,MAAA,CAAO,IAAA,CAAK,IAAKyB,CAAK,EAC7B,CAKA,WAAA,CAAYD,CAAAA,CAAmB,CAC7B,GAAI,CAAC,IAAA,CAAK,MAAA,EAAQ,SAAA,CAAW,OAC7B,IAAMxB,EAAU,CAAE,OAAA,CAASwB,CAAO,CAAA,CAC5BC,CAAAA,CAAQ1B,CAAAA,CAAc,qBAAqBC,CAAO,CAAA,CACxD,IAAA,CAAK,MAAA,CAAO,IAAA,CAAK,GAAA,CAAKyB,CAAK,EAC7B,CAKA,aAAA,CAAcD,CAAAA,CAAmB,CAC/B,GAAI,CAAC,IAAA,CAAK,MAAA,EAAQ,SAAA,CAAW,OAC7B,IAAMxB,CAAAA,CAAU,CAAE,SAAA,CAAWwB,CAAO,CAAA,CAC9BC,CAAAA,CAAQ1B,CAAAA,CAAc,oBAAA,CAAqBC,CAAO,CAAA,CACxD,IAAA,CAAK,MAAA,CAAO,IAAA,CAAK,GAAA,CAAKyB,CAAK,EAC7B,CAKA,IAAI,WAAA,EAAuB,CACzB,OAAO,IAAA,CAAK,MAAA,EAAQ,WAAa,KACnC,CACF,CAAA,CCrIO,IAAMC,CAAAA,CAAN,cAA0BtB,CAA0B,CAMzD,WAAA,EAAc,CACZ,KAAA,EAAM,CANR,IAAA,CAAQ,IAAA,CAAoB,IAAA,CAC5B,IAAA,CAAQ,IAAW,IAAA,CACnB,IAAA,CAAQ,OAAA,CAAmC,IAAA,CAC3C,IAAA,CAAQ,WAAA,CAA6B,KAIrC,CAMA,MAAM,IAAA,CAAKuB,CAAAA,CAAaC,CAAAA,CAA+B,CACrD,KAAK,IAAA,EAAK,CACV,IAAA,CAAK,IAAA,CAAK,SAAS,CAAA,CAEnB,QAAQ,GAAA,CAAI,mCAAA,CAAqCD,CAAAA,CAAK,QAAA,CAAUC,CAAK,CAAA,CAGrE,IAAMC,CAAAA,CAAW,gCAAA,CAAiC,IAAA,CAAK,SAAA,CAAU,SAAS,CAAA,CAE1E,GAAID,CAAAA,EAAS,CAACC,CAAAA,CACZ,GAAI,CACF,GAAM,CAAE,OAAA,CAASC,CAAI,CAAA,CAAI,MAAM,OAAO,QAAQ,EAC9C,GAAIA,CAAAA,CAAI,WAAA,EAAY,CAAG,CACrB,OAAA,CAAQ,IAAI,oCAAoC,CAAA,CAIhD,IAAMC,CAAAA,CADS,IAAI,GAAA,CAAIJ,CAAG,CAAA,CACE,MAAA,CAE5B,IAAA,CAAK,GAAA,CAAM,IAAIG,CAAAA,CACf,KAAK,OAAA,CAAU,IAAI,KAAA,CACnB,IAAA,CAAK,GAAA,CAAI,UAAA,CAAWH,CAAG,CAAA,CACvB,IAAA,CAAK,GAAA,CAAI,WAAA,CAAY,IAAA,CAAK,OAAO,CAAA,CAEjC,KAAK,OAAA,CAAQ,MAAA,CAAS,IAAM,CAC1B,IAAA,CAAK,IAAA,CAAK,SAAS,CAAA,CACnB,IAAA,CAAK,mBAAA,GACP,CAAA,CACA,IAAA,CAAK,QAAQ,OAAA,CAAU,IAAM,CAC3B,IAAA,CAAK,IAAA,CAAK,QAAQ,EAClB,IAAA,CAAK,kBAAA,GACP,CAAA,CACA,IAAA,CAAK,OAAA,CAAQ,QAAU,IAAM,CAC3B,IAAA,CAAK,IAAA,CAAK,OAAO,CAAA,CACjB,KAAK,kBAAA,GACP,CAAA,CACA,IAAA,CAAK,OAAA,CAAQ,OAAA,CAAWK,GAAM,CAC5B,OAAA,CAAQ,KAAA,CAAM,2BAAA,CAA6BA,CAAC,CAAA,CAC5C,KAAK,IAAA,CAAK,OAAA,CAASA,CAAC,EACtB,CAAA,CACA,IAAA,CAAK,QAAQ,gBAAA,CAAmB,IAAM,CACpC,IAAA,CAAK,IAAA,CAAK,QAAQ,EACpB,CAAA,CAEA,IAAA,CAAK,GAAA,CAAI,EAAA,CAAGF,CAAAA,CAAI,MAAA,CAAO,MAAO,CAACzB,CAAAA,CAAYH,CAAAA,GAAc,CACnDA,CAAAA,CAAK,KAAA,GACP,QAAQ,KAAA,CAAM,2BAAA,CAA6BA,CAAI,CAAA,CAC/C,IAAA,CAAK,IAAA,CAAK,QAASA,CAAI,CAAA,EAE3B,CAAC,CAAA,CAED,MACF,CACF,MAAY,CACV,OAAA,CAAQ,IAAA,CAAK,oEAAoE,EACnF,CAIF,KAAK,IAAA,CAAO,IAAI+B,WAAAA,CAAK,CACnB,GAAA,CAAK,CAACN,CAAG,CAAA,CACT,KAAA,CAAO,IAAA,CACP,MAAA,CAAQC,CAAAA,CAAQ,CAAC,MAAM,EAAI,MAAA,CAC3B,MAAA,CAAQ,IAAM,CACZ,OAAA,CAAQ,GAAA,CAAI,0CAA0C,CAAA,CACtD,IAAA,CAAK,IAAA,CAAK,QAAQ,EACpB,CAAA,CACA,YAAa,CAACM,CAAAA,CAAIhB,CAAAA,GAAQ,CACxB,OAAA,CAAQ,KAAA,CAAM,mCAAoCA,CAAAA,CAAK,KAAA,CAAOgB,CAAE,CAAA,CAChE,IAAA,CAAK,IAAA,CAAK,QAAShB,CAAG,EACxB,CAAA,CACA,MAAA,CAAQ,IAAM,CACZ,KAAK,IAAA,CAAK,SAAS,CAAA,CACnB,IAAA,CAAK,mBAAA,GACP,EACA,OAAA,CAAS,IAAM,CACb,IAAA,CAAK,IAAA,CAAK,QAAQ,EAClB,IAAA,CAAK,kBAAA,GACP,CAAA,CACA,MAAA,CAAQ,IAAM,CACZ,IAAA,CAAK,IAAA,CAAK,SAAS,CAAA,CACnB,IAAA,CAAK,kBAAA,GACP,CAAA,CACA,KAAA,CAAO,IAAM,CACX,IAAA,CAAK,IAAA,CAAK,OAAO,CAAA,CACjB,IAAA,CAAK,kBAAA,GACP,CACF,CAAC,EACH,CAEA,IAAA,EAAa,CACP,IAAA,CAAK,OAAA,CACP,IAAA,CAAK,QAAQ,IAAA,EAAK,CAAE,KAAA,CAAMc,CAAAA,EAAK,OAAA,CAAQ,KAAA,CAAM,wBAAyBA,CAAC,CAAC,CAAA,CAExE,IAAA,CAAK,IAAA,EAAM,IAAA,GAEf,CAEA,KAAA,EAAc,CACR,IAAA,CAAK,OAAA,CACP,IAAA,CAAK,OAAA,CAAQ,KAAA,EAAM,CAEnB,IAAA,CAAK,IAAA,EAAM,KAAA,GAEf,CAEA,MAAa,CACP,IAAA,CAAK,GAAA,GACP,IAAA,CAAK,GAAA,CAAI,OAAA,GACT,IAAA,CAAK,GAAA,CAAM,IAAA,CAAA,CAET,IAAA,CAAK,OAAA,GACP,IAAA,CAAK,QAAQ,KAAA,EAAM,CACnB,IAAA,CAAK,OAAA,CAAQ,GAAA,CAAM,EAAA,CACnB,KAAK,OAAA,CAAU,IAAA,CAAA,CAEb,IAAA,CAAK,IAAA,GACP,IAAA,CAAK,IAAA,CAAK,MAAK,CACf,IAAA,CAAK,IAAA,CAAK,MAAA,EAAO,CACjB,IAAA,CAAK,KAAO,IAAA,CAAA,CAEd,IAAA,CAAK,kBAAA,GACP,CAEA,IAAA,CAAKG,EAAkB,CACjB,IAAA,CAAK,OAAA,CACP,IAAA,CAAK,OAAA,CAAQ,WAAA,CAAcA,EAAK,GAAA,CAEhC,IAAA,CAAK,IAAA,EAAM,IAAA,CAAKA,CAAAA,CAAK,GAAI,EAE7B,CAEA,SAAA,CAAUC,CAAAA,CAAsB,CAC1B,IAAA,CAAK,OAAA,GACP,KAAK,OAAA,CAAQ,MAAA,CAASA,CAAAA,CAAAA,CAEpB,IAAA,CAAK,IAAA,EACP,IAAA,CAAK,KAAK,MAAA,CAAOA,CAAM,EAE3B,CAEA,IAAI,QAAA,EAAmB,CACrB,OAAI,IAAA,CAAK,OAAA,CAAgB,IAAA,CAAK,OAAA,CAAQ,QAAA,CAAW,KACzC,IAAA,CAAK,IAAA,EAAM,QAAA,EAAS,EAAK,CAAA,EAAK,GACxC,CAEA,IAAI,WAAA,EAAsB,CACxB,OAAI,IAAA,CAAK,OAAA,CAAgB,KAAK,OAAA,CAAQ,WAAA,CAAc,GAAA,CAAA,CAC5C,IAAA,CAAK,IAAA,EAAM,IAAA,EAAK,EAAe,CAAA,EAAK,GAC9C,CAEQ,mBAAA,EAA4B,CAClC,IAAA,CAAK,kBAAA,GACL,IAAMC,CAAAA,CAAS,IAAM,CAAA,CACD,IAAA,CAAK,OAAA,CAAU,CAAC,IAAA,CAAK,OAAA,CAAQ,MAAA,CAAS,IAAA,CAAK,IAAA,EAAM,OAAA,MAEjE,IAAA,CAAK,IAAA,CAAK,YAAA,CAAc,CACtB,WAAA,CAAa,IAAA,CAAK,YAClB,QAAA,CAAU,IAAA,CAAK,QACjB,CAAC,CAAA,CACD,IAAA,CAAK,YAAc,qBAAA,CAAsBA,CAAM,CAAA,EAEnD,CAAA,CACA,IAAA,CAAK,WAAA,CAAc,sBAAsBA,CAAM,EACjD,CAEQ,kBAAA,EAA2B,CAC7B,IAAA,CAAK,cAAgB,IAAA,GACvB,oBAAA,CAAqB,IAAA,CAAK,WAAW,CAAA,CACrC,IAAA,CAAK,YAAc,IAAA,EAEvB,CACF,CAAA,CCjMO,IAAMC,CAAAA,CAAN,cAA8BlC,CAA6B,CAIhE,WAAA,EAAc,CACZ,KAAA,EAAM,CAJR,IAAA,CAAQ,MAAe,EAAC,CACxB,IAAA,CAAQ,YAAA,CAAuB,GAI/B,CAEA,SAASmC,CAAAA,CAAqB,CAC5B,IAAA,CAAK,KAAA,CAAQA,CAAAA,CACb,IAAA,CAAK,aAAeA,CAAAA,CAAO,MAAA,CAAS,CAAA,CAAI,CAAA,CAAI,EAAA,CAC5C,IAAA,CAAK,KAAK,cAAA,CAAgB,IAAA,CAAK,KAAK,EACtC,CAEA,eAAA,EAA8B,CAC5B,OAAI,IAAA,CAAK,YAAA,EAAgB,CAAA,EAAK,IAAA,CAAK,YAAA,CAAe,KAAK,KAAA,CAAM,MAAA,CACpD,IAAA,CAAK,KAAA,CAAM,IAAA,CAAK,YAAY,CAAA,CAE9B,IACT,CAEA,IAAA,EAAmB,CACjB,GAAI,IAAA,CAAK,YAAA,CAAe,KAAK,KAAA,CAAM,MAAA,CAAS,CAAA,CAAG,CAC7C,IAAA,CAAK,YAAA,EAAA,CACL,IAAMC,CAAAA,CAAQ,IAAA,CAAK,eAAA,EAAgB,CACnC,OAAA,IAAA,CAAK,IAAA,CAAK,eAAgBA,CAAK,CAAA,CACxBA,CACT,CACA,OAAO,IACT,CAEA,QAAA,EAAuB,CACrB,GAAI,IAAA,CAAK,YAAA,CAAe,CAAA,CAAG,CACzB,IAAA,CAAK,YAAA,EAAA,CACL,IAAMA,CAAAA,CAAQ,IAAA,CAAK,eAAA,GACnB,OAAA,IAAA,CAAK,IAAA,CAAK,cAAA,CAAgBA,CAAK,CAAA,CACxBA,CACT,CACA,OAAO,IACT,CAEA,MAAA,CAAOC,CAAAA,CAA2B,CAChC,GAAIA,CAAAA,EAAS,CAAA,EAAKA,CAAAA,CAAQ,IAAA,CAAK,KAAA,CAAM,MAAA,CAAQ,CAC3C,IAAA,CAAK,YAAA,CAAeA,CAAAA,CACpB,IAAMD,CAAAA,CAAQ,IAAA,CAAK,iBAAgB,CACnC,OAAA,IAAA,CAAK,IAAA,CAAK,cAAA,CAAgBA,CAAK,CAAA,CACxBA,CACT,CACA,OAAO,IACT,CAEA,IAAI,OAAA,EAAmB,CACrB,OAAO,IAAA,CAAK,YAAA,CAAe,IAAA,CAAK,KAAA,CAAM,MAAA,CAAS,CACjD,CAEA,IAAI,WAAA,EAAuB,CACzB,OAAO,IAAA,CAAK,aAAe,CAC7B,CACF,CAAA,CCjEO,IAAME,CAAAA,CAAN,cAA0B,KAAM,CACrC,WAAA,CAAYzC,CAAAA,CAAwB0C,CAAAA,CAAe,CACjD,KAAA,CAAM1C,CAAO,CAAA,CADqB,IAAA,CAAA,IAAA,CAAA0C,CAAAA,CAElC,IAAA,CAAK,IAAA,CAAO,cACd,CACF,EAEaC,CAAAA,CAAN,cAAoCF,CAAY,CACrD,WAAA,CAAYzC,CAAAA,CAAiB,CAC3B,KAAA,CAAMA,CAAO,CAAA,CACb,IAAA,CAAK,IAAA,CAAO,wBACd,CACF,CAAA,CAEa4C,CAAAA,CAAN,cAAkCH,CAAY,CACnD,WAAA,CAAY1B,EAAY,CACtB,KAAA,CAAM,OAAOA,CAAAA,EAAU,QAAA,CAAWA,CAAAA,CAAQ,iBAAiB,CAAA,CAC3D,IAAA,CAAK,IAAA,CAAO,sBACd,CACF,CAAA,CAEa8B,EAAN,cAAkCJ,CAAY,CACnD,WAAA,CAAYzC,CAAAA,CAAiB,CAC3B,MAAMA,CAAO,CAAA,CACb,IAAA,CAAK,IAAA,CAAO,sBACd,CACF,EClBO,IAAM8C,CAAAA,CAAN,cAA2B3C,CAA2B,CAO3D,WAAA,CAAY4C,EAAsB,CAChC,KAAA,EAAM,CAHR,IAAA,CAAQ,MAAA,CAAgC,MAAA,CAItC,KAAK,MAAA,CAASA,CAAAA,CACd,IAAA,CAAK,SAAA,CAAY,IAAItC,CAAAA,CACrB,KAAK,KAAA,CAAQ,IAAIgB,CAAAA,CACjB,IAAA,CAAK,QAAA,CAAW,IAAIY,EAEpB,IAAA,CAAK,cAAA,EAAe,CAEhBU,CAAAA,CAAO,WAAA,EACT,IAAA,CAAK,UAET,CAEQ,cAAA,EAAuB,CAE7B,IAAA,CAAK,SAAA,CAAU,GAAG,WAAA,CAAa,IAAM,IAAA,CAAK,IAAA,CAAK,WAAW,CAAC,EAC3D,IAAA,CAAK,SAAA,CAAU,EAAA,CAAG,cAAA,CAAiBjC,CAAAA,EAAW,IAAA,CAAK,IAAA,CAAK,cAAA,CAAgBA,CAAM,CAAC,CAAA,CAC/E,IAAA,CAAK,SAAA,CAAU,EAAA,CAAG,QAAUC,CAAAA,EAAU,IAAA,CAAK,IAAA,CAAK,OAAA,CAAS,IAAI4B,CAAAA,CAAsB5B,EAAM,OAAO,CAAC,CAAC,CAAA,CAClG,IAAA,CAAK,SAAA,CAAU,GAAG,SAAA,CAAYhB,CAAAA,EAAY,IAAA,CAAK,mBAAA,CAAoBA,CAAO,CAAC,EAG3E,IAAA,CAAK,KAAA,CAAM,EAAA,CAAG,SAAA,CAAW,IAAM,IAAA,CAAK,aAAa,SAAS,CAAC,CAAA,CAC3D,IAAA,CAAK,KAAA,CAAM,EAAA,CAAG,SAAU,IAAM,IAAA,CAAK,YAAA,CAAa,QAAQ,CAAC,CAAA,CACzD,KAAK,KAAA,CAAM,EAAA,CAAG,SAAA,CAAW,IAAM,IAAA,CAAK,YAAA,CAAa,MAAM,CAAC,CAAA,CACxD,IAAA,CAAK,KAAA,CAAM,EAAA,CAAG,SAAA,CAAW,IAAM,IAAA,CAAK,YAAA,CAAa,SAAS,CAAC,CAAA,CAC3D,IAAA,CAAK,MAAM,EAAA,CAAG,OAAA,CAAUgB,CAAAA,EAAU,IAAA,CAAK,IAAA,CAAK,OAAA,CAAS,IAAI6B,CAAAA,CAAoB7B,CAAK,CAAC,CAAC,CAAA,CACpF,IAAA,CAAK,MAAM,EAAA,CAAG,YAAA,CAAeiC,CAAAA,EAAS,IAAA,CAAK,IAAA,CAAK,YAAA,CAAcA,CAAI,CAAC,CAAA,CACnE,IAAA,CAAK,KAAA,CAAM,EAAA,CAAG,OAAA,CAAS,IAAM,IAAA,CAAK,gBAAA,EAAkB,EACtD,CAEQ,OAAA,EAAgB,CACtB,IAAA,CAAK,SAAA,CAAU,OAAA,CAAQ,IAAA,CAAK,MAAA,CAAO,MAAA,CAAQ,IAAA,CAAK,MAAA,CAAO,SAAS,EAClE,CAEA,MAAM,QAAA,CAASC,CAAAA,CAAyC,CACjD,IAAA,CAAK,SAAA,CAAU,WAAA,EAAa,IAAA,CAAK,OAAA,EAAQ,CAC9C,MAAM,IAAA,CAAK,SAAA,CAAU,iBAAA,EAAkB,CAEvC,IAAA,CAAK,SAAA,CAAU,SAAS,CACtB,WAAA,CAAA,CAAA,CACA,cAAA,CAAgBA,CAAAA,CAAQ,cAAA,CACxB,eAAA,CAAiBA,EAAQ,eAAA,CACzB,UAAA,CAAYA,CAAAA,CAAQ,UACtB,CAAC,EACH,CAEA,MAAM,YAAA,CAAaA,CAAAA,CAA6C,CACzD,IAAA,CAAK,SAAA,CAAU,aAAa,IAAA,CAAK,OAAA,EAAQ,CAC9C,MAAM,IAAA,CAAK,SAAA,CAAU,mBAAkB,CAEvC,IAAA,CAAK,SAAA,CAAU,QAAA,CAAS,CACtB,WAAA,CAAA,CAAA,CACA,aAAcA,CAAAA,CAAQ,YAAA,CACtB,UAAA,CAAYA,CAAAA,CAAQ,UACtB,CAAC,EACH,CAEA,KAAA,EAAc,CACZ,IAAA,CAAK,KAAA,CAAM,KAAA,GACX,IAAA,CAAK,SAAA,CAAU,WAAA,CAAY,CACzB,MAAA,CAAQ,CAAA,CACR,WAAY,IAAA,CAAK,KAAA,CAAM,IAAA,CAAK,KAAA,CAAM,WAAA,CAAc,GAAI,CACtD,CAAC,EACH,CAEA,MAAA,EAAe,CACb,IAAA,CAAK,MAAM,IAAA,EAAK,CAChB,IAAA,CAAK,SAAA,CAAU,WAAA,CAAY,CACzB,OAAQ,CAAA,CACR,UAAA,CAAY,IAAA,CAAK,KAAA,CAAM,IAAA,CAAK,KAAA,CAAM,YAAc,GAAI,CACtD,CAAC,EACH,CAEA,IAAA,EAAa,CACX,IAAA,CAAK,KAAA,CAAM,IAAA,EAAK,CAChB,IAAA,CAAK,SAAA,CAAU,WAAA,CAAY,CACzB,MAAA,CAAQ,CAAA,CACR,UAAA,CAAY,IAAA,CAAK,KAAA,CAAM,IAAA,CAAK,MAAM,WAAA,CAAc,GAAI,CACtD,CAAC,EACH,CAEA,MAAa,CACX,IAAMC,CAAAA,CAAY,IAAA,CAAK,QAAA,CAAS,IAAA,GAC5BA,CAAAA,EAGF,IAAA,CAAK,QAAA,CAAS,CAAE,cAAA,CAAgBA,CAAAA,CAAU,EAAG,CAAC,EAElD,CAEA,IAAA,CAAKhB,CAAAA,CAAkB,CACrB,KAAK,KAAA,CAAM,IAAA,CAAKA,CAAE,CAAA,CAClB,IAAA,CAAK,SAAA,CAAU,YAAY,CACzB,MAAA,CAAQ,CAAA,CACR,UAAA,CAAYA,CACd,CAAC,EACH,CAEA,SAAA,CAAUC,CAAAA,CAAsB,CAC9B,IAAA,CAAK,KAAA,CAAM,UAAUA,CAAM,EAC7B,CAEQ,aAAA,CAAcgB,CAAAA,CAAmBC,CAAAA,CAAqBC,EAAmB,CAC/E,IAAA,CAAK,SAAA,CAAU,aAAA,CAAc,CAC3B,SAAA,CAAAF,EACA,UAAA,CAAYC,CAAAA,EAAc,IAAA,CAAK,KAAA,CAAM,IAAA,CAAK,KAAA,CAAM,YAAc,GAAI,CAAA,CAClE,SAAA,CAAWC,CAAAA,CAAQ,IAAA,CAAK,SAAA,CAAUA,CAAK,CAAA,CAAI,MAC7C,CAAC,EACH,CAEA,MAAc,oBAAoBtD,CAAAA,CAA6B,CAE7D,GADA,OAAA,CAAQ,GAAA,CAAI,mCAAA,CAAqCA,CAAO,CAAA,CACpDA,CAAAA,CAAQ,OAAA,CAAS,CACnB,IAAMuD,CAAAA,CAAMvD,CAAAA,CAAQ,OAAA,CAOpB,GANA,OAAA,CAAQ,GAAA,CAAI,gCAAA,CAAkCuD,CAAAA,CAAI,WAAA,CAAa,SAAUA,CAAAA,CAAI,KAAK,CAAA,CAClF,MAAM,IAAA,CAAK,KAAA,CAAM,KAAKA,CAAAA,CAAI,WAAA,CAAaA,CAAAA,CAAI,KAAK,CAAA,CAChD,IAAA,CAAK,MAAM,IAAA,EAAK,CAChB,IAAA,CAAK,aAAA,CAAc,cAAc,CAAA,CAG7BA,EAAI,cAAA,CACN,GAAI,CACF,IAAMC,CAAAA,CAAU,IAAA,CAAK,MAAMD,CAAAA,CAAI,cAAc,CAAA,CACzCC,CAAAA,CAAQ,MAAA,EACV,IAAA,CAAK,SAAS,QAAA,CAASA,CAAAA,CAAQ,MAAM,EAEzC,CAAA,KAAY,CAEZ,CAEJ,CAAA,KAAWxD,CAAAA,CAAQ,KAAA,EACjB,IAAA,CAAK,IAAA,CAAK,OAAA,CAAS,IAAI0C,CAAAA,CAAY1C,CAAAA,CAAQ,KAAA,CAAM,OAAA,CAASA,CAAAA,CAAQ,KAAA,CAAM,IAAI,CAAC,EAEjF,CAEQ,gBAAA,EAAyB,CAC3B,IAAA,CAAK,SAAS,OAAA,CAChB,IAAA,CAAK,IAAA,EAAK,CAEV,IAAA,CAAK,YAAA,CAAa,MAAM,EAE5B,CAEQ,YAAA,CAAayD,CAAAA,CAAqC,CACxD,IAAA,CAAK,OAASA,CAAAA,CACd,IAAA,CAAK,IAAA,CAAK,aAAA,CAAe,CACvB,MAAA,CAAAA,EACA,WAAA,CAAa,IAAA,CAAK,KAAA,CAAM,WAAA,CACxB,QAAA,CAAU,IAAA,CAAK,MAAM,QAAA,CACrB,MAAA,CAAQ,CACV,CAAC,EACH,CAEA,SAAgB,CACd,IAAA,CAAK,KAAA,CAAM,IAAA,EAAK,CAChB,IAAA,CAAK,SAAA,CAAU,UAAA,EAAW,CAC1B,IAAA,CAAK,kBAAA,GACP,CACF","file":"index.js","sourcesContent":["import * as protobuf from 'protobufjs';\n\n/**\n * Protobuf schema definition for the SDK.\n * Matches the backend contract in src/modules/streaming/sdk-streaming.proto\n */\nconst schema = `\nsyntax = \"proto3\";\n\nenum ContentKind {\n CONTENT_KIND_UNSPECIFIED = 0;\n CONTENT_KIND_SONG = 1;\n CONTENT_KIND_PLAYLIST = 2;\n CONTENT_KIND_CATEGORY = 3;\n}\n\nenum ErrorCode {\n ERROR_CODE_UNSPECIFIED = 0;\n UNAUTHORIZED = 1;\n VALIDATION_ERROR = 2;\n NOT_FOUND = 3;\n PROCESSING = 4;\n SERVICE_UNAVAILABLE = 5;\n BAD_PROTOBUF = 6;\n}\n\nenum SdkControlAction {\n CONTROL_UNSPECIFIED = 0;\n CONTROL_PLAY = 1;\n CONTROL_PAUSE = 2;\n CONTROL_STOP = 3;\n CONTROL_SEEK = 4;\n}\n\nmessage SdkClientInit {\n ContentKind contentKind = 1;\n string catalogTrackId = 2;\n string internalTrackId = 3;\n string playlistCode = 4;\n string categoryQuery = 5;\n string listenerId = 6;\n string deviceType = 7;\n string countryCode = 8;\n string region = 9;\n string protocolVersion = 10;\n}\n\nmessage SdkClientControl {\n SdkControlAction action = 1;\n uint32 positionMs = 2;\n}\n\nmessage SdkClientAnalytics {\n string eventType = 1;\n uint32 positionMs = 2;\n string extraJson = 3;\n}\n\nmessage SdkClientEnvelope {\n oneof payload {\n SdkClientInit init = 1;\n SdkClientControl control = 2;\n SdkClientAnalytics analytics = 3;\n }\n}\n\nmessage SdkServerInitAck {\n string sessionId = 1;\n string playbackUrl = 2;\n bool isHls = 3;\n uint32 heartbeatIntervalMs = 4;\n string contentSummary = 5;\n}\n\nmessage SdkServerError {\n ErrorCode code = 1;\n string message = 2;\n}\n\nmessage SdkServerEnvelope {\n oneof payload {\n SdkServerInitAck initAck = 1;\n SdkServerError error = 2;\n }\n}\n`;\n\nconst root = protobuf.parse(schema).root;\n\nexport const SdkClientEnvelope = root.lookupType('SdkClientEnvelope');\nexport const SdkServerEnvelope = root.lookupType('SdkServerEnvelope');\n\nexport enum ContentKind {\n UNSPECIFIED = 0,\n SONG = 1,\n PLAYLIST = 2,\n CATEGORY = 3,\n}\n\nexport enum ErrorCode {\n UNSPECIFIED = 0,\n UNAUTHORIZED = 1,\n VALIDATION_ERROR = 2,\n NOT_FOUND = 3,\n PROCESSING = 4,\n SERVICE_UNAVAILABLE = 5,\n BAD_PROTOBUF = 6,\n}\n","import { SdkClientEnvelope, SdkServerEnvelope } from '../proto/sdk-streaming';\n\nexport class ProtocolCodec {\n /**\n * Encodes a client envelope into a binary payload.\n */\n static encodeClientEnvelope(payload: any): Uint8Array {\n const message = SdkClientEnvelope.create(payload);\n return SdkClientEnvelope.encode(message).finish();\n }\n\n /**\n * Decodes a binary payload into a server envelope.\n */\n static decodeServerEnvelope(data: Uint8Array): any {\n const decoded = SdkServerEnvelope.decode(data);\n return SdkServerEnvelope.toObject(decoded, {\n enums: String,\n longs: String,\n bytes: String,\n defaults: true,\n oneofs: true,\n });\n }\n}\n","type Handler = (...args: any[]) => void;\n\nexport class EventEmitter<Events extends Record<string, any>> {\n private listeners: Map<keyof Events, Set<Handler>> = new Map();\n\n on<K extends keyof Events>(event: K, handler: Events[K]): void {\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set());\n }\n this.listeners.get(event)!.add(handler);\n }\n\n off<K extends keyof Events>(event: K, handler: Events[K]): void {\n const set = this.listeners.get(event);\n if (set) {\n set.delete(handler);\n }\n }\n\n once<K extends keyof Events>(event: K, handler: Events[K]): void {\n const onceHandler = ((...args: any[]) => {\n handler(...args);\n this.off(event, onceHandler as Events[K]);\n }) as Events[K];\n this.on(event, onceHandler);\n }\n\n protected emit<K extends keyof Events>(event: K, ...args: Parameters<Events[K]>): void {\n const set = this.listeners.get(event);\n if (set) {\n set.forEach((handler) => handler(...args));\n }\n }\n\n removeAllListeners(): void {\n this.listeners.clear();\n }\n}\n","import { io, Socket } from 'socket.io-client';\nimport { ProtocolCodec } from './ProtocolCodec';\nimport { EventEmitter } from '../core/EventEmitter';\n\nexport interface TransportEvents {\n connected: () => void;\n disconnected: (reason: string) => void;\n error: (error: any) => void;\n message: (payload: any) => void;\n}\n\nexport class TransportManager extends EventEmitter<TransportEvents> {\n private socket: Socket | null = null;\n private apiKey: string | null = null;\n private serverUrl: string | null = null;\n\n constructor() {\n super();\n }\n\n /**\n * Connects to the Synxed SDK namespace.\n */\n connect(apiKey: string, serverUrl: string): void {\n if (this.socket?.connected) return;\n\n this.apiKey = apiKey;\n this.serverUrl = serverUrl;\n\n const normalizedUrl = serverUrl.endsWith('/') ? serverUrl.slice(0, -1) : serverUrl;\n\n this.socket = io(`${normalizedUrl}/sdk`, {\n auth: { apiKey },\n transports: ['websocket'],\n });\n\n this.socket.on('connect', () => {\n this.emit('connected');\n });\n\n this.socket.on('disconnect', (reason) => {\n this.emit('disconnected', reason);\n });\n\n this.socket.on('connect_error', (error) => {\n this.emit('error', error);\n });\n\n this.socket.on('d', (data: ArrayBuffer | Uint8Array) => {\n try {\n const uint8Array = data instanceof Uint8Array ? data : new Uint8Array(data);\n const payload = ProtocolCodec.decodeServerEnvelope(uint8Array);\n this.emit('message', payload);\n } catch (err) {\n this.emit('error', new Error(`Failed to decode message: ${err}`));\n }\n });\n }\n\n /**\n * Returns a promise that resolves when the socket is connected.\n */\n async waitForConnection(): Promise<void> {\n console.log('[Synxed] Waiting for connection...');\n if (this.socket?.connected) {\n console.log('[Synxed] Already connected');\n return;\n }\n \n return new Promise((resolve, reject) => {\n const onConnect = () => {\n console.log('[Synxed] Socket connected event fired');\n cleanup();\n resolve();\n };\n \n const onError = (err: any) => {\n console.error('[Synxed] Socket connection error:', err);\n cleanup();\n reject(err);\n };\n \n const cleanup = () => {\n this.socket?.off('connect', onConnect);\n this.socket?.off('connect_error', onError);\n };\n\n this.socket?.once('connect', onConnect);\n this.socket?.once('connect_error', onError);\n \n if (!this.socket) {\n console.error('[Synxed] No socket instance found');\n reject(new Error('Socket not initialized. Call connect() first.'));\n }\n });\n }\n\n /**\n * Disconnects from the server.\n */\n disconnect(): void {\n if (this.socket) {\n this.socket.disconnect();\n this.socket = null;\n }\n }\n\n /**\n * Sends an init message to the backend.\n */\n sendInit(params: any): void {\n if (!this.socket?.connected) {\n throw new Error('Socket not connected');\n }\n\n console.log('[Synxed] Sending init packet:', params);\n const payload = { init: params };\n const bytes = ProtocolCodec.encodeClientEnvelope(payload);\n this.socket.emit('d', bytes);\n }\n\n /**\n * Sends a control message.\n */\n sendControl(params: any): void {\n if (!this.socket?.connected) return;\n const payload = { control: params };\n const bytes = ProtocolCodec.encodeClientEnvelope(payload);\n this.socket.emit('d', bytes);\n }\n\n /**\n * Sends an analytics message.\n */\n sendAnalytics(params: any): void {\n if (!this.socket?.connected) return;\n const payload = { analytics: params };\n const bytes = ProtocolCodec.encodeClientEnvelope(payload);\n this.socket.emit('d', bytes);\n }\n\n /**\n * Checks if the socket is connected.\n */\n get isConnected(): boolean {\n return this.socket?.connected || false;\n }\n}\n","import { Howl } from 'howler';\nimport { EventEmitter } from '../core/EventEmitter';\n\nexport interface AudioEvents {\n playing: () => void;\n paused: () => void;\n stopped: () => void;\n ended: () => void;\n loading: () => void;\n loaded: () => void;\n error: (error: any) => void;\n timeupdate: (data: { currentTime: number; duration: number }) => void;\n}\n\nexport class AudioEngine extends EventEmitter<AudioEvents> {\n private howl: Howl | null = null;\n private hls: any = null;\n private audioEl: HTMLAudioElement | null = null;\n private updateTimer: number | null = null;\n\n constructor() {\n super();\n }\n\n\n /**\n * Loads a track URL.\n */\n async load(url: string, isHls: boolean): Promise<void> {\n this.stop();\n this.emit('loading');\n\n console.log('[Synxed] AudioEngine loading URL:', url, 'isHls:', isHls);\n\n // Safari has native HLS support. Other browsers need hls.js.\n const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);\n\n if (isHls && !isSafari) {\n try {\n const { default: Hls } = await import('hls.js');\n if (Hls.isSupported()) {\n console.log('[Synxed] Using Hls.js for playback');\n \n // Extract query parameters from the manifest URL to forward to segments\n const urlObj = new URL(url);\n const searchParams = urlObj.search;\n\n this.hls = new Hls();\n this.audioEl = new Audio();\n this.hls.loadSource(url);\n this.hls.attachMedia(this.audioEl);\n \n this.audioEl.onplay = () => {\n this.emit('playing');\n this.startTimeUpdateLoop();\n };\n this.audioEl.onpause = () => {\n this.emit('paused');\n this.stopTimeUpdateLoop();\n };\n this.audioEl.onended = () => {\n this.emit('ended');\n this.stopTimeUpdateLoop();\n };\n this.audioEl.onerror = (e) => {\n console.error('[Synxed] HLS Audio error:', e);\n this.emit('error', e);\n };\n this.audioEl.onloadedmetadata = () => {\n this.emit('loaded');\n };\n\n this.hls.on(Hls.Events.ERROR, (event: any, data: any) => {\n if (data.fatal) {\n console.error('[Synxed] Fatal HLS error:', data);\n this.emit('error', data);\n }\n });\n\n return;\n }\n } catch (e) {\n console.warn('[Synxed] hls.js not found or error loading, falling back to native');\n }\n }\n\n // Fallback to Howler\n this.howl = new Howl({\n src: [url],\n html5: true, \n format: isHls ? ['m3u8'] : undefined,\n onload: () => {\n console.log('[Synxed] AudioEngine loaded successfully');\n this.emit('loaded');\n },\n onloaderror: (id, err) => {\n console.error('[Synxed] AudioEngine load error:', err, 'ID:', id);\n this.emit('error', err);\n },\n onplay: () => {\n this.emit('playing');\n this.startTimeUpdateLoop();\n },\n onpause: () => {\n this.emit('paused');\n this.stopTimeUpdateLoop();\n },\n onstop: () => {\n this.emit('stopped');\n this.stopTimeUpdateLoop();\n },\n onend: () => {\n this.emit('ended');\n this.stopTimeUpdateLoop();\n },\n });\n }\n\n play(): void {\n if (this.audioEl) {\n this.audioEl.play().catch(e => console.error('[Synxed] Play failed:', e));\n } else {\n this.howl?.play();\n }\n }\n\n pause(): void {\n if (this.audioEl) {\n this.audioEl.pause();\n } else {\n this.howl?.pause();\n }\n }\n\n stop(): void {\n if (this.hls) {\n this.hls.destroy();\n this.hls = null;\n }\n if (this.audioEl) {\n this.audioEl.pause();\n this.audioEl.src = '';\n this.audioEl = null;\n }\n if (this.howl) {\n this.howl.stop();\n this.howl.unload();\n this.howl = null;\n }\n this.stopTimeUpdateLoop();\n }\n\n seek(ms: number): void {\n if (this.audioEl) {\n this.audioEl.currentTime = ms / 1000;\n } else {\n this.howl?.seek(ms / 1000);\n }\n }\n\n setVolume(volume: number): void {\n if (this.audioEl) {\n this.audioEl.volume = volume;\n }\n if (this.howl) {\n this.howl.volume(volume);\n }\n }\n\n get duration(): number {\n if (this.audioEl) return this.audioEl.duration * 1000;\n return (this.howl?.duration() || 0) * 1000;\n }\n\n get currentTime(): number {\n if (this.audioEl) return this.audioEl.currentTime * 1000;\n return (this.howl?.seek() as number || 0) * 1000;\n }\n\n private startTimeUpdateLoop(): void {\n this.stopTimeUpdateLoop();\n const update = () => {\n const isPlaying = this.audioEl ? !this.audioEl.paused : this.howl?.playing();\n if (isPlaying) {\n this.emit('timeupdate', {\n currentTime: this.currentTime,\n duration: this.duration,\n });\n this.updateTimer = requestAnimationFrame(update);\n }\n };\n this.updateTimer = requestAnimationFrame(update);\n }\n\n private stopTimeUpdateLoop(): void {\n if (this.updateTimer !== null) {\n cancelAnimationFrame(this.updateTimer);\n this.updateTimer = null;\n }\n }\n}\n","import { EventEmitter } from '../core/EventEmitter';\n\nexport interface PlaylistEvents {\n trackChanged: (track: any) => void;\n queueUpdated: (tracks: any[]) => void;\n}\n\nexport class PlaylistManager extends EventEmitter<PlaylistEvents> {\n private queue: any[] = [];\n private currentIndex: number = -1;\n\n constructor() {\n super();\n }\n\n setQueue(tracks: any[]): void {\n this.queue = tracks;\n this.currentIndex = tracks.length > 0 ? 0 : -1;\n this.emit('queueUpdated', this.queue);\n }\n\n getCurrentTrack(): any | null {\n if (this.currentIndex >= 0 && this.currentIndex < this.queue.length) {\n return this.queue[this.currentIndex];\n }\n return null;\n }\n\n next(): any | null {\n if (this.currentIndex < this.queue.length - 1) {\n this.currentIndex++;\n const track = this.getCurrentTrack();\n this.emit('trackChanged', track);\n return track;\n }\n return null;\n }\n\n previous(): any | null {\n if (this.currentIndex > 0) {\n this.currentIndex--;\n const track = this.getCurrentTrack();\n this.emit('trackChanged', track);\n return track;\n }\n return null;\n }\n\n skipTo(index: number): any | null {\n if (index >= 0 && index < this.queue.length) {\n this.currentIndex = index;\n const track = this.getCurrentTrack();\n this.emit('trackChanged', track);\n return track;\n }\n return null;\n }\n\n get hasNext(): boolean {\n return this.currentIndex < this.queue.length - 1;\n }\n\n get hasPrevious(): boolean {\n return this.currentIndex > 0;\n }\n}\n","export class SynxedError extends Error {\n constructor(message: string, public code?: string) {\n super(message);\n this.name = 'SynxedError';\n }\n}\n\nexport class SynxedConnectionError extends SynxedError {\n constructor(message: string) {\n super(message);\n this.name = 'SynxedConnectionError';\n }\n}\n\nexport class SynxedPlaybackError extends SynxedError {\n constructor(error: any) {\n super(typeof error === 'string' ? error : 'Playback failed');\n this.name = 'SynxedPlaybackError';\n }\n}\n\nexport class SynxedProtocolError extends SynxedError {\n constructor(message: string) {\n super(message);\n this.name = 'SynxedProtocolError';\n }\n}\n","import { TransportManager } from '../transport/TransportManager';\nimport { AudioEngine } from '../audio/AudioEngine';\nimport { PlaylistManager } from '../playlist/PlaylistManager';\nimport { EventEmitter } from './EventEmitter';\nimport { ContentKind } from '../proto/sdk-streaming';\nimport { SynxedConfig, PlayerState, PlaySongOptions, PlayPlaylistOptions, SynxedEvents } from '../types';\nimport { SynxedError, SynxedPlaybackError, SynxedConnectionError } from './errors';\n\nexport class SynxedPlayer extends EventEmitter<SynxedEvents> {\n private transport: TransportManager;\n private audio: AudioEngine;\n private playlist: PlaylistManager;\n private config: SynxedConfig;\n private status: PlayerState['status'] = 'idle';\n\n constructor(config: SynxedConfig) {\n super();\n this.config = config;\n this.transport = new TransportManager();\n this.audio = new AudioEngine();\n this.playlist = new PlaylistManager();\n\n this.setupListeners();\n\n if (config.autoConnect) {\n this.connect();\n }\n }\n\n private setupListeners(): void {\n // Transport Listeners\n this.transport.on('connected', () => this.emit('connected'));\n this.transport.on('disconnected', (reason) => this.emit('disconnected', reason));\n this.transport.on('error', (error) => this.emit('error', new SynxedConnectionError(error.message)));\n this.transport.on('message', (payload) => this.handleServerMessage(payload));\n\n // Audio Listeners\n this.audio.on('playing', () => this.updateStatus('playing'));\n this.audio.on('paused', () => this.updateStatus('paused'));\n this.audio.on('stopped', () => this.updateStatus('idle'));\n this.audio.on('loading', () => this.updateStatus('loading'));\n this.audio.on('error', (error) => this.emit('error', new SynxedPlaybackError(error)));\n this.audio.on('timeupdate', (time) => this.emit('timeUpdate', time));\n this.audio.on('ended', () => this.handleTrackEnded());\n }\n\n private connect(): void {\n this.transport.connect(this.config.apiKey, this.config.serverUrl);\n }\n\n async playSong(options: PlaySongOptions): Promise<void> {\n if (!this.transport.isConnected) this.connect();\n await this.transport.waitForConnection();\n \n this.transport.sendInit({\n contentKind: ContentKind.SONG,\n catalogTrackId: options.catalogTrackId,\n internalTrackId: options.internalTrackId,\n listenerId: options.listenerId,\n });\n }\n\n async playPlaylist(options: PlayPlaylistOptions): Promise<void> {\n if (!this.transport.isConnected) this.connect();\n await this.transport.waitForConnection();\n\n this.transport.sendInit({\n contentKind: ContentKind.PLAYLIST,\n playlistCode: options.playlistCode,\n listenerId: options.listenerId,\n });\n }\n\n pause(): void {\n this.audio.pause();\n this.transport.sendControl({\n action: 2, // PAUSE\n positionMs: Math.floor(this.audio.currentTime * 1000),\n });\n }\n\n resume(): void {\n this.audio.play();\n this.transport.sendControl({\n action: 1, // PLAY\n positionMs: Math.floor(this.audio.currentTime * 1000),\n });\n }\n\n stop(): void {\n this.audio.stop();\n this.transport.sendControl({\n action: 3, // STOP\n positionMs: Math.floor(this.audio.currentTime * 1000),\n });\n }\n\n skip(): void {\n const nextTrack = this.playlist.next();\n if (nextTrack) {\n // In current backend, we need to re-init for each track\n // This logic will be refined once backend handles queues\n this.playSong({ catalogTrackId: nextTrack.id }); \n }\n }\n\n seek(ms: number): void {\n this.audio.seek(ms);\n this.transport.sendControl({\n action: 4, // SEEK\n positionMs: ms,\n });\n }\n\n setVolume(volume: number): void {\n this.audio.setVolume(volume);\n }\n\n private emitAnalytics(eventType: string, positionMs?: number, extra?: any): void {\n this.transport.sendAnalytics({\n eventType,\n positionMs: positionMs ?? Math.floor(this.audio.currentTime * 1000),\n extraJson: extra ? JSON.stringify(extra) : undefined,\n });\n }\n\n private async handleServerMessage(payload: any): Promise<void> {\n console.log('[Synxed] Received server message:', payload);\n if (payload.initAck) {\n const ack = payload.initAck;\n console.log('[Synxed] Loading playback URL:', ack.playbackUrl, 'isHls:', ack.isHls);\n await this.audio.load(ack.playbackUrl, ack.isHls);\n this.audio.play();\n this.emitAnalytics('stream_start');\n \n // Parse contentSummary if it's a playlist\n if (ack.contentSummary) {\n try {\n const summary = JSON.parse(ack.contentSummary);\n if (summary.tracks) {\n this.playlist.setQueue(summary.tracks);\n }\n } catch (e) {\n // Ignore parse errors for now\n }\n }\n } else if (payload.error) {\n this.emit('error', new SynxedError(payload.error.message, payload.error.code));\n }\n }\n\n private handleTrackEnded(): void {\n if (this.playlist.hasNext) {\n this.skip();\n } else {\n this.updateStatus('idle');\n }\n }\n\n private updateStatus(status: PlayerState['status']): void {\n this.status = status;\n this.emit('stateChange', {\n status,\n currentTime: this.audio.currentTime,\n duration: this.audio.duration,\n volume: 1, // Store volume locally if needed\n });\n }\n\n destroy(): void {\n this.audio.stop();\n this.transport.disconnect();\n this.removeAllListeners();\n }\n}\n"]}
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {io}from'socket.io-client';import*as k from'protobufjs';import {Howl}from'howler';var
|
|
1
|
+
import {io}from'socket.io-client';import*as k from'protobufjs';import {Howl}from'howler';var C=`
|
|
2
2
|
syntax = "proto3";
|
|
3
3
|
|
|
4
4
|
enum ContentKind {
|
|
@@ -18,30 +18,52 @@ enum ErrorCode {
|
|
|
18
18
|
BAD_PROTOBUF = 6;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
+
enum SdkControlAction {
|
|
22
|
+
CONTROL_UNSPECIFIED = 0;
|
|
23
|
+
CONTROL_PLAY = 1;
|
|
24
|
+
CONTROL_PAUSE = 2;
|
|
25
|
+
CONTROL_STOP = 3;
|
|
26
|
+
CONTROL_SEEK = 4;
|
|
27
|
+
}
|
|
28
|
+
|
|
21
29
|
message SdkClientInit {
|
|
22
|
-
ContentKind
|
|
23
|
-
string
|
|
24
|
-
string
|
|
25
|
-
string
|
|
26
|
-
string
|
|
27
|
-
string
|
|
28
|
-
string
|
|
29
|
-
string
|
|
30
|
-
string
|
|
30
|
+
ContentKind contentKind = 1;
|
|
31
|
+
string catalogTrackId = 2;
|
|
32
|
+
string internalTrackId = 3;
|
|
33
|
+
string playlistCode = 4;
|
|
34
|
+
string categoryQuery = 5;
|
|
35
|
+
string listenerId = 6;
|
|
36
|
+
string deviceType = 7;
|
|
37
|
+
string countryCode = 8;
|
|
38
|
+
string region = 9;
|
|
39
|
+
string protocolVersion = 10;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
message SdkClientControl {
|
|
43
|
+
SdkControlAction action = 1;
|
|
44
|
+
uint32 positionMs = 2;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
message SdkClientAnalytics {
|
|
48
|
+
string eventType = 1;
|
|
49
|
+
uint32 positionMs = 2;
|
|
50
|
+
string extraJson = 3;
|
|
31
51
|
}
|
|
32
52
|
|
|
33
53
|
message SdkClientEnvelope {
|
|
34
54
|
oneof payload {
|
|
35
55
|
SdkClientInit init = 1;
|
|
56
|
+
SdkClientControl control = 2;
|
|
57
|
+
SdkClientAnalytics analytics = 3;
|
|
36
58
|
}
|
|
37
59
|
}
|
|
38
60
|
|
|
39
61
|
message SdkServerInitAck {
|
|
40
|
-
string
|
|
41
|
-
string
|
|
42
|
-
bool
|
|
43
|
-
uint32
|
|
44
|
-
string
|
|
62
|
+
string sessionId = 1;
|
|
63
|
+
string playbackUrl = 2;
|
|
64
|
+
bool isHls = 3;
|
|
65
|
+
uint32 heartbeatIntervalMs = 4;
|
|
66
|
+
string contentSummary = 5;
|
|
45
67
|
}
|
|
46
68
|
|
|
47
69
|
message SdkServerError {
|
|
@@ -51,9 +73,9 @@ message SdkServerError {
|
|
|
51
73
|
|
|
52
74
|
message SdkServerEnvelope {
|
|
53
75
|
oneof payload {
|
|
54
|
-
SdkServerInitAck
|
|
76
|
+
SdkServerInitAck initAck = 1;
|
|
55
77
|
SdkServerError error = 2;
|
|
56
78
|
}
|
|
57
79
|
}
|
|
58
|
-
`,
|
|
80
|
+
`,T=k.parse(C).root,f=T.lookupType("SdkClientEnvelope"),S=T.lookupType("SdkServerEnvelope"),E=(i=>(i[i.UNSPECIFIED=0]="UNSPECIFIED",i[i.SONG=1]="SONG",i[i.PLAYLIST=2]="PLAYLIST",i[i.CATEGORY=3]="CATEGORY",i))(E||{}),x=(o=>(o[o.UNSPECIFIED=0]="UNSPECIFIED",o[o.UNAUTHORIZED=1]="UNAUTHORIZED",o[o.VALIDATION_ERROR=2]="VALIDATION_ERROR",o[o.NOT_FOUND=3]="NOT_FOUND",o[o.PROCESSING=4]="PROCESSING",o[o.SERVICE_UNAVAILABLE=5]="SERVICE_UNAVAILABLE",o[o.BAD_PROTOBUF=6]="BAD_PROTOBUF",o))(x||{});var l=class{static encodeClientEnvelope(n){let t=f.create(n);return f.encode(t).finish()}static decodeServerEnvelope(n){let t=S.decode(n);return S.toObject(t,{enums:String,longs:String,bytes:String,defaults:true,oneofs:true})}};var a=class{constructor(){this.listeners=new Map;}on(n,t){this.listeners.has(n)||this.listeners.set(n,new Set),this.listeners.get(n).add(t);}off(n,t){let e=this.listeners.get(n);e&&e.delete(t);}once(n,t){let e=((...i)=>{t(...i),this.off(n,e);});this.on(n,e);}emit(n,...t){let e=this.listeners.get(n);e&&e.forEach(i=>i(...t));}removeAllListeners(){this.listeners.clear();}};var u=class extends a{constructor(){super();this.socket=null;this.apiKey=null;this.serverUrl=null;}connect(t,e){if(this.socket?.connected)return;this.apiKey=t,this.serverUrl=e;let i=e.endsWith("/")?e.slice(0,-1):e;this.socket=io(`${i}/sdk`,{auth:{apiKey:t},transports:["websocket"]}),this.socket.on("connect",()=>{this.emit("connected");}),this.socket.on("disconnect",s=>{this.emit("disconnected",s);}),this.socket.on("connect_error",s=>{this.emit("error",s);}),this.socket.on("d",s=>{try{let r=s instanceof Uint8Array?s:new Uint8Array(s),o=l.decodeServerEnvelope(r);this.emit("message",o);}catch(r){this.emit("error",new Error(`Failed to decode message: ${r}`));}});}async waitForConnection(){if(console.log("[Synxed] Waiting for connection..."),this.socket?.connected){console.log("[Synxed] Already connected");return}return new Promise((t,e)=>{let i=()=>{console.log("[Synxed] Socket connected event fired"),r(),t();},s=o=>{console.error("[Synxed] Socket connection error:",o),r(),e(o);},r=()=>{this.socket?.off("connect",i),this.socket?.off("connect_error",s);};this.socket?.once("connect",i),this.socket?.once("connect_error",s),this.socket||(console.error("[Synxed] No socket instance found"),e(new Error("Socket not initialized. Call connect() first.")));})}disconnect(){this.socket&&(this.socket.disconnect(),this.socket=null);}sendInit(t){if(!this.socket?.connected)throw new Error("Socket not connected");console.log("[Synxed] Sending init packet:",t);let e={init:t},i=l.encodeClientEnvelope(e);this.socket.emit("d",i);}sendControl(t){if(!this.socket?.connected)return;let e={control:t},i=l.encodeClientEnvelope(e);this.socket.emit("d",i);}sendAnalytics(t){if(!this.socket?.connected)return;let e={analytics:t},i=l.encodeClientEnvelope(e);this.socket.emit("d",i);}get isConnected(){return this.socket?.connected||false}};var h=class extends a{constructor(){super();this.howl=null;this.hls=null;this.audioEl=null;this.updateTimer=null;}async load(t,e){this.stop(),this.emit("loading"),console.log("[Synxed] AudioEngine loading URL:",t,"isHls:",e);let i=/^((?!chrome|android).)*safari/i.test(navigator.userAgent);if(e&&!i)try{let{default:s}=await import('hls.js');if(s.isSupported()){console.log("[Synxed] Using Hls.js for playback");let o=new URL(t).search;this.hls=new s,this.audioEl=new Audio,this.hls.loadSource(t),this.hls.attachMedia(this.audioEl),this.audioEl.onplay=()=>{this.emit("playing"),this.startTimeUpdateLoop();},this.audioEl.onpause=()=>{this.emit("paused"),this.stopTimeUpdateLoop();},this.audioEl.onended=()=>{this.emit("ended"),this.stopTimeUpdateLoop();},this.audioEl.onerror=v=>{console.error("[Synxed] HLS Audio error:",v),this.emit("error",v);},this.audioEl.onloadedmetadata=()=>{this.emit("loaded");},this.hls.on(s.Events.ERROR,(v,g)=>{g.fatal&&(console.error("[Synxed] Fatal HLS error:",g),this.emit("error",g));});return}}catch{console.warn("[Synxed] hls.js not found or error loading, falling back to native");}this.howl=new Howl({src:[t],html5:true,format:e?["m3u8"]:void 0,onload:()=>{console.log("[Synxed] AudioEngine loaded successfully"),this.emit("loaded");},onloaderror:(s,r)=>{console.error("[Synxed] AudioEngine load error:",r,"ID:",s),this.emit("error",r);},onplay:()=>{this.emit("playing"),this.startTimeUpdateLoop();},onpause:()=>{this.emit("paused"),this.stopTimeUpdateLoop();},onstop:()=>{this.emit("stopped"),this.stopTimeUpdateLoop();},onend:()=>{this.emit("ended"),this.stopTimeUpdateLoop();}});}play(){this.audioEl?this.audioEl.play().catch(t=>console.error("[Synxed] Play failed:",t)):this.howl?.play();}pause(){this.audioEl?this.audioEl.pause():this.howl?.pause();}stop(){this.hls&&(this.hls.destroy(),this.hls=null),this.audioEl&&(this.audioEl.pause(),this.audioEl.src="",this.audioEl=null),this.howl&&(this.howl.stop(),this.howl.unload(),this.howl=null),this.stopTimeUpdateLoop();}seek(t){this.audioEl?this.audioEl.currentTime=t/1e3:this.howl?.seek(t/1e3);}setVolume(t){this.audioEl&&(this.audioEl.volume=t),this.howl&&this.howl.volume(t);}get duration(){return this.audioEl?this.audioEl.duration*1e3:(this.howl?.duration()||0)*1e3}get currentTime(){return this.audioEl?this.audioEl.currentTime*1e3:(this.howl?.seek()||0)*1e3}startTimeUpdateLoop(){this.stopTimeUpdateLoop();let t=()=>{(this.audioEl?!this.audioEl.paused:this.howl?.playing())&&(this.emit("timeupdate",{currentTime:this.currentTime,duration:this.duration}),this.updateTimer=requestAnimationFrame(t));};this.updateTimer=requestAnimationFrame(t);}stopTimeUpdateLoop(){this.updateTimer!==null&&(cancelAnimationFrame(this.updateTimer),this.updateTimer=null);}};var p=class extends a{constructor(){super();this.queue=[];this.currentIndex=-1;}setQueue(t){this.queue=t,this.currentIndex=t.length>0?0:-1,this.emit("queueUpdated",this.queue);}getCurrentTrack(){return this.currentIndex>=0&&this.currentIndex<this.queue.length?this.queue[this.currentIndex]:null}next(){if(this.currentIndex<this.queue.length-1){this.currentIndex++;let t=this.getCurrentTrack();return this.emit("trackChanged",t),t}return null}previous(){if(this.currentIndex>0){this.currentIndex--;let t=this.getCurrentTrack();return this.emit("trackChanged",t),t}return null}skipTo(t){if(t>=0&&t<this.queue.length){this.currentIndex=t;let e=this.getCurrentTrack();return this.emit("trackChanged",e),e}return null}get hasNext(){return this.currentIndex<this.queue.length-1}get hasPrevious(){return this.currentIndex>0}};var c=class extends Error{constructor(t,e){super(t);this.code=e;this.name="SynxedError";}},m=class extends c{constructor(n){super(n),this.name="SynxedConnectionError";}},y=class extends c{constructor(n){super(typeof n=="string"?n:"Playback failed"),this.name="SynxedPlaybackError";}},I=class extends c{constructor(n){super(n),this.name="SynxedProtocolError";}};var A=class extends a{constructor(t){super();this.status="idle";this.config=t,this.transport=new u,this.audio=new h,this.playlist=new p,this.setupListeners(),t.autoConnect&&this.connect();}setupListeners(){this.transport.on("connected",()=>this.emit("connected")),this.transport.on("disconnected",t=>this.emit("disconnected",t)),this.transport.on("error",t=>this.emit("error",new m(t.message))),this.transport.on("message",t=>this.handleServerMessage(t)),this.audio.on("playing",()=>this.updateStatus("playing")),this.audio.on("paused",()=>this.updateStatus("paused")),this.audio.on("stopped",()=>this.updateStatus("idle")),this.audio.on("loading",()=>this.updateStatus("loading")),this.audio.on("error",t=>this.emit("error",new y(t))),this.audio.on("timeupdate",t=>this.emit("timeUpdate",t)),this.audio.on("ended",()=>this.handleTrackEnded());}connect(){this.transport.connect(this.config.apiKey,this.config.serverUrl);}async playSong(t){this.transport.isConnected||this.connect(),await this.transport.waitForConnection(),this.transport.sendInit({contentKind:1,catalogTrackId:t.catalogTrackId,internalTrackId:t.internalTrackId,listenerId:t.listenerId});}async playPlaylist(t){this.transport.isConnected||this.connect(),await this.transport.waitForConnection(),this.transport.sendInit({contentKind:2,playlistCode:t.playlistCode,listenerId:t.listenerId});}pause(){this.audio.pause(),this.transport.sendControl({action:2,positionMs:Math.floor(this.audio.currentTime*1e3)});}resume(){this.audio.play(),this.transport.sendControl({action:1,positionMs:Math.floor(this.audio.currentTime*1e3)});}stop(){this.audio.stop(),this.transport.sendControl({action:3,positionMs:Math.floor(this.audio.currentTime*1e3)});}skip(){let t=this.playlist.next();t&&this.playSong({catalogTrackId:t.id});}seek(t){this.audio.seek(t),this.transport.sendControl({action:4,positionMs:t});}setVolume(t){this.audio.setVolume(t);}emitAnalytics(t,e,i){this.transport.sendAnalytics({eventType:t,positionMs:e??Math.floor(this.audio.currentTime*1e3),extraJson:i?JSON.stringify(i):void 0});}async handleServerMessage(t){if(console.log("[Synxed] Received server message:",t),t.initAck){let e=t.initAck;if(console.log("[Synxed] Loading playback URL:",e.playbackUrl,"isHls:",e.isHls),await this.audio.load(e.playbackUrl,e.isHls),this.audio.play(),this.emitAnalytics("stream_start"),e.contentSummary)try{let i=JSON.parse(e.contentSummary);i.tracks&&this.playlist.setQueue(i.tracks);}catch{}}else t.error&&this.emit("error",new c(t.error.message,t.error.code));}handleTrackEnded(){this.playlist.hasNext?this.skip():this.updateStatus("idle");}updateStatus(t){this.status=t,this.emit("stateChange",{status:t,currentTime:this.audio.currentTime,duration:this.audio.duration,volume:1});}destroy(){this.audio.stop(),this.transport.disconnect(),this.removeAllListeners();}};export{E as ContentKind,x as ErrorCode,m as SynxedConnectionError,c as SynxedError,y as SynxedPlaybackError,A as SynxedPlayer,I as SynxedProtocolError};//# sourceMappingURL=index.mjs.map
|
|
59
81
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/proto/sdk-streaming.ts","../src/transport/ProtocolCodec.ts","../src/core/EventEmitter.ts","../src/transport/TransportManager.ts","../src/audio/AudioEngine.ts","../src/playlist/PlaylistManager.ts","../src/core/errors.ts","../src/core/SynxedPlayer.ts"],"names":["schema","root","SdkClientEnvelope","SdkServerEnvelope","ContentKind","ErrorCode","ProtocolCodec","payload","message","data","decoded","EventEmitter","event","handler","set","onceHandler","args","TransportManager","apiKey","serverUrl","io","reason","error","uint8Array","err","params","bytes","AudioEngine","url","isHls","Howl","id","ms","volume","update","PlaylistManager","tracks","track","index","SynxedError","code","SynxedConnectionError","SynxedPlaybackError","SynxedProtocolError","SynxedPlayer","config","time","options","nextTrack","ack","summary","status"],"mappings":"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","file":"index.mjs","sourcesContent":["import * as protobuf from 'protobufjs';\n\n/**\n * Protobuf schema definition for the SDK.\n * Matches the backend contract in src/modules/streaming/sdk-streaming.proto\n */\nconst schema = `\nsyntax = \"proto3\";\n\nenum ContentKind {\n CONTENT_KIND_UNSPECIFIED = 0;\n CONTENT_KIND_SONG = 1;\n CONTENT_KIND_PLAYLIST = 2;\n CONTENT_KIND_CATEGORY = 3;\n}\n\nenum ErrorCode {\n ERROR_CODE_UNSPECIFIED = 0;\n UNAUTHORIZED = 1;\n VALIDATION_ERROR = 2;\n NOT_FOUND = 3;\n PROCESSING = 4;\n SERVICE_UNAVAILABLE = 5;\n BAD_PROTOBUF = 6;\n}\n\nmessage SdkClientInit {\n ContentKind content_kind = 1;\n string catalog_track_id = 2;\n string internal_track_id = 3;\n string playlist_code = 4;\n string listener_id = 5;\n string device_type = 6;\n string country_code = 7;\n string region = 8;\n string protocol_version = 9;\n}\n\nmessage SdkClientEnvelope {\n oneof payload {\n SdkClientInit init = 1;\n }\n}\n\nmessage SdkServerInitAck {\n string session_id = 1;\n string playback_url = 2;\n bool is_hls = 3;\n uint32 heartbeat_interval_ms = 4;\n string content_summary = 5;\n}\n\nmessage SdkServerError {\n ErrorCode code = 1;\n string message = 2;\n}\n\nmessage SdkServerEnvelope {\n oneof payload {\n SdkServerInitAck init_ack = 1;\n SdkServerError error = 2;\n }\n}\n`;\n\nconst root = protobuf.parse(schema).root;\n\nexport const SdkClientEnvelope = root.lookupType('SdkClientEnvelope');\nexport const SdkServerEnvelope = root.lookupType('SdkServerEnvelope');\n\nexport enum ContentKind {\n UNSPECIFIED = 0,\n SONG = 1,\n PLAYLIST = 2,\n CATEGORY = 3,\n}\n\nexport enum ErrorCode {\n UNSPECIFIED = 0,\n UNAUTHORIZED = 1,\n VALIDATION_ERROR = 2,\n NOT_FOUND = 3,\n PROCESSING = 4,\n SERVICE_UNAVAILABLE = 5,\n BAD_PROTOBUF = 6,\n}\n","import { SdkClientEnvelope, SdkServerEnvelope } from '../proto/sdk-streaming';\n\nexport class ProtocolCodec {\n /**\n * Encodes a client envelope into a binary payload.\n */\n static encodeClientEnvelope(payload: any): Uint8Array {\n const message = SdkClientEnvelope.create(payload);\n return SdkClientEnvelope.encode(message).finish();\n }\n\n /**\n * Decodes a binary payload into a server envelope.\n */\n static decodeServerEnvelope(data: Uint8Array): any {\n const decoded = SdkServerEnvelope.decode(data);\n return SdkServerEnvelope.toObject(decoded, {\n enums: String,\n longs: String,\n bytes: String,\n defaults: true,\n oneofs: true,\n });\n }\n}\n","type Handler = (...args: any[]) => void;\n\nexport class EventEmitter<Events extends Record<string, any>> {\n private listeners: Map<keyof Events, Set<Handler>> = new Map();\n\n on<K extends keyof Events>(event: K, handler: Events[K]): void {\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set());\n }\n this.listeners.get(event)!.add(handler);\n }\n\n off<K extends keyof Events>(event: K, handler: Events[K]): void {\n const set = this.listeners.get(event);\n if (set) {\n set.delete(handler);\n }\n }\n\n once<K extends keyof Events>(event: K, handler: Events[K]): void {\n const onceHandler = ((...args: any[]) => {\n handler(...args);\n this.off(event, onceHandler as Events[K]);\n }) as Events[K];\n this.on(event, onceHandler);\n }\n\n protected emit<K extends keyof Events>(event: K, ...args: Parameters<Events[K]>): void {\n const set = this.listeners.get(event);\n if (set) {\n set.forEach((handler) => handler(...args));\n }\n }\n\n removeAllListeners(): void {\n this.listeners.clear();\n }\n}\n","import { io, Socket } from 'socket.io-client';\nimport { ProtocolCodec } from './ProtocolCodec';\nimport { EventEmitter } from '../core/EventEmitter';\n\nexport interface TransportEvents {\n connected: () => void;\n disconnected: (reason: string) => void;\n error: (error: any) => void;\n message: (payload: any) => void;\n}\n\nexport class TransportManager extends EventEmitter<TransportEvents> {\n private socket: Socket | null = null;\n private apiKey: string | null = null;\n private serverUrl: string | null = null;\n\n constructor() {\n super();\n }\n\n /**\n * Connects to the Synxed SDK namespace.\n */\n connect(apiKey: string, serverUrl: string): void {\n if (this.socket?.connected) return;\n\n this.apiKey = apiKey;\n this.serverUrl = serverUrl;\n\n this.socket = io(`${serverUrl}/sdk`, {\n auth: { apiKey },\n transports: ['websocket'],\n });\n\n this.socket.on('connect', () => {\n this.emit('connected');\n });\n\n this.socket.on('disconnect', (reason) => {\n this.emit('disconnected', reason);\n });\n\n this.socket.on('connect_error', (error) => {\n this.emit('error', error);\n });\n\n this.socket.on('d', (data: ArrayBuffer | Uint8Array) => {\n try {\n const uint8Array = data instanceof Uint8Array ? data : new Uint8Array(data);\n const payload = ProtocolCodec.decodeServerEnvelope(uint8Array);\n this.emit('message', payload);\n } catch (err) {\n this.emit('error', new Error(`Failed to decode message: ${err}`));\n }\n });\n }\n\n /**\n * Disconnects from the server.\n */\n disconnect(): void {\n if (this.socket) {\n this.socket.disconnect();\n this.socket = null;\n }\n }\n\n /**\n * Sends an init message to the backend.\n */\n sendInit(params: any): void {\n if (!this.socket?.connected) {\n throw new Error('Socket not connected');\n }\n\n const payload = { init: params };\n const bytes = ProtocolCodec.encodeClientEnvelope(payload);\n this.socket.emit('d', bytes);\n }\n\n /**\n * Checks if the socket is connected.\n */\n get isConnected(): boolean {\n return this.socket?.connected || false;\n }\n}\n","import { Howl } from 'howler';\nimport { EventEmitter } from '../core/EventEmitter';\n\nexport interface AudioEvents {\n playing: () => void;\n paused: () => void;\n stopped: () => void;\n ended: () => void;\n loading: () => void;\n loaded: () => void;\n error: (error: any) => void;\n timeupdate: (data: { currentTime: number; duration: number }) => void;\n}\n\nexport class AudioEngine extends EventEmitter<AudioEvents> {\n private howl: Howl | null = null;\n private updateTimer: number | null = null;\n\n constructor() {\n super();\n }\n\n /**\n * Loads a track URL.\n */\n load(url: string, isHls: boolean): void {\n this.stop();\n this.emit('loading');\n\n // For HLS, we'd ideally use hls.js. \n // Howler doesn't natively support HLS streams well without custom logic.\n // For now, we'll use HTML5 audio mode which works for some HLS streams natively.\n this.howl = new Howl({\n src: [url],\n html5: true, // Required for streaming large files\n format: isHls ? ['m3u8'] : undefined,\n onload: () => {\n this.emit('loaded');\n },\n onloaderror: (id, err) => {\n this.emit('error', err);\n },\n onplay: () => {\n this.emit('playing');\n this.startTimeUpdateLoop();\n },\n onpause: () => {\n this.emit('paused');\n this.stopTimeUpdateLoop();\n },\n onstop: () => {\n this.emit('stopped');\n this.stopTimeUpdateLoop();\n },\n onend: () => {\n this.emit('ended');\n this.stopTimeUpdateLoop();\n },\n });\n }\n\n play(): void {\n this.howl?.play();\n }\n\n pause(): void {\n this.howl?.pause();\n }\n\n stop(): void {\n this.howl?.stop();\n this.howl?.unload();\n this.howl = null;\n }\n\n seek(ms: number): void {\n this.howl?.seek(ms / 1000);\n }\n\n setVolume(volume: number): void {\n this.howl?.volume(volume);\n }\n\n get duration(): number {\n return (this.howl?.duration() || 0) * 1000;\n }\n\n get currentTime(): number {\n return (this.howl?.seek() as number || 0) * 1000;\n }\n\n private startTimeUpdateLoop(): void {\n this.stopTimeUpdateLoop();\n const update = () => {\n if (this.howl?.playing()) {\n this.emit('timeupdate', {\n currentTime: this.currentTime,\n duration: this.duration,\n });\n this.updateTimer = requestAnimationFrame(update);\n }\n };\n this.updateTimer = requestAnimationFrame(update);\n }\n\n private stopTimeUpdateLoop(): void {\n if (this.updateTimer !== null) {\n cancelAnimationFrame(this.updateTimer);\n this.updateTimer = null;\n }\n }\n}\n","import { EventEmitter } from '../core/EventEmitter';\n\nexport interface PlaylistEvents {\n trackChanged: (track: any) => void;\n queueUpdated: (tracks: any[]) => void;\n}\n\nexport class PlaylistManager extends EventEmitter<PlaylistEvents> {\n private queue: any[] = [];\n private currentIndex: number = -1;\n\n constructor() {\n super();\n }\n\n setQueue(tracks: any[]): void {\n this.queue = tracks;\n this.currentIndex = tracks.length > 0 ? 0 : -1;\n this.emit('queueUpdated', this.queue);\n }\n\n getCurrentTrack(): any | null {\n if (this.currentIndex >= 0 && this.currentIndex < this.queue.length) {\n return this.queue[this.currentIndex];\n }\n return null;\n }\n\n next(): any | null {\n if (this.currentIndex < this.queue.length - 1) {\n this.currentIndex++;\n const track = this.getCurrentTrack();\n this.emit('trackChanged', track);\n return track;\n }\n return null;\n }\n\n previous(): any | null {\n if (this.currentIndex > 0) {\n this.currentIndex--;\n const track = this.getCurrentTrack();\n this.emit('trackChanged', track);\n return track;\n }\n return null;\n }\n\n skipTo(index: number): any | null {\n if (index >= 0 && index < this.queue.length) {\n this.currentIndex = index;\n const track = this.getCurrentTrack();\n this.emit('trackChanged', track);\n return track;\n }\n return null;\n }\n\n get hasNext(): boolean {\n return this.currentIndex < this.queue.length - 1;\n }\n\n get hasPrevious(): boolean {\n return this.currentIndex > 0;\n }\n}\n","export class SynxedError extends Error {\n constructor(message: string, public code?: string) {\n super(message);\n this.name = 'SynxedError';\n }\n}\n\nexport class SynxedConnectionError extends SynxedError {\n constructor(message: string) {\n super(message);\n this.name = 'SynxedConnectionError';\n }\n}\n\nexport class SynxedPlaybackError extends SynxedError {\n constructor(error: any) {\n super(typeof error === 'string' ? error : 'Playback failed');\n this.name = 'SynxedPlaybackError';\n }\n}\n\nexport class SynxedProtocolError extends SynxedError {\n constructor(message: string) {\n super(message);\n this.name = 'SynxedProtocolError';\n }\n}\n","import { TransportManager } from '../transport/TransportManager';\nimport { AudioEngine } from '../audio/AudioEngine';\nimport { PlaylistManager } from '../playlist/PlaylistManager';\nimport { EventEmitter } from './EventEmitter';\nimport { ContentKind } from '../proto/sdk-streaming';\nimport { SynxedConfig, PlayerState, PlaySongOptions, PlayPlaylistOptions, SynxedEvents } from '../types';\nimport { SynxedError, SynxedPlaybackError, SynxedConnectionError } from './errors';\n\nexport class SynxedPlayer extends EventEmitter<SynxedEvents> {\n private transport: TransportManager;\n private audio: AudioEngine;\n private playlist: PlaylistManager;\n private config: SynxedConfig;\n private status: PlayerState['status'] = 'idle';\n\n constructor(config: SynxedConfig) {\n super();\n this.config = config;\n this.transport = new TransportManager();\n this.audio = new AudioEngine();\n this.playlist = new PlaylistManager();\n\n this.setupListeners();\n\n if (config.autoConnect) {\n this.connect();\n }\n }\n\n private setupListeners(): void {\n // Transport Listeners\n this.transport.on('connected', () => this.emit('connected'));\n this.transport.on('disconnected', (reason) => this.emit('disconnected', reason));\n this.transport.on('error', (error) => this.emit('error', new SynxedConnectionError(error.message)));\n this.transport.on('message', (payload) => this.handleServerMessage(payload));\n\n // Audio Listeners\n this.audio.on('playing', () => this.updateStatus('playing'));\n this.audio.on('paused', () => this.updateStatus('paused'));\n this.audio.on('stopped', () => this.updateStatus('idle'));\n this.audio.on('loading', () => this.updateStatus('loading'));\n this.audio.on('error', (error) => this.emit('error', new SynxedPlaybackError(error)));\n this.audio.on('timeupdate', (time) => this.emit('timeUpdate', time));\n this.audio.on('ended', () => this.handleTrackEnded());\n }\n\n private connect(): void {\n this.transport.connect(this.config.apiKey, this.config.serverUrl);\n }\n\n async playSong(options: PlaySongOptions): Promise<void> {\n if (!this.transport.isConnected) this.connect();\n \n this.transport.sendInit({\n content_kind: ContentKind.SONG,\n catalog_track_id: options.catalogTrackId,\n internal_track_id: options.internalTrackId,\n listener_id: options.listenerId,\n });\n }\n\n async playPlaylist(options: PlayPlaylistOptions): Promise<void> {\n if (!this.transport.isConnected) this.connect();\n\n this.transport.sendInit({\n content_kind: ContentKind.PLAYLIST,\n playlist_code: options.playlistCode,\n listener_id: options.listenerId,\n });\n }\n\n pause(): void {\n this.audio.pause();\n }\n\n resume(): void {\n this.audio.play();\n }\n\n stop(): void {\n this.audio.stop();\n }\n\n skip(): void {\n const nextTrack = this.playlist.next();\n if (nextTrack) {\n // In current backend, we need to re-init for each track\n // This logic will be refined once backend handles queues\n this.playSong({ catalogTrackId: nextTrack.id }); \n }\n }\n\n seek(ms: number): void {\n this.audio.seek(ms);\n }\n\n setVolume(volume: number): void {\n this.audio.setVolume(volume);\n }\n\n private handleServerMessage(payload: any): void {\n if (payload.init_ack) {\n const ack = payload.init_ack;\n this.audio.load(ack.playback_url, ack.is_hls);\n this.audio.play();\n \n // Parse content_summary if it's a playlist\n if (ack.content_summary) {\n try {\n const summary = JSON.parse(ack.content_summary);\n if (summary.tracks) {\n this.playlist.setQueue(summary.tracks);\n }\n } catch (e) {\n // Ignore parse errors for now\n }\n }\n } else if (payload.error) {\n this.emit('error', new SynxedError(payload.error.message, payload.error.code));\n }\n }\n\n private handleTrackEnded(): void {\n if (this.playlist.hasNext) {\n this.skip();\n } else {\n this.updateStatus('idle');\n }\n }\n\n private updateStatus(status: PlayerState['status']): void {\n this.status = status;\n this.emit('stateChange', {\n status,\n currentTime: this.audio.currentTime,\n duration: this.audio.duration,\n volume: 1, // Store volume locally if needed\n });\n }\n\n destroy(): void {\n this.audio.stop();\n this.transport.disconnect();\n this.removeAllListeners();\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/proto/sdk-streaming.ts","../src/transport/ProtocolCodec.ts","../src/core/EventEmitter.ts","../src/transport/TransportManager.ts","../src/audio/AudioEngine.ts","../src/playlist/PlaylistManager.ts","../src/core/errors.ts","../src/core/SynxedPlayer.ts"],"names":["schema","root","SdkClientEnvelope","SdkServerEnvelope","ContentKind","ErrorCode","ProtocolCodec","payload","message","data","decoded","EventEmitter","event","handler","set","onceHandler","args","TransportManager","apiKey","serverUrl","normalizedUrl","io","reason","error","uint8Array","err","resolve","reject","onConnect","cleanup","onError","params","bytes","AudioEngine","url","isHls","isSafari","Hls","searchParams","e","Howl","id","ms","volume","update","PlaylistManager","tracks","track","index","SynxedError","code","SynxedConnectionError","SynxedPlaybackError","SynxedProtocolError","SynxedPlayer","config","time","options","nextTrack","eventType","positionMs","extra","ack","summary","status"],"mappings":"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","file":"index.mjs","sourcesContent":["import * as protobuf from 'protobufjs';\n\n/**\n * Protobuf schema definition for the SDK.\n * Matches the backend contract in src/modules/streaming/sdk-streaming.proto\n */\nconst schema = `\nsyntax = \"proto3\";\n\nenum ContentKind {\n CONTENT_KIND_UNSPECIFIED = 0;\n CONTENT_KIND_SONG = 1;\n CONTENT_KIND_PLAYLIST = 2;\n CONTENT_KIND_CATEGORY = 3;\n}\n\nenum ErrorCode {\n ERROR_CODE_UNSPECIFIED = 0;\n UNAUTHORIZED = 1;\n VALIDATION_ERROR = 2;\n NOT_FOUND = 3;\n PROCESSING = 4;\n SERVICE_UNAVAILABLE = 5;\n BAD_PROTOBUF = 6;\n}\n\nenum SdkControlAction {\n CONTROL_UNSPECIFIED = 0;\n CONTROL_PLAY = 1;\n CONTROL_PAUSE = 2;\n CONTROL_STOP = 3;\n CONTROL_SEEK = 4;\n}\n\nmessage SdkClientInit {\n ContentKind contentKind = 1;\n string catalogTrackId = 2;\n string internalTrackId = 3;\n string playlistCode = 4;\n string categoryQuery = 5;\n string listenerId = 6;\n string deviceType = 7;\n string countryCode = 8;\n string region = 9;\n string protocolVersion = 10;\n}\n\nmessage SdkClientControl {\n SdkControlAction action = 1;\n uint32 positionMs = 2;\n}\n\nmessage SdkClientAnalytics {\n string eventType = 1;\n uint32 positionMs = 2;\n string extraJson = 3;\n}\n\nmessage SdkClientEnvelope {\n oneof payload {\n SdkClientInit init = 1;\n SdkClientControl control = 2;\n SdkClientAnalytics analytics = 3;\n }\n}\n\nmessage SdkServerInitAck {\n string sessionId = 1;\n string playbackUrl = 2;\n bool isHls = 3;\n uint32 heartbeatIntervalMs = 4;\n string contentSummary = 5;\n}\n\nmessage SdkServerError {\n ErrorCode code = 1;\n string message = 2;\n}\n\nmessage SdkServerEnvelope {\n oneof payload {\n SdkServerInitAck initAck = 1;\n SdkServerError error = 2;\n }\n}\n`;\n\nconst root = protobuf.parse(schema).root;\n\nexport const SdkClientEnvelope = root.lookupType('SdkClientEnvelope');\nexport const SdkServerEnvelope = root.lookupType('SdkServerEnvelope');\n\nexport enum ContentKind {\n UNSPECIFIED = 0,\n SONG = 1,\n PLAYLIST = 2,\n CATEGORY = 3,\n}\n\nexport enum ErrorCode {\n UNSPECIFIED = 0,\n UNAUTHORIZED = 1,\n VALIDATION_ERROR = 2,\n NOT_FOUND = 3,\n PROCESSING = 4,\n SERVICE_UNAVAILABLE = 5,\n BAD_PROTOBUF = 6,\n}\n","import { SdkClientEnvelope, SdkServerEnvelope } from '../proto/sdk-streaming';\n\nexport class ProtocolCodec {\n /**\n * Encodes a client envelope into a binary payload.\n */\n static encodeClientEnvelope(payload: any): Uint8Array {\n const message = SdkClientEnvelope.create(payload);\n return SdkClientEnvelope.encode(message).finish();\n }\n\n /**\n * Decodes a binary payload into a server envelope.\n */\n static decodeServerEnvelope(data: Uint8Array): any {\n const decoded = SdkServerEnvelope.decode(data);\n return SdkServerEnvelope.toObject(decoded, {\n enums: String,\n longs: String,\n bytes: String,\n defaults: true,\n oneofs: true,\n });\n }\n}\n","type Handler = (...args: any[]) => void;\n\nexport class EventEmitter<Events extends Record<string, any>> {\n private listeners: Map<keyof Events, Set<Handler>> = new Map();\n\n on<K extends keyof Events>(event: K, handler: Events[K]): void {\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set());\n }\n this.listeners.get(event)!.add(handler);\n }\n\n off<K extends keyof Events>(event: K, handler: Events[K]): void {\n const set = this.listeners.get(event);\n if (set) {\n set.delete(handler);\n }\n }\n\n once<K extends keyof Events>(event: K, handler: Events[K]): void {\n const onceHandler = ((...args: any[]) => {\n handler(...args);\n this.off(event, onceHandler as Events[K]);\n }) as Events[K];\n this.on(event, onceHandler);\n }\n\n protected emit<K extends keyof Events>(event: K, ...args: Parameters<Events[K]>): void {\n const set = this.listeners.get(event);\n if (set) {\n set.forEach((handler) => handler(...args));\n }\n }\n\n removeAllListeners(): void {\n this.listeners.clear();\n }\n}\n","import { io, Socket } from 'socket.io-client';\nimport { ProtocolCodec } from './ProtocolCodec';\nimport { EventEmitter } from '../core/EventEmitter';\n\nexport interface TransportEvents {\n connected: () => void;\n disconnected: (reason: string) => void;\n error: (error: any) => void;\n message: (payload: any) => void;\n}\n\nexport class TransportManager extends EventEmitter<TransportEvents> {\n private socket: Socket | null = null;\n private apiKey: string | null = null;\n private serverUrl: string | null = null;\n\n constructor() {\n super();\n }\n\n /**\n * Connects to the Synxed SDK namespace.\n */\n connect(apiKey: string, serverUrl: string): void {\n if (this.socket?.connected) return;\n\n this.apiKey = apiKey;\n this.serverUrl = serverUrl;\n\n const normalizedUrl = serverUrl.endsWith('/') ? serverUrl.slice(0, -1) : serverUrl;\n\n this.socket = io(`${normalizedUrl}/sdk`, {\n auth: { apiKey },\n transports: ['websocket'],\n });\n\n this.socket.on('connect', () => {\n this.emit('connected');\n });\n\n this.socket.on('disconnect', (reason) => {\n this.emit('disconnected', reason);\n });\n\n this.socket.on('connect_error', (error) => {\n this.emit('error', error);\n });\n\n this.socket.on('d', (data: ArrayBuffer | Uint8Array) => {\n try {\n const uint8Array = data instanceof Uint8Array ? data : new Uint8Array(data);\n const payload = ProtocolCodec.decodeServerEnvelope(uint8Array);\n this.emit('message', payload);\n } catch (err) {\n this.emit('error', new Error(`Failed to decode message: ${err}`));\n }\n });\n }\n\n /**\n * Returns a promise that resolves when the socket is connected.\n */\n async waitForConnection(): Promise<void> {\n console.log('[Synxed] Waiting for connection...');\n if (this.socket?.connected) {\n console.log('[Synxed] Already connected');\n return;\n }\n \n return new Promise((resolve, reject) => {\n const onConnect = () => {\n console.log('[Synxed] Socket connected event fired');\n cleanup();\n resolve();\n };\n \n const onError = (err: any) => {\n console.error('[Synxed] Socket connection error:', err);\n cleanup();\n reject(err);\n };\n \n const cleanup = () => {\n this.socket?.off('connect', onConnect);\n this.socket?.off('connect_error', onError);\n };\n\n this.socket?.once('connect', onConnect);\n this.socket?.once('connect_error', onError);\n \n if (!this.socket) {\n console.error('[Synxed] No socket instance found');\n reject(new Error('Socket not initialized. Call connect() first.'));\n }\n });\n }\n\n /**\n * Disconnects from the server.\n */\n disconnect(): void {\n if (this.socket) {\n this.socket.disconnect();\n this.socket = null;\n }\n }\n\n /**\n * Sends an init message to the backend.\n */\n sendInit(params: any): void {\n if (!this.socket?.connected) {\n throw new Error('Socket not connected');\n }\n\n console.log('[Synxed] Sending init packet:', params);\n const payload = { init: params };\n const bytes = ProtocolCodec.encodeClientEnvelope(payload);\n this.socket.emit('d', bytes);\n }\n\n /**\n * Sends a control message.\n */\n sendControl(params: any): void {\n if (!this.socket?.connected) return;\n const payload = { control: params };\n const bytes = ProtocolCodec.encodeClientEnvelope(payload);\n this.socket.emit('d', bytes);\n }\n\n /**\n * Sends an analytics message.\n */\n sendAnalytics(params: any): void {\n if (!this.socket?.connected) return;\n const payload = { analytics: params };\n const bytes = ProtocolCodec.encodeClientEnvelope(payload);\n this.socket.emit('d', bytes);\n }\n\n /**\n * Checks if the socket is connected.\n */\n get isConnected(): boolean {\n return this.socket?.connected || false;\n }\n}\n","import { Howl } from 'howler';\nimport { EventEmitter } from '../core/EventEmitter';\n\nexport interface AudioEvents {\n playing: () => void;\n paused: () => void;\n stopped: () => void;\n ended: () => void;\n loading: () => void;\n loaded: () => void;\n error: (error: any) => void;\n timeupdate: (data: { currentTime: number; duration: number }) => void;\n}\n\nexport class AudioEngine extends EventEmitter<AudioEvents> {\n private howl: Howl | null = null;\n private hls: any = null;\n private audioEl: HTMLAudioElement | null = null;\n private updateTimer: number | null = null;\n\n constructor() {\n super();\n }\n\n\n /**\n * Loads a track URL.\n */\n async load(url: string, isHls: boolean): Promise<void> {\n this.stop();\n this.emit('loading');\n\n console.log('[Synxed] AudioEngine loading URL:', url, 'isHls:', isHls);\n\n // Safari has native HLS support. Other browsers need hls.js.\n const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);\n\n if (isHls && !isSafari) {\n try {\n const { default: Hls } = await import('hls.js');\n if (Hls.isSupported()) {\n console.log('[Synxed] Using Hls.js for playback');\n \n // Extract query parameters from the manifest URL to forward to segments\n const urlObj = new URL(url);\n const searchParams = urlObj.search;\n\n this.hls = new Hls();\n this.audioEl = new Audio();\n this.hls.loadSource(url);\n this.hls.attachMedia(this.audioEl);\n \n this.audioEl.onplay = () => {\n this.emit('playing');\n this.startTimeUpdateLoop();\n };\n this.audioEl.onpause = () => {\n this.emit('paused');\n this.stopTimeUpdateLoop();\n };\n this.audioEl.onended = () => {\n this.emit('ended');\n this.stopTimeUpdateLoop();\n };\n this.audioEl.onerror = (e) => {\n console.error('[Synxed] HLS Audio error:', e);\n this.emit('error', e);\n };\n this.audioEl.onloadedmetadata = () => {\n this.emit('loaded');\n };\n\n this.hls.on(Hls.Events.ERROR, (event: any, data: any) => {\n if (data.fatal) {\n console.error('[Synxed] Fatal HLS error:', data);\n this.emit('error', data);\n }\n });\n\n return;\n }\n } catch (e) {\n console.warn('[Synxed] hls.js not found or error loading, falling back to native');\n }\n }\n\n // Fallback to Howler\n this.howl = new Howl({\n src: [url],\n html5: true, \n format: isHls ? ['m3u8'] : undefined,\n onload: () => {\n console.log('[Synxed] AudioEngine loaded successfully');\n this.emit('loaded');\n },\n onloaderror: (id, err) => {\n console.error('[Synxed] AudioEngine load error:', err, 'ID:', id);\n this.emit('error', err);\n },\n onplay: () => {\n this.emit('playing');\n this.startTimeUpdateLoop();\n },\n onpause: () => {\n this.emit('paused');\n this.stopTimeUpdateLoop();\n },\n onstop: () => {\n this.emit('stopped');\n this.stopTimeUpdateLoop();\n },\n onend: () => {\n this.emit('ended');\n this.stopTimeUpdateLoop();\n },\n });\n }\n\n play(): void {\n if (this.audioEl) {\n this.audioEl.play().catch(e => console.error('[Synxed] Play failed:', e));\n } else {\n this.howl?.play();\n }\n }\n\n pause(): void {\n if (this.audioEl) {\n this.audioEl.pause();\n } else {\n this.howl?.pause();\n }\n }\n\n stop(): void {\n if (this.hls) {\n this.hls.destroy();\n this.hls = null;\n }\n if (this.audioEl) {\n this.audioEl.pause();\n this.audioEl.src = '';\n this.audioEl = null;\n }\n if (this.howl) {\n this.howl.stop();\n this.howl.unload();\n this.howl = null;\n }\n this.stopTimeUpdateLoop();\n }\n\n seek(ms: number): void {\n if (this.audioEl) {\n this.audioEl.currentTime = ms / 1000;\n } else {\n this.howl?.seek(ms / 1000);\n }\n }\n\n setVolume(volume: number): void {\n if (this.audioEl) {\n this.audioEl.volume = volume;\n }\n if (this.howl) {\n this.howl.volume(volume);\n }\n }\n\n get duration(): number {\n if (this.audioEl) return this.audioEl.duration * 1000;\n return (this.howl?.duration() || 0) * 1000;\n }\n\n get currentTime(): number {\n if (this.audioEl) return this.audioEl.currentTime * 1000;\n return (this.howl?.seek() as number || 0) * 1000;\n }\n\n private startTimeUpdateLoop(): void {\n this.stopTimeUpdateLoop();\n const update = () => {\n const isPlaying = this.audioEl ? !this.audioEl.paused : this.howl?.playing();\n if (isPlaying) {\n this.emit('timeupdate', {\n currentTime: this.currentTime,\n duration: this.duration,\n });\n this.updateTimer = requestAnimationFrame(update);\n }\n };\n this.updateTimer = requestAnimationFrame(update);\n }\n\n private stopTimeUpdateLoop(): void {\n if (this.updateTimer !== null) {\n cancelAnimationFrame(this.updateTimer);\n this.updateTimer = null;\n }\n }\n}\n","import { EventEmitter } from '../core/EventEmitter';\n\nexport interface PlaylistEvents {\n trackChanged: (track: any) => void;\n queueUpdated: (tracks: any[]) => void;\n}\n\nexport class PlaylistManager extends EventEmitter<PlaylistEvents> {\n private queue: any[] = [];\n private currentIndex: number = -1;\n\n constructor() {\n super();\n }\n\n setQueue(tracks: any[]): void {\n this.queue = tracks;\n this.currentIndex = tracks.length > 0 ? 0 : -1;\n this.emit('queueUpdated', this.queue);\n }\n\n getCurrentTrack(): any | null {\n if (this.currentIndex >= 0 && this.currentIndex < this.queue.length) {\n return this.queue[this.currentIndex];\n }\n return null;\n }\n\n next(): any | null {\n if (this.currentIndex < this.queue.length - 1) {\n this.currentIndex++;\n const track = this.getCurrentTrack();\n this.emit('trackChanged', track);\n return track;\n }\n return null;\n }\n\n previous(): any | null {\n if (this.currentIndex > 0) {\n this.currentIndex--;\n const track = this.getCurrentTrack();\n this.emit('trackChanged', track);\n return track;\n }\n return null;\n }\n\n skipTo(index: number): any | null {\n if (index >= 0 && index < this.queue.length) {\n this.currentIndex = index;\n const track = this.getCurrentTrack();\n this.emit('trackChanged', track);\n return track;\n }\n return null;\n }\n\n get hasNext(): boolean {\n return this.currentIndex < this.queue.length - 1;\n }\n\n get hasPrevious(): boolean {\n return this.currentIndex > 0;\n }\n}\n","export class SynxedError extends Error {\n constructor(message: string, public code?: string) {\n super(message);\n this.name = 'SynxedError';\n }\n}\n\nexport class SynxedConnectionError extends SynxedError {\n constructor(message: string) {\n super(message);\n this.name = 'SynxedConnectionError';\n }\n}\n\nexport class SynxedPlaybackError extends SynxedError {\n constructor(error: any) {\n super(typeof error === 'string' ? error : 'Playback failed');\n this.name = 'SynxedPlaybackError';\n }\n}\n\nexport class SynxedProtocolError extends SynxedError {\n constructor(message: string) {\n super(message);\n this.name = 'SynxedProtocolError';\n }\n}\n","import { TransportManager } from '../transport/TransportManager';\nimport { AudioEngine } from '../audio/AudioEngine';\nimport { PlaylistManager } from '../playlist/PlaylistManager';\nimport { EventEmitter } from './EventEmitter';\nimport { ContentKind } from '../proto/sdk-streaming';\nimport { SynxedConfig, PlayerState, PlaySongOptions, PlayPlaylistOptions, SynxedEvents } from '../types';\nimport { SynxedError, SynxedPlaybackError, SynxedConnectionError } from './errors';\n\nexport class SynxedPlayer extends EventEmitter<SynxedEvents> {\n private transport: TransportManager;\n private audio: AudioEngine;\n private playlist: PlaylistManager;\n private config: SynxedConfig;\n private status: PlayerState['status'] = 'idle';\n\n constructor(config: SynxedConfig) {\n super();\n this.config = config;\n this.transport = new TransportManager();\n this.audio = new AudioEngine();\n this.playlist = new PlaylistManager();\n\n this.setupListeners();\n\n if (config.autoConnect) {\n this.connect();\n }\n }\n\n private setupListeners(): void {\n // Transport Listeners\n this.transport.on('connected', () => this.emit('connected'));\n this.transport.on('disconnected', (reason) => this.emit('disconnected', reason));\n this.transport.on('error', (error) => this.emit('error', new SynxedConnectionError(error.message)));\n this.transport.on('message', (payload) => this.handleServerMessage(payload));\n\n // Audio Listeners\n this.audio.on('playing', () => this.updateStatus('playing'));\n this.audio.on('paused', () => this.updateStatus('paused'));\n this.audio.on('stopped', () => this.updateStatus('idle'));\n this.audio.on('loading', () => this.updateStatus('loading'));\n this.audio.on('error', (error) => this.emit('error', new SynxedPlaybackError(error)));\n this.audio.on('timeupdate', (time) => this.emit('timeUpdate', time));\n this.audio.on('ended', () => this.handleTrackEnded());\n }\n\n private connect(): void {\n this.transport.connect(this.config.apiKey, this.config.serverUrl);\n }\n\n async playSong(options: PlaySongOptions): Promise<void> {\n if (!this.transport.isConnected) this.connect();\n await this.transport.waitForConnection();\n \n this.transport.sendInit({\n contentKind: ContentKind.SONG,\n catalogTrackId: options.catalogTrackId,\n internalTrackId: options.internalTrackId,\n listenerId: options.listenerId,\n });\n }\n\n async playPlaylist(options: PlayPlaylistOptions): Promise<void> {\n if (!this.transport.isConnected) this.connect();\n await this.transport.waitForConnection();\n\n this.transport.sendInit({\n contentKind: ContentKind.PLAYLIST,\n playlistCode: options.playlistCode,\n listenerId: options.listenerId,\n });\n }\n\n pause(): void {\n this.audio.pause();\n this.transport.sendControl({\n action: 2, // PAUSE\n positionMs: Math.floor(this.audio.currentTime * 1000),\n });\n }\n\n resume(): void {\n this.audio.play();\n this.transport.sendControl({\n action: 1, // PLAY\n positionMs: Math.floor(this.audio.currentTime * 1000),\n });\n }\n\n stop(): void {\n this.audio.stop();\n this.transport.sendControl({\n action: 3, // STOP\n positionMs: Math.floor(this.audio.currentTime * 1000),\n });\n }\n\n skip(): void {\n const nextTrack = this.playlist.next();\n if (nextTrack) {\n // In current backend, we need to re-init for each track\n // This logic will be refined once backend handles queues\n this.playSong({ catalogTrackId: nextTrack.id }); \n }\n }\n\n seek(ms: number): void {\n this.audio.seek(ms);\n this.transport.sendControl({\n action: 4, // SEEK\n positionMs: ms,\n });\n }\n\n setVolume(volume: number): void {\n this.audio.setVolume(volume);\n }\n\n private emitAnalytics(eventType: string, positionMs?: number, extra?: any): void {\n this.transport.sendAnalytics({\n eventType,\n positionMs: positionMs ?? Math.floor(this.audio.currentTime * 1000),\n extraJson: extra ? JSON.stringify(extra) : undefined,\n });\n }\n\n private async handleServerMessage(payload: any): Promise<void> {\n console.log('[Synxed] Received server message:', payload);\n if (payload.initAck) {\n const ack = payload.initAck;\n console.log('[Synxed] Loading playback URL:', ack.playbackUrl, 'isHls:', ack.isHls);\n await this.audio.load(ack.playbackUrl, ack.isHls);\n this.audio.play();\n this.emitAnalytics('stream_start');\n \n // Parse contentSummary if it's a playlist\n if (ack.contentSummary) {\n try {\n const summary = JSON.parse(ack.contentSummary);\n if (summary.tracks) {\n this.playlist.setQueue(summary.tracks);\n }\n } catch (e) {\n // Ignore parse errors for now\n }\n }\n } else if (payload.error) {\n this.emit('error', new SynxedError(payload.error.message, payload.error.code));\n }\n }\n\n private handleTrackEnded(): void {\n if (this.playlist.hasNext) {\n this.skip();\n } else {\n this.updateStatus('idle');\n }\n }\n\n private updateStatus(status: PlayerState['status']): void {\n this.status = status;\n this.emit('stateChange', {\n status,\n currentTime: this.audio.currentTime,\n duration: this.audio.duration,\n volume: 1, // Store volume locally if needed\n });\n }\n\n destroy(): void {\n this.audio.stop();\n this.transport.disconnect();\n this.removeAllListeners();\n }\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "synxed-sdk",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Synxed music SDK — integrate streaming music playback into any web app",
|
|
5
5
|
"bin": {
|
|
6
6
|
"synxed": "dist/cli.js"
|
|
@@ -27,15 +27,16 @@
|
|
|
27
27
|
"prepublishOnly": "npm run build"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"
|
|
30
|
+
"howler": "^2.2.4",
|
|
31
31
|
"protobufjs": "^7.3.0",
|
|
32
|
-
"
|
|
32
|
+
"socket.io-client": "^4.7.5"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
|
-
"
|
|
35
|
+
"@types/howler": "^2.2.11",
|
|
36
|
+
"hls.js": "^1.6.16",
|
|
36
37
|
"tsup": "^8.2.3",
|
|
37
|
-
"
|
|
38
|
-
"
|
|
38
|
+
"typescript": "^5.5.4",
|
|
39
|
+
"vitest": "^2.0.5"
|
|
39
40
|
},
|
|
40
41
|
"peerDependencies": {
|
|
41
42
|
"hls.js": "^1.5.0"
|