@ultrst-armada/kloks 1.7.0 → 1.7.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/.krusbl-release-attestation.json +3 -3
- package/package.json +1 -1
- package/packages/backend/dist/{BaseStorageAdapter-tosOoSUg.d.ts → BaseStorageAdapter-6x_BQiB3.d.ts} +6 -1
- package/packages/backend/dist/{chunk-BI5RDDB4.js → chunk-3IUA66RS.js} +9 -2
- package/packages/backend/dist/{chunk-6QTNNZSE.js → chunk-6W7OAGNV.js} +52 -70
- package/packages/backend/dist/{chunk-Y3X3H2XX.js → chunk-7ZT2ZPPH.js} +3 -3
- package/packages/backend/dist/{chunk-KSZ67VZJ.js → chunk-F6IDQLC2.js} +1 -1
- package/packages/backend/dist/chunk-JUPWFW7V.js +134 -0
- package/packages/backend/dist/{chunk-J2J24JVC.js → chunk-R45CEV46.js} +210 -153
- package/packages/backend/dist/{chunk-N4Z57FVR.js → chunk-XHADDA75.js} +9 -3
- package/packages/backend/dist/index.d.ts +3 -3
- package/packages/backend/dist/index.js +22 -13
- package/packages/backend/dist/krnl-services.js +4 -4
- package/packages/backend/dist/services/index.js +2 -2
- package/packages/backend/dist/srkl/index.d.ts +7 -1
- package/packages/backend/dist/srkl/index.js +2 -2
- package/packages/backend/dist/storage/index.d.ts +35 -3
- package/packages/backend/dist/storage/index.js +12 -3
- package/packages/backend/dist/workspace/index.d.ts +27 -33
- package/packages/backend/dist/workspace/index.js +1 -1
- package/packages/client/dist/index.d.ts +34 -1
- package/packages/client/dist/index.js +116 -0
- package/packages/backend/dist/chunk-LS3HWJBX.js +0 -0
|
@@ -143,9 +143,9 @@ var LocalFSAdapter = class extends BaseStorageAdapter {
|
|
|
143
143
|
async function ensureS3DirectoryMarker(s3, bucketName, folderPrefix) {
|
|
144
144
|
const clean = folderPrefix.replace(/^\/+|\/+$/g, "");
|
|
145
145
|
if (!clean) return;
|
|
146
|
-
const { PutObjectCommand:
|
|
146
|
+
const { PutObjectCommand: PutObjectCommand2 } = await import("@aws-sdk/client-s3");
|
|
147
147
|
try {
|
|
148
|
-
await s3.send(new
|
|
148
|
+
await s3.send(new PutObjectCommand2({
|
|
149
149
|
Bucket: bucketName,
|
|
150
150
|
Key: `${clean}/`,
|
|
151
151
|
Body: Buffer.alloc(0),
|
|
@@ -197,7 +197,7 @@ async function permanentDeleteS3Folder(s3, bucketName, targetPrefix) {
|
|
|
197
197
|
const bare = targetPrefix.replace(/\/+$/, "");
|
|
198
198
|
const isMatch = (k) => k === bare || k === `${bare}/` || k.startsWith(`${bare}/`);
|
|
199
199
|
try {
|
|
200
|
-
const { ListObjectVersionsCommand, DeleteObjectsCommand, DeleteObjectCommand, ListObjectsV2Command:
|
|
200
|
+
const { ListObjectVersionsCommand, DeleteObjectsCommand, DeleteObjectCommand, ListObjectsV2Command: ListObjectsV2Command2 } = await import("@aws-sdk/client-s3");
|
|
201
201
|
let keyMarker;
|
|
202
202
|
let versionMarker;
|
|
203
203
|
let isTruncated = true;
|
|
@@ -237,7 +237,7 @@ async function permanentDeleteS3Folder(s3, bucketName, targetPrefix) {
|
|
|
237
237
|
let contToken;
|
|
238
238
|
let more = true;
|
|
239
239
|
while (more) {
|
|
240
|
-
const v2Res = await s3.send(new
|
|
240
|
+
const v2Res = await s3.send(new ListObjectsV2Command2({ Bucket: bucketName, Prefix: bare, ContinuationToken: contToken }));
|
|
241
241
|
for (const obj of v2Res.Contents || []) {
|
|
242
242
|
if (obj.Key && isMatch(obj.Key)) {
|
|
243
243
|
await permanentDeleteS3Object(s3, bucketName, obj.Key);
|
|
@@ -262,12 +262,12 @@ async function renameS3Folder(s3, bucketName, oldPrefix, newPrefix) {
|
|
|
262
262
|
const newDir = `${newClean}/`;
|
|
263
263
|
let movedCount = 0;
|
|
264
264
|
try {
|
|
265
|
-
const { ListObjectsV2Command:
|
|
265
|
+
const { ListObjectsV2Command: ListObjectsV2Command2, GetObjectCommand: GetObjectCommand2, PutObjectCommand: PutObjectCommand2 } = await import("@aws-sdk/client-s3");
|
|
266
266
|
let contToken;
|
|
267
267
|
let more = true;
|
|
268
268
|
const items = [];
|
|
269
269
|
while (more) {
|
|
270
|
-
const res = await s3.send(new
|
|
270
|
+
const res = await s3.send(new ListObjectsV2Command2({ Bucket: bucketName, Prefix: oldFolderKey, ContinuationToken: contToken }));
|
|
271
271
|
for (const obj of res.Contents || []) {
|
|
272
272
|
if (!obj.Key) continue;
|
|
273
273
|
if (obj.Key === oldFolderKey || obj.Key === oldDir) items.push({ Key: obj.Key, isDir: true, subRel: "" });
|
|
@@ -283,10 +283,10 @@ async function renameS3Folder(s3, bucketName, oldPrefix, newPrefix) {
|
|
|
283
283
|
continue;
|
|
284
284
|
}
|
|
285
285
|
const newKey = `${newDir}${item.subRel}`;
|
|
286
|
-
const getRes = await s3.send(new
|
|
286
|
+
const getRes = await s3.send(new GetObjectCommand2({ Bucket: bucketName, Key: item.Key }));
|
|
287
287
|
if (getRes.Body) {
|
|
288
288
|
const bytes = await getRes.Body.transformToByteArray();
|
|
289
|
-
await s3.send(new
|
|
289
|
+
await s3.send(new PutObjectCommand2({ Bucket: bucketName, Key: newKey, Body: bytes, ContentType: getRes.ContentType || "application/octet-stream" }));
|
|
290
290
|
movedCount++;
|
|
291
291
|
}
|
|
292
292
|
}
|
|
@@ -298,129 +298,6 @@ async function renameS3Folder(s3, bucketName, oldPrefix, newPrefix) {
|
|
|
298
298
|
}
|
|
299
299
|
}
|
|
300
300
|
|
|
301
|
-
// src/storage/S3Adapter.ts
|
|
302
|
-
var S3Client;
|
|
303
|
-
var PutObjectCommand;
|
|
304
|
-
var GetObjectCommand;
|
|
305
|
-
var ListObjectsV2Command;
|
|
306
|
-
var HeadObjectCommand;
|
|
307
|
-
var S3Adapter = class extends BaseStorageAdapter {
|
|
308
|
-
client;
|
|
309
|
-
bucket;
|
|
310
|
-
constructor(config) {
|
|
311
|
-
super(config);
|
|
312
|
-
this.bucket = config.bucket || "";
|
|
313
|
-
}
|
|
314
|
-
async ensureClient() {
|
|
315
|
-
if (this.client) return;
|
|
316
|
-
try {
|
|
317
|
-
const aws = await import("@aws-sdk/client-s3");
|
|
318
|
-
S3Client = aws.S3Client;
|
|
319
|
-
PutObjectCommand = aws.PutObjectCommand;
|
|
320
|
-
GetObjectCommand = aws.GetObjectCommand;
|
|
321
|
-
ListObjectsV2Command = aws.ListObjectsV2Command;
|
|
322
|
-
HeadObjectCommand = aws.HeadObjectCommand;
|
|
323
|
-
this.client = new S3Client({
|
|
324
|
-
region: this.config.region || "us-east-1",
|
|
325
|
-
endpoint: this.config.endpoint,
|
|
326
|
-
credentials: {
|
|
327
|
-
accessKeyId: this.config.accessKey,
|
|
328
|
-
secretAccessKey: this.config.secretKey
|
|
329
|
-
},
|
|
330
|
-
forcePathStyle: Boolean(this.config.endpoint)
|
|
331
|
-
});
|
|
332
|
-
} catch (e) {
|
|
333
|
-
throw new Error(`@aws-sdk/client-s3 failed to initialize: ${e.message}`);
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
async read(pathStr) {
|
|
337
|
-
await this.ensureClient();
|
|
338
|
-
const command = new GetObjectCommand({ Bucket: this.bucket, Key: this.normalizePath(pathStr) });
|
|
339
|
-
const response = await this.client.send(command);
|
|
340
|
-
return response.Body ? await response.Body.transformToByteArray() : new Uint8Array();
|
|
341
|
-
}
|
|
342
|
-
async write(pathStr, data, contentType = "application/octet-stream") {
|
|
343
|
-
await this.ensureClient();
|
|
344
|
-
const body = typeof data === "string" ? Buffer.from(data, "utf-8") : Buffer.from(data);
|
|
345
|
-
const command = new PutObjectCommand({
|
|
346
|
-
Bucket: this.bucket,
|
|
347
|
-
Key: this.normalizePath(pathStr),
|
|
348
|
-
Body: body,
|
|
349
|
-
ContentType: contentType
|
|
350
|
-
});
|
|
351
|
-
await this.client.send(command);
|
|
352
|
-
}
|
|
353
|
-
async delete(pathStr) {
|
|
354
|
-
await this.ensureClient();
|
|
355
|
-
await permanentDeleteS3Object(this.client, this.bucket, this.normalizePath(pathStr));
|
|
356
|
-
}
|
|
357
|
-
async deleteFolder(pathStr) {
|
|
358
|
-
await this.ensureClient();
|
|
359
|
-
return await permanentDeleteS3Folder(this.client, this.bucket, this.normalizePath(pathStr));
|
|
360
|
-
}
|
|
361
|
-
async renameFolder(oldPath, newPath) {
|
|
362
|
-
await this.ensureClient();
|
|
363
|
-
return await renameS3Folder(this.client, this.bucket, this.normalizePath(oldPath), this.normalizePath(newPath));
|
|
364
|
-
}
|
|
365
|
-
async ensureDirectory(pathStr) {
|
|
366
|
-
await this.ensureClient();
|
|
367
|
-
await ensureS3DirectoryMarker(this.client, this.bucket, this.normalizePath(pathStr));
|
|
368
|
-
}
|
|
369
|
-
async exists(pathStr) {
|
|
370
|
-
await this.ensureClient();
|
|
371
|
-
try {
|
|
372
|
-
const command = new HeadObjectCommand({ Bucket: this.bucket, Key: this.normalizePath(pathStr) });
|
|
373
|
-
await this.client.send(command);
|
|
374
|
-
return true;
|
|
375
|
-
} catch (e) {
|
|
376
|
-
if (e.name === "NotFound" || e.$metadata?.httpStatusCode === 404) return false;
|
|
377
|
-
throw e;
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
async list(pathStr = "") {
|
|
381
|
-
await this.ensureClient();
|
|
382
|
-
const prefix = pathStr ? this.normalizePath(pathStr).replace(/\/+$/, "") + "/" : "";
|
|
383
|
-
const command = new ListObjectsV2Command({ Bucket: this.bucket, Prefix: prefix });
|
|
384
|
-
const response = await this.client.send(command);
|
|
385
|
-
return (response.Contents || []).map((item) => ({
|
|
386
|
-
path: item.Key,
|
|
387
|
-
size: item.Size || 0,
|
|
388
|
-
modifiedAt: item.LastModified ? item.LastModified.getTime() : 0
|
|
389
|
-
}));
|
|
390
|
-
}
|
|
391
|
-
async stat(pathStr) {
|
|
392
|
-
await this.ensureClient();
|
|
393
|
-
const command = new HeadObjectCommand({ Bucket: this.bucket, Key: this.normalizePath(pathStr) });
|
|
394
|
-
const response = await this.client.send(command);
|
|
395
|
-
return {
|
|
396
|
-
path: pathStr,
|
|
397
|
-
size: response.ContentLength || 0,
|
|
398
|
-
modifiedAt: response.LastModified ? response.LastModified.getTime() : 0
|
|
399
|
-
};
|
|
400
|
-
}
|
|
401
|
-
async mkdir(pathStr) {
|
|
402
|
-
await this.ensureDirectory(pathStr);
|
|
403
|
-
}
|
|
404
|
-
async testConnection() {
|
|
405
|
-
const start = performance.now();
|
|
406
|
-
try {
|
|
407
|
-
await this.ensureClient();
|
|
408
|
-
const res = await this.client.send(new ListObjectsV2Command({ Bucket: this.bucket, MaxKeys: 1 }));
|
|
409
|
-
return {
|
|
410
|
-
ok: true,
|
|
411
|
-
latencyMs: Math.round(performance.now() - start),
|
|
412
|
-
details: { bucket: this.bucket, keyCount: res.KeyCount ?? 0 }
|
|
413
|
-
};
|
|
414
|
-
} catch (e) {
|
|
415
|
-
return {
|
|
416
|
-
ok: false,
|
|
417
|
-
latencyMs: Math.round(performance.now() - start),
|
|
418
|
-
error: e.message
|
|
419
|
-
};
|
|
420
|
-
}
|
|
421
|
-
}
|
|
422
|
-
};
|
|
423
|
-
|
|
424
301
|
// src/storage/b2Endpoint.ts
|
|
425
302
|
function isSecretMasked(str) {
|
|
426
303
|
return Boolean(str && (str.includes("\u2022") || str.includes("***")));
|
|
@@ -486,11 +363,11 @@ ${appKey}`;
|
|
|
486
363
|
}
|
|
487
364
|
|
|
488
365
|
// src/storage/BackblazeB2Adapter.ts
|
|
489
|
-
var
|
|
490
|
-
var
|
|
491
|
-
var
|
|
492
|
-
var
|
|
493
|
-
var
|
|
366
|
+
var S3Client;
|
|
367
|
+
var PutObjectCommand;
|
|
368
|
+
var GetObjectCommand;
|
|
369
|
+
var ListObjectsV2Command;
|
|
370
|
+
var HeadObjectCommand;
|
|
494
371
|
var BackblazeB2Adapter = class extends BaseStorageAdapter {
|
|
495
372
|
client;
|
|
496
373
|
bucket;
|
|
@@ -502,17 +379,17 @@ var BackblazeB2Adapter = class extends BaseStorageAdapter {
|
|
|
502
379
|
if (this.client) return;
|
|
503
380
|
try {
|
|
504
381
|
const aws = await import("@aws-sdk/client-s3");
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
382
|
+
S3Client = aws.S3Client;
|
|
383
|
+
PutObjectCommand = aws.PutObjectCommand;
|
|
384
|
+
GetObjectCommand = aws.GetObjectCommand;
|
|
385
|
+
ListObjectsV2Command = aws.ListObjectsV2Command;
|
|
386
|
+
HeadObjectCommand = aws.HeadObjectCommand;
|
|
510
387
|
const rawKeyId = this.config.b2KeyId || this.config.accessKey || this.config.keyId;
|
|
511
388
|
const rawAppKey = this.config.b2ApplicationKey || this.config.secretKey || this.config.applicationKey;
|
|
512
389
|
const { keyId, appKey } = normalizeBackblazeCredentials(rawKeyId, rawAppKey);
|
|
513
390
|
const rawEndpoint = this.config.b2Endpoint || this.config.endpoint || this.config.b2Region || this.config.region;
|
|
514
391
|
const { endpoint, region } = resolveBackblazeEndpoint(rawEndpoint, keyId);
|
|
515
|
-
this.client = new
|
|
392
|
+
this.client = new S3Client({
|
|
516
393
|
region,
|
|
517
394
|
endpoint,
|
|
518
395
|
forcePathStyle: true,
|
|
@@ -527,14 +404,14 @@ var BackblazeB2Adapter = class extends BaseStorageAdapter {
|
|
|
527
404
|
}
|
|
528
405
|
async read(pathStr) {
|
|
529
406
|
await this.ensureClient();
|
|
530
|
-
const command = new
|
|
407
|
+
const command = new GetObjectCommand({ Bucket: this.bucket, Key: this.normalizePath(pathStr) });
|
|
531
408
|
const response = await this.client.send(command);
|
|
532
409
|
return response.Body ? await response.Body.transformToByteArray() : new Uint8Array();
|
|
533
410
|
}
|
|
534
411
|
async write(pathStr, data, contentType = "text/plain") {
|
|
535
412
|
await this.ensureClient();
|
|
536
413
|
const body = typeof data === "string" ? Buffer.from(data, "utf-8") : Buffer.from(data);
|
|
537
|
-
const command = new
|
|
414
|
+
const command = new PutObjectCommand({
|
|
538
415
|
Bucket: this.bucket,
|
|
539
416
|
Key: this.normalizePath(pathStr),
|
|
540
417
|
Body: body,
|
|
@@ -566,7 +443,7 @@ var BackblazeB2Adapter = class extends BaseStorageAdapter {
|
|
|
566
443
|
async exists(pathStr) {
|
|
567
444
|
await this.ensureClient();
|
|
568
445
|
try {
|
|
569
|
-
const command = new
|
|
446
|
+
const command = new HeadObjectCommand({ Bucket: this.bucket, Key: this.normalizePath(pathStr) });
|
|
570
447
|
await this.client.send(command);
|
|
571
448
|
return true;
|
|
572
449
|
} catch (e) {
|
|
@@ -577,7 +454,7 @@ var BackblazeB2Adapter = class extends BaseStorageAdapter {
|
|
|
577
454
|
async list(pathStr = "") {
|
|
578
455
|
await this.ensureClient();
|
|
579
456
|
const prefix = pathStr ? this.normalizePath(pathStr).replace(/\/+$/, "") + "/" : "";
|
|
580
|
-
const command = new
|
|
457
|
+
const command = new ListObjectsV2Command({ Bucket: this.bucket, Prefix: prefix });
|
|
581
458
|
const response = await this.client.send(command);
|
|
582
459
|
return (response.Contents || []).map((item) => ({
|
|
583
460
|
path: item.Key,
|
|
@@ -587,7 +464,7 @@ var BackblazeB2Adapter = class extends BaseStorageAdapter {
|
|
|
587
464
|
}
|
|
588
465
|
async stat(pathStr) {
|
|
589
466
|
await this.ensureClient();
|
|
590
|
-
const command = new
|
|
467
|
+
const command = new HeadObjectCommand({ Bucket: this.bucket, Key: this.normalizePath(pathStr) });
|
|
591
468
|
const response = await this.client.send(command);
|
|
592
469
|
return {
|
|
593
470
|
path: pathStr,
|
|
@@ -602,7 +479,7 @@ var BackblazeB2Adapter = class extends BaseStorageAdapter {
|
|
|
602
479
|
const start = performance.now();
|
|
603
480
|
try {
|
|
604
481
|
await this.ensureClient();
|
|
605
|
-
const res = await this.client.send(new
|
|
482
|
+
const res = await this.client.send(new ListObjectsV2Command({ Bucket: this.bucket, MaxKeys: 1 }));
|
|
606
483
|
return {
|
|
607
484
|
ok: true,
|
|
608
485
|
latencyMs: Math.round(performance.now() - start),
|
|
@@ -618,6 +495,185 @@ var BackblazeB2Adapter = class extends BaseStorageAdapter {
|
|
|
618
495
|
}
|
|
619
496
|
};
|
|
620
497
|
|
|
498
|
+
// src/storage/GoogleDriveOAuth.ts
|
|
499
|
+
var AUTH_URL = "https://accounts.google.com/o/oauth2/v2/auth";
|
|
500
|
+
var TOKEN_URL = "https://oauth2.googleapis.com/token";
|
|
501
|
+
function createGoogleDriveAuthorizationUrl(config, state, codeChallenge) {
|
|
502
|
+
const params = new URLSearchParams({
|
|
503
|
+
client_id: config.clientId,
|
|
504
|
+
redirect_uri: config.redirectUri,
|
|
505
|
+
response_type: "code",
|
|
506
|
+
access_type: "offline",
|
|
507
|
+
prompt: "consent",
|
|
508
|
+
scope: (config.scopes || ["https://www.googleapis.com/auth/drive.file"]).join(" "),
|
|
509
|
+
state
|
|
510
|
+
});
|
|
511
|
+
if (codeChallenge) {
|
|
512
|
+
params.set("code_challenge", codeChallenge);
|
|
513
|
+
params.set("code_challenge_method", "S256");
|
|
514
|
+
}
|
|
515
|
+
return `${AUTH_URL}?${params.toString()}`;
|
|
516
|
+
}
|
|
517
|
+
async function exchangeGoogleDriveCode(config, code, codeVerifier) {
|
|
518
|
+
const body = new URLSearchParams({
|
|
519
|
+
client_id: config.clientId,
|
|
520
|
+
redirect_uri: config.redirectUri,
|
|
521
|
+
code,
|
|
522
|
+
grant_type: "authorization_code"
|
|
523
|
+
});
|
|
524
|
+
if (config.clientSecret) body.set("client_secret", config.clientSecret);
|
|
525
|
+
if (codeVerifier) body.set("code_verifier", codeVerifier);
|
|
526
|
+
const response = await fetch(TOKEN_URL, {
|
|
527
|
+
method: "POST",
|
|
528
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
529
|
+
body
|
|
530
|
+
});
|
|
531
|
+
if (!response.ok) throw new Error(`Google OAuth token exchange failed: ${response.status}`);
|
|
532
|
+
const data = await response.json();
|
|
533
|
+
return {
|
|
534
|
+
accessToken: data.access_token,
|
|
535
|
+
refreshToken: data.refresh_token,
|
|
536
|
+
expiresAt: data.expires_in ? Date.now() + Number(data.expires_in) * 1e3 : void 0,
|
|
537
|
+
tokenType: data.token_type
|
|
538
|
+
};
|
|
539
|
+
}
|
|
540
|
+
async function refreshGoogleDriveAccessToken(clientId, refreshToken) {
|
|
541
|
+
const body = new URLSearchParams({
|
|
542
|
+
client_id: clientId,
|
|
543
|
+
refresh_token: refreshToken,
|
|
544
|
+
grant_type: "refresh_token"
|
|
545
|
+
});
|
|
546
|
+
const response = await fetch(TOKEN_URL, {
|
|
547
|
+
method: "POST",
|
|
548
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
549
|
+
body
|
|
550
|
+
});
|
|
551
|
+
if (!response.ok) throw new Error(`Google OAuth refresh failed: ${response.status}`);
|
|
552
|
+
const data = await response.json();
|
|
553
|
+
return {
|
|
554
|
+
accessToken: data.access_token,
|
|
555
|
+
expiresAt: data.expires_in ? Date.now() + Number(data.expires_in) * 1e3 : void 0,
|
|
556
|
+
tokenType: data.token_type
|
|
557
|
+
};
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
// src/storage/GoogleDriveAdapter.ts
|
|
561
|
+
var GoogleDriveAdapter = class extends BaseStorageAdapter {
|
|
562
|
+
async token() {
|
|
563
|
+
const accessToken = this.config.googleAccessToken || this.config.accessKey;
|
|
564
|
+
const expiresAt = Number(this.config.googleAccessTokenExpiresAt || 0);
|
|
565
|
+
if (accessToken && (!expiresAt || expiresAt > Date.now() + 6e4)) return accessToken;
|
|
566
|
+
const refreshToken = this.config.googleRefreshToken;
|
|
567
|
+
const clientId = this.config.googleClientId;
|
|
568
|
+
if (!refreshToken || !clientId) throw new Error("Google Drive OAuth credentials are incomplete.");
|
|
569
|
+
const refreshed = await refreshGoogleDriveAccessToken(clientId, refreshToken);
|
|
570
|
+
this.config.googleAccessToken = refreshed.accessToken;
|
|
571
|
+
this.config.googleAccessTokenExpiresAt = refreshed.expiresAt;
|
|
572
|
+
return refreshed.accessToken;
|
|
573
|
+
}
|
|
574
|
+
async request(url, init = {}) {
|
|
575
|
+
const headers = new Headers(init.headers);
|
|
576
|
+
headers.set("Authorization", `Bearer ${await this.token()}`);
|
|
577
|
+
return fetch(url, { ...init, headers });
|
|
578
|
+
}
|
|
579
|
+
async findChild(parentId, name) {
|
|
580
|
+
const q = `'${parentId}' in parents and name = '${name.replace(/'/g, "\\'")}' and trashed = false`;
|
|
581
|
+
const res = await this.request(`https://www.googleapis.com/drive/v3/files?q=${encodeURIComponent(q)}&fields=files(id,name,size,modifiedTime,mimeType)&pageSize=10`);
|
|
582
|
+
if (!res.ok) throw new Error(`Google Drive lookup failed: ${res.status}`);
|
|
583
|
+
const data = await res.json();
|
|
584
|
+
return data.files?.[0] || null;
|
|
585
|
+
}
|
|
586
|
+
async resolveParent(relativeDir, create = false) {
|
|
587
|
+
let parent = this.config.googleRootFolderId || this.config.rootFolderId || "root";
|
|
588
|
+
for (const part of this.normalizePath(relativeDir).split("/").filter(Boolean)) {
|
|
589
|
+
let child = await this.findChild(parent, part);
|
|
590
|
+
if (!child && create) {
|
|
591
|
+
const res = await this.request("https://www.googleapis.com/drive/v3/files", {
|
|
592
|
+
method: "POST",
|
|
593
|
+
headers: { "Content-Type": "application/json" },
|
|
594
|
+
body: JSON.stringify({ name: part, mimeType: "application/vnd.google-apps.folder", parents: [parent] })
|
|
595
|
+
});
|
|
596
|
+
if (!res.ok) throw new Error(`Google Drive folder creation failed: ${res.status}`);
|
|
597
|
+
child = await res.json();
|
|
598
|
+
}
|
|
599
|
+
if (!child) throw new Error(`Google Drive directory not found: ${part}`);
|
|
600
|
+
parent = child.id;
|
|
601
|
+
}
|
|
602
|
+
return parent;
|
|
603
|
+
}
|
|
604
|
+
split(pathStr) {
|
|
605
|
+
const key = this.normalizePath(pathStr);
|
|
606
|
+
const i = key.lastIndexOf("/");
|
|
607
|
+
return i < 0 ? { dir: "", name: key } : { dir: key.slice(0, i), name: key.slice(i + 1) };
|
|
608
|
+
}
|
|
609
|
+
async read(pathStr) {
|
|
610
|
+
const { dir, name } = this.split(pathStr);
|
|
611
|
+
const parent = await this.resolveParent(dir);
|
|
612
|
+
const file = await this.findChild(parent, name);
|
|
613
|
+
if (!file) throw new Error(`Google Drive file not found: ${pathStr}`);
|
|
614
|
+
const res = await this.request(`https://www.googleapis.com/drive/v3/files/${file.id}?alt=media`);
|
|
615
|
+
if (!res.ok) throw new Error(`Google Drive download failed: ${res.status}`);
|
|
616
|
+
return new Uint8Array(await res.arrayBuffer());
|
|
617
|
+
}
|
|
618
|
+
async write(pathStr, data, contentType = "application/octet-stream") {
|
|
619
|
+
const { dir, name } = this.split(pathStr);
|
|
620
|
+
const parent = await this.resolveParent(dir, true);
|
|
621
|
+
const existing = await this.findChild(parent, name);
|
|
622
|
+
const bytes = typeof data === "string" ? new TextEncoder().encode(data) : data;
|
|
623
|
+
const form = new FormData();
|
|
624
|
+
form.append("metadata", new Blob([JSON.stringify({ name, mimeType: contentType, ...existing ? {} : { parents: [parent] } })], { type: "application/json" }));
|
|
625
|
+
form.append("file", new Blob([bytes], { type: contentType }));
|
|
626
|
+
const url = existing ? `https://www.googleapis.com/upload/drive/v3/files/${existing.id}?uploadType=multipart` : "https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart";
|
|
627
|
+
const res = await this.request(url, { method: existing ? "PATCH" : "POST", body: form });
|
|
628
|
+
if (!res.ok) throw new Error(`Google Drive upload failed: ${res.status}`);
|
|
629
|
+
}
|
|
630
|
+
async delete(pathStr) {
|
|
631
|
+
const { dir, name } = this.split(pathStr);
|
|
632
|
+
const parent = await this.resolveParent(dir);
|
|
633
|
+
const file = await this.findChild(parent, name);
|
|
634
|
+
if (!file) return;
|
|
635
|
+
const res = await this.request(`https://www.googleapis.com/drive/v3/files/${file.id}`, { method: "DELETE" });
|
|
636
|
+
if (!res.ok && res.status !== 404) throw new Error(`Google Drive delete failed: ${res.status}`);
|
|
637
|
+
}
|
|
638
|
+
async exists(pathStr) {
|
|
639
|
+
try {
|
|
640
|
+
await this.stat(pathStr);
|
|
641
|
+
return true;
|
|
642
|
+
} catch {
|
|
643
|
+
return false;
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
async list(pathStr = "") {
|
|
647
|
+
const parent = await this.resolveParent(pathStr);
|
|
648
|
+
const q = `'${parent}' in parents and trashed = false`;
|
|
649
|
+
const res = await this.request(`https://www.googleapis.com/drive/v3/files?q=${encodeURIComponent(q)}&fields=files(id,name,size,modifiedTime,mimeType)&pageSize=1000`);
|
|
650
|
+
if (!res.ok) throw new Error(`Google Drive list failed: ${res.status}`);
|
|
651
|
+
const data = await res.json();
|
|
652
|
+
return (data.files || []).map((f) => ({ path: this.normalizePath(pathStr ? `${pathStr}/${f.name}` : f.name), size: Number(f.size || 0), modifiedAt: f.modifiedTime ? Date.parse(f.modifiedTime) : 0 }));
|
|
653
|
+
}
|
|
654
|
+
async stat(pathStr) {
|
|
655
|
+
const { dir, name } = this.split(pathStr);
|
|
656
|
+
const parent = await this.resolveParent(dir);
|
|
657
|
+
const file = await this.findChild(parent, name);
|
|
658
|
+
if (!file) throw new Error(`Google Drive file not found: ${pathStr}`);
|
|
659
|
+
return { path: pathStr, size: Number(file.size || 0), modifiedAt: file.modifiedTime ? Date.parse(file.modifiedTime) : 0 };
|
|
660
|
+
}
|
|
661
|
+
async mkdir(pathStr) {
|
|
662
|
+
await this.resolveParent(pathStr, true);
|
|
663
|
+
}
|
|
664
|
+
async testConnection() {
|
|
665
|
+
const start = performance.now();
|
|
666
|
+
try {
|
|
667
|
+
const res = await this.request("https://www.googleapis.com/drive/v3/about?fields=user");
|
|
668
|
+
if (!res.ok) throw new Error(`Google Drive authorization failed: ${res.status}`);
|
|
669
|
+
const data = await res.json();
|
|
670
|
+
return { ok: true, latencyMs: Math.round(performance.now() - start), details: { email: data.user?.emailAddress } };
|
|
671
|
+
} catch (e) {
|
|
672
|
+
return { ok: false, latencyMs: Math.round(performance.now() - start), error: e.message };
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
};
|
|
676
|
+
|
|
621
677
|
// src/storage/SupabaseStorageAdapter.ts
|
|
622
678
|
var createClient;
|
|
623
679
|
var SupabaseStorageAdapter = class extends BaseStorageAdapter {
|
|
@@ -699,15 +755,13 @@ var StorageAdapterFactory = class {
|
|
|
699
755
|
switch (config.provider) {
|
|
700
756
|
case "local_fs":
|
|
701
757
|
return new LocalFSAdapter(config);
|
|
702
|
-
case "s3":
|
|
703
|
-
case "cloudflare_r2":
|
|
704
|
-
case "r2":
|
|
705
|
-
return new S3Adapter(config);
|
|
706
758
|
case "backblaze_b2":
|
|
707
759
|
case "b2":
|
|
708
760
|
return new BackblazeB2Adapter(config);
|
|
709
761
|
case "supabase":
|
|
710
762
|
return new SupabaseStorageAdapter(config);
|
|
763
|
+
case "google_drive":
|
|
764
|
+
return new GoogleDriveAdapter(config);
|
|
711
765
|
default:
|
|
712
766
|
throw new Error(`Unsupported storage provider: ${config.provider}`);
|
|
713
767
|
}
|
|
@@ -721,11 +775,14 @@ export {
|
|
|
721
775
|
permanentDeleteS3Object,
|
|
722
776
|
permanentDeleteS3Folder,
|
|
723
777
|
renameS3Folder,
|
|
724
|
-
S3Adapter,
|
|
725
778
|
isSecretMasked,
|
|
726
779
|
resolveBackblazeEndpoint,
|
|
727
780
|
normalizeBackblazeCredentials,
|
|
728
781
|
BackblazeB2Adapter,
|
|
782
|
+
createGoogleDriveAuthorizationUrl,
|
|
783
|
+
exchangeGoogleDriveCode,
|
|
784
|
+
refreshGoogleDriveAccessToken,
|
|
785
|
+
GoogleDriveAdapter,
|
|
729
786
|
SupabaseStorageAdapter,
|
|
730
787
|
StorageAdapterFactory
|
|
731
788
|
};
|
|
@@ -41,8 +41,8 @@ async function getSrklAccounts(userId, service, queryDb) {
|
|
|
41
41
|
}
|
|
42
42
|
for (const conn of pool) {
|
|
43
43
|
if (service && !conn.provider?.toLowerCase().includes(service.toLowerCase())) continue;
|
|
44
|
-
const kId = (conn.b2KeyId || conn.keyId || conn.accessKeyId || "").trim();
|
|
45
|
-
const key = kId ? `key:${kId}` : `id:${conn.id}`;
|
|
44
|
+
const kId = (conn.b2KeyId || conn.keyId || conn.accessKeyId || conn.googleEmail || "").trim();
|
|
45
|
+
const key = kId ? `key:${kId}:${conn.googleRootFolderId || conn.b2BucketName || ""}` : `id:${conn.id}`;
|
|
46
46
|
if (!seenKeys.has(key)) {
|
|
47
47
|
seenKeys.add(key);
|
|
48
48
|
accounts.push({
|
|
@@ -55,7 +55,13 @@ async function getSrklAccounts(userId, service, queryDb) {
|
|
|
55
55
|
applicationKey: conn.b2ApplicationKey || conn.appKey,
|
|
56
56
|
bucketName: conn.b2BucketName || conn.bucketName,
|
|
57
57
|
region: conn.b2Region || conn.region,
|
|
58
|
-
endpoint: conn.b2Endpoint || conn.endpoint
|
|
58
|
+
endpoint: conn.b2Endpoint || conn.endpoint,
|
|
59
|
+
email: conn.googleEmail,
|
|
60
|
+
rootFolderId: conn.googleRootFolderId,
|
|
61
|
+
rootFolderName: conn.googleRootFolderName,
|
|
62
|
+
accessToken: conn.googleAccessToken,
|
|
63
|
+
accessTokenExpiresAt: conn.googleAccessTokenExpiresAt,
|
|
64
|
+
refreshToken: conn.googleRefreshToken
|
|
59
65
|
}
|
|
60
66
|
});
|
|
61
67
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { A as AuthCredentials, a as AuthSession, B as BaseAccountProvider, C as CreateUserData, R as RateLimiter, S as SessionManager, b as SignupInput, U as User, c as UserRole } from './BaseAccountProvider-DduKf5HG.js';
|
|
2
2
|
export { AdminGuard, LocalAccountProvider, PasswordHasher, SystemUser, loginSystemUser, resolveUserFromToken } from './auth/index.js';
|
|
3
|
-
export { B as BaseStorageAdapter, C as ConnectionTestResult, D as DeleteFolderResult, F as FileInfo, R as RenameFolderResult, S as StorageConfig, a as StorageMode, b as StorageProviderType, U as UploadResult } from './BaseStorageAdapter-
|
|
4
|
-
export { B2AuthToken, BackblazeB2Adapter, LocalFSAdapter, S3Adapter, StorageAdapterFactory, SupabaseStorageAdapter, authorizeB2, b2DownloadFile, b2ListBuckets, b2ListFileNames, b2UploadFile, ensureS3DirectoryMarker, isSecretMasked, normalizeBackblazeCredentials, permanentDeleteS3Folder, permanentDeleteS3Object, renameS3Folder, resolveBackblazeEndpoint } from './storage/index.js';
|
|
3
|
+
export { B as BaseStorageAdapter, C as ConnectionTestResult, D as DeleteFolderResult, F as FileInfo, R as RenameFolderResult, S as StorageConfig, a as StorageMode, b as StorageProviderType, U as UploadResult } from './BaseStorageAdapter-6x_BQiB3.js';
|
|
4
|
+
export { B2AuthToken, BackblazeB2Adapter, GoogleDriveAdapter, GoogleDriveOAuthConfig, GoogleDriveTokenSet, LocalFSAdapter, S3Adapter, StorageAdapterFactory, SupabaseStorageAdapter, authorizeB2, b2DownloadFile, b2ListBuckets, b2ListFileNames, b2UploadFile, createGoogleDriveAuthorizationUrl, ensureS3DirectoryMarker, exchangeGoogleDriveCode, isSecretMasked, normalizeBackblazeCredentials, permanentDeleteS3Folder, permanentDeleteS3Object, refreshGoogleDriveAccessToken, renameS3Folder, resolveBackblazeEndpoint } from './storage/index.js';
|
|
5
5
|
export { CloneReplicationResult, ConflictPolicy, RemoteWorkspaceService, SyncEngine, SyncState, WorkingWorkspaceService, WorkspaceCloneSyncEngine, WorkspaceConfig, WorkspaceDescriptor, WorkspaceFS, WorkspaceFileEntry, WorkspaceListResult, WorkspaceLookupResult, WorkspaceMutationResult, WorkspaceSecondaryClone, WorkspaceService, WorkspaceSyncSummary, formatCanonicalWorkspaceFolderName, remoteWorkspaceService, sanitizeWorkspaceName, workingWorkspaceService } from './workspace/index.js';
|
|
6
6
|
export { AuditEvent, AuditLogger, ClusterConfig, ControlPlaneManager, DatabaseClusterManager, HealthStatus, detectDatabaseEngine, getSystemDatabaseUrls, resolveSystemDatabaseClusterNodes } from './control-plane/index.js';
|
|
7
7
|
export { ApiError, ApiResponse, BaseApiRoute, Middleware, RouteConfig, createSSEResponse, withAuth, withCors } from './api/index.js';
|
|
@@ -211,7 +211,7 @@ interface WorkingWorkspaceConfig {
|
|
|
211
211
|
declare function getDefaultWorkingWorkspaceDir(): string;
|
|
212
212
|
declare function getWorkingWorkspaceConfig(): WorkingWorkspaceConfig;
|
|
213
213
|
declare function setWorkingWorkspaceConfig(cfg: Partial<WorkingWorkspaceConfig>): WorkingWorkspaceConfig;
|
|
214
|
-
declare function getWorkingWorkspaceDir(): string;
|
|
214
|
+
declare function getWorkingWorkspaceDir(workspaceId?: string): string;
|
|
215
215
|
declare function findWorkspaceRecord(workspaceId: string): Promise<{
|
|
216
216
|
user: any;
|
|
217
217
|
workspace: any;
|
|
@@ -29,8 +29,10 @@ import {
|
|
|
29
29
|
srklService,
|
|
30
30
|
syncSrklAccounts,
|
|
31
31
|
useSrklServices
|
|
32
|
-
} from "./chunk-
|
|
33
|
-
import
|
|
32
|
+
} from "./chunk-3IUA66RS.js";
|
|
33
|
+
import {
|
|
34
|
+
S3Adapter
|
|
35
|
+
} from "./chunk-JUPWFW7V.js";
|
|
34
36
|
import {
|
|
35
37
|
RemoteWorkspaceService,
|
|
36
38
|
SyncEngine,
|
|
@@ -46,7 +48,7 @@ import {
|
|
|
46
48
|
setWorkingWorkspaceConfig,
|
|
47
49
|
syncWorkspace,
|
|
48
50
|
workingWorkspaceService
|
|
49
|
-
} from "./chunk-
|
|
51
|
+
} from "./chunk-6W7OAGNV.js";
|
|
50
52
|
import {
|
|
51
53
|
AuthServiceDefinition,
|
|
52
54
|
AuthServiceFacade,
|
|
@@ -80,30 +82,33 @@ import {
|
|
|
80
82
|
krnlWorkspaceGraphServiceFacade,
|
|
81
83
|
krnlWorkspaceServiceDefinition,
|
|
82
84
|
krnlWorkspaceServiceFacade
|
|
83
|
-
} from "./chunk-
|
|
85
|
+
} from "./chunk-7ZT2ZPPH.js";
|
|
84
86
|
import {
|
|
85
87
|
workspaceGraphService
|
|
86
|
-
} from "./chunk-
|
|
88
|
+
} from "./chunk-F6IDQLC2.js";
|
|
87
89
|
import {
|
|
88
90
|
getPrimarySrklDeploymentUrl,
|
|
89
91
|
getSrklAccounts,
|
|
90
92
|
srklListBackblazeBuckets
|
|
91
|
-
} from "./chunk-
|
|
93
|
+
} from "./chunk-XHADDA75.js";
|
|
92
94
|
import {
|
|
93
95
|
BackblazeB2Adapter,
|
|
94
96
|
BaseStorageAdapter,
|
|
97
|
+
GoogleDriveAdapter,
|
|
95
98
|
LocalFSAdapter,
|
|
96
|
-
S3Adapter,
|
|
97
99
|
StorageAdapterFactory,
|
|
98
100
|
SupabaseStorageAdapter,
|
|
101
|
+
createGoogleDriveAuthorizationUrl,
|
|
99
102
|
ensureS3DirectoryMarker,
|
|
103
|
+
exchangeGoogleDriveCode,
|
|
100
104
|
isSecretMasked,
|
|
101
105
|
normalizeBackblazeCredentials,
|
|
102
106
|
permanentDeleteS3Folder,
|
|
103
107
|
permanentDeleteS3Object,
|
|
108
|
+
refreshGoogleDriveAccessToken,
|
|
104
109
|
renameS3Folder,
|
|
105
110
|
resolveBackblazeEndpoint
|
|
106
|
-
} from "./chunk-
|
|
111
|
+
} from "./chunk-R45CEV46.js";
|
|
107
112
|
import {
|
|
108
113
|
authorizeB2,
|
|
109
114
|
b2DownloadFile,
|
|
@@ -151,11 +156,6 @@ import {
|
|
|
151
156
|
withAuth,
|
|
152
157
|
withCors
|
|
153
158
|
} from "./chunk-TWCEVES2.js";
|
|
154
|
-
import {
|
|
155
|
-
BackendProvider,
|
|
156
|
-
useBackend,
|
|
157
|
-
useBackendClient
|
|
158
|
-
} from "./chunk-G3ZOSXUR.js";
|
|
159
159
|
import {
|
|
160
160
|
AdminGuard,
|
|
161
161
|
BaseAccountProvider,
|
|
@@ -168,6 +168,11 @@ import {
|
|
|
168
168
|
loginSystemUser,
|
|
169
169
|
resolveUserFromToken
|
|
170
170
|
} from "./chunk-ZDH4XI7W.js";
|
|
171
|
+
import {
|
|
172
|
+
BackendProvider,
|
|
173
|
+
useBackend,
|
|
174
|
+
useBackendClient
|
|
175
|
+
} from "./chunk-G3ZOSXUR.js";
|
|
171
176
|
import {
|
|
172
177
|
BackendRegistry,
|
|
173
178
|
ConcurrencyConflictError,
|
|
@@ -4232,6 +4237,7 @@ export {
|
|
|
4232
4237
|
GitHubActionsClient,
|
|
4233
4238
|
GitHubActionsServiceDefinition,
|
|
4234
4239
|
GitHubActionsServiceFacade,
|
|
4240
|
+
GoogleDriveAdapter,
|
|
4235
4241
|
HTTPTransport,
|
|
4236
4242
|
HealthMonitor,
|
|
4237
4243
|
IdempotencyManager,
|
|
@@ -4305,6 +4311,7 @@ export {
|
|
|
4305
4311
|
createCompositeService,
|
|
4306
4312
|
createCredential,
|
|
4307
4313
|
createEmptyContract,
|
|
4314
|
+
createGoogleDriveAuthorizationUrl,
|
|
4308
4315
|
createGraphAssetFolder,
|
|
4309
4316
|
createGraphAssetFolder as createGraphAssetSubfolder,
|
|
4310
4317
|
createGraphPackage,
|
|
@@ -4338,6 +4345,7 @@ export {
|
|
|
4338
4345
|
ensureProjectsRoot,
|
|
4339
4346
|
ensureS3DirectoryMarker,
|
|
4340
4347
|
ensureWorkspaceStructure,
|
|
4348
|
+
exchangeGoogleDriveCode,
|
|
4341
4349
|
exportEncryptedCredentials,
|
|
4342
4350
|
exportGraphAsJsonFile,
|
|
4343
4351
|
fetchCloudflareData,
|
|
@@ -4421,6 +4429,7 @@ export {
|
|
|
4421
4429
|
queryUnifiedDb,
|
|
4422
4430
|
readWorkspaceFile,
|
|
4423
4431
|
recordExecution,
|
|
4432
|
+
refreshGoogleDriveAccessToken,
|
|
4424
4433
|
remoteWorkspaceService,
|
|
4425
4434
|
removeGraphDependency,
|
|
4426
4435
|
renameAppInWorkspaceData,
|
|
@@ -31,10 +31,10 @@ import {
|
|
|
31
31
|
krnlWorkspaceGraphServiceFacade,
|
|
32
32
|
krnlWorkspaceServiceDefinition,
|
|
33
33
|
krnlWorkspaceServiceFacade
|
|
34
|
-
} from "./chunk-
|
|
35
|
-
import "./chunk-
|
|
36
|
-
import "./chunk-
|
|
37
|
-
import "./chunk-
|
|
34
|
+
} from "./chunk-7ZT2ZPPH.js";
|
|
35
|
+
import "./chunk-F6IDQLC2.js";
|
|
36
|
+
import "./chunk-XHADDA75.js";
|
|
37
|
+
import "./chunk-R45CEV46.js";
|
|
38
38
|
import "./chunk-4QEMALXF.js";
|
|
39
39
|
import "./chunk-FZKBTF34.js";
|
|
40
40
|
import "./chunk-6K75XXFD.js";
|