@viraatdas/rudder 3.2.1 → 3.3.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/dist/cloud.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { spawn } from "node:child_process";
2
2
  import { createHash, randomUUID } from "node:crypto";
3
3
  import { AttachSession, containsCtrlC } from "./attach-session.js";
4
+ import { PasteBridge, readLocalClipboard } from "./paste-bridge.js";
4
5
  import fsp from "node:fs/promises";
5
6
  import os from "node:os";
6
7
  import path from "node:path";
@@ -2851,6 +2852,22 @@ function raceLeave(session, promise) {
2851
2852
  promise.then((value) => { off(); resolve(value); }, (error) => { off(); reject(error); });
2852
2853
  });
2853
2854
  }
2855
+ // One pasted file up to the home machine, through the phone's upload route.
2856
+ async function uploadPastedFile(baseUrl, token, workspaceId, file, name) {
2857
+ const bytes = await fsp.readFile(file);
2858
+ const url = `${baseUrl.replace(/\/$/, "")}/api/app/upload?workspace=${encodeURIComponent(workspaceId)}&name=${encodeURIComponent(name)}`;
2859
+ const response = await fetch(url, {
2860
+ method: "POST",
2861
+ headers: { authorization: `Bearer ${token}`, "content-type": "application/octet-stream" },
2862
+ body: bytes,
2863
+ signal: AbortSignal.timeout(90_000),
2864
+ });
2865
+ const body = await response.json().catch(() => ({}));
2866
+ if (!response.ok || typeof body.path !== "string") {
2867
+ throw new Error(body.error || `HTTP ${response.status}`);
2868
+ }
2869
+ return body.path;
2870
+ }
2854
2871
  async function runAttach(target, options, sharedSession) {
2855
2872
  const client = await cloudClient({ requireToken: true });
2856
2873
  const baseUrl = client.baseUrl;
@@ -2938,6 +2955,22 @@ async function runAttach(target, options, sharedSession) {
2938
2955
  }
2939
2956
  resolve(value);
2940
2957
  };
2958
+ // Files and clipboard images from this computer reach the cloud machine
2959
+ // as uploads (src/paste-bridge.ts); only the home's repo rows take them.
2960
+ const paste = new PasteBridge({
2961
+ send: (data) => {
2962
+ if (socket.readyState === WebSocket.OPEN) {
2963
+ socket.send(data, { binary: true });
2964
+ predictor?.onInput(data);
2965
+ }
2966
+ },
2967
+ upload: (file, name) => uploadPastedFile(baseUrl, token, target.id, file, name),
2968
+ readClipboard: target.kind === "workspace" && isInteractive ? readLocalClipboard : undefined,
2969
+ status: (text) => (text ? session.showStatus(text) : session.clearStatus()),
2970
+ });
2971
+ if (target.kind !== "workspace") {
2972
+ paste.disabled = true;
2973
+ }
2941
2974
  let lastCtrlC = 0;
2942
2975
  const onStdin = (chunk) => {
2943
2976
  const buffer = typeof chunk === "string" ? Buffer.from(chunk, "utf8") : chunk;
@@ -2998,8 +3031,7 @@ async function runAttach(target, options, sharedSession) {
2998
3031
  }
2999
3032
  lastCtrlC = now;
3000
3033
  }
3001
- socket.send(buffer, { binary: true });
3002
- predictor?.onInput(buffer);
3034
+ paste.forward(buffer);
3003
3035
  };
3004
3036
  const onResize = () => {
3005
3037
  if (hasControl) {
@@ -4188,6 +4220,9 @@ async function cloudSync(args, options) {
4188
4220
  const cloud = await client.request("/api/rudder/home/sync", {
4189
4221
  method: "POST",
4190
4222
  body: all || !slug ? {} : { repos: [slug], ...(work ? { work } : {}) },
4223
+ }).catch((error) => {
4224
+ const message = error instanceof Error ? error.message : String(error);
4225
+ throw new Error(message === "fetch failed" ? "the cloud machine did not answer in time (it may be restarting); run /sync again in a minute" : message);
4191
4226
  }).finally(() => fsp.rm(scratch, { recursive: true, force: true }).catch(() => undefined));
4192
4227
  const results = cloud.results ?? [];
4193
4228
  // And the cloud's work comes back here.
@@ -4207,6 +4242,18 @@ async function cloudSync(args, options) {
4207
4242
  await fsp.rm(dir, { recursive: true, force: true }).catch(() => undefined);
4208
4243
  }
4209
4244
  }
4245
+ // Work the other side already had was not news: report only what moved.
4246
+ if (local?.work?.sent && mine?.report?.work?.received?.outcome === "have") {
4247
+ delete local.work.sent;
4248
+ }
4249
+ if (mine?.report?.work?.sent && local?.work?.received?.outcome === "have") {
4250
+ delete mine.report.work.sent;
4251
+ }
4252
+ for (const side of [local?.work, mine?.report?.work]) {
4253
+ if (side?.received?.outcome === "have") {
4254
+ delete side.received;
4255
+ }
4256
+ }
4210
4257
  if (local) {
4211
4258
  lines[0] = describeSync(`this laptop (${slug})`, local);
4212
4259
  }