poe-code 12.0.6 → 12.0.7

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 (56) hide show
  1. package/README.md +20 -1
  2. package/dist/index.js +46 -5
  3. package/dist/index.js.map +2 -2
  4. package/dist/metafile.json +1 -1
  5. package/package.json +46 -5
  6. package/packages/package-lint/dist/bundle-policy.d.ts +144 -1
  7. package/packages/package-lint/dist/bundle-policy.js +289 -60
  8. package/packages/package-lint/dist/model.d.ts +2 -1
  9. package/packages/package-lint/dist/model.js +8 -1
  10. package/packages/safe-fs/dist/bridge/filesystem.d.ts +88 -0
  11. package/packages/safe-fs/dist/bridge/index.d.ts +6 -0
  12. package/packages/safe-fs/dist/bridge/stats.d.ts +4 -0
  13. package/packages/safe-fs/dist/bridge/types.d.ts +75 -0
  14. package/packages/safe-fs/dist/bridge/values.d.ts +6 -0
  15. package/packages/safe-fs/dist/contracts/errors.d.ts +3 -2
  16. package/packages/safe-fs/dist/contracts/path.d.ts +1 -6
  17. package/packages/safe-fs/dist/contracts/virtual-path.d.ts +7 -0
  18. package/packages/safe-fs/dist/core.d.ts +11 -0
  19. package/packages/safe-fs/dist/fs/mount/comparison.d.ts +1 -0
  20. package/packages/safe-fs/dist/fs/overlay/index.d.ts +2 -1
  21. package/packages/safe-fs/dist/fs/readonly/index.d.ts +2 -1
  22. package/packages/safe-fs/dist/fs/s3/authority.d.ts +3 -9
  23. package/packages/safe-fs/dist/fs/s3/registry.d.ts +10 -0
  24. package/packages/safe-fs/dist/fs/webdav/webdav.d.ts +2 -1
  25. package/packages/safe-fs/dist/node/stats.d.ts +1 -4
  26. package/packages/safe-fs/dist/node/values.d.ts +1 -6
  27. package/packages/safe-fs/dist/node-host.d.ts +1 -0
  28. package/packages/safe-fs/dist/node-unavailable.d.ts +1 -0
  29. package/packages/safe-fs/dist/platform/browser.d.ts +12 -0
  30. package/packages/safe-fs/dist/platform/node.d.ts +13 -0
  31. package/packages/safejs/dist/browser/chunks/chunk-MUKMA7ZY.js +4053 -0
  32. package/packages/safejs/dist/browser/chunks/chunk-MUKMA7ZY.js.map +7 -0
  33. package/packages/safejs/dist/browser/safe-fs-core.js +55 -0
  34. package/packages/safejs/dist/browser/safe-fs-core.js.map +7 -0
  35. package/packages/safejs/dist/browser/safe-fs.js +55 -0
  36. package/packages/safejs/dist/browser/safe-fs.js.map +7 -0
  37. package/packages/safejs/dist/chunks/chunk-F7NY24BF.js +2603 -0
  38. package/packages/safejs/dist/chunks/chunk-F7NY24BF.js.map +7 -0
  39. package/packages/safejs/dist/chunks/{chunk-KJSS53IH.js → chunk-NTYX57KK.js} +6 -4
  40. package/packages/safejs/dist/chunks/{chunk-KJSS53IH.js.map → chunk-NTYX57KK.js.map} +1 -1
  41. package/packages/safejs/dist/chunks/{chunk-B3G3JVCW.js → chunk-YBQUQPZV.js} +637 -3120
  42. package/packages/safejs/dist/chunks/chunk-YBQUQPZV.js.map +7 -0
  43. package/packages/safejs/dist/cli.js +3 -2
  44. package/packages/safejs/dist/cli.js.map +1 -1
  45. package/packages/safejs/dist/index.js +3 -2
  46. package/packages/safejs/dist/index.js.map +1 -1
  47. package/packages/safejs/dist/safe-fs-core.js +80 -0
  48. package/packages/safejs/dist/safe-fs-core.js.map +7 -0
  49. package/packages/safejs/dist/safe-fs-node.js +94 -0
  50. package/packages/safejs/dist/safe-fs-node.js.map +7 -0
  51. package/packages/safejs/dist/safe-fs.js +20 -18
  52. package/packages/terminal-pilot/dist/commands/index.d.ts +2 -2
  53. package/packages/terminal-pilot/dist/commands/installer.d.ts +1 -1
  54. package/packages/tiny-mcp-client/dist/index.d.ts +1 -1
  55. package/packages/toolcraft/dist/mcp.d.ts +3 -3
  56. package/packages/safejs/dist/chunks/chunk-B3G3JVCW.js.map +0 -7
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "poe-code",
3
- "version": "12.0.6",
3
+ "version": "12.0.7",
4
4
  "description": "CLI tool to configure Poe API for developer workflows.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -16,15 +16,27 @@
16
16
  "import": "./packages/memory/dist/index.js"
17
17
  },
18
18
  "./safejs": {
19
- "types": "./packages/safejs/dist/index.d.ts",
19
+ "types": {
20
+ "browser": "./packages/safe-fs/dist/node-unavailable.d.ts",
21
+ "default": "./packages/safejs/dist/index.d.ts"
22
+ },
23
+ "browser": null,
20
24
  "import": "./packages/safejs/dist/index.js"
21
25
  },
22
26
  "./safejs/core": {
23
- "types": "./packages/safejs/dist/core.d.ts",
27
+ "types": {
28
+ "browser": "./packages/safe-fs/dist/node-unavailable.d.ts",
29
+ "default": "./packages/safejs/dist/core.d.ts"
30
+ },
31
+ "browser": null,
24
32
  "import": "./packages/safejs/dist/core.js"
25
33
  },
26
34
  "./safejs/cli": {
27
- "types": "./packages/safejs/dist/cli.d.ts",
35
+ "types": {
36
+ "browser": "./packages/safe-fs/dist/node-unavailable.d.ts",
37
+ "default": "./packages/safejs/dist/cli.d.ts"
38
+ },
39
+ "browser": null,
28
40
  "import": "./packages/safejs/dist/cli.js"
29
41
  },
30
42
  "./agent": {
@@ -48,8 +60,28 @@
48
60
  "import": "./dist/skills.js"
49
61
  },
50
62
  "./safe-fs": {
51
- "types": "./packages/safe-fs/dist/index.d.ts",
63
+ "types": {
64
+ "browser": "./packages/safe-fs/dist/core.d.ts",
65
+ "default": "./packages/safe-fs/dist/index.d.ts"
66
+ },
67
+ "browser": "./packages/safejs/dist/browser/safe-fs.js",
52
68
  "import": "./packages/safejs/dist/safe-fs.js"
69
+ },
70
+ "./safe-fs/core": {
71
+ "types": {
72
+ "browser": "./packages/safe-fs/dist/core.d.ts",
73
+ "default": "./packages/safe-fs/dist/core.d.ts"
74
+ },
75
+ "browser": "./packages/safejs/dist/browser/safe-fs-core.js",
76
+ "import": "./packages/safejs/dist/safe-fs-core.js"
77
+ },
78
+ "./safe-fs/node": {
79
+ "types": {
80
+ "browser": "./packages/safe-fs/dist/node-unavailable.d.ts",
81
+ "default": "./packages/safe-fs/dist/node-host.d.ts"
82
+ },
83
+ "browser": null,
84
+ "import": "./packages/safejs/dist/safe-fs-node.js"
53
85
  }
54
86
  },
55
87
  "workspaces": [
@@ -338,5 +370,14 @@
338
370
  "ini": "5.0.0",
339
371
  "toml": "3.0.0",
340
372
  "vite": "6.4.3"
373
+ },
374
+ "imports": {
375
+ "#safe-fs-platform": {
376
+ "types": {
377
+ "browser": "./packages/safe-fs/dist/platform/browser.d.ts",
378
+ "default": "./packages/safe-fs/dist/platform/node.d.ts"
379
+ },
380
+ "default": null
381
+ }
341
382
  }
342
383
  }
@@ -1,9 +1,138 @@
1
+ export declare const canonicalFsRoutes: readonly [{
2
+ readonly workspace: "@poe-code/safe-fs";
3
+ readonly specifier: "poe-code/safe-fs";
4
+ readonly key: "./safe-fs";
5
+ readonly source: {
6
+ readonly node: "packages/safe-fs/src/index.ts";
7
+ readonly browser: "packages/safe-fs/src/core.ts";
8
+ };
9
+ readonly runtime: {
10
+ readonly node: "packages/safejs/dist/safe-fs.js";
11
+ readonly browser: "packages/safejs/dist/browser/safe-fs.js";
12
+ };
13
+ readonly types: {
14
+ readonly node: "packages/safe-fs/dist/index.d.ts";
15
+ readonly browser: "packages/safe-fs/dist/core.d.ts";
16
+ };
17
+ }, {
18
+ readonly workspace: "@poe-code/safe-fs/core";
19
+ readonly specifier: "poe-code/safe-fs/core";
20
+ readonly key: "./safe-fs/core";
21
+ readonly source: {
22
+ readonly node: "packages/safe-fs/src/core.ts";
23
+ readonly browser: "packages/safe-fs/src/core.ts";
24
+ };
25
+ readonly runtime: {
26
+ readonly node: "packages/safejs/dist/safe-fs-core.js";
27
+ readonly browser: "packages/safejs/dist/browser/safe-fs-core.js";
28
+ };
29
+ readonly types: {
30
+ readonly node: "packages/safe-fs/dist/core.d.ts";
31
+ readonly browser: "packages/safe-fs/dist/core.d.ts";
32
+ };
33
+ }, {
34
+ readonly workspace: "@poe-code/safe-fs/node";
35
+ readonly specifier: "poe-code/safe-fs/node";
36
+ readonly key: "./safe-fs/node";
37
+ readonly source: {
38
+ readonly node: "packages/safe-fs/src/node-host.ts";
39
+ readonly browser: null;
40
+ };
41
+ readonly runtime: {
42
+ readonly node: "packages/safejs/dist/safe-fs-node.js";
43
+ readonly browser: null;
44
+ };
45
+ readonly types: {
46
+ readonly node: "packages/safe-fs/dist/node-host.d.ts";
47
+ readonly browser: "packages/safe-fs/dist/node-unavailable.d.ts";
48
+ };
49
+ }];
50
+ export declare const canonicalFsProfiles: {
51
+ readonly node: {
52
+ readonly outdir: "packages/safejs/dist";
53
+ readonly policy: "packages/safe-fs/src/platform/node.ts";
54
+ readonly types: "packages/safe-fs/dist/platform/node.d.ts";
55
+ };
56
+ readonly browser: {
57
+ readonly outdir: "packages/safejs/dist/browser";
58
+ readonly policy: "packages/safe-fs/src/platform/browser.ts";
59
+ readonly types: "packages/safe-fs/dist/platform/browser.d.ts";
60
+ };
61
+ };
62
+ export declare const canonicalFsExports: {
63
+ [k: string]: {
64
+ types: {
65
+ browser: string;
66
+ default: string;
67
+ };
68
+ browser: string | null;
69
+ import: string;
70
+ };
71
+ };
72
+ export declare const canonicalFsTypeImports: {
73
+ "#safe-fs-platform": {
74
+ types: {
75
+ browser: string;
76
+ default: string;
77
+ };
78
+ default: null;
79
+ };
80
+ };
1
81
  export declare const canonicalFs: {
2
- readonly workspace: "../../safe-fs/dist/index.js";
82
+ readonly workspace: "@poe-code/safe-fs";
3
83
  readonly specifier: "poe-code/safe-fs";
4
84
  readonly source: "packages/safe-fs/src/index.ts";
5
85
  readonly runtime: "packages/safejs/dist/safe-fs.js";
6
86
  readonly types: "packages/safe-fs/dist/index.d.ts";
87
+ readonly routes: readonly [{
88
+ readonly workspace: "@poe-code/safe-fs";
89
+ readonly specifier: "poe-code/safe-fs";
90
+ readonly key: "./safe-fs";
91
+ readonly source: {
92
+ readonly node: "packages/safe-fs/src/index.ts";
93
+ readonly browser: "packages/safe-fs/src/core.ts";
94
+ };
95
+ readonly runtime: {
96
+ readonly node: "packages/safejs/dist/safe-fs.js";
97
+ readonly browser: "packages/safejs/dist/browser/safe-fs.js";
98
+ };
99
+ readonly types: {
100
+ readonly node: "packages/safe-fs/dist/index.d.ts";
101
+ readonly browser: "packages/safe-fs/dist/core.d.ts";
102
+ };
103
+ }, {
104
+ readonly workspace: "@poe-code/safe-fs/core";
105
+ readonly specifier: "poe-code/safe-fs/core";
106
+ readonly key: "./safe-fs/core";
107
+ readonly source: {
108
+ readonly node: "packages/safe-fs/src/core.ts";
109
+ readonly browser: "packages/safe-fs/src/core.ts";
110
+ };
111
+ readonly runtime: {
112
+ readonly node: "packages/safejs/dist/safe-fs-core.js";
113
+ readonly browser: "packages/safejs/dist/browser/safe-fs-core.js";
114
+ };
115
+ readonly types: {
116
+ readonly node: "packages/safe-fs/dist/core.d.ts";
117
+ readonly browser: "packages/safe-fs/dist/core.d.ts";
118
+ };
119
+ }, {
120
+ readonly workspace: "@poe-code/safe-fs/node";
121
+ readonly specifier: "poe-code/safe-fs/node";
122
+ readonly key: "./safe-fs/node";
123
+ readonly source: {
124
+ readonly node: "packages/safe-fs/src/node-host.ts";
125
+ readonly browser: null;
126
+ };
127
+ readonly runtime: {
128
+ readonly node: "packages/safejs/dist/safe-fs-node.js";
129
+ readonly browser: null;
130
+ };
131
+ readonly types: {
132
+ readonly node: "packages/safe-fs/dist/node-host.d.ts";
133
+ readonly browser: "packages/safe-fs/dist/node-unavailable.d.ts";
134
+ };
135
+ }];
7
136
  };
8
137
  export interface BundleMetafile {
9
138
  inputs?: Record<string, unknown>;
@@ -21,6 +150,12 @@ export interface BundleMetafile {
21
150
  entryPoints: string[];
22
151
  metafile: BundleMetafile;
23
152
  };
153
+ browserCanonicalBundle?: {
154
+ entryPoints: string[];
155
+ metafile: BundleMetafile;
156
+ };
157
+ canonicalTypes?: Record<string, string[]>;
158
+ canonicalEmptyTypes?: string[];
24
159
  }
25
160
  export interface BundleIssue {
26
161
  external: string;
@@ -29,10 +164,18 @@ export interface BundleIssue {
29
164
  interface PackageManifest {
30
165
  name: string;
31
166
  exports?: unknown;
167
+ imports?: unknown;
32
168
  dependencies?: Record<string, string>;
33
169
  optionalDependencies?: Record<string, string>;
34
170
  }
35
171
  export declare function findBundleIssues(manifest: PackageManifest, workspaceNames: ReadonlySet<string>, metafile: BundleMetafile, packedFiles: ReadonlySet<string>): BundleIssue[];
172
+ export declare function collectCanonicalDeclarations(rootDir: string, files: {
173
+ readdir(filename: string): Promise<{
174
+ name: string;
175
+ isDirectory(): boolean;
176
+ }[]>;
177
+ readFile(filename: string): Promise<string>;
178
+ }): Promise<Pick<BundleMetafile, "canonicalTypes" | "canonicalEmptyTypes">>;
36
179
  export declare function collectPackageFiles(rootDir: string, entries: readonly string[], files: {
37
180
  readdir(filename: string): Promise<{
38
181
  name: string;
@@ -1,11 +1,91 @@
1
1
  import { isBuiltin } from "node:module";
2
2
  import path from "node:path";
3
+ export const canonicalFsRoutes = [
4
+ {
5
+ workspace: "@poe-code/safe-fs",
6
+ specifier: "poe-code/safe-fs",
7
+ key: "./safe-fs",
8
+ source: { node: "packages/safe-fs/src/index.ts", browser: "packages/safe-fs/src/core.ts" },
9
+ runtime: {
10
+ node: "packages/safejs/dist/safe-fs.js",
11
+ browser: "packages/safejs/dist/browser/safe-fs.js"
12
+ },
13
+ types: { node: "packages/safe-fs/dist/index.d.ts", browser: "packages/safe-fs/dist/core.d.ts" }
14
+ },
15
+ {
16
+ workspace: "@poe-code/safe-fs/core",
17
+ specifier: "poe-code/safe-fs/core",
18
+ key: "./safe-fs/core",
19
+ source: { node: "packages/safe-fs/src/core.ts", browser: "packages/safe-fs/src/core.ts" },
20
+ runtime: {
21
+ node: "packages/safejs/dist/safe-fs-core.js",
22
+ browser: "packages/safejs/dist/browser/safe-fs-core.js"
23
+ },
24
+ types: { node: "packages/safe-fs/dist/core.d.ts", browser: "packages/safe-fs/dist/core.d.ts" }
25
+ },
26
+ {
27
+ workspace: "@poe-code/safe-fs/node",
28
+ specifier: "poe-code/safe-fs/node",
29
+ key: "./safe-fs/node",
30
+ source: { node: "packages/safe-fs/src/node-host.ts", browser: null },
31
+ runtime: { node: "packages/safejs/dist/safe-fs-node.js", browser: null },
32
+ types: {
33
+ node: "packages/safe-fs/dist/node-host.d.ts",
34
+ browser: "packages/safe-fs/dist/node-unavailable.d.ts"
35
+ }
36
+ }
37
+ ];
38
+ export const canonicalFsProfiles = {
39
+ node: {
40
+ outdir: "packages/safejs/dist",
41
+ policy: "packages/safe-fs/src/platform/node.ts",
42
+ types: "packages/safe-fs/dist/platform/node.d.ts"
43
+ },
44
+ browser: {
45
+ outdir: "packages/safejs/dist/browser",
46
+ policy: "packages/safe-fs/src/platform/browser.ts",
47
+ types: "packages/safe-fs/dist/platform/browser.d.ts"
48
+ }
49
+ };
50
+ export const canonicalFsExports = Object.fromEntries(canonicalFsRoutes.map((route) => [
51
+ route.key,
52
+ {
53
+ types: { browser: `./${route.types.browser}`, default: `./${route.types.node}` },
54
+ browser: route.runtime.browser === null ? null : `./${route.runtime.browser}`,
55
+ import: `./${route.runtime.node}`
56
+ }
57
+ ]));
58
+ const nodeOnlySafeJsExports = Object.fromEntries([
59
+ ["./safejs", "index"],
60
+ ["./safejs/core", "core"],
61
+ ["./safejs/cli", "cli"]
62
+ ].map(([route, entry]) => [
63
+ route,
64
+ {
65
+ types: {
66
+ browser: "./packages/safe-fs/dist/node-unavailable.d.ts",
67
+ default: `./packages/safejs/dist/${entry}.d.ts`
68
+ },
69
+ browser: null,
70
+ import: `./packages/safejs/dist/${entry}.js`
71
+ }
72
+ ]));
73
+ export const canonicalFsTypeImports = {
74
+ "#safe-fs-platform": {
75
+ types: {
76
+ browser: `./${canonicalFsProfiles.browser.types}`,
77
+ default: `./${canonicalFsProfiles.node.types}`
78
+ },
79
+ default: null
80
+ }
81
+ };
3
82
  export const canonicalFs = {
4
83
  workspace: "@poe-code/safe-fs",
5
84
  specifier: "poe-code/safe-fs",
6
85
  source: "packages/safe-fs/src/index.ts",
7
86
  runtime: "packages/safejs/dist/safe-fs.js",
8
- types: "packages/safe-fs/dist/index.d.ts"
87
+ types: "packages/safe-fs/dist/index.d.ts",
88
+ routes: canonicalFsRoutes
9
89
  };
10
90
  function record(value) {
11
91
  return value !== null && typeof value === "object" && !Array.isArray(value)
@@ -31,7 +111,8 @@ function packageName(specifier) {
31
111
  }
32
112
  export function findBundleIssues(manifest, workspaceNames, metafile, packedFiles) {
33
113
  const issues = [];
34
- const exported = record(record(manifest.exports)["./safe-fs"]);
114
+ const exported = record(manifest.exports);
115
+ const routes = new Set(canonicalFsRoutes.map((route) => route.specifier));
35
116
  const imports = new Set(Object.values(metafile.outputs ?? {}).flatMap((output) => (output.imports ?? [])
36
117
  .filter((dependency) => dependency.external)
37
118
  .map((dependency) => dependency.path ?? "")));
@@ -42,7 +123,7 @@ export function findBundleIssues(manifest, workspaceNames, metafile, packedFiles
42
123
  for (const specifier of [...imports].sort()) {
43
124
  if (isBuiltin(specifier))
44
125
  continue;
45
- if (specifier === canonicalFs.specifier && manifest.name === "poe-code")
126
+ if (routes.has(specifier) && manifest.name === "poe-code")
46
127
  continue;
47
128
  const dependency = packageName(specifier);
48
129
  const reason = !dependency
@@ -55,79 +136,227 @@ export function findBundleIssues(manifest, workspaceNames, metafile, packedFiles
55
136
  if (reason)
56
137
  issues.push({ external: specifier, reason });
57
138
  }
139
+ const exportKeys = Object.keys(exported).filter((key) => key === "./safe-fs" || key.startsWith("./safe-fs/"));
58
140
  if (!metafile.canonicalBundle &&
59
- !imports.has(canonicalFs.specifier) &&
60
- !Object.keys(exported).length)
141
+ !metafile.browserCanonicalBundle &&
142
+ !exportKeys.length &&
143
+ ![...imports].some((specifier) => routes.has(specifier)))
61
144
  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")) {
145
+ const fail = (reason, external = canonicalFs.specifier) => {
146
+ if (!issues.some((issue) => issue.external === external && issue.reason === reason))
147
+ issues.push({ external, reason });
148
+ };
149
+ for (const route of canonicalFsRoutes) {
150
+ if (manifest.name !== "poe-code" ||
151
+ JSON.stringify(exported[route.key]) !== JSON.stringify(canonicalFsExports[route.key]))
152
+ fail("invalid-canonical-export", route.specifier);
153
+ }
154
+ if (exportKeys.some((key) => !canonicalFsRoutes.some((route) => route.key === key)))
67
155
  fail("invalid-canonical-export");
156
+ for (const [key, expected] of Object.entries(nodeOnlySafeJsExports)) {
157
+ if (JSON.stringify(exported[key]) !== JSON.stringify(expected))
158
+ fail("invalid-node-only-safejs-export", `poe-code${key.slice(1)}`);
159
+ }
160
+ if (JSON.stringify(record(manifest.imports)["#safe-fs-platform"]) !==
161
+ JSON.stringify(canonicalFsTypeImports["#safe-fs-platform"]))
162
+ fail("invalid-canonical-type-import");
163
+ const canonicalPaths = canonicalFsRoutes
164
+ .flatMap((route) => [...Object.values(route.runtime), ...Object.values(route.types)])
165
+ .filter((filename) => filename !== null);
166
+ for (const filename of canonicalPaths) {
167
+ let directory = path.posix.dirname(filename);
168
+ while (directory !== ".") {
169
+ if (packedFiles.has(`${directory}/package.json`))
170
+ fail("nested-canonical-package-scope");
171
+ directory = path.posix.dirname(directory);
172
+ }
68
173
  }
69
- if (!packedFiles.has(canonicalFs.types))
70
- fail("unpacked-canonical-types");
71
174
  if ([...packedFiles].some((filename) => filename.startsWith("packages/safe-fs/dist/") &&
72
175
  [".js", ".mjs", ".cjs"].some((extension) => filename.endsWith(extension))))
73
176
  fail("duplicate-packed-runtime");
74
- if (Object.keys(metafile.inputs ?? {}).some((input) => input.startsWith("packages/safe-fs/src/"))) {
177
+ if (Object.keys(metafile.inputs ?? {}).some((input) => input.startsWith("packages/safe-fs/src/")))
75
178
  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");
179
+ const emptyTypes = "packages/safe-fs/dist/node-unavailable.d.ts";
180
+ if (!metafile.canonicalEmptyTypes?.includes(emptyTypes))
181
+ fail("nonempty-browser-node-types", "poe-code/safe-fs/node");
182
+ for (const profile of ["node", "browser"]) {
183
+ const settings = canonicalFsProfiles[profile];
184
+ const canonical = profile === "node" ? metafile.canonicalBundle : metafile.browserCanonicalBundle;
185
+ if (!canonical || !Array.isArray(canonical.entryPoints)) {
186
+ fail("missing-canonical-root");
103
187
  continue;
104
188
  }
105
- const output = outputs[filename];
106
- if (!output) {
107
- fail("missing-canonical-output");
108
- continue;
189
+ const inputs = canonical.metafile.inputs ?? {};
190
+ if (!Object.hasOwn(inputs, settings.policy) ||
191
+ Object.hasOwn(inputs, canonicalFsProfiles[profile === "node" ? "browser" : "node"].policy))
192
+ fail("wrong-canonical-policy");
193
+ const outputs = canonical.metafile.outputs ?? {};
194
+ for (const singleton of [
195
+ "contracts/errors.ts",
196
+ "bridge/filesystem.ts",
197
+ "fs/memory/index.ts",
198
+ "fs/mount/comparison.ts",
199
+ "fs/s3/registry.ts",
200
+ "fs/s3/authority.ts",
201
+ `platform/${profile}.ts`
202
+ ]) {
203
+ const source = `packages/safe-fs/src/${singleton}`;
204
+ if (!Object.hasOwn(inputs, source))
205
+ continue;
206
+ const copies = Object.entries(outputs).filter(([filename, output]) => packedFiles.has(filename) && Object.hasOwn(output.inputs ?? {}, source));
207
+ if (copies.length > 1)
208
+ fail("duplicate-canonical-singleton");
209
+ }
210
+ const pending = [];
211
+ for (const route of canonicalFsRoutes) {
212
+ const source = route.source[profile];
213
+ const runtime = route.runtime[profile];
214
+ if (source === null || runtime === null)
215
+ continue;
216
+ if (!canonical.entryPoints.includes(source))
217
+ fail("missing-canonical-root", route.specifier);
218
+ if (!Object.hasOwn(inputs, source))
219
+ fail("missing-canonical-source", route.specifier);
220
+ if (outputs[runtime]?.entryPoint !== source)
221
+ fail("invalid-canonical-root", route.specifier);
222
+ pending.push(runtime);
223
+ }
224
+ for (const entry of canonical.entryPoints) {
225
+ if (!Object.values(outputs).some((output) => output.entryPoint === entry))
226
+ fail("missing-declared-root");
109
227
  }
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");
228
+ const rootedOutputs = new Set();
229
+ const rootedPending = Object.entries(outputs)
230
+ .filter(([, output]) => output.entryPoint && canonical.entryPoints.includes(output.entryPoint))
231
+ .map(([filename]) => filename);
232
+ while (rootedPending.length) {
233
+ const filename = rootedPending.pop();
234
+ if (rootedOutputs.has(filename))
235
+ continue;
236
+ rootedOutputs.add(filename);
237
+ for (const dependency of outputs[filename]?.imports ?? []) {
238
+ if (!dependency.external && dependency.path)
239
+ rootedPending.push(dependency.path);
240
+ }
241
+ }
242
+ for (const [filename, output] of Object.entries(outputs)) {
243
+ if (output.entryPoint && !rootedOutputs.has(filename) && packedFiles.has(filename))
244
+ fail("undeclared-canonical-root");
245
+ }
246
+ const visited = new Set();
247
+ while (pending.length) {
248
+ const filename = pending.pop();
249
+ if (visited.has(filename))
250
+ continue;
251
+ visited.add(filename);
252
+ if (!filename.startsWith(`${settings.outdir}/`) ||
253
+ path.posix.normalize(filename) !== filename ||
254
+ (profile === "node" && filename.startsWith(`${canonicalFsProfiles.browser.outdir}/`))) {
255
+ fail("invalid-canonical-path");
256
+ continue;
257
+ }
258
+ const output = outputs[filename];
259
+ if (!output) {
260
+ fail("missing-canonical-output");
261
+ continue;
262
+ }
263
+ if (!packedFiles.has(filename))
264
+ fail("unpacked-canonical-output");
265
+ if (filename.endsWith(".js"))
266
+ pending.push(`${filename}.map`);
267
+ if (Object.keys(output.inputs ?? {}).some((input) => !input.startsWith("packages/safe-fs/src/")))
268
+ fail("foreign-canonical-input");
269
+ if (output.cssBundle)
270
+ pending.push(output.cssBundle);
271
+ for (const dependency of output.imports ?? []) {
272
+ if (dependency.external) {
273
+ if (profile === "browser" || !dependency.path || !isBuiltin(dependency.path))
274
+ fail("external-canonical-dependency");
275
+ }
276
+ else if (dependency.path)
277
+ pending.push(dependency.path);
278
+ else
279
+ fail("missing-canonical-edge");
280
+ }
281
+ }
282
+ const typeQueue = canonicalFsRoutes.map((route) => route.types[profile]);
283
+ typeQueue.push(settings.types);
284
+ const seenTypes = new Set();
285
+ while (typeQueue.length) {
286
+ const filename = typeQueue.pop();
287
+ if (seenTypes.has(filename))
288
+ continue;
289
+ seenTypes.add(filename);
290
+ if (!filename.startsWith("packages/safe-fs/dist/") ||
291
+ path.posix.normalize(filename) !== filename ||
292
+ !filename.endsWith(".d.ts")) {
293
+ fail("invalid-canonical-types-path");
294
+ continue;
295
+ }
296
+ if (!packedFiles.has(filename))
297
+ fail("unpacked-canonical-types");
298
+ const edges = metafile.canonicalTypes?.[filename];
299
+ if (!Array.isArray(edges)) {
300
+ fail("missing-canonical-types");
301
+ continue;
302
+ }
303
+ for (const edge of edges) {
304
+ if (edge === "#safe-fs-platform")
305
+ typeQueue.push(settings.types);
306
+ else if (isBuiltin(edge)) {
307
+ if (profile === "browser")
308
+ fail("external-canonical-types");
309
+ }
310
+ else if (edge.startsWith(".") &&
311
+ !["?", "#", "%", "\\", ":"].some((character) => edge.includes(character)) &&
312
+ (edge.endsWith(".js") || edge.endsWith(".d.ts"))) {
313
+ const target = edge.endsWith(".js") ? `${edge.slice(0, -3)}.d.ts` : edge;
314
+ typeQueue.push(path.posix.normalize(path.posix.join(path.posix.dirname(filename), target)));
315
+ }
316
+ else
317
+ fail("external-canonical-types");
122
318
  }
123
- else if (dependency.path)
124
- pending.push(dependency.path);
125
- else
126
- fail("missing-canonical-edge");
127
319
  }
128
320
  }
129
321
  return issues;
130
322
  }
323
+ export async function collectCanonicalDeclarations(rootDir, files) {
324
+ const { default: ts } = await import("typescript");
325
+ const declarations = await collectPackageFiles(rootDir, ["packages/safe-fs/dist/**/*.d.ts"], files);
326
+ const canonicalTypes = {};
327
+ const canonicalEmptyTypes = [];
328
+ for (const filename of declarations) {
329
+ const source = ts.createSourceFile(filename, await files.readFile(path.join(rootDir, filename)), ts.ScriptTarget.Latest, true);
330
+ const imports = new Set(source.referencedFiles.map((reference) => reference.fileName));
331
+ const visit = (node) => {
332
+ if ((ts.isImportDeclaration(node) || ts.isExportDeclaration(node)) &&
333
+ node.moduleSpecifier &&
334
+ ts.isStringLiteral(node.moduleSpecifier))
335
+ imports.add(node.moduleSpecifier.text);
336
+ if (ts.isImportTypeNode(node) &&
337
+ ts.isLiteralTypeNode(node.argument) &&
338
+ ts.isStringLiteral(node.argument.literal))
339
+ imports.add(node.argument.literal.text);
340
+ if (ts.isExternalModuleReference(node) &&
341
+ node.expression &&
342
+ ts.isStringLiteral(node.expression))
343
+ imports.add(node.expression.text);
344
+ ts.forEachChild(node, visit);
345
+ };
346
+ visit(source);
347
+ for (const reference of source.typeReferenceDirectives)
348
+ imports.add(`types:${reference.fileName}`);
349
+ canonicalTypes[filename] = [...imports];
350
+ if (source.statements.length === 1 &&
351
+ source.statements.every((statement) => ts.isExportDeclaration(statement) &&
352
+ !statement.moduleSpecifier &&
353
+ statement.exportClause &&
354
+ ts.isNamedExports(statement.exportClause) &&
355
+ statement.exportClause.elements.length === 0))
356
+ canonicalEmptyTypes.push(filename);
357
+ }
358
+ return { canonicalTypes, canonicalEmptyTypes };
359
+ }
131
360
  export async function collectPackageFiles(rootDir, entries, files) {
132
361
  const packed = new Set();
133
362
  async function visit(filename, declarationsOnly) {
@@ -1,4 +1,4 @@
1
- import type { BundleMetafile } from "./bundle-policy.js";
1
+ import { type BundleMetafile } from "./bundle-policy.js";
2
2
  import { type PackageFileView, type PacklistProvider } from "./packlist.js";
3
3
  import { type RuntimeAssetDeclaration, type RuntimeFileAssetView } from "./runtime-files.js";
4
4
  import { type SourceImportView } from "./source-imports.js";
@@ -40,6 +40,7 @@ export interface PackageInfo {
40
40
  ecosystem: Ecosystem;
41
41
  main: string | undefined;
42
42
  exports: unknown;
43
+ imports?: unknown;
43
44
  bin: Record<string, string>;
44
45
  files: string[];
45
46
  scripts: Record<string, string>;