// src/utils/async_context.ts
var FallbackStorage = class {
  store;
  run(s, fn) {
    const prev = this.store;
    this.store = s;
    try {
      const result = fn();
      if (result instanceof Promise) {
        return result.finally(() => {
          this.store = prev;
        });
      }
      this.store = prev;
      return result;
    } catch (err) {
      this.store = prev;
      throw err;
    }
  }
  getStore() {
    return this.store;
  }
};
async function resolveCtor() {
  const g = globalThis;
  if (g.AsyncLocalStorage !== void 0) return g.AsyncLocalStorage;
  if (g.process?.versions?.node !== void 0) {
    try {
      const modName = "node:async_hooks";
      const mod = await import(
        /* @vite-ignore */
        modName
      );
      return mod.AsyncLocalStorage;
    } catch {
      return FallbackStorage;
    }
  }
  return FallbackStorage;
}
var AsyncStorageCtor = await resolveCtor();
function createAsyncContext() {
  return new AsyncStorageCtor();
}

// src/types.ts
var MountMode = Object.freeze({
  READ: "read",
  WRITE: "write",
  EXEC: "exec"
});
var ConsistencyPolicy = Object.freeze({
  LAZY: "lazy",
  ALWAYS: "always"
});
var DriftPolicy = Object.freeze({
  /** Raise ContentDriftError on first mismatch. */
  STRICT: "strict",
  /** Skip drift checks entirely. */
  OFF: "off"
});
var ResourceName = Object.freeze({
  DISK: "disk",
  S3: "s3",
  RAM: "ram",
  GITHUB: "github",
  LINEAR: "linear",
  GDOCS: "gdocs",
  GSHEETS: "gsheets",
  GSLIDES: "gslides",
  GDRIVE: "gdrive",
  DROPBOX: "dropbox",
  BOX: "box",
  SLACK: "slack",
  DISCORD: "discord",
  GMAIL: "gmail",
  TRELLO: "trello",
  TELEGRAM: "telegram",
  MONGODB: "mongodb",
  NOTION: "notion",
  LANGFUSE: "langfuse",
  SSH: "ssh",
  REDIS: "redis",
  GITHUB_CI: "github_ci",
  GCS: "gcs",
  OCI: "oci",
  R2: "r2",
  EMAIL: "email",
  PAPERCLIP: "paperclip",
  OPFS: "opfs",
  SUPABASE: "supabase",
  POSTGRES: "postgres",
  SSCHOLAR_PAPER: "sscholar-paper",
  SSCHOLAR_AUTHOR: "sscholar-author",
  VERCEL: "vercel",
  POSTHOG: "posthog"
});
var DEFAULT_SESSION_ID = "default";
var DEFAULT_AGENT_ID = "default";
var FileType = Object.freeze({
  DIRECTORY: "directory",
  TEXT: "text",
  BINARY: "binary",
  JSON: "json",
  CSV: "csv",
  IMAGE_PNG: "image/png",
  IMAGE_JPEG: "image/jpeg",
  IMAGE_GIF: "image/gif",
  ZIP: "application/zip",
  GZIP: "application/gzip",
  PDF: "application/pdf",
  PARQUET: "parquet",
  ORC: "orc",
  FEATHER: "feather",
  HDF5: "hdf5"
});
var FileStat = class {
  name;
  size;
  modified;
  fingerprint;
  revision;
  type;
  extra;
  constructor(init) {
    this.name = init.name;
    this.size = init.size ?? null;
    this.modified = init.modified ?? null;
    this.fingerprint = init.fingerprint ?? null;
    this.revision = init.revision ?? null;
    this.type = init.type ?? null;
    this.extra = init.extra ?? {};
    Object.freeze(this);
  }
};
var PathSpec = class _PathSpec {
  original;
  directory;
  pattern;
  resolved;
  prefix;
  constructor(init) {
    this.original = init.original;
    this.directory = init.directory;
    this.pattern = init.pattern ?? null;
    this.resolved = init.resolved ?? true;
    this.prefix = init.prefix ?? "";
    Object.freeze(this);
  }
  get stripPrefix() {
    if (this.prefix && this.original.startsWith(this.prefix)) {
      return this.original.slice(this.prefix.length) || "/";
    }
    return this.original;
  }
  get key() {
    return this.stripPrefix.replace(/^\/+|\/+$/g, "");
  }
  get dir() {
    return new _PathSpec({
      original: this.directory,
      directory: this.directory,
      pattern: this.pattern,
      resolved: false,
      prefix: this.prefix
    });
  }
  child(name) {
    return `${this.original.replace(/\/+$/, "")}/${name}`;
  }
  static fromStrPath(path, prefix = "") {
    const idx = path.lastIndexOf("/");
    const directory = path.slice(0, idx + 1) || "/";
    return new _PathSpec({ original: path, directory, prefix });
  }
};

// src/observe/record.ts
var OpRecord = class {
  op;
  path;
  source;
  bytes;
  timestamp;
  durationMs;
  fingerprint;
  revision;
  constructor(init) {
    this.op = init.op;
    this.path = init.path;
    this.source = init.source;
    this.bytes = init.bytes;
    this.timestamp = init.timestamp;
    this.durationMs = init.durationMs;
    this.fingerprint = init.fingerprint ?? null;
    this.revision = init.revision ?? null;
  }
  get isCache() {
    return this.source === ResourceName.RAM;
  }
  toJSON() {
    return {
      op: this.op,
      path: this.path,
      source: this.source,
      bytes: this.bytes,
      timestamp: this.timestamp,
      durationMs: this.durationMs,
      fingerprint: this.fingerprint,
      revision: this.revision
    };
  }
};

// src/observe/context.ts
var storage = createAsyncContext();
var revisionsStorage = createAsyncContext();
async function runWithRecording(fn) {
  const state = { records: [], virtualPrefix: "" };
  const value = await storage.run(state, fn);
  return [value, state.records];
}
function setVirtualPrefix(prefix) {
  const state = storage.getStore();
  if (state !== void 0) state.virtualPrefix = prefix;
}
function record(op, path, source, nbytes, startMs, options = {}) {
  const state = storage.getStore();
  if (state === void 0) return;
  const elapsed = Math.floor(performance.now() - startMs);
  state.records.push(
    new OpRecord({
      op,
      path: applyPrefix(state.virtualPrefix, path),
      source,
      bytes: nbytes,
      timestamp: Date.now(),
      durationMs: elapsed,
      fingerprint: options.fingerprint ?? null,
      revision: options.revision ?? null
    })
  );
}
function recordStream(op, path, source, options = {}) {
  const state = storage.getStore();
  if (state === void 0) return null;
  const rec = new OpRecord({
    op,
    path: applyPrefix(state.virtualPrefix, path),
    source,
    bytes: 0,
    timestamp: Date.now(),
    durationMs: 0,
    fingerprint: options.fingerprint ?? null,
    revision: options.revision ?? null
  });
  state.records.push(rec);
  return rec;
}
function runWithRevisions(revisions, fn) {
  return Promise.resolve(revisionsStorage.run({ map: revisions }, fn));
}
function revisionFor(path) {
  const map = revisionsStorage.getStore()?.map;
  if (!map) return null;
  return map.get(path) ?? null;
}
function applyPrefix(prefix, path) {
  if (prefix !== "" && !path.startsWith(prefix)) {
    return prefix.replace(/\/+$/, "") + path;
  }
  return path;
}

// src/utils/optional_peer.ts
async function loadOptionalPeer(importer, config) {
  try {
    return await importer();
  } catch (err) {
    const code = err?.code;
    if (code !== "ERR_MODULE_NOT_FOUND" && code !== "MODULE_NOT_FOUND") throw err;
    const docsLine = config.docsUrl !== void 0 ? `
See ${config.docsUrl} for details.` : "";
    throw new Error(
      `${config.feature} requires the optional peer dependency \`${config.packageName}\`. Install it with:

    pnpm add ${config.packageName}
` + docsLine
    );
  }
}

// src/utils/key_prefix.ts
function normalize(raw) {
  if (raw === void 0 || raw === "") return "";
  const stripped = raw.replace(/^\/+/, "");
  return stripped.endsWith("/") ? stripped : `${stripped}/`;
}
function apply(prefix, path) {
  return prefix + path.replace(/^\/+/, "");
}
function applyDir(prefix, path) {
  const key = apply(prefix, path);
  if (key === "" || key.endsWith("/")) return key;
  return `${key}/`;
}
function strip(prefix, key) {
  if (prefix !== "" && key.startsWith(prefix)) return key.slice(prefix.length);
  return key;
}

// src/core/s3/_client.ts
function s3Key(path, config) {
  return apply(config.keyPrefix ?? "", path);
}
function s3Prefix(path, config) {
  return applyDir(config.keyPrefix ?? "", path);
}
function stripKeyPrefix(key, config) {
  return strip(config.keyPrefix ?? "", key);
}
function rawPathOf(path) {
  const prefix = path.prefix;
  return prefix !== "" && path.original.startsWith(prefix) ? path.original.slice(prefix.length) || "/" : path.original;
}
function fnmatch(name, pattern) {
  let re = "^";
  for (const ch of pattern) {
    if (ch === "*") re += ".*";
    else if (ch === "?") re += ".";
    else if (/[.+^${}()|[\]\\]/.test(ch)) re += "\\" + ch;
    else re += ch;
  }
  re += "$";
  return new RegExp(re).test(name);
}
async function withClient(config, fn) {
  const client = await createS3Client(config);
  try {
    return await fn(client);
  } finally {
    client.destroy?.();
  }
}
var cachedModule = null;
async function loadS3Module(config) {
  if (config?.presignedUrlProvider !== void 0) {
    const { BROWSER_S3_MODULE } = await import("./_client_browser-KPKXNOAW.js");
    return BROWSER_S3_MODULE;
  }
  cachedModule ??= loadOptionalPeer(
    () => import("@aws-sdk/client-s3"),
    {
      feature: "S3Resource",
      packageName: "@aws-sdk/client-s3",
      docsUrl: "https://mirage.dev/typescript/install"
    }
  );
  return cachedModule;
}
async function createS3Client(config) {
  if (config.presignedUrlProvider !== void 0) {
    const { createBrowserS3Client } = await import("./_client_browser-KPKXNOAW.js");
    return createBrowserS3Client(config);
  }
  const mod = await loadS3Module();
  const options = {};
  if (config.region !== void 0) options.region = config.region;
  if (config.endpoint !== void 0) options.endpoint = config.endpoint;
  if (config.forcePathStyle === true) options.forcePathStyle = true;
  if (config.accessKeyId !== void 0 && config.secretAccessKey !== void 0) {
    options.credentials = {
      accessKeyId: config.accessKeyId,
      secretAccessKey: config.secretAccessKey,
      ...config.sessionToken !== void 0 ? { sessionToken: config.sessionToken } : {}
    };
  }
  if (config.timeoutMs !== void 0) {
    options.requestHandler = {
      connectionTimeout: config.timeoutMs,
      requestTimeout: config.timeoutMs
    };
  }
  return new mod.S3Client(options);
}
function isNotFoundError(err) {
  if (err === null || typeof err !== "object") return false;
  const e = err;
  if (e.name === "NoSuchKey" || e.name === "NotFound") return true;
  if (e.Code === "NoSuchKey" || e.Code === "404") return true;
  return e.$metadata?.httpStatusCode === 404;
}
async function streamToBuffer(stream) {
  if (stream === null || stream === void 0) return new Uint8Array();
  const s = stream;
  if (typeof s.transformToByteArray === "function") {
    return s.transformToByteArray();
  }
  if (typeof s[Symbol.asyncIterator] === "function") {
    const chunks = [];
    let total = 0;
    for await (const chunk of s) {
      chunks.push(chunk);
      total += chunk.byteLength;
    }
    const out = new Uint8Array(total);
    let offset = 0;
    for (const c of chunks) {
      out.set(c, offset);
      offset += c.byteLength;
    }
    return out;
  }
  throw new Error("S3 response Body is not a readable stream");
}

// src/core/s3/read.ts
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 };
}
async function read(accessor, path, _index, options = {}) {
  const virtual = path.original;
  const prefix = path.prefix;
  const rawPath = prefix !== "" && virtual.startsWith(prefix) ? virtual.slice(prefix.length) || "/" : virtual;
  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;
  }
  if (options.offset !== void 0 || options.size !== void 0) {
    const start = options.offset ?? 0;
    const end = options.size !== void 0 ? start + options.size - 1 : "";
    input.Range = `bytes=${String(start)}-${String(end)}`;
  }
  const startMs = performance.now();
  try {
    const resp = await client.send(new GetObjectCommand(input));
    const bytes = await streamToBuffer(resp.Body);
    const { fingerprint, revision } = fpRevFromS3Response(resp);
    record("read", virtual, ResourceName.S3, bytes.byteLength, startMs, {
      fingerprint,
      revision
    });
    return bytes;
  } catch (err) {
    if (isNotFoundError(err)) {
      const e = new Error(`S3 object not found: ${rawPath}`);
      e.code = "ENOENT";
      throw e;
    }
    throw err;
  } finally {
    ;
    client.destroy?.();
  }
}

export {
  MountMode,
  ConsistencyPolicy,
  DriftPolicy,
  ResourceName,
  DEFAULT_SESSION_ID,
  DEFAULT_AGENT_ID,
  FileType,
  FileStat,
  PathSpec,
  loadOptionalPeer,
  createAsyncContext,
  OpRecord,
  runWithRecording,
  setVirtualPrefix,
  record,
  recordStream,
  runWithRevisions,
  revisionFor,
  normalize,
  s3Key,
  s3Prefix,
  stripKeyPrefix,
  rawPathOf,
  fnmatch,
  withClient,
  loadS3Module,
  createS3Client,
  isNotFoundError,
  streamToBuffer,
  fpRevFromS3Response,
  read
};
//# sourceMappingURL=chunk-LTJVLIAZ.js.map