builtins.ts 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. /**
  2. * The Node-compatibility table, in one place. Two consumers share it, and they
  3. * must resolve to the same module instances:
  4. * - the worker vite build aliases these specifiers for code bundled statically
  5. * into the worker (vendored loader, Connection, …);
  6. * - the worker module loader answers `require('node:fs')` from VFS-loaded
  7. * modules out of this table, before bare-name resolution.
  8. * Anything absent here fails loudly at resolution instead of resolving to an
  9. * empty module. `process` is deliberately absent: the worker host installs that
  10. * global itself and fills it into this table at assembly time.
  11. *
  12. * Import paths carry the classification: `./implemented/<module>.ts` backs the
  13. * module's real semantics over a worker data source, while `./mock/<module>.ts`
  14. * is a structural placeholder whose calls report the missing capability. File
  15. * names match their Node module specifiers exactly, nesting included.
  16. *
  17. * Every value is a {@link StaticModuleFactory}, so the loader reads a table
  18. * entry only when a `require` names that specifier. What a factory defers is the
  19. * table read, not module evaluation: each one answers a namespace object of the
  20. * static ESM graph below, which the worker bundle evaluates at load like any
  21. * other import. Deferring a shim's own start-up cost therefore belongs inside
  22. * that shim, on the path that first needs it.
  23. */
  24. import * as nodeAsyncHooks from './builtin_modules/implemented/async_hooks.ts'
  25. import * as nodeBuffer from './builtin_modules/implemented/buffer.ts'
  26. import * as nodeCrypto from './builtin_modules/implemented/crypto.ts'
  27. import * as nodeDnsPromises from './builtin_modules/mock/dns/promises.ts'
  28. import * as nodeEvents from './builtin_modules/implemented/events.ts'
  29. import * as nodeFs from './builtin_modules/implemented/fs.ts'
  30. import * as nodeFsPromises from './builtin_modules/implemented/fs/promises.ts'
  31. import * as nodeHttp from './builtin_modules/implemented/http.ts'
  32. import * as nodeModule from './builtin_modules/implemented/module.ts'
  33. import * as nodeOs from './builtin_modules/implemented/os.ts'
  34. import * as nodePath from './builtin_modules/implemented/path.ts'
  35. import * as nodePerfHooks from './builtin_modules/implemented/perf_hooks.ts'
  36. import * as nodeStream from './builtin_modules/implemented/stream.ts'
  37. import * as nodeTimersPromises from './builtin_modules/implemented/timers/promises.ts'
  38. import * as nodeTty from './builtin_modules/implemented/tty.ts'
  39. import * as nodeUrl from './builtin_modules/implemented/url.ts'
  40. import * as nodeUtil from './builtin_modules/implemented/util.ts'
  41. import * as nodeUtilTypes from './builtin_modules/implemented/util/types.ts'
  42. import * as nodeZlib from './builtin_modules/implemented/zlib.ts'
  43. import * as nodeChildProcess from './builtin_modules/implemented/child_process.ts'
  44. import * as nodeNet from './builtin_modules/mock/net.ts'
  45. import * as nodeSqlite from './builtin_modules/mock/sqlite.ts'
  46. import * as nodeVm from './builtin_modules/mock/vm.ts'
  47. import * as nodeWorkerThreads from './builtin_modules/mock/worker_threads.ts'
  48. import * as koffi from './external_packages/koffi.ts'
  49. import * as nodePty from './external_packages/node-pty.ts'
  50. import * as piAi from './external_packages/pi-ai.ts'
  51. import * as ripgrep from './external_packages/ripgrep.ts'
  52. import * as sharp from './external_packages/sharp.ts'
  53. import * as ws from './external_packages/ws.ts'
  54. import { REPLACED_EXTERNAL_PACKAGES } from './external_packages/replaced-externals.ts'
  55. import type { StaticModuleFactory } from '../module-system/module-loader.ts'
  56. /** Builtin modules, keyed with and without the `node:` prefix. */
  57. const BUILTINS: Record<string, StaticModuleFactory> = {
  58. async_hooks: () => nodeAsyncHooks,
  59. buffer: () => nodeBuffer,
  60. child_process: () => nodeChildProcess,
  61. crypto: () => nodeCrypto,
  62. 'dns/promises': () => nodeDnsPromises,
  63. events: () => nodeEvents,
  64. fs: () => nodeFs,
  65. 'fs/promises': () => nodeFsPromises,
  66. http: () => nodeHttp,
  67. module: () => nodeModule,
  68. net: () => nodeNet,
  69. os: () => nodeOs,
  70. path: () => nodePath,
  71. 'path/posix': () => nodePath,
  72. perf_hooks: () => nodePerfHooks,
  73. sqlite: () => nodeSqlite,
  74. stream: () => nodeStream,
  75. 'timers/promises': () => nodeTimersPromises,
  76. tty: () => nodeTty,
  77. url: () => nodeUrl,
  78. util: () => nodeUtil,
  79. 'util/types': () => nodeUtilTypes,
  80. vm: () => nodeVm,
  81. worker_threads: () => nodeWorkerThreads,
  82. zlib: () => nodeZlib,
  83. }
  84. /** External npm packages replaced wholesale (structural not-implemented stubs and fakes). */
  85. const EXTERNALS: Record<string, StaticModuleFactory> = {
  86. 'koffi': () => koffi,
  87. 'sharp': () => sharp,
  88. 'node-pty': () => nodePty,
  89. 'ws': () => ws,
  90. '@vscode/ripgrep': () => ripgrep,
  91. '@earendil-works/pi-ai': () => piAi,
  92. }
  93. /**
  94. * Prefixes whose every subpath resolves to one replacement module. The loader
  95. * matches the longest prefix after its exact table misses, so pi-ai's
  96. * `/providers/*` and `/api/*.lazy` entries need no enumeration.
  97. */
  98. export const REPLACED_PREFIXES: Record<string, StaticModuleFactory> = {
  99. '@earendil-works/pi-ai/': () => piAi,
  100. }
  101. // One list, two consumers: a package replaced here must also be kept out of the
  102. // VFS image, so any divergence fails at worker start rather than at first require.
  103. const declared = [...REPLACED_EXTERNAL_PACKAGES].sort().join(',')
  104. const wired = Object.keys(EXTERNALS).sort().join(',')
  105. if (declared !== wired) {
  106. throw new Error(`web-preview: replaced-external lists diverge — declared [${declared}] vs wired [${wired}]`)
  107. }
  108. /**
  109. * Build the specifier → factory table the worker module loader consults first.
  110. * @returns every replaced specifier, including its `node:`-prefixed alias.
  111. */
  112. export function createNodeBuiltins(): Record<string, StaticModuleFactory> {
  113. const table: Record<string, StaticModuleFactory> = { ...EXTERNALS }
  114. for (const [name, factory] of Object.entries(BUILTINS)) {
  115. table[name] = factory
  116. table[`node:${name}`] = factory
  117. }
  118. return table
  119. }