Initial commit

This commit is contained in:
2025-03-07 19:22:02 +01:00
commit 4a98255d83
55743 changed files with 5280367 additions and 0 deletions
+27
View File
@@ -0,0 +1,27 @@
import { Link } from './node';
import * as opts from './node/types/options';
import type { IDir, IDirent } from './node/types/misc';
/**
* A directory stream, like `fs.Dir`.
*/
export declare class Dir implements IDir {
protected readonly link: Link;
protected options: opts.IOpendirOptions;
private iteratorInfo;
constructor(link: Link, options: opts.IOpendirOptions);
private wrapAsync;
private isFunction;
private promisify;
private closeBase;
private readBase;
readonly path: string;
closeBaseAsync(callback: (err?: Error) => void): void;
close(): Promise<void>;
close(callback?: (err?: Error) => void): void;
closeSync(): void;
readBaseAsync(callback: (err: Error | null, dir?: IDirent | null) => void): void;
read(): Promise<IDirent | null>;
read(callback?: (err: Error | null, dir?: IDirent | null) => void): void;
readSync(): IDirent | null;
[Symbol.asyncIterator](): AsyncIterableIterator<IDirent>;
}
+137
View File
@@ -0,0 +1,137 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Dir = void 0;
const util_1 = require("./node/util");
const Dirent_1 = require("./Dirent");
/**
* A directory stream, like `fs.Dir`.
*/
class Dir {
constructor(link, options) {
this.link = link;
this.options = options;
this.iteratorInfo = [];
this.path = link.getParentPath();
this.iteratorInfo.push(link.children[Symbol.iterator]());
}
wrapAsync(method, args, callback) {
(0, util_1.validateCallback)(callback);
setImmediate(() => {
let result;
try {
result = method.apply(this, args);
}
catch (err) {
callback(err);
return;
}
callback(null, result);
});
}
isFunction(x) {
return typeof x === 'function';
}
promisify(obj, fn) {
return (...args) => new Promise((resolve, reject) => {
if (this.isFunction(obj[fn])) {
obj[fn].bind(obj)(...args, (error, result) => {
if (error)
reject(error);
resolve(result);
});
}
else {
reject('Not a function');
}
});
}
closeBase() { }
readBase(iteratorInfo) {
let done;
let value;
let name;
let link;
do {
do {
({ done, value } = iteratorInfo[iteratorInfo.length - 1].next());
if (!done) {
[name, link] = value;
}
else {
break;
}
} while (name === '.' || name === '..');
if (done) {
iteratorInfo.pop();
if (iteratorInfo.length === 0) {
break;
}
else {
done = false;
}
}
else {
if (this.options.recursive && link.children.size) {
iteratorInfo.push(link.children[Symbol.iterator]());
}
return Dirent_1.default.build(link, this.options.encoding);
}
} while (!done);
return null;
}
closeBaseAsync(callback) {
this.wrapAsync(this.closeBase, [], callback);
}
close(callback) {
if (typeof callback === 'function') {
this.closeBaseAsync(callback);
}
else {
return this.promisify(this, 'closeBaseAsync')();
}
}
closeSync() {
this.closeBase();
}
readBaseAsync(callback) {
this.wrapAsync(this.readBase, [this.iteratorInfo], callback);
}
read(callback) {
if (typeof callback === 'function') {
this.readBaseAsync(callback);
}
else {
return this.promisify(this, 'readBaseAsync')();
}
}
readSync() {
return this.readBase(this.iteratorInfo);
}
[Symbol.asyncIterator]() {
const iteratorInfo = [];
const _this = this;
iteratorInfo.push(_this.link.children[Symbol.iterator]());
// auxiliary object so promisify() can be used
const o = {
readBaseAsync(callback) {
_this.wrapAsync(_this.readBase, [iteratorInfo], callback);
},
};
return {
async next() {
const dirEnt = await _this.promisify(o, 'readBaseAsync')();
if (dirEnt !== null) {
return { done: false, value: dirEnt };
}
else {
return { done: true, value: undefined };
}
},
[Symbol.asyncIterator]() {
throw new Error('Not implemented');
},
};
}
}
exports.Dir = Dir;
//# sourceMappingURL=Dir.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"Dir.js","sourceRoot":"","sources":["../src/Dir.ts"],"names":[],"mappings":"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"}
+22
View File
@@ -0,0 +1,22 @@
import { Link } from './node';
import { TEncodingExtended, TDataOut } from './encoding';
import type { IDirent } from './node/types/misc';
/**
* A directory entry, like `fs.Dirent`.
*/
export declare class Dirent implements IDirent {
static build(link: Link, encoding: TEncodingExtended | undefined): Dirent;
name: TDataOut;
path: string;
parentPath: string;
private mode;
private _checkModeProperty;
isDirectory(): boolean;
isFile(): boolean;
isBlockDevice(): boolean;
isCharacterDevice(): boolean;
isSymbolicLink(): boolean;
isFIFO(): boolean;
isSocket(): boolean;
}
export default Dirent;
+53
View File
@@ -0,0 +1,53 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Dirent = void 0;
const constants_1 = require("./constants");
const encoding_1 = require("./encoding");
const { S_IFMT, S_IFDIR, S_IFREG, S_IFBLK, S_IFCHR, S_IFLNK, S_IFIFO, S_IFSOCK } = constants_1.constants;
/**
* A directory entry, like `fs.Dirent`.
*/
class Dirent {
constructor() {
this.name = '';
this.path = '';
this.parentPath = '';
this.mode = 0;
}
static build(link, encoding) {
const dirent = new Dirent();
const { mode } = link.getNode();
dirent.name = (0, encoding_1.strToEncoding)(link.getName(), encoding);
dirent.mode = mode;
dirent.path = link.getParentPath();
dirent.parentPath = dirent.path;
return dirent;
}
_checkModeProperty(property) {
return (this.mode & S_IFMT) === property;
}
isDirectory() {
return this._checkModeProperty(S_IFDIR);
}
isFile() {
return this._checkModeProperty(S_IFREG);
}
isBlockDevice() {
return this._checkModeProperty(S_IFBLK);
}
isCharacterDevice() {
return this._checkModeProperty(S_IFCHR);
}
isSymbolicLink() {
return this._checkModeProperty(S_IFLNK);
}
isFIFO() {
return this._checkModeProperty(S_IFIFO);
}
isSocket() {
return this._checkModeProperty(S_IFSOCK);
}
}
exports.Dirent = Dirent;
exports.default = Dirent;
//# sourceMappingURL=Dirent.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"Dirent.js","sourceRoot":"","sources":["../src/Dirent.ts"],"names":[],"mappings":";;;AACA,2CAAwC;AACxC,yCAAwE;AAGxE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,qBAAS,CAAC;AAE7F;;GAEG;AACH,MAAa,MAAM;IAAnB;QAaE,SAAI,GAAa,EAAE,CAAC;QACpB,SAAI,GAAG,EAAE,CAAC;QACV,eAAU,GAAG,EAAE,CAAC;QACR,SAAI,GAAW,CAAC,CAAC;IAiC3B,CAAC;IAhDC,MAAM,CAAC,KAAK,CAAC,IAAU,EAAE,QAAuC;QAC9D,MAAM,MAAM,GAAG,IAAI,MAAM,EAAE,CAAC;QAC5B,MAAM,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;QAEhC,MAAM,CAAC,IAAI,GAAG,IAAA,wBAAa,EAAC,IAAI,CAAC,OAAO,EAAE,EAAE,QAAQ,CAAC,CAAC;QACtD,MAAM,CAAC,IAAI,GAAG,IAAI,CAAC;QACnB,MAAM,CAAC,IAAI,GAAG,IAAI,CAAC,aAAa,EAAE,CAAC;QACnC,MAAM,CAAC,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC;QAEhC,OAAO,MAAM,CAAC;IAChB,CAAC;IAOO,kBAAkB,CAAC,QAAgB;QACzC,OAAO,CAAC,IAAI,CAAC,IAAI,GAAG,MAAM,CAAC,KAAK,QAAQ,CAAC;IAC3C,CAAC;IAED,WAAW;QACT,OAAO,IAAI,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC;IAC1C,CAAC;IAED,MAAM;QACJ,OAAO,IAAI,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC;IAC1C,CAAC;IAED,aAAa;QACX,OAAO,IAAI,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC;IAC1C,CAAC;IAED,iBAAiB;QACf,OAAO,IAAI,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC;IAC1C,CAAC;IAED,cAAc;QACZ,OAAO,IAAI,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC;IAC1C,CAAC;IAED,MAAM;QACJ,OAAO,IAAI,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC;IAC1C,CAAC;IAED,QAAQ;QACN,OAAO,IAAI,CAAC,kBAAkB,CAAC,QAAQ,CAAC,CAAC;IAC3C,CAAC;CACF;AAjDD,wBAiDC;AAED,kBAAe,MAAM,CAAC"}
+41
View File
@@ -0,0 +1,41 @@
import { Node } from './node';
export type TStatNumber = number | bigint;
/**
* Statistics about a file/directory, like `fs.Stats`.
*/
export declare class Stats<T = TStatNumber> {
static build(node: Node, bigint: false): Stats<number>;
static build(node: Node, bigint: true): Stats<bigint>;
static build(node: Node, bigint?: boolean): Stats<TStatNumber>;
uid: T;
gid: T;
rdev: T;
blksize: T;
ino: T;
size: T;
blocks: T;
atime: Date;
mtime: Date;
ctime: Date;
birthtime: Date;
atimeMs: T;
mtimeMs: T;
ctimeMs: T;
birthtimeMs: T;
atimeNs: T extends bigint ? T : undefined;
mtimeNs: T extends bigint ? T : undefined;
ctimeNs: T extends bigint ? T : undefined;
birthtimeNs: T extends bigint ? T : undefined;
dev: T;
mode: T;
nlink: T;
private _checkModeProperty;
isDirectory(): boolean;
isFile(): boolean;
isBlockDevice(): boolean;
isCharacterDevice(): boolean;
isSymbolicLink(): boolean;
isFIFO(): boolean;
isSocket(): boolean;
}
export default Stats;
+72
View File
@@ -0,0 +1,72 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Stats = void 0;
const constants_1 = require("./constants");
const { S_IFMT, S_IFDIR, S_IFREG, S_IFBLK, S_IFCHR, S_IFLNK, S_IFIFO, S_IFSOCK } = constants_1.constants;
/**
* Statistics about a file/directory, like `fs.Stats`.
*/
class Stats {
static build(node, bigint = false) {
const stats = new Stats();
const { uid, gid, atime, mtime, ctime } = node;
const getStatNumber = !bigint ? number => number : number => BigInt(number);
// Copy all values on Stats from Node, so that if Node values
// change, values on Stats would still be the old ones,
// just like in Node fs.
stats.uid = getStatNumber(uid);
stats.gid = getStatNumber(gid);
stats.rdev = getStatNumber(node.rdev);
stats.blksize = getStatNumber(4096);
stats.ino = getStatNumber(node.ino);
stats.size = getStatNumber(node.getSize());
stats.blocks = getStatNumber(1);
stats.atime = atime;
stats.mtime = mtime;
stats.ctime = ctime;
stats.birthtime = ctime;
stats.atimeMs = getStatNumber(atime.getTime());
stats.mtimeMs = getStatNumber(mtime.getTime());
const ctimeMs = getStatNumber(ctime.getTime());
stats.ctimeMs = ctimeMs;
stats.birthtimeMs = ctimeMs;
if (bigint) {
stats.atimeNs = BigInt(atime.getTime()) * BigInt(1000000);
stats.mtimeNs = BigInt(mtime.getTime()) * BigInt(1000000);
const ctimeNs = BigInt(ctime.getTime()) * BigInt(1000000);
stats.ctimeNs = ctimeNs;
stats.birthtimeNs = ctimeNs;
}
stats.dev = getStatNumber(0);
stats.mode = getStatNumber(node.mode);
stats.nlink = getStatNumber(node.nlink);
return stats;
}
_checkModeProperty(property) {
return (Number(this.mode) & S_IFMT) === property;
}
isDirectory() {
return this._checkModeProperty(S_IFDIR);
}
isFile() {
return this._checkModeProperty(S_IFREG);
}
isBlockDevice() {
return this._checkModeProperty(S_IFBLK);
}
isCharacterDevice() {
return this._checkModeProperty(S_IFCHR);
}
isSymbolicLink() {
return this._checkModeProperty(S_IFLNK);
}
isFIFO() {
return this._checkModeProperty(S_IFIFO);
}
isSocket() {
return this._checkModeProperty(S_IFSOCK);
}
}
exports.Stats = Stats;
exports.default = Stats;
//# sourceMappingURL=Stats.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"Stats.js","sourceRoot":"","sources":["../src/Stats.ts"],"names":[],"mappings":"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"}
+10
View File
@@ -0,0 +1,10 @@
import type { CrudResourceInfo } from '../crud/types';
export interface CasApi<Hash> {
put(blob: Uint8Array): Promise<Hash>;
get(hash: Hash, options?: CasGetOptions): Promise<Uint8Array>;
del(hash: Hash, silent?: boolean): Promise<void>;
info(hash: Hash): Promise<CrudResourceInfo>;
}
export interface CasGetOptions {
skipVerification?: boolean;
}
+3
View File
@@ -0,0 +1,3 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=types.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/cas/types.ts"],"names":[],"mappings":""}
+63
View File
@@ -0,0 +1,63 @@
export declare const constants: {
O_RDONLY: number;
O_WRONLY: number;
O_RDWR: number;
S_IFMT: number;
S_IFREG: number;
S_IFDIR: number;
S_IFCHR: number;
S_IFBLK: number;
S_IFIFO: number;
S_IFLNK: number;
S_IFSOCK: number;
O_CREAT: number;
O_EXCL: number;
O_NOCTTY: number;
O_TRUNC: number;
O_APPEND: number;
O_DIRECTORY: number;
O_NOATIME: number;
O_NOFOLLOW: number;
O_SYNC: number;
O_SYMLINK: number;
O_DIRECT: number;
O_NONBLOCK: number;
S_IRWXU: number;
S_IRUSR: number;
S_IWUSR: number;
S_IXUSR: number;
S_IRWXG: number;
S_IRGRP: number;
S_IWGRP: number;
S_IXGRP: number;
S_IRWXO: number;
S_IROTH: number;
S_IWOTH: number;
S_IXOTH: number;
F_OK: number;
R_OK: number;
W_OK: number;
X_OK: number;
UV_FS_SYMLINK_DIR: number;
UV_FS_SYMLINK_JUNCTION: number;
UV_FS_COPYFILE_EXCL: number;
UV_FS_COPYFILE_FICLONE: number;
UV_FS_COPYFILE_FICLONE_FORCE: number;
COPYFILE_EXCL: number;
COPYFILE_FICLONE: number;
COPYFILE_FICLONE_FORCE: number;
};
export declare const enum S {
ISUID = 2048,// (04000) set-user-ID (set process effective user ID on execve(2))
ISGID = 1024,// (02000) set-group-ID (set process effective group ID on execve(2); mandatory locking, as described in fcntl(2); take a new file's group from parent directory, as described in chown(2) and mkdir(2))
ISVTX = 512,// (01000) sticky bit (restricted deletion flag, as described in unlink(2))
IRUSR = 256,// (00400) read by owner
IWUSR = 128,// (00200) write by owner
IXUSR = 64,// (00100) execute/search by owner
IRGRP = 32,// (00040) read by group
IWGRP = 16,// (00020) write by group
IXGRP = 8,// (00010) execute/search by group
IROTH = 4,// (00004) read by others
IWOTH = 2,// (00002) write by others
IXOTH = 1
}
+53
View File
@@ -0,0 +1,53 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.constants = void 0;
exports.constants = {
O_RDONLY: 0,
O_WRONLY: 1,
O_RDWR: 2,
S_IFMT: 61440,
S_IFREG: 32768,
S_IFDIR: 16384,
S_IFCHR: 8192,
S_IFBLK: 24576,
S_IFIFO: 4096,
S_IFLNK: 40960,
S_IFSOCK: 49152,
O_CREAT: 64,
O_EXCL: 128,
O_NOCTTY: 256,
O_TRUNC: 512,
O_APPEND: 1024,
O_DIRECTORY: 65536,
O_NOATIME: 262144,
O_NOFOLLOW: 131072,
O_SYNC: 1052672,
O_SYMLINK: 2097152,
O_DIRECT: 16384,
O_NONBLOCK: 2048,
S_IRWXU: 448,
S_IRUSR: 256,
S_IWUSR: 128,
S_IXUSR: 64,
S_IRWXG: 56,
S_IRGRP: 32,
S_IWGRP: 16,
S_IXGRP: 8,
S_IRWXO: 7,
S_IROTH: 4,
S_IWOTH: 2,
S_IXOTH: 1,
F_OK: 0,
R_OK: 4,
W_OK: 2,
X_OK: 1,
UV_FS_SYMLINK_DIR: 1,
UV_FS_SYMLINK_JUNCTION: 2,
UV_FS_COPYFILE_EXCL: 1,
UV_FS_COPYFILE_FICLONE: 2,
UV_FS_COPYFILE_FICLONE_FORCE: 4,
COPYFILE_EXCL: 1,
COPYFILE_FICLONE: 2,
COPYFILE_FICLONE_FORCE: 4,
};
//# sourceMappingURL=constants.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":";;;AAAa,QAAA,SAAS,GAAG;IACvB,QAAQ,EAAE,CAAC;IACX,QAAQ,EAAE,CAAC;IACX,MAAM,EAAE,CAAC;IACT,MAAM,EAAE,KAAK;IACb,OAAO,EAAE,KAAK;IACd,OAAO,EAAE,KAAK;IACd,OAAO,EAAE,IAAI;IACb,OAAO,EAAE,KAAK;IACd,OAAO,EAAE,IAAI;IACb,OAAO,EAAE,KAAK;IACd,QAAQ,EAAE,KAAK;IACf,OAAO,EAAE,EAAE;IACX,MAAM,EAAE,GAAG;IACX,QAAQ,EAAE,GAAG;IACb,OAAO,EAAE,GAAG;IACZ,QAAQ,EAAE,IAAI;IACd,WAAW,EAAE,KAAK;IAClB,SAAS,EAAE,MAAM;IACjB,UAAU,EAAE,MAAM;IAClB,MAAM,EAAE,OAAO;IACf,SAAS,EAAE,OAAO;IAClB,QAAQ,EAAE,KAAK;IACf,UAAU,EAAE,IAAI;IAChB,OAAO,EAAE,GAAG;IACZ,OAAO,EAAE,GAAG;IACZ,OAAO,EAAE,GAAG;IACZ,OAAO,EAAE,EAAE;IACX,OAAO,EAAE,EAAE;IACX,OAAO,EAAE,EAAE;IACX,OAAO,EAAE,EAAE;IACX,OAAO,EAAE,CAAC;IACV,OAAO,EAAE,CAAC;IACV,OAAO,EAAE,CAAC;IACV,OAAO,EAAE,CAAC;IACV,OAAO,EAAE,CAAC;IAEV,IAAI,EAAE,CAAC;IACP,IAAI,EAAE,CAAC;IACP,IAAI,EAAE,CAAC;IACP,IAAI,EAAE,CAAC;IAEP,iBAAiB,EAAE,CAAC;IACpB,sBAAsB,EAAE,CAAC;IAEzB,mBAAmB,EAAE,CAAC;IACtB,sBAAsB,EAAE,CAAC;IACzB,4BAA4B,EAAE,CAAC;IAC/B,aAAa,EAAE,CAAC;IAChB,gBAAgB,EAAE,CAAC;IACnB,sBAAsB,EAAE,CAAC;CAC1B,CAAC"}
+9
View File
@@ -0,0 +1,9 @@
export declare const enum AMODE {
F_OK = 0,
/** Tests for Execute or Search permissions. */
X_OK = 1,
/** Tests for Write permission. */
W_OK = 2,
/** Tests for Read permission. */
R_OK = 4
}
+3
View File
@@ -0,0 +1,3 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=AMODE.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"AMODE.js","sourceRoot":"","sources":["../../src/consts/AMODE.ts"],"names":[],"mappings":""}
+28
View File
@@ -0,0 +1,28 @@
/**
* Constants used in `open` system calls, see [open(2)](http://man7.org/linux/man-pages/man2/open.2.html).
*
* @see http://man7.org/linux/man-pages/man2/open.2.html
* @see https://www.gnu.org/software/libc/manual/html_node/Open_002dtime-Flags.html
*/
export declare const enum FLAG {
O_RDONLY = 0,
O_WRONLY = 1,
O_RDWR = 2,
O_ACCMODE = 3,
O_CREAT = 64,
O_EXCL = 128,
O_NOCTTY = 256,
O_TRUNC = 512,
O_APPEND = 1024,
O_NONBLOCK = 2048,
O_DSYNC = 4096,
FASYNC = 8192,
O_DIRECT = 16384,
O_LARGEFILE = 0,
O_DIRECTORY = 65536,
O_NOFOLLOW = 131072,
O_NOATIME = 262144,
O_CLOEXEC = 524288,
O_SYNC = 1052672,
O_NDELAY = 2048
}
+3
View File
@@ -0,0 +1,3 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=FLAG.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"FLAG.js","sourceRoot":"","sources":["../../src/consts/FLAG.ts"],"names":[],"mappings":""}
+10
View File
@@ -0,0 +1,10 @@
import { CrudCasBase } from './CrudCasBase';
import type { CrudApi } from '../crud/types';
export interface CrudCasOptions {
hash: (blob: Uint8Array) => Promise<string>;
}
export declare class CrudCas extends CrudCasBase<string> {
protected readonly crud: CrudApi;
protected readonly options: CrudCasOptions;
constructor(crud: CrudApi, options: CrudCasOptions);
}
+15
View File
@@ -0,0 +1,15 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CrudCas = void 0;
const util_1 = require("./util");
const CrudCasBase_1 = require("./CrudCasBase");
const hashEqual = (h1, h2) => h1 === h2;
class CrudCas extends CrudCasBase_1.CrudCasBase {
constructor(crud, options) {
super(crud, options.hash, util_1.hashToLocation, hashEqual);
this.crud = crud;
this.options = options;
}
}
exports.CrudCas = CrudCas;
//# sourceMappingURL=CrudCas.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"CrudCas.js","sourceRoot":"","sources":["../../src/crud-to-cas/CrudCas.ts"],"names":[],"mappings":";;;AAAA,iCAAwC;AACxC,+CAA4C;AAO5C,MAAM,SAAS,GAAG,CAAC,EAAU,EAAE,EAAU,EAAE,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC;AAExD,MAAa,OAAQ,SAAQ,yBAAmB;IAC9C,YACqB,IAAa,EACb,OAAuB;QAE1C,KAAK,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,qBAAc,EAAE,SAAS,CAAC,CAAC;QAHlC,SAAI,GAAJ,IAAI,CAAS;QACb,YAAO,GAAP,OAAO,CAAgB;IAG5C,CAAC;CACF;AAPD,0BAOC"}
+14
View File
@@ -0,0 +1,14 @@
import type { CasApi, CasGetOptions } from '../cas/types';
import type { CrudApi, CrudResourceInfo } from '../crud/types';
import type { FsLocation } from '../fsa-to-node/types';
export declare class CrudCasBase<Hash> implements CasApi<Hash> {
protected readonly crud: CrudApi;
protected readonly hash: (blob: Uint8Array) => Promise<Hash>;
protected readonly hash2Loc: (hash: Hash) => FsLocation;
protected readonly hashEqual: (h1: Hash, h2: Hash) => boolean;
constructor(crud: CrudApi, hash: (blob: Uint8Array) => Promise<Hash>, hash2Loc: (hash: Hash) => FsLocation, hashEqual: (h1: Hash, h2: Hash) => boolean);
readonly put: (blob: Uint8Array) => Promise<Hash>;
readonly get: (hash: Hash, options?: CasGetOptions) => Promise<Uint8Array>;
readonly del: (hash: Hash, silent?: boolean) => Promise<void>;
readonly info: (hash: Hash) => Promise<CrudResourceInfo>;
}
+58
View File
@@ -0,0 +1,58 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CrudCasBase = void 0;
const normalizeErrors = async (code) => {
try {
return await code();
}
catch (error) {
if (error && typeof error === 'object') {
switch (error.name) {
case 'ResourceNotFound':
case 'CollectionNotFound':
throw new DOMException(error.message, 'BlobNotFound');
}
}
throw error;
}
};
class CrudCasBase {
constructor(crud, hash, hash2Loc, hashEqual) {
this.crud = crud;
this.hash = hash;
this.hash2Loc = hash2Loc;
this.hashEqual = hashEqual;
this.put = async (blob) => {
const digest = await this.hash(blob);
const [collection, resource] = this.hash2Loc(digest);
await this.crud.put(collection, resource, blob);
return digest;
};
this.get = async (hash, options) => {
const [collection, resource] = this.hash2Loc(hash);
return await normalizeErrors(async () => {
const blob = await this.crud.get(collection, resource);
if (!(options === null || options === void 0 ? void 0 : options.skipVerification)) {
const digest = await this.hash(blob);
if (!this.hashEqual(digest, hash))
throw new DOMException('Blob contents does not match hash', 'Integrity');
}
return blob;
});
};
this.del = async (hash, silent) => {
const [collection, resource] = this.hash2Loc(hash);
await normalizeErrors(async () => {
return await this.crud.del(collection, resource, silent);
});
};
this.info = async (hash) => {
const [collection, resource] = this.hash2Loc(hash);
return await normalizeErrors(async () => {
return await this.crud.info(collection, resource);
});
};
}
}
exports.CrudCasBase = CrudCasBase;
//# sourceMappingURL=CrudCasBase.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"CrudCasBase.js","sourceRoot":"","sources":["../../src/crud-to-cas/CrudCasBase.ts"],"names":[],"mappings":";;;AAIA,MAAM,eAAe,GAAG,KAAK,EAAK,IAAsB,EAAc,EAAE;IACtE,IAAI,CAAC;QACH,OAAO,MAAM,IAAI,EAAE,CAAC;IACtB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YACvC,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;gBACnB,KAAK,kBAAkB,CAAC;gBACxB,KAAK,oBAAoB;oBACvB,MAAM,IAAI,YAAY,CAAC,KAAK,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC;YAC1D,CAAC;QACH,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC,CAAC;AAEF,MAAa,WAAW;IACtB,YACqB,IAAa,EACb,IAAyC,EACzC,QAAoC,EACpC,SAA0C;QAH1C,SAAI,GAAJ,IAAI,CAAS;QACb,SAAI,GAAJ,IAAI,CAAqC;QACzC,aAAQ,GAAR,QAAQ,CAA4B;QACpC,cAAS,GAAT,SAAS,CAAiC;QAG/C,QAAG,GAAG,KAAK,EAAE,IAAgB,EAAiB,EAAE;YAC9D,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACrC,MAAM,CAAC,UAAU,EAAE,QAAQ,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;YACrD,MAAM,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;YAChD,OAAO,MAAM,CAAC;QAChB,CAAC,CAAC;QAEc,QAAG,GAAG,KAAK,EAAE,IAAU,EAAE,OAAuB,EAAuB,EAAE;YACvF,MAAM,CAAC,UAAU,EAAE,QAAQ,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;YACnD,OAAO,MAAM,eAAe,CAAC,KAAK,IAAI,EAAE;gBACtC,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;gBACvD,IAAI,CAAC,CAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,gBAAgB,CAAA,EAAE,CAAC;oBAC/B,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;oBACrC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,CAAC;wBAAE,MAAM,IAAI,YAAY,CAAC,mCAAmC,EAAE,WAAW,CAAC,CAAC;gBAC9G,CAAC;gBACD,OAAO,IAAI,CAAC;YACd,CAAC,CAAC,CAAC;QACL,CAAC,CAAC;QAEc,QAAG,GAAG,KAAK,EAAE,IAAU,EAAE,MAAgB,EAAiB,EAAE;YAC1E,MAAM,CAAC,UAAU,EAAE,QAAQ,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;YACnD,MAAM,eAAe,CAAC,KAAK,IAAI,EAAE;gBAC/B,OAAO,MAAM,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC;YAC3D,CAAC,CAAC,CAAC;QACL,CAAC,CAAC;QAEc,SAAI,GAAG,KAAK,EAAE,IAAU,EAA6B,EAAE;YACrE,MAAM,CAAC,UAAU,EAAE,QAAQ,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;YACnD,OAAO,MAAM,eAAe,CAAC,KAAK,IAAI,EAAE;gBACtC,OAAO,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;YACpD,CAAC,CAAC,CAAC;QACL,CAAC,CAAC;IAjCC,CAAC;CAkCL;AAxCD,kCAwCC"}
+1
View File
@@ -0,0 +1 @@
export { CrudCas, CrudCasOptions } from './CrudCas';
+6
View File
@@ -0,0 +1,6 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CrudCas = void 0;
var CrudCas_1 = require("./CrudCas");
Object.defineProperty(exports, "CrudCas", { enumerable: true, get: function () { return CrudCas_1.CrudCas; } });
//# sourceMappingURL=index.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/crud-to-cas/index.ts"],"names":[],"mappings":";;;AAAA,qCAAoD;AAA3C,kGAAA,OAAO,OAAA"}
+2
View File
@@ -0,0 +1,2 @@
import type { FsLocation } from '../fsa-to-node/types';
export declare const hashToLocation: (hash: string) => FsLocation;
+13
View File
@@ -0,0 +1,13 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.hashToLocation = void 0;
const hashToLocation = (hash) => {
if (hash.length < 20)
throw new TypeError('Hash is too short');
const lastTwo = hash.slice(-2);
const twoBeforeLastTwo = hash.slice(-4, -2);
const folder = [lastTwo, twoBeforeLastTwo];
return [folder, hash];
};
exports.hashToLocation = hashToLocation;
//# sourceMappingURL=util.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"util.js","sourceRoot":"","sources":["../../src/crud-to-cas/util.ts"],"names":[],"mappings":";;;AAEO,MAAM,cAAc,GAAG,CAAC,IAAY,EAAc,EAAE;IACzD,IAAI,IAAI,CAAC,MAAM,GAAG,EAAE;QAAE,MAAM,IAAI,SAAS,CAAC,mBAAmB,CAAC,CAAC;IAC/D,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/B,MAAM,gBAAgB,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAC5C,MAAM,MAAM,GAAG,CAAC,OAAO,EAAE,gBAAgB,CAAC,CAAC;IAC3C,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;AACxB,CAAC,CAAC;AANW,QAAA,cAAc,kBAMzB"}
+83
View File
@@ -0,0 +1,83 @@
export interface CrudApi {
/**
* Creates a new resource, or overwrites an existing one.
*
* @param collection Type of the resource, collection name.
* @param id Id of the resource, document name.
* @param data Blob content of the resource.
* @param options Write behavior options.
*/
put: (collection: CrudCollection, id: string, data: Uint8Array, options?: CrudPutOptions) => Promise<void>;
/**
* Retrieves the content of a resource.
*
* @param collection Type of the resource, collection name.
* @param id Id of the resource, document name.
* @returns Blob content of the resource.
*/
get: (collection: CrudCollection, id: string) => Promise<Uint8Array>;
/**
* Deletes a resource.
*
* @param collection Type of the resource, collection name.
* @param id Id of the resource, document name.
* @param silent When true, does not throw an error if the collection or
* resource does not exist. Default is false.
*/
del: (collection: CrudCollection, id: string, silent?: boolean) => Promise<void>;
/**
* Fetches information about a resource.
*
* @param collection Type of the resource, collection name.
* @param id Id of the resource, document name, if any.
* @returns Information about the resource.
*/
info: (collection: CrudCollection, id?: string) => Promise<CrudResourceInfo>;
/**
* Deletes all resources of a collection, and deletes recursively all sub-collections.
*
* @param collection Type of the resource, collection name.
* @param silent When true, does not throw an error if the collection or
* resource does not exist. Default is false.
*/
drop: (collection: CrudCollection, silent?: boolean) => Promise<void>;
/**
* Iterates over all resources of a collection.
*
* @param collection Type of the resource, collection name.
* @returns Iterator of resources of the given type.
*/
scan: (collection: CrudCollection) => AsyncIterableIterator<CrudCollectionEntry>;
/**
* Fetches a list of resources of a collection, and sub-collections.
*
* @param collection Type of the resource, collection name.
* @returns List of resources of the given type, and sub-types.
*/
list: (collection: CrudCollection) => Promise<CrudCollectionEntry[]>;
/**
* Creates a new CrudApi instance, with the given collection as root.
*
* @param collection Type of the resource, collection name.
* @returns A new CrudApi instance, with the given collection as root.
*/
from: (collection: CrudCollection) => Promise<CrudApi>;
}
export type CrudCollection = string[];
export interface CrudPutOptions {
throwIf?: 'exists' | 'missing';
}
export interface CrudCollectionEntry {
/** Kind of the resource, type or item. */
type: 'resource' | 'collection';
/** Name of the resource. */
id: string;
}
export interface CrudResourceInfo extends CrudCollectionEntry {
/** Size of the resource in bytes. */
size?: number;
/** Timestamp when the resource last modified. */
modified?: number;
/** Timestamp when the resource was created. */
created?: number;
}
+3
View File
@@ -0,0 +1,3 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=types.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/crud/types.ts"],"names":[],"mappings":""}
+2
View File
@@ -0,0 +1,2 @@
import { CrudCollection } from './types';
export declare const assertType: (type: CrudCollection, method: string, klass: string) => void;
+11
View File
@@ -0,0 +1,11 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.assertType = void 0;
const util_1 = require("../node-to-fsa/util");
const assertType = (type, method, klass) => {
const length = type.length;
for (let i = 0; i < length; i++)
(0, util_1.assertName)(type[i], method, klass);
};
exports.assertType = assertType;
//# sourceMappingURL=util.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"util.js","sourceRoot":"","sources":["../../src/crud/util.ts"],"names":[],"mappings":";;;AACA,8CAAiD;AAE1C,MAAM,UAAU,GAAG,CAAC,IAAoB,EAAE,MAAc,EAAE,KAAa,EAAQ,EAAE;IACtF,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;IAC3B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,EAAE,CAAC,EAAE;QAAE,IAAA,iBAAU,EAAC,IAAI,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;AACtE,CAAC,CAAC;AAHW,QAAA,UAAU,cAGrB"}
+5
View File
@@ -0,0 +1,5 @@
export type TDataOut = string | Buffer;
export type TEncodingExtended = BufferEncoding | 'buffer';
export declare const ENCODING_UTF8: BufferEncoding;
export declare function assertEncoding(encoding: string | undefined): void;
export declare function strToEncoding(str: string, encoding?: TEncodingExtended): TDataOut;
+20
View File
@@ -0,0 +1,20 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ENCODING_UTF8 = void 0;
exports.assertEncoding = assertEncoding;
exports.strToEncoding = strToEncoding;
const buffer_1 = require("./internal/buffer");
const errors = require("./internal/errors");
exports.ENCODING_UTF8 = 'utf8';
function assertEncoding(encoding) {
if (encoding && !buffer_1.Buffer.isEncoding(encoding))
throw new errors.TypeError('ERR_INVALID_OPT_VALUE_ENCODING', encoding);
}
function strToEncoding(str, encoding) {
if (!encoding || encoding === exports.ENCODING_UTF8)
return str; // UTF-8
if (encoding === 'buffer')
return new buffer_1.Buffer(str); // `buffer` encoding
return new buffer_1.Buffer(str).toString(encoding); // Custom encoding
}
//# sourceMappingURL=encoding.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"encoding.js","sourceRoot":"","sources":["../src/encoding.ts"],"names":[],"mappings":";;;AAQA,wCAEC;AAED,sCAIC;AAhBD,8CAA2C;AAC3C,4CAA4C;AAK/B,QAAA,aAAa,GAAmB,MAAM,CAAC;AAEpD,SAAgB,cAAc,CAAC,QAA4B;IACzD,IAAI,QAAQ,IAAI,CAAC,eAAM,CAAC,UAAU,CAAC,QAAQ,CAAC;QAAE,MAAM,IAAI,MAAM,CAAC,SAAS,CAAC,gCAAgC,EAAE,QAAQ,CAAC,CAAC;AACvH,CAAC;AAED,SAAgB,aAAa,CAAC,GAAW,EAAE,QAA4B;IACrE,IAAI,CAAC,QAAQ,IAAI,QAAQ,KAAK,qBAAa;QAAE,OAAO,GAAG,CAAC,CAAC,QAAQ;IACjE,IAAI,QAAQ,KAAK,QAAQ;QAAE,OAAO,IAAI,eAAM,CAAC,GAAG,CAAC,CAAC,CAAC,oBAAoB;IACvE,OAAO,IAAI,eAAM,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,kBAAkB;AAC/D,CAAC"}
+16
View File
@@ -0,0 +1,16 @@
import type * as crud from '../crud/types';
import type * as fsa from '../fsa/types';
export declare class FsaCrud implements crud.CrudApi {
protected readonly root: fsa.IFileSystemDirectoryHandle | Promise<fsa.IFileSystemDirectoryHandle>;
constructor(root: fsa.IFileSystemDirectoryHandle | Promise<fsa.IFileSystemDirectoryHandle>);
protected getDir(collection: crud.CrudCollection, create: boolean): Promise<[dir: fsa.IFileSystemDirectoryHandle, parent: fsa.IFileSystemDirectoryHandle | undefined]>;
protected getFile(collection: crud.CrudCollection, id: string): Promise<[dir: fsa.IFileSystemDirectoryHandle, file: fsa.IFileSystemFileHandle]>;
readonly put: (collection: crud.CrudCollection, id: string, data: Uint8Array, options?: crud.CrudPutOptions) => Promise<void>;
readonly get: (collection: crud.CrudCollection, id: string) => Promise<Uint8Array>;
readonly del: (collection: crud.CrudCollection, id: string, silent?: boolean) => Promise<void>;
readonly info: (collection: crud.CrudCollection, id?: string) => Promise<crud.CrudResourceInfo>;
readonly drop: (collection: crud.CrudCollection, silent?: boolean) => Promise<void>;
readonly scan: (collection: crud.CrudCollection) => AsyncIterableIterator<crud.CrudCollectionEntry>;
readonly list: (collection: crud.CrudCollection) => Promise<crud.CrudCollectionEntry[]>;
readonly from: (collection: crud.CrudCollection) => Promise<crud.CrudApi>;
}
+211
View File
@@ -0,0 +1,211 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.FsaCrud = void 0;
const tslib_1 = require("tslib");
const util_1 = require("../node-to-fsa/util");
const util_2 = require("../crud/util");
const util_3 = require("./util");
class FsaCrud {
constructor(root) {
this.root = root;
this.put = async (collection, id, data, options) => {
(0, util_2.assertType)(collection, 'put', 'crudfs');
(0, util_1.assertName)(id, 'put', 'crudfs');
const [dir] = await this.getDir(collection, true);
let file;
switch (options === null || options === void 0 ? void 0 : options.throwIf) {
case 'exists': {
try {
file = await dir.getFileHandle(id, { create: false });
throw (0, util_3.newExistsError)();
}
catch (e) {
if (e.name !== 'NotFoundError')
throw e;
file = await dir.getFileHandle(id, { create: true });
}
break;
}
case 'missing': {
try {
file = await dir.getFileHandle(id, { create: false });
}
catch (e) {
if (e.name === 'NotFoundError')
throw (0, util_3.newMissingError)();
throw e;
}
break;
}
default: {
file = await dir.getFileHandle(id, { create: true });
}
}
const writable = await file.createWritable();
await writable.write(data);
await writable.close();
};
this.get = async (collection, id) => {
(0, util_2.assertType)(collection, 'get', 'crudfs');
(0, util_1.assertName)(id, 'get', 'crudfs');
const [, file] = await this.getFile(collection, id);
const blob = await file.getFile();
const buffer = await blob.arrayBuffer();
return new Uint8Array(buffer);
};
this.del = async (collection, id, silent) => {
(0, util_2.assertType)(collection, 'del', 'crudfs');
(0, util_1.assertName)(id, 'del', 'crudfs');
try {
const [dir] = await this.getFile(collection, id);
await dir.removeEntry(id, { recursive: false });
}
catch (error) {
if (!silent)
throw error;
}
};
this.info = async (collection, id) => {
(0, util_2.assertType)(collection, 'info', 'crudfs');
if (id) {
(0, util_1.assertName)(id, 'info', 'crudfs');
const [, file] = await this.getFile(collection, id);
const blob = await file.getFile();
return {
type: 'resource',
id,
size: blob.size,
modified: blob.lastModified,
};
}
else {
await this.getDir(collection, false);
return {
type: 'collection',
id: '',
};
}
};
this.drop = async (collection, silent) => {
var _a, e_1, _b, _c;
(0, util_2.assertType)(collection, 'drop', 'crudfs');
try {
const [dir, parent] = await this.getDir(collection, false);
if (parent) {
await parent.removeEntry(dir.name, { recursive: true });
}
else {
const root = await this.root;
try {
for (var _d = true, _e = tslib_1.__asyncValues(root.keys()), _f; _f = await _e.next(), _a = _f.done, !_a; _d = true) {
_c = _f.value;
_d = false;
const name = _c;
await root.removeEntry(name, { recursive: true });
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (!_d && !_a && (_b = _e.return)) await _b.call(_e);
}
finally { if (e_1) throw e_1.error; }
}
}
}
catch (error) {
if (!silent)
throw error;
}
};
this.scan = function (collection) {
return tslib_1.__asyncGenerator(this, arguments, function* () {
var _a, e_2, _b, _c;
(0, util_2.assertType)(collection, 'scan', 'crudfs');
const [dir] = yield tslib_1.__await(this.getDir(collection, false));
try {
for (var _d = true, _e = tslib_1.__asyncValues(dir.entries()), _f; _f = yield tslib_1.__await(_e.next()), _a = _f.done, !_a; _d = true) {
_c = _f.value;
_d = false;
const [id, handle] = _c;
if (handle.kind === 'file') {
yield yield tslib_1.__await({
type: 'resource',
id,
});
}
else if (handle.kind === 'directory') {
yield yield tslib_1.__await({
type: 'collection',
id,
});
}
}
}
catch (e_2_1) { e_2 = { error: e_2_1 }; }
finally {
try {
if (!_d && !_a && (_b = _e.return)) yield tslib_1.__await(_b.call(_e));
}
finally { if (e_2) throw e_2.error; }
}
});
};
this.list = async (collection) => {
var _a, e_3, _b, _c;
const entries = [];
try {
for (var _d = true, _e = tslib_1.__asyncValues(this.scan(collection)), _f; _f = await _e.next(), _a = _f.done, !_a; _d = true) {
_c = _f.value;
_d = false;
const entry = _c;
entries.push(entry);
}
}
catch (e_3_1) { e_3 = { error: e_3_1 }; }
finally {
try {
if (!_d && !_a && (_b = _e.return)) await _b.call(_e);
}
finally { if (e_3) throw e_3.error; }
}
return entries;
};
this.from = async (collection) => {
(0, util_2.assertType)(collection, 'from', 'crudfs');
const [dir] = await this.getDir(collection, true);
return new FsaCrud(dir);
};
}
async getDir(collection, create) {
let parent = undefined;
let dir = await this.root;
try {
for (const name of collection) {
const child = await dir.getDirectoryHandle(name, { create });
parent = dir;
dir = child;
}
return [dir, parent];
}
catch (error) {
if (error.name === 'NotFoundError')
throw (0, util_3.newFolder404Error)(collection);
throw error;
}
}
async getFile(collection, id) {
const [dir] = await this.getDir(collection, false);
try {
const file = await dir.getFileHandle(id, { create: false });
return [dir, file];
}
catch (error) {
if (error.name === 'NotFoundError')
throw (0, util_3.newFile404Error)(collection, id);
throw error;
}
}
}
exports.FsaCrud = FsaCrud;
//# sourceMappingURL=FsaCrud.js.map
File diff suppressed because one or more lines are too long
+1
View File
@@ -0,0 +1 @@
export { FsaCrud } from './FsaCrud';
+6
View File
@@ -0,0 +1,6 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.FsaCrud = void 0;
var FsaCrud_1 = require("./FsaCrud");
Object.defineProperty(exports, "FsaCrud", { enumerable: true, get: function () { return FsaCrud_1.FsaCrud; } });
//# sourceMappingURL=index.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/fsa-to-crud/index.ts"],"names":[],"mappings":";;;AAAA,qCAAoC;AAA3B,kGAAA,OAAO,OAAA"}
+5
View File
@@ -0,0 +1,5 @@
import type * as crud from '../crud/types';
export declare const newFile404Error: (collection: crud.CrudCollection, id: string) => DOMException;
export declare const newFolder404Error: (collection: crud.CrudCollection) => DOMException;
export declare const newExistsError: () => DOMException;
export declare const newMissingError: () => DOMException;
+12
View File
@@ -0,0 +1,12 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.newMissingError = exports.newExistsError = exports.newFolder404Error = exports.newFile404Error = void 0;
const newFile404Error = (collection, id) => new DOMException(`Resource "${id}" in /${collection.join('/')} not found`, 'ResourceNotFound');
exports.newFile404Error = newFile404Error;
const newFolder404Error = (collection) => new DOMException(`Collection /${collection.join('/')} does not exist`, 'CollectionNotFound');
exports.newFolder404Error = newFolder404Error;
const newExistsError = () => new DOMException('Resource already exists', 'Exists');
exports.newExistsError = newExistsError;
const newMissingError = () => new DOMException('Resource is missing', 'Missing');
exports.newMissingError = newMissingError;
//# sourceMappingURL=util.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"util.js","sourceRoot":"","sources":["../../src/fsa-to-crud/util.ts"],"names":[],"mappings":";;;AAEO,MAAM,eAAe,GAAG,CAAC,UAA+B,EAAE,EAAU,EAAE,EAAE,CAC7E,IAAI,YAAY,CAAC,aAAa,EAAE,SAAS,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,kBAAkB,CAAC,CAAC;AADpF,QAAA,eAAe,mBACqE;AAE1F,MAAM,iBAAiB,GAAG,CAAC,UAA+B,EAAE,EAAE,CACnE,IAAI,YAAY,CAAC,eAAe,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,iBAAiB,EAAE,oBAAoB,CAAC,CAAC;AADlF,QAAA,iBAAiB,qBACiE;AAExF,MAAM,cAAc,GAAG,GAAG,EAAE,CAAC,IAAI,YAAY,CAAC,yBAAyB,EAAE,QAAQ,CAAC,CAAC;AAA7E,QAAA,cAAc,kBAA+D;AAEnF,MAAM,eAAe,GAAG,GAAG,EAAE,CAAC,IAAI,YAAY,CAAC,qBAAqB,EAAE,SAAS,CAAC,CAAC;AAA3E,QAAA,eAAe,mBAA4D"}
+33
View File
@@ -0,0 +1,33 @@
import { FsaNodeFsOpenFile } from './FsaNodeFsOpenFile';
import type * as fsa from '../fsa/types';
import type * as misc from '../node/types/misc';
import type { FsaNodeSyncAdapter } from './types';
export declare class FsaNodeCore {
protected readonly root: fsa.IFileSystemDirectoryHandle | Promise<fsa.IFileSystemDirectoryHandle>;
syncAdapter?: FsaNodeSyncAdapter | undefined;
protected static fd: number;
protected readonly fds: Map<number, FsaNodeFsOpenFile>;
constructor(root: fsa.IFileSystemDirectoryHandle | Promise<fsa.IFileSystemDirectoryHandle>, syncAdapter?: FsaNodeSyncAdapter | undefined);
protected getSyncAdapter(): FsaNodeSyncAdapter;
/**
* A list of reusable (opened and closed) file descriptors, that should be
* used first before creating a new file descriptor.
*/
releasedFds: number[];
protected newFdNumber(): number;
/**
* @param path Path from root to the new folder.
* @param create Whether to create the folders if they don't exist.
*/
protected getDir(path: string[], create: boolean, funcName?: string): Promise<fsa.IFileSystemDirectoryHandle>;
protected getFile(path: string[], name: string, funcName?: string, create?: boolean): Promise<fsa.IFileSystemFileHandle>;
protected getFileOrDir(path: string[], name: string, funcName?: string): Promise<fsa.IFileSystemFileHandle | fsa.IFileSystemDirectoryHandle>;
protected getFileByFd(fd: number, funcName?: string): FsaNodeFsOpenFile;
protected getFileByFdAsync(fd: number, funcName?: string): Promise<FsaNodeFsOpenFile>;
__getFileById(id: misc.TFileId, funcName?: string): Promise<fsa.IFileSystemFileHandle>;
protected getFileByIdOrCreate(id: misc.TFileId, funcName?: string): Promise<fsa.IFileSystemFileHandle>;
protected __open(filename: string, flags: number, mode: number): Promise<FsaNodeFsOpenFile>;
protected __open2(fsaFile: fsa.IFileSystemFileHandle, filename: string, flags: number, mode: number): FsaNodeFsOpenFile;
protected __close(fd: number): Promise<void>;
protected getFileName(id: misc.TFileId): string;
}
+190
View File
@@ -0,0 +1,190 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.FsaNodeCore = void 0;
const util_1 = require("../node/util");
const util_2 = require("./util");
const constants_1 = require("../node/constants");
const FsaNodeFsOpenFile_1 = require("./FsaNodeFsOpenFile");
const util = require("../node/util");
class FsaNodeCore {
constructor(root, syncAdapter) {
this.root = root;
this.syncAdapter = syncAdapter;
this.fds = new Map();
/**
* A list of reusable (opened and closed) file descriptors, that should be
* used first before creating a new file descriptor.
*/
this.releasedFds = [];
if (root instanceof Promise) {
root
.then(root => {
this.root = root;
})
.catch(error => { });
}
}
getSyncAdapter() {
const adapter = this.syncAdapter;
if (!adapter)
throw new Error('No sync adapter');
return adapter;
}
newFdNumber() {
const releasedFd = this.releasedFds.pop();
return typeof releasedFd === 'number' ? releasedFd : FsaNodeCore.fd--;
}
/**
* @param path Path from root to the new folder.
* @param create Whether to create the folders if they don't exist.
*/
async getDir(path, create, funcName) {
let curr = await this.root;
const options = { create };
try {
for (const name of path) {
curr = await curr.getDirectoryHandle(name, options);
}
}
catch (error) {
if (error && typeof error === 'object') {
switch (error.name) {
case 'TypeMismatchError':
throw (0, util_1.createError)('ENOTDIR', funcName, path.join("/" /* FsaToNodeConstants.Separator */));
case 'NotFoundError':
throw (0, util_1.createError)('ENOENT', funcName, path.join("/" /* FsaToNodeConstants.Separator */));
}
}
throw error;
}
return curr;
}
async getFile(path, name, funcName, create) {
const dir = await this.getDir(path, false, funcName);
const file = await dir.getFileHandle(name, { create });
return file;
}
async getFileOrDir(path, name, funcName) {
const dir = await this.getDir(path, false, funcName);
if (!name)
return dir;
try {
const file = await dir.getFileHandle(name);
return file;
}
catch (error) {
if (error && typeof error === 'object') {
switch (error.name) {
case 'TypeMismatchError':
try {
return await dir.getDirectoryHandle(name);
}
catch (error2) {
if (error2 && typeof error2 === 'object') {
switch (error2.name) {
case 'TypeMismatchError':
throw (0, util_1.createError)('ENOTDIR', funcName, path.join("/" /* FsaToNodeConstants.Separator */));
case 'NotFoundError':
throw (0, util_1.createError)('ENOENT', funcName, path.join("/" /* FsaToNodeConstants.Separator */));
}
}
}
case 'NotFoundError':
throw (0, util_1.createError)('ENOENT', funcName, path.join("/" /* FsaToNodeConstants.Separator */));
}
}
throw error;
}
}
getFileByFd(fd, funcName) {
if (!(0, util_1.isFd)(fd))
throw TypeError(constants_1.ERRSTR.FD);
const file = this.fds.get(fd);
if (!file)
throw (0, util_1.createError)('EBADF', funcName);
return file;
}
async getFileByFdAsync(fd, funcName) {
return this.getFileByFd(fd, funcName);
}
async __getFileById(id, funcName) {
if (typeof id === 'number')
return (await this.getFileByFd(id, funcName)).file;
const filename = (0, util_1.pathToFilename)(id);
const [folder, name] = (0, util_2.pathToLocation)(filename);
return await this.getFile(folder, name, funcName);
}
async getFileByIdOrCreate(id, funcName) {
if (typeof id === 'number')
return (await this.getFileByFd(id, funcName)).file;
const filename = (0, util_1.pathToFilename)(id);
const [folder, name] = (0, util_2.pathToLocation)(filename);
const dir = await this.getDir(folder, false, funcName);
return await dir.getFileHandle(name, { create: true });
}
async __open(filename, flags, mode) {
const [folder, name] = (0, util_2.pathToLocation)(filename);
const throwIfExists = !!(flags & 128 /* FLAG.O_EXCL */);
if (throwIfExists) {
try {
await this.getFile(folder, name, 'open', false);
throw util.createError('EEXIST', 'writeFile');
}
catch (error) {
const file404 = error && typeof error === 'object' && (error.code === 'ENOENT' || error.name === 'NotFoundError');
if (!file404) {
if (error && typeof error === 'object') {
switch (error.name) {
case 'TypeMismatchError':
throw (0, util_1.createError)('ENOTDIR', 'open', filename);
case 'NotFoundError':
throw (0, util_1.createError)('ENOENT', 'open', filename);
}
}
throw error;
}
}
}
try {
const createIfMissing = !!(flags & 64 /* FLAG.O_CREAT */);
const fsaFile = await this.getFile(folder, name, 'open', createIfMissing);
return this.__open2(fsaFile, filename, flags, mode);
}
catch (error) {
if (error && typeof error === 'object') {
switch (error.name) {
case 'TypeMismatchError':
throw (0, util_1.createError)('ENOTDIR', 'open', filename);
case 'NotFoundError':
throw (0, util_1.createError)('ENOENT', 'open', filename);
}
}
throw error;
}
}
__open2(fsaFile, filename, flags, mode) {
const fd = this.newFdNumber();
const file = new FsaNodeFsOpenFile_1.FsaNodeFsOpenFile(fd, mode, flags, fsaFile, filename);
this.fds.set(fd, file);
return file;
}
async __close(fd) {
const openFile = await this.getFileByFdAsync(fd, 'close');
await openFile.close();
const deleted = this.fds.delete(fd);
if (deleted)
this.releasedFds.push(fd);
}
getFileName(id) {
if (typeof id === 'number') {
const openFile = this.fds.get(id);
if (!openFile)
throw (0, util_1.createError)('EBADF', 'readFile');
return openFile.filename;
}
return (0, util_1.pathToFilename)(id);
}
}
exports.FsaNodeCore = FsaNodeCore;
FsaNodeCore.fd = 0x7fffffff;
//# sourceMappingURL=FsaNodeCore.js.map
File diff suppressed because one or more lines are too long
+13
View File
@@ -0,0 +1,13 @@
import type { IDirent, TDataOut } from '../node/types/misc';
export declare class FsaNodeDirent implements IDirent {
readonly name: TDataOut;
protected readonly kind: 'file' | 'directory';
constructor(name: TDataOut, kind: 'file' | 'directory');
isDirectory(): boolean;
isFile(): boolean;
isBlockDevice(): boolean;
isCharacterDevice(): boolean;
isSymbolicLink(): boolean;
isFIFO(): boolean;
isSocket(): boolean;
}
+32
View File
@@ -0,0 +1,32 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.FsaNodeDirent = void 0;
class FsaNodeDirent {
constructor(name, kind) {
this.name = name;
this.kind = kind;
}
isDirectory() {
return this.kind === 'directory';
}
isFile() {
return this.kind === 'file';
}
isBlockDevice() {
return false;
}
isCharacterDevice() {
return false;
}
isSymbolicLink() {
return false;
}
isFIFO() {
return false;
}
isSocket() {
return false;
}
}
exports.FsaNodeDirent = FsaNodeDirent;
//# sourceMappingURL=FsaNodeDirent.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"FsaNodeDirent.js","sourceRoot":"","sources":["../../src/fsa-to-node/FsaNodeDirent.ts"],"names":[],"mappings":";;;AAEA,MAAa,aAAa;IACxB,YACkB,IAAc,EACX,IAA0B;QAD7B,SAAI,GAAJ,IAAI,CAAU;QACX,SAAI,GAAJ,IAAI,CAAsB;IAC5C,CAAC;IAEG,WAAW;QAChB,OAAO,IAAI,CAAC,IAAI,KAAK,WAAW,CAAC;IACnC,CAAC;IAEM,MAAM;QACX,OAAO,IAAI,CAAC,IAAI,KAAK,MAAM,CAAC;IAC9B,CAAC;IAEM,aAAa;QAClB,OAAO,KAAK,CAAC;IACf,CAAC;IAEM,iBAAiB;QACtB,OAAO,KAAK,CAAC;IACf,CAAC;IAEM,cAAc;QACnB,OAAO,KAAK,CAAC;IACf,CAAC;IAEM,MAAM;QACX,OAAO,KAAK,CAAC;IACf,CAAC;IAEM,QAAQ;QACb,OAAO,KAAK,CAAC;IACf,CAAC;CACF;AAjCD,sCAiCC"}
+184
View File
@@ -0,0 +1,184 @@
import { FsaNodeDirent } from './FsaNodeDirent';
import { FsaNodeStats } from './FsaNodeStats';
import { FsSynchronousApi } from '../node/types/FsSynchronousApi';
import { FsaNodeWriteStream } from './FsaNodeWriteStream';
import { FsaNodeReadStream } from './FsaNodeReadStream';
import { FsaNodeCore } from './FsaNodeCore';
import type { FsCallbackApi, FsPromisesApi } from '../node/types';
import type { FsCommonObjects } from '../node/types/FsCommonObjects';
/**
* Constructs a Node.js `fs` API from a File System Access API
* [`FileSystemDirectoryHandle` object](https://developer.mozilla.org/en-US/docs/Web/API/FileSystemDirectoryHandle).
*/
export declare class FsaNodeFs extends FsaNodeCore implements FsCallbackApi, FsSynchronousApi, FsCommonObjects {
readonly promises: FsPromisesApi;
readonly open: FsCallbackApi['open'];
readonly close: FsCallbackApi['close'];
readonly read: FsCallbackApi['read'];
readonly readFile: FsCallbackApi['readFile'];
readonly write: FsCallbackApi['write'];
readonly writev: FsCallbackApi['writev'];
readonly writeFile: FsCallbackApi['writeFile'];
readonly copyFile: FsCallbackApi['copyFile'];
/**
* @todo There is a proposal for native "self remove" operation.
* @see https://github.com/whatwg/fs/blob/main/proposals/Remove.md
*/
readonly unlink: FsCallbackApi['unlink'];
readonly realpath: FsCallbackApi['realpath'];
readonly stat: FsCallbackApi['stat'];
readonly lstat: FsCallbackApi['lstat'];
readonly fstat: FsCallbackApi['fstat'];
private getHandleStats;
/**
* @todo There is a proposal for native move support.
* @see https://github.com/whatwg/fs/blob/main/proposals/MovingNonOpfsFiles.md
*/
readonly rename: FsCallbackApi['rename'];
readonly exists: FsCallbackApi['exists'];
readonly access: FsCallbackApi['access'];
readonly appendFile: FsCallbackApi['appendFile'];
readonly readdir: FsCallbackApi['readdir'];
readonly readlink: FsCallbackApi['readlink'];
/** @todo Could this use `FileSystemSyncAccessHandle.flush` through a Worker thread? */
readonly fsync: FsCallbackApi['fsync'];
readonly fdatasync: FsCallbackApi['fdatasync'];
readonly ftruncate: FsCallbackApi['ftruncate'];
readonly truncate: FsCallbackApi['truncate'];
readonly futimes: FsCallbackApi['futimes'];
readonly utimes: FsCallbackApi['utimes'];
readonly mkdir: FsCallbackApi['mkdir'];
readonly mkdtemp: FsCallbackApi['mkdtemp'];
private rmAll;
readonly rmdir: FsCallbackApi['rmdir'];
readonly rm: FsCallbackApi['rm'];
readonly fchmod: FsCallbackApi['fchmod'];
readonly chmod: FsCallbackApi['chmod'];
readonly lchmod: FsCallbackApi['lchmod'];
readonly fchown: FsCallbackApi['fchown'];
readonly chown: FsCallbackApi['chown'];
readonly lchown: FsCallbackApi['lchown'];
readonly createWriteStream: FsCallbackApi['createWriteStream'];
readonly createReadStream: FsCallbackApi['createReadStream'];
readonly cp: FsCallbackApi['cp'];
readonly lutimes: FsCallbackApi['lutimes'];
readonly openAsBlob: FsCallbackApi['openAsBlob'];
readonly opendir: FsCallbackApi['opendir'];
readonly readv: FsCallbackApi['readv'];
readonly statfs: FsCallbackApi['statfs'];
/**
* @todo Watchers could be implemented in the future on top of `FileSystemObserver`,
* which is currently a proposal.
* @see https://github.com/whatwg/fs/blob/main/proposals/FileSystemObserver.md
*/
readonly watchFile: FsCallbackApi['watchFile'];
readonly unwatchFile: FsCallbackApi['unwatchFile'];
readonly watch: FsCallbackApi['watch'];
readonly symlink: FsCallbackApi['symlink'];
readonly link: FsCallbackApi['link'];
readonly statSync: FsSynchronousApi['statSync'];
readonly lstatSync: FsSynchronousApi['lstatSync'];
readonly fstatSync: FsSynchronousApi['fstatSync'];
readonly accessSync: FsSynchronousApi['accessSync'];
readonly readFileSync: FsSynchronousApi['readFileSync'];
readonly writeFileSync: FsSynchronousApi['writeFileSync'];
readonly appendFileSync: FsSynchronousApi['appendFileSync'];
readonly closeSync: FsSynchronousApi['closeSync'];
readonly existsSync: FsSynchronousApi['existsSync'];
readonly copyFileSync: FsSynchronousApi['copyFileSync'];
readonly renameSync: FsSynchronousApi['renameSync'];
readonly rmdirSync: FsSynchronousApi['rmdirSync'];
readonly rmSync: FsSynchronousApi['rmSync'];
readonly mkdirSync: FsSynchronousApi['mkdirSync'];
readonly mkdtempSync: FsSynchronousApi['mkdtempSync'];
readonly readlinkSync: FsSynchronousApi['readlinkSync'];
readonly truncateSync: FsSynchronousApi['truncateSync'];
readonly ftruncateSync: FsSynchronousApi['ftruncateSync'];
readonly unlinkSync: FsSynchronousApi['unlinkSync'];
readonly readdirSync: FsSynchronousApi['readdirSync'];
readonly realpathSync: FsSynchronousApi['realpathSync'];
readonly readSync: FsSynchronousApi['readSync'];
readonly writeSync: FsSynchronousApi['writeSync'];
readonly openSync: FsSynchronousApi['openSync'];
readonly writevSync: FsSynchronousApi['writevSync'];
readonly fdatasyncSync: FsSynchronousApi['fdatasyncSync'];
readonly fsyncSync: FsSynchronousApi['fsyncSync'];
readonly chmodSync: FsSynchronousApi['chmodSync'];
readonly chownSync: FsSynchronousApi['chownSync'];
readonly fchmodSync: FsSynchronousApi['fchmodSync'];
readonly fchownSync: FsSynchronousApi['fchownSync'];
readonly futimesSync: FsSynchronousApi['futimesSync'];
readonly lchmodSync: FsSynchronousApi['lchmodSync'];
readonly lchownSync: FsSynchronousApi['lchownSync'];
readonly utimesSync: FsSynchronousApi['utimesSync'];
readonly lutimesSync: FsSynchronousApi['lutimesSync'];
readonly cpSync: FsSynchronousApi['cpSync'];
readonly opendirSync: FsSynchronousApi['opendirSync'];
readonly statfsSync: FsSynchronousApi['statfsSync'];
readonly readvSync: FsSynchronousApi['readvSync'];
readonly symlinkSync: FsSynchronousApi['symlinkSync'];
readonly linkSync: FsSynchronousApi['linkSync'];
readonly F_OK: number;
readonly R_OK: number;
readonly W_OK: number;
readonly X_OK: number;
readonly constants: {
O_RDONLY: number;
O_WRONLY: number;
O_RDWR: number;
S_IFMT: number;
S_IFREG: number;
S_IFDIR: number;
S_IFCHR: number;
S_IFBLK: number;
S_IFIFO: number;
S_IFLNK: number;
S_IFSOCK: number;
O_CREAT: number;
O_EXCL: number;
O_NOCTTY: number;
O_TRUNC: number;
O_APPEND: number;
O_DIRECTORY: number;
O_NOATIME: number;
O_NOFOLLOW: number;
O_SYNC: number;
O_SYMLINK: number;
O_DIRECT: number;
O_NONBLOCK: number;
S_IRWXU: number;
S_IRUSR: number;
S_IWUSR: number;
S_IXUSR: number;
S_IRWXG: number;
S_IRGRP: number;
S_IWGRP: number;
S_IXGRP: number;
S_IRWXO: number;
S_IROTH: number;
S_IWOTH: number;
S_IXOTH: number;
F_OK: number;
R_OK: number;
W_OK: number;
X_OK: number;
UV_FS_SYMLINK_DIR: number;
UV_FS_SYMLINK_JUNCTION: number;
UV_FS_COPYFILE_EXCL: number;
UV_FS_COPYFILE_FICLONE: number;
UV_FS_COPYFILE_FICLONE_FORCE: number;
COPYFILE_EXCL: number;
COPYFILE_FICLONE: number;
COPYFILE_FICLONE_FORCE: number;
};
readonly Dirent: typeof FsaNodeDirent;
readonly Stats: {
new (isBigInt: boolean, size: any, kind: "file" | "directory"): FsaNodeStats<any>;
};
readonly WriteStream: typeof FsaNodeWriteStream;
readonly ReadStream: typeof FsaNodeReadStream;
readonly StatFs: any;
readonly Dir: any;
readonly StatsWatcher: any;
readonly FSWatcher: any;
}
+856
View File
@@ -0,0 +1,856 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.FsaNodeFs = void 0;
const tslib_1 = require("tslib");
const optHelpers = require("../node/options");
const util = require("../node/util");
const buffer_1 = require("../internal/buffer");
const FsPromises_1 = require("../node/FsPromises");
const util_1 = require("./util");
const constants_1 = require("../node/constants");
const encoding_1 = require("../encoding");
const FsaNodeDirent_1 = require("./FsaNodeDirent");
const constants_2 = require("../constants");
const FsaNodeStats_1 = require("./FsaNodeStats");
const queueMicrotask_1 = require("../queueMicrotask");
const FsaNodeWriteStream_1 = require("./FsaNodeWriteStream");
const FsaNodeReadStream_1 = require("./FsaNodeReadStream");
const FsaNodeCore_1 = require("./FsaNodeCore");
const FileHandle_1 = require("../node/FileHandle");
const notSupported = () => {
throw new Error('Method not supported by the File System Access API.');
};
const notImplemented = () => {
throw new Error('Not implemented');
};
const noop = () => { };
/**
* Constructs a Node.js `fs` API from a File System Access API
* [`FileSystemDirectoryHandle` object](https://developer.mozilla.org/en-US/docs/Web/API/FileSystemDirectoryHandle).
*/
class FsaNodeFs extends FsaNodeCore_1.FsaNodeCore {
constructor() {
// ------------------------------------------------------------ FsPromisesApi
super(...arguments);
this.promises = new FsPromises_1.FsPromises(this, FileHandle_1.FileHandle);
// ------------------------------------------------------------ FsCallbackApi
this.open = (path, flags, a, b) => {
let mode = a;
let callback = b;
if (typeof a === 'function') {
mode = 438 /* MODE.DEFAULT */;
callback = a;
}
mode = mode || 438 /* MODE.DEFAULT */;
const modeNum = util.modeToNumber(mode);
const filename = util.pathToFilename(path);
const flagsNum = util.flagsToNumber(flags);
this.__open(filename, flagsNum, modeNum).then(openFile => callback(null, openFile.fd), error => callback(error));
};
this.close = (fd, callback) => {
util.validateFd(fd);
this.__close(fd).then(() => callback(null), error => callback(error));
};
this.read = (fd, buffer, offset, length, position, callback) => {
util.validateCallback(callback);
// This `if` branch is from Node.js
if (length === 0) {
return (0, queueMicrotask_1.default)(() => {
if (callback)
callback(null, 0, buffer);
});
}
(async () => {
const openFile = await this.getFileByFd(fd, 'read');
const file = await openFile.file.getFile();
const src = await file.arrayBuffer();
const slice = new Uint8Array(src, Number(position), Number(length));
const dest = new Uint8Array(buffer.buffer, buffer.byteOffset + offset, slice.length);
dest.set(slice, 0);
return slice.length;
})().then(bytesWritten => callback(null, bytesWritten, buffer), error => callback(error));
};
this.readFile = (id, a, b) => {
const [opts, callback] = optHelpers.optsAndCbGenerator(optHelpers.getReadFileOptions)(a, b);
const flagsNum = util.flagsToNumber(opts.flag);
(async () => {
let fd = typeof id === 'number' ? id : -1;
const originalFd = fd;
try {
if (fd === -1) {
const filename = util.pathToFilename(id);
fd = (await this.__open(filename, flagsNum, 0)).fd;
}
const handle = await this.__getFileById(fd, 'readFile');
const file = await handle.getFile();
const buffer = buffer_1.Buffer.from(await file.arrayBuffer());
return util.bufferToEncoding(buffer, opts.encoding);
}
finally {
try {
const idWasFd = typeof originalFd === 'number' && originalFd >= 0;
if (idWasFd)
await this.__close(originalFd);
}
catch (_a) { }
}
})()
.then(data => callback(null, data))
.catch(error => callback(error));
};
this.write = (fd, a, b, c, d, e) => {
const [, asStr, buf, offset, length, position, cb] = util.getWriteArgs(fd, a, b, c, d, e);
(async () => {
const openFile = await this.getFileByFd(fd, 'write');
const data = buf.subarray(offset, offset + length);
await openFile.write(data, position);
return length;
})().then(bytesWritten => cb(null, bytesWritten, asStr ? a : buf), error => cb(error));
};
this.writev = (fd, buffers, a, b) => {
util.validateFd(fd);
let position = null;
let callback;
if (typeof a === 'function') {
callback = a;
}
else {
position = Number(a);
callback = b;
}
util.validateCallback(callback);
(async () => {
const openFile = await this.getFileByFd(fd, 'writev');
const length = buffers.length;
let bytesWritten = 0;
for (let i = 0; i < length; i++) {
const data = buffers[i];
await openFile.write(data, position);
bytesWritten += data.byteLength;
position = null;
}
return bytesWritten;
})().then(bytesWritten => callback(null, bytesWritten, buffers), error => callback(error));
};
this.writeFile = (id, data, a, b) => {
let options = a;
let callback = b;
if (typeof a === 'function') {
options = optHelpers.writeFileDefaults;
callback = a;
}
const cb = util.validateCallback(callback);
const opts = optHelpers.getWriteFileOptions(options);
const flagsNum = util.flagsToNumber(opts.flag);
const modeNum = util.modeToNumber(opts.mode);
const buf = util.dataToBuffer(data, opts.encoding);
(async () => {
let fd = typeof id === 'number' ? id : -1;
const originalFd = fd;
try {
if (fd === -1) {
const filename = util.pathToFilename(id);
fd = (await this.__open(filename, flagsNum, modeNum)).fd;
}
const file = await this.__getFileById(fd, 'writeFile');
const writable = await file.createWritable({ keepExistingData: false });
await writable.write(buf);
await writable.close();
}
finally {
try {
const idWasFd = typeof originalFd === 'number' && originalFd >= 0;
if (idWasFd)
await this.__close(originalFd);
}
catch (_a) { }
}
})().then(() => cb(null), error => cb(error));
};
this.copyFile = (src, dest, a, b) => {
const srcFilename = util.pathToFilename(src);
const destFilename = util.pathToFilename(dest);
let flags;
let callback;
if (typeof a === 'function') {
flags = 0;
callback = a;
}
else {
flags = a;
callback = b;
}
util.validateCallback(callback);
const [oldFolder, oldName] = (0, util_1.pathToLocation)(srcFilename);
const [newFolder, newName] = (0, util_1.pathToLocation)(destFilename);
(async () => {
const oldFile = await this.getFile(oldFolder, oldName, 'copyFile');
const newDir = await this.getDir(newFolder, false, 'copyFile');
const newFile = await newDir.getFileHandle(newName, { create: true });
const writable = await newFile.createWritable({ keepExistingData: false });
const oldData = await oldFile.getFile();
await writable.write(await oldData.arrayBuffer());
await writable.close();
})().then(() => callback(null), error => callback(error));
};
/**
* @todo There is a proposal for native "self remove" operation.
* @see https://github.com/whatwg/fs/blob/main/proposals/Remove.md
*/
this.unlink = (path, callback) => {
const filename = util.pathToFilename(path);
const [folder, name] = (0, util_1.pathToLocation)(filename);
this.getDir(folder, false, 'unlink')
.then(dir => dir.removeEntry(name))
.then(() => callback(null), error => {
if (error && typeof error === 'object') {
switch (error.name) {
case 'NotFoundError': {
callback(util.createError('ENOENT', 'unlink', filename));
return;
}
case 'InvalidModificationError': {
callback(util.createError('EISDIR', 'unlink', filename));
return;
}
}
}
callback(error);
});
};
this.realpath = (path, a, b) => {
const [opts, callback] = optHelpers.getRealpathOptsAndCb(a, b);
let pathFilename = util.pathToFilename(path);
if (pathFilename[0] !== "/" /* FsaToNodeConstants.Separator */)
pathFilename = "/" /* FsaToNodeConstants.Separator */ + pathFilename;
callback(null, (0, encoding_1.strToEncoding)(pathFilename, opts.encoding));
};
this.stat = (path, a, b) => {
const [{ bigint = false, throwIfNoEntry = true }, callback] = optHelpers.getStatOptsAndCb(a, b);
const filename = util.pathToFilename(path);
const [folder, name] = (0, util_1.pathToLocation)(filename);
(async () => {
const handle = await this.getFileOrDir(folder, name, 'stat');
return await this.getHandleStats(bigint, handle);
})().then(stats => callback(null, stats), error => callback(error));
};
this.lstat = this.stat;
this.fstat = (fd, a, b) => {
const [{ bigint = false, throwIfNoEntry = true }, callback] = optHelpers.getStatOptsAndCb(a, b);
(async () => {
const openFile = await this.getFileByFd(fd, 'fstat');
return await this.getHandleStats(bigint, openFile.file);
})().then(stats => callback(null, stats), error => callback(error));
};
/**
* @todo There is a proposal for native move support.
* @see https://github.com/whatwg/fs/blob/main/proposals/MovingNonOpfsFiles.md
*/
this.rename = (oldPath, newPath, callback) => {
const oldPathFilename = util.pathToFilename(oldPath);
const newPathFilename = util.pathToFilename(newPath);
const [oldFolder, oldName] = (0, util_1.pathToLocation)(oldPathFilename);
const [newFolder, newName] = (0, util_1.pathToLocation)(newPathFilename);
(async () => {
const oldFile = await this.getFile(oldFolder, oldName, 'rename');
const newDir = await this.getDir(newFolder, false, 'rename');
const newFile = await newDir.getFileHandle(newName, { create: true });
const writable = await newFile.createWritable({ keepExistingData: false });
const oldData = await oldFile.getFile();
await writable.write(await oldData.arrayBuffer());
await writable.close();
const oldDir = await this.getDir(oldFolder, false, 'rename');
await oldDir.removeEntry(oldName);
})().then(() => callback(null), error => callback(error));
};
this.exists = (path, callback) => {
const filename = util.pathToFilename(path);
if (typeof callback !== 'function')
throw Error(constants_1.ERRSTR.CB);
this.access(path, 0 /* AMODE.F_OK */, error => callback(!error));
};
this.access = (path, a, b) => {
let mode = 0 /* AMODE.F_OK */;
let callback;
if (typeof a !== 'function') {
mode = a | 0; // cast to number
callback = util.validateCallback(b);
}
else {
callback = a;
}
const filename = util.pathToFilename(path);
const [folder, name] = (0, util_1.pathToLocation)(filename);
(async () => {
const node = folder.length || name ? await this.getFileOrDir(folder, name, 'access') : await this.root;
const checkIfCanExecute = mode & 1 /* AMODE.X_OK */;
if (checkIfCanExecute)
throw util.createError('EACCESS', 'access', filename);
const checkIfCanWrite = mode & 2 /* AMODE.W_OK */;
switch (node.kind) {
case 'file': {
if (checkIfCanWrite) {
try {
const file = node;
const writable = await file.createWritable();
await writable.close();
}
catch (_a) {
throw util.createError('EACCESS', 'access', filename);
}
}
break;
}
case 'directory': {
if (checkIfCanWrite) {
const dir = node;
const canWrite = await (0, util_1.testDirectoryIsWritable)(dir);
if (!canWrite)
throw util.createError('EACCESS', 'access', filename);
}
break;
}
default: {
throw util.createError('EACCESS', 'access', filename);
}
}
})().then(() => callback(null), error => callback(error));
};
this.appendFile = (id, data, a, b) => {
const [opts, callback] = optHelpers.getAppendFileOptsAndCb(a, b);
const buffer = util.dataToBuffer(data, opts.encoding);
this.getFileByIdOrCreate(id, 'appendFile')
.then(file => (async () => {
const blob = await file.getFile();
const writable = await file.createWritable({ keepExistingData: true });
await writable.write({
type: 'write',
data: buffer,
position: blob.size,
});
await writable.close();
})())
.then(() => callback(null), error => callback(error));
};
this.readdir = (path, a, b) => {
const [options, callback] = optHelpers.getReaddirOptsAndCb(a, b);
const filename = util.pathToFilename(path);
const [folder, name] = (0, util_1.pathToLocation)(filename);
if (name)
folder.push(name);
this.getDir(folder, false, 'readdir')
.then(dir => (async () => {
var _a, e_1, _b, _c, _d, e_2, _e, _f;
if (options.withFileTypes) {
const list = [];
try {
for (var _g = true, _h = tslib_1.__asyncValues(dir.entries()), _j; _j = await _h.next(), _a = _j.done, !_a; _g = true) {
_c = _j.value;
_g = false;
const [name, handle] = _c;
const dirent = new FsaNodeDirent_1.FsaNodeDirent(name, handle.kind);
list.push(dirent);
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (!_g && !_a && (_b = _h.return)) await _b.call(_h);
}
finally { if (e_1) throw e_1.error; }
}
if (!util.isWin && options.encoding !== 'buffer')
list.sort((a, b) => {
if (a.name < b.name)
return -1;
if (a.name > b.name)
return 1;
return 0;
});
return list;
}
else {
const list = [];
try {
for (var _k = true, _l = tslib_1.__asyncValues(dir.keys()), _m; _m = await _l.next(), _d = _m.done, !_d; _k = true) {
_f = _m.value;
_k = false;
const key = _f;
list.push(key);
}
}
catch (e_2_1) { e_2 = { error: e_2_1 }; }
finally {
try {
if (!_k && !_d && (_e = _l.return)) await _e.call(_l);
}
finally { if (e_2) throw e_2.error; }
}
if (!util.isWin && options.encoding !== 'buffer')
list.sort();
return list;
}
})())
.then(res => callback(null, res), err => callback(err));
};
this.readlink = (path, a, b) => {
const [opts, callback] = optHelpers.getDefaultOptsAndCb(a, b);
const filename = util.pathToFilename(path);
const buffer = buffer_1.Buffer.from(filename);
callback(null, util.bufferToEncoding(buffer, opts.encoding));
};
/** @todo Could this use `FileSystemSyncAccessHandle.flush` through a Worker thread? */
this.fsync = (fd, callback) => {
callback(null);
};
this.fdatasync = (fd, callback) => {
callback(null);
};
this.ftruncate = (fd, a, b) => {
const len = typeof a === 'number' ? a : 0;
const callback = util.validateCallback(typeof a === 'number' ? b : a);
this.getFileByFdAsync(fd)
.then(file => file.file.createWritable({ keepExistingData: true }))
.then(writable => writable.truncate(len).then(() => writable.close()))
.then(() => callback(null), error => callback(error));
};
this.truncate = (path, a, b) => {
const len = typeof a === 'number' ? a : 0;
const callback = util.validateCallback(typeof a === 'number' ? b : a);
this.open(path, 'r+', (error, fd) => {
if (error)
callback(error);
else {
this.ftruncate(fd, len, error => {
if (error)
this.close(fd, () => callback(error));
else
this.close(fd, callback);
});
}
});
};
this.futimes = (fd, atime, mtime, callback) => {
callback(null);
};
this.utimes = (path, atime, mtime, callback) => {
callback(null);
};
this.mkdir = (path, a, b) => {
var _a;
const opts = optHelpers.getMkdirOptions(a);
const callback = util.validateCallback(typeof a === 'function' ? a : b);
// const modeNum = modeToNumber(opts.mode, 0o777);
const filename = util.pathToFilename(path);
const [folder, name] = (0, util_1.pathToLocation)(filename);
// TODO: need to throw if directory already exists
this.getDir(folder, (_a = opts.recursive) !== null && _a !== void 0 ? _a : false)
.then(dir => dir.getDirectoryHandle(name, { create: true }))
.then(() => callback(null), error => {
if (error && typeof error === 'object') {
switch (error.name) {
case 'NotFoundError': {
const err = util.createError('ENOENT', 'mkdir', folder.join('/'));
callback(err);
return;
}
}
}
callback(error);
});
};
this.mkdtemp = (prefix, a, b) => {
const [{ encoding }, callback] = optHelpers.getDefaultOptsAndCb(a, b);
if (!prefix || typeof prefix !== 'string')
throw new TypeError('filename prefix is required');
if (!util.nullCheck(prefix))
return;
const filename = prefix + util.genRndStr6();
this.mkdir(filename, 511 /* MODE.DIR */, err => {
if (err)
callback(err);
else
callback(null, (0, encoding_1.strToEncoding)(filename, encoding));
});
};
this.rmdir = (path, a, b) => {
const options = optHelpers.getRmdirOptions(a);
const callback = util.validateCallback(typeof a === 'function' ? a : b);
const [folder, name] = (0, util_1.pathToLocation)(util.pathToFilename(path));
if (!name && options.recursive)
return this.rmAll(callback);
this.getDir(folder, false, 'rmdir')
.then(dir => dir.getDirectoryHandle(name).then(() => dir))
.then(dir => { var _a; return dir.removeEntry(name, { recursive: (_a = options.recursive) !== null && _a !== void 0 ? _a : false }); })
.then(() => callback(null), error => {
if (error && typeof error === 'object') {
switch (error.name) {
case 'NotFoundError': {
const err = util.createError('ENOENT', 'rmdir', folder.join('/'));
callback(err);
return;
}
case 'InvalidModificationError': {
const err = util.createError('ENOTEMPTY', 'rmdir', folder.join('/'));
callback(err);
return;
}
}
}
callback(error);
});
};
this.rm = (path, a, b) => {
const [options, callback] = optHelpers.getRmOptsAndCb(a, b);
const [folder, name] = (0, util_1.pathToLocation)(util.pathToFilename(path));
if (!name && options.recursive)
return this.rmAll(callback);
this.getDir(folder, false, 'rmdir')
.then(dir => { var _a; return dir.removeEntry(name, { recursive: (_a = options.recursive) !== null && _a !== void 0 ? _a : false }); })
.then(() => callback(null), error => {
if (options.force) {
callback(null);
return;
}
if (error && typeof error === 'object') {
switch (error.name) {
case 'NotFoundError': {
const err = util.createError('ENOENT', 'rmdir', folder.join('/'));
callback(err);
return;
}
case 'InvalidModificationError': {
const err = util.createError('ENOTEMPTY', 'rmdir', folder.join('/'));
callback(err);
return;
}
}
}
callback(error);
});
};
this.fchmod = (fd, mode, callback) => {
callback(null);
};
this.chmod = (path, mode, callback) => {
callback(null);
};
this.lchmod = (path, mode, callback) => {
callback(null);
};
this.fchown = (fd, uid, gid, callback) => {
callback(null);
};
this.chown = (path, uid, gid, callback) => {
callback(null);
};
this.lchown = (path, uid, gid, callback) => {
callback(null);
};
this.createWriteStream = (path, options) => {
var _a;
const defaults = {
encoding: 'utf8',
flags: 'w',
autoClose: true,
emitClose: true,
};
const optionsObj = optHelpers.getOptions(defaults, options);
const filename = util.pathToFilename(path);
const flags = util.flagsToNumber((_a = optionsObj.flags) !== null && _a !== void 0 ? _a : 'w');
const fd = optionsObj.fd ? (typeof optionsObj.fd === 'number' ? optionsObj.fd : optionsObj.fd.fd) : 0;
const handle = fd ? this.getFileByFdAsync(fd) : this.__open(filename, flags, 0);
const stream = new FsaNodeWriteStream_1.FsaNodeWriteStream(handle, filename, optionsObj);
if (optionsObj.autoClose) {
stream.once('finish', () => {
handle.then(file => this.close(file.fd, () => { }));
});
stream.once('error', () => {
handle.then(file => this.close(file.fd, () => { }));
});
}
return stream;
};
this.createReadStream = (path, options) => {
const defaults = {
flags: 'r',
fd: null,
mode: 0o666,
autoClose: true,
emitClose: true,
start: 0,
end: Infinity,
highWaterMark: 64 * 1024,
fs: null,
signal: null,
};
const optionsObj = optHelpers.getOptions(defaults, options);
const filename = util.pathToFilename(path);
const flags = util.flagsToNumber(optionsObj.flags);
const fd = optionsObj.fd ? (typeof optionsObj.fd === 'number' ? optionsObj.fd : optionsObj.fd.fd) : 0;
const handle = fd ? this.getFileByFdAsync(fd) : this.__open(filename, flags, 0);
const stream = new FsaNodeReadStream_1.FsaNodeReadStream(this, handle, filename, optionsObj);
return stream;
};
this.cp = notImplemented;
this.lutimes = notImplemented;
this.openAsBlob = notImplemented;
this.opendir = notImplemented;
this.readv = notImplemented;
this.statfs = notImplemented;
/**
* @todo Watchers could be implemented in the future on top of `FileSystemObserver`,
* which is currently a proposal.
* @see https://github.com/whatwg/fs/blob/main/proposals/FileSystemObserver.md
*/
this.watchFile = notSupported;
this.unwatchFile = notSupported;
this.watch = notSupported;
this.symlink = notSupported;
this.link = notSupported;
// --------------------------------------------------------- FsSynchronousApi
this.statSync = (path, options) => {
var _a;
const { bigint = true, throwIfNoEntry = true } = optHelpers.getStatOptions(options);
const filename = util.pathToFilename(path);
const location = (0, util_1.pathToLocation)(filename);
const adapter = this.getSyncAdapter();
const res = adapter.call('stat', location);
const stats = new FsaNodeStats_1.FsaNodeStats(bigint, (_a = res.size) !== null && _a !== void 0 ? _a : 0, res.kind);
return stats;
};
this.lstatSync = this.statSync;
this.fstatSync = (fd, options) => {
const filename = this.getFileName(fd);
return this.statSync(filename, options);
};
this.accessSync = (path, mode = 0 /* AMODE.F_OK */) => {
const filename = util.pathToFilename(path);
mode = mode | 0;
const adapter = this.getSyncAdapter();
adapter.call('access', [filename, mode]);
};
this.readFileSync = (id, options) => {
const opts = optHelpers.getReadFileOptions(options);
const flagsNum = util.flagsToNumber(opts.flag);
const filename = this.getFileName(id);
const adapter = this.getSyncAdapter();
const uint8 = adapter.call('readFile', [filename, opts]);
const buffer = buffer_1.Buffer.from(uint8.buffer, uint8.byteOffset, uint8.byteLength);
return util.bufferToEncoding(buffer, opts.encoding);
};
this.writeFileSync = (id, data, options) => {
const opts = optHelpers.getWriteFileOptions(options);
const flagsNum = util.flagsToNumber(opts.flag);
const modeNum = util.modeToNumber(opts.mode);
const buf = util.dataToBuffer(data, opts.encoding);
const filename = this.getFileName(id);
const adapter = this.getSyncAdapter();
adapter.call('writeFile', [filename, util.bufToUint8(buf), opts]);
};
this.appendFileSync = (id, data, options) => {
const opts = optHelpers.getAppendFileOpts(options);
if (!opts.flag || util.isFd(id))
opts.flag = 'a';
const filename = this.getFileName(id);
const buf = util.dataToBuffer(data, opts.encoding);
const adapter = this.getSyncAdapter();
adapter.call('appendFile', [filename, util.bufToUint8(buf), opts]);
};
this.closeSync = (fd) => {
util.validateFd(fd);
const file = this.getFileByFd(fd, 'close');
file.close().catch(() => { });
this.fds.delete(fd);
this.releasedFds.push(fd);
};
this.existsSync = (path) => {
try {
this.statSync(path);
return true;
}
catch (_a) {
return false;
}
};
this.copyFileSync = (src, dest, flags) => {
const srcFilename = util.pathToFilename(src);
const destFilename = util.pathToFilename(dest);
const adapter = this.getSyncAdapter();
adapter.call('copy', [srcFilename, destFilename, flags]);
};
this.renameSync = (oldPath, newPath) => {
const srcFilename = util.pathToFilename(oldPath);
const destFilename = util.pathToFilename(newPath);
const adapter = this.getSyncAdapter();
adapter.call('move', [srcFilename, destFilename]);
};
this.rmdirSync = (path, opts) => {
const filename = util.pathToFilename(path);
const adapter = this.getSyncAdapter();
adapter.call('rmdir', [filename, opts]);
};
this.rmSync = (path, options) => {
const filename = util.pathToFilename(path);
const adapter = this.getSyncAdapter();
adapter.call('rm', [filename, options]);
};
this.mkdirSync = (path, options) => {
const opts = optHelpers.getMkdirOptions(options);
const modeNum = util.modeToNumber(opts.mode, 0o777);
const filename = util.pathToFilename(path);
return this.getSyncAdapter().call('mkdir', [filename, options]);
};
this.mkdtempSync = (prefix, options) => {
const { encoding } = optHelpers.getDefaultOpts(options);
if (!prefix || typeof prefix !== 'string')
throw new TypeError('filename prefix is required');
util.nullCheck(prefix);
const result = this.getSyncAdapter().call('mkdtemp', [prefix, options]);
return (0, encoding_1.strToEncoding)(result, encoding);
};
this.readlinkSync = (path, options) => {
const opts = optHelpers.getDefaultOpts(options);
const filename = util.pathToFilename(path);
const buffer = buffer_1.Buffer.from(filename);
return util.bufferToEncoding(buffer, opts.encoding);
};
this.truncateSync = (id, len) => {
if (util.isFd(id))
return this.ftruncateSync(id, len);
const filename = util.pathToFilename(id);
this.getSyncAdapter().call('trunc', [filename, Number(len) || 0]);
};
this.ftruncateSync = (fd, len) => {
const filename = this.getFileName(fd);
this.truncateSync(filename, len);
};
this.unlinkSync = (path) => {
const filename = util.pathToFilename(path);
this.getSyncAdapter().call('unlink', [filename]);
};
this.readdirSync = (path, options) => {
const opts = optHelpers.getReaddirOptions(options);
const filename = util.pathToFilename(path);
const adapter = this.getSyncAdapter();
const list = adapter.call('readdir', [filename]);
if (opts.withFileTypes) {
const res = [];
for (const entry of list)
res.push(new FsaNodeDirent_1.FsaNodeDirent(entry.name, entry.kind));
return res;
}
else {
const res = [];
for (const entry of list) {
const buffer = buffer_1.Buffer.from(entry.name);
res.push(util.bufferToEncoding(buffer, opts.encoding));
}
return res;
}
};
this.realpathSync = (path, options) => {
let filename = util.pathToFilename(path);
const { encoding } = optHelpers.getRealpathOptions(options);
if (filename[0] !== "/" /* FsaToNodeConstants.Separator */)
filename = "/" /* FsaToNodeConstants.Separator */ + filename;
return (0, encoding_1.strToEncoding)(filename, encoding);
};
this.readSync = (fd, buffer, offset, length, position) => {
util.validateFd(fd);
const filename = this.getFileName(fd);
const adapter = this.getSyncAdapter();
const uint8 = adapter.call('read', [filename, position, length]);
const dest = new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);
dest.set(uint8, offset);
return uint8.length;
};
this.writeSync = (fd, a, b, c, d) => {
const [, buf, offset, length, position] = util.getWriteSyncArgs(fd, a, b, c, d);
const filename = this.getFileName(fd);
const data = new Uint8Array(buf.buffer, buf.byteOffset + offset, length);
return this.getSyncAdapter().call('write', [filename, data, position || null]);
};
this.openSync = (path, flags, mode = 438 /* MODE.DEFAULT */) => {
const modeNum = util.modeToNumber(mode);
const filename = util.pathToFilename(path);
const flagsNum = util.flagsToNumber(flags);
const adapter = this.getSyncAdapter();
const handle = adapter.call('open', [filename, flagsNum, modeNum]);
const openFile = this.__open2(handle, filename, flagsNum, modeNum);
return openFile.fd;
};
this.writevSync = (fd, buffers, position) => {
if (buffers.length === 0)
return;
this.writeSync(fd, buffers[0], 0, buffers[0].byteLength, position);
for (let i = 1; i < buffers.length; i++) {
this.writeSync(fd, buffers[i], 0, buffers[i].byteLength, null);
}
};
this.fdatasyncSync = noop;
this.fsyncSync = noop;
this.chmodSync = noop;
this.chownSync = noop;
this.fchmodSync = noop;
this.fchownSync = noop;
this.futimesSync = noop;
this.lchmodSync = noop;
this.lchownSync = noop;
this.utimesSync = noop;
this.lutimesSync = noop;
this.cpSync = notImplemented;
this.opendirSync = notImplemented;
this.statfsSync = notImplemented;
this.readvSync = notImplemented;
this.symlinkSync = notSupported;
this.linkSync = notSupported;
// ---------------------------------------------------------- FsCommonObjects
this.F_OK = constants_2.constants.F_OK;
this.R_OK = constants_2.constants.R_OK;
this.W_OK = constants_2.constants.W_OK;
this.X_OK = constants_2.constants.X_OK;
this.constants = constants_2.constants;
this.Dirent = FsaNodeDirent_1.FsaNodeDirent;
this.Stats = (FsaNodeStats_1.FsaNodeStats);
this.WriteStream = FsaNodeWriteStream_1.FsaNodeWriteStream;
this.ReadStream = FsaNodeReadStream_1.FsaNodeReadStream;
this.StatFs = 0;
this.Dir = 0;
this.StatsWatcher = 0;
this.FSWatcher = 0;
}
async getHandleStats(bigint, handle) {
let size = 0;
if (handle.kind === 'file') {
const file = handle;
const fileData = await file.getFile();
size = fileData.size;
}
const stats = new FsaNodeStats_1.FsaNodeStats(bigint, bigint ? BigInt(size) : size, handle.kind);
return stats;
}
rmAll(callback) {
(async () => {
var _a, e_3, _b, _c;
const root = await this.root;
try {
for (var _d = true, _e = tslib_1.__asyncValues(root.keys()), _f; _f = await _e.next(), _a = _f.done, !_a; _d = true) {
_c = _f.value;
_d = false;
const name = _c;
await root.removeEntry(name, { recursive: true });
}
}
catch (e_3_1) { e_3 = { error: e_3_1 }; }
finally {
try {
if (!_d && !_a && (_b = _e.return)) await _b.call(_e);
}
finally { if (e_3) throw e_3.error; }
}
})().then(() => callback(null), error => callback(error));
}
}
exports.FsaNodeFs = FsaNodeFs;
//# sourceMappingURL=FsaNodeFs.js.map
File diff suppressed because one or more lines are too long
+24
View File
@@ -0,0 +1,24 @@
import type * as fsa from '../fsa/types';
import type * as misc from '../node/types/misc';
/**
* Represents an open file. Stores additional metadata about the open file, such
* as the seek position.
*/
export declare class FsaNodeFsOpenFile {
readonly fd: number;
readonly createMode: misc.TMode;
readonly flags: number;
readonly file: fsa.IFileSystemFileHandle;
readonly filename: string;
protected seek: number;
/**
* This influences the behavior of the next write operation. On the first
* write we want to overwrite the file or keep the existing data, depending
* with which flags the file was opened. On subsequent writes we want to
* append to the file.
*/
protected keepExistingData: boolean;
constructor(fd: number, createMode: misc.TMode, flags: number, file: fsa.IFileSystemFileHandle, filename: string);
close(): Promise<void>;
write(data: ArrayBufferView, seek: number | null): Promise<void>;
}
+34
View File
@@ -0,0 +1,34 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.FsaNodeFsOpenFile = void 0;
/**
* Represents an open file. Stores additional metadata about the open file, such
* as the seek position.
*/
class FsaNodeFsOpenFile {
constructor(fd, createMode, flags, file, filename) {
this.fd = fd;
this.createMode = createMode;
this.flags = flags;
this.file = file;
this.filename = filename;
this.seek = 0;
this.keepExistingData = !!(flags & 1024 /* FLAG.O_APPEND */);
}
async close() { }
async write(data, seek) {
if (typeof seek !== 'number')
seek = this.seek;
const writer = await this.file.createWritable({ keepExistingData: this.keepExistingData });
await writer.write({
type: 'write',
data,
position: seek,
});
await writer.close();
this.keepExistingData = true;
this.seek += data.byteLength;
}
}
exports.FsaNodeFsOpenFile = FsaNodeFsOpenFile;
//# sourceMappingURL=FsaNodeFsOpenFile.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"FsaNodeFsOpenFile.js","sourceRoot":"","sources":["../../src/fsa-to-node/FsaNodeFsOpenFile.ts"],"names":[],"mappings":";;;AAIA;;;GAGG;AACH,MAAa,iBAAiB;IAW5B,YACkB,EAAU,EACV,UAAsB,EACtB,KAAa,EACb,IAA+B,EAC/B,QAAgB;QAJhB,OAAE,GAAF,EAAE,CAAQ;QACV,eAAU,GAAV,UAAU,CAAY;QACtB,UAAK,GAAL,KAAK,CAAQ;QACb,SAAI,GAAJ,IAAI,CAA2B;QAC/B,aAAQ,GAAR,QAAQ,CAAQ;QAfxB,SAAI,GAAW,CAAC,CAAC;QAiBzB,IAAI,CAAC,gBAAgB,GAAG,CAAC,CAAC,CAAC,KAAK,2BAAgB,CAAC,CAAC;IACpD,CAAC;IAEM,KAAK,CAAC,KAAK,KAAmB,CAAC;IAE/B,KAAK,CAAC,KAAK,CAAC,IAAqB,EAAE,IAAmB;QAC3D,IAAI,OAAO,IAAI,KAAK,QAAQ;YAAE,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;QAC/C,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,EAAE,gBAAgB,EAAE,IAAI,CAAC,gBAAgB,EAAE,CAAC,CAAC;QAC3F,MAAM,MAAM,CAAC,KAAK,CAAC;YACjB,IAAI,EAAE,OAAO;YACb,IAAI;YACJ,QAAQ,EAAE,IAAI;SACf,CAAC,CAAC;QACH,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;QACrB,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC;QAC7B,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,UAAU,CAAC;IAC/B,CAAC;CACF;AAnCD,8CAmCC"}
+23
View File
@@ -0,0 +1,23 @@
import { Readable } from 'stream';
import { Defer } from '../thingies/Defer';
import type { FsaNodeFsOpenFile } from './FsaNodeFsOpenFile';
import type { IReadStream } from '../node/types/misc';
import type { IReadStreamOptions } from '../node/types/options';
import type { FsaNodeFs } from './FsaNodeFs';
export declare class FsaNodeReadStream extends Readable implements IReadStream {
protected readonly fs: FsaNodeFs;
protected readonly handle: Promise<FsaNodeFsOpenFile>;
readonly path: string;
protected readonly options: IReadStreamOptions;
protected __pending__: boolean;
protected __closed__: boolean;
protected __bytes__: number;
protected readonly __mutex__: <T = unknown>(code: import("../thingies/types").Code<T>) => Promise<T>;
protected readonly __file__: Defer<FsaNodeFsOpenFile>;
constructor(fs: FsaNodeFs, handle: Promise<FsaNodeFsOpenFile>, path: string, options: IReadStreamOptions);
private __read__;
private __close__;
get bytesRead(): number;
get pending(): boolean;
_read(): void;
}
+90
View File
@@ -0,0 +1,90 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.FsaNodeReadStream = void 0;
const stream_1 = require("stream");
const Defer_1 = require("../thingies/Defer");
const concurrency_1 = require("../thingies/concurrency");
class FsaNodeReadStream extends stream_1.Readable {
constructor(fs, handle, path, options) {
super();
this.fs = fs;
this.handle = handle;
this.path = path;
this.options = options;
this.__pending__ = true;
this.__closed__ = false;
this.__bytes__ = 0;
this.__mutex__ = (0, concurrency_1.concurrency)(1);
this.__file__ = new Defer_1.Defer();
handle
.then(file => {
if (this.__closed__)
return;
this.__file__.resolve(file);
if (this.options.fd !== undefined)
this.emit('open', file.fd);
this.emit('ready');
})
.catch(error => {
this.__file__.reject(error);
})
.finally(() => {
this.__pending__ = false;
});
}
async __read__() {
return await this.__mutex__(async () => {
if (this.__closed__)
return;
const { file } = await this.__file__.promise;
const blob = await file.getFile();
const buffer = await blob.arrayBuffer();
const start = this.options.start || 0;
let end = typeof this.options.end === 'number' ? this.options.end + 1 : buffer.byteLength;
if (end > buffer.byteLength)
end = buffer.byteLength;
const uint8 = new Uint8Array(buffer, start, end - start);
return uint8;
});
}
__close__() {
if (this.__closed__)
return;
this.__closed__ = true;
if (this.options.autoClose) {
this.__file__.promise
.then(file => {
this.fs.close(file.fd, () => {
this.emit('close');
});
return file.close();
})
.catch(error => { });
}
}
// -------------------------------------------------------------- IReadStream
get bytesRead() {
return this.__bytes__;
}
get pending() {
return this.__pending__;
}
// ----------------------------------------------------------------- Readable
_read() {
this.__read__().then((uint8) => {
if (this.__closed__)
return;
if (!uint8)
return this.push(null);
this.__bytes__ += uint8.length;
this.__close__();
this.push(uint8);
this.push(null);
}, error => {
this.__close__();
this.destroy(error);
});
}
}
exports.FsaNodeReadStream = FsaNodeReadStream;
//# sourceMappingURL=FsaNodeReadStream.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"FsaNodeReadStream.js","sourceRoot":"","sources":["../../src/fsa-to-node/FsaNodeReadStream.ts"],"names":[],"mappings":"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"}
+30
View File
@@ -0,0 +1,30 @@
import type * as misc from '../node/types/misc';
export declare class FsaNodeStats<T = misc.TStatNumber> implements misc.IStats<T> {
protected readonly kind: 'file' | 'directory';
readonly uid: T;
readonly gid: T;
readonly rdev: T;
readonly blksize: T;
readonly ino: T;
readonly size: T;
readonly blocks: T;
readonly atime: Date;
readonly mtime: Date;
readonly ctime: Date;
readonly birthtime: Date;
readonly atimeMs: T;
readonly mtimeMs: T;
readonly ctimeMs: T;
readonly birthtimeMs: T;
readonly dev: T;
readonly mode: T;
readonly nlink: T;
constructor(isBigInt: boolean, size: T, kind: 'file' | 'directory');
isDirectory(): boolean;
isFile(): boolean;
isBlockDevice(): boolean;
isCharacterDevice(): boolean;
isSymbolicLink(): boolean;
isFIFO(): boolean;
isSocket(): boolean;
}
+53
View File
@@ -0,0 +1,53 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.FsaNodeStats = void 0;
const time = 0;
const timex = typeof BigInt === 'function' ? BigInt(time) : time;
const date = new Date(time);
class FsaNodeStats {
constructor(isBigInt, size, kind) {
this.kind = kind;
const dummy = (isBigInt ? timex : time);
this.uid = dummy;
this.gid = dummy;
this.rdev = dummy;
this.blksize = dummy;
this.ino = dummy;
this.size = size;
this.blocks = dummy;
this.atime = date;
this.mtime = date;
this.ctime = date;
this.birthtime = date;
this.atimeMs = dummy;
this.mtimeMs = dummy;
this.ctimeMs = dummy;
this.birthtimeMs = dummy;
this.dev = dummy;
this.mode = dummy;
this.nlink = dummy;
}
isDirectory() {
return this.kind === 'directory';
}
isFile() {
return this.kind === 'file';
}
isBlockDevice() {
return false;
}
isCharacterDevice() {
return false;
}
isSymbolicLink() {
return false;
}
isFIFO() {
return false;
}
isSocket() {
return false;
}
}
exports.FsaNodeStats = FsaNodeStats;
//# sourceMappingURL=FsaNodeStats.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"FsaNodeStats.js","sourceRoot":"","sources":["../../src/fsa-to-node/FsaNodeStats.ts"],"names":[],"mappings":";;;AAEA,MAAM,IAAI,GAAW,CAAC,CAAC;AACvB,MAAM,KAAK,GAAW,OAAO,MAAM,KAAK,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAE,IAAsB,CAAC;AAC5F,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC;AAE5B,MAAa,YAAY;IAoBvB,YACE,QAAiB,EACjB,IAAO,EACY,IAA0B;QAA1B,SAAI,GAAJ,IAAI,CAAsB;QAE7C,MAAM,KAAK,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAa,CAAC;QACpD,IAAI,CAAC,GAAG,GAAG,KAAK,CAAC;QACjB,IAAI,CAAC,GAAG,GAAG,KAAK,CAAC;QACjB,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC;QAClB,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;QACrB,IAAI,CAAC,GAAG,GAAG,KAAK,CAAC;QACjB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;QACpB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QAClB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QAClB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QAClB,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;QACtB,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;QACrB,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;QACrB,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;QACrB,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC;QACzB,IAAI,CAAC,GAAG,GAAG,KAAK,CAAC;QACjB,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC;QAClB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;IACrB,CAAC;IAEM,WAAW;QAChB,OAAO,IAAI,CAAC,IAAI,KAAK,WAAW,CAAC;IACnC,CAAC;IAEM,MAAM;QACX,OAAO,IAAI,CAAC,IAAI,KAAK,MAAM,CAAC;IAC9B,CAAC;IAEM,aAAa;QAClB,OAAO,KAAK,CAAC;IACf,CAAC;IAEM,iBAAiB;QACtB,OAAO,KAAK,CAAC;IACf,CAAC;IAEM,cAAc;QACnB,OAAO,KAAK,CAAC;IACf,CAAC;IAEM,MAAM;QACX,OAAO,KAAK,CAAC;IACf,CAAC;IAEM,QAAQ;QACb,OAAO,KAAK,CAAC;IACf,CAAC;CACF;AAzED,oCAyEC"}
+47
View File
@@ -0,0 +1,47 @@
import { Writable } from 'stream';
import { FsaNodeFsOpenFile } from './FsaNodeFsOpenFile';
import type { IFileSystemWritableFileStream } from '../fsa/types';
import type { IWriteStream } from '../node/types/misc';
import type { IWriteStreamOptions } from '../node/types/options';
/**
* This WriteStream implementation does not build on top of the `fs` module,
* but instead uses the lower-level `FileSystemFileHandle` interface. The reason
* is the different semantics in `fs` and FSA (File System Access API) write streams.
*
* When data is written to an FSA file, a new FSA stream is created, it copies
* the file to a temporary swap file. After each written chunk, that swap file
* is closed and the original file is replaced with the swap file. This means,
* if WriteStream was built on top of `fs`, each chunk write would result in
* a file copy, write, close, rename operations, which is not what we want.
*
* Instead this implementation hooks into the lower-level and closes the swap
* file only once the stream is closed. The downside is that the written data
* is not immediately visible to other processes (because it is written to the
* swap file), but that is the trade-off we have to make.
*
* @todo Could make this flush the data to the original file periodically, so that
* the data is visible to other processes.
* @todo This stream could work through `FileSystemSyncAccessHandle.write` in a
* Worker thread instead.
*/
export declare class FsaNodeWriteStream extends Writable implements IWriteStream {
readonly path: string;
protected readonly options: IWriteStreamOptions;
protected __pending__: boolean;
protected __closed__: boolean;
protected __bytes__: number;
protected readonly __stream__: Promise<IFileSystemWritableFileStream>;
protected readonly __mutex__: <T = unknown>(code: import("../thingies/types").Code<T>) => Promise<T>;
constructor(handle: Promise<FsaNodeFsOpenFile>, path: string, options: IWriteStreamOptions);
private ___write___;
private __close__;
get bytesWritten(): number;
get pending(): boolean;
close(cb: any): void;
_write(chunk: any, encoding: string, callback: (error?: Error | null) => void): void;
_writev(chunks: Array<{
chunk: any;
encoding: string;
}>, callback: (error?: Error | null) => void): void;
_final(callback: (error?: Error | null) => void): void;
}
+151
View File
@@ -0,0 +1,151 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.FsaNodeWriteStream = void 0;
const stream_1 = require("stream");
const Defer_1 = require("../thingies/Defer");
const concurrency_1 = require("../thingies/concurrency");
const util_1 = require("../node/util");
const queueMicrotask_1 = require("../queueMicrotask");
/**
* This WriteStream implementation does not build on top of the `fs` module,
* but instead uses the lower-level `FileSystemFileHandle` interface. The reason
* is the different semantics in `fs` and FSA (File System Access API) write streams.
*
* When data is written to an FSA file, a new FSA stream is created, it copies
* the file to a temporary swap file. After each written chunk, that swap file
* is closed and the original file is replaced with the swap file. This means,
* if WriteStream was built on top of `fs`, each chunk write would result in
* a file copy, write, close, rename operations, which is not what we want.
*
* Instead this implementation hooks into the lower-level and closes the swap
* file only once the stream is closed. The downside is that the written data
* is not immediately visible to other processes (because it is written to the
* swap file), but that is the trade-off we have to make.
*
* @todo Could make this flush the data to the original file periodically, so that
* the data is visible to other processes.
* @todo This stream could work through `FileSystemSyncAccessHandle.write` in a
* Worker thread instead.
*/
class FsaNodeWriteStream extends stream_1.Writable {
constructor(handle, path, options) {
super();
this.path = path;
this.options = options;
this.__pending__ = true;
this.__closed__ = false;
this.__bytes__ = 0;
this.__mutex__ = (0, concurrency_1.concurrency)(1);
if (options.start !== undefined) {
if (typeof options.start !== 'number') {
throw new TypeError('"start" option must be a Number');
}
if (options.start < 0) {
throw new TypeError('"start" must be >= zero');
}
}
const stream = new Defer_1.Defer();
this.__stream__ = stream.promise;
(async () => {
var _a, _b;
const fsaHandle = await handle;
const fileWasOpened = !options.fd;
if (fileWasOpened)
this.emit('open', fsaHandle.fd);
const flags = (0, util_1.flagsToNumber)((_a = options.flags) !== null && _a !== void 0 ? _a : 'w');
const keepExistingData = flags & 1024 /* FLAG.O_APPEND */ ? true : false;
const writable = await fsaHandle.file.createWritable({ keepExistingData });
if (keepExistingData) {
const start = Number((_b = options.start) !== null && _b !== void 0 ? _b : 0);
if (start)
await writable.seek(start);
}
this.__pending__ = false;
stream.resolve(writable);
})().catch(error => {
stream.reject(error);
});
}
async ___write___(buffers) {
await this.__mutex__(async () => {
if (this.__closed__)
return;
// if (this.__closed__) throw new Error('WriteStream is closed');
const writable = await this.__stream__;
for (const buffer of buffers) {
await writable.write(buffer);
this.__bytes__ += buffer.byteLength;
}
});
}
async __close__() {
const emitClose = this.options.emitClose;
await this.__mutex__(async () => {
if (this.__closed__ && emitClose) {
(0, queueMicrotask_1.default)(() => this.emit('close'));
return;
}
try {
const writable = await this.__stream__;
this.__closed__ = true;
await writable.close();
if (emitClose)
this.emit('close');
}
catch (error) {
this.emit('error', error);
if (emitClose)
this.emit('close', error);
}
});
}
// ------------------------------------------------------------- IWriteStream
get bytesWritten() {
return this.__bytes__;
}
get pending() {
return this.__pending__;
}
close(cb) {
if (cb)
this.once('close', cb);
this.__close__().catch(() => { });
}
// ----------------------------------------------------------------- Writable
_write(chunk, encoding, callback) {
this.___write___([chunk])
.then(() => {
if (callback)
callback(null);
})
.catch(error => {
if (callback)
callback(error);
});
}
_writev(chunks, callback) {
const buffers = chunks.map(({ chunk }) => chunk);
this.___write___(buffers)
.then(() => {
if (callback)
callback(null);
})
.catch(error => {
if (callback)
callback(error);
});
}
_final(callback) {
this.__close__()
.then(() => {
if (callback)
callback(null);
})
.catch(error => {
if (callback)
callback(error);
});
}
}
exports.FsaNodeWriteStream = FsaNodeWriteStream;
//# sourceMappingURL=FsaNodeWriteStream.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"FsaNodeWriteStream.js","sourceRoot":"","sources":["../../src/fsa-to-node/FsaNodeWriteStream.ts"],"names":[],"mappings":"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"}
+3
View File
@@ -0,0 +1,3 @@
export declare const enum FsaToNodeConstants {
Separator = "/"
}
+3
View File
@@ -0,0 +1,3 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=constants.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/fsa-to-node/constants.ts"],"names":[],"mappings":""}
+2
View File
@@ -0,0 +1,2 @@
export { FsaNodeFs } from './FsaNodeFs';
export { FsaNodeSyncAdapterWorker } from './worker/FsaNodeSyncAdapterWorker';
+8
View File
@@ -0,0 +1,8 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.FsaNodeSyncAdapterWorker = exports.FsaNodeFs = void 0;
var FsaNodeFs_1 = require("./FsaNodeFs");
Object.defineProperty(exports, "FsaNodeFs", { enumerable: true, get: function () { return FsaNodeFs_1.FsaNodeFs; } });
var FsaNodeSyncAdapterWorker_1 = require("./worker/FsaNodeSyncAdapterWorker");
Object.defineProperty(exports, "FsaNodeSyncAdapterWorker", { enumerable: true, get: function () { return FsaNodeSyncAdapterWorker_1.FsaNodeSyncAdapterWorker; } });
//# sourceMappingURL=index.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/fsa-to-node/index.ts"],"names":[],"mappings":";;;AAAA,yCAAwC;AAA/B,sGAAA,SAAS,OAAA;AAClB,8EAA6E;AAApE,oIAAA,wBAAwB,OAAA"}
+2
View File
@@ -0,0 +1,2 @@
import { encoder, decoder } from '@jsonjoy.com/json-pack/lib/cbor/shared';
export { encoder, decoder };
+7
View File
@@ -0,0 +1,7 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.decoder = exports.encoder = void 0;
const shared_1 = require("@jsonjoy.com/json-pack/lib/cbor/shared");
Object.defineProperty(exports, "encoder", { enumerable: true, get: function () { return shared_1.encoder; } });
Object.defineProperty(exports, "decoder", { enumerable: true, get: function () { return shared_1.decoder; } });
//# sourceMappingURL=json.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"json.js","sourceRoot":"","sources":["../../src/fsa-to-node/json.ts"],"names":[],"mappings":";;;AAAA,mEAA0E;AACjE,wFADA,gBAAO,OACA;AAAE,wFADA,gBAAO,OACA"}
+37
View File
@@ -0,0 +1,37 @@
import type { IFileSystemFileHandle } from '../fsa/types';
import type * as opts from '../node/types/options';
import type * as misc from '../node/types/misc';
export type FsLocation = [folder: string[], file: string];
/**
* Adapter which implements synchronous calls to the FSA API.
*/
export interface FsaNodeSyncAdapterApi {
stat(location: FsLocation): FsaNodeSyncAdapterStats;
access(req: [filename: string, mode: number]): void;
readFile(req: [filename: string, opts?: opts.IReadFileOptions]): Uint8Array;
writeFile(req: [filename: string, data: Uint8Array, opts?: opts.IWriteFileOptions]): void;
appendFile(req: [filename: string, data: Uint8Array, opts?: opts.IAppendFileOptions]): void;
copy(req: [src: string, dst: string, flags?: number]): void;
move(req: [src: string, dst: string]): void;
rmdir(req: [filename: string, opts?: opts.IRmdirOptions]): void;
rm(req: [filename: string, opts?: opts.IRmOptions]): void;
mkdir(req: [filename: string, opts?: misc.TMode | opts.IMkdirOptions]): string | undefined;
mkdtemp(req: [filename: string, opts?: misc.TMode | opts.IOptions]): string;
trunc(req: [filename: string, len: number]): void;
unlink(req: [filename: string]): void;
readdir(req: [filename: string]): FsaNodeSyncAdapterEntry[];
read(req: [filename: string, position: number, length: number]): Uint8Array;
write(req: [filename: string, data: Uint8Array, position: number | null]): number;
open(req: [filename: string, flags: number, mode: number]): IFileSystemFileHandle;
}
export interface FsaNodeSyncAdapter {
call<K extends keyof FsaNodeSyncAdapterApi>(method: K, payload: Parameters<FsaNodeSyncAdapterApi[K]>[0]): ReturnType<FsaNodeSyncAdapterApi[K]>;
}
export interface FsaNodeSyncAdapterStats {
kind: 'file' | 'directory';
size?: number;
}
export interface FsaNodeSyncAdapterEntry {
kind: 'file' | 'directory';
name: string;
}
+3
View File
@@ -0,0 +1,3 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=types.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/fsa-to-node/types.ts"],"names":[],"mappings":""}
+4
View File
@@ -0,0 +1,4 @@
import { IFileSystemDirectoryHandle } from '../fsa/types';
import type { FsLocation } from './types';
export declare const pathToLocation: (path: string) => FsLocation;
export declare const testDirectoryIsWritable: (dir: IFileSystemDirectoryHandle) => Promise<boolean>;
+34
View File
@@ -0,0 +1,34 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.testDirectoryIsWritable = exports.pathToLocation = void 0;
const pathToLocation = (path) => {
if (path[0] === "/" /* FsaToNodeConstants.Separator */)
path = path.slice(1);
if (path[path.length - 1] === "/" /* FsaToNodeConstants.Separator */)
path = path.slice(0, -1);
const lastSlashIndex = path.lastIndexOf("/" /* FsaToNodeConstants.Separator */);
if (lastSlashIndex === -1)
return [[], path];
const file = path.slice(lastSlashIndex + 1);
const folder = path.slice(0, lastSlashIndex).split("/" /* FsaToNodeConstants.Separator */);
return [folder, file];
};
exports.pathToLocation = pathToLocation;
const testDirectoryIsWritable = async (dir) => {
const testFileName = '__memfs_writable_test_file_' + Math.random().toString(36).slice(2) + Date.now();
try {
await dir.getFileHandle(testFileName, { create: true });
return true;
}
catch (_a) {
return false;
}
finally {
try {
await dir.removeEntry(testFileName);
}
catch (e) { }
}
};
exports.testDirectoryIsWritable = testDirectoryIsWritable;
//# sourceMappingURL=util.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"util.js","sourceRoot":"","sources":["../../src/fsa-to-node/util.ts"],"names":[],"mappings":";;;AAIO,MAAM,cAAc,GAAG,CAAC,IAAY,EAAc,EAAE;IACzD,IAAI,IAAI,CAAC,CAAC,CAAC,2CAAiC;QAAE,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACnE,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,2CAAiC;QAAE,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACrF,MAAM,cAAc,GAAG,IAAI,CAAC,WAAW,wCAA8B,CAAC;IACtE,IAAI,cAAc,KAAK,CAAC,CAAC;QAAE,OAAO,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;IAC7C,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,GAAG,CAAC,CAAC,CAAC;IAC5C,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,cAAc,CAAC,CAAC,KAAK,wCAA8B,CAAC;IACjF,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;AACxB,CAAC,CAAC;AARW,QAAA,cAAc,kBAQzB;AAEK,MAAM,uBAAuB,GAAG,KAAK,EAAE,GAA+B,EAAoB,EAAE;IACjG,MAAM,YAAY,GAAG,6BAA6B,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACtG,IAAI,CAAC;QACH,MAAM,GAAG,CAAC,aAAa,CAAC,YAAY,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;QACxD,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,WAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;YAAS,CAAC;QACT,IAAI,CAAC;YACH,MAAM,GAAG,CAAC,WAAW,CAAC,YAAY,CAAC,CAAC;QACtC,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC,CAAA,CAAC;IAChB,CAAC;AACH,CAAC,CAAC;AAZW,QAAA,uBAAuB,2BAYlC"}
@@ -0,0 +1,10 @@
import { SyncMessenger } from './SyncMessenger';
import type * as fsa from '../../fsa/types';
import type { FsaNodeSyncAdapter, FsaNodeSyncAdapterApi } from '../types';
export declare class FsaNodeSyncAdapterWorker implements FsaNodeSyncAdapter {
protected readonly messenger: SyncMessenger;
protected readonly root: fsa.IFileSystemDirectoryHandle;
static start(url: string, dir: fsa.IFileSystemDirectoryHandle | Promise<fsa.IFileSystemDirectoryHandle>): Promise<FsaNodeSyncAdapterWorker>;
constructor(messenger: SyncMessenger, root: fsa.IFileSystemDirectoryHandle);
call<K extends keyof FsaNodeSyncAdapterApi>(method: K, payload: Parameters<FsaNodeSyncAdapterApi[K]>[0]): ReturnType<FsaNodeSyncAdapterApi[K]>;
}
+62
View File
@@ -0,0 +1,62 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.FsaNodeSyncAdapterWorker = void 0;
const Defer_1 = require("../../thingies/Defer");
const SyncMessenger_1 = require("./SyncMessenger");
const json_1 = require("../json");
let rootId = 0;
class FsaNodeSyncAdapterWorker {
static async start(url, dir) {
const worker = new Worker(url);
const future = new Defer_1.Defer();
let id = rootId++;
let messenger = undefined;
const _dir = await dir;
worker.onmessage = e => {
const data = e.data;
if (!Array.isArray(data))
return;
const msg = data;
const code = msg[0];
switch (code) {
case 0 /* FsaNodeWorkerMessageCode.Init */: {
const [, sab] = msg;
messenger = new SyncMessenger_1.SyncMessenger(sab);
const setRootMessage = [1 /* FsaNodeWorkerMessageCode.SetRoot */, id, _dir];
worker.postMessage(setRootMessage);
break;
}
case 2 /* FsaNodeWorkerMessageCode.RootSet */: {
const [, rootId] = msg;
if (id !== rootId)
return;
const adapter = new FsaNodeSyncAdapterWorker(messenger, _dir);
future.resolve(adapter);
break;
}
}
};
return await future.promise;
}
constructor(messenger, root) {
this.messenger = messenger;
this.root = root;
}
call(method, payload) {
const request = [3 /* FsaNodeWorkerMessageCode.Request */, method, payload];
const encoded = json_1.encoder.encode(request);
const encodedResponse = this.messenger.callSync(encoded);
const [code, data] = json_1.decoder.decode(encodedResponse);
switch (code) {
case 4 /* FsaNodeWorkerMessageCode.Response */:
return data;
case 5 /* FsaNodeWorkerMessageCode.ResponseError */:
throw data;
default: {
throw new Error('Invalid response message code');
}
}
}
}
exports.FsaNodeSyncAdapterWorker = FsaNodeSyncAdapterWorker;
//# sourceMappingURL=FsaNodeSyncAdapterWorker.js.map
@@ -0,0 +1 @@
{"version":3,"file":"FsaNodeSyncAdapterWorker.js","sourceRoot":"","sources":["../../../src/fsa-to-node/worker/FsaNodeSyncAdapterWorker.ts"],"names":[],"mappings":";;;AAAA,gDAA6C;AAE7C,mDAAgD;AAChD,kCAA2C;AAa3C,IAAI,MAAM,GAAG,CAAC,CAAC;AAEf,MAAa,wBAAwB;IAC5B,MAAM,CAAC,KAAK,CAAC,KAAK,CACvB,GAAW,EACX,GAA6E;QAE7E,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC;QAC/B,MAAM,MAAM,GAAG,IAAI,aAAK,EAA4B,CAAC;QACrD,IAAI,EAAE,GAAG,MAAM,EAAE,CAAC;QAClB,IAAI,SAAS,GAA8B,SAAS,CAAC;QACrD,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC;QACvB,MAAM,CAAC,SAAS,GAAG,CAAC,CAAC,EAAE;YACrB,MAAM,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC;YACpB,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;gBAAE,OAAO;YACjC,MAAM,GAAG,GAAG,IAAwB,CAAC;YACrC,MAAM,IAAI,GAAG,GAAG,CAAC,CAAC,CAA6B,CAAC;YAChD,QAAQ,IAAI,EAAE,CAAC;gBACb,0CAAkC,CAAC,CAAC,CAAC;oBACnC,MAAM,CAAC,EAAE,GAAG,CAAC,GAAG,GAA2B,CAAC;oBAC5C,SAAS,GAAG,IAAI,6BAAa,CAAC,GAAG,CAAC,CAAC;oBACnC,MAAM,cAAc,GAA4B,2CAAmC,EAAE,EAAE,IAAI,CAAC,CAAC;oBAC7F,MAAM,CAAC,WAAW,CAAC,cAAc,CAAC,CAAC;oBACnC,MAAM;gBACR,CAAC;gBACD,6CAAqC,CAAC,CAAC,CAAC;oBACtC,MAAM,CAAC,EAAE,MAAM,CAAC,GAAG,GAA8B,CAAC;oBAClD,IAAI,EAAE,KAAK,MAAM;wBAAE,OAAO;oBAC1B,MAAM,OAAO,GAAG,IAAI,wBAAwB,CAAC,SAAU,EAAE,IAAI,CAAC,CAAC;oBAC/D,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;oBACxB,MAAM;gBACR,CAAC;YACH,CAAC;QACH,CAAC,CAAC;QACF,OAAO,MAAM,MAAM,CAAC,OAAO,CAAC;IAC9B,CAAC;IAED,YACqB,SAAwB,EACxB,IAAoC;QADpC,cAAS,GAAT,SAAS,CAAe;QACxB,SAAI,GAAJ,IAAI,CAAgC;IACtD,CAAC;IAEG,IAAI,CACT,MAAS,EACT,OAAgD;QAEhD,MAAM,OAAO,GAA4B,2CAAmC,MAAM,EAAE,OAAO,CAAC,CAAC;QAC7F,MAAM,OAAO,GAAG,cAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QACxC,MAAM,eAAe,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QAEzD,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,cAAO,CAAC,MAAM,CAAC,eAAe,CAAY,CAAC;QAChE,QAAQ,IAAI,EAAE,CAAC;YACb;gBACE,OAAO,IAAW,CAAC;YACrB;gBACE,MAAM,IAAI,CAAC;YACb,OAAO,CAAC,CAAC,CAAC;gBACR,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;YACnD,CAAC;QACH,CAAC;IACH,CAAC;CACF;AA3DD,4DA2DC"}
+20
View File
@@ -0,0 +1,20 @@
import { AsyncCallback, SyncMessenger } from './SyncMessenger';
import { FsaNodeFs } from '../FsaNodeFs';
import type * as fsa from '../../fsa/types';
import type { FsaNodeWorkerMsg } from './types';
import type { FsaNodeSyncAdapterApi } from '../types';
export declare class FsaNodeSyncWorker {
protected readonly sab: SharedArrayBuffer;
protected readonly messenger: SyncMessenger;
protected root: fsa.IFileSystemDirectoryHandle;
protected fs: FsaNodeFs;
start(): void;
protected onPostMessage: (msg: FsaNodeWorkerMsg) => void;
protected readonly onRequest: AsyncCallback;
protected getDir(path: string[], create: boolean, funcName?: string): Promise<fsa.IFileSystemDirectoryHandle>;
protected getFile(path: string[], name: string, funcName?: string, create?: boolean): Promise<fsa.IFileSystemFileHandle>;
protected getFileOrDir(path: string[], name: string, funcName?: string, create?: boolean): Promise<fsa.IFileSystemFileHandle | fsa.IFileSystemDirectoryHandle>;
protected handlers: {
[K in keyof FsaNodeSyncAdapterApi]: (request: Parameters<FsaNodeSyncAdapterApi[K]>[0]) => Promise<ReturnType<FsaNodeSyncAdapterApi[K]>>;
};
}
+176
View File
@@ -0,0 +1,176 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.FsaNodeSyncWorker = void 0;
const SyncMessenger_1 = require("./SyncMessenger");
const FsaNodeFs_1 = require("../FsaNodeFs");
const json_1 = require("../json");
class FsaNodeSyncWorker {
constructor() {
this.sab = new SharedArrayBuffer(1024 * 1024);
this.messenger = new SyncMessenger_1.SyncMessenger(this.sab);
this.onPostMessage = (msg) => {
switch (msg[0]) {
case 1 /* FsaNodeWorkerMessageCode.SetRoot */: {
const [, id, dir] = msg;
this.root = dir;
this.fs = new FsaNodeFs_1.FsaNodeFs(this.root);
const response = [2 /* FsaNodeWorkerMessageCode.RootSet */, id];
postMessage(response);
this.messenger.serveAsync(this.onRequest);
break;
}
}
};
this.onRequest = async (request) => {
try {
const message = json_1.decoder.decode(request);
if (!Array.isArray(message))
throw new Error('Invalid message format');
const code = message[0];
if (code !== 3 /* FsaNodeWorkerMessageCode.Request */)
throw new Error('Invalid message code');
const [, method, payload] = message;
const handler = this.handlers[method];
if (!handler)
throw new Error(`Unknown method ${method}`);
const response = await handler(payload);
return json_1.encoder.encode([4 /* FsaNodeWorkerMessageCode.Response */, response]);
}
catch (err) {
const message = err && typeof err === 'object' && err.message ? err.message : 'Unknown error';
const error = { message };
if (err && typeof err === 'object' && (err.code || err.name))
error.code = err.code || err.name;
return json_1.encoder.encode([5 /* FsaNodeWorkerMessageCode.ResponseError */, error]);
}
};
this.handlers = {
stat: async (location) => {
const handle = await this.getFileOrDir(location[0], location[1], 'statSync');
return {
kind: handle.kind,
};
},
access: async ([filename, mode]) => {
await this.fs.promises.access(filename, mode);
},
readFile: async ([filename, opts]) => {
const buf = (await this.fs.promises.readFile(filename, Object.assign(Object.assign({}, opts), { encoding: 'buffer' })));
const uint8 = new Uint8Array(buf, buf.byteOffset, buf.byteLength);
return uint8;
},
writeFile: async ([filename, data, opts]) => {
await this.fs.promises.writeFile(filename, data, Object.assign(Object.assign({}, opts), { encoding: 'buffer' }));
},
appendFile: async ([filename, data, opts]) => {
await this.fs.promises.appendFile(filename, data, Object.assign(Object.assign({}, opts), { encoding: 'buffer' }));
},
copy: async ([src, dst, flags]) => {
await this.fs.promises.copyFile(src, dst, flags);
},
move: async ([src, dst]) => {
await this.fs.promises.rename(src, dst);
},
rmdir: async ([filename, options]) => {
await this.fs.promises.rmdir(filename, options);
},
rm: async ([filename, options]) => {
await this.fs.promises.rm(filename, options);
},
mkdir: async ([filename, options]) => {
return await this.fs.promises.mkdir(filename, options);
},
mkdtemp: async ([filename]) => {
return (await this.fs.promises.mkdtemp(filename, { encoding: 'utf8' }));
},
trunc: async ([filename, len]) => {
await this.fs.promises.truncate(filename, len);
},
unlink: async ([filename]) => {
await this.fs.promises.unlink(filename);
},
readdir: async ([filename]) => {
const list = (await this.fs.promises.readdir(filename, { withFileTypes: true, encoding: 'utf8' }));
const res = list.map(entry => ({
kind: entry.isDirectory() ? 'directory' : 'file',
name: entry.name,
}));
return res;
},
read: async ([filename, position, length]) => {
let uint8 = new Uint8Array(length);
const handle = await this.fs.promises.open(filename, 'r');
const bytesRead = await new Promise((resolve, reject) => {
this.fs.read(handle.fd, uint8, 0, length, position, (err, bytesRead) => {
if (err)
return reject(err);
resolve(bytesRead || length);
});
});
if (bytesRead < length)
uint8 = uint8.slice(0, bytesRead);
return uint8;
},
write: async ([filename, data, position]) => {
const handle = await this.fs.promises.open(filename, 'a');
const { bytesWritten } = await handle.write(data, 0, data.length, position || undefined);
return bytesWritten;
},
open: async ([filename, flags, mode]) => {
const handle = await this.fs.promises.open(filename, flags, mode);
const file = await this.fs.__getFileById(handle.fd);
await handle.close();
return file;
},
};
}
start() {
onmessage = e => {
if (!Array.isArray(e.data))
return;
this.onPostMessage(e.data);
};
const initMsg = [0 /* FsaNodeWorkerMessageCode.Init */, this.sab];
postMessage(initMsg);
}
async getDir(path, create, funcName) {
let curr = this.root;
const options = { create };
try {
for (const name of path) {
curr = await curr.getDirectoryHandle(name, options);
}
}
catch (error) {
// if (error && typeof error === 'object' && error.name === 'TypeMismatchError')
// throw createError('ENOTDIR', funcName, path.join(FsaToNodeConstants.Separator));
throw error;
}
return curr;
}
async getFile(path, name, funcName, create) {
const dir = await this.getDir(path, false, funcName);
const file = await dir.getFileHandle(name, { create });
return file;
}
async getFileOrDir(path, name, funcName, create) {
const dir = await this.getDir(path, false, funcName);
try {
const file = await dir.getFileHandle(name);
return file;
}
catch (error) {
if (error && typeof error === 'object') {
switch (error.name) {
case 'TypeMismatchError':
return await dir.getDirectoryHandle(name);
// case 'NotFoundError':
// throw createError('ENOENT', funcName, path.join(FsaToNodeConstants.Separator));
}
}
throw error;
}
}
}
exports.FsaNodeSyncWorker = FsaNodeSyncWorker;
//# sourceMappingURL=FsaNodeSyncWorker.js.map
File diff suppressed because one or more lines are too long
+24
View File
@@ -0,0 +1,24 @@
export type AsyncCallback = (request: Uint8Array) => Promise<Uint8Array>;
/**
* `SyncMessenger` allows to execute asynchronous code synchronously. The
* asynchronous code is executed in a Worker thread, while the main thread is
* blocked until the asynchronous code is finished.
*
* First four 4-byte words is the header, where the first word is used for Atomics
* notifications. The second word is used for spin-locking the main thread until
* the asynchronous code is finished. The third word is used to specify payload
* length. The fourth word is currently unused.
*
* The maximum payload size is the size of the SharedArrayBuffer minus the
* header size.
*/
export declare class SyncMessenger {
protected readonly sab: SharedArrayBuffer;
protected readonly int32: Int32Array;
protected readonly uint8: Uint8Array;
protected readonly headerSize: any;
protected readonly dataSize: any;
constructor(sab: SharedArrayBuffer);
callSync(data: Uint8Array): Uint8Array;
serveAsync(callback: AsyncCallback): void;
}
+72
View File
@@ -0,0 +1,72 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.SyncMessenger = void 0;
/**
* @param condition Condition to wait for, when true, the function returns.
* @param ms Maximum time to wait in milliseconds.
*/
const sleepUntil = (condition, ms = 100) => {
const start = Date.now();
while (!condition()) {
const now = Date.now();
if (now - start > ms)
throw new Error('Timeout');
}
};
/**
* `SyncMessenger` allows to execute asynchronous code synchronously. The
* asynchronous code is executed in a Worker thread, while the main thread is
* blocked until the asynchronous code is finished.
*
* First four 4-byte words is the header, where the first word is used for Atomics
* notifications. The second word is used for spin-locking the main thread until
* the asynchronous code is finished. The third word is used to specify payload
* length. The fourth word is currently unused.
*
* The maximum payload size is the size of the SharedArrayBuffer minus the
* header size.
*/
class SyncMessenger {
constructor(sab) {
this.sab = sab;
this.int32 = new Int32Array(sab);
this.uint8 = new Uint8Array(sab);
this.headerSize = 4 * 4;
this.dataSize = sab.byteLength - this.headerSize;
}
callSync(data) {
const requestLength = data.length;
const headerSize = this.headerSize;
const int32 = this.int32;
int32[1] = 0;
int32[2] = requestLength;
this.uint8.set(data, headerSize);
Atomics.notify(int32, 0);
sleepUntil(() => int32[1] === 1);
const responseLength = int32[2];
const response = this.uint8.slice(headerSize, headerSize + responseLength);
return response;
}
serveAsync(callback) {
const headerSize = this.headerSize;
(async () => {
try {
const int32 = this.int32;
const res = Atomics.wait(int32, 0, 0);
if (res !== 'ok')
throw new Error(`Unexpected Atomics.wait result: ${res}`);
const requestLength = this.int32[2];
const request = this.uint8.slice(headerSize, headerSize + requestLength);
const response = await callback(request);
const responseLength = response.length;
int32[2] = responseLength;
this.uint8.set(response, headerSize);
int32[1] = 1;
}
catch (_a) { }
this.serveAsync(callback);
})().catch(() => { });
}
}
exports.SyncMessenger = SyncMessenger;
//# sourceMappingURL=SyncMessenger.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"SyncMessenger.js","sourceRoot":"","sources":["../../../src/fsa-to-node/worker/SyncMessenger.ts"],"names":[],"mappings":"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"}
+8
View File
@@ -0,0 +1,8 @@
export declare const enum FsaNodeWorkerMessageCode {
Init = 0,
SetRoot = 1,
RootSet = 2,
Request = 3,
Response = 4,
ResponseError = 5
}
+3
View File
@@ -0,0 +1,3 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=constants.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../../src/fsa-to-node/worker/constants.ts"],"names":[],"mappings":""}
+17
View File
@@ -0,0 +1,17 @@
import type { IFileSystemDirectoryHandle } from '../../fsa/types';
import type { FsaNodeWorkerMessageCode } from './constants';
export type FsaNodeWorkerMsgInit = [type: FsaNodeWorkerMessageCode.Init, sab: SharedArrayBuffer];
export type FsaNodeWorkerMsgSetRoot = [
type: FsaNodeWorkerMessageCode.SetRoot,
id: number,
dir: IFileSystemDirectoryHandle
];
export type FsaNodeWorkerMsgRootSet = [type: FsaNodeWorkerMessageCode.RootSet, id: number];
export type FsaNodeWorkerMsgRequest = [type: FsaNodeWorkerMessageCode.Request, method: string, data: unknown];
export type FsaNodeWorkerMsgResponse = [type: FsaNodeWorkerMessageCode.Response, data: unknown];
export type FsaNodeWorkerMsgResponseError = [type: FsaNodeWorkerMessageCode.ResponseError, data: unknown];
export interface FsaNodeWorkerError {
message: string;
code?: string;
}
export type FsaNodeWorkerMsg = FsaNodeWorkerMsgInit | FsaNodeWorkerMsgSetRoot | FsaNodeWorkerMsgRootSet | FsaNodeWorkerMsgRequest | FsaNodeWorkerMsgResponse | FsaNodeWorkerMsgResponseError;

Some files were not shown because too many files have changed in this diff Show More