@dench.com/cli 0.3.0 → 0.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/fs-daemon.ts +57 -23
- package/package.json +1 -1
package/fs-daemon.ts
CHANGED
|
@@ -27,9 +27,11 @@
|
|
|
27
27
|
*
|
|
28
28
|
* Usage (daemon mode):
|
|
29
29
|
* dench-fs-daemon \
|
|
30
|
-
* --org-id <orgId> \
|
|
31
30
|
* --workspace /workspace \
|
|
32
31
|
* --hot-cache /tmp/dench-cache
|
|
32
|
+
*
|
|
33
|
+
* `--org-id` is optional: when omitted, the daemon resolves the organization
|
|
34
|
+
* from DENCH_API_KEY via Convex before it starts watching files.
|
|
33
35
|
*/
|
|
34
36
|
import { createHash } from "node:crypto";
|
|
35
37
|
import { mkdirSync } from "node:fs";
|
|
@@ -39,7 +41,7 @@ import { ConvexClient, ConvexHttpClient } from "convex/browser";
|
|
|
39
41
|
import { makeFunctionReference } from "convex/server";
|
|
40
42
|
|
|
41
43
|
type Args = {
|
|
42
|
-
orgId
|
|
44
|
+
orgId?: string;
|
|
43
45
|
workspace: string;
|
|
44
46
|
hotCache: string;
|
|
45
47
|
};
|
|
@@ -71,11 +73,6 @@ function parseArgs(argv: string[]): Args {
|
|
|
71
73
|
out.workspace ??= process.env.DENCH_VOLUME_PATH?.trim() || "/workspace";
|
|
72
74
|
out.hotCache ??=
|
|
73
75
|
process.env.DENCH_HOT_CACHE_PATH?.trim() || "/tmp/dench-cache";
|
|
74
|
-
if (!out.orgId) {
|
|
75
|
-
throw new Error(
|
|
76
|
-
"dench-fs-daemon: org id is required. Set DENCH_ORG_ID env var or pass --org-id.",
|
|
77
|
-
);
|
|
78
|
-
}
|
|
79
76
|
return out as Args;
|
|
80
77
|
}
|
|
81
78
|
|
|
@@ -185,6 +182,9 @@ const api = {
|
|
|
185
182
|
),
|
|
186
183
|
deleteFile: makeFunctionReference<"mutation">("functions/files:deleteFile"),
|
|
187
184
|
listTree: makeFunctionReference<"query">("functions/files:listTree"),
|
|
185
|
+
resolveApiKeyOrganization: makeFunctionReference<"query">(
|
|
186
|
+
"functions/files:resolveApiKeyOrganization",
|
|
187
|
+
),
|
|
188
188
|
appendLiveBuffer: makeFunctionReference<"mutation">(
|
|
189
189
|
"functions/files:appendLiveBuffer",
|
|
190
190
|
),
|
|
@@ -201,17 +201,24 @@ class DenchFileClient {
|
|
|
201
201
|
private http: ConvexHttpClient;
|
|
202
202
|
private realtime: ConvexClient | null = null;
|
|
203
203
|
|
|
204
|
-
constructor(
|
|
204
|
+
constructor(
|
|
205
|
+
convexUrl: string,
|
|
206
|
+
private readonly apiKey: string,
|
|
207
|
+
) {
|
|
205
208
|
this.http = new ConvexHttpClient(convexUrl);
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
this.http.
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
async resolveOrganizationId(): Promise<string> {
|
|
212
|
+
const result = (await this.http.query(api.files.resolveApiKeyOrganization, {
|
|
213
|
+
apiKey: this.apiKey,
|
|
214
|
+
})) as { organizationId: string };
|
|
215
|
+
return result.organizationId;
|
|
210
216
|
}
|
|
211
217
|
|
|
212
218
|
async generateUploadUrl(path: string): Promise<string> {
|
|
213
219
|
return (await this.http.mutation(api.files.generateUploadUrl, {
|
|
214
220
|
path,
|
|
221
|
+
apiKey: this.apiKey,
|
|
215
222
|
})) as string;
|
|
216
223
|
}
|
|
217
224
|
|
|
@@ -242,7 +249,10 @@ class DenchFileClient {
|
|
|
242
249
|
lastModifiedBy: string;
|
|
243
250
|
}): Promise<{ versionConflict: boolean; currentHash?: string }> {
|
|
244
251
|
try {
|
|
245
|
-
await this.http.mutation(api.files.commitFileUpload,
|
|
252
|
+
await this.http.mutation(api.files.commitFileUpload, {
|
|
253
|
+
...args,
|
|
254
|
+
apiKey: this.apiKey,
|
|
255
|
+
});
|
|
246
256
|
return { versionConflict: false };
|
|
247
257
|
} catch (error) {
|
|
248
258
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -260,12 +270,16 @@ class DenchFileClient {
|
|
|
260
270
|
}
|
|
261
271
|
|
|
262
272
|
async deleteFile(path: string): Promise<void> {
|
|
263
|
-
await this.http.mutation(api.files.deleteFile, {
|
|
273
|
+
await this.http.mutation(api.files.deleteFile, {
|
|
274
|
+
path,
|
|
275
|
+
apiKey: this.apiKey,
|
|
276
|
+
});
|
|
264
277
|
}
|
|
265
278
|
|
|
266
279
|
async getSignedDownloadUrl(path: string): Promise<string | null> {
|
|
267
280
|
const url = (await this.http.action(api.files.getFileSignedDownloadUrl, {
|
|
268
281
|
path,
|
|
282
|
+
apiKey: this.apiKey,
|
|
269
283
|
})) as string | null;
|
|
270
284
|
return url ?? null;
|
|
271
285
|
}
|
|
@@ -275,11 +289,17 @@ class DenchFileClient {
|
|
|
275
289
|
runId: string;
|
|
276
290
|
chunk: string;
|
|
277
291
|
}): Promise<void> {
|
|
278
|
-
await this.http.mutation(api.files.appendLiveBuffer,
|
|
292
|
+
await this.http.mutation(api.files.appendLiveBuffer, {
|
|
293
|
+
...args,
|
|
294
|
+
apiKey: this.apiKey,
|
|
295
|
+
} as never);
|
|
279
296
|
}
|
|
280
297
|
|
|
281
298
|
async finalizeLiveBuffer(path: string): Promise<void> {
|
|
282
|
-
await this.http.mutation(api.files.finalizeLiveBuffer, {
|
|
299
|
+
await this.http.mutation(api.files.finalizeLiveBuffer, {
|
|
300
|
+
path,
|
|
301
|
+
apiKey: this.apiKey,
|
|
302
|
+
});
|
|
283
303
|
}
|
|
284
304
|
|
|
285
305
|
/**
|
|
@@ -298,7 +318,7 @@ class DenchFileClient {
|
|
|
298
318
|
}
|
|
299
319
|
const unsubscribe = this.realtime.onUpdate(
|
|
300
320
|
api.files.listTree,
|
|
301
|
-
{ prefix: "/" },
|
|
321
|
+
{ prefix: "/", apiKey: this.apiKey },
|
|
302
322
|
(rows: unknown) => {
|
|
303
323
|
const list = Array.isArray(rows)
|
|
304
324
|
? (rows as Array<{
|
|
@@ -350,14 +370,16 @@ async function runDaemon(daemonArgs: Args): Promise<void> {
|
|
|
350
370
|
return;
|
|
351
371
|
}
|
|
352
372
|
|
|
373
|
+
const client = new DenchFileClient(convexUrl, apiKey);
|
|
374
|
+
const resolvedOrgId =
|
|
375
|
+
daemonArgs.orgId ?? (await client.resolveOrganizationId());
|
|
353
376
|
console.log(
|
|
354
|
-
`[dench-fs-daemon] starting org=${
|
|
377
|
+
`[dench-fs-daemon] starting org=${resolvedOrgId} workspace=${daemonArgs.workspace}`,
|
|
355
378
|
);
|
|
356
379
|
mkdirSync(daemonArgs.workspace, { recursive: true });
|
|
357
380
|
mkdirSync(daemonArgs.hotCache, { recursive: true });
|
|
358
381
|
|
|
359
382
|
const tracker = new HashTracker();
|
|
360
|
-
const client = new DenchFileClient(convexUrl, apiKey);
|
|
361
383
|
|
|
362
384
|
let chokidar: typeof import("chokidar");
|
|
363
385
|
try {
|
|
@@ -606,11 +628,19 @@ async function main(): Promise<void> {
|
|
|
606
628
|
*/
|
|
607
629
|
async function runInitialSync(argv: string[]): Promise<void> {
|
|
608
630
|
const initial = argv.includes("--initial");
|
|
609
|
-
const
|
|
610
|
-
const
|
|
611
|
-
|
|
631
|
+
const orgIdIndex = argv.indexOf("--org-id");
|
|
632
|
+
const workspaceIndex = argv.indexOf("--workspace");
|
|
633
|
+
const orgId =
|
|
634
|
+
orgIdIndex === -1
|
|
635
|
+
? (process.env.DENCH_ORG_ID?.trim() ?? undefined)
|
|
636
|
+
: argv[orgIdIndex + 1];
|
|
637
|
+
const workspace =
|
|
638
|
+
workspaceIndex === -1
|
|
639
|
+
? "/workspace"
|
|
640
|
+
: (argv[workspaceIndex + 1] ?? "/workspace");
|
|
641
|
+
if (!initial) {
|
|
612
642
|
throw new Error(
|
|
613
|
-
"dench fs sync --initial --org-id <orgId> [--workspace /workspace]",
|
|
643
|
+
"dench fs sync --initial [--org-id <orgId>] [--workspace /workspace]",
|
|
614
644
|
);
|
|
615
645
|
}
|
|
616
646
|
const convexUrl = process.env.CONVEX_URL?.trim();
|
|
@@ -619,6 +649,10 @@ async function runInitialSync(argv: string[]): Promise<void> {
|
|
|
619
649
|
throw new Error("dench fs sync requires CONVEX_URL + DENCH_API_KEY in env");
|
|
620
650
|
}
|
|
621
651
|
const client = new DenchFileClient(convexUrl, apiKey);
|
|
652
|
+
const resolvedOrgId = orgId ?? (await client.resolveOrganizationId());
|
|
653
|
+
process.stdout.write(
|
|
654
|
+
`[dench-fs-daemon] initial sync org=${resolvedOrgId} workspace=${workspace}\n`,
|
|
655
|
+
);
|
|
622
656
|
const fs = await import("node:fs/promises");
|
|
623
657
|
const path = await import("node:path");
|
|
624
658
|
|