forgeos 0.1.0-alpha.0 → 0.1.0-alpha.2

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 (283) hide show
  1. package/.npmignore +9 -1
  2. package/AGENTS.md +6 -1
  3. package/CHANGELOG.md +30 -0
  4. package/CONTRIBUTING.md +22 -1
  5. package/README.md +30 -3
  6. package/bin/forge.mjs +4 -3
  7. package/package.json +3 -1
  8. package/packages/eslint-plugin-forge/index.ts +15 -15
  9. package/packages/eslint-plugin-forge/package.json +10 -10
  10. package/packages/eslint-plugin-forge/src/check-source.ts +95 -95
  11. package/packages/eslint-plugin-forge/src/load-artifacts.ts +24 -24
  12. package/packages/eslint-plugin-forge/src/rule-no-forge-guard-violation.ts +93 -93
  13. package/src/forge/_generated/actionSubscriptions.json +2 -2
  14. package/src/forge/_generated/actionSubscriptions.ts +3 -3
  15. package/src/forge/_generated/agentAdapterManifest.json +2 -2
  16. package/src/forge/_generated/agentAdapterManifest.ts +3 -3
  17. package/src/forge/_generated/agentContract.json +2 -2
  18. package/src/forge/_generated/agentContract.ts +6786 -2
  19. package/src/forge/_generated/agentQuickstart.md +1 -1
  20. package/src/forge/_generated/aiContext.ts +1 -1
  21. package/src/forge/_generated/aiModels.json +1 -1
  22. package/src/forge/_generated/aiModels.ts +1 -1
  23. package/src/forge/_generated/aiProviders.json +1 -1
  24. package/src/forge/_generated/aiProviders.ts +1 -1
  25. package/src/forge/_generated/aiRegistry.json +2 -2
  26. package/src/forge/_generated/aiRegistry.ts +3 -3
  27. package/src/forge/_generated/api.json +2 -2
  28. package/src/forge/_generated/api.ts +1 -1
  29. package/src/forge/_generated/appGraph.json +2 -2
  30. package/src/forge/_generated/appGraph.ts +1297 -1141
  31. package/src/forge/_generated/appMap.md +1 -1
  32. package/src/forge/_generated/artifactManifest.json +2 -2
  33. package/src/forge/_generated/artifactManifest.ts +2 -2
  34. package/src/forge/_generated/authClaims.json +1 -1
  35. package/src/forge/_generated/authClaims.ts +1 -1
  36. package/src/forge/_generated/authConfig.json +1 -1
  37. package/src/forge/_generated/authConfig.ts +1 -1
  38. package/src/forge/_generated/authContext.ts +1 -1
  39. package/src/forge/_generated/authRegistry.json +1 -1
  40. package/src/forge/_generated/authRegistry.ts +1 -1
  41. package/src/forge/_generated/buildInfo.json +2 -2
  42. package/src/forge/_generated/buildInfo.ts +4 -4
  43. package/src/forge/_generated/capabilityMap.json +2 -2
  44. package/src/forge/_generated/capabilityMap.md +1 -1
  45. package/src/forge/_generated/capabilityMap.ts +2 -2
  46. package/src/forge/_generated/client.ts +1 -1
  47. package/src/forge/_generated/clientApi.ts +1 -1
  48. package/src/forge/_generated/clientManifest.json +2 -2
  49. package/src/forge/_generated/clientManifest.ts +3 -3
  50. package/src/forge/_generated/clientTypes.ts +1 -1
  51. package/src/forge/_generated/configRegistry.json +1 -1
  52. package/src/forge/_generated/configRegistry.ts +1 -1
  53. package/src/forge/_generated/dataGraph.json +2 -2
  54. package/src/forge/_generated/dataGraph.ts +3 -3
  55. package/src/forge/_generated/db.json +1 -1
  56. package/src/forge/_generated/db.ts +1 -1
  57. package/src/forge/_generated/dbSecurityManifest.json +1 -1
  58. package/src/forge/_generated/dbSecurityManifest.ts +1 -1
  59. package/src/forge/_generated/dbSessionContext.json +1 -1
  60. package/src/forge/_generated/dbSessionContext.ts +1 -1
  61. package/src/forge/_generated/deployManifest.json +2 -2
  62. package/src/forge/_generated/deployManifest.ts +7 -7
  63. package/src/forge/_generated/devManifest.json +2 -2
  64. package/src/forge/_generated/devManifest.ts +3 -3
  65. package/src/forge/_generated/envSchema.json +1 -1
  66. package/src/forge/_generated/envSchema.ts +1 -1
  67. package/src/forge/_generated/frontendGraph.json +1 -1
  68. package/src/forge/_generated/frontendGraph.ts +1 -1
  69. package/src/forge/_generated/importGuards.json +2 -2
  70. package/src/forge/_generated/importGuards.ts +35 -1
  71. package/src/forge/_generated/index.ts +1 -1
  72. package/src/forge/_generated/liveProductionManifest.json +1 -1
  73. package/src/forge/_generated/liveProductionManifest.ts +1 -1
  74. package/src/forge/_generated/liveProtocol.json +1 -1
  75. package/src/forge/_generated/liveProtocol.ts +1 -1
  76. package/src/forge/_generated/liveQueryRegistry.json +2 -2
  77. package/src/forge/_generated/liveQueryRegistry.ts +3 -3
  78. package/src/forge/_generated/liveTransportConfig.json +1 -1
  79. package/src/forge/_generated/liveTransportConfig.ts +1 -1
  80. package/src/forge/_generated/makeRegistry.json +2 -2
  81. package/src/forge/_generated/makeRegistry.ts +2 -2
  82. package/src/forge/_generated/makeTemplates.json +1 -1
  83. package/src/forge/_generated/makeTemplates.ts +1 -1
  84. package/src/forge/_generated/mockMap.json +1 -1
  85. package/src/forge/_generated/mockMap.ts +1 -1
  86. package/src/forge/_generated/operationPlaybooks.md +7 -5
  87. package/src/forge/_generated/packageGraph.json +2 -2
  88. package/src/forge/_generated/packageGraph.ts +90964 -14284
  89. package/src/forge/_generated/packageUpgradeRegistry.json +2 -2
  90. package/src/forge/_generated/packageUpgradeRegistry.ts +2 -2
  91. package/src/forge/_generated/permissionMatrix.json +2 -2
  92. package/src/forge/_generated/permissionMatrix.ts +3 -3
  93. package/src/forge/_generated/policyRegistry.json +2 -2
  94. package/src/forge/_generated/policyRegistry.ts +3 -3
  95. package/src/forge/_generated/queryRegistry.json +2 -2
  96. package/src/forge/_generated/queryRegistry.ts +3 -3
  97. package/src/forge/_generated/react.d.ts +1 -1
  98. package/src/forge/_generated/react.ts +1 -1
  99. package/src/forge/_generated/reactManifest.json +2 -2
  100. package/src/forge/_generated/reactManifest.ts +3 -3
  101. package/src/forge/_generated/releaseManifest.json +2 -2
  102. package/src/forge/_generated/releaseManifest.ts +3 -3
  103. package/src/forge/_generated/rlsPolicies.json +1 -1
  104. package/src/forge/_generated/rlsPolicies.sql +1 -1
  105. package/src/forge/_generated/rlsPolicies.ts +1 -1
  106. package/src/forge/_generated/runtimeGraph.json +2 -2
  107. package/src/forge/_generated/runtimeGraph.ts +3 -3
  108. package/src/forge/_generated/runtimeMatrix.json +2 -2
  109. package/src/forge/_generated/runtimeMatrix.ts +106177 -7917
  110. package/src/forge/_generated/runtimeRegistry.ts +1 -1
  111. package/src/forge/_generated/runtimeRules.md +1 -1
  112. package/src/forge/_generated/secretRegistry.json +1 -1
  113. package/src/forge/_generated/secretRegistry.ts +1 -1
  114. package/src/forge/_generated/secretsContext.ts +1 -1
  115. package/src/forge/_generated/serverApi.ts +1 -1
  116. package/src/forge/_generated/sourceMapManifest.json +2 -2
  117. package/src/forge/_generated/sourceMapManifest.ts +2 -2
  118. package/src/forge/_generated/sqlPlan.json +1 -1
  119. package/src/forge/_generated/sqlPlan.ts +1 -1
  120. package/src/forge/_generated/subscriptionManifest.json +2 -2
  121. package/src/forge/_generated/subscriptionManifest.ts +3 -3
  122. package/src/forge/_generated/symbolicationManifest.json +2 -2
  123. package/src/forge/_generated/symbolicationManifest.ts +2 -2
  124. package/src/forge/_generated/telemetryRegistry.json +2 -2
  125. package/src/forge/_generated/telemetryRegistry.ts +3 -3
  126. package/src/forge/_generated/telemetrySinks.json +2 -2
  127. package/src/forge/_generated/telemetrySinks.ts +2 -2
  128. package/src/forge/_generated/tenantScope.json +2 -2
  129. package/src/forge/_generated/tenantScope.ts +3 -3
  130. package/src/forge/_generated/testGraph.json +2 -2
  131. package/src/forge/_generated/testGraph.ts +129 -75
  132. package/src/forge/_generated/testPlanRegistry.json +2 -2
  133. package/src/forge/_generated/testPlanRegistry.ts +2 -2
  134. package/src/forge/_generated/uiRoutes.json +1 -1
  135. package/src/forge/_generated/uiRoutes.ts +1 -1
  136. package/src/forge/_generated/uiScenarios.json +1 -1
  137. package/src/forge/_generated/uiScenarios.ts +1 -1
  138. package/src/forge/_generated/uiTestManifest.json +2 -2
  139. package/src/forge/_generated/uiTestManifest.ts +2 -2
  140. package/src/forge/_generated/workflowRegistry.json +2 -2
  141. package/src/forge/_generated/workflowRegistry.ts +3 -3
  142. package/src/forge/_generated/workflowSubscriptions.json +2 -2
  143. package/src/forge/_generated/workflowSubscriptions.ts +3 -3
  144. package/src/forge/cli/commands.ts +861 -861
  145. package/src/forge/cli/deps.ts +178 -11
  146. package/src/forge/cli/dev.ts +32 -5
  147. package/src/forge/cli/index.ts +7 -7
  148. package/src/forge/cli/main.ts +54 -54
  149. package/src/forge/cli/new.ts +29 -1
  150. package/src/forge/cli/output.ts +97 -97
  151. package/src/forge/cli/parse.ts +679 -673
  152. package/src/forge/cli/version.ts +1 -1
  153. package/src/forge/compiler/agent-contract/build.ts +28 -0
  154. package/src/forge/compiler/agent-contract/types.ts +16 -0
  155. package/src/forge/compiler/app-graph/build.ts +112 -112
  156. package/src/forge/compiler/app-graph/classify.ts +10 -10
  157. package/src/forge/compiler/app-graph/dup-symbol.ts +29 -29
  158. package/src/forge/compiler/app-graph/extract.ts +123 -123
  159. package/src/forge/compiler/app-graph/forge-apis.ts +29 -29
  160. package/src/forge/compiler/app-graph/index.ts +11 -11
  161. package/src/forge/compiler/app-graph/module-graph.ts +316 -316
  162. package/src/forge/compiler/app-graph/parser.ts +119 -119
  163. package/src/forge/compiler/app-graph/symbols.ts +48 -48
  164. package/src/forge/compiler/app-graph/tsconfig-hash.ts +62 -62
  165. package/src/forge/compiler/app-graph/types.ts +43 -43
  166. package/src/forge/compiler/app-graph/versions.ts +14 -14
  167. package/src/forge/compiler/cache/index.ts +17 -17
  168. package/src/forge/compiler/cache/key.ts +46 -46
  169. package/src/forge/compiler/cache/scheduler.ts +72 -72
  170. package/src/forge/compiler/cache/store.ts +78 -78
  171. package/src/forge/compiler/classifier/capabilities.ts +78 -78
  172. package/src/forge/compiler/classifier/classify.ts +113 -113
  173. package/src/forge/compiler/classifier/contexts.ts +188 -188
  174. package/src/forge/compiler/classifier/index.ts +18 -18
  175. package/src/forge/compiler/classifier/runtime-matrix.ts +45 -45
  176. package/src/forge/compiler/classifier/secrets.ts +41 -41
  177. package/src/forge/compiler/classifier/signals.ts +129 -129
  178. package/src/forge/compiler/diagnostics/codes.ts +125 -120
  179. package/src/forge/compiler/diagnostics/create.ts +87 -87
  180. package/src/forge/compiler/diagnostics/index.ts +41 -41
  181. package/src/forge/compiler/emitter/artifact-kind.ts +14 -14
  182. package/src/forge/compiler/emitter/barrel.ts +38 -38
  183. package/src/forge/compiler/emitter/constants.ts +7 -7
  184. package/src/forge/compiler/emitter/emit.ts +234 -237
  185. package/src/forge/compiler/emitter/index.ts +24 -24
  186. package/src/forge/compiler/emitter/lock.ts +61 -61
  187. package/src/forge/compiler/emitter/render.ts +73 -73
  188. package/src/forge/compiler/guards/artifacts.ts +96 -96
  189. package/src/forge/compiler/guards/check-import-guards.ts +106 -106
  190. package/src/forge/compiler/guards/index.ts +11 -11
  191. package/src/forge/compiler/guards/propagate-contexts.ts +57 -57
  192. package/src/forge/compiler/index.ts +17 -17
  193. package/src/forge/compiler/integration/add.ts +493 -493
  194. package/src/forge/compiler/integration/index.ts +17 -17
  195. package/src/forge/compiler/integration/plan.ts +279 -279
  196. package/src/forge/compiler/integration/render.ts +189 -189
  197. package/src/forge/compiler/integration/snapshot.ts +52 -52
  198. package/src/forge/compiler/orchestrator/discover.ts +214 -214
  199. package/src/forge/compiler/orchestrator/guards.ts +5 -5
  200. package/src/forge/compiler/orchestrator/index.ts +27 -27
  201. package/src/forge/compiler/orchestrator/manifest.ts +69 -69
  202. package/src/forge/compiler/orchestrator/orphans.ts +51 -51
  203. package/src/forge/compiler/orchestrator/plan.ts +804 -804
  204. package/src/forge/compiler/orchestrator/run.ts +178 -178
  205. package/src/forge/compiler/orchestrator/serialize.ts +859 -859
  206. package/src/forge/compiler/orchestrator/types.ts +23 -23
  207. package/src/forge/compiler/orchestrator/verify.ts +35 -35
  208. package/src/forge/compiler/package-graph/capabilities-stub.ts +33 -33
  209. package/src/forge/compiler/package-graph/checksum.ts +107 -97
  210. package/src/forge/compiler/package-graph/compiler.ts +444 -363
  211. package/src/forge/compiler/package-graph/constants.ts +4 -4
  212. package/src/forge/compiler/package-graph/exports-discovery.ts +91 -84
  213. package/src/forge/compiler/package-graph/extract-dts.ts +32 -32
  214. package/src/forge/compiler/package-graph/index.ts +24 -24
  215. package/src/forge/compiler/package-graph/jsdoc.ts +50 -50
  216. package/src/forge/compiler/package-graph/oracle.ts +326 -0
  217. package/src/forge/compiler/package-graph/read-file.ts +21 -21
  218. package/src/forge/compiler/package-graph/resolve.ts +131 -127
  219. package/src/forge/compiler/package-manager/adapter.ts +232 -232
  220. package/src/forge/compiler/package-manager/commands.ts +47 -47
  221. package/src/forge/compiler/package-manager/detect.ts +65 -65
  222. package/src/forge/compiler/package-manager/executor.ts +29 -29
  223. package/src/forge/compiler/package-manager/index.ts +22 -22
  224. package/src/forge/compiler/package-manager/parse-spec.ts +16 -16
  225. package/src/forge/compiler/package-manager/version.ts +20 -20
  226. package/src/forge/compiler/primitives/compare.ts +26 -26
  227. package/src/forge/compiler/primitives/hash.ts +42 -33
  228. package/src/forge/compiler/primitives/header.ts +43 -43
  229. package/src/forge/compiler/primitives/index.ts +45 -45
  230. package/src/forge/compiler/primitives/paths.ts +24 -24
  231. package/src/forge/compiler/primitives/serialize.ts +66 -66
  232. package/src/forge/compiler/primitives/sort.ts +87 -87
  233. package/src/forge/compiler/recipes/definitions.ts +269 -269
  234. package/src/forge/compiler/recipes/helpers.ts +37 -37
  235. package/src/forge/compiler/recipes/index.ts +21 -21
  236. package/src/forge/compiler/recipes/registry.ts +87 -87
  237. package/src/forge/compiler/sandbox/artifact-sanitize.ts +26 -26
  238. package/src/forge/compiler/sandbox/backends/child.ts +123 -123
  239. package/src/forge/compiler/sandbox/backends/docker.ts +173 -173
  240. package/src/forge/compiler/sandbox/index.ts +51 -51
  241. package/src/forge/compiler/sandbox/inspect.ts +143 -143
  242. package/src/forge/compiler/sandbox/inspector-entry.ts +115 -115
  243. package/src/forge/compiler/sandbox/limits.ts +31 -31
  244. package/src/forge/compiler/sandbox/scrub-env.ts +60 -60
  245. package/src/forge/compiler/sandbox/secret-scan.ts +54 -54
  246. package/src/forge/compiler/sandbox/serialize.ts +106 -106
  247. package/src/forge/compiler/sandbox/types.ts +7 -7
  248. package/src/forge/compiler/types/app-graph.ts +71 -71
  249. package/src/forge/compiler/types/capability.ts +29 -29
  250. package/src/forge/compiler/types/classification.ts +9 -9
  251. package/src/forge/compiler/types/cli.ts +85 -85
  252. package/src/forge/compiler/types/diagnostic.ts +2 -2
  253. package/src/forge/compiler/types/emit.ts +25 -25
  254. package/src/forge/compiler/types/import-guards.ts +19 -19
  255. package/src/forge/compiler/types/index.ts +98 -98
  256. package/src/forge/compiler/types/integration.ts +25 -25
  257. package/src/forge/compiler/types/json.ts +3 -3
  258. package/src/forge/compiler/types/lock.ts +37 -37
  259. package/src/forge/compiler/types/package-graph.ts +122 -77
  260. package/src/forge/compiler/types/runtime-matrix.ts +16 -16
  261. package/src/forge/compiler/types/runtime.ts +30 -30
  262. package/src/forge/compiler/types/sandbox.ts +24 -24
  263. package/src/forge/dev/server.ts +16 -2
  264. package/src/forge/refactor/index.ts +10 -2
  265. package/src/forge/refactor/runtime-rename.ts +598 -0
  266. package/src/forge/runtime/executor.ts +3 -2
  267. package/src/forge/runtime/live/live-query-runner.ts +2 -1
  268. package/src/forge/runtime/outbox/process.ts +2 -1
  269. package/src/forge/runtime/query/run-query.ts +2 -1
  270. package/src/forge/runtime/runner/run-entry.ts +2 -1
  271. package/src/forge/runtime/telemetry/sinks/posthog.ts +4 -5
  272. package/src/forge/runtime/telemetry/sinks/sentry.ts +4 -5
  273. package/src/forge/runtime/workflows/resolve-step.ts +2 -1
  274. package/src/forge/version.ts +3 -0
  275. package/templates/b2b-support-web/src/actions/captureTicketCreated.ts +7 -2
  276. package/templates/b2b-support-web/src/commands/closeTicket.ts +6 -1
  277. package/templates/b2b-support-web/src/commands/createTicket.ts +8 -2
  278. package/templates/b2b-support-web/src/queries/getTicket.ts +8 -1
  279. package/templates/b2b-support-web/web/components/CreateTicketForm.tsx +1 -2
  280. package/templates/b2b-support-web/web/components/PolicyDeniedDemo.tsx +1 -2
  281. package/templates/b2b-support-web/web/components/TicketList.tsx +1 -2
  282. package/templates/b2b-support-web/web/components/TraceDetails.tsx +1 -1
  283. package/templates/b2b-support-web/web/lib/forge.ts +1 -0
@@ -0,0 +1,326 @@
1
+ import { join } from "node:path";
2
+ import type {
3
+ ExportKind,
4
+ ExportSignature,
5
+ PackageApi,
6
+ PackageMetadata,
7
+ PackageRuntimeCompatibility,
8
+ RuntimeTypeMismatch,
9
+ } from "../types/package-graph.ts";
10
+ import type { RuntimeExportKind } from "../types/sandbox.ts";
11
+ import { stableSortStrings } from "../primitives/sort.ts";
12
+ import { nodeFileSystem } from "../fs/index.ts";
13
+ import { readTextFile } from "./read-file.ts";
14
+
15
+ const INSTALL_SCRIPT_NAMES = new Set(["preinstall", "install", "postinstall", "prepare"]);
16
+ const NATIVE_HINTS = ["node-gyp", "prebuild", "node-pre-gyp", "cmake-js"];
17
+
18
+ export interface PackageApiSymbol {
19
+ package: string;
20
+ version: string;
21
+ entrypoint: string;
22
+ name: string;
23
+ kind: ExportKind;
24
+ signature: string;
25
+ overloads: string[];
26
+ declarations: string[];
27
+ jsdoc: ExportSignature["jsdoc"];
28
+ examples: string[];
29
+ classification: ExportSignature["classification"];
30
+ }
31
+
32
+ export interface DependencyApiSummary {
33
+ package: string;
34
+ version: string;
35
+ source: PackageApi["source"];
36
+ entrypoints: Array<{
37
+ subpath: string;
38
+ dtsPath: string | null;
39
+ conditions: string[];
40
+ exportCount: number;
41
+ exports: string[];
42
+ }>;
43
+ symbols: PackageApiSymbol[];
44
+ runtimeTypeMismatches: RuntimeTypeMismatch[];
45
+ runtimeCompatibility: PackageRuntimeCompatibility;
46
+ metadata: PackageMetadata;
47
+ }
48
+
49
+ export function readPackageMetadata(installPath: string, exportSubpathCount: number): PackageMetadata {
50
+ const raw = readTextFile(join(installPath, "package.json"));
51
+ const pkg = JSON.parse(raw) as {
52
+ type?: string;
53
+ main?: string;
54
+ module?: string;
55
+ browser?: string | boolean | Record<string, string | false>;
56
+ types?: string;
57
+ typings?: string;
58
+ engines?: Record<string, string>;
59
+ peerDependencies?: Record<string, string>;
60
+ optionalPeerDependencies?: Record<string, string>;
61
+ scripts?: Record<string, string>;
62
+ dependencies?: Record<string, string>;
63
+ optionalDependencies?: Record<string, string>;
64
+ };
65
+ const scripts = pkg.scripts ?? {};
66
+ const scriptText = Object.entries(scripts)
67
+ .map(([name, value]) => `${name}:${value}`)
68
+ .join("\n")
69
+ .toLowerCase();
70
+ const dependencies = {
71
+ ...(pkg.dependencies ?? {}),
72
+ ...(pkg.optionalDependencies ?? {}),
73
+ };
74
+ const dependencyNames = Object.keys(dependencies).map((name) => name.toLowerCase());
75
+ const hasInstallScripts = Object.keys(scripts).some((name) => INSTALL_SCRIPT_NAMES.has(name));
76
+ const hasNativeBindings =
77
+ NATIVE_HINTS.some((hint) => scriptText.includes(hint)) ||
78
+ dependencyNames.some((name) => NATIVE_HINTS.includes(name)) ||
79
+ hasNativeBinary(installPath);
80
+
81
+ return {
82
+ ...(pkg.type === "module" || pkg.type === "commonjs" ? { type: pkg.type } : {}),
83
+ engines: sortRecord(pkg.engines ?? {}),
84
+ entryFields: {
85
+ ...(typeof pkg.main === "string" ? { main: pkg.main } : {}),
86
+ ...(typeof pkg.module === "string" ? { module: pkg.module } : {}),
87
+ ...(typeof pkg.browser === "string" || typeof pkg.browser === "boolean" ? { browser: pkg.browser } : {}),
88
+ ...(typeof pkg.types === "string"
89
+ ? { types: pkg.types }
90
+ : typeof pkg.typings === "string"
91
+ ? { types: pkg.typings }
92
+ : {}),
93
+ },
94
+ peerDependencies: stableSortStrings(Object.keys(pkg.peerDependencies ?? {})),
95
+ optionalPeerDependencies: stableSortStrings(Object.keys(pkg.optionalPeerDependencies ?? {})),
96
+ hasInstallScripts,
97
+ hasNativeBindings,
98
+ exportSubpathCount,
99
+ };
100
+ }
101
+
102
+ export function buildRuntimeCompatibility(metadata: PackageMetadata): PackageRuntimeCompatibility {
103
+ const reasons: string[] = [];
104
+ const risks: string[] = [];
105
+ let node: PackageRuntimeCompatibility["node"] = "compatible";
106
+ let bun: PackageRuntimeCompatibility["bun"] = "compatible";
107
+ let browser: PackageRuntimeCompatibility["browser"] = metadata.entryFields.browser ? "compatible" : "unknown";
108
+ let edge: PackageRuntimeCompatibility["edge"] = "unknown";
109
+
110
+ if (metadata.type === "module") {
111
+ reasons.push("package declares ESM via package.json type=module");
112
+ }
113
+ if (metadata.engines.node) {
114
+ reasons.push(`package declares node engine ${metadata.engines.node}`);
115
+ }
116
+ if (metadata.entryFields.browser) {
117
+ reasons.push("package declares a browser entry");
118
+ edge = "risky";
119
+ }
120
+ if (metadata.hasInstallScripts) {
121
+ risks.push("package has install lifecycle scripts");
122
+ bun = "risky";
123
+ }
124
+ if (metadata.hasNativeBindings) {
125
+ risks.push("package appears to use native bindings or native build tooling");
126
+ bun = "risky";
127
+ browser = "risky";
128
+ edge = "risky";
129
+ }
130
+ if (metadata.engines.bun) {
131
+ reasons.push(`package declares bun engine ${metadata.engines.bun}`);
132
+ bun = "compatible";
133
+ }
134
+ if (metadata.engines.node && metadata.engines.node.includes("<")) {
135
+ risks.push("node engine range may exclude modern Node versions");
136
+ node = "risky";
137
+ }
138
+ if (metadata.entryFields.browser === false) {
139
+ browser = "risky";
140
+ risks.push("package explicitly disables browser entry support");
141
+ }
142
+
143
+ return {
144
+ node,
145
+ bun,
146
+ browser,
147
+ edge,
148
+ reasons: stableSortStrings(reasons),
149
+ risks: stableSortStrings(risks),
150
+ };
151
+ }
152
+
153
+ export function runtimeTypeMismatches(api: Pick<PackageApi, "entrypoints" | "runtimeShape">): RuntimeTypeMismatch[] {
154
+ if (!api.runtimeShape) {
155
+ return [];
156
+ }
157
+ const typeEntrypoints = new Map(api.entrypoints.map((entrypoint) => [entrypoint.subpath, entrypoint]));
158
+ const runtimeEntrypoints = new Map(api.runtimeShape.entrypoints.map((entrypoint) => [entrypoint.subpath, entrypoint]));
159
+ const mismatches: RuntimeTypeMismatch[] = [];
160
+
161
+ for (const [subpath, typeEntrypoint] of typeEntrypoints) {
162
+ const runtimeEntrypoint = runtimeEntrypoints.get(subpath);
163
+ if (!runtimeEntrypoint) {
164
+ for (const exported of typeEntrypoint.exports) {
165
+ mismatches.push({
166
+ entrypoint: subpath,
167
+ exportName: exported.name,
168
+ kind: "types-only",
169
+ typesKind: exported.kind,
170
+ });
171
+ }
172
+ continue;
173
+ }
174
+ const runtimeExports = new Map(runtimeEntrypoint.exports.map((exported) => [exported.name, exported]));
175
+ for (const exported of typeEntrypoint.exports) {
176
+ const runtimeExport = runtimeExports.get(exported.name);
177
+ if (!runtimeExport) {
178
+ mismatches.push({
179
+ entrypoint: subpath,
180
+ exportName: exported.name,
181
+ kind: "types-only",
182
+ typesKind: exported.kind,
183
+ });
184
+ continue;
185
+ }
186
+ if (!kindsCompatible(exported.kind, runtimeExport.kind)) {
187
+ mismatches.push({
188
+ entrypoint: subpath,
189
+ exportName: exported.name,
190
+ kind: "kind-mismatch",
191
+ typesKind: exported.kind,
192
+ runtimeKind: runtimeExport.kind,
193
+ });
194
+ }
195
+ }
196
+ }
197
+
198
+ for (const [subpath, runtimeEntrypoint] of runtimeEntrypoints) {
199
+ const typeEntrypoint = typeEntrypoints.get(subpath);
200
+ const typeExports = new Set(typeEntrypoint?.exports.map((exported) => exported.name) ?? []);
201
+ for (const runtimeExport of runtimeEntrypoint.exports) {
202
+ if (!typeExports.has(runtimeExport.name)) {
203
+ mismatches.push({
204
+ entrypoint: subpath,
205
+ exportName: runtimeExport.name,
206
+ kind: "runtime-only",
207
+ runtimeKind: runtimeExport.kind,
208
+ });
209
+ }
210
+ }
211
+ }
212
+
213
+ return mismatches.sort((a, b) =>
214
+ `${a.entrypoint}:${a.exportName}:${a.kind}`.localeCompare(`${b.entrypoint}:${b.exportName}:${b.kind}`),
215
+ );
216
+ }
217
+
218
+ export function summarizeDependencyApi(api: PackageApi, symbolName?: string): DependencyApiSummary {
219
+ const symbols = flattenPackageSymbols(api)
220
+ .filter((symbol) => !symbolName || symbol.name === symbolName)
221
+ .sort((a, b) => `${a.entrypoint}:${a.name}`.localeCompare(`${b.entrypoint}:${b.name}`));
222
+ return {
223
+ package: api.name,
224
+ version: api.version,
225
+ source: api.source,
226
+ entrypoints: api.entrypoints.map((entrypoint) => ({
227
+ subpath: entrypoint.subpath,
228
+ dtsPath: entrypoint.dtsPath,
229
+ conditions: entrypoint.conditions,
230
+ exportCount: entrypoint.exports.length,
231
+ exports: entrypoint.exports.map((exported) => exported.name).sort(),
232
+ })),
233
+ symbols,
234
+ runtimeTypeMismatches: api.runtimeTypeMismatches ?? [],
235
+ runtimeCompatibility: api.runtimeCompatibility ?? defaultRuntimeCompatibility(),
236
+ metadata: api.metadata ?? defaultPackageMetadata(api.entrypoints.length),
237
+ };
238
+ }
239
+
240
+ export function flattenPackageSymbols(api: PackageApi): PackageApiSymbol[] {
241
+ return api.entrypoints.flatMap((entrypoint) =>
242
+ entrypoint.exports.map((exported) => ({
243
+ package: api.name,
244
+ version: api.version,
245
+ entrypoint: entrypoint.subpath,
246
+ name: exported.name,
247
+ kind: exported.kind,
248
+ signature: exported.signature,
249
+ overloads: exported.overloads ?? [],
250
+ declarations: exported.declarations ?? [],
251
+ jsdoc: exported.jsdoc,
252
+ examples: exported.examples,
253
+ classification: exported.classification,
254
+ })),
255
+ );
256
+ }
257
+
258
+ export function traceForPackage(api: PackageApi): Array<{ entrypoint: string; trace: PackageApi["entrypoints"][number]["resolutionTrace"] }> {
259
+ return api.entrypoints.map((entrypoint) => ({
260
+ entrypoint: entrypoint.subpath,
261
+ trace: entrypoint.resolutionTrace ?? [],
262
+ }));
263
+ }
264
+
265
+ function kindsCompatible(typeKind: ExportKind, runtimeKind: RuntimeExportKind): boolean {
266
+ if (runtimeKind === "unknown") {
267
+ return true;
268
+ }
269
+ if (typeKind === "function" && runtimeKind === "function") {
270
+ return true;
271
+ }
272
+ if (typeKind === "class" && runtimeKind === "class") {
273
+ return true;
274
+ }
275
+ if ((typeKind === "const" || typeKind === "namespace") && (runtimeKind === "const" || runtimeKind === "object")) {
276
+ return true;
277
+ }
278
+ return false;
279
+ }
280
+
281
+ export function defaultRuntimeCompatibility(): PackageRuntimeCompatibility {
282
+ return {
283
+ node: "unknown",
284
+ bun: "unknown",
285
+ browser: "unknown",
286
+ edge: "unknown",
287
+ reasons: [],
288
+ risks: [],
289
+ };
290
+ }
291
+
292
+ export function defaultPackageMetadata(exportSubpathCount: number): PackageMetadata {
293
+ return {
294
+ engines: {},
295
+ entryFields: {},
296
+ peerDependencies: [],
297
+ optionalPeerDependencies: [],
298
+ hasInstallScripts: false,
299
+ hasNativeBindings: false,
300
+ exportSubpathCount,
301
+ };
302
+ }
303
+
304
+ function sortRecord(input: Record<string, string>): Record<string, string> {
305
+ return Object.fromEntries(Object.entries(input).sort(([a], [b]) => a.localeCompare(b)));
306
+ }
307
+
308
+ function hasNativeBinary(dir: string, depth = 0): boolean {
309
+ if (depth > 4 || !nodeFileSystem.exists(dir)) {
310
+ return false;
311
+ }
312
+ for (const entry of nodeFileSystem.readDir(dir)) {
313
+ if (entry.name === "node_modules" || entry.name === ".git") {
314
+ continue;
315
+ }
316
+ const full = join(dir, entry.name);
317
+ if (entry.isDirectory) {
318
+ if (hasNativeBinary(full, depth + 1)) {
319
+ return true;
320
+ }
321
+ } else if (entry.name.endsWith(".node") || entry.name === "binding.gyp") {
322
+ return true;
323
+ }
324
+ }
325
+ return false;
326
+ }
@@ -1,21 +1,21 @@
1
- import { readFileSync } from "node:fs";
2
-
3
- export interface ReadFileTracker {
4
- recordRead(path: string): void;
5
- }
6
-
7
- let activeTracker: ReadFileTracker | undefined;
8
-
9
- export function setReadFileTracker(tracker: ReadFileTracker | undefined): void {
10
- activeTracker = tracker;
11
- }
12
-
13
- export function readTextFile(path: string): string {
14
- activeTracker?.recordRead(path);
15
- return readFileSync(path, "utf8");
16
- }
17
-
18
- export function readBinaryFile(path: string): Uint8Array {
19
- activeTracker?.recordRead(path);
20
- return readFileSync(path);
21
- }
1
+ import { readFileSync } from "node:fs";
2
+
3
+ export interface ReadFileTracker {
4
+ recordRead(path: string): void;
5
+ }
6
+
7
+ let activeTracker: ReadFileTracker | undefined;
8
+
9
+ export function setReadFileTracker(tracker: ReadFileTracker | undefined): void {
10
+ activeTracker = tracker;
11
+ }
12
+
13
+ export function readTextFile(path: string): string {
14
+ activeTracker?.recordRead(path);
15
+ return readFileSync(path, "utf8");
16
+ }
17
+
18
+ export function readBinaryFile(path: string): Uint8Array {
19
+ activeTracker?.recordRead(path);
20
+ return readFileSync(path);
21
+ }
@@ -1,127 +1,131 @@
1
- import { join } from "node:path";
2
- import ts from "typescript";
3
- import type { ResolutionMode } from "../types/runtime.ts";
4
- import { readTextFile } from "./read-file.ts";
5
-
6
- export interface ResolvedEntrypoint {
7
- dtsPath: string | null;
8
- conditions: string[];
9
- }
10
-
11
- export function createResolutionCompilerOptions(
12
- mode: ResolutionMode,
13
- ): ts.CompilerOptions {
14
- return {
15
- moduleResolution:
16
- mode === "nodenext"
17
- ? ts.ModuleResolutionKind.NodeNext
18
- : ts.ModuleResolutionKind.Bundler,
19
- resolvePackageJsonExports: true,
20
- resolvePackageJsonImports: true,
21
- customConditions: ["types"],
22
- noEmit: true,
23
- types: [],
24
- skipLibCheck: true,
25
- };
26
- }
27
-
28
- export function moduleSpecifierForSubpath(
29
- packageName: string,
30
- subpath: string,
31
- ): string {
32
- if (subpath === ".") {
33
- return packageName;
34
- }
35
- const trimmed = subpath.startsWith("./") ? subpath.slice(2) : subpath;
36
- return `${packageName}/${trimmed}`;
37
- }
38
-
39
- export function resolveEntrypointTypes(
40
- installPath: string,
41
- packageName: string,
42
- subpath: string,
43
- mode: ResolutionMode,
44
- ): ResolvedEntrypoint {
45
- const containingFile = join(installPath, "package.json");
46
- const specifier = moduleSpecifierForSubpath(packageName, subpath);
47
- const options = createResolutionCompilerOptions(mode);
48
-
49
- const result = ts.resolveModuleName(
50
- specifier,
51
- containingFile,
52
- options,
53
- ts.sys,
54
- );
55
-
56
- const resolved = result.resolvedModule;
57
- if (resolved == null) {
58
- return { dtsPath: null, conditions: [] };
59
- }
60
-
61
- const dtsPath = pickTypesPath(resolved);
62
- const conditions = extractConditions(resolved);
63
-
64
- return { dtsPath, conditions };
65
- }
66
-
67
- function pickTypesPath(resolved: ts.ResolvedModuleFull): string | null {
68
- if (resolved.extension === ts.Extension.Dts) {
69
- return resolved.resolvedFileName;
70
- }
71
- if (resolved.extension === ts.Extension.Ts) {
72
- return resolved.resolvedFileName;
73
- }
74
- if (resolved.extension === ts.Extension.Tsx) {
75
- return resolved.resolvedFileName;
76
- }
77
- return resolved.resolvedFileName.endsWith(".d.ts")
78
- ? resolved.resolvedFileName
79
- : null;
80
- }
81
-
82
- function extractConditions(resolved: ts.ResolvedModuleFull): string[] {
83
- const conditions = (resolved as { packageId?: { conditions?: string[] } })
84
- .packageId?.conditions;
85
- if (Array.isArray(conditions) && conditions.length > 0) {
86
- return [...conditions];
87
- }
88
- return [];
89
- }
90
-
91
- export function typesPackageName(packageName: string): string {
92
- if (packageName.startsWith("@")) {
93
- return `@types/${packageName.slice(1).replace("/", "__")}`;
94
- }
95
- return `@types/${packageName}`;
96
- }
97
-
98
- export function resolveTypesPackage(
99
- typesPackageName: string,
100
- installPath: string,
101
- mode: ResolutionMode,
102
- ): string | null {
103
- const typesInstallPath = join(installPath, "..", typesPackageName);
104
- const packageJsonPath = join(typesInstallPath, "package.json");
105
-
106
- try {
107
- readTextFile(packageJsonPath);
108
- } catch {
109
- return null;
110
- }
111
-
112
- const directIndex = join(typesInstallPath, "index.d.ts");
113
- try {
114
- readTextFile(directIndex);
115
- return directIndex;
116
- } catch {
117
- // fall through to module resolver
118
- }
119
-
120
- const resolved = resolveEntrypointTypes(
121
- typesInstallPath,
122
- typesPackageName,
123
- ".",
124
- mode,
125
- );
126
- return resolved.dtsPath;
127
- }
1
+ import { join } from "node:path";
2
+ import ts from "typescript";
3
+ import type { ResolutionMode } from "../types/runtime.ts";
4
+ import { readTextFile } from "./read-file.ts";
5
+
6
+ export interface ResolvedEntrypoint {
7
+ dtsPath: string | null;
8
+ conditions: string[];
9
+ }
10
+
11
+ export function createResolutionCompilerOptions(
12
+ mode: ResolutionMode,
13
+ ): ts.CompilerOptions {
14
+ return {
15
+ moduleResolution:
16
+ mode === "nodenext"
17
+ ? ts.ModuleResolutionKind.NodeNext
18
+ : ts.ModuleResolutionKind.Bundler,
19
+ resolvePackageJsonExports: true,
20
+ resolvePackageJsonImports: true,
21
+ customConditions: ["types"],
22
+ noEmit: true,
23
+ types: [],
24
+ skipLibCheck: true,
25
+ };
26
+ }
27
+
28
+ export function moduleSpecifierForSubpath(
29
+ packageName: string,
30
+ subpath: string,
31
+ ): string {
32
+ if (subpath === ".") {
33
+ return packageName;
34
+ }
35
+ const trimmed = subpath.startsWith("./") ? subpath.slice(2) : subpath;
36
+ return `${packageName}/${trimmed}`;
37
+ }
38
+
39
+ export function resolveEntrypointTypes(
40
+ installPath: string,
41
+ packageName: string,
42
+ subpath: string,
43
+ mode: ResolutionMode,
44
+ ): ResolvedEntrypoint {
45
+ const containingFile = join(installPath, "package.json");
46
+ const specifier = moduleSpecifierForSubpath(packageName, subpath);
47
+ const options = createResolutionCompilerOptions(mode);
48
+
49
+ const result = ts.resolveModuleName(
50
+ specifier,
51
+ containingFile,
52
+ options,
53
+ ts.sys,
54
+ );
55
+
56
+ const resolved = result.resolvedModule;
57
+ if (resolved == null) {
58
+ return { dtsPath: null, conditions: [] };
59
+ }
60
+
61
+ const dtsPath = pickTypesPath(resolved);
62
+ const conditions = extractConditions(resolved);
63
+
64
+ return { dtsPath, conditions };
65
+ }
66
+
67
+ function pickTypesPath(resolved: ts.ResolvedModuleFull): string | null {
68
+ if (resolved.extension === ts.Extension.Dts) {
69
+ return resolved.resolvedFileName;
70
+ }
71
+ if (resolved.extension === ts.Extension.Ts) {
72
+ return resolved.resolvedFileName;
73
+ }
74
+ if (resolved.extension === ts.Extension.Tsx) {
75
+ return resolved.resolvedFileName;
76
+ }
77
+ return isDeclarationPath(resolved.resolvedFileName)
78
+ ? resolved.resolvedFileName
79
+ : null;
80
+ }
81
+
82
+ function isDeclarationPath(path: string): boolean {
83
+ return path.endsWith(".d.ts") || path.endsWith(".d.cts") || path.endsWith(".d.mts");
84
+ }
85
+
86
+ function extractConditions(resolved: ts.ResolvedModuleFull): string[] {
87
+ const conditions = (resolved as { packageId?: { conditions?: string[] } })
88
+ .packageId?.conditions;
89
+ if (Array.isArray(conditions) && conditions.length > 0) {
90
+ return [...conditions];
91
+ }
92
+ return [];
93
+ }
94
+
95
+ export function typesPackageName(packageName: string): string {
96
+ if (packageName.startsWith("@")) {
97
+ return `@types/${packageName.slice(1).replace("/", "__")}`;
98
+ }
99
+ return `@types/${packageName}`;
100
+ }
101
+
102
+ export function resolveTypesPackage(
103
+ typesPackageName: string,
104
+ installPath: string,
105
+ mode: ResolutionMode,
106
+ ): string | null {
107
+ const typesInstallPath = join(installPath, "..", typesPackageName);
108
+ const packageJsonPath = join(typesInstallPath, "package.json");
109
+
110
+ try {
111
+ readTextFile(packageJsonPath);
112
+ } catch {
113
+ return null;
114
+ }
115
+
116
+ const directIndex = join(typesInstallPath, "index.d.ts");
117
+ try {
118
+ readTextFile(directIndex);
119
+ return directIndex;
120
+ } catch {
121
+ // fall through to module resolver
122
+ }
123
+
124
+ const resolved = resolveEntrypointTypes(
125
+ typesInstallPath,
126
+ typesPackageName,
127
+ ".",
128
+ mode,
129
+ );
130
+ return resolved.dtsPath;
131
+ }