convex
Version:
Client for the Convex Cloud
497 lines (496 loc) • 15.2 kB
JavaScript
;
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
var fs_exports = {};
__export(fs_exports, {
NodeFs: () => NodeFs,
Observations: () => Observations,
RecordingFs: () => RecordingFs,
consistentPathSort: () => consistentPathSort,
nodeFs: () => nodeFs,
stMatches: () => stMatches,
withTmpDir: () => withTmpDir
});
module.exports = __toCommonJS(fs_exports);
var import_chalk = require("chalk");
var import_fs = __toESM(require("fs"), 1);
var fsPromises = __toESM(require("fs/promises"), 1);
var import_os = __toESM(require("os"), 1);
var import_path = __toESM(require("path"), 1);
var import_crypto = __toESM(require("crypto"), 1);
const tmpDirOverrideVar = "CONVEX_TMPDIR";
function tmpDirPath() {
const envTmpDir = process.env[tmpDirOverrideVar];
return envTmpDir ?? import_os.default.tmpdir();
}
const tmpDirRoot = tmpDirPath();
let warned = false;
function warnCrossFilesystem(dstPath) {
const dstDir = import_path.default.dirname(dstPath);
if (!warned) {
console.warn(
import_chalk.chalkStderr.yellow(
`Temporary directory '${tmpDirRoot}' and project directory '${dstDir}' are on different filesystems.`
)
);
console.warn(
import_chalk.chalkStderr.gray(
` If you're running into errors with other tools watching the project directory, override the temporary directory location with the ${import_chalk.chalkStderr.bold(
tmpDirOverrideVar
)} environment variable.`
)
);
console.warn(
import_chalk.chalkStderr.gray(
` Be sure to pick a temporary directory that's on the same filesystem as your project.`
)
);
warned = true;
}
}
async function withTmpDir(callback) {
const tmpPath = import_fs.default.mkdtempSync(import_path.default.join(tmpDirRoot, "convex"));
const tmpDir = {
writeUtf8File(contents) {
const filePath = import_path.default.join(tmpPath, import_crypto.default.randomUUID());
nodeFs.writeUtf8File(filePath, contents);
return filePath;
},
registerTempPath(st) {
const filePath = import_path.default.join(tmpPath, import_crypto.default.randomUUID());
nodeFs.registerPath(filePath, st);
return filePath;
},
writeFileStream(path2, stream, onData) {
return nodeFs.writeFileStream(path2, stream, onData);
},
path: tmpPath
};
try {
await callback(tmpDir);
} finally {
import_fs.default.rmSync(tmpPath, { force: true, recursive: true });
}
}
class NodeFs {
listDir(dirPath) {
return import_fs.default.readdirSync(dirPath, { withFileTypes: true });
}
exists(path2) {
try {
import_fs.default.statSync(path2);
return true;
} catch (e) {
if (e.code === "ENOENT") {
return false;
}
throw e;
}
}
stat(path2) {
return import_fs.default.statSync(path2);
}
readUtf8File(path2) {
return import_fs.default.readFileSync(path2, { encoding: "utf-8" });
}
createReadStream(path2, options) {
return import_fs.default.createReadStream(path2, options);
}
// To avoid issues with filesystem events triggering for our own streamed file
// writes, writeFileStream is intentionally not on the Filesystem interface
// and not implemented by RecordingFs.
async writeFileStream(path2, stream, onData) {
const fileHandle = await fsPromises.open(path2, "wx", 420);
try {
for await (const chunk of stream) {
if (onData) {
onData(chunk);
}
await fileHandle.write(chunk);
}
} finally {
await fileHandle.close();
}
}
access(path2) {
return import_fs.default.accessSync(path2);
}
writeUtf8File(path2, contents, mode) {
const fd = import_fs.default.openSync(path2, "w", mode);
try {
import_fs.default.writeFileSync(fd, contents, { encoding: "utf-8" });
import_fs.default.fsyncSync(fd);
} finally {
import_fs.default.closeSync(fd);
}
}
mkdir(dirPath, options) {
try {
import_fs.default.mkdirSync(dirPath, { recursive: options?.recursive });
} catch (e) {
if (options?.allowExisting && e.code === "EEXIST") {
return;
}
throw e;
}
}
rmdir(path2) {
import_fs.default.rmdirSync(path2);
}
unlink(path2) {
return import_fs.default.unlinkSync(path2);
}
swapTmpFile(fromPath, toPath) {
try {
return import_fs.default.renameSync(fromPath, toPath);
} catch (e) {
if (e.code === "EXDEV") {
warnCrossFilesystem(toPath);
import_fs.default.copyFileSync(fromPath, toPath);
return;
}
throw e;
}
}
registerPath(_path, _st) {
}
invalidate() {
}
}
const nodeFs = new NodeFs();
class RecordingFs {
constructor(traceEvents) {
// Absolute path -> Set of observed child names
__publicField(this, "observedDirectories", /* @__PURE__ */ new Map());
// Absolute path -> observed stat (or null if observed nonexistent)
__publicField(this, "observedFiles", /* @__PURE__ */ new Map());
// Have we noticed that files have changed while recording?
__publicField(this, "invalidated", false);
__publicField(this, "traceEvents");
this.traceEvents = traceEvents;
}
listDir(dirPath) {
const absDirPath = import_path.default.resolve(dirPath);
const dirSt = nodeFs.stat(absDirPath);
this.registerNormalized(absDirPath, dirSt);
const entries = nodeFs.listDir(dirPath);
for (const entry of entries) {
const childPath = import_path.default.join(absDirPath, entry.name);
const childSt = nodeFs.stat(childPath);
this.registerPath(childPath, childSt);
}
const observedNames = new Set(entries.map((e) => e.name));
const existingNames = this.observedDirectories.get(absDirPath);
if (existingNames) {
if (!setsEqual(observedNames, existingNames)) {
if (this.traceEvents) {
console.log(
"Invalidating due to directory children mismatch",
observedNames,
existingNames
);
}
this.invalidated = true;
}
}
this.observedDirectories.set(absDirPath, observedNames);
return entries;
}
exists(path2) {
try {
const st = nodeFs.stat(path2);
this.registerPath(path2, st);
return true;
} catch (err) {
if (err.code === "ENOENT") {
this.registerPath(path2, null);
return false;
}
throw err;
}
}
stat(path2) {
try {
const st = nodeFs.stat(path2);
this.registerPath(path2, st);
return st;
} catch (err) {
if (err.code === "ENOENT") {
this.registerPath(path2, null);
}
throw err;
}
}
readUtf8File(path2) {
try {
const st = nodeFs.stat(path2);
this.registerPath(path2, st);
return nodeFs.readUtf8File(path2);
} catch (err) {
if (err.code === "ENOENT") {
this.registerPath(path2, null);
}
throw err;
}
}
createReadStream(path2, options) {
try {
const st = nodeFs.stat(path2);
this.registerPath(path2, st);
return nodeFs.createReadStream(path2, options);
} catch (err) {
if (err.code === "ENOENT") {
this.registerPath(path2, null);
}
throw err;
}
}
access(path2) {
try {
const st = nodeFs.stat(path2);
this.registerPath(path2, st);
return nodeFs.access(path2);
} catch (err) {
if (err.code === "ENOENT") {
this.registerPath(path2, null);
}
throw err;
}
}
writeUtf8File(filePath, contents, mode) {
const absPath = import_path.default.resolve(filePath);
nodeFs.writeUtf8File(filePath, contents, mode);
this.updateOnWrite(absPath);
}
mkdir(dirPath, options) {
const absPath = import_path.default.resolve(dirPath);
try {
import_fs.default.mkdirSync(absPath, { recursive: options?.recursive });
} catch (e) {
if (options?.allowExisting && e.code === "EEXIST") {
const st = nodeFs.stat(absPath);
this.registerNormalized(absPath, st);
return;
}
throw e;
}
this.updateOnWrite(absPath);
}
rmdir(dirPath) {
const absPath = import_path.default.resolve(dirPath);
import_fs.default.rmdirSync(absPath);
this.updateOnDelete(absPath);
}
unlink(filePath) {
const absPath = import_path.default.resolve(filePath);
import_fs.default.unlinkSync(absPath);
this.updateOnDelete(absPath);
}
swapTmpFile(fromPath, toPath) {
const absToPath = import_path.default.resolve(toPath);
nodeFs.swapTmpFile(fromPath, absToPath);
this.updateOnWrite(absToPath);
}
updateOnWrite(absPath) {
const newSt = nodeFs.stat(absPath);
this.observedFiles.set(absPath, newSt);
const parentPath = import_path.default.resolve(import_path.default.dirname(absPath));
const observedParent = this.observedDirectories.get(parentPath);
if (observedParent !== void 0) {
observedParent.add(import_path.default.basename(absPath));
}
}
updateOnDelete(absPath) {
this.observedFiles.set(absPath, null);
const parentPath = import_path.default.resolve(import_path.default.dirname(absPath));
const observedParent = this.observedDirectories.get(parentPath);
if (observedParent !== void 0) {
observedParent.delete(import_path.default.basename(absPath));
}
}
registerPath(p, st) {
const absPath = import_path.default.resolve(p);
this.registerNormalized(absPath, st);
}
invalidate() {
this.invalidated = true;
}
registerNormalized(absPath, observed) {
const existing = this.observedFiles.get(absPath);
if (existing !== void 0) {
const stMatch = stMatches(observed, existing);
if (!stMatch.matches) {
if (this.traceEvents) {
console.log(
"Invalidating due to st mismatch",
absPath,
observed,
existing,
stMatch.reason
);
}
this.invalidated = true;
}
}
this.observedFiles.set(absPath, observed);
}
finalize() {
if (this.invalidated) {
return "invalidated";
}
return new Observations(this.observedDirectories, this.observedFiles);
}
}
class Observations {
constructor(directories, files) {
__publicField(this, "directories");
__publicField(this, "files");
this.directories = directories;
this.files = files;
}
paths() {
const out = [];
for (const path2 of this.directories.keys()) {
out.push(path2);
}
for (const path2 of this.files.keys()) {
out.push(path2);
}
return out;
}
overlaps({
absPath
}) {
let currentSt;
try {
currentSt = nodeFs.stat(absPath);
} catch (e) {
if (e.code === "ENOENT") {
currentSt = null;
} else {
throw e;
}
}
const observedSt = this.files.get(absPath);
if (observedSt !== void 0) {
const stMatch = stMatches(observedSt, currentSt);
if (!stMatch.matches) {
const reason = `modified (${stMatch.reason})`;
return { overlaps: true, reason };
}
}
const parentPath = import_path.default.resolve(import_path.default.dirname(absPath));
const observedParent = this.directories.get(parentPath);
if (observedParent !== void 0) {
const filename = import_path.default.basename(absPath);
if (currentSt === null && observedParent.has(filename)) {
return { overlaps: true, reason: "deleted" };
}
if (currentSt !== null && !observedParent.has(filename)) {
return { overlaps: true, reason: "added" };
}
}
return { overlaps: false };
}
}
function setsEqual(a, b) {
if (a.size !== b.size) {
return false;
}
for (const elem of a.keys()) {
if (!b.has(elem)) {
return false;
}
}
return true;
}
function stMatches(a, b) {
if (a === null && b === null) {
return { matches: true };
}
if (a !== null && b !== null) {
if (a.dev !== b.dev) {
return { matches: false, reason: "device boundary" };
}
if (a.isFile() || b.isFile()) {
if (!a.isFile() || !b.isFile()) {
return { matches: false, reason: "file type" };
}
if (a.ino !== b.ino) {
return {
matches: false,
reason: `file inode (${a.ino} vs. ${b.ino})`
};
}
if (a.size !== b.size) {
return {
matches: false,
reason: `file size (${a.size} vs. ${b.size})`
};
}
if (a.mtimeMs !== b.mtimeMs) {
return {
matches: false,
reason: `file mtime (${a.mtimeMs} vs. ${b.mtimeMs})`
};
}
return { matches: true };
}
if (a.isDirectory() || b.isDirectory()) {
if (!b.isDirectory() || !b.isDirectory()) {
return { matches: false, reason: "dir file type" };
}
if (a.ino !== b.ino) {
return {
matches: false,
reason: `dir inode (${a.ino} vs. ${b.ino})`
};
}
return { matches: true };
}
if (a.ino !== b.ino) {
return {
matches: false,
reason: `special inode (${a.ino} vs. ${b.ino})`
};
}
return { matches: true };
}
return { matches: false, reason: "deleted mismatch" };
}
function consistentPathSort(a, b) {
for (let i = 0; i < Math.min(a.name.length, b.name.length); i++) {
if (a.name.charCodeAt(i) !== b.name.charCodeAt(i)) {
return a.name.charCodeAt(i) - b.name.charCodeAt(i);
}
}
return a.name.length - b.name.length;
}
//# sourceMappingURL=fs.js.map