@seedvault/cli 0.2.1 → 0.3.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.
Files changed (2) hide show
  1. package/dist/sv.js +50 -46
  2. package/package.json +1 -1
package/dist/sv.js CHANGED
@@ -1,6 +1,10 @@
1
1
  #!/usr/bin/env bun
2
2
  // @bun
3
3
 
4
+ // src/index.ts
5
+ import { readFileSync as readFileSync2 } from "fs";
6
+ import { resolve as resolve6 } from "path";
7
+
4
8
  // src/commands/init.ts
5
9
  import * as readline from "readline/promises";
6
10
  import { stdout } from "process";
@@ -191,23 +195,23 @@ function createClient(serverUrl, token) {
191
195
  const res = await request("GET", "/v1/contributors");
192
196
  return res.json();
193
197
  },
194
- async putFile(contributorId, path, content) {
195
- const res = await request("PUT", `/v1/contributors/${contributorId}/files/${encodePath(path)}`, {
198
+ async putFile(username, path, content) {
199
+ const res = await request("PUT", `/v1/contributors/${username}/files/${encodePath(path)}`, {
196
200
  body: content,
197
201
  contentType: "text/markdown"
198
202
  });
199
203
  return res.json();
200
204
  },
201
- async deleteFile(contributorId, path) {
202
- await request("DELETE", `/v1/contributors/${contributorId}/files/${encodePath(path)}`);
205
+ async deleteFile(username, path) {
206
+ await request("DELETE", `/v1/contributors/${username}/files/${encodePath(path)}`);
203
207
  },
204
- async listFiles(contributorId, prefix) {
208
+ async listFiles(username, prefix) {
205
209
  const qs = prefix ? `?prefix=${encodeURIComponent(prefix)}` : "";
206
- const res = await request("GET", `/v1/contributors/${contributorId}/files${qs}`);
210
+ const res = await request("GET", `/v1/contributors/${username}/files${qs}`);
207
211
  return res.json();
208
212
  },
209
- async getFile(contributorId, path) {
210
- const res = await request("GET", `/v1/contributors/${contributorId}/files/${encodePath(path)}`);
213
+ async getFile(username, path) {
214
+ const res = await request("GET", `/v1/contributors/${username}/files/${encodePath(path)}`);
211
215
  return res.text();
212
216
  },
213
217
  async health() {
@@ -233,21 +237,21 @@ async function init(args) {
233
237
  console.error(`Could not reach server at ${flags.server}`);
234
238
  process.exit(1);
235
239
  }
236
- const contributorId = flags["contributor-id"] || "";
237
- if (!contributorId) {
238
- console.error("When using --token, also pass --contributor-id");
240
+ const username = flags["username"] || "";
241
+ if (!username) {
242
+ console.error("When using --token, also pass --username");
239
243
  process.exit(1);
240
244
  }
241
245
  const config = {
242
246
  server: flags.server,
243
247
  token: flags.token,
244
- contributorId,
248
+ username,
245
249
  collections: []
246
250
  };
247
251
  saveConfig(config);
248
252
  console.log("Seedvault configured.");
249
253
  console.log(` Server: ${config.server}`);
250
- console.log(` Contributor ID: ${config.contributorId}`);
254
+ console.log(` Username: ${config.username}`);
251
255
  return;
252
256
  }
253
257
  if (flags.server && flags.name) {
@@ -262,13 +266,13 @@ async function init(args) {
262
266
  const config = {
263
267
  server: flags.server,
264
268
  token: result.token,
265
- contributorId: result.contributor.id,
269
+ username: result.contributor.username,
266
270
  collections: []
267
271
  };
268
272
  saveConfig(config);
269
273
  console.log("Signed up and configured.");
270
274
  console.log(` Server: ${config.server}`);
271
- console.log(` Contributor: ${result.contributor.name} (${result.contributor.id})`);
275
+ console.log(` Username: ${result.contributor.username}`);
272
276
  console.log(` Token: ${result.token}`);
273
277
  return;
274
278
  }
@@ -300,25 +304,24 @@ async function init(args) {
300
304
  const hasToken = await rl.question("Do you already have a token? (y/N): ");
301
305
  if (hasToken.toLowerCase() === "y") {
302
306
  const token = await rl.question("Token: ");
303
- const contributorId = await rl.question("Contributor ID: ");
304
- const config = { server, token: token.trim(), contributorId: contributorId.trim(), collections: [] };
307
+ const username = await rl.question("Username: ");
308
+ const config = { server, token: token.trim(), username: username.trim(), collections: [] };
305
309
  saveConfig(config);
306
310
  console.log(`
307
311
  Seedvault configured.`);
308
312
  } else {
309
- const name = await rl.question("Contributor name (e.g. your-name-notes): ");
313
+ const name = await rl.question("Username (e.g. your-name-notes): ");
310
314
  const invite = await rl.question("Invite code (leave blank if first user): ");
311
315
  const result = await client.signup(name.trim(), invite.trim() || undefined);
312
316
  const config = {
313
317
  server,
314
318
  token: result.token,
315
- contributorId: result.contributor.id,
319
+ username: result.contributor.username,
316
320
  collections: []
317
321
  };
318
322
  saveConfig(config);
319
323
  console.log(`
320
- Signed up as '${result.contributor.name}'.`);
321
- console.log(` Contributor ID: ${result.contributor.id}`);
324
+ Signed up as '${result.contributor.username}'.`);
322
325
  console.log(` Token: ${result.token}`);
323
326
  console.log(`
324
327
  Save your token \u2014 it won't be shown again.`);
@@ -2095,9 +2098,9 @@ class RetryQueue {
2095
2098
  const op = this.items[0];
2096
2099
  try {
2097
2100
  if (op.type === "put" && op.content !== null) {
2098
- await this.client.putFile(op.contributorId, op.serverPath, op.content);
2101
+ await this.client.putFile(op.username, op.serverPath, op.content);
2099
2102
  } else if (op.type === "delete") {
2100
- await this.client.deleteFile(op.contributorId, op.serverPath);
2103
+ await this.client.deleteFile(op.username, op.serverPath);
2101
2104
  }
2102
2105
  this.items.shift();
2103
2106
  this.backoff = MIN_BACKOFF;
@@ -2125,13 +2128,13 @@ class RetryQueue {
2125
2128
  // src/daemon/syncer.ts
2126
2129
  class Syncer {
2127
2130
  client;
2128
- contributorId;
2131
+ username;
2129
2132
  collections;
2130
2133
  queue;
2131
2134
  log;
2132
2135
  constructor(opts) {
2133
2136
  this.client = opts.client;
2134
- this.contributorId = opts.contributorId;
2137
+ this.username = opts.username;
2135
2138
  this.collections = opts.collections;
2136
2139
  this.log = opts.onLog;
2137
2140
  this.queue = new RetryQueue(opts.client, opts.onLog);
@@ -2157,7 +2160,7 @@ class Syncer {
2157
2160
  let deleted = 0;
2158
2161
  this.log(`Syncing '${collection.name}' (${collection.path})...`);
2159
2162
  try {
2160
- const { files: serverFiles } = await this.client.listFiles(this.contributorId, collection.name + "/");
2163
+ const { files: serverFiles } = await this.client.listFiles(this.username, collection.name + "/");
2161
2164
  const serverMap = new Map;
2162
2165
  for (const f of serverFiles) {
2163
2166
  serverMap.set(f.path, f.modifiedAt);
@@ -2179,12 +2182,12 @@ class Syncer {
2179
2182
  }
2180
2183
  const content = await readFile(localFile.path, "utf-8");
2181
2184
  try {
2182
- await this.client.putFile(this.contributorId, serverPath, content);
2185
+ await this.client.putFile(this.username, serverPath, content);
2183
2186
  uploaded++;
2184
2187
  } catch {
2185
2188
  this.queue.enqueue({
2186
2189
  type: "put",
2187
- contributorId: this.contributorId,
2190
+ username: this.username,
2188
2191
  serverPath,
2189
2192
  content,
2190
2193
  queuedAt: new Date().toISOString()
@@ -2195,12 +2198,12 @@ class Syncer {
2195
2198
  if (localServerPaths.has(f.path))
2196
2199
  continue;
2197
2200
  try {
2198
- await this.client.deleteFile(this.contributorId, f.path);
2201
+ await this.client.deleteFile(this.username, f.path);
2199
2202
  deleted++;
2200
2203
  } catch {
2201
2204
  this.queue.enqueue({
2202
2205
  type: "delete",
2203
- contributorId: this.contributorId,
2206
+ username: this.username,
2204
2207
  serverPath: f.path,
2205
2208
  content: null,
2206
2209
  queuedAt: new Date().toISOString()
@@ -2218,15 +2221,15 @@ class Syncer {
2218
2221
  let queued = 0;
2219
2222
  this.log(`Removing '${collection.name}' files from server...`);
2220
2223
  try {
2221
- const { files: serverFiles } = await this.client.listFiles(this.contributorId, collection.name + "/");
2224
+ const { files: serverFiles } = await this.client.listFiles(this.username, collection.name + "/");
2222
2225
  for (const f of serverFiles) {
2223
2226
  try {
2224
- await this.client.deleteFile(this.contributorId, f.path);
2227
+ await this.client.deleteFile(this.username, f.path);
2225
2228
  deleted++;
2226
2229
  } catch {
2227
2230
  this.queue.enqueue({
2228
2231
  type: "delete",
2229
- contributorId: this.contributorId,
2232
+ username: this.username,
2230
2233
  serverPath: f.path,
2231
2234
  content: null,
2232
2235
  queuedAt: new Date().toISOString()
@@ -2246,7 +2249,7 @@ class Syncer {
2246
2249
  this.log(`PUT ${event.serverPath} (${content.length} bytes)`);
2247
2250
  this.queue.enqueue({
2248
2251
  type: "put",
2249
- contributorId: this.contributorId,
2252
+ username: this.username,
2250
2253
  serverPath: event.serverPath,
2251
2254
  content,
2252
2255
  queuedAt: new Date().toISOString()
@@ -2255,7 +2258,7 @@ class Syncer {
2255
2258
  this.log(`DELETE ${event.serverPath}`);
2256
2259
  this.queue.enqueue({
2257
2260
  type: "delete",
2258
- contributorId: this.contributorId,
2261
+ username: this.username,
2259
2262
  serverPath: event.serverPath,
2260
2263
  content: null,
2261
2264
  queuedAt: new Date().toISOString()
@@ -2669,7 +2672,7 @@ async function startForeground() {
2669
2672
  maybeLogOverlapWarning(removedOverlappingCollections);
2670
2673
  log("Seedvault daemon starting...");
2671
2674
  log(` Server: ${config.server}`);
2672
- log(` Contributor: ${config.contributorId}`);
2675
+ log(` Contributor: ${config.username}`);
2673
2676
  if (config.collections.length === 0) {
2674
2677
  log(" Collections: none");
2675
2678
  log(" Waiting for collections to be added...");
@@ -2679,7 +2682,7 @@ async function startForeground() {
2679
2682
  writeFileSync2(getPidPath(), String(process.pid));
2680
2683
  const syncer = new Syncer({
2681
2684
  client,
2682
- contributorId: config.contributorId,
2685
+ username: config.username,
2683
2686
  collections: config.collections,
2684
2687
  onLog: log
2685
2688
  });
@@ -2809,7 +2812,7 @@ async function status() {
2809
2812
  console.log(`Seedvault Status
2810
2813
  `);
2811
2814
  console.log(` Server: ${config.server}`);
2812
- console.log(` Contributor: ${config.contributorId}`);
2815
+ console.log(` Contributor: ${config.username}`);
2813
2816
  try {
2814
2817
  const platform = detectPlatform();
2815
2818
  const serviceName = platform === "macos" ? "launchd" : platform === "linux" ? "systemd" : "Task Scheduler";
@@ -2847,7 +2850,7 @@ async function ls(args) {
2847
2850
  const config = loadConfig();
2848
2851
  const client = createClient(config.server, config.token);
2849
2852
  const prefix = args[0] || undefined;
2850
- const { files } = await client.listFiles(config.contributorId, prefix);
2853
+ const { files } = await client.listFiles(config.username, prefix);
2851
2854
  if (files.length === 0) {
2852
2855
  console.log(prefix ? `No files matching '${prefix}'.` : "No files in your contributor.");
2853
2856
  return;
@@ -2879,7 +2882,7 @@ async function cat(args) {
2879
2882
  const config = loadConfig();
2880
2883
  const client = createClient(config.server, config.token);
2881
2884
  try {
2882
- const content = await client.getFile(config.contributorId, filePath);
2885
+ const content = await client.getFile(config.username, filePath);
2883
2886
  process.stdout.write(content);
2884
2887
  } catch (e) {
2885
2888
  if (e instanceof ApiError && e.status === 404) {
@@ -2902,9 +2905,8 @@ async function contributors() {
2902
2905
  console.log(`Contributors:
2903
2906
  `);
2904
2907
  for (const contributor of contributors2) {
2905
- const you = contributor.id === config.contributorId ? " (you)" : "";
2906
- console.log(` ${contributor.name}${you}`);
2907
- console.log(` ID: ${contributor.id}`);
2908
+ const you = contributor.username === config.username ? " (you)" : "";
2909
+ console.log(` ${contributor.username}${you}`);
2908
2910
  console.log(` Created: ${new Date(contributor.createdAt).toLocaleString()}`);
2909
2911
  console.log();
2910
2912
  }
@@ -2938,8 +2940,8 @@ Usage: sv <command> [options]
2938
2940
 
2939
2941
  Setup:
2940
2942
  init Interactive first-time setup
2941
- init --server URL --token T Non-interactive (existing token)
2942
- init --server URL --name N Non-interactive (signup)
2943
+ init --server URL --token T --username U Non-interactive (existing token)
2944
+ init --server URL --name N Non-interactive (signup)
2943
2945
 
2944
2946
  Collections:
2945
2947
  add <path> [--name N] Add a collection path
@@ -2967,7 +2969,9 @@ async function main() {
2967
2969
  return;
2968
2970
  }
2969
2971
  if (cmd === "--version" || cmd === "-v") {
2970
- console.log("0.2.1");
2972
+ const pkgPath = resolve6(import.meta.dirname, "..", "package.json");
2973
+ const pkg = JSON.parse(readFileSync2(pkgPath, "utf-8"));
2974
+ console.log(pkg.version);
2971
2975
  return;
2972
2976
  }
2973
2977
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seedvault/cli",
3
- "version": "0.2.1",
3
+ "version": "0.3.0",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "sv": "bin/sv.mjs"