@seedvault/cli 0.4.2 → 0.4.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/sv.js +53 -26
- package/package.json +1 -1
package/dist/sv.js
CHANGED
|
@@ -158,6 +158,9 @@ function createClient(serverUrl, token) {
|
|
|
158
158
|
if (opts.contentType) {
|
|
159
159
|
headers["Content-Type"] = opts.contentType;
|
|
160
160
|
}
|
|
161
|
+
if (opts.extraHeaders) {
|
|
162
|
+
Object.assign(headers, opts.extraHeaders);
|
|
163
|
+
}
|
|
161
164
|
const res = await fetch(`${base}${path}`, {
|
|
162
165
|
method,
|
|
163
166
|
headers,
|
|
@@ -199,10 +202,16 @@ function createClient(serverUrl, token) {
|
|
|
199
202
|
const res = await request("GET", "/v1/contributors");
|
|
200
203
|
return res.json();
|
|
201
204
|
},
|
|
202
|
-
async putFile(username, path, content) {
|
|
205
|
+
async putFile(username, path, content, opts) {
|
|
206
|
+
const extraHeaders = {};
|
|
207
|
+
if (opts?.originCtime)
|
|
208
|
+
extraHeaders["X-Origin-Ctime"] = opts.originCtime;
|
|
209
|
+
if (opts?.originMtime)
|
|
210
|
+
extraHeaders["X-Origin-Mtime"] = opts.originMtime;
|
|
203
211
|
const res = await request("PUT", `/v1/files/${username}/${encodePath(path)}`, {
|
|
204
212
|
body: content,
|
|
205
|
-
contentType: "text/markdown"
|
|
213
|
+
contentType: "text/markdown",
|
|
214
|
+
extraHeaders: Object.keys(extraHeaders).length > 0 ? extraHeaders : undefined
|
|
206
215
|
});
|
|
207
216
|
return res.json();
|
|
208
217
|
},
|
|
@@ -2148,7 +2157,8 @@ class RetryQueue {
|
|
|
2148
2157
|
const op = this.items[0];
|
|
2149
2158
|
try {
|
|
2150
2159
|
if (op.type === "put" && op.content !== null) {
|
|
2151
|
-
|
|
2160
|
+
const opts = op.originCtime || op.originMtime ? { originCtime: op.originCtime ?? undefined, originMtime: op.originMtime ?? undefined } : undefined;
|
|
2161
|
+
await this.client.putFile(op.username, op.serverPath, op.content, opts);
|
|
2152
2162
|
} else if (op.type === "delete") {
|
|
2153
2163
|
await this.client.deleteFile(op.username, op.serverPath);
|
|
2154
2164
|
}
|
|
@@ -2228,7 +2238,9 @@ class Syncer {
|
|
|
2228
2238
|
username: this.username,
|
|
2229
2239
|
serverPath: f.path,
|
|
2230
2240
|
content: null,
|
|
2231
|
-
queuedAt: new Date().toISOString()
|
|
2241
|
+
queuedAt: new Date().toISOString(),
|
|
2242
|
+
originCtime: null,
|
|
2243
|
+
originMtime: null
|
|
2232
2244
|
});
|
|
2233
2245
|
}
|
|
2234
2246
|
});
|
|
@@ -2244,7 +2256,7 @@ class Syncer {
|
|
|
2244
2256
|
const { files: serverFiles } = await this.client.listFiles(this.username, collection.name + "/");
|
|
2245
2257
|
const serverMap = new Map;
|
|
2246
2258
|
for (const f of serverFiles) {
|
|
2247
|
-
serverMap.set(f.path, f
|
|
2259
|
+
serverMap.set(f.path, f);
|
|
2248
2260
|
}
|
|
2249
2261
|
const localFiles = await walkMd(collection.path);
|
|
2250
2262
|
const localServerPaths = new Set;
|
|
@@ -2253,8 +2265,9 @@ class Syncer {
|
|
|
2253
2265
|
const relPath = toPosixPath(relative5(collection.path, localFile.path));
|
|
2254
2266
|
const serverPath = `${collection.name}/${relPath}`;
|
|
2255
2267
|
localServerPaths.add(serverPath);
|
|
2256
|
-
const
|
|
2257
|
-
if (
|
|
2268
|
+
const serverEntry = serverMap.get(serverPath);
|
|
2269
|
+
if (serverEntry) {
|
|
2270
|
+
const serverMod = serverEntry.originMtime || serverEntry.modifiedAt;
|
|
2258
2271
|
const serverDate = new Date(serverMod).getTime();
|
|
2259
2272
|
const localDate = localFile.mtimeMs;
|
|
2260
2273
|
if (localDate <= serverDate) {
|
|
@@ -2263,11 +2276,16 @@ class Syncer {
|
|
|
2263
2276
|
}
|
|
2264
2277
|
}
|
|
2265
2278
|
const content = await readFile(localFile.path, "utf-8");
|
|
2266
|
-
|
|
2279
|
+
const originCtime = new Date(localFile.birthtimeMs).toISOString();
|
|
2280
|
+
const originMtime = new Date(localFile.mtimeMs).toISOString();
|
|
2281
|
+
toUpload.push({ serverPath, content, originCtime, originMtime });
|
|
2267
2282
|
}
|
|
2268
2283
|
await pooled(toUpload, SYNC_CONCURRENCY, async (item) => {
|
|
2269
2284
|
try {
|
|
2270
|
-
await this.client.putFile(this.username, item.serverPath, item.content
|
|
2285
|
+
await this.client.putFile(this.username, item.serverPath, item.content, {
|
|
2286
|
+
originCtime: item.originCtime,
|
|
2287
|
+
originMtime: item.originMtime
|
|
2288
|
+
});
|
|
2271
2289
|
uploaded++;
|
|
2272
2290
|
} catch {
|
|
2273
2291
|
this.queue.enqueue({
|
|
@@ -2275,7 +2293,9 @@ class Syncer {
|
|
|
2275
2293
|
username: this.username,
|
|
2276
2294
|
serverPath: item.serverPath,
|
|
2277
2295
|
content: item.content,
|
|
2278
|
-
queuedAt: new Date().toISOString()
|
|
2296
|
+
queuedAt: new Date().toISOString(),
|
|
2297
|
+
originCtime: item.originCtime,
|
|
2298
|
+
originMtime: item.originMtime
|
|
2279
2299
|
});
|
|
2280
2300
|
}
|
|
2281
2301
|
});
|
|
@@ -2329,14 +2349,21 @@ class Syncer {
|
|
|
2329
2349
|
}
|
|
2330
2350
|
async handleEvent(event) {
|
|
2331
2351
|
if (event.type === "add" || event.type === "change") {
|
|
2332
|
-
const content = await
|
|
2352
|
+
const [content, s] = await Promise.all([
|
|
2353
|
+
readFile(event.localPath, "utf-8"),
|
|
2354
|
+
stat4(event.localPath)
|
|
2355
|
+
]);
|
|
2356
|
+
const originCtime = new Date(s.birthtimeMs).toISOString();
|
|
2357
|
+
const originMtime = new Date(s.mtimeMs).toISOString();
|
|
2333
2358
|
this.log(`PUT ${event.serverPath} (${content.length} bytes)`);
|
|
2334
2359
|
this.queue.enqueue({
|
|
2335
2360
|
type: "put",
|
|
2336
2361
|
username: this.username,
|
|
2337
2362
|
serverPath: event.serverPath,
|
|
2338
2363
|
content,
|
|
2339
|
-
queuedAt: new Date().toISOString()
|
|
2364
|
+
queuedAt: new Date().toISOString(),
|
|
2365
|
+
originCtime,
|
|
2366
|
+
originMtime
|
|
2340
2367
|
});
|
|
2341
2368
|
} else if (event.type === "unlink") {
|
|
2342
2369
|
this.log(`DELETE ${event.serverPath}`);
|
|
@@ -2345,7 +2372,9 @@ class Syncer {
|
|
|
2345
2372
|
username: this.username,
|
|
2346
2373
|
serverPath: event.serverPath,
|
|
2347
2374
|
content: null,
|
|
2348
|
-
queuedAt: new Date().toISOString()
|
|
2375
|
+
queuedAt: new Date().toISOString(),
|
|
2376
|
+
originCtime: null,
|
|
2377
|
+
originMtime: null
|
|
2349
2378
|
});
|
|
2350
2379
|
}
|
|
2351
2380
|
}
|
|
@@ -2384,7 +2413,7 @@ async function walkDirRecursive(dir, results) {
|
|
|
2384
2413
|
await walkDirRecursive(full, results);
|
|
2385
2414
|
} else if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
2386
2415
|
const s = await stat4(full);
|
|
2387
|
-
results.push({ path: full, mtimeMs: s.mtimeMs });
|
|
2416
|
+
results.push({ path: full, mtimeMs: s.mtimeMs, birthtimeMs: s.birthtimeMs });
|
|
2388
2417
|
}
|
|
2389
2418
|
}
|
|
2390
2419
|
}
|
|
@@ -2780,15 +2809,13 @@ async function startForeground() {
|
|
|
2780
2809
|
collections: config.collections,
|
|
2781
2810
|
onLog: log
|
|
2782
2811
|
});
|
|
2783
|
-
|
|
2784
|
-
|
|
2785
|
-
|
|
2786
|
-
|
|
2787
|
-
|
|
2788
|
-
|
|
2789
|
-
|
|
2790
|
-
log("Will continue watching for changes...");
|
|
2791
|
-
}
|
|
2812
|
+
log("Running initial sync...");
|
|
2813
|
+
try {
|
|
2814
|
+
const { uploaded, skipped, deleted } = await syncer.initialSync();
|
|
2815
|
+
log(`Initial sync complete: ${uploaded} uploaded, ${skipped} skipped, ${deleted} deleted`);
|
|
2816
|
+
} catch (e) {
|
|
2817
|
+
log(`Initial sync failed: ${e.message}`);
|
|
2818
|
+
log("Will continue watching for changes...");
|
|
2792
2819
|
}
|
|
2793
2820
|
let watcher = null;
|
|
2794
2821
|
const rebuildWatcher = async (collections2) => {
|
|
@@ -3047,7 +3074,7 @@ Share this with the person you want to invite.`);
|
|
|
3047
3074
|
}
|
|
3048
3075
|
}
|
|
3049
3076
|
|
|
3050
|
-
// src/commands/
|
|
3077
|
+
// src/commands/update.ts
|
|
3051
3078
|
import { readFileSync as readFileSync2 } from "fs";
|
|
3052
3079
|
import { resolve as resolve6 } from "path";
|
|
3053
3080
|
var {$ } = globalThis.Bun;
|
|
@@ -3105,7 +3132,7 @@ Vault:
|
|
|
3105
3132
|
invite Generate an invite code (operator only)
|
|
3106
3133
|
|
|
3107
3134
|
Maintenance:
|
|
3108
|
-
|
|
3135
|
+
update Update CLI to latest version
|
|
3109
3136
|
`.trim();
|
|
3110
3137
|
async function main() {
|
|
3111
3138
|
const [cmd, ...args] = process.argv.slice(2);
|
|
@@ -3145,7 +3172,7 @@ async function main() {
|
|
|
3145
3172
|
return await contributors();
|
|
3146
3173
|
case "invite":
|
|
3147
3174
|
return await invite();
|
|
3148
|
-
case "
|
|
3175
|
+
case "update":
|
|
3149
3176
|
return await upgrade();
|
|
3150
3177
|
default:
|
|
3151
3178
|
console.error(`Unknown command: ${cmd}
|