@ultrst-armada/kloks 1.6.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-OZDYAEH4.js → chunk-3IUA66RS.js} +219 -3
- package/packages/backend/dist/{chunk-E72GXBXF.js → chunk-6K75XXFD.js} +9 -200
- package/packages/backend/dist/{chunk-GPXV4GBD.js → chunk-6W7OAGNV.js} +59 -75
- package/packages/backend/dist/{chunk-GQUNN7SA.js → chunk-7ZT2ZPPH.js} +7 -5
- package/packages/backend/dist/{chunk-DBZVGMJ7.js → chunk-F6IDQLC2.js} +2 -2
- 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-3HZYAZF4.js → chunk-SQGBAWZN.js} +97 -7
- package/packages/backend/dist/chunk-VAFCR2MS.js +203 -0
- package/packages/backend/dist/{chunk-VDROUXFT.js → chunk-XHADDA75.js} +19 -13
- package/packages/backend/dist/development/index.d.ts +54 -1
- package/packages/backend/dist/development/index.js +7 -1
- package/packages/backend/dist/index.d.ts +5 -5
- package/packages/backend/dist/index.js +38 -211
- package/packages/backend/dist/krnl-services.js +6 -5
- package/packages/backend/dist/services/index.js +4 -3
- package/packages/backend/dist/srkl/index.d.ts +55 -2
- package/packages/backend/dist/srkl/index.js +3 -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 +3 -2
- package/packages/backend/kloks.manifest.json +25 -0
- 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
|
};
|
|
@@ -245,6 +245,7 @@ var DevelopmentServiceDefinition = createServiceDefinition({
|
|
|
245
245
|
providers: [
|
|
246
246
|
{ id: "webcontainer", capabilities: ["install", "lint", "test", "build", "validate", "check", "process-host"] },
|
|
247
247
|
{ id: "typescript-language-server", capabilities: ["lsp", "diagnostics", "completion", "hover", "definition", "references", "rename", "symbols"] },
|
|
248
|
+
{ id: "agent-harness", capabilities: ["deepseek", "openai", "google", "headless", "sdk", "acp"] },
|
|
248
249
|
{ id: "github-actions", capabilities: ["dispatch", "observe", "rerun", "cancel"] }
|
|
249
250
|
]
|
|
250
251
|
})
|
|
@@ -301,8 +302,8 @@ var COMMANDS2 = {
|
|
|
301
302
|
var DEFAULT_LAYERS = ["syntax", "lint", "krnl", "frnl"];
|
|
302
303
|
var commandText = (command, args) => [command, ...args].join(" ");
|
|
303
304
|
var CodeValidationRuntime = class {
|
|
304
|
-
constructor(
|
|
305
|
-
this.runtime =
|
|
305
|
+
constructor(runtime5 = new WebContainerRuntime()) {
|
|
306
|
+
this.runtime = runtime5;
|
|
306
307
|
}
|
|
307
308
|
runtime;
|
|
308
309
|
async validate(input = {}) {
|
|
@@ -356,8 +357,8 @@ var CodeValidationServiceFacade = {
|
|
|
356
357
|
|
|
357
358
|
// src/development/codeDiagnosticsService.ts
|
|
358
359
|
var CodeDiagnosticsService = class {
|
|
359
|
-
constructor(
|
|
360
|
-
this.runtime =
|
|
360
|
+
constructor(runtime5 = new WebContainerRuntime()) {
|
|
361
|
+
this.runtime = runtime5;
|
|
361
362
|
}
|
|
362
363
|
runtime;
|
|
363
364
|
async diagnostics(input = {}) {
|
|
@@ -375,8 +376,8 @@ var TYPESCRIPT_LANGUAGE_SERVER_VERSION = "6.0.2";
|
|
|
375
376
|
var PACKAGE = TYPESCRIPT_LANGUAGE_SERVER_PACKAGE;
|
|
376
377
|
var DEFAULT_VERSION = TYPESCRIPT_LANGUAGE_SERVER_VERSION;
|
|
377
378
|
var TypeScriptLanguageServerRuntime = class {
|
|
378
|
-
constructor(
|
|
379
|
-
this.runtime =
|
|
379
|
+
constructor(runtime5 = new WebContainerRuntime()) {
|
|
380
|
+
this.runtime = runtime5;
|
|
380
381
|
}
|
|
381
382
|
runtime;
|
|
382
383
|
process = null;
|
|
@@ -502,6 +503,92 @@ var TypeScriptLanguageServerServiceFacade = {
|
|
|
502
503
|
}
|
|
503
504
|
};
|
|
504
505
|
|
|
506
|
+
// src/development/agentHarnessService.ts
|
|
507
|
+
var PROVIDERS = [
|
|
508
|
+
{
|
|
509
|
+
id: "deepseek",
|
|
510
|
+
name: "DeepSeek Harness",
|
|
511
|
+
package: "@deepseek-ai/dsh",
|
|
512
|
+
capabilities: ["headless", "sdk", "acp", "web"],
|
|
513
|
+
implemented: true
|
|
514
|
+
},
|
|
515
|
+
{
|
|
516
|
+
id: "openai",
|
|
517
|
+
name: "OpenAI Agents SDK",
|
|
518
|
+
package: "@openai/agents",
|
|
519
|
+
capabilities: ["agents", "tools", "handoffs", "guardrails", "sessions", "tracing"],
|
|
520
|
+
implemented: false
|
|
521
|
+
},
|
|
522
|
+
{
|
|
523
|
+
id: "google",
|
|
524
|
+
name: "Google ADK",
|
|
525
|
+
package: "@google/adk",
|
|
526
|
+
capabilities: ["agents", "tools", "multi-agent", "evaluation", "deployment"],
|
|
527
|
+
implemented: false
|
|
528
|
+
}
|
|
529
|
+
];
|
|
530
|
+
var AgentHarnessRuntime = class {
|
|
531
|
+
constructor(runtime5 = new WebContainerRuntime()) {
|
|
532
|
+
this.runtime = runtime5;
|
|
533
|
+
}
|
|
534
|
+
runtime;
|
|
535
|
+
providers() {
|
|
536
|
+
return PROVIDERS.map((provider) => ({ ...provider, capabilities: [...provider.capabilities] }));
|
|
537
|
+
}
|
|
538
|
+
async run(input) {
|
|
539
|
+
if (input.provider !== "deepseek") {
|
|
540
|
+
throw new Error(
|
|
541
|
+
`Agent harness provider "${input.provider}" is registered but not yet executable; install and register its adapter before running it.`
|
|
542
|
+
);
|
|
543
|
+
}
|
|
544
|
+
const started = Date.now();
|
|
545
|
+
const profile = input.profile ?? "headless";
|
|
546
|
+
const command = "pnpm";
|
|
547
|
+
const args = ["exec", "dsh", "--profile", profile, input.prompt];
|
|
548
|
+
const result = await this.runtime.runCommand(command, args, input.cwd ?? ".", input.env);
|
|
549
|
+
return {
|
|
550
|
+
provider: input.provider,
|
|
551
|
+
ok: result.exitCode === 0,
|
|
552
|
+
exitCode: result.exitCode,
|
|
553
|
+
output: result.output,
|
|
554
|
+
durationMs: Date.now() - started,
|
|
555
|
+
command: [command, ...args].join(" ")
|
|
556
|
+
};
|
|
557
|
+
}
|
|
558
|
+
};
|
|
559
|
+
var runtime4 = new AgentHarnessRuntime();
|
|
560
|
+
var AgentHarnessServiceDefinition = createServiceDefinition({
|
|
561
|
+
id: "kloks.backend.agentHarness",
|
|
562
|
+
name: "AgentHarnessService",
|
|
563
|
+
version: "1.0.0",
|
|
564
|
+
operations: {
|
|
565
|
+
providers: {
|
|
566
|
+
id: "AgentHarnessService.providers",
|
|
567
|
+
name: "providers",
|
|
568
|
+
handler: async () => runtime4.providers()
|
|
569
|
+
},
|
|
570
|
+
run: {
|
|
571
|
+
id: "AgentHarnessService.run",
|
|
572
|
+
name: "run",
|
|
573
|
+
handler: async (input) => runtime4.run(input)
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
});
|
|
577
|
+
var AgentHarnessServiceFacade = {
|
|
578
|
+
id: AgentHarnessServiceDefinition.id,
|
|
579
|
+
name: AgentHarnessServiceDefinition.name,
|
|
580
|
+
version: AgentHarnessServiceDefinition.version,
|
|
581
|
+
runtime: "client",
|
|
582
|
+
deployment: "local",
|
|
583
|
+
definition: AgentHarnessServiceDefinition,
|
|
584
|
+
createInstance: () => createService(AgentHarnessServiceDefinition),
|
|
585
|
+
execute: async (op, input) => {
|
|
586
|
+
const instance = createService(AgentHarnessServiceDefinition);
|
|
587
|
+
await instance.start();
|
|
588
|
+
return instance.call(op, input);
|
|
589
|
+
}
|
|
590
|
+
};
|
|
591
|
+
|
|
505
592
|
export {
|
|
506
593
|
GitHubActionsClient,
|
|
507
594
|
GitHubActionsServiceDefinition,
|
|
@@ -521,5 +608,8 @@ export {
|
|
|
521
608
|
TYPESCRIPT_LANGUAGE_SERVER_PACKAGE,
|
|
522
609
|
TYPESCRIPT_LANGUAGE_SERVER_VERSION,
|
|
523
610
|
TypeScriptLanguageServerServiceDefinition,
|
|
524
|
-
TypeScriptLanguageServerServiceFacade
|
|
611
|
+
TypeScriptLanguageServerServiceFacade,
|
|
612
|
+
AgentHarnessRuntime,
|
|
613
|
+
AgentHarnessServiceDefinition,
|
|
614
|
+
AgentHarnessServiceFacade
|
|
525
615
|
};
|