@struktoai/mirage-core
Version:
A Unified Virtual Filesystem For AI Agents
79 lines • 3.22 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 { publishRead } from "../../cache/context.js";
import { eacces, enoent } from "../../errors/fs.js";
import { record, revisionFor, startOp } from "../../observe/context.js";
import { VFSName } from "../../types.js";
import { rawPathOf } from "../../utils/key_prefix.js";
import { rangeHeader } from "../../utils/ranges.js";
import { createS3Client, isDenied, isNotFound, loadS3Module, s3Key, streamToBuffer, } from "./client.js";
/**
* Extract `(fingerprint, revision)` from a GetObject / HeadObject response.
*
* VersionId is null on non-versioned buckets; the SDK can also return the
* literal string "null" there, which we normalize.
*/
export function fpRevFromS3Response(resp) {
const rawEtag = resp.ETag ?? '';
const fingerprint = rawEtag.replace(/^"|"$/g, '') || null;
let vid = resp.VersionId ?? null;
if (vid === 'null')
vid = null;
return { fingerprint, revision: vid };
}
export async function read(accessor, path, options = {}) {
const virtual = path.virtual;
const rawPath = rawPathOf(path);
// `virtual` retains the mount prefix (e.g. /s3/foo) for snapshot records;
// `rawPath` is the backend-relative key used for the actual S3 call.
const { config } = accessor;
const key = s3Key(rawPath, config);
const { GetObjectCommand } = await loadS3Module(config);
const client = await createS3Client(config);
const input = { Bucket: config.bucket, Key: key };
const pinnedRevision = revisionFor(virtual);
if (pinnedRevision !== null) {
input.VersionId = pinnedRevision;
}
const range = rangeHeader(options.offset ?? 0, options.size ?? null);
if (range !== null)
input.Range = range;
const timer = startOp();
try {
const resp = (await client.send(new GetObjectCommand(input)));
const bytes = await streamToBuffer(resp.Body);
const { fingerprint, revision } = fpRevFromS3Response(resp);
record('read', virtual, VFSName.S3, bytes.byteLength, timer, {
fingerprint,
revision,
});
// Only a whole read's token names the object; a window's does not.
if (range === null)
publishRead(virtual, bytes, fingerprint);
return bytes;
}
catch (err) {
if (isNotFound(err)) {
throw enoent(path);
}
if (isDenied(err))
throw eacces(path);
throw err;
}
finally {
;
client.destroy?.();
}
}
//# sourceMappingURL=read.js.map