uncloud-p2p 1.0.3 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -49,6 +49,12 @@ export declare class UncloudP2P {
49
49
  private updateState;
50
50
  private handleError;
51
51
  disconnect(): void;
52
+ /**
53
+ * Uploads a file, string, or binary buffer to a specific target path on the remote node.
54
+ * @param targetPath The destination path on the node (e.g., "test/output.txt")
55
+ * @param content The file content as a string, Blob, File, or ArrayBuffer
56
+ */
57
+ uploadFile(targetPath: string, content: string | Blob | File | ArrayBuffer): Promise<void>;
52
58
  }
53
59
  export * from "./uncloudproto";
54
60
  export * from "./files";
package/dist/index.js CHANGED
@@ -284,6 +284,82 @@ class UncloudP2P {
284
284
  this.localCandidates = [];
285
285
  this.updateState("idle");
286
286
  }
287
+ /**
288
+ * Uploads a file, string, or binary buffer to a specific target path on the remote node.
289
+ * @param targetPath The destination path on the node (e.g., "test/output.txt")
290
+ * @param content The file content as a string, Blob, File, or ArrayBuffer
291
+ */
292
+ async uploadFile(targetPath, content) {
293
+ if (!this.dc || this.dc.readyState !== "open" || !this.pc) {
294
+ throw new Error("P2P control channel or peer connection is not established");
295
+ }
296
+ // 1. Normalize data input types into a standardized buffer payload
297
+ let rawDataBuffer;
298
+ if (typeof content === "string") {
299
+ rawDataBuffer = new TextEncoder().encode(content).buffer;
300
+ }
301
+ else if (content instanceof ArrayBuffer) {
302
+ rawDataBuffer = content;
303
+ }
304
+ else if (content instanceof Blob) {
305
+ rawDataBuffer = await content.arrayBuffer();
306
+ }
307
+ else {
308
+ throw new Error("Unsupported upload data payload type configuration.");
309
+ }
310
+ const fileSize = rawDataBuffer.byteLength;
311
+ this.log(`Initiating upload handshake sequence for target destination: ${targetPath} (${fileSize} bytes)`);
312
+ // 2. Alert the control stream channel about our upload metadata context intent
313
+ // Note: We inject the full structured "targetPath" into the metadata "name" field
314
+ const controlHandshake = (0, uncloudproto_1.newMessage)(uncloudproto_1.Actions.CLIENT_TO_NODE_FILE_TRANSFER, {
315
+ name: targetPath,
316
+ size: fileSize,
317
+ });
318
+ this.dc.send(controlHandshake.toJSON());
319
+ // 3. Construct a temporary WebRTC out-of-band data channel pipe for the file stream blocks
320
+ const uploadStreamChannel = this.pc.createDataChannel(uncloudproto_1.StreamNames.CLIENT_TO_NODE_FILE_TRANSFER, { ordered: true });
321
+ // 4. Return an execution promise wrapping the chunk fragmentation loop
322
+ return new Promise((resolve, reject) => {
323
+ uploadStreamChannel.onopen = async () => {
324
+ try {
325
+ this.log(`Streaming channel pipe activated. Processing transfer payload...`);
326
+ // Send data channel sync context header
327
+ const binaryChannelHeader = (0, uncloudproto_1.newMessage)(uncloudproto_1.Actions.CLIENT_TO_NODE_FILE_TRANSFER, {
328
+ name: targetPath,
329
+ size: fileSize,
330
+ });
331
+ uploadStreamChannel.send(binaryChannelHeader.toJSON());
332
+ // Stream the file data in standard WebRTC payload fragment sizes (16KB chunks)
333
+ const CHUNK_SIZE = 16384;
334
+ let currentByteOffset = 0;
335
+ while (currentByteOffset < fileSize) {
336
+ // Guard against overflowing the internal WebRTC browser buffer cache allocations
337
+ if (uploadStreamChannel.bufferedAmount > 1024 * 1024) {
338
+ await new Promise((r) => setTimeout(r, 25));
339
+ continue;
340
+ }
341
+ const frameEndIndex = Math.min(currentByteOffset + CHUNK_SIZE, fileSize);
342
+ const dataSlice = rawDataBuffer.slice(currentByteOffset, frameEndIndex);
343
+ uploadStreamChannel.send(dataSlice);
344
+ currentByteOffset = frameEndIndex;
345
+ }
346
+ this.log(`Data payload transfer pipeline complete. Closing stream context map.`, "success");
347
+ // Allow internal socket layer flush buffers to breathe before killing context mapping frame references
348
+ setTimeout(() => {
349
+ uploadStreamChannel.close();
350
+ resolve();
351
+ }, 800);
352
+ }
353
+ catch (streamError) {
354
+ uploadStreamChannel.close();
355
+ reject(streamError);
356
+ }
357
+ };
358
+ uploadStreamChannel.onerror = (channelErr) => {
359
+ reject(new Error(`Data transfer stream errored mid-flight: ${channelErr}`));
360
+ };
361
+ });
362
+ }
287
363
  }
288
364
  exports.UncloudP2P = UncloudP2P;
289
365
  // src/index.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "uncloud-p2p",
3
- "version": "1.0.3",
3
+ "version": "1.0.4",
4
4
  "description": "Public Peer to Peer File Reader",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",