@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.
@@ -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: PutObjectCommand3 } = await import("@aws-sdk/client-s3");
146
+ const { PutObjectCommand: PutObjectCommand2 } = await import("@aws-sdk/client-s3");
147
147
  try {
148
- await s3.send(new PutObjectCommand3({
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: ListObjectsV2Command3 } = await import("@aws-sdk/client-s3");
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 ListObjectsV2Command3({ Bucket: bucketName, Prefix: bare, ContinuationToken: contToken }));
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: ListObjectsV2Command3, GetObjectCommand: GetObjectCommand3, PutObjectCommand: PutObjectCommand3 } = await import("@aws-sdk/client-s3");
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 ListObjectsV2Command3({ Bucket: bucketName, Prefix: oldFolderKey, ContinuationToken: contToken }));
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 GetObjectCommand3({ Bucket: bucketName, Key: item.Key }));
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 PutObjectCommand3({ Bucket: bucketName, Key: newKey, Body: bytes, ContentType: getRes.ContentType || "application/octet-stream" }));
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 S3Client2;
490
- var PutObjectCommand2;
491
- var GetObjectCommand2;
492
- var ListObjectsV2Command2;
493
- var HeadObjectCommand2;
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
- S3Client2 = aws.S3Client;
506
- PutObjectCommand2 = aws.PutObjectCommand;
507
- GetObjectCommand2 = aws.GetObjectCommand;
508
- ListObjectsV2Command2 = aws.ListObjectsV2Command;
509
- HeadObjectCommand2 = aws.HeadObjectCommand;
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 S3Client2({
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 GetObjectCommand2({ Bucket: this.bucket, Key: this.normalizePath(pathStr) });
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 PutObjectCommand2({
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 HeadObjectCommand2({ Bucket: this.bucket, Key: this.normalizePath(pathStr) });
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 ListObjectsV2Command2({ Bucket: this.bucket, Prefix: prefix });
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 HeadObjectCommand2({ Bucket: this.bucket, Key: this.normalizePath(pathStr) });
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 ListObjectsV2Command2({ Bucket: this.bucket, MaxKeys: 1 }));
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-tosOoSUg.js';
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-BI5RDDB4.js";
33
- import "./chunk-LS3HWJBX.js";
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-6QTNNZSE.js";
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-Y3X3H2XX.js";
85
+ } from "./chunk-7ZT2ZPPH.js";
84
86
  import {
85
87
  workspaceGraphService
86
- } from "./chunk-KSZ67VZJ.js";
88
+ } from "./chunk-F6IDQLC2.js";
87
89
  import {
88
90
  getPrimarySrklDeploymentUrl,
89
91
  getSrklAccounts,
90
92
  srklListBackblazeBuckets
91
- } from "./chunk-N4Z57FVR.js";
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-J2J24JVC.js";
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-Y3X3H2XX.js";
35
- import "./chunk-KSZ67VZJ.js";
36
- import "./chunk-N4Z57FVR.js";
37
- import "./chunk-J2J24JVC.js";
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";