@aigne/afs-gcs 1.11.0-beta.6 → 1.11.0-beta.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -1,5 +1,4 @@
1
- import { AFSAccessMode, AFSBaseProvider, AFSDeleteResult, AFSEntry, AFSExecResult, AFSListResult, AFSModuleLoadParams, AFSStatResult, AFSWriteEntryPayload, AFSWriteResult, RouteContext } from "@aigne/afs";
2
- import * as zod0 from "zod";
1
+ import { AFSAccessMode, AFSBaseProvider, AFSDeleteResult, AFSEntry, AFSExecResult, AFSExplainResult, AFSListResult, AFSModuleLoadParams, AFSSearchResult, AFSStatResult, AFSWriteEntryPayload, AFSWriteResult, ProviderManifest, RouteContext } from "@aigne/afs";
3
2
  import { z } from "zod";
4
3
 
5
4
  //#region src/types.d.ts
@@ -73,74 +72,54 @@ declare class AFSGCS extends AFSBaseProvider {
73
72
  private bucket;
74
73
  private listCache?;
75
74
  private statCache?;
76
- constructor(options: AFSGCSOptions);
75
+ constructor(options: AFSGCSOptions & {
76
+ uri?: string;
77
+ token?: string;
78
+ auth?: unknown;
79
+ });
77
80
  /**
78
81
  * Schema for configuration validation
79
82
  */
80
- static schema(): zod0.ZodEffects<zod0.ZodObject<{
81
- name: zod0.ZodType<string | undefined, zod0.ZodTypeDef, string | undefined>;
82
- description: zod0.ZodType<string | undefined, zod0.ZodTypeDef, string | undefined>;
83
- bucket: zod0.ZodEffects<zod0.ZodString, string, string>;
84
- prefix: zod0.ZodType<string | undefined, zod0.ZodTypeDef, string | undefined>;
85
- projectId: zod0.ZodType<string | undefined, zod0.ZodTypeDef, string | undefined>;
86
- accessMode: zod0.ZodType<"readonly" | "readwrite" | undefined, zod0.ZodTypeDef, "readonly" | "readwrite" | undefined>;
87
- endpoint: zod0.ZodType<string | undefined, zod0.ZodTypeDef, string | undefined>;
88
- keyFilename: zod0.ZodType<string | undefined, zod0.ZodTypeDef, string | undefined>;
89
- credentials: zod0.ZodType<{
90
- clientEmail: string;
91
- privateKey: string;
92
- } | undefined, zod0.ZodTypeDef, {
93
- clientEmail: string;
94
- privateKey: string;
95
- } | undefined>;
96
- cacheTtl: zod0.ZodType<number | undefined, zod0.ZodTypeDef, number | undefined>;
97
- }, "strict", zod0.ZodTypeAny, {
98
- bucket: string;
99
- name?: string | undefined;
100
- description?: string | undefined;
101
- prefix?: string | undefined;
102
- projectId?: string | undefined;
103
- accessMode?: "readonly" | "readwrite" | undefined;
104
- endpoint?: string | undefined;
105
- keyFilename?: string | undefined;
106
- credentials?: {
107
- clientEmail: string;
108
- privateKey: string;
109
- } | undefined;
110
- cacheTtl?: number | undefined;
111
- }, {
83
+ static schema(): z.ZodType<{
84
+ name: string | undefined;
85
+ description: string | undefined;
112
86
  bucket: string;
113
- name?: string | undefined;
114
- description?: string | undefined;
115
- prefix?: string | undefined;
116
- projectId?: string | undefined;
117
- accessMode?: "readonly" | "readwrite" | undefined;
118
- endpoint?: string | undefined;
119
- keyFilename?: string | undefined;
120
- credentials?: {
87
+ prefix: string | undefined;
88
+ projectId: string | undefined;
89
+ accessMode: "readonly" | "readwrite" | undefined;
90
+ endpoint: string | undefined;
91
+ keyFilename: string | undefined;
92
+ credentials: {
121
93
  clientEmail: string;
122
94
  privateKey: string;
123
95
  } | undefined;
124
- cacheTtl?: number | undefined;
125
- }>, {
96
+ cacheTtl: number | undefined;
97
+ }, unknown, z.core.$ZodTypeInternals<{
98
+ name: string | undefined;
99
+ description: string | undefined;
126
100
  bucket: string;
127
- name?: string | undefined;
128
- description?: string | undefined;
129
- prefix?: string | undefined;
130
- projectId?: string | undefined;
131
- accessMode?: "readonly" | "readwrite" | undefined;
132
- endpoint?: string | undefined;
133
- keyFilename?: string | undefined;
134
- credentials?: {
101
+ prefix: string | undefined;
102
+ projectId: string | undefined;
103
+ accessMode: "readonly" | "readwrite" | undefined;
104
+ endpoint: string | undefined;
105
+ keyFilename: string | undefined;
106
+ credentials: {
135
107
  clientEmail: string;
136
108
  privateKey: string;
137
109
  } | undefined;
138
- cacheTtl?: number | undefined;
139
- }, any>;
110
+ cacheTtl: number | undefined;
111
+ }, unknown>>;
112
+ /**
113
+ * Provider manifest for URI-based discovery
114
+ */
115
+ static manifest(): ProviderManifest;
140
116
  /**
141
117
  * Load from configuration file
142
118
  */
143
- static load(params: AFSModuleLoadParams): Promise<AFSGCS>;
119
+ static load({
120
+ basePath,
121
+ config
122
+ }?: AFSModuleLoadParams): Promise<AFSGCS>;
144
123
  /**
145
124
  * Build the full GCS key from a path
146
125
  */
@@ -201,46 +180,14 @@ declare class AFSGCS extends AFSBaseProvider {
201
180
  rewriteActionHandler(ctx: RouteContext<{
202
181
  path: string;
203
182
  }>, args: Record<string, unknown>): Promise<AFSExecResult>;
204
- /**
205
- * Generate a signed URL for downloading an object
206
- * @deprecated Use action /.actions/sign-download instead
207
- */
208
- getSignedDownloadUrl(path: string, options?: {
209
- expiresIn?: number;
210
- }): Promise<string>;
211
- /**
212
- * Generate a signed URL for uploading an object
213
- * @deprecated Use action /.actions/sign-upload instead
214
- */
215
- getSignedUploadUrl(path: string, options?: {
216
- expiresIn?: number;
217
- contentType?: string;
218
- }): Promise<string>;
219
- /**
220
- * List all versions (generations) of an object
221
- * @deprecated Use list on /:path/@versions instead
222
- */
223
- listVersions(path: string): Promise<Array<{
224
- generation: string;
225
- isLive: boolean;
226
- timeCreated?: Date;
227
- size: number;
228
- etag?: string;
229
- }>>;
230
- /**
231
- * Read a specific version (generation) of an object
232
- * @deprecated Use read on /:path/@versions/:generation instead
233
- */
234
- readVersion(path: string, generation: string): Promise<{
235
- content: string;
236
- metadata: Record<string, unknown>;
237
- }>;
238
- /**
239
- * Create a directory marker
240
- * @deprecated Use write with empty content instead
241
- */
242
- mkdir(path: string): Promise<void>;
183
+ explainHandler(ctx: RouteContext<{
184
+ path?: string;
185
+ }>): Promise<AFSExplainResult>;
186
+ searchHandler(ctx: RouteContext<{
187
+ path?: string;
188
+ }>, query: string): Promise<AFSSearchResult>;
189
+ readCapabilities(_ctx: RouteContext): Promise<AFSEntry>;
243
190
  }
244
191
  //#endregion
245
- export { AFSGCS, type AFSGCSOptions, type ParsedGCSUri };
192
+ export { AFSGCS, AFSGCS as default, type AFSGCSOptions, type ParsedGCSUri };
246
193
  //# sourceMappingURL=index.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/types.ts","../src/gcs-afs.ts"],"mappings":"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"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/types.ts","../src/gcs-afs.ts"],"mappings":"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"}
package/dist/index.mjs CHANGED
@@ -1,7 +1,8 @@
1
- import { AFSBaseProvider, AFSError, AFSNotFoundError, Actions, Delete, List, Meta, Read, Stat, Write } from "@aigne/afs";
1
+ import { AFSBaseProvider, AFSError, AFSNotFoundError, Actions, Delete, Explain, List, Meta, Read, Search, Stat, Write } from "@aigne/afs";
2
2
  import { camelize, optionalize, zodParse } from "@aigne/afs/utils/zod";
3
- import { Storage } from "@google-cloud/storage";
3
+ import { joinURL } from "ufo";
4
4
  import { z } from "zod";
5
+ import { Storage } from "@google-cloud/storage";
5
6
 
6
7
  //#region src/cache.ts
7
8
  /**
@@ -319,7 +320,8 @@ var AFSGCS = class AFSGCS extends AFSBaseProvider {
319
320
  statCache;
320
321
  constructor(options) {
321
322
  super();
322
- const parsed = afsgcsOptionsSchema.parse(options);
323
+ const { uri: _uri, token: _token, auth: _auth, ...cleanOptions } = options;
324
+ const parsed = afsgcsOptionsSchema.parse(cleanOptions);
323
325
  this.options = {
324
326
  ...parsed,
325
327
  bucket: parsed.bucket,
@@ -343,10 +345,33 @@ var AFSGCS = class AFSGCS extends AFSBaseProvider {
343
345
  return afsgcsOptionsSchema;
344
346
  }
345
347
  /**
348
+ * Provider manifest for URI-based discovery
349
+ */
350
+ static manifest() {
351
+ return {
352
+ name: "gcs",
353
+ description: "Google Cloud Storage",
354
+ uriTemplate: "gcs://{bucket}/{prefix+?}",
355
+ category: "cloud-storage",
356
+ schema: z.object({
357
+ bucket: z.string(),
358
+ prefix: z.string().optional(),
359
+ projectId: z.string().optional(),
360
+ keyFilename: z.string().optional()
361
+ }),
362
+ tags: [
363
+ "gcp",
364
+ "gcs",
365
+ "cloud",
366
+ "storage"
367
+ ]
368
+ };
369
+ }
370
+ /**
346
371
  * Load from configuration file
347
372
  */
348
- static async load(params) {
349
- return new AFSGCS(zodParse(afsgcsOptionsSchema, params.parsed, { prefix: params.filepath }));
373
+ static async load({ basePath, config } = {}) {
374
+ return new AFSGCS(zodParse(afsgcsOptionsSchema, config, { prefix: basePath }));
350
375
  }
351
376
  /**
352
377
  * Build the full GCS key from a path
@@ -359,7 +384,8 @@ var AFSGCS = class AFSGCS extends AFSBaseProvider {
359
384
  * Generate a unique ID for a GCS object
360
385
  */
361
386
  generateId(key) {
362
- return `gs://${this.options.bucket}/${key}`;
387
+ const cleanKey = key.replace(/^\/+/, "");
388
+ return `gcs://${this.options.bucket}/${cleanKey}`;
363
389
  }
364
390
  /**
365
391
  * Invalidate caches for a given path
@@ -423,14 +449,12 @@ var AFSGCS = class AFSGCS extends AFSBaseProvider {
423
449
  if (!dirPrefix) continue;
424
450
  const dirName = dirPrefix.slice(prefix.length).replace(/\/$/, "");
425
451
  if (!dirName) continue;
426
- const entryPath = basePath ? `${basePath}/${dirName}` : dirName;
427
- const normalizedPath = entryPath.startsWith("/") ? entryPath : `/${entryPath}`;
428
452
  childEntries.push({
429
453
  id: this.generateId(dirPrefix),
430
- path: normalizedPath,
431
- metadata: {
454
+ path: joinURL("/", basePath, dirName),
455
+ meta: {
432
456
  kind: "afs:node",
433
- childrenCount: void 0,
457
+ childrenCount: -1,
434
458
  platformRef: generatePlatformRef(bucketName, dirPrefix, true)
435
459
  }
436
460
  });
@@ -442,15 +466,13 @@ var AFSGCS = class AFSGCS extends AFSBaseProvider {
442
466
  if (file.name.endsWith("/")) {
443
467
  const dirName = file.name.slice(prefix.length).replace(/\/$/, "");
444
468
  if (!dirName) continue;
445
- const entryPath$1 = basePath ? `${basePath}/${dirName}` : dirName;
446
- const normalizedPath$1 = entryPath$1.startsWith("/") ? entryPath$1 : `/${entryPath$1}`;
447
469
  childEntries.push({
448
470
  id: this.generateId(file.name),
449
- path: normalizedPath$1,
471
+ path: joinURL("/", basePath, dirName),
450
472
  updatedAt: file.metadata.updated ? new Date(file.metadata.updated) : void 0,
451
- metadata: {
473
+ meta: {
452
474
  kind: "afs:node",
453
- childrenCount: void 0,
475
+ childrenCount: -1,
454
476
  platformRef: generatePlatformRef(bucketName, file.name, true)
455
477
  }
456
478
  });
@@ -459,13 +481,11 @@ var AFSGCS = class AFSGCS extends AFSBaseProvider {
459
481
  }
460
482
  const fileName = file.name.slice(prefix.length);
461
483
  if (!fileName || fileName.includes("/")) continue;
462
- const entryPath = basePath ? `${basePath}/${fileName}` : fileName;
463
- const normalizedPath = entryPath.startsWith("/") ? entryPath : `/${entryPath}`;
464
484
  childEntries.push({
465
485
  id: this.generateId(file.name),
466
- path: normalizedPath,
486
+ path: joinURL("/", basePath, fileName),
467
487
  updatedAt: file.metadata.updated ? new Date(file.metadata.updated) : void 0,
468
- metadata: {
488
+ meta: {
469
489
  size: file.metadata.size ? Number(file.metadata.size) : void 0,
470
490
  contentType: file.metadata.contentType,
471
491
  lastModified: file.metadata.updated,
@@ -479,36 +499,12 @@ var AFSGCS = class AFSGCS extends AFSBaseProvider {
479
499
  const selfPath = basePath ? basePath.startsWith("/") ? basePath : `/${basePath}` : "/";
480
500
  if (childEntries.length === 0 && basePath) {
481
501
  const key = this.options.prefix ? `${this.options.prefix}/${basePath}` : basePath;
482
- const file = this.bucket.file(key);
483
- const [fileExists] = await file.exists();
484
- if (fileExists) {
485
- const [metadata] = await file.getMetadata();
486
- return { data: [{
487
- id: this.generateId(key),
488
- path: selfPath,
489
- updatedAt: metadata.updated ? new Date(metadata.updated) : void 0,
490
- metadata: {
491
- size: metadata.size ? Number(metadata.size) : void 0,
492
- contentType: metadata.contentType,
493
- lastModified: metadata.updated,
494
- etag: metadata.etag,
495
- childrenCount: 0,
496
- platformRef: generatePlatformRef(bucketName, key, false)
497
- }
498
- }] };
499
- }
502
+ const [fileExists] = await this.bucket.file(key).exists();
503
+ if (fileExists) return { data: [] };
500
504
  const [dirExists] = await this.bucket.file(`${key}/`).exists();
501
505
  if (!dirExists) throw new AFSNotFoundError(selfPath);
502
506
  }
503
- return { data: [{
504
- id: this.generateId(prefix || "/"),
505
- path: selfPath,
506
- metadata: {
507
- kind: "afs:node",
508
- childrenCount: childEntries.length,
509
- platformRef: generatePlatformRef(bucketName, prefix, true)
510
- }
511
- }, ...childEntries] };
507
+ return { data: childEntries };
512
508
  }
513
509
  async listVersionsHandler(ctx) {
514
510
  try {
@@ -523,13 +519,13 @@ var AFSGCS = class AFSGCS extends AFSBaseProvider {
523
519
  if (versionFile.name !== key) continue;
524
520
  const generation = versionFile.metadata.generation;
525
521
  if (!generation) continue;
526
- const versionPath = `/${normalizedPath}/@versions/${generation}`;
522
+ const versionPath = joinURL("/", normalizedPath, "@versions", String(generation));
527
523
  const isLive = !versionFile.metadata.timeDeleted;
528
524
  entries.push({
529
525
  id: `${this.generateId(key)}:${generation}`,
530
526
  path: versionPath,
531
527
  updatedAt: versionFile.metadata.timeCreated ? new Date(versionFile.metadata.timeCreated) : void 0,
532
- metadata: {
528
+ meta: {
533
529
  generation,
534
530
  isLive,
535
531
  timeCreated: versionFile.metadata.timeCreated,
@@ -559,7 +555,7 @@ var AFSGCS = class AFSGCS extends AFSBaseProvider {
559
555
  id: this.generateId("/"),
560
556
  path: "/",
561
557
  content: "",
562
- metadata: {
558
+ meta: {
563
559
  kind: "afs:node",
564
560
  childrenCount,
565
561
  platformRef: generatePlatformRef(bucketName, "", true)
@@ -575,9 +571,9 @@ var AFSGCS = class AFSGCS extends AFSBaseProvider {
575
571
  path: normalizedOutputPath,
576
572
  content: "",
577
573
  updatedAt: metadata.updated ? new Date(metadata.updated) : void 0,
578
- metadata: {
574
+ meta: {
579
575
  kind: "afs:node",
580
- childrenCount: void 0,
576
+ childrenCount: -1,
581
577
  platformRef: generatePlatformRef(bucketName, key, true)
582
578
  }
583
579
  };
@@ -587,7 +583,7 @@ var AFSGCS = class AFSGCS extends AFSBaseProvider {
587
583
  path: normalizedOutputPath,
588
584
  content: content.toString("utf-8"),
589
585
  updatedAt: metadata.updated ? new Date(metadata.updated) : void 0,
590
- metadata: {
586
+ meta: {
591
587
  size: metadata.size ? Number(metadata.size) : void 0,
592
588
  mimeType: metadata.contentType,
593
589
  contentType: metadata.contentType,
@@ -608,7 +604,7 @@ var AFSGCS = class AFSGCS extends AFSBaseProvider {
608
604
  id: this.generateId(`${key}/`),
609
605
  path: normalizedOutputPath,
610
606
  content: "",
611
- metadata: {
607
+ meta: {
612
608
  kind: "afs:node",
613
609
  childrenCount,
614
610
  platformRef: generatePlatformRef(bucketName, key, true)
@@ -624,9 +620,9 @@ var AFSGCS = class AFSGCS extends AFSBaseProvider {
624
620
  path: normalizedOutputPath,
625
621
  content: "",
626
622
  updatedAt: dirMetadata.updated ? new Date(dirMetadata.updated) : void 0,
627
- metadata: {
623
+ meta: {
628
624
  kind: "afs:node",
629
- childrenCount: void 0,
625
+ childrenCount: -1,
630
626
  platformRef: generatePlatformRef(bucketName, key, true)
631
627
  }
632
628
  };
@@ -652,7 +648,7 @@ var AFSGCS = class AFSGCS extends AFSBaseProvider {
652
648
  path: ctx.path,
653
649
  content: content.toString("utf-8"),
654
650
  updatedAt: metadata.timeCreated ? new Date(metadata.timeCreated) : void 0,
655
- metadata: {
651
+ meta: {
656
652
  size: metadata.size ? Number(metadata.size) : void 0,
657
653
  contentType: metadata.contentType,
658
654
  timeCreated: metadata.timeCreated,
@@ -681,7 +677,7 @@ var AFSGCS = class AFSGCS extends AFSBaseProvider {
681
677
  return {
682
678
  id: this.generateId("/"),
683
679
  path: "/.meta",
684
- metadata: {
680
+ meta: {
685
681
  kind: "afs:node",
686
682
  childrenCount,
687
683
  platformRef: generatePlatformRef(bucketName, "", true)
@@ -694,7 +690,7 @@ var AFSGCS = class AFSGCS extends AFSBaseProvider {
694
690
  if (cached) return {
695
691
  id: cached.id,
696
692
  path: ctx.path,
697
- metadata: cached.metadata
693
+ meta: cached.meta
698
694
  };
699
695
  }
700
696
  const file = this.bucket.file(key);
@@ -705,9 +701,9 @@ var AFSGCS = class AFSGCS extends AFSBaseProvider {
705
701
  id: this.generateId(key),
706
702
  path: ctx.path,
707
703
  updatedAt: metadata.updated ? new Date(metadata.updated) : void 0,
708
- metadata: {
704
+ meta: {
709
705
  kind: "afs:node",
710
- childrenCount: void 0,
706
+ childrenCount: -1,
711
707
  platformRef: generatePlatformRef(bucketName, key, true)
712
708
  }
713
709
  };
@@ -715,7 +711,7 @@ var AFSGCS = class AFSGCS extends AFSBaseProvider {
715
711
  id: this.generateId(key),
716
712
  path: ctx.path,
717
713
  updatedAt: metadata.updated ? new Date(metadata.updated) : void 0,
718
- metadata: {
714
+ meta: {
719
715
  kind: "afs:document",
720
716
  size: metadata.size ? Number(metadata.size) : void 0,
721
717
  contentType: metadata.contentType,
@@ -742,9 +738,9 @@ var AFSGCS = class AFSGCS extends AFSBaseProvider {
742
738
  if (files.length > 0) return {
743
739
  id: this.generateId(`${key}/`),
744
740
  path: ctx.path,
745
- metadata: {
741
+ meta: {
746
742
  kind: "afs:node",
747
- childrenCount: void 0,
743
+ childrenCount: -1,
748
744
  platformRef: generatePlatformRef(bucketName, key, true)
749
745
  }
750
746
  };
@@ -756,9 +752,9 @@ var AFSGCS = class AFSGCS extends AFSBaseProvider {
756
752
  id: this.generateId(`${key}/`),
757
753
  path: ctx.path,
758
754
  updatedAt: dirMetadata.updated ? new Date(dirMetadata.updated) : void 0,
759
- metadata: {
755
+ meta: {
760
756
  kind: "afs:node",
761
- childrenCount: void 0,
757
+ childrenCount: -1,
762
758
  platformRef: generatePlatformRef(bucketName, key, true)
763
759
  }
764
760
  };
@@ -774,11 +770,11 @@ var AFSGCS = class AFSGCS extends AFSBaseProvider {
774
770
  ...ctx,
775
771
  path: ctx.path.endsWith("/.meta") ? ctx.path : `${ctx.path}/.meta`
776
772
  });
773
+ const pathSegments = ctx.path.split("/").filter(Boolean);
777
774
  return { data: {
775
+ id: pathSegments.length > 0 ? pathSegments[pathSegments.length - 1] : "/",
778
776
  path: ctx.path,
779
- size: metaEntry.metadata?.size,
780
- childrenCount: metaEntry.metadata?.childrenCount,
781
- meta: metaEntry.metadata
777
+ meta: metaEntry.meta
782
778
  } };
783
779
  }
784
780
  async writeHandler(ctx, payload) {
@@ -791,7 +787,7 @@ var AFSGCS = class AFSGCS extends AFSBaseProvider {
791
787
  else if (payload.content !== void 0) content = JSON.stringify(payload.content);
792
788
  else content = "";
793
789
  const saveOptions = { validation: false };
794
- if (payload.metadata?.mimeType || payload.metadata?.contentType) saveOptions.contentType = payload.metadata.mimeType ?? payload.metadata.contentType;
790
+ if (payload.meta?.mimeType || payload.meta?.contentType) saveOptions.contentType = payload.meta.mimeType ?? payload.meta.contentType;
795
791
  await file.save(content, saveOptions);
796
792
  const [metadata] = await file.getMetadata();
797
793
  const normalizedOutputPath = ctx.path.startsWith("/") ? ctx.path : `/${ctx.path}`;
@@ -801,11 +797,11 @@ var AFSGCS = class AFSGCS extends AFSBaseProvider {
801
797
  path: normalizedOutputPath,
802
798
  content: payload.content,
803
799
  updatedAt: metadata.updated ? new Date(metadata.updated) : /* @__PURE__ */ new Date(),
804
- metadata: {
800
+ meta: {
805
801
  size: metadata.size ? Number(metadata.size) : 0,
806
802
  etag: metadata.etag,
807
803
  generation: metadata.generation,
808
- ...payload.metadata
804
+ ...payload.meta
809
805
  }
810
806
  } };
811
807
  } catch (error) {
@@ -834,42 +830,88 @@ var AFSGCS = class AFSGCS extends AFSBaseProvider {
834
830
  }
835
831
  }
836
832
  async listActionsHandler(ctx) {
837
- const basePath = ctx.path.replace(/\/\.actions$/, "");
838
833
  return { data: [
839
834
  {
840
835
  id: "presign-download",
841
- path: `${basePath}/.actions/presign-download`,
836
+ path: joinURL(ctx.path, "presign-download"),
842
837
  summary: "Generate signed download URL",
843
- metadata: {
838
+ meta: {
844
839
  kind: "afs:executable",
845
- kinds: ["afs:executable", "afs:node"]
840
+ kinds: ["afs:executable", "afs:node"],
841
+ inputSchema: {
842
+ type: "object",
843
+ properties: { expiresIn: {
844
+ type: "number",
845
+ description: "Expiration in seconds (default: 3600, max: 604800)"
846
+ } }
847
+ }
846
848
  }
847
849
  },
848
850
  {
849
851
  id: "presign-upload",
850
- path: `${basePath}/.actions/presign-upload`,
852
+ path: joinURL(ctx.path, "presign-upload"),
851
853
  summary: "Generate signed upload URL",
852
- metadata: {
854
+ meta: {
853
855
  kind: "afs:executable",
854
- kinds: ["afs:executable", "afs:node"]
856
+ kinds: ["afs:executable", "afs:node"],
857
+ inputSchema: {
858
+ type: "object",
859
+ properties: {
860
+ expiresIn: {
861
+ type: "number",
862
+ description: "Expiration in seconds"
863
+ },
864
+ contentType: {
865
+ type: "string",
866
+ description: "Content-Type for upload"
867
+ }
868
+ }
869
+ }
855
870
  }
856
871
  },
857
872
  {
858
873
  id: "compose",
859
- path: `${basePath}/.actions/compose`,
874
+ path: joinURL(ctx.path, "compose"),
860
875
  summary: "Compose multiple objects into one",
861
- metadata: {
876
+ meta: {
862
877
  kind: "afs:executable",
863
- kinds: ["afs:executable", "afs:node"]
878
+ kinds: ["afs:executable", "afs:node"],
879
+ inputSchema: {
880
+ type: "object",
881
+ properties: { sources: {
882
+ type: "array",
883
+ description: "Array of source paths (2-32)",
884
+ items: { type: "string" }
885
+ } },
886
+ required: ["sources"]
887
+ }
864
888
  }
865
889
  },
866
890
  {
867
891
  id: "rewrite",
868
- path: `${basePath}/.actions/rewrite`,
892
+ path: joinURL(ctx.path, "rewrite"),
869
893
  summary: "Rewrite object to new location",
870
- metadata: {
894
+ meta: {
871
895
  kind: "afs:executable",
872
- kinds: ["afs:executable", "afs:node"]
896
+ kinds: ["afs:executable", "afs:node"],
897
+ inputSchema: {
898
+ type: "object",
899
+ properties: {
900
+ destination: {
901
+ type: "string",
902
+ description: "Destination path"
903
+ },
904
+ storageClass: {
905
+ type: "string",
906
+ description: "Target storage class"
907
+ },
908
+ contentType: {
909
+ type: "string",
910
+ description: "Override content type"
911
+ }
912
+ },
913
+ required: ["destination"]
914
+ }
873
915
  }
874
916
  }
875
917
  ] };
@@ -966,74 +1008,180 @@ var AFSGCS = class AFSGCS extends AFSBaseProvider {
966
1008
  }
967
1009
  };
968
1010
  }
969
- /**
970
- * Generate a signed URL for downloading an object
971
- * @deprecated Use action /.actions/sign-download instead
972
- */
973
- async getSignedDownloadUrl(path, options) {
974
- return (await this.signDownloadActionHandler({
975
- path: `/${path}`,
976
- params: { path },
977
- options: {}
978
- }, { expiresIn: options?.expiresIn })).data.url;
979
- }
980
- /**
981
- * Generate a signed URL for uploading an object
982
- * @deprecated Use action /.actions/sign-upload instead
983
- */
984
- async getSignedUploadUrl(path, options) {
985
- return (await this.signUploadActionHandler({
986
- path: `/${path}`,
987
- params: { path },
988
- options: {}
989
- }, {
990
- expiresIn: options?.expiresIn,
991
- contentType: options?.contentType
992
- })).data.url;
993
- }
994
- /**
995
- * List all versions (generations) of an object
996
- * @deprecated Use list on /:path/@versions instead
997
- */
998
- async listVersions(path) {
999
- return (await this.listVersionsHandler({
1000
- path: `/${path}/@versions`,
1001
- params: { path },
1002
- options: {}
1003
- })).data.map((entry) => ({
1004
- generation: entry.metadata?.generation,
1005
- isLive: entry.metadata?.isLive,
1006
- timeCreated: entry.updatedAt,
1007
- size: entry.metadata?.size ?? 0,
1008
- etag: entry.metadata?.etag
1009
- }));
1010
- }
1011
- /**
1012
- * Read a specific version (generation) of an object
1013
- * @deprecated Use read on /:path/@versions/:generation instead
1014
- */
1015
- async readVersion(path, generation) {
1016
- const result = await this.readVersionHandler({
1017
- path: `/${path}/@versions/${generation}`,
1018
- params: {
1019
- path,
1020
- generation
1021
- },
1022
- options: {}
1011
+ async explainHandler(ctx) {
1012
+ const normalizedPath = (ctx.params.path ?? "").replace(/^\/+/, "").replace(/\/+$/, "");
1013
+ if (!normalizedPath) {
1014
+ const [files$1, , response$1] = await this.bucket.getFiles({
1015
+ prefix: this.options.prefix ? `${this.options.prefix}/` : void 0,
1016
+ delimiter: "/",
1017
+ maxResults: 1e3
1018
+ });
1019
+ const objectCount$1 = files$1.length;
1020
+ const prefixCount$1 = response$1?.prefixes?.length ?? 0;
1021
+ const lines$1 = [];
1022
+ lines$1.push(`# ${this.options.bucket}`);
1023
+ lines$1.push("");
1024
+ lines$1.push(`- **Type**: GCS Bucket`);
1025
+ lines$1.push(`- **Bucket**: ${this.options.bucket}`);
1026
+ if (this.options.prefix) lines$1.push(`- **Prefix**: ${this.options.prefix}`);
1027
+ if (this.options.projectId) lines$1.push(`- **Project**: ${this.options.projectId}`);
1028
+ lines$1.push(`- **Access Mode**: ${this.accessMode}`);
1029
+ lines$1.push(`- **Top-level Objects**: ${objectCount$1}`);
1030
+ lines$1.push(`- **Top-level Prefixes**: ${prefixCount$1}`);
1031
+ return {
1032
+ format: "markdown",
1033
+ content: lines$1.join("\n")
1034
+ };
1035
+ }
1036
+ const key = this.buildGCSKey(normalizedPath);
1037
+ const file = this.bucket.file(key);
1038
+ const [exists] = await file.exists();
1039
+ if (exists) {
1040
+ const [metadata] = await file.getMetadata();
1041
+ const lines$1 = [];
1042
+ lines$1.push(`# ${normalizedPath}`);
1043
+ lines$1.push("");
1044
+ lines$1.push(`- **Type**: Object`);
1045
+ lines$1.push(`- **Key**: ${key}`);
1046
+ lines$1.push(`- **Size**: ${metadata.size ?? 0} bytes`);
1047
+ if (metadata.contentType) lines$1.push(`- **Content-Type**: ${metadata.contentType}`);
1048
+ if (metadata.storageClass) lines$1.push(`- **Storage Class**: ${metadata.storageClass}`);
1049
+ if (metadata.updated) lines$1.push(`- **Last Modified**: ${metadata.updated}`);
1050
+ if (metadata.etag) lines$1.push(`- **ETag**: ${metadata.etag}`);
1051
+ if (metadata.generation) lines$1.push(`- **Generation**: ${metadata.generation}`);
1052
+ return {
1053
+ format: "markdown",
1054
+ content: lines$1.join("\n")
1055
+ };
1056
+ }
1057
+ const prefix = key.endsWith("/") ? key : `${key}/`;
1058
+ const [files, , response] = await this.bucket.getFiles({
1059
+ prefix,
1060
+ delimiter: "/",
1061
+ maxResults: 1e3
1023
1062
  });
1063
+ const objectCount = files.length;
1064
+ const prefixCount = response?.prefixes?.length ?? 0;
1065
+ if (objectCount === 0 && prefixCount === 0) throw new AFSNotFoundError(`/${normalizedPath}`, `Path not found: ${normalizedPath}`);
1066
+ const lines = [];
1067
+ lines.push(`# ${normalizedPath}/`);
1068
+ lines.push("");
1069
+ lines.push(`- **Type**: Prefix (directory)`);
1070
+ lines.push(`- **Prefix**: ${prefix}`);
1071
+ lines.push(`- **Objects**: ${objectCount}`);
1072
+ lines.push(`- **Sub-prefixes**: ${prefixCount}`);
1024
1073
  return {
1025
- content: result.content,
1026
- metadata: result.metadata
1074
+ format: "markdown",
1075
+ content: lines.join("\n")
1027
1076
  };
1028
1077
  }
1029
- /**
1030
- * Create a directory marker
1031
- * @deprecated Use write with empty content instead
1032
- */
1033
- async mkdir(path) {
1034
- const key = this.buildGCSKey(path);
1035
- const dirKey = key.endsWith("/") ? key : `${key}/`;
1036
- await this.bucket.file(dirKey).save("", { contentType: "application/x-directory" });
1078
+ async searchHandler(ctx, query) {
1079
+ const { minimatch } = await import("minimatch");
1080
+ const normalizedPath = (ctx.params.path ?? "").replace(/^\/+/, "").replace(/\/+$/, "");
1081
+ const prefix = normalizedPath ? this.options.prefix ? `${this.options.prefix}/${normalizedPath}/` : `${normalizedPath}/` : this.options.prefix ? `${this.options.prefix}/` : "";
1082
+ const [files] = await this.bucket.getFiles({ prefix: prefix || void 0 });
1083
+ const results = [];
1084
+ for (const file of files) {
1085
+ const relativePath = prefix ? file.name.slice(prefix.length) : file.name;
1086
+ if (!relativePath) continue;
1087
+ if (minimatch(relativePath, query)) {
1088
+ const displayPath = joinURL("/", normalizedPath, relativePath);
1089
+ results.push({
1090
+ id: this.generateId(file.name),
1091
+ path: displayPath,
1092
+ meta: {
1093
+ size: file.metadata?.size ? Number(file.metadata.size) : void 0,
1094
+ contentType: file.metadata?.contentType,
1095
+ lastModified: file.metadata?.updated
1096
+ }
1097
+ });
1098
+ }
1099
+ }
1100
+ return { data: results };
1101
+ }
1102
+ async readCapabilities(_ctx) {
1103
+ const capabilities = {
1104
+ schemaVersion: 1,
1105
+ provider: "gcs",
1106
+ description: `GCS bucket: ${this.options.bucket}`,
1107
+ tools: [],
1108
+ operations: this.getOperationsDeclaration(),
1109
+ actions: [{
1110
+ description: "GCS object actions",
1111
+ catalog: [
1112
+ {
1113
+ name: "presign-download",
1114
+ description: "Generate a signed download URL",
1115
+ inputSchema: {
1116
+ type: "object",
1117
+ properties: { expiresIn: {
1118
+ type: "number",
1119
+ description: "Expiration in seconds (default: 3600, max: 604800)"
1120
+ } }
1121
+ }
1122
+ },
1123
+ {
1124
+ name: "presign-upload",
1125
+ description: "Generate a signed upload URL",
1126
+ inputSchema: {
1127
+ type: "object",
1128
+ properties: {
1129
+ expiresIn: {
1130
+ type: "number",
1131
+ description: "Expiration in seconds"
1132
+ },
1133
+ contentType: {
1134
+ type: "string",
1135
+ description: "Content-Type for upload"
1136
+ }
1137
+ }
1138
+ }
1139
+ },
1140
+ {
1141
+ name: "compose",
1142
+ description: "Compose multiple objects into one (max 32 sources)",
1143
+ inputSchema: {
1144
+ type: "object",
1145
+ properties: { sources: {
1146
+ type: "array",
1147
+ description: "Array of source paths (2-32)",
1148
+ items: { type: "string" }
1149
+ } },
1150
+ required: ["sources"]
1151
+ }
1152
+ },
1153
+ {
1154
+ name: "rewrite",
1155
+ description: "Copy/rewrite object to a new location",
1156
+ inputSchema: {
1157
+ type: "object",
1158
+ properties: {
1159
+ destination: {
1160
+ type: "string",
1161
+ description: "Destination path"
1162
+ },
1163
+ storageClass: {
1164
+ type: "string",
1165
+ description: "Target storage class"
1166
+ },
1167
+ contentType: {
1168
+ type: "string",
1169
+ description: "Override content type"
1170
+ }
1171
+ },
1172
+ required: ["destination"]
1173
+ }
1174
+ }
1175
+ ],
1176
+ discovery: { pathTemplate: "/{path}/.actions" }
1177
+ }]
1178
+ };
1179
+ return {
1180
+ id: ".capabilities",
1181
+ path: "/.meta/.capabilities",
1182
+ content: JSON.stringify(capabilities, null, 2),
1183
+ meta: { kind: "afs:capabilities" }
1184
+ };
1037
1185
  }
1038
1186
  };
1039
1187
  __decorate([List("/"), List("/:path*")], AFSGCS.prototype, "listHandler", null);
@@ -1049,7 +1197,10 @@ __decorate([Actions.Exec("/:path*", "presign-download")], AFSGCS.prototype, "sig
1049
1197
  __decorate([Actions.Exec("/:path*", "presign-upload")], AFSGCS.prototype, "signUploadActionHandler", null);
1050
1198
  __decorate([Actions.Exec("/:path*", "compose")], AFSGCS.prototype, "composeActionHandler", null);
1051
1199
  __decorate([Actions.Exec("/:path*", "rewrite")], AFSGCS.prototype, "rewriteActionHandler", null);
1200
+ __decorate([Explain("/"), Explain("/:path*")], AFSGCS.prototype, "explainHandler", null);
1201
+ __decorate([Search("/"), Search("/:path*")], AFSGCS.prototype, "searchHandler", null);
1202
+ __decorate([Read("/.meta/.capabilities")], AFSGCS.prototype, "readCapabilities", null);
1052
1203
 
1053
1204
  //#endregion
1054
- export { AFSGCS };
1205
+ export { AFSGCS, AFSGCS as default };
1055
1206
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["AFSError","entryPath","normalizedPath","files","apiResponse"],"sources":["../src/cache.ts","../src/client.ts","../src/errors.ts","../src/platform-ref.ts","../src/types.ts","../src/gcs-afs.ts"],"sourcesContent":["/**\n * GCS Response Caching\n *\n * LRU cache with TTL for GCS list and stat results.\n */\n\n/**\n * Cache entry with expiration\n */\ninterface CacheEntry<T> {\n value: T;\n expiresAt: number;\n}\n\n/**\n * LRU Cache with TTL support\n */\nexport class LRUCache<T> {\n private cache = new Map<string, CacheEntry<T>>();\n private maxSize: number;\n private defaultTtl: number;\n\n /**\n * Create a new LRU cache\n *\n * @param maxSize - Maximum number of entries (default: 1000)\n * @param defaultTtl - Default TTL in seconds (default: 60)\n */\n constructor(maxSize = 1000, defaultTtl = 60) {\n this.maxSize = maxSize;\n this.defaultTtl = defaultTtl;\n }\n\n /**\n * Get a value from the cache\n *\n * @param key - Cache key\n * @returns Cached value or undefined if not found/expired\n */\n get(key: string): T | undefined {\n const entry = this.cache.get(key);\n\n if (!entry) {\n return undefined;\n }\n\n // Check if expired\n if (Date.now() > entry.expiresAt) {\n this.cache.delete(key);\n return undefined;\n }\n\n // Move to end (most recently used)\n this.cache.delete(key);\n this.cache.set(key, entry);\n\n return entry.value;\n }\n\n /**\n * Set a value in the cache\n *\n * @param key - Cache key\n * @param value - Value to cache\n * @param ttl - TTL in seconds (optional, uses default)\n */\n set(key: string, value: T, ttl?: number): void {\n // Remove if already exists (to update position)\n if (this.cache.has(key)) {\n this.cache.delete(key);\n }\n\n // Evict oldest entries if at capacity\n while (this.cache.size >= this.maxSize) {\n const oldestKey = this.cache.keys().next().value;\n if (oldestKey) {\n this.cache.delete(oldestKey);\n }\n }\n\n const expiresAt = Date.now() + (ttl ?? this.defaultTtl) * 1000;\n this.cache.set(key, { value, expiresAt });\n }\n\n /**\n * Delete a value from the cache\n *\n * @param key - Cache key\n */\n delete(key: string): void {\n this.cache.delete(key);\n }\n\n /**\n * Delete all entries matching a prefix\n *\n * @param prefix - Key prefix to match\n */\n deleteByPrefix(prefix: string): void {\n for (const key of this.cache.keys()) {\n if (key.startsWith(prefix)) {\n this.cache.delete(key);\n }\n }\n }\n\n /**\n * Clear all entries\n */\n clear(): void {\n this.cache.clear();\n }\n\n /**\n * Get the number of entries in the cache\n */\n get size(): number {\n return this.cache.size;\n }\n\n /**\n * Prune expired entries\n */\n prune(): void {\n const now = Date.now();\n for (const [key, entry] of this.cache.entries()) {\n if (now > entry.expiresAt) {\n this.cache.delete(key);\n }\n }\n }\n}\n\n/**\n * Create a cache key from bucket, prefix, and path\n */\nexport function createCacheKey(\n bucket: string,\n prefix: string,\n path: string,\n suffix?: string,\n): string {\n const base = `${bucket}:${prefix}:${path}`;\n return suffix ? `${base}:${suffix}` : base;\n}\n","/**\n * GCS Client Factory\n *\n * Creates configured Google Cloud Storage clients.\n */\n\nimport { Storage, type StorageOptions } from \"@google-cloud/storage\";\nimport type { AFSGCSOptions } from \"./types.js\";\n\n/**\n * Create a GCS Storage client from options\n *\n * @param options - AFSGCS options\n * @returns Configured Storage client\n */\nexport function createGCSClient(options: AFSGCSOptions): Storage {\n const storageOptions: StorageOptions = {};\n\n // Project ID\n if (options.projectId) {\n storageOptions.projectId = options.projectId;\n }\n\n // Custom endpoint (for fake-gcs-server)\n if (options.endpoint) {\n storageOptions.apiEndpoint = options.endpoint;\n }\n\n // Key file authentication\n if (options.keyFilename) {\n storageOptions.keyFilename = options.keyFilename;\n }\n\n // Explicit credentials\n if (options.credentials) {\n storageOptions.credentials = {\n client_email: options.credentials.clientEmail,\n private_key: options.credentials.privateKey,\n };\n }\n\n return new Storage(storageOptions);\n}\n","/**\n * GCS Provider Error Handling\n *\n * Maps GCS SDK errors to AFS error types.\n */\n\n/**\n * AFS error codes\n */\nexport const AFSErrorCode = {\n ENTRY_NOT_FOUND: \"ENTRY_NOT_FOUND\",\n MODULE_NOT_FOUND: \"MODULE_NOT_FOUND\",\n PERMISSION_DENIED: \"PERMISSION_DENIED\",\n AUTH_ERROR: \"AUTH_ERROR\",\n RATE_LIMIT_EXCEEDED: \"RATE_LIMIT_EXCEEDED\",\n INVALID_OPERATION: \"INVALID_OPERATION\",\n ALREADY_EXISTS: \"ALREADY_EXISTS\",\n SERVICE_UNAVAILABLE: \"SERVICE_UNAVAILABLE\",\n UNKNOWN: \"UNKNOWN\",\n} as const;\n\nexport type AFSErrorCode = (typeof AFSErrorCode)[keyof typeof AFSErrorCode];\n\n/**\n * AFS Error class\n */\nexport class AFSError extends Error {\n readonly code: AFSErrorCode;\n readonly retryAfter?: number;\n\n constructor(code: AFSErrorCode, message: string, options?: { retryAfter?: number }) {\n super(message);\n this.name = \"AFSError\";\n this.code = code;\n this.retryAfter = options?.retryAfter;\n }\n}\n\n/**\n * Custom GCS error class for internal use\n */\nexport class GCSError extends Error {\n constructor(\n message: string,\n public readonly code: number,\n ) {\n super(message);\n this.name = \"GCSError\";\n }\n}\n\n/**\n * Map GCS HTTP status codes to AFS error codes\n */\nconst STATUS_TO_AFS_ERROR: Record<number, AFSErrorCode> = {\n 400: AFSErrorCode.INVALID_OPERATION,\n 401: AFSErrorCode.AUTH_ERROR,\n 403: AFSErrorCode.PERMISSION_DENIED,\n 404: AFSErrorCode.ENTRY_NOT_FOUND,\n 409: AFSErrorCode.ALREADY_EXISTS,\n 429: AFSErrorCode.RATE_LIMIT_EXCEEDED,\n 503: AFSErrorCode.SERVICE_UNAVAILABLE,\n};\n\n/**\n * Map GCS error to AFS error\n *\n * @param error - GCS SDK error or generic error\n * @returns AFSError with appropriate error code\n */\nexport function mapGCSError(error: unknown): AFSError {\n // Handle GCSError\n if (error instanceof GCSError) {\n const afsCode = STATUS_TO_AFS_ERROR[error.code] ?? AFSErrorCode.UNKNOWN;\n return new AFSError(afsCode, error.message);\n }\n\n // Handle GCS SDK ApiError format (has code property)\n if (typeof error === \"object\" && error !== null && \"code\" in error) {\n const err = error as { code: number; message?: string };\n const statusCode = typeof err.code === \"number\" ? err.code : 500;\n const message = err.message ?? \"Unknown GCS error\";\n const afsCode = STATUS_TO_AFS_ERROR[statusCode] ?? AFSErrorCode.UNKNOWN;\n return new AFSError(afsCode, message);\n }\n\n // Handle generic Error\n if (error instanceof Error) {\n return new AFSError(AFSErrorCode.UNKNOWN, error.message);\n }\n\n // Unknown error type\n return new AFSError(AFSErrorCode.UNKNOWN, String(error));\n}\n","/**\n * GCS Platform Reference\n *\n * Generates Google Cloud Console URLs for GCS objects and directories.\n */\n\n/**\n * Platform reference containing console URL\n */\nexport interface GCSPlatformRef {\n consoleUrl: string;\n}\n\n/**\n * Generate platform reference with GCP Console URL\n *\n * @param bucket - GCS bucket name\n * @param prefix - Object prefix/key (without leading slash)\n * @param isDirectory - Whether this is a directory (prefix)\n * @returns Platform reference with console URL\n */\nexport function generatePlatformRef(\n bucket: string,\n prefix: string,\n isDirectory: boolean,\n): GCSPlatformRef {\n // GCS Console URL format:\n // Objects: https://console.cloud.google.com/storage/browser/_details/{bucket}/{path}\n // Folders: https://console.cloud.google.com/storage/browser/{bucket}/{path}\n\n if (isDirectory) {\n // Directory URL\n const normalizedPrefix = prefix.endsWith(\"/\") ? prefix : prefix ? `${prefix}/` : \"\";\n return {\n consoleUrl: `https://console.cloud.google.com/storage/browser/${bucket}/${normalizedPrefix}`,\n };\n }\n\n // File URL\n const encodedPrefix = encodeURIComponent(prefix).replace(/%2F/g, \"/\");\n return {\n consoleUrl: `https://console.cloud.google.com/storage/browser/_details/${bucket}/${encodedPrefix}`,\n };\n}\n","/**\n * AFS GCS Provider Types\n */\n\nimport { camelize, optionalize } from \"@aigne/afs/utils/zod\";\nimport { z } from \"zod\";\n\n/**\n * Configuration options for AFSGCS\n */\nexport interface AFSGCSOptions {\n /** Module name (used as mount path segment) */\n name?: string;\n\n /** Module description */\n description?: string;\n\n /** GCS bucket name */\n bucket: string;\n\n /** Key prefix (optional) */\n prefix?: string;\n\n /** GCP project ID */\n projectId?: string;\n\n /** Access mode */\n accessMode?: \"readonly\" | \"readwrite\";\n\n /** Custom endpoint for GCS-compatible services (fake-gcs-server) */\n endpoint?: string;\n\n /** Path to service account key file */\n keyFilename?: string;\n\n /** Explicit credentials (for programmatic access) */\n credentials?: {\n clientEmail: string;\n privateKey: string;\n };\n\n /** Cache TTL in seconds (0 = no cache) */\n cacheTtl?: number;\n}\n\n/**\n * GCS bucket name validation regex\n * - 3-63 characters\n * - lowercase letters, numbers, hyphens, dots (but not consecutive dots)\n * - must start and end with letter or number\n */\nconst BUCKET_NAME_REGEX = /^[a-z0-9][a-z0-9.-]{1,61}[a-z0-9]$/;\n\n/**\n * Additional validation for bucket names\n */\nfunction isValidBucketName(name: string): boolean {\n // Check basic regex\n if (!BUCKET_NAME_REGEX.test(name)) return false;\n\n // No consecutive dots\n if (name.includes(\"..\")) return false;\n\n // No underscores\n if (name.includes(\"_\")) return false;\n\n return true;\n}\n\n/**\n * Zod schema for options validation\n */\nexport const afsgcsOptionsSchema = camelize(\n z\n .object({\n name: optionalize(z.string()),\n description: optionalize(z.string()),\n bucket: z.string().refine(isValidBucketName, \"Invalid GCS bucket name\"),\n prefix: optionalize(z.string()),\n projectId: optionalize(z.string()),\n accessMode: optionalize(z.enum([\"readonly\", \"readwrite\"])),\n endpoint: optionalize(z.string().url()),\n keyFilename: optionalize(z.string()),\n credentials: optionalize(\n z.object({\n clientEmail: z.string(),\n privateKey: z.string(),\n }),\n ),\n cacheTtl: optionalize(z.number().int().min(0)),\n })\n .strict(),\n);\n\n/**\n * Parsed GCS URI\n */\nexport interface ParsedGCSUri {\n bucket: string;\n prefix: string;\n}\n","/**\n * AFS GCS Provider\n *\n * GCS provider using AFSBaseProvider decorator routing pattern.\n * Provides access to Google Cloud Storage through AFS.\n */\n\nimport {\n Actions,\n type AFSAccessMode,\n AFSBaseProvider,\n type AFSDeleteResult,\n type AFSEntry,\n AFSError,\n type AFSExecResult,\n type AFSListResult,\n type AFSModuleClass,\n type AFSModuleLoadParams,\n AFSNotFoundError,\n type AFSStatResult,\n type AFSWriteEntryPayload,\n type AFSWriteResult,\n Delete,\n List,\n Meta,\n Read,\n type RouteContext,\n Stat,\n Write,\n} from \"@aigne/afs\";\nimport { zodParse } from \"@aigne/afs/utils/zod\";\nimport type { Bucket, Storage } from \"@google-cloud/storage\";\nimport { createCacheKey, LRUCache } from \"./cache.js\";\nimport { createGCSClient } from \"./client.js\";\nimport { mapGCSError } from \"./errors.js\";\nimport { generatePlatformRef } from \"./platform-ref.js\";\nimport { type AFSGCSOptions, afsgcsOptionsSchema } from \"./types.js\";\n\n/**\n * Default URL expiration time (1 hour)\n */\nconst DEFAULT_EXPIRES_IN = 3600;\n\n/**\n * Maximum expiration time (7 days)\n */\nconst MAX_EXPIRES_IN = 604800;\n\n/**\n * Maximum sources for compose operation\n */\nconst MAX_COMPOSE_SOURCES = 32;\n\n/**\n * AFSGCS Provider using Base Provider pattern\n *\n * Provides access to Google Cloud Storage through AFS.\n * Uses decorator routing (@List, @Read, @Write, @Delete, @Meta, @Actions).\n *\n * @example\n * ```typescript\n * const gcs = new AFSGCS({\n * bucket: \"my-bucket\",\n * prefix: \"data\",\n * projectId: \"my-project\",\n * });\n *\n * // Mount to AFS\n * afs.mount(gcs);\n *\n * // List objects\n * const result = await afs.list(\"/modules/my-bucket/data\");\n *\n * // Read object\n * const content = await afs.read(\"/modules/my-bucket/data/file.json\");\n * ```\n */\nexport class AFSGCS extends AFSBaseProvider {\n override readonly name: string;\n override readonly description?: string;\n override readonly accessMode: AFSAccessMode;\n\n private options: Required<Pick<AFSGCSOptions, \"bucket\">> & AFSGCSOptions;\n private storage: Storage;\n private bucket: Bucket;\n private listCache?: LRUCache<AFSListResult>;\n private statCache?: LRUCache<AFSEntry>;\n\n constructor(options: AFSGCSOptions) {\n super();\n\n // Validate options\n const parsed = afsgcsOptionsSchema.parse(options);\n\n this.options = {\n ...parsed,\n bucket: parsed.bucket,\n prefix: parsed.prefix ?? \"\",\n accessMode: parsed.accessMode ?? \"readonly\",\n };\n\n this.name = parsed.name ?? parsed.bucket;\n this.description = parsed.description ?? `GCS bucket: ${parsed.bucket}`;\n this.accessMode = this.options.accessMode ?? \"readonly\";\n\n // Create GCS client\n this.storage = createGCSClient(this.options);\n this.bucket = this.storage.bucket(parsed.bucket);\n\n // Initialize caches if cacheTtl is set\n if (parsed.cacheTtl && parsed.cacheTtl > 0) {\n this.listCache = new LRUCache<AFSListResult>(1000, parsed.cacheTtl);\n this.statCache = new LRUCache<AFSEntry>(5000, parsed.cacheTtl);\n }\n }\n\n /**\n * Schema for configuration validation\n */\n static schema() {\n return afsgcsOptionsSchema;\n }\n\n /**\n * Load from configuration file\n */\n static async load(params: AFSModuleLoadParams): Promise<AFSGCS> {\n const options = zodParse(afsgcsOptionsSchema, params.parsed, { prefix: params.filepath });\n return new AFSGCS(options);\n }\n\n // ========== Helper Methods ==========\n\n /**\n * Build the full GCS key from a path\n */\n private buildGCSKey(path: string): string {\n const normalizedPath = path.replace(/^\\/+/, \"\").replace(/\\/+$/, \"\");\n return this.options.prefix ? `${this.options.prefix}/${normalizedPath}` : normalizedPath;\n }\n\n /**\n * Generate a unique ID for a GCS object\n */\n private generateId(key: string): string {\n return `gs://${this.options.bucket}/${key}`;\n }\n\n /**\n * Invalidate caches for a given path\n */\n private invalidateCache(path: string): void {\n if (this.statCache) {\n const statKey = createCacheKey(this.options.bucket, this.options.prefix ?? \"\", path);\n this.statCache.delete(statKey);\n }\n\n if (this.listCache) {\n // Invalidate list cache for parent directory\n const parentPath = path.split(\"/\").slice(0, -1).join(\"/\") || \"/\";\n const listPrefix = createCacheKey(this.options.bucket, this.options.prefix ?? \"\", parentPath);\n this.listCache.deleteByPrefix(listPrefix);\n }\n }\n\n /**\n * Clear all caches\n */\n clearCache(): void {\n this.listCache?.clear();\n this.statCache?.clear();\n }\n\n // ========== List Operations ==========\n\n @List(\"/\")\n @List(\"/:path*\")\n async listHandler(ctx: RouteContext<{ path?: string }>): Promise<AFSListResult> {\n try {\n const path = ctx.params.path ?? \"\";\n const normalizedPath = path.replace(/^\\/+/, \"\").replace(/\\/+$/, \"\");\n\n // Build the full GCS prefix\n const fullPrefix = this.options.prefix\n ? normalizedPath\n ? `${this.options.prefix}/${normalizedPath}/`\n : `${this.options.prefix}/`\n : normalizedPath\n ? `${normalizedPath}/`\n : \"\";\n\n const maxChildren = (ctx.options as { limit?: number } | undefined)?.limit ?? 1000;\n\n // Check cache first\n if (this.listCache) {\n const cacheKey = createCacheKey(\n this.options.bucket,\n this.options.prefix ?? \"\",\n normalizedPath,\n JSON.stringify(ctx.options ?? {}),\n );\n const cached = this.listCache.get(cacheKey);\n if (cached) {\n return cached;\n }\n }\n\n const result = await this.listWithDelimiter(fullPrefix, normalizedPath, maxChildren);\n\n // Cache the result\n if (this.listCache) {\n const cacheKey = createCacheKey(\n this.options.bucket,\n this.options.prefix ?? \"\",\n normalizedPath,\n JSON.stringify(ctx.options ?? {}),\n );\n this.listCache.set(cacheKey, result);\n\n // Also populate stat cache from list results\n if (this.statCache) {\n for (const entry of result.data) {\n const statKey = createCacheKey(\n this.options.bucket,\n this.options.prefix ?? \"\",\n entry.path,\n );\n this.statCache.set(statKey, entry);\n }\n }\n }\n\n return result;\n } catch (error) {\n if (error instanceof AFSNotFoundError) {\n throw error;\n }\n throw mapGCSError(error);\n }\n }\n\n /**\n * List with delimiter (single level)\n */\n private async listWithDelimiter(\n prefix: string,\n basePath: string,\n maxChildren: number,\n ): Promise<AFSListResult> {\n const childEntries: AFSEntry[] = [];\n const bucketName = this.options.bucket;\n\n const [files, , apiResponse] = await this.bucket.getFiles({\n prefix,\n delimiter: \"/\",\n maxResults: maxChildren,\n });\n\n // Add directories from prefixes\n const prefixes = (apiResponse as Record<string, unknown>)?.prefixes as string[] | undefined;\n if (prefixes) {\n for (const dirPrefix of prefixes) {\n if (!dirPrefix) continue;\n\n // Extract directory name\n const dirName = dirPrefix.slice(prefix.length).replace(/\\/$/, \"\");\n if (!dirName) continue;\n\n const entryPath = basePath ? `${basePath}/${dirName}` : dirName;\n const normalizedPath = entryPath.startsWith(\"/\") ? entryPath : `/${entryPath}`;\n\n childEntries.push({\n id: this.generateId(dirPrefix),\n path: normalizedPath,\n metadata: {\n kind: \"afs:node\",\n childrenCount: undefined,\n platformRef: generatePlatformRef(bucketName, dirPrefix, true),\n },\n });\n\n if (childEntries.length >= maxChildren) break;\n }\n }\n\n // Add files from Contents\n for (const file of files) {\n if (!file.name) continue;\n\n // Skip the prefix itself (if it's a \"directory marker\")\n if (file.name === prefix) continue;\n\n // Handle directory markers (ending with /)\n if (file.name.endsWith(\"/\")) {\n const dirName = file.name.slice(prefix.length).replace(/\\/$/, \"\");\n if (!dirName) continue;\n\n const entryPath = basePath ? `${basePath}/${dirName}` : dirName;\n const normalizedPath = entryPath.startsWith(\"/\") ? entryPath : `/${entryPath}`;\n\n childEntries.push({\n id: this.generateId(file.name),\n path: normalizedPath,\n updatedAt: file.metadata.updated ? new Date(file.metadata.updated as string) : undefined,\n metadata: {\n kind: \"afs:node\",\n childrenCount: undefined,\n platformRef: generatePlatformRef(bucketName, file.name, true),\n },\n });\n\n if (childEntries.length >= maxChildren) break;\n continue;\n }\n\n // Extract file name\n const fileName = file.name.slice(prefix.length);\n if (!fileName || fileName.includes(\"/\")) continue;\n\n const entryPath = basePath ? `${basePath}/${fileName}` : fileName;\n const normalizedPath = entryPath.startsWith(\"/\") ? entryPath : `/${entryPath}`;\n\n childEntries.push({\n id: this.generateId(file.name),\n path: normalizedPath,\n updatedAt: file.metadata.updated ? new Date(file.metadata.updated as string) : undefined,\n metadata: {\n size: file.metadata.size ? Number(file.metadata.size) : undefined,\n contentType: file.metadata.contentType,\n lastModified: file.metadata.updated,\n etag: file.metadata.etag,\n storageClass: file.metadata.storageClass,\n platformRef: generatePlatformRef(bucketName, file.name, false),\n },\n });\n\n if (childEntries.length >= maxChildren) break;\n }\n\n // Build result with self entry first\n const selfPath = basePath ? (basePath.startsWith(\"/\") ? basePath : `/${basePath}`) : \"/\";\n\n // For non-root paths with no children, check if the path exists\n if (childEntries.length === 0 && basePath) {\n // Check if this path exists as a file\n const key = this.options.prefix ? `${this.options.prefix}/${basePath}` : basePath;\n const file = this.bucket.file(key);\n const [fileExists] = await file.exists();\n\n if (fileExists) {\n // Path exists as an object (file)\n const [metadata] = await file.getMetadata();\n return {\n data: [\n {\n id: this.generateId(key),\n path: selfPath,\n updatedAt: metadata.updated ? new Date(metadata.updated as string) : undefined,\n metadata: {\n size: metadata.size ? Number(metadata.size) : undefined,\n contentType: metadata.contentType,\n lastModified: metadata.updated,\n etag: metadata.etag,\n childrenCount: 0,\n platformRef: generatePlatformRef(bucketName, key, false),\n },\n },\n ],\n };\n }\n\n // Check for directory marker\n const dirMarker = this.bucket.file(`${key}/`);\n const [dirExists] = await dirMarker.exists();\n\n if (!dirExists) {\n // Neither file nor directory marker exists\n throw new AFSNotFoundError(selfPath);\n }\n }\n\n // Create self entry (the directory itself)\n const selfEntry: AFSEntry = {\n id: this.generateId(prefix || \"/\"),\n path: selfPath,\n metadata: {\n kind: \"afs:node\",\n childrenCount: childEntries.length,\n platformRef: generatePlatformRef(bucketName, prefix, true),\n },\n };\n\n return { data: [selfEntry, ...childEntries] };\n }\n\n // ========== Versioning List ==========\n\n @List(\"/:path*/@versions\")\n async listVersionsHandler(ctx: RouteContext<{ path: string }>): Promise<AFSListResult> {\n try {\n const normalizedPath = ctx.params.path.replace(/^\\/+/, \"\").replace(/\\/+$/, \"\");\n const key = this.options.prefix ? `${this.options.prefix}/${normalizedPath}` : normalizedPath;\n\n // Get all generations of the file\n const [files] = await this.bucket.getFiles({\n prefix: key,\n versions: true,\n });\n\n const entries: AFSEntry[] = [];\n\n for (const versionFile of files) {\n // Only include exact key matches\n if (versionFile.name !== key) continue;\n\n const generation = versionFile.metadata.generation;\n if (!generation) continue;\n\n const versionPath = `/${normalizedPath}/@versions/${generation}`;\n const isLive = !versionFile.metadata.timeDeleted;\n\n entries.push({\n id: `${this.generateId(key)}:${generation}`,\n path: versionPath,\n updatedAt: versionFile.metadata.timeCreated\n ? new Date(versionFile.metadata.timeCreated as string)\n : undefined,\n metadata: {\n generation: generation,\n isLive,\n timeCreated: versionFile.metadata.timeCreated,\n size: versionFile.metadata.size ? Number(versionFile.metadata.size) : 0,\n etag: versionFile.metadata.etag,\n },\n });\n }\n\n return { data: entries };\n } catch (error) {\n throw mapGCSError(error);\n }\n }\n\n // ========== Read Operations ==========\n\n @Read(\"/:path*\")\n async readHandler(ctx: RouteContext<{ path: string }>): Promise<AFSEntry> {\n try {\n const key = this.buildGCSKey(ctx.params.path);\n const normalizedOutputPath = ctx.path.startsWith(\"/\") ? ctx.path : `/${ctx.path}`;\n const bucketName = this.options.bucket;\n\n // Handle root path - return bucket metadata with childrenCount\n if (!key) {\n const [files, , apiResponse] = await this.bucket.getFiles({\n prefix: this.options.prefix ? `${this.options.prefix}/` : \"\",\n delimiter: \"/\",\n maxResults: 1000,\n });\n const prefixes = (apiResponse as Record<string, unknown>)?.prefixes as string[] | undefined;\n const childrenCount = (prefixes?.length ?? 0) + files.length;\n\n return {\n id: this.generateId(\"/\"),\n path: \"/\",\n content: \"\",\n metadata: {\n kind: \"afs:node\",\n childrenCount,\n platformRef: generatePlatformRef(bucketName, \"\", true),\n },\n };\n }\n\n const file = this.bucket.file(key);\n\n // Check if file exists\n const [exists] = await file.exists();\n\n if (exists) {\n const [metadata] = await file.getMetadata();\n\n // Check if this is a directory marker\n if (key.endsWith(\"/\") || metadata.contentType === \"application/x-directory\") {\n // Return directory info instead of throwing\n return {\n id: this.generateId(key),\n path: normalizedOutputPath,\n content: \"\",\n updatedAt: metadata.updated ? new Date(metadata.updated as string) : undefined,\n metadata: {\n kind: \"afs:node\",\n childrenCount: undefined,\n platformRef: generatePlatformRef(bucketName, key, true),\n },\n };\n }\n\n // Download content\n const [content] = await file.download();\n\n return {\n id: this.generateId(key),\n path: normalizedOutputPath,\n content: content.toString(\"utf-8\"),\n updatedAt: metadata.updated ? new Date(metadata.updated as string) : undefined,\n metadata: {\n size: metadata.size ? Number(metadata.size) : undefined,\n mimeType: metadata.contentType,\n contentType: metadata.contentType,\n lastModified: metadata.updated,\n etag: metadata.etag,\n },\n };\n }\n\n // File doesn't exist, check if it's a directory prefix\n const [files, , apiResponse] = await this.bucket.getFiles({\n prefix: `${key}/`,\n delimiter: \"/\",\n maxResults: 1000,\n });\n const prefixes = (apiResponse as Record<string, unknown>)?.prefixes as string[] | undefined;\n const hasChildren = files.length > 0 || (prefixes && prefixes.length > 0);\n\n if (hasChildren) {\n // It's a directory - return directory info\n const childrenCount = (prefixes?.length ?? 0) + files.length;\n return {\n id: this.generateId(`${key}/`),\n path: normalizedOutputPath,\n content: \"\",\n metadata: {\n kind: \"afs:node\",\n childrenCount,\n platformRef: generatePlatformRef(bucketName, key, true),\n },\n };\n }\n\n // Also check for directory marker (key ending with /)\n const dirMarker = this.bucket.file(`${key}/`);\n const [dirExists] = await dirMarker.exists();\n\n if (dirExists) {\n const [dirMetadata] = await dirMarker.getMetadata();\n return {\n id: this.generateId(`${key}/`),\n path: normalizedOutputPath,\n content: \"\",\n updatedAt: dirMetadata.updated ? new Date(dirMetadata.updated as string) : undefined,\n metadata: {\n kind: \"afs:node\",\n childrenCount: undefined,\n platformRef: generatePlatformRef(bucketName, key, true),\n },\n };\n }\n\n // Neither file nor directory exists\n throw new AFSNotFoundError(`/${ctx.params.path}`);\n } catch (error) {\n if (error instanceof AFSError || error instanceof AFSNotFoundError) {\n throw error;\n }\n throw mapGCSError(error);\n }\n }\n\n // ========== Version Read ==========\n\n @Read(\"/:path*/@versions/:generation\")\n async readVersionHandler(\n ctx: RouteContext<{ path: string; generation: string }>,\n ): Promise<AFSEntry> {\n try {\n const normalizedPath = ctx.params.path.replace(/^\\/+/, \"\").replace(/\\/+$/, \"\");\n const key = this.options.prefix ? `${this.options.prefix}/${normalizedPath}` : normalizedPath;\n const generation = ctx.params.generation;\n\n const file = this.bucket.file(key, { generation: parseInt(generation, 10) });\n\n // Check if version exists\n const [exists] = await file.exists();\n if (!exists) {\n throw new AFSNotFoundError(`/${normalizedPath}/@versions/${generation}`);\n }\n\n const [content] = await file.download();\n const [metadata] = await file.getMetadata();\n\n return {\n id: `${this.generateId(key)}:${generation}`,\n path: ctx.path,\n content: content.toString(\"utf-8\"),\n updatedAt: metadata.timeCreated ? new Date(metadata.timeCreated as string) : undefined,\n metadata: {\n size: metadata.size ? Number(metadata.size) : undefined,\n contentType: metadata.contentType,\n timeCreated: metadata.timeCreated,\n etag: metadata.etag,\n generation: metadata.generation,\n },\n };\n } catch (error) {\n if (error instanceof AFSNotFoundError) {\n throw error;\n }\n throw mapGCSError(error);\n }\n }\n\n // ========== Meta Operations ==========\n\n @Meta(\"/\")\n @Meta(\"/:path*\")\n async metaHandler(ctx: RouteContext<{ path?: string }>): Promise<AFSEntry> {\n try {\n const path = ctx.params.path ?? \"\";\n const normalizedPath = path.replace(/^\\/+/, \"\").replace(/\\/+$/, \"\");\n const key = this.options.prefix\n ? normalizedPath\n ? `${this.options.prefix}/${normalizedPath}`\n : this.options.prefix\n : normalizedPath;\n\n const bucketName = this.options.bucket;\n\n // Root metadata\n if (!key) {\n const [files, , apiResponse] = await this.bucket.getFiles({\n prefix: this.options.prefix ? `${this.options.prefix}/` : \"\",\n delimiter: \"/\",\n maxResults: 1000,\n });\n const prefixes = (apiResponse as Record<string, unknown>)?.prefixes as string[] | undefined;\n const childrenCount = (prefixes?.length ?? 0) + files.length;\n\n return {\n id: this.generateId(\"/\"),\n path: \"/.meta\",\n metadata: {\n kind: \"afs:node\",\n childrenCount,\n platformRef: generatePlatformRef(bucketName, \"\", true),\n },\n };\n }\n\n // Check cache first\n if (this.statCache) {\n const cacheKey = createCacheKey(bucketName, this.options.prefix ?? \"\", path);\n const cached = this.statCache.get(cacheKey);\n if (cached) {\n return {\n id: cached.id,\n path: ctx.path,\n metadata: cached.metadata,\n };\n }\n }\n\n // Try to get the object directly (file case)\n const file = this.bucket.file(key);\n const [exists] = await file.exists();\n\n if (exists) {\n const [metadata] = await file.getMetadata();\n\n // Check if this is a directory marker\n if (key.endsWith(\"/\") || metadata.contentType === \"application/x-directory\") {\n return {\n id: this.generateId(key),\n path: ctx.path,\n updatedAt: metadata.updated ? new Date(metadata.updated as string) : undefined,\n metadata: {\n kind: \"afs:node\",\n childrenCount: undefined,\n platformRef: generatePlatformRef(bucketName, key, true),\n },\n };\n }\n\n const result = {\n id: this.generateId(key),\n path: ctx.path,\n updatedAt: metadata.updated ? new Date(metadata.updated as string) : undefined,\n metadata: {\n kind: \"afs:document\",\n size: metadata.size ? Number(metadata.size) : undefined,\n contentType: metadata.contentType,\n lastModified: metadata.updated,\n etag: metadata.etag,\n storageClass: metadata.storageClass,\n // GCS-specific fields\n generation: metadata.generation,\n metageneration: metadata.metageneration,\n crc32c: metadata.crc32c,\n md5Hash: metadata.md5Hash,\n platformRef: generatePlatformRef(bucketName, key, false),\n },\n };\n\n // Cache the result\n if (this.statCache) {\n const cacheKey = createCacheKey(bucketName, this.options.prefix ?? \"\", path);\n this.statCache.set(cacheKey, result);\n }\n\n return result;\n }\n\n // File doesn't exist, check if it's a directory prefix\n const [files] = await this.bucket.getFiles({\n prefix: `${key}/`,\n maxResults: 1,\n });\n\n if (files.length > 0) {\n // There are objects under this prefix, so it's a directory\n return {\n id: this.generateId(`${key}/`),\n path: ctx.path,\n metadata: {\n kind: \"afs:node\",\n childrenCount: undefined,\n platformRef: generatePlatformRef(bucketName, key, true),\n },\n };\n }\n\n // Also check for directory marker (key ending with /)\n const dirMarker = this.bucket.file(`${key}/`);\n const [dirExists] = await dirMarker.exists();\n\n if (dirExists) {\n const [dirMetadata] = await dirMarker.getMetadata();\n return {\n id: this.generateId(`${key}/`),\n path: ctx.path,\n updatedAt: dirMetadata.updated ? new Date(dirMetadata.updated as string) : undefined,\n metadata: {\n kind: \"afs:node\",\n childrenCount: undefined,\n platformRef: generatePlatformRef(bucketName, key, true),\n },\n };\n }\n\n // Neither file nor directory exists\n throw new AFSNotFoundError(path.startsWith(\"/\") ? path : `/${path}`);\n } catch (error) {\n if (error instanceof AFSNotFoundError) {\n throw error;\n }\n throw mapGCSError(error);\n }\n }\n\n // ========== Stat Operations ==========\n\n @Stat(\"/\")\n @Stat(\"/:path*\")\n async statHandler(ctx: RouteContext<{ path?: string }>): Promise<AFSStatResult> {\n // Delegate to meta handler and convert to stat result\n const metaEntry = await this.metaHandler({\n ...ctx,\n path: ctx.path.endsWith(\"/.meta\") ? ctx.path : `${ctx.path}/.meta`,\n });\n\n return {\n data: {\n path: ctx.path,\n size: metaEntry.metadata?.size as number | undefined,\n childrenCount: metaEntry.metadata?.childrenCount as number | undefined,\n meta: metaEntry.metadata as Record<string, unknown>,\n },\n };\n }\n\n // ========== Write Operations ==========\n\n @Write(\"/:path*\")\n async writeHandler(\n ctx: RouteContext<{ path: string }>,\n payload: AFSWriteEntryPayload,\n ): Promise<AFSWriteResult> {\n try {\n const key = this.buildGCSKey(ctx.params.path);\n const file = this.bucket.file(key);\n\n // Prepare content\n let content: string | Buffer;\n if (typeof payload.content === \"string\") {\n content = payload.content;\n } else if (Buffer.isBuffer(payload.content)) {\n content = payload.content;\n } else if (payload.content !== undefined) {\n // JSON content\n content = JSON.stringify(payload.content);\n } else {\n content = \"\";\n }\n\n // Prepare save options\n // Disable validation for fake-gcs-server compatibility (it doesn't properly support CRC32C)\n const saveOptions: {\n contentType?: string;\n metadata?: Record<string, string>;\n validation?: boolean;\n } = {\n validation: false,\n };\n if (payload.metadata?.mimeType || payload.metadata?.contentType) {\n saveOptions.contentType =\n (payload.metadata.mimeType as string) ?? (payload.metadata.contentType as string);\n }\n\n // Write content\n await file.save(content, saveOptions);\n\n // Get updated metadata\n const [metadata] = await file.getMetadata();\n\n const normalizedOutputPath = ctx.path.startsWith(\"/\") ? ctx.path : `/${ctx.path}`;\n\n // Invalidate caches for the written path\n this.invalidateCache(ctx.params.path);\n\n return {\n data: {\n id: this.generateId(key),\n path: normalizedOutputPath,\n content: payload.content,\n updatedAt: metadata.updated ? new Date(metadata.updated as string) : new Date(),\n metadata: {\n size: metadata.size ? Number(metadata.size) : 0,\n etag: metadata.etag,\n generation: metadata.generation,\n ...payload.metadata,\n },\n },\n };\n } catch (error) {\n throw mapGCSError(error);\n }\n }\n\n // ========== Delete Operations ==========\n\n @Delete(\"/:path*\")\n async deleteHandler(ctx: RouteContext<{ path: string }>): Promise<AFSDeleteResult> {\n try {\n const key = this.buildGCSKey(ctx.params.path);\n const file = this.bucket.file(key);\n const [exists] = await file.exists();\n\n if (exists) {\n // It's a file, delete it directly\n await file.delete();\n\n // Invalidate caches for the deleted path\n this.invalidateCache(ctx.params.path);\n\n return {\n message: `Successfully deleted: ${ctx.params.path}`,\n };\n }\n\n // Check if it's a directory (has children)\n const [files] = await this.bucket.getFiles({\n prefix: `${key}/`,\n maxResults: 1,\n });\n\n if (files.length === 0) {\n throw new AFSNotFoundError(`/${ctx.params.path}`);\n }\n\n // Directory with children - need recursive option\n throw new AFSError(\n `Cannot delete non-empty directory: ${ctx.params.path}. Use recursive option.`,\n \"AFS_INVALID_OPERATION\",\n );\n } catch (error) {\n if (error instanceof AFSError || error instanceof AFSNotFoundError) {\n throw error;\n }\n throw mapGCSError(error);\n }\n }\n\n // ========== Action System ==========\n\n @Actions(\"/:path*\")\n async listActionsHandler(ctx: RouteContext<{ path: string }>): Promise<AFSListResult> {\n const basePath = ctx.path.replace(/\\/\\.actions$/, \"\");\n return {\n data: [\n {\n id: \"presign-download\",\n path: `${basePath}/.actions/presign-download`,\n summary: \"Generate signed download URL\",\n metadata: { kind: \"afs:executable\", kinds: [\"afs:executable\", \"afs:node\"] },\n },\n {\n id: \"presign-upload\",\n path: `${basePath}/.actions/presign-upload`,\n summary: \"Generate signed upload URL\",\n metadata: { kind: \"afs:executable\", kinds: [\"afs:executable\", \"afs:node\"] },\n },\n {\n id: \"compose\",\n path: `${basePath}/.actions/compose`,\n summary: \"Compose multiple objects into one\",\n metadata: { kind: \"afs:executable\", kinds: [\"afs:executable\", \"afs:node\"] },\n },\n {\n id: \"rewrite\",\n path: `${basePath}/.actions/rewrite`,\n summary: \"Rewrite object to new location\",\n metadata: { kind: \"afs:executable\", kinds: [\"afs:executable\", \"afs:node\"] },\n },\n ],\n };\n }\n\n @Actions.Exec(\"/:path*\", \"presign-download\")\n async signDownloadActionHandler(\n ctx: RouteContext<{ path: string }>,\n args: Record<string, unknown>,\n ): Promise<AFSExecResult> {\n const normalizedPath = ctx.params.path.replace(/^\\/+/, \"\").replace(/\\/+$/, \"\");\n const key = this.options.prefix ? `${this.options.prefix}/${normalizedPath}` : normalizedPath;\n const file = this.bucket.file(key);\n\n let expiresIn = (args.expiresIn as number) ?? DEFAULT_EXPIRES_IN;\n if (expiresIn > MAX_EXPIRES_IN) expiresIn = MAX_EXPIRES_IN;\n if (expiresIn < 1) expiresIn = 1;\n\n const expiresAt = Date.now() + expiresIn * 1000;\n\n const [url] = await file.getSignedUrl({\n action: \"read\",\n expires: expiresAt,\n });\n\n return {\n success: true,\n data: {\n url,\n expiresAt: new Date(expiresAt).toISOString(),\n },\n };\n }\n\n @Actions.Exec(\"/:path*\", \"presign-upload\")\n async signUploadActionHandler(\n ctx: RouteContext<{ path: string }>,\n args: Record<string, unknown>,\n ): Promise<AFSExecResult> {\n const normalizedPath = ctx.params.path.replace(/^\\/+/, \"\").replace(/\\/+$/, \"\");\n const key = this.options.prefix ? `${this.options.prefix}/${normalizedPath}` : normalizedPath;\n const file = this.bucket.file(key);\n\n let expiresIn = (args.expiresIn as number) ?? DEFAULT_EXPIRES_IN;\n if (expiresIn > MAX_EXPIRES_IN) expiresIn = MAX_EXPIRES_IN;\n if (expiresIn < 1) expiresIn = 1;\n\n const expiresAt = Date.now() + expiresIn * 1000;\n const contentType = (args.contentType as string) ?? \"application/octet-stream\";\n\n const [url] = await file.getSignedUrl({\n action: \"write\",\n expires: expiresAt,\n contentType,\n });\n\n return {\n success: true,\n data: {\n url,\n expiresAt: new Date(expiresAt).toISOString(),\n },\n };\n }\n\n @Actions.Exec(\"/:path*\", \"compose\")\n async composeActionHandler(\n ctx: RouteContext<{ path: string }>,\n args: Record<string, unknown>,\n ): Promise<AFSExecResult> {\n const normalizedPath = ctx.params.path.replace(/^\\/+/, \"\").replace(/\\/+$/, \"\");\n const destinationKey = this.options.prefix\n ? `${this.options.prefix}/${normalizedPath}`\n : normalizedPath;\n\n const sources = args.sources as string[];\n if (!sources || !Array.isArray(sources) || sources.length < 2) {\n throw new AFSError(\"compose requires at least 2 source objects\", \"AFS_INVALID_ARGUMENT\");\n }\n\n if (sources.length > MAX_COMPOSE_SOURCES) {\n throw new AFSError(\n `compose supports maximum ${MAX_COMPOSE_SOURCES} sources`,\n \"AFS_INVALID_ARGUMENT\",\n );\n }\n\n // Build source file references\n const sourceFiles = sources.map((source) => {\n const sourcePath = source.replace(/^\\/+/, \"\").replace(/\\/+$/, \"\");\n const sourceKey = this.options.prefix ? `${this.options.prefix}/${sourcePath}` : sourcePath;\n return this.bucket.file(sourceKey);\n });\n\n const destinationFile = this.bucket.file(destinationKey);\n\n // Compose the files using bucket.combine()\n await this.bucket.combine(sourceFiles, destinationFile);\n\n // Get metadata of the composed file\n const [metadata] = await destinationFile.getMetadata();\n\n // Invalidate cache for destination\n this.invalidateCache(ctx.params.path);\n\n return {\n success: true,\n data: {\n generation: metadata.generation,\n size: metadata.size ? Number(metadata.size) : 0,\n etag: metadata.etag,\n },\n };\n }\n\n @Actions.Exec(\"/:path*\", \"rewrite\")\n async rewriteActionHandler(\n ctx: RouteContext<{ path: string }>,\n args: Record<string, unknown>,\n ): Promise<AFSExecResult> {\n const normalizedPath = ctx.params.path.replace(/^\\/+/, \"\").replace(/\\/+$/, \"\");\n const sourceKey = this.options.prefix\n ? `${this.options.prefix}/${normalizedPath}`\n : normalizedPath;\n\n const destination = args.destination as string;\n if (!destination) {\n throw new AFSError(\"rewrite requires destination path\", \"AFS_INVALID_ARGUMENT\");\n }\n\n const destPath = destination.replace(/^\\/+/, \"\").replace(/\\/+$/, \"\");\n const destKey = this.options.prefix ? `${this.options.prefix}/${destPath}` : destPath;\n\n const sourceFile = this.bucket.file(sourceKey);\n const destFile = this.bucket.file(destKey);\n\n // Copy options\n const copyOptions: { contentType?: string; metadata?: Record<string, string> } = {};\n if (args.storageClass) {\n copyOptions.metadata = { storageClass: args.storageClass as string };\n }\n if (args.contentType) {\n copyOptions.contentType = args.contentType as string;\n }\n\n // Copy (rewrite) the file\n await sourceFile.copy(destFile, copyOptions);\n\n // Get metadata of the new file\n const [metadata] = await destFile.getMetadata();\n\n // Invalidate cache for destination\n this.invalidateCache(destPath);\n\n return {\n success: true,\n data: {\n destination: `/${destPath}`,\n generation: metadata.generation,\n size: metadata.size ? Number(metadata.size) : 0,\n etag: metadata.etag,\n storageClass: metadata.storageClass,\n },\n };\n }\n\n // ========== Legacy API compatibility (for migration) ==========\n\n /**\n * Generate a signed URL for downloading an object\n * @deprecated Use action /.actions/sign-download instead\n */\n async getSignedDownloadUrl(path: string, options?: { expiresIn?: number }): Promise<string> {\n const result = await this.signDownloadActionHandler(\n { path: `/${path}`, params: { path }, options: {} },\n { expiresIn: options?.expiresIn },\n );\n return result.data!.url as string;\n }\n\n /**\n * Generate a signed URL for uploading an object\n * @deprecated Use action /.actions/sign-upload instead\n */\n async getSignedUploadUrl(\n path: string,\n options?: { expiresIn?: number; contentType?: string },\n ): Promise<string> {\n const result = await this.signUploadActionHandler(\n { path: `/${path}`, params: { path }, options: {} },\n { expiresIn: options?.expiresIn, contentType: options?.contentType },\n );\n return result.data!.url as string;\n }\n\n /**\n * List all versions (generations) of an object\n * @deprecated Use list on /:path/@versions instead\n */\n async listVersions(path: string): Promise<\n Array<{\n generation: string;\n isLive: boolean;\n timeCreated?: Date;\n size: number;\n etag?: string;\n }>\n > {\n const result = await this.listVersionsHandler({\n path: `/${path}/@versions`,\n params: { path },\n options: {},\n });\n return result.data.map((entry) => ({\n generation: entry.metadata?.generation as string,\n isLive: entry.metadata?.isLive as boolean,\n timeCreated: entry.updatedAt,\n size: (entry.metadata?.size as number) ?? 0,\n etag: entry.metadata?.etag as string | undefined,\n }));\n }\n\n /**\n * Read a specific version (generation) of an object\n * @deprecated Use read on /:path/@versions/:generation instead\n */\n async readVersion(\n path: string,\n generation: string,\n ): Promise<{ content: string; metadata: Record<string, unknown> }> {\n const result = await this.readVersionHandler({\n path: `/${path}/@versions/${generation}`,\n params: { path, generation },\n options: {},\n });\n return {\n content: result.content as string,\n metadata: result.metadata as Record<string, unknown>,\n };\n }\n\n /**\n * Create a directory marker\n * @deprecated Use write with empty content instead\n */\n async mkdir(path: string): Promise<void> {\n const key = this.buildGCSKey(path);\n const dirKey = key.endsWith(\"/\") ? key : `${key}/`;\n const file = this.bucket.file(dirKey);\n\n await file.save(\"\", { contentType: \"application/x-directory\" });\n }\n}\n\n// Type check: AFSGCS should implement AFSModuleClass\nconst _typeCheck: AFSModuleClass<AFSGCS, AFSGCSOptions> = AFSGCS;\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":["AFSError","files","apiResponse","response","objectCount","prefixCount","lines"],"sources":["../src/cache.ts","../src/client.ts","../src/errors.ts","../src/platform-ref.ts","../src/types.ts","../src/gcs-afs.ts"],"sourcesContent":["/**\n * GCS Response Caching\n *\n * LRU cache with TTL for GCS list and stat results.\n */\n\n/**\n * Cache entry with expiration\n */\ninterface CacheEntry<T> {\n value: T;\n expiresAt: number;\n}\n\n/**\n * LRU Cache with TTL support\n */\nexport class LRUCache<T> {\n private cache = new Map<string, CacheEntry<T>>();\n private maxSize: number;\n private defaultTtl: number;\n\n /**\n * Create a new LRU cache\n *\n * @param maxSize - Maximum number of entries (default: 1000)\n * @param defaultTtl - Default TTL in seconds (default: 60)\n */\n constructor(maxSize = 1000, defaultTtl = 60) {\n this.maxSize = maxSize;\n this.defaultTtl = defaultTtl;\n }\n\n /**\n * Get a value from the cache\n *\n * @param key - Cache key\n * @returns Cached value or undefined if not found/expired\n */\n get(key: string): T | undefined {\n const entry = this.cache.get(key);\n\n if (!entry) {\n return undefined;\n }\n\n // Check if expired\n if (Date.now() > entry.expiresAt) {\n this.cache.delete(key);\n return undefined;\n }\n\n // Move to end (most recently used)\n this.cache.delete(key);\n this.cache.set(key, entry);\n\n return entry.value;\n }\n\n /**\n * Set a value in the cache\n *\n * @param key - Cache key\n * @param value - Value to cache\n * @param ttl - TTL in seconds (optional, uses default)\n */\n set(key: string, value: T, ttl?: number): void {\n // Remove if already exists (to update position)\n if (this.cache.has(key)) {\n this.cache.delete(key);\n }\n\n // Evict oldest entries if at capacity\n while (this.cache.size >= this.maxSize) {\n const oldestKey = this.cache.keys().next().value;\n if (oldestKey) {\n this.cache.delete(oldestKey);\n }\n }\n\n const expiresAt = Date.now() + (ttl ?? this.defaultTtl) * 1000;\n this.cache.set(key, { value, expiresAt });\n }\n\n /**\n * Delete a value from the cache\n *\n * @param key - Cache key\n */\n delete(key: string): void {\n this.cache.delete(key);\n }\n\n /**\n * Delete all entries matching a prefix\n *\n * @param prefix - Key prefix to match\n */\n deleteByPrefix(prefix: string): void {\n for (const key of this.cache.keys()) {\n if (key.startsWith(prefix)) {\n this.cache.delete(key);\n }\n }\n }\n\n /**\n * Clear all entries\n */\n clear(): void {\n this.cache.clear();\n }\n\n /**\n * Get the number of entries in the cache\n */\n get size(): number {\n return this.cache.size;\n }\n\n /**\n * Prune expired entries\n */\n prune(): void {\n const now = Date.now();\n for (const [key, entry] of this.cache.entries()) {\n if (now > entry.expiresAt) {\n this.cache.delete(key);\n }\n }\n }\n}\n\n/**\n * Create a cache key from bucket, prefix, and path\n */\nexport function createCacheKey(\n bucket: string,\n prefix: string,\n path: string,\n suffix?: string,\n): string {\n const base = `${bucket}:${prefix}:${path}`;\n return suffix ? `${base}:${suffix}` : base;\n}\n","/**\n * GCS Client Factory\n *\n * Creates configured Google Cloud Storage clients.\n */\n\nimport { Storage, type StorageOptions } from \"@google-cloud/storage\";\nimport type { AFSGCSOptions } from \"./types.js\";\n\n/**\n * Create a GCS Storage client from options\n *\n * @param options - AFSGCS options\n * @returns Configured Storage client\n */\nexport function createGCSClient(options: AFSGCSOptions): Storage {\n const storageOptions: StorageOptions = {};\n\n // Project ID\n if (options.projectId) {\n storageOptions.projectId = options.projectId;\n }\n\n // Custom endpoint (for fake-gcs-server)\n if (options.endpoint) {\n storageOptions.apiEndpoint = options.endpoint;\n }\n\n // Key file authentication\n if (options.keyFilename) {\n storageOptions.keyFilename = options.keyFilename;\n }\n\n // Explicit credentials\n if (options.credentials) {\n storageOptions.credentials = {\n client_email: options.credentials.clientEmail,\n private_key: options.credentials.privateKey,\n };\n }\n\n return new Storage(storageOptions);\n}\n","/**\n * GCS Provider Error Handling\n *\n * Maps GCS SDK errors to AFS error types.\n */\n\n/**\n * AFS error codes\n */\nexport const AFSErrorCode = {\n ENTRY_NOT_FOUND: \"ENTRY_NOT_FOUND\",\n MODULE_NOT_FOUND: \"MODULE_NOT_FOUND\",\n PERMISSION_DENIED: \"PERMISSION_DENIED\",\n AUTH_ERROR: \"AUTH_ERROR\",\n RATE_LIMIT_EXCEEDED: \"RATE_LIMIT_EXCEEDED\",\n INVALID_OPERATION: \"INVALID_OPERATION\",\n ALREADY_EXISTS: \"ALREADY_EXISTS\",\n SERVICE_UNAVAILABLE: \"SERVICE_UNAVAILABLE\",\n UNKNOWN: \"UNKNOWN\",\n} as const;\n\nexport type AFSErrorCode = (typeof AFSErrorCode)[keyof typeof AFSErrorCode];\n\n/**\n * AFS Error class\n */\nexport class AFSError extends Error {\n readonly code: AFSErrorCode;\n readonly retryAfter?: number;\n\n constructor(code: AFSErrorCode, message: string, options?: { retryAfter?: number }) {\n super(message);\n this.name = \"AFSError\";\n this.code = code;\n this.retryAfter = options?.retryAfter;\n }\n}\n\n/**\n * Custom GCS error class for internal use\n */\nexport class GCSError extends Error {\n constructor(\n message: string,\n public readonly code: number,\n ) {\n super(message);\n this.name = \"GCSError\";\n }\n}\n\n/**\n * Map GCS HTTP status codes to AFS error codes\n */\nconst STATUS_TO_AFS_ERROR: Record<number, AFSErrorCode> = {\n 400: AFSErrorCode.INVALID_OPERATION,\n 401: AFSErrorCode.AUTH_ERROR,\n 403: AFSErrorCode.PERMISSION_DENIED,\n 404: AFSErrorCode.ENTRY_NOT_FOUND,\n 409: AFSErrorCode.ALREADY_EXISTS,\n 429: AFSErrorCode.RATE_LIMIT_EXCEEDED,\n 503: AFSErrorCode.SERVICE_UNAVAILABLE,\n};\n\n/**\n * Map GCS error to AFS error\n *\n * @param error - GCS SDK error or generic error\n * @returns AFSError with appropriate error code\n */\nexport function mapGCSError(error: unknown): AFSError {\n // Handle GCSError\n if (error instanceof GCSError) {\n const afsCode = STATUS_TO_AFS_ERROR[error.code] ?? AFSErrorCode.UNKNOWN;\n return new AFSError(afsCode, error.message);\n }\n\n // Handle GCS SDK ApiError format (has code property)\n if (typeof error === \"object\" && error !== null && \"code\" in error) {\n const err = error as { code: number; message?: string };\n const statusCode = typeof err.code === \"number\" ? err.code : 500;\n const message = err.message ?? \"Unknown GCS error\";\n const afsCode = STATUS_TO_AFS_ERROR[statusCode] ?? AFSErrorCode.UNKNOWN;\n return new AFSError(afsCode, message);\n }\n\n // Handle generic Error\n if (error instanceof Error) {\n return new AFSError(AFSErrorCode.UNKNOWN, error.message);\n }\n\n // Unknown error type\n return new AFSError(AFSErrorCode.UNKNOWN, String(error));\n}\n","/**\n * GCS Platform Reference\n *\n * Generates Google Cloud Console URLs for GCS objects and directories.\n */\n\n/**\n * Platform reference containing console URL\n */\nexport interface GCSPlatformRef {\n consoleUrl: string;\n}\n\n/**\n * Generate platform reference with GCP Console URL\n *\n * @param bucket - GCS bucket name\n * @param prefix - Object prefix/key (without leading slash)\n * @param isDirectory - Whether this is a directory (prefix)\n * @returns Platform reference with console URL\n */\nexport function generatePlatformRef(\n bucket: string,\n prefix: string,\n isDirectory: boolean,\n): GCSPlatformRef {\n // GCS Console URL format:\n // Objects: https://console.cloud.google.com/storage/browser/_details/{bucket}/{path}\n // Folders: https://console.cloud.google.com/storage/browser/{bucket}/{path}\n\n if (isDirectory) {\n // Directory URL\n const normalizedPrefix = prefix.endsWith(\"/\") ? prefix : prefix ? `${prefix}/` : \"\";\n return {\n consoleUrl: `https://console.cloud.google.com/storage/browser/${bucket}/${normalizedPrefix}`,\n };\n }\n\n // File URL\n const encodedPrefix = encodeURIComponent(prefix).replace(/%2F/g, \"/\");\n return {\n consoleUrl: `https://console.cloud.google.com/storage/browser/_details/${bucket}/${encodedPrefix}`,\n };\n}\n","/**\n * AFS GCS Provider Types\n */\n\nimport { camelize, optionalize } from \"@aigne/afs/utils/zod\";\nimport { z } from \"zod\";\n\n/**\n * Configuration options for AFSGCS\n */\nexport interface AFSGCSOptions {\n /** Module name (used as mount path segment) */\n name?: string;\n\n /** Module description */\n description?: string;\n\n /** GCS bucket name */\n bucket: string;\n\n /** Key prefix (optional) */\n prefix?: string;\n\n /** GCP project ID */\n projectId?: string;\n\n /** Access mode */\n accessMode?: \"readonly\" | \"readwrite\";\n\n /** Custom endpoint for GCS-compatible services (fake-gcs-server) */\n endpoint?: string;\n\n /** Path to service account key file */\n keyFilename?: string;\n\n /** Explicit credentials (for programmatic access) */\n credentials?: {\n clientEmail: string;\n privateKey: string;\n };\n\n /** Cache TTL in seconds (0 = no cache) */\n cacheTtl?: number;\n}\n\n/**\n * GCS bucket name validation regex\n * - 3-63 characters\n * - lowercase letters, numbers, hyphens, dots (but not consecutive dots)\n * - must start and end with letter or number\n */\nconst BUCKET_NAME_REGEX = /^[a-z0-9][a-z0-9.-]{1,61}[a-z0-9]$/;\n\n/**\n * Additional validation for bucket names\n */\nfunction isValidBucketName(name: string): boolean {\n // Check basic regex\n if (!BUCKET_NAME_REGEX.test(name)) return false;\n\n // No consecutive dots\n if (name.includes(\"..\")) return false;\n\n // No underscores\n if (name.includes(\"_\")) return false;\n\n return true;\n}\n\n/**\n * Zod schema for options validation\n */\nexport const afsgcsOptionsSchema = camelize(\n z\n .object({\n name: optionalize(z.string()),\n description: optionalize(z.string()),\n bucket: z.string().refine(isValidBucketName, \"Invalid GCS bucket name\"),\n prefix: optionalize(z.string()),\n projectId: optionalize(z.string()),\n accessMode: optionalize(z.enum([\"readonly\", \"readwrite\"])),\n endpoint: optionalize(z.string().url()),\n keyFilename: optionalize(z.string()),\n credentials: optionalize(\n z.object({\n clientEmail: z.string(),\n privateKey: z.string(),\n }),\n ),\n cacheTtl: optionalize(z.number().int().min(0)),\n })\n .strict(),\n);\n\n/**\n * Parsed GCS URI\n */\nexport interface ParsedGCSUri {\n bucket: string;\n prefix: string;\n}\n","/**\n * AFS GCS Provider\n *\n * GCS provider using AFSBaseProvider decorator routing pattern.\n * Provides access to Google Cloud Storage through AFS.\n */\n\nimport {\n Actions,\n type AFSAccessMode,\n AFSBaseProvider,\n type AFSDeleteResult,\n type AFSEntry,\n AFSError,\n type AFSExecResult,\n type AFSExplainResult,\n type AFSListResult,\n type AFSModuleClass,\n type AFSModuleLoadParams,\n AFSNotFoundError,\n type AFSSearchResult,\n type AFSStatResult,\n type AFSWriteEntryPayload,\n type AFSWriteResult,\n type CapabilitiesManifest,\n Delete,\n Explain,\n List,\n Meta,\n type ProviderManifest,\n Read,\n type RouteContext,\n Search,\n Stat,\n Write,\n} from \"@aigne/afs\";\nimport { zodParse } from \"@aigne/afs/utils/zod\";\nimport type { Bucket, Storage } from \"@google-cloud/storage\";\nimport { joinURL } from \"ufo\";\nimport { z } from \"zod\";\nimport { createCacheKey, LRUCache } from \"./cache.js\";\nimport { createGCSClient } from \"./client.js\";\nimport { mapGCSError } from \"./errors.js\";\nimport { generatePlatformRef } from \"./platform-ref.js\";\nimport { type AFSGCSOptions, afsgcsOptionsSchema } from \"./types.js\";\n\n/**\n * Default URL expiration time (1 hour)\n */\nconst DEFAULT_EXPIRES_IN = 3600;\n\n/**\n * Maximum expiration time (7 days)\n */\nconst MAX_EXPIRES_IN = 604800;\n\n/**\n * Maximum sources for compose operation\n */\nconst MAX_COMPOSE_SOURCES = 32;\n\n/**\n * AFSGCS Provider using Base Provider pattern\n *\n * Provides access to Google Cloud Storage through AFS.\n * Uses decorator routing (@List, @Read, @Write, @Delete, @Meta, @Actions).\n *\n * @example\n * ```typescript\n * const gcs = new AFSGCS({\n * bucket: \"my-bucket\",\n * prefix: \"data\",\n * projectId: \"my-project\",\n * });\n *\n * // Mount to AFS\n * afs.mount(gcs);\n *\n * // List objects\n * const result = await afs.list(\"/modules/my-bucket/data\");\n *\n * // Read object\n * const content = await afs.read(\"/modules/my-bucket/data/file.json\");\n * ```\n */\nexport class AFSGCS extends AFSBaseProvider {\n override readonly name: string;\n override readonly description?: string;\n override readonly accessMode: AFSAccessMode;\n\n private options: Required<Pick<AFSGCSOptions, \"bucket\">> & AFSGCSOptions;\n private storage: Storage;\n private bucket: Bucket;\n private listCache?: LRUCache<AFSListResult>;\n private statCache?: LRUCache<AFSEntry>;\n\n constructor(options: AFSGCSOptions & { uri?: string; token?: string; auth?: unknown }) {\n super();\n\n // Strip registry-injected keys before strict schema validation\n const { uri: _uri, token: _token, auth: _auth, ...cleanOptions } = options as any;\n\n // Validate options\n const parsed = afsgcsOptionsSchema.parse(cleanOptions);\n\n this.options = {\n ...parsed,\n bucket: parsed.bucket,\n prefix: parsed.prefix ?? \"\",\n accessMode: parsed.accessMode ?? \"readonly\",\n };\n\n this.name = parsed.name ?? parsed.bucket;\n this.description = parsed.description ?? `GCS bucket: ${parsed.bucket}`;\n this.accessMode = this.options.accessMode ?? \"readonly\";\n\n // Create GCS client\n this.storage = createGCSClient(this.options);\n this.bucket = this.storage.bucket(parsed.bucket);\n\n // Initialize caches if cacheTtl is set\n if (parsed.cacheTtl && parsed.cacheTtl > 0) {\n this.listCache = new LRUCache<AFSListResult>(1000, parsed.cacheTtl);\n this.statCache = new LRUCache<AFSEntry>(5000, parsed.cacheTtl);\n }\n }\n\n /**\n * Schema for configuration validation\n */\n static schema() {\n return afsgcsOptionsSchema;\n }\n\n /**\n * Provider manifest for URI-based discovery\n */\n static manifest(): ProviderManifest {\n return {\n name: \"gcs\",\n description: \"Google Cloud Storage\",\n uriTemplate: \"gcs://{bucket}/{prefix+?}\",\n category: \"cloud-storage\",\n schema: z.object({\n bucket: z.string(),\n prefix: z.string().optional(),\n projectId: z.string().optional(),\n keyFilename: z.string().optional(),\n }),\n tags: [\"gcp\", \"gcs\", \"cloud\", \"storage\"],\n };\n }\n\n /**\n * Load from configuration file\n */\n static async load({ basePath, config }: AFSModuleLoadParams = {}): Promise<AFSGCS> {\n const options = zodParse(afsgcsOptionsSchema, config, { prefix: basePath });\n return new AFSGCS(options);\n }\n\n // ========== Helper Methods ==========\n\n /**\n * Build the full GCS key from a path\n */\n private buildGCSKey(path: string): string {\n const normalizedPath = path.replace(/^\\/+/, \"\").replace(/\\/+$/, \"\");\n return this.options.prefix ? `${this.options.prefix}/${normalizedPath}` : normalizedPath;\n }\n\n /**\n * Generate a unique ID for a GCS object\n */\n private generateId(key: string): string {\n const cleanKey = key.replace(/^\\/+/, \"\");\n return `gcs://${this.options.bucket}/${cleanKey}`;\n }\n\n /**\n * Invalidate caches for a given path\n */\n private invalidateCache(path: string): void {\n if (this.statCache) {\n const statKey = createCacheKey(this.options.bucket, this.options.prefix ?? \"\", path);\n this.statCache.delete(statKey);\n }\n\n if (this.listCache) {\n // Invalidate list cache for parent directory\n const parentPath = path.split(\"/\").slice(0, -1).join(\"/\") || \"/\";\n const listPrefix = createCacheKey(this.options.bucket, this.options.prefix ?? \"\", parentPath);\n this.listCache.deleteByPrefix(listPrefix);\n }\n }\n\n /**\n * Clear all caches\n */\n clearCache(): void {\n this.listCache?.clear();\n this.statCache?.clear();\n }\n\n // ========== List Operations ==========\n\n @List(\"/\")\n @List(\"/:path*\")\n async listHandler(ctx: RouteContext<{ path?: string }>): Promise<AFSListResult> {\n try {\n const path = ctx.params.path ?? \"\";\n const normalizedPath = path.replace(/^\\/+/, \"\").replace(/\\/+$/, \"\");\n\n // Build the full GCS prefix\n const fullPrefix = this.options.prefix\n ? normalizedPath\n ? `${this.options.prefix}/${normalizedPath}/`\n : `${this.options.prefix}/`\n : normalizedPath\n ? `${normalizedPath}/`\n : \"\";\n\n const maxChildren = (ctx.options as { limit?: number } | undefined)?.limit ?? 1000;\n\n // Check cache first\n if (this.listCache) {\n const cacheKey = createCacheKey(\n this.options.bucket,\n this.options.prefix ?? \"\",\n normalizedPath,\n JSON.stringify(ctx.options ?? {}),\n );\n const cached = this.listCache.get(cacheKey);\n if (cached) {\n return cached;\n }\n }\n\n const result = await this.listWithDelimiter(fullPrefix, normalizedPath, maxChildren);\n\n // Cache the result\n if (this.listCache) {\n const cacheKey = createCacheKey(\n this.options.bucket,\n this.options.prefix ?? \"\",\n normalizedPath,\n JSON.stringify(ctx.options ?? {}),\n );\n this.listCache.set(cacheKey, result);\n\n // Also populate stat cache from list results\n if (this.statCache) {\n for (const entry of result.data) {\n const statKey = createCacheKey(\n this.options.bucket,\n this.options.prefix ?? \"\",\n entry.path,\n );\n this.statCache.set(statKey, entry);\n }\n }\n }\n\n return result;\n } catch (error) {\n if (error instanceof AFSNotFoundError) {\n throw error;\n }\n throw mapGCSError(error);\n }\n }\n\n /**\n * List with delimiter (single level)\n */\n private async listWithDelimiter(\n prefix: string,\n basePath: string,\n maxChildren: number,\n ): Promise<AFSListResult> {\n const childEntries: AFSEntry[] = [];\n const bucketName = this.options.bucket;\n\n const [files, , apiResponse] = await this.bucket.getFiles({\n prefix,\n delimiter: \"/\",\n maxResults: maxChildren,\n });\n\n // Add directories from prefixes\n const prefixes = (apiResponse as Record<string, unknown>)?.prefixes as string[] | undefined;\n if (prefixes) {\n for (const dirPrefix of prefixes) {\n if (!dirPrefix) continue;\n\n // Extract directory name\n const dirName = dirPrefix.slice(prefix.length).replace(/\\/$/, \"\");\n if (!dirName) continue;\n\n childEntries.push({\n id: this.generateId(dirPrefix),\n path: joinURL(\"/\", basePath, dirName),\n meta: {\n kind: \"afs:node\",\n childrenCount: -1,\n platformRef: generatePlatformRef(bucketName, dirPrefix, true),\n },\n });\n\n if (childEntries.length >= maxChildren) break;\n }\n }\n\n // Add files from Contents\n for (const file of files) {\n if (!file.name) continue;\n\n // Skip the prefix itself (if it's a \"directory marker\")\n if (file.name === prefix) continue;\n\n // Handle directory markers (ending with /)\n if (file.name.endsWith(\"/\")) {\n const dirName = file.name.slice(prefix.length).replace(/\\/$/, \"\");\n if (!dirName) continue;\n\n childEntries.push({\n id: this.generateId(file.name),\n path: joinURL(\"/\", basePath, dirName),\n updatedAt: file.metadata.updated ? new Date(file.metadata.updated as string) : undefined,\n meta: {\n kind: \"afs:node\",\n childrenCount: -1,\n platformRef: generatePlatformRef(bucketName, file.name, true),\n },\n });\n\n if (childEntries.length >= maxChildren) break;\n continue;\n }\n\n // Extract file name\n const fileName = file.name.slice(prefix.length);\n if (!fileName || fileName.includes(\"/\")) continue;\n\n childEntries.push({\n id: this.generateId(file.name),\n path: joinURL(\"/\", basePath, fileName),\n updatedAt: file.metadata.updated ? new Date(file.metadata.updated as string) : undefined,\n meta: {\n size: file.metadata.size ? Number(file.metadata.size) : undefined,\n contentType: file.metadata.contentType,\n lastModified: file.metadata.updated,\n etag: file.metadata.etag,\n storageClass: file.metadata.storageClass,\n platformRef: generatePlatformRef(bucketName, file.name, false),\n },\n });\n\n if (childEntries.length >= maxChildren) break;\n }\n\n const selfPath = basePath ? (basePath.startsWith(\"/\") ? basePath : `/${basePath}`) : \"/\";\n\n // For non-root paths with no children, check if the path exists\n if (childEntries.length === 0 && basePath) {\n // Check if this path exists as a file\n const key = this.options.prefix ? `${this.options.prefix}/${basePath}` : basePath;\n const file = this.bucket.file(key);\n const [fileExists] = await file.exists();\n\n if (fileExists) {\n // Path exists as an object (file), not a directory - return empty children\n return { data: [] };\n }\n\n // Check for directory marker\n const dirMarker = this.bucket.file(`${key}/`);\n const [dirExists] = await dirMarker.exists();\n\n if (!dirExists) {\n // Neither file nor directory marker exists\n throw new AFSNotFoundError(selfPath);\n }\n }\n\n return { data: childEntries };\n }\n\n // ========== Versioning List ==========\n\n @List(\"/:path*/@versions\")\n async listVersionsHandler(ctx: RouteContext<{ path: string }>): Promise<AFSListResult> {\n try {\n const normalizedPath = ctx.params.path.replace(/^\\/+/, \"\").replace(/\\/+$/, \"\");\n const key = this.options.prefix ? `${this.options.prefix}/${normalizedPath}` : normalizedPath;\n\n // Get all generations of the file\n const [files] = await this.bucket.getFiles({\n prefix: key,\n versions: true,\n });\n\n const entries: AFSEntry[] = [];\n\n for (const versionFile of files) {\n // Only include exact key matches\n if (versionFile.name !== key) continue;\n\n const generation = versionFile.metadata.generation;\n if (!generation) continue;\n\n const versionPath = joinURL(\"/\", normalizedPath, \"@versions\", String(generation));\n const isLive = !versionFile.metadata.timeDeleted;\n\n entries.push({\n id: `${this.generateId(key)}:${generation}`,\n path: versionPath,\n updatedAt: versionFile.metadata.timeCreated\n ? new Date(versionFile.metadata.timeCreated as string)\n : undefined,\n meta: {\n generation: generation,\n isLive,\n timeCreated: versionFile.metadata.timeCreated,\n size: versionFile.metadata.size ? Number(versionFile.metadata.size) : 0,\n etag: versionFile.metadata.etag,\n },\n });\n }\n\n return { data: entries };\n } catch (error) {\n throw mapGCSError(error);\n }\n }\n\n // ========== Read Operations ==========\n\n @Read(\"/:path*\")\n async readHandler(ctx: RouteContext<{ path: string }>): Promise<AFSEntry> {\n try {\n const key = this.buildGCSKey(ctx.params.path);\n const normalizedOutputPath = ctx.path.startsWith(\"/\") ? ctx.path : `/${ctx.path}`;\n const bucketName = this.options.bucket;\n\n // Handle root path - return bucket metadata with childrenCount\n if (!key) {\n const [files, , apiResponse] = await this.bucket.getFiles({\n prefix: this.options.prefix ? `${this.options.prefix}/` : \"\",\n delimiter: \"/\",\n maxResults: 1000,\n });\n const prefixes = (apiResponse as Record<string, unknown>)?.prefixes as string[] | undefined;\n const childrenCount = (prefixes?.length ?? 0) + files.length;\n\n return {\n id: this.generateId(\"/\"),\n path: \"/\",\n content: \"\",\n meta: {\n kind: \"afs:node\",\n childrenCount,\n platformRef: generatePlatformRef(bucketName, \"\", true),\n },\n };\n }\n\n const file = this.bucket.file(key);\n\n // Check if file exists\n const [exists] = await file.exists();\n\n if (exists) {\n const [metadata] = await file.getMetadata();\n\n // Check if this is a directory marker\n if (key.endsWith(\"/\") || metadata.contentType === \"application/x-directory\") {\n // Return directory info instead of throwing\n return {\n id: this.generateId(key),\n path: normalizedOutputPath,\n content: \"\",\n updatedAt: metadata.updated ? new Date(metadata.updated as string) : undefined,\n meta: {\n kind: \"afs:node\",\n childrenCount: -1,\n platformRef: generatePlatformRef(bucketName, key, true),\n },\n };\n }\n\n // Download content\n const [content] = await file.download();\n\n return {\n id: this.generateId(key),\n path: normalizedOutputPath,\n content: content.toString(\"utf-8\"),\n updatedAt: metadata.updated ? new Date(metadata.updated as string) : undefined,\n meta: {\n size: metadata.size ? Number(metadata.size) : undefined,\n mimeType: metadata.contentType,\n contentType: metadata.contentType,\n lastModified: metadata.updated,\n etag: metadata.etag,\n },\n };\n }\n\n // File doesn't exist, check if it's a directory prefix\n const [files, , apiResponse] = await this.bucket.getFiles({\n prefix: `${key}/`,\n delimiter: \"/\",\n maxResults: 1000,\n });\n const prefixes = (apiResponse as Record<string, unknown>)?.prefixes as string[] | undefined;\n const hasChildren = files.length > 0 || (prefixes && prefixes.length > 0);\n\n if (hasChildren) {\n // It's a directory - return directory info\n const childrenCount = (prefixes?.length ?? 0) + files.length;\n return {\n id: this.generateId(`${key}/`),\n path: normalizedOutputPath,\n content: \"\",\n meta: {\n kind: \"afs:node\",\n childrenCount,\n platformRef: generatePlatformRef(bucketName, key, true),\n },\n };\n }\n\n // Also check for directory marker (key ending with /)\n const dirMarker = this.bucket.file(`${key}/`);\n const [dirExists] = await dirMarker.exists();\n\n if (dirExists) {\n const [dirMetadata] = await dirMarker.getMetadata();\n return {\n id: this.generateId(`${key}/`),\n path: normalizedOutputPath,\n content: \"\",\n updatedAt: dirMetadata.updated ? new Date(dirMetadata.updated as string) : undefined,\n meta: {\n kind: \"afs:node\",\n childrenCount: -1,\n platformRef: generatePlatformRef(bucketName, key, true),\n },\n };\n }\n\n // Neither file nor directory exists\n throw new AFSNotFoundError(`/${ctx.params.path}`);\n } catch (error) {\n if (error instanceof AFSError || error instanceof AFSNotFoundError) {\n throw error;\n }\n throw mapGCSError(error);\n }\n }\n\n // ========== Version Read ==========\n\n @Read(\"/:path*/@versions/:generation\")\n async readVersionHandler(\n ctx: RouteContext<{ path: string; generation: string }>,\n ): Promise<AFSEntry> {\n try {\n const normalizedPath = ctx.params.path.replace(/^\\/+/, \"\").replace(/\\/+$/, \"\");\n const key = this.options.prefix ? `${this.options.prefix}/${normalizedPath}` : normalizedPath;\n const generation = ctx.params.generation;\n\n const file = this.bucket.file(key, { generation: parseInt(generation, 10) });\n\n // Check if version exists\n const [exists] = await file.exists();\n if (!exists) {\n throw new AFSNotFoundError(`/${normalizedPath}/@versions/${generation}`);\n }\n\n const [content] = await file.download();\n const [metadata] = await file.getMetadata();\n\n return {\n id: `${this.generateId(key)}:${generation}`,\n path: ctx.path,\n content: content.toString(\"utf-8\"),\n updatedAt: metadata.timeCreated ? new Date(metadata.timeCreated as string) : undefined,\n meta: {\n size: metadata.size ? Number(metadata.size) : undefined,\n contentType: metadata.contentType,\n timeCreated: metadata.timeCreated,\n etag: metadata.etag,\n generation: metadata.generation,\n },\n };\n } catch (error) {\n if (error instanceof AFSNotFoundError) {\n throw error;\n }\n throw mapGCSError(error);\n }\n }\n\n // ========== Meta Operations ==========\n\n @Meta(\"/\")\n @Meta(\"/:path*\")\n async metaHandler(ctx: RouteContext<{ path?: string }>): Promise<AFSEntry> {\n try {\n const path = ctx.params.path ?? \"\";\n const normalizedPath = path.replace(/^\\/+/, \"\").replace(/\\/+$/, \"\");\n const key = this.options.prefix\n ? normalizedPath\n ? `${this.options.prefix}/${normalizedPath}`\n : this.options.prefix\n : normalizedPath;\n\n const bucketName = this.options.bucket;\n\n // Root metadata\n if (!key) {\n const [files, , apiResponse] = await this.bucket.getFiles({\n prefix: this.options.prefix ? `${this.options.prefix}/` : \"\",\n delimiter: \"/\",\n maxResults: 1000,\n });\n const prefixes = (apiResponse as Record<string, unknown>)?.prefixes as string[] | undefined;\n const childrenCount = (prefixes?.length ?? 0) + files.length;\n\n return {\n id: this.generateId(\"/\"),\n path: \"/.meta\",\n meta: {\n kind: \"afs:node\",\n childrenCount,\n platformRef: generatePlatformRef(bucketName, \"\", true),\n },\n };\n }\n\n // Check cache first\n if (this.statCache) {\n const cacheKey = createCacheKey(bucketName, this.options.prefix ?? \"\", path);\n const cached = this.statCache.get(cacheKey);\n if (cached) {\n return {\n id: cached.id,\n path: ctx.path,\n meta: cached.meta,\n };\n }\n }\n\n // Try to get the object directly (file case)\n const file = this.bucket.file(key);\n const [exists] = await file.exists();\n\n if (exists) {\n const [metadata] = await file.getMetadata();\n\n // Check if this is a directory marker\n if (key.endsWith(\"/\") || metadata.contentType === \"application/x-directory\") {\n return {\n id: this.generateId(key),\n path: ctx.path,\n updatedAt: metadata.updated ? new Date(metadata.updated as string) : undefined,\n meta: {\n kind: \"afs:node\",\n childrenCount: -1,\n platformRef: generatePlatformRef(bucketName, key, true),\n },\n };\n }\n\n const result = {\n id: this.generateId(key),\n path: ctx.path,\n updatedAt: metadata.updated ? new Date(metadata.updated as string) : undefined,\n meta: {\n kind: \"afs:document\",\n size: metadata.size ? Number(metadata.size) : undefined,\n contentType: metadata.contentType,\n lastModified: metadata.updated,\n etag: metadata.etag,\n storageClass: metadata.storageClass,\n // GCS-specific fields\n generation: metadata.generation,\n metageneration: metadata.metageneration,\n crc32c: metadata.crc32c,\n md5Hash: metadata.md5Hash,\n platformRef: generatePlatformRef(bucketName, key, false),\n },\n };\n\n // Cache the result\n if (this.statCache) {\n const cacheKey = createCacheKey(bucketName, this.options.prefix ?? \"\", path);\n this.statCache.set(cacheKey, result);\n }\n\n return result;\n }\n\n // File doesn't exist, check if it's a directory prefix\n const [files] = await this.bucket.getFiles({\n prefix: `${key}/`,\n maxResults: 1,\n });\n\n if (files.length > 0) {\n // There are objects under this prefix, so it's a directory\n return {\n id: this.generateId(`${key}/`),\n path: ctx.path,\n meta: {\n kind: \"afs:node\",\n childrenCount: -1,\n platformRef: generatePlatformRef(bucketName, key, true),\n },\n };\n }\n\n // Also check for directory marker (key ending with /)\n const dirMarker = this.bucket.file(`${key}/`);\n const [dirExists] = await dirMarker.exists();\n\n if (dirExists) {\n const [dirMetadata] = await dirMarker.getMetadata();\n return {\n id: this.generateId(`${key}/`),\n path: ctx.path,\n updatedAt: dirMetadata.updated ? new Date(dirMetadata.updated as string) : undefined,\n meta: {\n kind: \"afs:node\",\n childrenCount: -1,\n platformRef: generatePlatformRef(bucketName, key, true),\n },\n };\n }\n\n // Neither file nor directory exists\n throw new AFSNotFoundError(path.startsWith(\"/\") ? path : `/${path}`);\n } catch (error) {\n if (error instanceof AFSNotFoundError) {\n throw error;\n }\n throw mapGCSError(error);\n }\n }\n\n // ========== Stat Operations ==========\n\n @Stat(\"/\")\n @Stat(\"/:path*\")\n async statHandler(ctx: RouteContext<{ path?: string }>): Promise<AFSStatResult> {\n // Delegate to meta handler and convert to stat result\n const metaEntry = await this.metaHandler({\n ...ctx,\n path: ctx.path.endsWith(\"/.meta\") ? ctx.path : `${ctx.path}/.meta`,\n });\n\n // Extract id from path\n const pathSegments = ctx.path.split(\"/\").filter(Boolean);\n const id = pathSegments.length > 0 ? (pathSegments[pathSegments.length - 1] as string) : \"/\";\n\n return {\n data: {\n id,\n path: ctx.path,\n meta: metaEntry.meta as Record<string, unknown>,\n },\n };\n }\n\n // ========== Write Operations ==========\n\n @Write(\"/:path*\")\n async writeHandler(\n ctx: RouteContext<{ path: string }>,\n payload: AFSWriteEntryPayload,\n ): Promise<AFSWriteResult> {\n try {\n const key = this.buildGCSKey(ctx.params.path);\n const file = this.bucket.file(key);\n\n // Prepare content\n let content: string | Buffer;\n if (typeof payload.content === \"string\") {\n content = payload.content;\n } else if (Buffer.isBuffer(payload.content)) {\n content = payload.content;\n } else if (payload.content !== undefined) {\n // JSON content\n content = JSON.stringify(payload.content);\n } else {\n content = \"\";\n }\n\n // Prepare save options\n // Disable validation for fake-gcs-server compatibility (it doesn't properly support CRC32C)\n const saveOptions: {\n contentType?: string;\n metadata?: Record<string, string>;\n validation?: boolean;\n } = {\n validation: false,\n };\n if (payload.meta?.mimeType || payload.meta?.contentType) {\n saveOptions.contentType =\n (payload.meta.mimeType as string) ?? (payload.meta.contentType as string);\n }\n\n // Write content\n await file.save(content, saveOptions);\n\n // Get updated metadata\n const [metadata] = await file.getMetadata();\n\n const normalizedOutputPath = ctx.path.startsWith(\"/\") ? ctx.path : `/${ctx.path}`;\n\n // Invalidate caches for the written path\n this.invalidateCache(ctx.params.path);\n\n return {\n data: {\n id: this.generateId(key),\n path: normalizedOutputPath,\n content: payload.content,\n updatedAt: metadata.updated ? new Date(metadata.updated as string) : new Date(),\n meta: {\n size: metadata.size ? Number(metadata.size) : 0,\n etag: metadata.etag,\n generation: metadata.generation,\n ...payload.meta,\n },\n },\n };\n } catch (error) {\n throw mapGCSError(error);\n }\n }\n\n // ========== Delete Operations ==========\n\n @Delete(\"/:path*\")\n async deleteHandler(ctx: RouteContext<{ path: string }>): Promise<AFSDeleteResult> {\n try {\n const key = this.buildGCSKey(ctx.params.path);\n const file = this.bucket.file(key);\n const [exists] = await file.exists();\n\n if (exists) {\n // It's a file, delete it directly\n await file.delete();\n\n // Invalidate caches for the deleted path\n this.invalidateCache(ctx.params.path);\n\n return {\n message: `Successfully deleted: ${ctx.params.path}`,\n };\n }\n\n // Check if it's a directory (has children)\n const [files] = await this.bucket.getFiles({\n prefix: `${key}/`,\n maxResults: 1,\n });\n\n if (files.length === 0) {\n throw new AFSNotFoundError(`/${ctx.params.path}`);\n }\n\n // Directory with children - need recursive option\n throw new AFSError(\n `Cannot delete non-empty directory: ${ctx.params.path}. Use recursive option.`,\n \"AFS_INVALID_OPERATION\",\n );\n } catch (error) {\n if (error instanceof AFSError || error instanceof AFSNotFoundError) {\n throw error;\n }\n throw mapGCSError(error);\n }\n }\n\n // ========== Action System ==========\n\n @Actions(\"/:path*\")\n async listActionsHandler(ctx: RouteContext<{ path: string }>): Promise<AFSListResult> {\n return {\n data: [\n {\n id: \"presign-download\",\n path: joinURL(ctx.path, \"presign-download\"),\n summary: \"Generate signed download URL\",\n meta: {\n kind: \"afs:executable\",\n kinds: [\"afs:executable\", \"afs:node\"],\n inputSchema: {\n type: \"object\",\n properties: {\n expiresIn: {\n type: \"number\",\n description: \"Expiration in seconds (default: 3600, max: 604800)\",\n },\n },\n },\n },\n },\n {\n id: \"presign-upload\",\n path: joinURL(ctx.path, \"presign-upload\"),\n summary: \"Generate signed upload URL\",\n meta: {\n kind: \"afs:executable\",\n kinds: [\"afs:executable\", \"afs:node\"],\n inputSchema: {\n type: \"object\",\n properties: {\n expiresIn: { type: \"number\", description: \"Expiration in seconds\" },\n contentType: { type: \"string\", description: \"Content-Type for upload\" },\n },\n },\n },\n },\n {\n id: \"compose\",\n path: joinURL(ctx.path, \"compose\"),\n summary: \"Compose multiple objects into one\",\n meta: {\n kind: \"afs:executable\",\n kinds: [\"afs:executable\", \"afs:node\"],\n inputSchema: {\n type: \"object\",\n properties: {\n sources: {\n type: \"array\",\n description: \"Array of source paths (2-32)\",\n items: { type: \"string\" },\n },\n },\n required: [\"sources\"],\n },\n },\n },\n {\n id: \"rewrite\",\n path: joinURL(ctx.path, \"rewrite\"),\n summary: \"Rewrite object to new location\",\n meta: {\n kind: \"afs:executable\",\n kinds: [\"afs:executable\", \"afs:node\"],\n inputSchema: {\n type: \"object\",\n properties: {\n destination: { type: \"string\", description: \"Destination path\" },\n storageClass: { type: \"string\", description: \"Target storage class\" },\n contentType: { type: \"string\", description: \"Override content type\" },\n },\n required: [\"destination\"],\n },\n },\n },\n ],\n };\n }\n\n @Actions.Exec(\"/:path*\", \"presign-download\")\n async signDownloadActionHandler(\n ctx: RouteContext<{ path: string }>,\n args: Record<string, unknown>,\n ): Promise<AFSExecResult> {\n const normalizedPath = ctx.params.path.replace(/^\\/+/, \"\").replace(/\\/+$/, \"\");\n const key = this.options.prefix ? `${this.options.prefix}/${normalizedPath}` : normalizedPath;\n const file = this.bucket.file(key);\n\n let expiresIn = (args.expiresIn as number) ?? DEFAULT_EXPIRES_IN;\n if (expiresIn > MAX_EXPIRES_IN) expiresIn = MAX_EXPIRES_IN;\n if (expiresIn < 1) expiresIn = 1;\n\n const expiresAt = Date.now() + expiresIn * 1000;\n\n const [url] = await file.getSignedUrl({\n action: \"read\",\n expires: expiresAt,\n });\n\n return {\n success: true,\n data: {\n url,\n expiresAt: new Date(expiresAt).toISOString(),\n },\n };\n }\n\n @Actions.Exec(\"/:path*\", \"presign-upload\")\n async signUploadActionHandler(\n ctx: RouteContext<{ path: string }>,\n args: Record<string, unknown>,\n ): Promise<AFSExecResult> {\n const normalizedPath = ctx.params.path.replace(/^\\/+/, \"\").replace(/\\/+$/, \"\");\n const key = this.options.prefix ? `${this.options.prefix}/${normalizedPath}` : normalizedPath;\n const file = this.bucket.file(key);\n\n let expiresIn = (args.expiresIn as number) ?? DEFAULT_EXPIRES_IN;\n if (expiresIn > MAX_EXPIRES_IN) expiresIn = MAX_EXPIRES_IN;\n if (expiresIn < 1) expiresIn = 1;\n\n const expiresAt = Date.now() + expiresIn * 1000;\n const contentType = (args.contentType as string) ?? \"application/octet-stream\";\n\n const [url] = await file.getSignedUrl({\n action: \"write\",\n expires: expiresAt,\n contentType,\n });\n\n return {\n success: true,\n data: {\n url,\n expiresAt: new Date(expiresAt).toISOString(),\n },\n };\n }\n\n @Actions.Exec(\"/:path*\", \"compose\")\n async composeActionHandler(\n ctx: RouteContext<{ path: string }>,\n args: Record<string, unknown>,\n ): Promise<AFSExecResult> {\n const normalizedPath = ctx.params.path.replace(/^\\/+/, \"\").replace(/\\/+$/, \"\");\n const destinationKey = this.options.prefix\n ? `${this.options.prefix}/${normalizedPath}`\n : normalizedPath;\n\n const sources = args.sources as string[];\n if (!sources || !Array.isArray(sources) || sources.length < 2) {\n throw new AFSError(\"compose requires at least 2 source objects\", \"AFS_INVALID_ARGUMENT\");\n }\n\n if (sources.length > MAX_COMPOSE_SOURCES) {\n throw new AFSError(\n `compose supports maximum ${MAX_COMPOSE_SOURCES} sources`,\n \"AFS_INVALID_ARGUMENT\",\n );\n }\n\n // Build source file references\n const sourceFiles = sources.map((source) => {\n const sourcePath = source.replace(/^\\/+/, \"\").replace(/\\/+$/, \"\");\n const sourceKey = this.options.prefix ? `${this.options.prefix}/${sourcePath}` : sourcePath;\n return this.bucket.file(sourceKey);\n });\n\n const destinationFile = this.bucket.file(destinationKey);\n\n // Compose the files using bucket.combine()\n await this.bucket.combine(sourceFiles, destinationFile);\n\n // Get metadata of the composed file\n const [metadata] = await destinationFile.getMetadata();\n\n // Invalidate cache for destination\n this.invalidateCache(ctx.params.path);\n\n return {\n success: true,\n data: {\n generation: metadata.generation,\n size: metadata.size ? Number(metadata.size) : 0,\n etag: metadata.etag,\n },\n };\n }\n\n @Actions.Exec(\"/:path*\", \"rewrite\")\n async rewriteActionHandler(\n ctx: RouteContext<{ path: string }>,\n args: Record<string, unknown>,\n ): Promise<AFSExecResult> {\n const normalizedPath = ctx.params.path.replace(/^\\/+/, \"\").replace(/\\/+$/, \"\");\n const sourceKey = this.options.prefix\n ? `${this.options.prefix}/${normalizedPath}`\n : normalizedPath;\n\n const destination = args.destination as string;\n if (!destination) {\n throw new AFSError(\"rewrite requires destination path\", \"AFS_INVALID_ARGUMENT\");\n }\n\n const destPath = destination.replace(/^\\/+/, \"\").replace(/\\/+$/, \"\");\n const destKey = this.options.prefix ? `${this.options.prefix}/${destPath}` : destPath;\n\n const sourceFile = this.bucket.file(sourceKey);\n const destFile = this.bucket.file(destKey);\n\n // Copy options\n const copyOptions: { contentType?: string; metadata?: Record<string, string> } = {};\n if (args.storageClass) {\n copyOptions.metadata = { storageClass: args.storageClass as string };\n }\n if (args.contentType) {\n copyOptions.contentType = args.contentType as string;\n }\n\n // Copy (rewrite) the file\n await sourceFile.copy(destFile, copyOptions);\n\n // Get metadata of the new file\n const [metadata] = await destFile.getMetadata();\n\n // Invalidate cache for destination\n this.invalidateCache(destPath);\n\n return {\n success: true,\n data: {\n destination: `/${destPath}`,\n generation: metadata.generation,\n size: metadata.size ? Number(metadata.size) : 0,\n etag: metadata.etag,\n storageClass: metadata.storageClass,\n },\n };\n }\n\n // ========== Explain Operations ==========\n\n @Explain(\"/\")\n @Explain(\"/:path*\")\n async explainHandler(ctx: RouteContext<{ path?: string }>): Promise<AFSExplainResult> {\n const normalizedPath = (ctx.params.path ?? \"\").replace(/^\\/+/, \"\").replace(/\\/+$/, \"\");\n\n // Root explain\n if (!normalizedPath) {\n const [files, , response] = await this.bucket.getFiles({\n prefix: this.options.prefix ? `${this.options.prefix}/` : undefined,\n delimiter: \"/\",\n maxResults: 1000,\n });\n\n const objectCount = files.length;\n const prefixCount = (response as any)?.prefixes?.length ?? 0;\n\n const lines: string[] = [];\n lines.push(`# ${this.options.bucket}`);\n lines.push(\"\");\n lines.push(`- **Type**: GCS Bucket`);\n lines.push(`- **Bucket**: ${this.options.bucket}`);\n if (this.options.prefix) {\n lines.push(`- **Prefix**: ${this.options.prefix}`);\n }\n if (this.options.projectId) {\n lines.push(`- **Project**: ${this.options.projectId}`);\n }\n lines.push(`- **Access Mode**: ${this.accessMode}`);\n lines.push(`- **Top-level Objects**: ${objectCount}`);\n lines.push(`- **Top-level Prefixes**: ${prefixCount}`);\n\n return { format: \"markdown\", content: lines.join(\"\\n\") };\n }\n\n const key = this.buildGCSKey(normalizedPath);\n\n // Try as object first\n const file = this.bucket.file(key);\n const [exists] = await file.exists();\n\n if (exists) {\n const [metadata] = await file.getMetadata();\n\n const lines: string[] = [];\n lines.push(`# ${normalizedPath}`);\n lines.push(\"\");\n lines.push(`- **Type**: Object`);\n lines.push(`- **Key**: ${key}`);\n lines.push(`- **Size**: ${metadata.size ?? 0} bytes`);\n if (metadata.contentType) lines.push(`- **Content-Type**: ${metadata.contentType}`);\n if (metadata.storageClass) lines.push(`- **Storage Class**: ${metadata.storageClass}`);\n if (metadata.updated) lines.push(`- **Last Modified**: ${metadata.updated}`);\n if (metadata.etag) lines.push(`- **ETag**: ${metadata.etag}`);\n if (metadata.generation) lines.push(`- **Generation**: ${metadata.generation}`);\n\n return { format: \"markdown\", content: lines.join(\"\\n\") };\n }\n\n // Try as prefix (directory)\n const prefix = key.endsWith(\"/\") ? key : `${key}/`;\n const [files, , response] = await this.bucket.getFiles({\n prefix,\n delimiter: \"/\",\n maxResults: 1000,\n });\n\n const objectCount = files.length;\n const prefixCount = (response as any)?.prefixes?.length ?? 0;\n\n if (objectCount === 0 && prefixCount === 0) {\n throw new AFSNotFoundError(`/${normalizedPath}`, `Path not found: ${normalizedPath}`);\n }\n\n const lines: string[] = [];\n lines.push(`# ${normalizedPath}/`);\n lines.push(\"\");\n lines.push(`- **Type**: Prefix (directory)`);\n lines.push(`- **Prefix**: ${prefix}`);\n lines.push(`- **Objects**: ${objectCount}`);\n lines.push(`- **Sub-prefixes**: ${prefixCount}`);\n\n return { format: \"markdown\", content: lines.join(\"\\n\") };\n }\n\n // ========== Search Operations ==========\n\n @Search(\"/\")\n @Search(\"/:path*\")\n async searchHandler(\n ctx: RouteContext<{ path?: string }>,\n query: string,\n ): Promise<AFSSearchResult> {\n const { minimatch } = await import(\"minimatch\");\n const path = ctx.params.path ?? \"\";\n const normalizedPath = path.replace(/^\\/+/, \"\").replace(/\\/+$/, \"\");\n const prefix = normalizedPath\n ? this.options.prefix\n ? `${this.options.prefix}/${normalizedPath}/`\n : `${normalizedPath}/`\n : this.options.prefix\n ? `${this.options.prefix}/`\n : \"\";\n\n const [files] = await this.bucket.getFiles({\n prefix: prefix || undefined,\n });\n\n const results: AFSEntry[] = [];\n for (const file of files) {\n const relativePath = prefix ? file.name.slice(prefix.length) : file.name;\n if (!relativePath) continue;\n\n if (minimatch(relativePath, query)) {\n const displayPath = joinURL(\"/\", normalizedPath, relativePath);\n results.push({\n id: this.generateId(file.name),\n path: displayPath,\n meta: {\n size: file.metadata?.size ? Number(file.metadata.size) : undefined,\n contentType: file.metadata?.contentType,\n lastModified: file.metadata?.updated,\n },\n });\n }\n }\n\n return { data: results };\n }\n\n // ========== Capabilities ==========\n\n @Read(\"/.meta/.capabilities\")\n async readCapabilities(_ctx: RouteContext): Promise<AFSEntry> {\n const capabilities: CapabilitiesManifest = {\n schemaVersion: 1,\n provider: \"gcs\",\n description: `GCS bucket: ${this.options.bucket}`,\n tools: [],\n operations: this.getOperationsDeclaration(),\n actions: [\n {\n description: \"GCS object actions\",\n catalog: [\n {\n name: \"presign-download\",\n description: \"Generate a signed download URL\",\n inputSchema: {\n type: \"object\",\n properties: {\n expiresIn: {\n type: \"number\",\n description: \"Expiration in seconds (default: 3600, max: 604800)\",\n },\n },\n },\n },\n {\n name: \"presign-upload\",\n description: \"Generate a signed upload URL\",\n inputSchema: {\n type: \"object\",\n properties: {\n expiresIn: { type: \"number\", description: \"Expiration in seconds\" },\n contentType: { type: \"string\", description: \"Content-Type for upload\" },\n },\n },\n },\n {\n name: \"compose\",\n description: \"Compose multiple objects into one (max 32 sources)\",\n inputSchema: {\n type: \"object\",\n properties: {\n sources: {\n type: \"array\",\n description: \"Array of source paths (2-32)\",\n items: { type: \"string\" },\n },\n },\n required: [\"sources\"],\n },\n },\n {\n name: \"rewrite\",\n description: \"Copy/rewrite object to a new location\",\n inputSchema: {\n type: \"object\",\n properties: {\n destination: { type: \"string\", description: \"Destination path\" },\n storageClass: { type: \"string\", description: \"Target storage class\" },\n contentType: { type: \"string\", description: \"Override content type\" },\n },\n required: [\"destination\"],\n },\n },\n ],\n discovery: { pathTemplate: \"/{path}/.actions\" },\n },\n ],\n };\n\n return {\n id: \".capabilities\",\n path: \"/.meta/.capabilities\",\n content: JSON.stringify(capabilities, null, 2),\n meta: { kind: \"afs:capabilities\" },\n };\n }\n}\n\n// Type check: AFSGCS should implement AFSModuleClass\nconst _typeCheck: AFSModuleClass<AFSGCS, AFSGCSOptions> = AFSGCS;\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aigne/afs-gcs",
3
- "version": "1.11.0-beta.6",
3
+ "version": "1.11.0-beta.8",
4
4
  "description": "AIGNE AFS module for Google Cloud Storage",
5
5
  "license": "UNLICENSED",
6
6
  "publishConfig": {
@@ -34,8 +34,10 @@
34
34
  ],
35
35
  "dependencies": {
36
36
  "@google-cloud/storage": "^7.16.0",
37
- "zod": "^3.25.67",
38
- "@aigne/afs": "^1.11.0-beta.6"
37
+ "minimatch": "^10.1.1",
38
+ "ufo": "^1.6.3",
39
+ "zod": "^4.0.0",
40
+ "@aigne/afs": "^1.11.0-beta.8"
39
41
  },
40
42
  "devDependencies": {
41
43
  "@types/bun": "^1.3.6",
@@ -43,6 +45,7 @@
43
45
  "rimraf": "^6.1.2",
44
46
  "tsdown": "0.20.0-beta.3",
45
47
  "typescript": "5.9.2",
48
+ "@aigne/afs-testing": "1.11.0-beta.8",
46
49
  "@aigne/scripts": "0.0.0",
47
50
  "@aigne/typescript-config": "0.0.0"
48
51
  },