poe-code 12.0.2 → 12.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/README.md +24 -0
  2. package/dist/index.js +8 -2
  3. package/dist/index.js.map +2 -2
  4. package/dist/metafile.json +1 -1
  5. package/package.json +8 -2
  6. package/packages/package-lint/dist/bundle-policy.d.ts +45 -0
  7. package/packages/package-lint/dist/bundle-policy.js +169 -0
  8. package/packages/package-lint/dist/model.d.ts +4 -10
  9. package/packages/package-lint/dist/model.js +4 -2
  10. package/packages/package-lint/dist/packlist.js +5 -1
  11. package/packages/package-lint/dist/rules/bundle-self-contained.js +11 -25
  12. package/packages/safe-fs/dist/contracts/abort.d.ts +5 -0
  13. package/packages/safe-fs/dist/contracts/cleanup.d.ts +1 -0
  14. package/packages/safe-fs/dist/contracts/errors.d.ts +49 -0
  15. package/packages/safe-fs/dist/contracts/filesystem.d.ts +96 -0
  16. package/packages/safe-fs/dist/contracts/index.d.ts +4 -0
  17. package/packages/safe-fs/dist/contracts/io.d.ts +8 -0
  18. package/packages/safe-fs/dist/contracts/path.d.ts +13 -0
  19. package/packages/safe-fs/dist/fs/memory/index.d.ts +58 -0
  20. package/packages/safe-fs/dist/fs/mount/comparison.d.ts +18 -0
  21. package/packages/safe-fs/dist/fs/mount/identity.d.ts +2 -0
  22. package/packages/safe-fs/dist/fs/mount/index.d.ts +44 -0
  23. package/packages/safe-fs/dist/fs/overlay/index.d.ts +72 -0
  24. package/packages/safe-fs/dist/fs/readonly/index.d.ts +30 -0
  25. package/packages/safe-fs/dist/fs/real/allocation.d.ts +1 -0
  26. package/packages/safe-fs/dist/fs/real/index.d.ts +76 -0
  27. package/packages/safe-fs/dist/fs/s3/authority.d.ts +13 -0
  28. package/packages/safe-fs/dist/fs/s3/filesystem.d.ts +93 -0
  29. package/packages/safe-fs/dist/fs/s3/http/index.d.ts +2 -0
  30. package/packages/safe-fs/dist/fs/s3/http/request.d.ts +16 -0
  31. package/packages/safe-fs/dist/fs/s3/http/signature.d.ts +20 -0
  32. package/packages/safe-fs/dist/fs/s3/http/transport.d.ts +3 -0
  33. package/packages/safe-fs/dist/fs/s3/http/types.d.ts +30 -0
  34. package/packages/safe-fs/dist/fs/s3/http/xml.d.ts +11 -0
  35. package/packages/safe-fs/dist/fs/s3/index.d.ts +6 -0
  36. package/packages/safe-fs/dist/fs/s3/mock.d.ts +48 -0
  37. package/packages/safe-fs/dist/fs/s3/transport.d.ts +103 -0
  38. package/packages/safe-fs/dist/fs/webdav/index.d.ts +2 -0
  39. package/packages/safe-fs/dist/fs/webdav/resource-id.d.ts +18 -0
  40. package/packages/safe-fs/dist/fs/webdav/webdav.d.ts +98 -0
  41. package/packages/safe-fs/dist/fs/webdav/xml.d.ts +15 -0
  42. package/packages/safe-fs/dist/index.d.ts +11 -0
  43. package/packages/safe-fs/dist/node/filesystem.d.ts +11 -0
  44. package/packages/safe-fs/dist/node/index.d.ts +2 -0
  45. package/packages/safe-fs/dist/node/stats.d.ts +4 -0
  46. package/packages/safe-fs/dist/node/values.d.ts +6 -0
  47. package/packages/safejs/dist/safe-fs.js +6476 -0
  48. package/packages/safejs/dist/safe-fs.js.map +7 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "poe-code",
3
- "version": "12.0.2",
3
+ "version": "12.0.3",
4
4
  "description": "CLI tool to configure Poe API for developer workflows.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -46,6 +46,10 @@
46
46
  "./skills": {
47
47
  "types": "./dist/skills.d.ts",
48
48
  "import": "./dist/skills.js"
49
+ },
50
+ "./safe-fs": {
51
+ "types": "./packages/safe-fs/dist/index.d.ts",
52
+ "import": "./packages/safejs/dist/safe-fs.js"
49
53
  }
50
54
  },
51
55
  "workspaces": [
@@ -194,7 +198,8 @@
194
198
  "packages/toolcraft-openapi/dist",
195
199
  "packages/toolcraft-schema/dist",
196
200
  "packages/workspace-resolver/dist",
197
- "packages/worktree/dist"
201
+ "packages/worktree/dist",
202
+ "packages/safe-fs/dist/**/*.d.ts"
198
203
  ],
199
204
  "engines": {
200
205
  "node": ">=18.18"
@@ -270,6 +275,7 @@
270
275
  "@poe-code/providers": "*",
271
276
  "@poe-code/py-poe-spawn": "*",
272
277
  "@poe-code/ralph": "*",
278
+ "@poe-code/safe-fs": "*",
273
279
  "@poe-code/safejs": "*",
274
280
  "@poe-code/superintendent": "*",
275
281
  "@poe-code/task-list": "*",
@@ -0,0 +1,45 @@
1
+ export declare const canonicalFs: {
2
+ readonly workspace: "../../safe-fs/dist/index.js";
3
+ readonly specifier: "poe-code/safe-fs";
4
+ readonly source: "packages/safe-fs/src/index.ts";
5
+ readonly runtime: "packages/safejs/dist/safe-fs.js";
6
+ readonly types: "packages/safe-fs/dist/index.d.ts";
7
+ };
8
+ export interface BundleMetafile {
9
+ inputs?: Record<string, unknown>;
10
+ outputs?: Record<string, {
11
+ entryPoint?: string;
12
+ imports?: {
13
+ path?: string;
14
+ external?: boolean;
15
+ kind?: string;
16
+ }[];
17
+ inputs?: Record<string, unknown>;
18
+ cssBundle?: string;
19
+ }>;
20
+ canonicalBundle?: {
21
+ entryPoints: string[];
22
+ metafile: BundleMetafile;
23
+ };
24
+ }
25
+ export interface BundleIssue {
26
+ external: string;
27
+ reason: string;
28
+ }
29
+ interface PackageManifest {
30
+ name: string;
31
+ exports?: unknown;
32
+ dependencies?: Record<string, string>;
33
+ optionalDependencies?: Record<string, string>;
34
+ }
35
+ export declare function findBundleIssues(manifest: PackageManifest, workspaceNames: ReadonlySet<string>, metafile: BundleMetafile, packedFiles: ReadonlySet<string>): BundleIssue[];
36
+ export declare function collectPackageFiles(rootDir: string, entries: readonly string[], files: {
37
+ readdir(filename: string): Promise<{
38
+ name: string;
39
+ isDirectory(): boolean;
40
+ }[]>;
41
+ stat?(filename: string): Promise<{
42
+ isFile(): boolean;
43
+ }>;
44
+ }): Promise<Set<string>>;
45
+ export {};
@@ -0,0 +1,169 @@
1
+ import { isBuiltin } from "node:module";
2
+ import path from "node:path";
3
+ export const canonicalFs = {
4
+ workspace: "@poe-code/safe-fs",
5
+ specifier: "poe-code/safe-fs",
6
+ source: "packages/safe-fs/src/index.ts",
7
+ runtime: "packages/safejs/dist/safe-fs.js",
8
+ types: "packages/safe-fs/dist/index.d.ts"
9
+ };
10
+ function record(value) {
11
+ return value !== null && typeof value === "object" && !Array.isArray(value)
12
+ ? value
13
+ : {};
14
+ }
15
+ function packageName(specifier) {
16
+ if (!specifier ||
17
+ specifier.startsWith(".") ||
18
+ specifier.startsWith("/") ||
19
+ [...specifier].some((character) => character.charCodeAt(0) <= 32) ||
20
+ [":", "\\", "?", "#", "%"].some((character) => specifier.includes(character)))
21
+ return undefined;
22
+ const parts = specifier.split("/");
23
+ if (parts.some((part) => !part || part === "." || part === ".."))
24
+ return undefined;
25
+ if (specifier.startsWith("@")) {
26
+ if (parts.length < 2 || parts[0].length === 1)
27
+ return undefined;
28
+ return `${parts[0]}/${parts[1]}`;
29
+ }
30
+ return parts[0];
31
+ }
32
+ export function findBundleIssues(manifest, workspaceNames, metafile, packedFiles) {
33
+ const issues = [];
34
+ const exported = record(record(manifest.exports)["./safe-fs"]);
35
+ const imports = new Set(Object.values(metafile.outputs ?? {}).flatMap((output) => (output.imports ?? [])
36
+ .filter((dependency) => dependency.external)
37
+ .map((dependency) => dependency.path ?? "")));
38
+ const runtimeDependencies = new Set([
39
+ ...Object.keys(manifest.dependencies ?? {}),
40
+ ...Object.keys(manifest.optionalDependencies ?? {})
41
+ ]);
42
+ for (const specifier of [...imports].sort()) {
43
+ if (isBuiltin(specifier))
44
+ continue;
45
+ if (specifier === canonicalFs.specifier && manifest.name === "poe-code")
46
+ continue;
47
+ const dependency = packageName(specifier);
48
+ const reason = !dependency
49
+ ? "invalid-external"
50
+ : dependency === manifest.name || workspaceNames.has(dependency)
51
+ ? "workspace-not-inlined"
52
+ : !runtimeDependencies.has(dependency)
53
+ ? "undeclared-dependency"
54
+ : undefined;
55
+ if (reason)
56
+ issues.push({ external: specifier, reason });
57
+ }
58
+ if (!metafile.canonicalBundle &&
59
+ !imports.has(canonicalFs.specifier) &&
60
+ !Object.keys(exported).length)
61
+ return issues;
62
+ const fail = (reason) => issues.push({ external: canonicalFs.specifier, reason });
63
+ if (manifest.name !== "poe-code" ||
64
+ exported.import !== `./${canonicalFs.runtime}` ||
65
+ exported.types !== `./${canonicalFs.types}` ||
66
+ Object.keys(exported).some((condition) => condition !== "import" && condition !== "types")) {
67
+ fail("invalid-canonical-export");
68
+ }
69
+ if (!packedFiles.has(canonicalFs.types))
70
+ fail("unpacked-canonical-types");
71
+ if ([...packedFiles].some((filename) => filename.startsWith("packages/safe-fs/dist/") &&
72
+ [".js", ".mjs", ".cjs"].some((extension) => filename.endsWith(extension))))
73
+ fail("duplicate-packed-runtime");
74
+ if (Object.keys(metafile.inputs ?? {}).some((input) => input.startsWith("packages/safe-fs/src/"))) {
75
+ fail("duplicate-canonical-runtime");
76
+ }
77
+ const canonical = metafile.canonicalBundle;
78
+ if (!canonical ||
79
+ !Array.isArray(canonical.entryPoints) ||
80
+ !canonical.entryPoints.includes(canonicalFs.source)) {
81
+ fail("missing-canonical-root");
82
+ return issues;
83
+ }
84
+ const outputs = canonical.metafile.outputs ?? {};
85
+ if (!Object.hasOwn(canonical.metafile.inputs ?? {}, canonicalFs.source))
86
+ fail("missing-canonical-source");
87
+ if (outputs[canonicalFs.runtime]?.entryPoint !== canonicalFs.source)
88
+ fail("invalid-canonical-root");
89
+ for (const entry of canonical.entryPoints) {
90
+ if (!Object.values(outputs).some((output) => output.entryPoint === entry))
91
+ fail("missing-declared-root");
92
+ }
93
+ const pending = [canonicalFs.runtime];
94
+ const visited = new Set();
95
+ while (pending.length) {
96
+ const filename = pending.pop();
97
+ if (visited.has(filename))
98
+ continue;
99
+ visited.add(filename);
100
+ if (!filename.startsWith("packages/safejs/dist/") ||
101
+ path.posix.normalize(filename) !== filename) {
102
+ fail("invalid-canonical-path");
103
+ continue;
104
+ }
105
+ const output = outputs[filename];
106
+ if (!output) {
107
+ fail("missing-canonical-output");
108
+ continue;
109
+ }
110
+ if (!packedFiles.has(filename))
111
+ fail("unpacked-canonical-output");
112
+ if (filename.endsWith(".js"))
113
+ pending.push(`${filename}.map`);
114
+ if (Object.keys(output.inputs ?? {}).some((input) => !input.startsWith("packages/safe-fs/src/")))
115
+ fail("foreign-canonical-input");
116
+ if (output.cssBundle)
117
+ pending.push(output.cssBundle);
118
+ for (const dependency of output.imports ?? []) {
119
+ if (dependency.external) {
120
+ if (!dependency.path || !isBuiltin(dependency.path))
121
+ fail("external-canonical-dependency");
122
+ }
123
+ else if (dependency.path)
124
+ pending.push(dependency.path);
125
+ else
126
+ fail("missing-canonical-edge");
127
+ }
128
+ }
129
+ return issues;
130
+ }
131
+ export async function collectPackageFiles(rootDir, entries, files) {
132
+ const packed = new Set();
133
+ async function visit(filename, declarationsOnly) {
134
+ const absolute = path.join(rootDir, filename);
135
+ let children;
136
+ try {
137
+ children = await files.readdir(absolute);
138
+ }
139
+ catch (error) {
140
+ const code = error.code;
141
+ if (code === "ENOENT")
142
+ return;
143
+ if (code !== "ENOTDIR")
144
+ throw error;
145
+ if ((!declarationsOnly || filename.endsWith(".d.ts")) &&
146
+ (!files.stat || (await files.stat(absolute)).isFile()))
147
+ packed.add(filename);
148
+ return;
149
+ }
150
+ for (const child of children) {
151
+ const relative = path.posix.join(filename, child.name);
152
+ if (child.isDirectory())
153
+ await visit(relative, declarationsOnly);
154
+ else if (!declarationsOnly || child.name.endsWith(".d.ts"))
155
+ packed.add(relative);
156
+ }
157
+ }
158
+ for (const entry of entries) {
159
+ const declarationsOnly = entry.endsWith("/**/*.d.ts");
160
+ const directory = declarationsOnly ? entry.slice(0, -"/**/*.d.ts".length) : entry;
161
+ if (directory.includes("*") ||
162
+ directory.startsWith("/") ||
163
+ directory.split("/").includes("..")) {
164
+ throw new Error(`Unsupported package files entry: ${entry}`);
165
+ }
166
+ await visit(directory, declarationsOnly);
167
+ }
168
+ return packed;
169
+ }
@@ -1,3 +1,4 @@
1
+ import type { BundleMetafile } from "./bundle-policy.js";
1
2
  import { type PackageFileView, type PacklistProvider } from "./packlist.js";
2
3
  import { type RuntimeAssetDeclaration, type RuntimeFileAssetView } from "./runtime-files.js";
3
4
  import { type SourceImportView } from "./source-imports.js";
@@ -97,6 +98,8 @@ export interface BuildView {
97
98
  inlinedDirs: Set<string>;
98
99
  /** Bare specifiers left external by the bundle, reduced to package names. */
99
100
  externals: Set<string>;
101
+ externalImports: Set<string>;
102
+ metafile: BundleMetafile;
100
103
  }
101
104
  export interface Violation {
102
105
  rule: string;
@@ -133,16 +136,7 @@ export declare function loadWorkspace(fs: LintFs, rootDir: string, options?: {
133
136
  export declare function releaseTargetDirs(model: WorkspaceModel): Set<string>;
134
137
  /** A package genuinely reaches npm: it is a public npm package a release workflow publishes. */
135
138
  export declare function isGenuinelyPublished(model: WorkspaceModel, pkg: PackageInfo): boolean;
136
- export declare function parseMetafile(meta: {
137
- inputs?: Record<string, unknown>;
138
- outputs?: Record<string, {
139
- imports?: {
140
- path?: string;
141
- external?: boolean;
142
- kind?: string;
143
- }[];
144
- }>;
145
- }): BuildView;
139
+ export declare function parseMetafile(meta: BundleMetafile): BuildView;
146
140
  export declare function loadBuildView(fs: LintFs, rootDir: string): Promise<BuildView | undefined>;
147
141
  /** All workspace packages plus the root package. */
148
142
  export declare function allPackages(model: WorkspaceModel): PackageInfo[];
@@ -427,16 +427,18 @@ export function parseMetafile(meta) {
427
427
  inlinedDirs.add(dir);
428
428
  }
429
429
  const externals = new Set();
430
+ const externalImports = new Set();
430
431
  for (const output of Object.values(meta.outputs ?? {})) {
431
432
  for (const imp of output.imports ?? []) {
432
- if (imp.external && imp.kind !== "dynamic-import" && typeof imp.path === "string") {
433
+ if (imp.external && typeof imp.path === "string") {
434
+ externalImports.add(imp.path);
433
435
  const name = toPackageName(imp.path);
434
436
  if (name)
435
437
  externals.add(name);
436
438
  }
437
439
  }
438
440
  }
439
- return { inlinedDirs, externals };
441
+ return { inlinedDirs, externals, externalImports, metafile: meta };
440
442
  }
441
443
  export async function loadBuildView(fs, rootDir) {
442
444
  let raw;
@@ -1,4 +1,5 @@
1
1
  import path from "node:path";
2
+ import { collectPackageFiles } from "./bundle-policy.js";
2
3
  function toPosix(p) {
3
4
  return p.replaceAll("\\", "/");
4
5
  }
@@ -66,7 +67,10 @@ async function listFallbackPackFiles(fs, packageRoot) {
66
67
  return listAllFiles(fs, packageRoot);
67
68
  const files = new Set();
68
69
  for (const entry of allowlist) {
69
- for (const listed of await listFilesEntry(fs, packageRoot, entry))
70
+ const listedFiles = entry.endsWith("/**/*.d.ts")
71
+ ? await collectPackageFiles(packageRoot, [entry], fs)
72
+ : await listFilesEntry(fs, packageRoot, entry);
73
+ for (const listed of listedFiles)
70
74
  files.add(listed);
71
75
  }
72
76
  return files;
@@ -1,4 +1,4 @@
1
- import { isBuiltin } from "node:module";
1
+ import { findBundleIssues } from "../bundle-policy.js";
2
2
  const id = "bundle-self-contained";
3
3
  function workspaceNames(model) {
4
4
  const names = new Set(model.packages.map((p) => p.name));
@@ -18,30 +18,16 @@ export const bundleSelfContained = {
18
18
  return [];
19
19
  const violations = [];
20
20
  const workspace = workspaceNames(model);
21
- const rootDeps = new Set(Object.keys(model.root.dependencies));
22
- for (const external of [...build.externals].sort()) {
23
- if (workspace.has(external)) {
24
- violations.push({
25
- rule: id,
26
- package: external,
27
- severity: "error",
28
- via: "bundle",
29
- detail: { external, reason: "workspace-not-inlined" },
30
- message: `workspace package ${external} is externalized by the bundle instead of inlined; it is unpublished and will not resolve at runtime`,
31
- fix: `Add a source alias for ${external} so the bundle inlines it.`
32
- });
33
- }
34
- else if (!rootDeps.has(external) && !isBuiltin(external)) {
35
- violations.push({
36
- rule: id,
37
- package: model.root.name,
38
- severity: "error",
39
- via: "bundle",
40
- detail: { external, reason: "undeclared-dependency" },
41
- message: `bundle externalizes ${external}, which is not declared in root dependencies`,
42
- fix: `Add ${external} to root "dependencies".`
43
- });
44
- }
21
+ for (const issue of findBundleIssues(model.root, workspace, build.metafile, model.packageFiles.get(".")?.files ?? new Set())) {
22
+ violations.push({
23
+ rule: id,
24
+ package: workspace.has(issue.external) ? issue.external : model.root.name,
25
+ severity: "error",
26
+ via: "bundle",
27
+ detail: { ...issue },
28
+ message: `bundle import ${issue.external} violates publication policy: ${issue.reason}`,
29
+ fix: "Inline private workspace code or supply the exact declared and packed canonical artifact; declare ordinary runtime dependencies."
30
+ });
45
31
  }
46
32
  return violations;
47
33
  }
@@ -0,0 +1,5 @@
1
+ export interface AbortSignalScope {
2
+ readonly signal: AbortSignal;
3
+ dispose(): void;
4
+ }
5
+ export declare function composeAbortSignals(signals: readonly AbortSignal[]): AbortSignalScope;
@@ -0,0 +1 @@
1
+ export declare function finishCleanup(cleanup: () => unknown, failed: boolean): Promise<void>;
@@ -0,0 +1,49 @@
1
+ declare const descriptions: {
2
+ readonly EACCES: "permission denied";
3
+ readonly EAGAIN: "resource temporarily unavailable";
4
+ readonly EBADF: "bad file descriptor";
5
+ readonly EBUSY: "resource busy or locked";
6
+ readonly ECANCELED: "operation canceled";
7
+ readonly EEXIST: "file already exists";
8
+ readonly EFBIG: "file too large";
9
+ readonly EINTR: "interrupted system call";
10
+ readonly EINVAL: "invalid argument";
11
+ readonly EIO: "input/output error";
12
+ readonly EISDIR: "illegal operation on a directory";
13
+ readonly ELOOP: "too many symbolic links encountered";
14
+ readonly EMFILE: "too many open files";
15
+ readonly ENAMETOOLONG: "name too long";
16
+ readonly ENFILE: "file table overflow";
17
+ readonly ENOENT: "no such file or directory";
18
+ readonly ENOMEM: "not enough memory";
19
+ readonly ENOSPC: "no space left on device";
20
+ readonly ENOSYS: "function not implemented";
21
+ readonly ENOTDIR: "not a directory";
22
+ readonly ENOTEMPTY: "directory not empty";
23
+ readonly ENOTSUP: "operation not supported";
24
+ readonly EOPNOTSUPP: "operation not supported";
25
+ readonly EPERM: "operation not permitted";
26
+ readonly EPIPE: "broken pipe";
27
+ readonly EROFS: "read-only file system";
28
+ readonly ETIMEDOUT: "operation timed out";
29
+ readonly EXDEV: "cross-device link not permitted";
30
+ };
31
+ export type ErrnoCode = keyof typeof descriptions;
32
+ export interface FsErrorOptions extends ErrorOptions {
33
+ readonly syscall?: string;
34
+ readonly path?: string;
35
+ readonly dest?: string;
36
+ readonly message?: string;
37
+ }
38
+ export declare class FsError extends Error {
39
+ readonly code: ErrnoCode;
40
+ readonly errno: number;
41
+ readonly syscall?: string;
42
+ readonly path?: string;
43
+ readonly dest?: string;
44
+ constructor(code: ErrnoCode, options?: FsErrorOptions);
45
+ }
46
+ export declare function isErrnoCode(code: unknown): code is ErrnoCode;
47
+ export declare function isFsError(error: unknown, code?: ErrnoCode): error is FsError;
48
+ export declare function toFsError(error: unknown, options?: FsErrorOptions): FsError;
49
+ export {};
@@ -0,0 +1,96 @@
1
+ import type { ByteSource } from "./io.js";
2
+ export type FileType = "file" | "directory" | "symlink";
3
+ export type EntryComparison = "same" | "distinct" | "unknown";
4
+ export interface FileStat {
5
+ readonly type: FileType;
6
+ readonly size: number;
7
+ readonly allocatedBytes?: number;
8
+ readonly mode: number;
9
+ readonly mtimeMs: number;
10
+ readonly atimeMs: number;
11
+ readonly ctimeMs: number;
12
+ readonly birthtimeMs?: number;
13
+ readonly identityScope?: object | symbol;
14
+ readonly ino?: number;
15
+ readonly dev?: number;
16
+ readonly nlink?: number;
17
+ readonly uid?: number;
18
+ readonly gid?: number;
19
+ }
20
+ export interface DirectoryEntry {
21
+ readonly name: string;
22
+ readonly type: FileType;
23
+ }
24
+ export interface FileSystemCapabilities {
25
+ readonly readOnly?: boolean;
26
+ readonly symlinks?: boolean;
27
+ readonly hardlinks?: boolean;
28
+ readonly permissions?: boolean;
29
+ readonly timestamps?: boolean;
30
+ readonly atomicRename?: boolean;
31
+ readonly snapshotRmdir?: boolean;
32
+ readonly streamingRead?: boolean;
33
+ readonly streamingWrite?: boolean;
34
+ readonly [capability: string]: boolean | undefined;
35
+ }
36
+ export interface FsOptions {
37
+ readonly signal?: AbortSignal;
38
+ }
39
+ export interface ReadFileOptions extends FsOptions {
40
+ readonly maxBytes?: number;
41
+ }
42
+ export interface WriteFileOptions extends FsOptions {
43
+ readonly flag?: "w" | "wx" | "a" | "ax";
44
+ readonly mode?: number;
45
+ }
46
+ export interface AppendFileOptions extends FsOptions {
47
+ readonly mode?: number;
48
+ }
49
+ export interface MkdirOptions extends FsOptions {
50
+ readonly recursive?: boolean;
51
+ readonly mode?: number;
52
+ }
53
+ export interface RemoveOptions extends FsOptions {
54
+ readonly recursive?: boolean;
55
+ readonly force?: boolean;
56
+ }
57
+ export interface CopyFileOptions extends FsOptions {
58
+ readonly exclusive?: boolean;
59
+ }
60
+ export interface ReadStreamOptions extends FsOptions {
61
+ readonly start?: number;
62
+ readonly endExclusive?: number;
63
+ readonly chunkSize?: number;
64
+ }
65
+ export interface FileSystem {
66
+ readonly capabilities: FileSystemCapabilities;
67
+ readFile(path: string, options?: ReadFileOptions): Promise<Uint8Array>;
68
+ writeFile(path: string, data: Uint8Array, options?: WriteFileOptions): Promise<void>;
69
+ appendFile(path: string, data: Uint8Array, options?: AppendFileOptions): Promise<void>;
70
+ stat(path: string, options?: FsOptions): Promise<FileStat>;
71
+ lstat(path: string, options?: FsOptions): Promise<FileStat>;
72
+ compareEntry?(path: string, peer: FileSystem, peerPath: string, options?: FsOptions): Promise<EntryComparison>;
73
+ readdir(path: string, options?: FsOptions): Promise<DirectoryEntry[]>;
74
+ mkdir(path: string, options?: MkdirOptions): Promise<void>;
75
+ rm(path: string, options?: RemoveOptions): Promise<void>;
76
+ rmdir?(path: string, options?: FsOptions): Promise<void>;
77
+ rename(source: string, destination: string, options?: FsOptions): Promise<void>;
78
+ copyFile(source: string, destination: string, options?: CopyFileOptions): Promise<void>;
79
+ realpath(path: string, options?: FsOptions): Promise<string>;
80
+ access(path: string, mode?: number, options?: FsOptions): Promise<void>;
81
+ readlink?(path: string, options?: FsOptions): Promise<string>;
82
+ symlink?(target: string, path: string, options?: FsOptions): Promise<void>;
83
+ link?(existingPath: string, newPath: string, options?: FsOptions): Promise<void>;
84
+ chmod?(path: string, mode: number, options?: FsOptions): Promise<void>;
85
+ utimes?(path: string, atimeMs: number, mtimeMs: number, options?: FsOptions): Promise<void>;
86
+ truncate?(path: string, length?: number, options?: FsOptions): Promise<void>;
87
+ readStream?(path: string, options?: ReadStreamOptions): ByteSource;
88
+ writeStream?(path: string, source: ByteSource, options?: WriteFileOptions): Promise<void>;
89
+ }
90
+ export type FileSystemFactory = (options: Readonly<Record<string, unknown>>) => FileSystem | Promise<FileSystem>;
91
+ export declare const ACCESS_MODES: Readonly<{
92
+ F_OK: 0;
93
+ R_OK: 4;
94
+ W_OK: 2;
95
+ X_OK: 1;
96
+ }>;
@@ -0,0 +1,4 @@
1
+ export * from "./errors.js";
2
+ export * from "./filesystem.js";
3
+ export * from "./io.js";
4
+ export * from "./path.js";
@@ -0,0 +1,8 @@
1
+ export type ByteSource = AsyncIterable<Uint8Array>;
2
+ export interface CollectOptions {
3
+ readonly maxBytes: number;
4
+ readonly signal?: AbortSignal;
5
+ }
6
+ export declare function toByteSource(input: string | Uint8Array): ByteSource;
7
+ export declare function collectBytes(source: ByteSource, options: CollectOptions): Promise<Uint8Array>;
8
+ export declare function readBytes(source: ByteSource, signal?: AbortSignal): AsyncGenerator<Uint8Array>;
@@ -0,0 +1,13 @@
1
+ import { posix } from "node:path";
2
+ export declare const posixPath: typeof posix;
3
+ export declare const basename: typeof posix.basename;
4
+ export declare const dirname: typeof posix.dirname;
5
+ export declare const extname: typeof posix.extname;
6
+ export declare const joinPath: typeof posix.join;
7
+ export declare const isAbsolutePath: typeof posix.isAbsolute;
8
+ export declare function validatePath(path: string): void;
9
+ export declare function resolvePath(cwd: string, ...paths: string[]): string;
10
+ export declare function normalizePath(path: string, cwd?: string): string;
11
+ export declare function relativePath(from: string, to: string): string;
12
+ export declare function isPathWithin(root: string, path: string): boolean;
13
+ export declare function assertPathWithin(root: string, path: string): string;
@@ -0,0 +1,58 @@
1
+ import type { AppendFileOptions, CopyFileOptions, DirectoryEntry, EntryComparison, FileStat, FileSystem, FsOptions, MkdirOptions, ReadFileOptions, ReadStreamOptions, RemoveOptions, WriteFileOptions } from "../../contracts/filesystem.js";
2
+ import type { ByteSource } from "../../contracts/io.js";
3
+ export declare class MemoryFileSystem implements FileSystem {
4
+ readonly capabilities: Readonly<{
5
+ readOnly: false;
6
+ symlinks: true;
7
+ hardlinks: true;
8
+ permissions: true;
9
+ timestamps: true;
10
+ atomicRename: true;
11
+ streamingRead: true;
12
+ streamingWrite: true;
13
+ }>;
14
+ private readonly identityScope;
15
+ private nextInode;
16
+ private readonly root;
17
+ constructor();
18
+ compareEntry(path: string, peer: FileSystem, peerPath: string, options?: FsOptions): Promise<EntryComparison>;
19
+ private metadata;
20
+ private directory;
21
+ private fail;
22
+ private validatePath;
23
+ private permission;
24
+ private mode;
25
+ private integer;
26
+ private changed;
27
+ private resolve;
28
+ private file;
29
+ private entry;
30
+ private terminalDot;
31
+ private snapshot;
32
+ private bytes;
33
+ private allocate;
34
+ private openWrite;
35
+ private append;
36
+ readFile(path: string, options?: ReadFileOptions): Promise<Uint8Array>;
37
+ writeFile(path: string, data: Uint8Array, options?: WriteFileOptions): Promise<void>;
38
+ appendFile(path: string, data: Uint8Array, options?: AppendFileOptions): Promise<void>;
39
+ stat(path: string, options?: FsOptions): Promise<FileStat>;
40
+ lstat(path: string, options?: FsOptions): Promise<FileStat>;
41
+ readdir(path: string, options?: FsOptions): Promise<DirectoryEntry[]>;
42
+ mkdir(path: string, options?: MkdirOptions): Promise<void>;
43
+ rmdir(path: string, options?: FsOptions): Promise<void>;
44
+ rm(path: string, options?: RemoveOptions): Promise<void>;
45
+ rename(source: string, destination: string, options?: FsOptions): Promise<void>;
46
+ copyFile(source: string, destination: string, options?: CopyFileOptions): Promise<void>;
47
+ realpath(path: string, options?: FsOptions): Promise<string>;
48
+ access(path: string, mode?: number, options?: FsOptions): Promise<void>;
49
+ readlink(path: string, options?: FsOptions): Promise<string>;
50
+ symlink(target: string, path: string, options?: FsOptions): Promise<void>;
51
+ link(existingPath: string, newPath: string, options?: FsOptions): Promise<void>;
52
+ chmod(path: string, mode: number, options?: FsOptions): Promise<void>;
53
+ utimes(path: string, atimeMs: number, mtimeMs: number, options?: FsOptions): Promise<void>;
54
+ truncate(path: string, length?: number, options?: FsOptions): Promise<void>;
55
+ readStream(path: string, options?: ReadStreamOptions): ByteSource;
56
+ writeStream(path: string, source: ByteSource, options?: WriteFileOptions): Promise<void>;
57
+ }
58
+ export declare function createMemoryFileSystem(): MemoryFileSystem;
@@ -0,0 +1,18 @@
1
+ import type { EntryComparison, FileStat, FileSystem, FsOptions } from "../../contracts/filesystem.js";
2
+ export interface EntryLocation {
3
+ readonly filesystem: FileSystem;
4
+ readonly path: string;
5
+ readonly readOnly?: boolean;
6
+ readonly stat?: FileStat;
7
+ }
8
+ export interface EntryView extends EntryLocation {
9
+ readonly stat: FileStat;
10
+ readonly readOnly: boolean;
11
+ }
12
+ export type EntryViewResolver = (path: string, options: FsOptions) => Promise<EntryLocation>;
13
+ export type EntryAuthority = (own: EntryView, peer: EntryView, options: FsOptions) => Promise<EntryComparison>;
14
+ export declare function registerEntryView(filesystem: FileSystem, resolver: EntryViewResolver): void;
15
+ export declare function registerEntryAuthority(filesystem: FileSystem, authority: EntryAuthority): void;
16
+ export declare function resolveEntryView(filesystem: FileSystem, path: string, options?: FsOptions): Promise<EntryView>;
17
+ export declare function compareResolvedEntries(own: EntryView, peer: EntryView, options?: FsOptions): Promise<EntryComparison>;
18
+ export declare function compareEntries(filesystem: FileSystem, path: string, peer: FileSystem, peerPath: string, options?: FsOptions): Promise<EntryComparison>;
@@ -0,0 +1,2 @@
1
+ import type { FileStat } from "../../contracts/filesystem.js";
2
+ export declare function compareIdentity(left: FileStat | undefined, right: FileStat | undefined): "same" | "distinct" | "unknown";