filepizza-client 2.0.1 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/peerjs.ts ADDED
@@ -0,0 +1,125 @@
1
+ // src/peerjs.ts
2
+ import Peer, { PeerOptions } from 'peerjs'
3
+ import { PeerJSSignalingServer } from './types'
4
+
5
+ const DEFAULT_ICE_SERVERS: RTCIceServer[] = [
6
+ { urls: 'stun:stun.l.google.com:19302' },
7
+ ]
8
+
9
+ export type PeerJSConfigOptions = {
10
+ filePizzaServerUrl: string
11
+ iceServers?: RTCIceServer[]
12
+ peerJSSignalingServer?: PeerJSSignalingServer
13
+ discoverPeerJSSignalingServer?: boolean
14
+ }
15
+
16
+ function normalizeBaseUrl(url: string): string {
17
+ return url.replace(/\/+$/, '')
18
+ }
19
+
20
+ function parsePeerJSServerUrl(serverUrlString: string): PeerJSSignalingServer {
21
+ const serverUrl = new URL(serverUrlString)
22
+
23
+ return {
24
+ host: serverUrl.hostname,
25
+ port: serverUrl.port
26
+ ? Number.parseInt(serverUrl.port, 10)
27
+ : serverUrl.protocol === 'https:'
28
+ ? 443
29
+ : 80,
30
+ path: serverUrl.pathname,
31
+ secure: serverUrl.protocol === 'https:',
32
+ }
33
+ }
34
+
35
+ export async function getIceServers(
36
+ filePizzaServerUrl: string,
37
+ ): Promise<RTCIceServer[]> {
38
+ try {
39
+ const response = await fetch(`${normalizeBaseUrl(filePizzaServerUrl)}/api/ice`, {
40
+ method: 'POST',
41
+ })
42
+
43
+ if (!response.ok) {
44
+ throw new Error(`Failed to get ICE servers: ${response.status}`)
45
+ }
46
+
47
+ const data = await response.json()
48
+ return data.iceServers || DEFAULT_ICE_SERVERS
49
+ } catch (error) {
50
+ console.error('Error getting ICE servers:', error)
51
+ return DEFAULT_ICE_SERVERS
52
+ }
53
+ }
54
+
55
+ export async function discoverPeerJSSignalingServer(
56
+ filePizzaServerUrl: string,
57
+ ): Promise<PeerJSSignalingServer | undefined> {
58
+ try {
59
+ const response = await fetch(
60
+ `${normalizeBaseUrl(filePizzaServerUrl)}/api/peerjs-servers`,
61
+ )
62
+
63
+ if (!response.ok) {
64
+ return undefined
65
+ }
66
+
67
+ const data = await response.json()
68
+ const firstServer = data.servers?.[0]
69
+
70
+ if (!firstServer) {
71
+ return undefined
72
+ }
73
+
74
+ return parsePeerJSServerUrl(firstServer)
75
+ } catch (error) {
76
+ console.error('Error discovering PeerJS signaling server:', error)
77
+ return undefined
78
+ }
79
+ }
80
+
81
+ export async function buildPeerOptions({
82
+ filePizzaServerUrl,
83
+ iceServers,
84
+ peerJSSignalingServer,
85
+ discoverPeerJSSignalingServer: shouldDiscover = true,
86
+ }: PeerJSConfigOptions): Promise<PeerOptions> {
87
+ const resolvedIceServers =
88
+ iceServers || (await getIceServers(filePizzaServerUrl))
89
+
90
+ const discoveredPeerJSSignalingServer =
91
+ peerJSSignalingServer || shouldDiscover
92
+ ? peerJSSignalingServer ||
93
+ (await discoverPeerJSSignalingServer(filePizzaServerUrl))
94
+ : undefined
95
+
96
+ return {
97
+ ...discoveredPeerJSSignalingServer,
98
+ config: {
99
+ iceServers: resolvedIceServers,
100
+ },
101
+ debug: 2,
102
+ }
103
+ }
104
+
105
+ export async function createPeer(
106
+ options: PeerJSConfigOptions,
107
+ ): Promise<Peer> {
108
+ const peerOptions = await buildPeerOptions(options)
109
+ const peer = new Peer(peerOptions)
110
+
111
+ if (peer.id) {
112
+ return peer
113
+ }
114
+
115
+ await new Promise<void>((resolve) => {
116
+ const onOpen = () => {
117
+ peer.off('open', onOpen)
118
+ resolve()
119
+ }
120
+
121
+ peer.on('open', onOpen)
122
+ })
123
+
124
+ return peer
125
+ }
package/src/types.ts CHANGED
@@ -1,10 +1,17 @@
1
- // src/core/types.ts
1
+ // src/types.ts
2
+ import type { PeerOptions } from 'peerjs'
3
+
2
4
  export interface EventEmitter {
3
- on(event: string, listener: (...args: any[]) => void): this;
4
- off(event: string, listener: (...args: any[]) => void): this;
5
- emit(event: string, ...args: any[]): boolean;
5
+ on(event: string, listener: (...args: any[]) => void): this
6
+ off(event: string, listener: (...args: any[]) => void): this
7
+ emit(event: string, ...args: any[]): boolean
6
8
  }
7
9
 
10
+ export type PeerJSSignalingServer = Pick<
11
+ PeerOptions,
12
+ 'host' | 'port' | 'path' | 'secure' | 'key' | 'token' | 'pingInterval'
13
+ >
14
+
8
15
  /**
9
16
  * Connection status
10
17
  */
@@ -18,66 +25,68 @@ export enum ConnectionStatus {
18
25
  Authenticating = 'AUTHENTICATING',
19
26
  InvalidPassword = 'INVALID_PASSWORD',
20
27
  Closed = 'CLOSED',
21
- Error = 'ERROR'
28
+ Error = 'ERROR',
22
29
  }
23
30
 
24
31
  /**
25
32
  * File information
26
33
  */
27
34
  export interface FileInfo {
28
- fileName: string;
29
- size: number;
30
- type: string;
35
+ fileName: string
36
+ size: number
37
+ type: string
31
38
  }
32
39
 
33
40
  /**
34
41
  * Interface for a completed file ready to download
35
42
  */
36
43
  export interface CompletedFile extends FileInfo {
37
- data: Uint8Array;
38
- downloadUrl?: string;
44
+ data: Uint8Array
45
+ downloadUrl?: string
39
46
  }
40
47
 
41
48
  /**
42
49
  * Progress information
43
50
  */
44
51
  export interface ProgressInfo {
45
- fileIndex: number;
46
- fileName: string;
47
- totalFiles: number;
48
- currentFileProgress: number;
49
- overallProgress: number;
50
- bytesTransferred: number;
51
- totalBytes: number;
52
+ fileIndex: number
53
+ fileName: string
54
+ totalFiles: number
55
+ currentFileProgress: number
56
+ overallProgress: number
57
+ bytesTransferred: number
58
+ totalBytes: number
52
59
  }
53
60
 
54
61
  /**
55
62
  * Connection information
56
63
  */
57
64
  export interface ConnectionInfo {
58
- id: string;
59
- status: ConnectionStatus;
60
- browserName?: string;
61
- browserVersion?: string;
62
- osName?: string;
63
- osVersion?: string;
64
- mobileVendor?: string;
65
- mobileModel?: string;
65
+ id: string
66
+ status: ConnectionStatus
67
+ browserName?: string
68
+ browserVersion?: string
69
+ osName?: string
70
+ osVersion?: string
71
+ mobileVendor?: string
72
+ mobileModel?: string
66
73
  }
67
74
 
68
75
  /**
69
- * Message types for peer-to-peer communication
76
+ * Message types for peer-to-peer communication.
77
+ *
78
+ * This mirrors the server frontend protocol in filepizza-server/src/messages.ts.
70
79
  */
71
80
  export enum MessageType {
72
81
  RequestInfo = 'RequestInfo',
73
82
  Info = 'Info',
74
83
  Start = 'Start',
75
84
  Chunk = 'Chunk',
85
+ ChunkAck = 'ChunkAck',
76
86
  Pause = 'Pause',
77
- Resume = 'Resume',
78
87
  Done = 'Done',
79
88
  Error = 'Error',
80
89
  PasswordRequired = 'PasswordRequired',
81
90
  UsePassword = 'UsePassword',
82
91
  Report = 'Report',
83
- }
92
+ }