filepizza-client 0.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/README.md ADDED
@@ -0,0 +1,20 @@
1
+ <div align="center">
2
+ <img src="public/images/api_button.png" alt="FilePizza client API" width="50%" /><h3>Client API for integrating the FilePizza Server into your apps</h3>
3
+ </div>
4
+
5
+ # FilePizza Client API
6
+
7
+ The `filepizza-client` API provides bindings to [FilePizza server](https://github.com/TeXlyre/filepizza-server). FilePizza is a React library for browser-to-browser file transfer using WebRTC. It allows you to integrate peer-to-peer file sharing functionality into your web applications.
8
+
9
+ ## Features
10
+
11
+ - Direct browser-to-browser file transfers (no server storage)
12
+ - Password protection for transfers
13
+ - Support for single and multiple file transfers
14
+ - Progress tracking and event notifications
15
+
16
+ ## Installation
17
+
18
+ ```bash
19
+ npm install filepizza-client
20
+ ```
@@ -0,0 +1,7 @@
1
+ export declare class DownloadHelper {
2
+ private static isNewChromiumBased;
3
+ static downloadFile(fileName: string, data: Blob | Uint8Array): Promise<void>;
4
+ private static downloadWithFileSystemAccessAPI;
5
+ private static downloadWithBlobUrl;
6
+ static streamToUint8Array(stream: ReadableStream<Uint8Array>): Promise<Uint8Array>;
7
+ }
@@ -0,0 +1,75 @@
1
+ // src/utils/download-helper.ts
2
+ export class DownloadHelper {
3
+ static isNewChromiumBased() {
4
+ return 'showSaveFilePicker' in window;
5
+ }
6
+ static async downloadFile(fileName, data) {
7
+ const blob = data instanceof Blob ? data : new Blob([data]);
8
+ if (this.isNewChromiumBased()) {
9
+ await this.downloadWithFileSystemAccessAPI(fileName, blob);
10
+ }
11
+ else {
12
+ this.downloadWithBlobUrl(fileName, blob);
13
+ }
14
+ }
15
+ static async downloadWithFileSystemAccessAPI(fileName, blob) {
16
+ try {
17
+ // @ts-ignore - TypeScript may not recognize showSaveFilePicker
18
+ const fileHandle = await window.showSaveFilePicker({
19
+ suggestedName: fileName,
20
+ types: [{
21
+ description: 'Files',
22
+ accept: { '*/*': ['.bin'] },
23
+ }],
24
+ });
25
+ const writable = await fileHandle.createWritable();
26
+ await writable.write(blob);
27
+ await writable.close();
28
+ }
29
+ catch (error) {
30
+ console.error('Error downloading with File System Access API:', error);
31
+ // Fall back to blob URL method if the user cancels or there's an error
32
+ if (error.name !== 'AbortError') {
33
+ this.downloadWithBlobUrl(fileName, blob);
34
+ }
35
+ }
36
+ }
37
+ static downloadWithBlobUrl(fileName, blob) {
38
+ const url = URL.createObjectURL(blob);
39
+ const a = document.createElement('a');
40
+ a.href = url;
41
+ a.download = fileName;
42
+ a.style.display = 'none';
43
+ document.body.appendChild(a);
44
+ a.click();
45
+ setTimeout(() => {
46
+ document.body.removeChild(a);
47
+ URL.revokeObjectURL(url);
48
+ }, 100);
49
+ }
50
+ static async streamToUint8Array(stream) {
51
+ const reader = stream.getReader();
52
+ const chunks = [];
53
+ try {
54
+ while (true) {
55
+ const { done, value } = await reader.read();
56
+ if (done)
57
+ break;
58
+ chunks.push(value);
59
+ }
60
+ }
61
+ finally {
62
+ reader.releaseLock();
63
+ }
64
+ // Combine chunks
65
+ const totalLength = chunks.reduce((total, chunk) => total + chunk.length, 0);
66
+ const combinedChunks = new Uint8Array(totalLength);
67
+ let offset = 0;
68
+ for (const chunk of chunks) {
69
+ combinedChunks.set(chunk, offset);
70
+ offset += chunk.length;
71
+ }
72
+ return combinedChunks;
73
+ }
74
+ }
75
+ //# sourceMappingURL=download-helper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"download-helper.js","sourceRoot":"","sources":["../src/download-helper.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import { EventEmitter as EventEmitterInterface } from './types';
2
+ export declare class EventEmitter implements EventEmitterInterface {
3
+ private events;
4
+ /**
5
+ * Register an event listener
6
+ */
7
+ on(event: string, listener: (...args: any[]) => void): this;
8
+ /**
9
+ * Remove an event listener
10
+ */
11
+ off(event: string, listener: (...args: any[]) => void): this;
12
+ /**
13
+ * Emit an event
14
+ */
15
+ emit(event: string, ...args: any[]): boolean;
16
+ /**
17
+ * Register a one-time event listener
18
+ */
19
+ once(event: string, listener: (...args: any[]) => void): this;
20
+ /**
21
+ * Remove all listeners for an event
22
+ */
23
+ removeAllListeners(event?: string): this;
24
+ }
@@ -0,0 +1,64 @@
1
+ export class EventEmitter {
2
+ constructor() {
3
+ this.events = {};
4
+ }
5
+ /**
6
+ * Register an event listener
7
+ */
8
+ on(event, listener) {
9
+ if (!this.events[event]) {
10
+ this.events[event] = [];
11
+ }
12
+ this.events[event].push(listener);
13
+ return this;
14
+ }
15
+ /**
16
+ * Remove an event listener
17
+ */
18
+ off(event, listener) {
19
+ if (this.events[event]) {
20
+ this.events[event] = this.events[event].filter(l => l !== listener);
21
+ }
22
+ return this;
23
+ }
24
+ /**
25
+ * Emit an event
26
+ */
27
+ emit(event, ...args) {
28
+ if (!this.events[event]) {
29
+ return false;
30
+ }
31
+ this.events[event].forEach(listener => {
32
+ try {
33
+ listener(...args);
34
+ }
35
+ catch (error) {
36
+ console.error(`Error in event listener for ${event}:`, error);
37
+ }
38
+ });
39
+ return true;
40
+ }
41
+ /**
42
+ * Register a one-time event listener
43
+ */
44
+ once(event, listener) {
45
+ const onceListener = (...args) => {
46
+ this.off(event, onceListener);
47
+ listener(...args);
48
+ };
49
+ return this.on(event, onceListener);
50
+ }
51
+ /**
52
+ * Remove all listeners for an event
53
+ */
54
+ removeAllListeners(event) {
55
+ if (event) {
56
+ delete this.events[event];
57
+ }
58
+ else {
59
+ this.events = {};
60
+ }
61
+ return this;
62
+ }
63
+ }
64
+ //# sourceMappingURL=event-emitter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-emitter.js","sourceRoot":"","sources":["../src/event-emitter.ts"],"names":[],"mappings":"AAGA,MAAM,OAAO,YAAY;IAAzB;QACU,WAAM,GAAoD,EAAE,CAAA;IAkEtE,CAAC;IAhEC;;OAEG;IACH,EAAE,CAAC,KAAa,EAAE,QAAkC;QAClD,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;YACxB,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,CAAA;QACzB,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;QACjC,OAAO,IAAI,CAAA;IACb,CAAC;IAED;;OAEG;IACH,GAAG,CAAC,KAAa,EAAE,QAAkC;QACnD,IAAI,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;YACvB,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,QAAQ,CAAC,CAAA;QACrE,CAAC;QACD,OAAO,IAAI,CAAA;IACb,CAAC;IAED;;OAEG;IACH,IAAI,CAAC,KAAa,EAAE,GAAG,IAAW;QAChC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;YACxB,OAAO,KAAK,CAAA;QACd,CAAC;QAED,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE;YACpC,IAAI,CAAC;gBACH,QAAQ,CAAC,GAAG,IAAI,CAAC,CAAA;YACnB,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,OAAO,CAAC,KAAK,CAAC,+BAA+B,KAAK,GAAG,EAAE,KAAK,CAAC,CAAA;YAC/D,CAAC;QACH,CAAC,CAAC,CAAA;QAEF,OAAO,IAAI,CAAA;IACb,CAAC;IAED;;OAEG;IACH,IAAI,CAAC,KAAa,EAAE,QAAkC;QACpD,MAAM,YAAY,GAAG,CAAC,GAAG,IAAW,EAAE,EAAE;YACtC,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,YAAY,CAAC,CAAA;YAC7B,QAAQ,CAAC,GAAG,IAAI,CAAC,CAAA;QACnB,CAAC,CAAA;QAED,OAAO,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,CAAC,CAAA;IACrC,CAAC;IAED;;OAEG;IACH,kBAAkB,CAAC,KAAc;QAC/B,IAAI,KAAK,EAAE,CAAC;YACV,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;QAC3B,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,MAAM,GAAG,EAAE,CAAA;QAClB,CAAC;QAED,OAAO,IAAI,CAAA;IACb,CAAC;CACF"}
@@ -0,0 +1,159 @@
1
+ import { EventEmitter } from './event-emitter';
2
+ import { FileInfo, ProgressInfo, ConnectionStatus, CompletedFile } from './types';
3
+ /**
4
+ * FilePizza Downloader - connects to FilePizza uploads
5
+ */
6
+ export declare class FilePizzaDownloader extends EventEmitter {
7
+ private peer?;
8
+ private connection?;
9
+ private filePizzaServerUrl;
10
+ private filesInfo;
11
+ private currentFileIndex;
12
+ private currentFileBytesReceived;
13
+ private totalBytesReceived;
14
+ private totalBytes;
15
+ private status;
16
+ private fileStreams;
17
+ private isPasswordRequired;
18
+ private isPasswordInvalid;
19
+ private errorMessage?;
20
+ private iceServers?;
21
+ private completedFiles;
22
+ /**
23
+ * Create a new FilePizza downloader
24
+ * @param options Configuration options
25
+ */
26
+ constructor(options?: {
27
+ filePizzaServerUrl?: string;
28
+ });
29
+ /**
30
+ * Initialize the downloader
31
+ */
32
+ initialize(): Promise<void>;
33
+ /**
34
+ * Connect to an uploader using a FilePizza URL or slug
35
+ */
36
+ connect(urlOrSlug: string): Promise<boolean>;
37
+ /**
38
+ * Submit password for protected download
39
+ */
40
+ submitPassword(password: string): void;
41
+ /**
42
+ * Start downloading the files
43
+ */
44
+ startDownload(): Promise<void>;
45
+ /**
46
+ * Pause the download
47
+ */
48
+ pauseDownload(): void;
49
+ /**
50
+ * Resume the download
51
+ */
52
+ resumeDownload(): void;
53
+ /**
54
+ * Cancel the download
55
+ */
56
+ /**
57
+ * Cancel the download
58
+ */
59
+ cancelDownload(): void;
60
+ /**
61
+ * Get file information
62
+ */
63
+ getFileInfo(): FileInfo[];
64
+ /**
65
+ * Get download status
66
+ */
67
+ getStatus(): {
68
+ status: ConnectionStatus;
69
+ isPasswordRequired: boolean;
70
+ isPasswordInvalid: boolean;
71
+ errorMessage?: string;
72
+ };
73
+ /**
74
+ * Get progress information
75
+ */
76
+ getProgress(): ProgressInfo;
77
+ /**
78
+ * Extract slug from URL or use directly
79
+ */
80
+ private extractSlug;
81
+ /**
82
+ * Extract uploader peer IDs from the FilePizza server when multiple uploaders are present
83
+ */
84
+ private extractUploaderPeerIDs;
85
+ /**
86
+ * Look up the uploader's peer ID from the FilePizza server
87
+ */
88
+ private lookupUploaderPeerID;
89
+ /**
90
+ * Connect to a specific uploader by ID
91
+ */
92
+ getAvailableUploaders(urlOrSlug: string): Promise<string[]>;
93
+ /**
94
+ * Connect to a specific uploader by ID
95
+ */
96
+ connectToUploader(uploaderId: string): Promise<boolean>;
97
+ /**
98
+ * Get ICE servers from the FilePizza server
99
+ */
100
+ private getIceServers;
101
+ /**
102
+ * Connect directly to a peer
103
+ */
104
+ private connectToPeer;
105
+ /**
106
+ * Handle incoming data from uploader
107
+ */
108
+ private handleData;
109
+ /**
110
+ * Handle password required message
111
+ */
112
+ private handlePasswordRequired;
113
+ /**
114
+ * Handle file info message
115
+ */
116
+ private handleInfo;
117
+ /**
118
+ * Handle error message
119
+ */
120
+ private handleError;
121
+ /**
122
+ * Handle report message (channel reported for violation)
123
+ */
124
+ private handleReport;
125
+ /**
126
+ * Handle chunk message
127
+ */
128
+ private handleChunk;
129
+ /**
130
+ * Initialize streams for all files
131
+ */
132
+ private initializeFileStreams;
133
+ /**
134
+ * Store a completed file
135
+ */
136
+ private storeCompletedFile;
137
+ /**
138
+ * Download a completed file
139
+ */
140
+ downloadFile(fileName: string): Promise<void>;
141
+ /**
142
+ * Get completed files
143
+ */
144
+ getCompletedFiles(): CompletedFile[];
145
+ /**
146
+ * Download all completed files
147
+ */
148
+ downloadAllFiles(): Promise<void>;
149
+ /**
150
+ * Request the next file
151
+ */
152
+ private requestNextFile;
153
+ private getBrowserName;
154
+ private getBrowserVersion;
155
+ private getOSName;
156
+ private getOSVersion;
157
+ private getMobileVendor;
158
+ private getMobileModel;
159
+ }