UNPKG

@struktoai/mirage-core

Version:

A Unified Virtual Filesystem For AI Agents

133 lines • 5.38 kB
// ========= 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 { appendByStreamedRewrite } from "../../core/generic/rewrite.js"; import { checksum as s3Checksum } from "../../core/s3/checksum.js"; import { AWS_DOMAINS, CONDITION_SUPPORT, CUSTOM_CONDITION_SUPPORT, MD5_ETAG_STORES, } from "../../core/s3/constants.js"; import { copy as s3Copy, copyFrom as s3CopyFrom } from "../../core/s3/copy.js"; import { create as s3Create } from "../../core/s3/create.js"; import { exists as s3Exists } from "../../core/s3/exists.js"; import { mkdir as s3Mkdir } from "../../core/s3/mkdir.js"; import { readdir as s3Readdir, tree as s3Tree } from "../../core/s3/readdir.js"; import { rename as s3Rename } from "../../core/s3/rename.js"; import { rmR as s3RmR } from "../../core/s3/rm.js"; import { rmdir as s3Rmdir } from "../../core/s3/rmdir.js"; import { stat as s3Stat } from "../../core/s3/stat.js"; import { readRange as s3ReadRange, readStream as s3Stream } from "../../core/s3/stream.js"; import { truncate as s3Truncate } from "../../core/s3/truncate.js"; import { unlink as s3Unlink } from "../../core/s3/unlink.js"; import { replace as s3Replace, write as s3Write } from "../../core/s3/write.js"; import { exdev } from "../../errors/fs.js"; import { BaseVFS } from "../base.js"; function awsEndpoint(endpoint) { let host; try { host = new URL(endpoint).hostname; } catch (error) { console.debug(`endpoint not parsed: ${endpoint}: ${String(error)}`); return false; } return AWS_DOMAINS.some((domain) => host === domain || host.endsWith(`.${domain}`)); } /** * S3's functions over its accessor, which the node and browser * packages build over their own transport. */ export class S3VFS extends BaseVFS { get conditionSupport() { if (this.presigned) return {}; if (this.name === 'minio') return CUSTOM_CONDITION_SUPPORT; const endpoint = this.resolvedEndpoint; if (this.name === 's3' && endpoint !== undefined && endpoint !== '' && !awsEndpoint(endpoint)) return CUSTOM_CONDITION_SUPPORT; return CONDITION_SUPPORT; } readsRanges = true; /** * The endpoint this mount's writes go to, for its write-condition row: the * config's. The node mount also reads the environment. Mirrors Python's * `resolved_endpoint`. */ get resolvedEndpoint() { return this.accessor.config.endpoint; } /** Whether requests go through presigned URLs, which carry no condition. */ get presigned() { return this.accessor.config.presignedUrlProvider !== undefined; } readTree(path, handed) { return s3Tree(this.accessor, path, handed?.limit); } readdir(path, handed) { return s3Readdir(this.accessor, path, handed?.limit); } read(path, _handed, offset = 0, size = null) { if (offset === 0 && size === null) return s3Stream(this.accessor, path); return s3ReadRange(this.accessor, path, offset, size); } stat(path) { return s3Stat(this.accessor, path); } copyFrom(source, src, dst) { if (!(source instanceof S3VFS)) return Promise.reject(exdev(dst)); return s3CopyFrom(this.accessor, source.accessor, src, dst); } checksum(path, algorithm) { if (!MD5_ETAG_STORES.has(this.name) || this.presigned) return Promise.resolve(null); const aws = this.name === 's3' && this.resolvedEndpoint === undefined; return s3Checksum(this.accessor, path, algorithm, aws); } exists(path) { return s3Exists(this.accessor, path); } write(path, data, signal) { return s3Write(this.accessor, path, data, signal); } append(path, data) { return appendByStreamedRewrite((p, remember) => s3Stream(this.accessor, p, remember), (request) => s3Replace(this.accessor, request), (p) => this.stat(p), path, data); } _replace(request, signal) { return s3Replace(this.accessor, request, signal); } create(path) { return s3Create(this.accessor, path); } mkdir(path, parents = false) { return s3Mkdir(this.accessor, path, parents); } unlink(path) { return s3Unlink(this.accessor, path); } rmdir(path) { return s3Rmdir(this.accessor, path); } rmR(path) { return s3RmR(this.accessor, path); } rename(src, dst) { return s3Rename(this.accessor, src, dst); } copy(src, dst) { return s3Copy(this.accessor, src, dst); } truncate(path, length, noCreate = false) { return s3Truncate(this.accessor, path, length, noCreate); } } //# sourceMappingURL=s3.js.map