@struktoai/mirage-core
Version:
A Unified Virtual Filesystem For AI Agents
171 lines (170 loc) • 7.14 kB
JavaScript
// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
import { GDriveAccessor } from "../../accessor/gdrive.js";
import { capacity as gdriveCapacity } from "../../core/gdrive/capacity.js";
import { checksum as gdriveChecksum } from "../../core/gdrive/checksum.js";
import { copy as gdriveCopy } from "../../core/gdrive/copy.js";
import { create as gdriveCreate } from "../../core/gdrive/create.js";
import { buildDeltaHook } from "../../core/gdrive/events.js";
import { exists as gdriveExists } from "../../core/gdrive/exists.js";
import { mkdir as gdriveMkdir } from "../../core/gdrive/mkdir.js";
import { read as gdriveRead, readStream as gdriveStream } from "../../core/gdrive/read.js";
import { readdir as gdriveReaddir } from "../../core/gdrive/readdir.js";
import { rename as gdriveRename } from "../../core/gdrive/rename.js";
import { rmR as gdriveRmR } from "../../core/gdrive/rm.js";
import { rmdir as gdriveRmdir } from "../../core/gdrive/rmdir.js";
import { filesContaining as gdriveFilesContaining } from "../../core/gdrive/search.js";
import { setAttrs as gdriveSetAttrs } from "../../core/gdrive/set_attrs.js";
import { stat as gdriveStat } from "../../core/gdrive/stat.js";
import { tree as gdriveTree } from "../../core/gdrive/tree.js";
import { truncate as gdriveTruncate } from "../../core/gdrive/truncate.js";
import { unlink as gdriveUnlink } from "../../core/gdrive/unlink.js";
import { write as gdriveWrite } from "../../core/gdrive/write.js";
import { TokenManager } from "../../core/google/client.js";
import {} from "../../events/index.js";
import { VFSName } from "../../types.js";
import { BaseVFS } from "../base.js";
import { GoogleDriveConfig } from "./config.js";
export const VFS_MD = `\`\`\`text
{prefix}
<folder>/ # the Drive folder hierarchy, mirrored
<name>.gdoc.json # Google Docs: the gdocs gdoc.json shape
<name>.gsheet.json # Google Sheets: the gsheets gsheet.json shape
<name>.gslide.json # Google Slides: the gslides gslide.json shape
<file> # PDFs, images and the rest: raw bytes
<shared-drive>/ # each shared drive you can see
\`\`\`
- There is no \`owned/\` and \`shared/\` split: this is your full Drive
view, including files shared with you that were added to My Drive.
- This is a remote mount: prefer targeted reads over full scans. A
date-prefixed glob (\`2026-05-*\`) becomes a Drive \`modifiedTime\` range
query.
- To act on Drive items by id (create, update, export, permissions), use
the \`gws\` CLI if installed (\`gws drive --help\`).`;
export class GoogleDriveVFS extends BaseVFS {
name = VFSName.GDRIVE;
cachesReads = true;
supportsSnapshot = true;
readRevalidatable = true;
indexTtl = 86_400;
handed = {
readdir: ['entry'],
read: ['entry'],
stat: ['entry'],
checksum: ['entry'],
exists: ['entry'],
readTree: ['entry'],
write: ['entry', 'parent'],
create: ['entry', 'parent'],
mkdir: ['parent'],
unlink: ['entry'],
rmdir: ['entry'],
rmR: ['entry'],
rename: ['entry', 'parent', 'dstParent', 'dstEntry'],
copy: ['entry', 'dstParent', 'dstEntry'],
dirCopy: ['entry', 'dstParent', 'dstEntry'],
truncate: ['entry', 'parent'],
setattr: ['entry'],
filesContaining: ['entry'],
};
vfsMd = VFS_MD;
wholeWordSearch = true;
config;
accessor;
constructor(config) {
super();
this.config = config;
const tm = new TokenManager(config);
this.accessor = new GDriveAccessor({ tokenManager: tm });
}
readsRanges = true;
readdir(path, handed) {
return gdriveReaddir(this.accessor, path, handed?.entry);
}
read(path, handed, offset = 0, size = null) {
if (offset === 0 && size === null) {
return gdriveStream(this.accessor, path, handed?.entry);
}
return gdriveRead(this.accessor, path, size === null ? { offset } : { offset, size }, handed?.entry);
}
stat(path, handed) {
return gdriveStat(this.accessor, path, handed?.entry);
}
checksum(path, algorithm, handed) {
return gdriveChecksum(this.accessor, path, algorithm, handed?.entry);
}
exists(path, handed) {
return gdriveExists(this.accessor, path, handed?.entry);
}
readTree(path, handed) {
return gdriveTree(this.accessor, path, handed?.entry, handed?.limit);
}
write(path, data, signal, handed = {}) {
return gdriveWrite(this.accessor, path, data, handed, signal);
}
create(path, handed = {}) {
return gdriveCreate(this.accessor, path, handed);
}
mkdir(path, parents = false, handed = {}) {
return gdriveMkdir(this.accessor, path, parents, handed);
}
unlink(path, handed) {
return gdriveUnlink(this.accessor, path, handed);
}
rmdir(path, handed) {
return gdriveRmdir(this.accessor, path, handed);
}
rmR(path, handed = {}) {
return gdriveRmR(this.accessor, path, handed);
}
rename(src, dst, handed = {}) {
return gdriveRename(this.accessor, src, dst, handed);
}
copy(src, dst, signal, handed = {}) {
return gdriveCopy(this.accessor, src, dst, signal, handed);
}
dirCopy(src, dst, handed = {}) {
return gdriveCopy(this.accessor, src, dst, undefined, handed);
}
truncate(path, length, noCreate = false, handed = {}) {
return gdriveTruncate(this.accessor, path, length, noCreate, handed);
}
/**
* Whether this VFS answers `name`; with no walk limit it reads every
* file rather than ask the service's search.
*/
supports(name) {
if (name === 'files_containing' && this.walkLimit < 0)
return false;
return super.supports(name);
}
filesContaining(path, text, opts, handed) {
if (!opts.wholeWord || this.walkLimit < 0)
return Promise.resolve(null);
return gdriveFilesContaining(this.accessor, text, path, handed?.entry);
}
setattr(path, fields, handed) {
return gdriveSetAttrs(this.accessor, path, fields, handed?.entry ?? null);
}
capacity() {
return gdriveCapacity(this.accessor);
}
deltaHook() {
return buildDeltaHook(this.accessor);
}
getState() {
return Promise.resolve(this.configState(GoogleDriveConfig, this.config));
}
}
//# sourceMappingURL=gdrive.js.map