@serveryyswys/node.operit 0.0.0-stage → 0.1.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 (148) hide show
  1. package/BUILTINS.json +383 -0
  2. package/DESIGN.md +513 -0
  3. package/LICENSE +201 -0
  4. package/NOTICE +17 -0
  5. package/README.md +311 -2
  6. package/dist/assert/strict.d.ts +2 -0
  7. package/dist/assert/strict.js +7 -0
  8. package/dist/assert.d.ts +3 -0
  9. package/dist/assert.js +483 -0
  10. package/dist/buffer.d.ts +60 -0
  11. package/dist/buffer.js +524 -0
  12. package/dist/child_process.d.ts +56 -0
  13. package/dist/child_process.js +371 -0
  14. package/dist/console.d.ts +60 -0
  15. package/dist/console.js +193 -0
  16. package/dist/constants.d.ts +2 -0
  17. package/dist/constants.js +19 -0
  18. package/dist/crypto.d.ts +76 -0
  19. package/dist/crypto.js +312 -0
  20. package/dist/diagnostics_channel.d.ts +36 -0
  21. package/dist/diagnostics_channel.js +76 -0
  22. package/dist/dns/promises.d.ts +34 -0
  23. package/dist/dns/promises.js +190 -0
  24. package/dist/dns.d.ts +88 -0
  25. package/dist/dns.js +259 -0
  26. package/dist/events.d.ts +40 -0
  27. package/dist/events.js +237 -0
  28. package/dist/fs/promises.d.ts +160 -0
  29. package/dist/fs/promises.js +130 -0
  30. package/dist/fs.d.ts +221 -0
  31. package/dist/fs.js +944 -0
  32. package/dist/http.d.ts +92 -0
  33. package/dist/http.js +319 -0
  34. package/dist/https.d.ts +296 -0
  35. package/dist/https.js +50 -0
  36. package/dist/index.d.ts +2821 -0
  37. package/dist/index.js +93 -0
  38. package/dist/lib/bridge.d.ts +60 -0
  39. package/dist/lib/bridge.js +207 -0
  40. package/dist/lib/bytes.d.ts +20 -0
  41. package/dist/lib/bytes.js +239 -0
  42. package/dist/lib/child-process-types.d.ts +45 -0
  43. package/dist/lib/child-process-types.js +2 -0
  44. package/dist/lib/console-types.d.ts +12 -0
  45. package/dist/lib/console-types.js +2 -0
  46. package/dist/lib/cwd.d.ts +2 -0
  47. package/dist/lib/cwd.js +32 -0
  48. package/dist/lib/deep-equal.d.ts +3 -0
  49. package/dist/lib/deep-equal.js +223 -0
  50. package/dist/lib/deflate.d.ts +2 -0
  51. package/dist/lib/deflate.js +234 -0
  52. package/dist/lib/diagnostics-channel-types.d.ts +7 -0
  53. package/dist/lib/diagnostics-channel-types.js +2 -0
  54. package/dist/lib/dns-driver.d.ts +14 -0
  55. package/dist/lib/dns-driver.js +85 -0
  56. package/dist/lib/dns-types.d.ts +22 -0
  57. package/dist/lib/dns-types.js +2 -0
  58. package/dist/lib/errors.d.ts +48 -0
  59. package/dist/lib/errors.js +424 -0
  60. package/dist/lib/fs-driver.d.ts +70 -0
  61. package/dist/lib/fs-driver.js +364 -0
  62. package/dist/lib/fs-env.d.ts +30 -0
  63. package/dist/lib/fs-env.js +157 -0
  64. package/dist/lib/fs-types.d.ts +19 -0
  65. package/dist/lib/fs-types.js +2 -0
  66. package/dist/lib/hashes.d.ts +27 -0
  67. package/dist/lib/hashes.js +432 -0
  68. package/dist/lib/http-driver.d.ts +30 -0
  69. package/dist/lib/http-driver.js +72 -0
  70. package/dist/lib/http-types.d.ts +18 -0
  71. package/dist/lib/http-types.js +2 -0
  72. package/dist/lib/inflate.d.ts +6 -0
  73. package/dist/lib/inflate.js +284 -0
  74. package/dist/lib/path-types.d.ts +37 -0
  75. package/dist/lib/path-types.js +2 -0
  76. package/dist/lib/paths.d.ts +8 -0
  77. package/dist/lib/paths.js +106 -0
  78. package/dist/lib/perf-hooks-types.d.ts +18 -0
  79. package/dist/lib/perf-hooks-types.js +2 -0
  80. package/dist/lib/process-driver.d.ts +31 -0
  81. package/dist/lib/process-driver.js +102 -0
  82. package/dist/lib/punycode.d.ts +8 -0
  83. package/dist/lib/punycode.js +179 -0
  84. package/dist/lib/stream-consumers-types.d.ts +4 -0
  85. package/dist/lib/stream-consumers-types.js +2 -0
  86. package/dist/lib/stream-types.d.ts +29 -0
  87. package/dist/lib/stream-types.js +2 -0
  88. package/dist/lib/timers-types.d.ts +18 -0
  89. package/dist/lib/timers-types.js +2 -0
  90. package/dist/lib/url-search-params.d.ts +26 -0
  91. package/dist/lib/url-search-params.js +281 -0
  92. package/dist/lib/url-types.d.ts +44 -0
  93. package/dist/lib/url-types.js +2 -0
  94. package/dist/lib/url-whatwg.d.ts +78 -0
  95. package/dist/lib/url-whatwg.js +857 -0
  96. package/dist/lib/util-types.d.ts +13 -0
  97. package/dist/lib/util-types.js +2 -0
  98. package/dist/lib/v8-types.d.ts +30 -0
  99. package/dist/lib/v8-types.js +2 -0
  100. package/dist/lib/zlib-types.d.ts +12 -0
  101. package/dist/lib/zlib-types.js +2 -0
  102. package/dist/module.d.ts +8 -0
  103. package/dist/module.js +102 -0
  104. package/dist/os.d.ts +80 -0
  105. package/dist/os.js +247 -0
  106. package/dist/path/posix.d.ts +2 -0
  107. package/dist/path/posix.js +7 -0
  108. package/dist/path/win32.d.ts +2 -0
  109. package/dist/path/win32.js +10 -0
  110. package/dist/path.d.ts +3 -0
  111. package/dist/path.js +1222 -0
  112. package/dist/perf_hooks.d.ts +36 -0
  113. package/dist/perf_hooks.js +144 -0
  114. package/dist/process.d.ts +69 -0
  115. package/dist/process.js +230 -0
  116. package/dist/punycode.d.ts +22 -0
  117. package/dist/punycode.js +53 -0
  118. package/dist/querystring.d.ts +15 -0
  119. package/dist/querystring.js +209 -0
  120. package/dist/stream/consumers.d.ts +24 -0
  121. package/dist/stream/consumers.js +75 -0
  122. package/dist/stream/promises.d.ts +5 -0
  123. package/dist/stream/promises.js +10 -0
  124. package/dist/stream.d.ts +84 -0
  125. package/dist/stream.js +875 -0
  126. package/dist/string_decoder.d.ts +15 -0
  127. package/dist/string_decoder.js +237 -0
  128. package/dist/sys.d.ts +8 -0
  129. package/dist/sys.js +9 -0
  130. package/dist/timers/promises.d.ts +19 -0
  131. package/dist/timers/promises.js +74 -0
  132. package/dist/timers.d.ts +21 -0
  133. package/dist/timers.js +41 -0
  134. package/dist/tty.d.ts +9 -0
  135. package/dist/tty.js +25 -0
  136. package/dist/unsupported.d.ts +12 -0
  137. package/dist/unsupported.js +17 -0
  138. package/dist/url.d.ts +28 -0
  139. package/dist/url.js +486 -0
  140. package/dist/util/types.d.ts +16 -0
  141. package/dist/util/types.js +9 -0
  142. package/dist/util.d.ts +63 -0
  143. package/dist/util.js +527 -0
  144. package/dist/v8.d.ts +25 -0
  145. package/dist/v8.js +127 -0
  146. package/dist/zlib.d.ts +88 -0
  147. package/dist/zlib.js +371 -0
  148. package/package.json +31 -4
package/BUILTINS.json ADDED
@@ -0,0 +1,383 @@
1
+ {
2
+ "schema": 1,
3
+ "package": "@serveryyswys/node.operit",
4
+ "entry": "dist/index.js",
5
+ "unsupportedEntry": "dist/unsupported.js",
6
+ "distDir": "dist",
7
+ "subpathTemplate": "<distDir>/<subpath>.js",
8
+ "subpathStrategy": "direct",
9
+ "requireExplicitExtension": true,
10
+ "requireExplicitExtensionReason": "包名含点(node.operit),Operit 的 buildCandidatePaths 会把 .operit 当成扩展名并只试一个候选,因此重写必须产出显式 .js 路径,不能依赖目录回落。",
11
+ "statusSemantics": {
12
+ "ready": "已实现并与 Node 对拍通过。",
13
+ "partial": "已实现,但有明确的、写在 note 里的差异或未覆盖部分。",
14
+ "planned": "尚未实现,计划中。OperitPackageManager 应当让构建失败,不要把问题带到运行期。",
15
+ "unsupported": "**不提供**。原因有两类,都写在 note 里:其一,平台不成立(例如 vm 需要 Node 运行时本身、dns 的记录级查询需要 Android 没有的 JNDI DNS provider);其二,**刻意不做**(例如 net 的裸 socket —— 那会绕过 Operit 的工具审批模型)。两类都要求 OperitPackageManager 让构建失败。"
16
+ },
17
+ "builtins": {
18
+ "path": {
19
+ "subpath": "path",
20
+ "status": "ready"
21
+ },
22
+ "path/posix": {
23
+ "subpath": "path/posix",
24
+ "status": "ready"
25
+ },
26
+ "path/win32": {
27
+ "subpath": "path/win32",
28
+ "status": "partial",
29
+ "note": "与 Node 的 path.win32 在两类边缘有偏差:1) 归一化时含歧义冒号的相对路径(如 '9:')缺少 '.\\' 前缀;2) UNC 根的 dirname/parse 边界。日常 Windows 路径形态经对拍一致,分歧率约 1.5%。"
30
+ },
31
+ "fs": {
32
+ "subpath": "fs",
33
+ "status": "partial",
34
+ "note": "Node 语义层(选项、flag、错误码、返回值形状)已与本机 Node 的 fs 逐项对拍通过,覆盖同步面、fd 系列(openSync/readSync/writeSync/closeSync/fstatSync/ftruncateSync/fsyncSync)、回调形式、流式接口与 fs/promises(open 按 Node 语义返回 FileHandle,其 read/write 返回 {bytesRead/buffer} / {bytesWritten/buffer})。Java 驱动依赖的 bridge 行为尚未真机验证。已知近似:atime/ctime/birthtime 取 mtime;mode 为按类型的默认值;readdir 不区分符号链接;读流是「按需整块读 + 切片」,没有流式的内存特性,'open' 事件参数为 null;fstat 走路径而不是 fd(文件被 unlink 后行为不同)。"
35
+ },
36
+ "fs/promises": {
37
+ "subpath": "fs/promises",
38
+ "status": "partial",
39
+ "note": "同步面包 Promise;宿主只有 Java bridge 一条同步通道,所以是「接口异步、执行同步」。近似点同 fs。"
40
+ },
41
+ "buffer": {
42
+ "subpath": "buffer",
43
+ "status": "ready",
44
+ "note": "与 Node 的 Buffer 逐项对拍通过,含 Node 特有的 base64 容错规则与 ascii 编解码不对称行为。"
45
+ },
46
+ "os": {
47
+ "subpath": "os",
48
+ "status": "partial",
49
+ "note": "形状与语义对齐 Node,取值来自 Android。近似:totalmem/freemem 是 JVM 堆而非物理内存;cpus() 的 model 取 os.arch、speed/times 为 0;homedir() 为 /sdcard;loadavg() 恒 [0,0,0];getPriority/setPriority 抛 ONJ_UNSUPPORTED(POSIX niceness 在 Android 不成立)。"
50
+ },
51
+ "process": {
52
+ "subpath": "process",
53
+ "status": "partial",
54
+ "note": "require('process') 返回的进程对象;Operit 没有 process 全局,裸引用需 OperitPackageManager 注入。差异:env 是 Proxy(读走 getEnv,空串与未设置都表现为 undefined,无法枚举);写环境变量依赖未文档化的 NativeInterface.setEnv;exit/abort 显式抛 ONJ_UNSUPPORTED;versions.node 是声明的兼容目标而非真实运行时版本。"
55
+ },
56
+ "util": {
57
+ "subpath": "util",
58
+ "status": "partial",
59
+ "note": "format(占位符、参数不足、多余参数、%%、%c)、promisify、inherits、types、isDeepStrictEqual、TextEncoder/TextDecoder 已实现并对拍;isDeepStrictEqual 已与 Node 在 4225 对语料上零分歧(含 Map/Set/TypedArray/循环引用/符号键/-0/NaN),实现见 lib/deep-equal.ts,assert 也复用它。inspect 只对齐常用形态,支持 compact: false 的多行排版,但 Node 的 breakLength 折行算法未照搬。TextDecoder 只支持 utf-8。"
60
+ },
61
+ "events": {
62
+ "subpath": "events",
63
+ "status": "ready",
64
+ "note": "EventEmitter 行为序列与 Node 对拍一致。差异:不能用 EventEmitter.call(this) 做函数式继承;captureRejections 与 events.on()(异步迭代器)未实现。"
65
+ },
66
+ "string_decoder": {
67
+ "subpath": "string_decoder",
68
+ "status": "ready",
69
+ "note": "utf8/utf16le/base64 的跨块缓冲语义与 Node 对拍一致(含 end() 只吐一个 U+FFFD)。"
70
+ },
71
+ "assert": {
72
+ "subpath": "assert",
73
+ "status": "partial",
74
+ "note": "已实现:模块本身可调用,ok/equal/notEqual/strictEqual/notStrictEqual/deepStrictEqual/notDeepStrictEqual/deepEqual/notDeepEqual/throws/doesNotThrow/rejects/doesNotReject/ifError/match/doesNotMatch/fail/AssertionError。错误字段(code/operator/generatedMessage/actual/expected)与 Node 逐项对拍一致。唯一消息差异:assert.ok / assert(value) 失败时 Node 会把调用处的源码表达式附在消息里(取源码要读栈指向的文件,QuickJS 上不可靠),这里只给出 'The expression evaluated to a falsy value'。差异块用的是「公共前后缀 diff」,对单点差异与 Node 逐字一致,多段交错差异时 Node 的 Myers diff 对齐方式可能不同。"
75
+ },
76
+ "assert/strict": {
77
+ "subpath": "assert/strict",
78
+ "status": "partial",
79
+ "note": "与 require('assert').strict 是同一对象;equal 等同 strictEqual,deepEqual 等同 deepStrictEqual。实现与限制同 assert。"
80
+ },
81
+ "querystring": {
82
+ "subpath": "querystring",
83
+ "status": "ready",
84
+ "note": "stringify/parse/escape/unescape 与 Node 对拍一致,含宽松百分号解码与 maxKeys 的空分段计数行为。"
85
+ },
86
+ "url": {
87
+ "subpath": "url",
88
+ "status": "partial",
89
+ "note": "已实现并与 Node 对拍:URLSearchParams、**WHATWG URL**(特殊协议与自定义协议、authority、IPv4/IPv6/域名 punycode、按组件的百分号编码、点段规范化、相对引用、全部 getter 与 setter、searchParams 活视图、URL.canParse / URL.parse)、旧版 parse/format/resolve、pathToFileURL/fileURLToPath、urlToHttpOptions、domainToASCII/domainToUnicode。对拍规模:53 条绝对 URL 逐字段比对 + 12 条相对引用 + 9 个 setter + 活视图与 canParse/parse,零分歧。已知差异:blob: 的 origin 返回 'null'(Node 会解析内部 URL);域名只做 RFC 3492 punycode,不做 UTS-46 映射与归一化;pathToFileURL/fileURLToPath 是 POSIX 规则(面向 Android),Node 在 Windows 上给的是带盘符的形式。几处容易想当然的细节都是实测出来的(空查询 '?' 的 search 是 '' 但 href 保留 '?'、主机结尾的点要保留、file://localhost 归一成空主机、http:///path 的主机是 path),注释都在 src/lib/url-whatwg.ts。punycode 只做 RFC 3492 本体。"
90
+ },
91
+ "crypto": {
92
+ "subpath": "crypto",
93
+ "status": "partial",
94
+ "note": "已实现并与 Node 全量对拍:createHash(md5/sha1/sha224/sha256/sha384/sha512,纯 JS 实现)、createHmac、pbkdf2/pbkdf2Sync、timingSafeEqual、getHashes、randomBytes/randomFillSync/randomUUID/randomInt(随机数走 java.util.UUID.randomUUID,无需往 bridge 传 byte[])。未实现,调用即抛 ONJ_UNSUPPORTED:createCipheriv/createDecipheriv/createSign/createVerify/generateKeyPair(Sync)/createDiffieHellman。"
95
+ },
96
+ "zlib": {
97
+ "subpath": "zlib",
98
+ "status": "partial",
99
+ "note": "已实现并与 Node 双向对拍:inflate/inflateRaw/gunzip/unzip(完整 DEFLATE,含 stored、定长与动态 Huffman)、deflate/deflateRaw/gzip(定长 Huffman + LZ77)、流式接口(createGzip/createGunzip/createDeflate/createInflate/createDeflateRaw/createInflateRaw/createUnzip)、同步与回调两种形式、constants。压缩侧未实现动态 Huffman,压缩率低于 zlib,但输出是任何解压器都能读的合法流。流式接口基于 stream.Transform,但内部仍是一次性处理(攒到 _flush 才压缩/解压),没有真流式的低延迟与低内存。Brotli 未实现。"
100
+ },
101
+ "stream": {
102
+ "subpath": "stream",
103
+ "status": "partial",
104
+ "note": "Readable/Writable/Duplex/Transform/PassThrough、pipe/unpipe、pipeline 与 finished(回调形式)、Symbol.asyncIterator、Readable.from 已实现,9 个场景与 Node 对拍一致。用 queueMicrotask 调度,事件时序与 Node 同类但不必逐拍相同(测试比对的是语义结果)。未实现:objectMode 的完整语义差异、cork 的合并优化、compose、addAbortSignal。stream.pipeline 不给回调会按 Node 语义抛 ERR_INVALID_ARG_TYPE,Promise 形式请用 stream/promises。"
105
+ },
106
+ "stream/promises": {
107
+ "subpath": "stream/promises",
108
+ "status": "partial",
109
+ "note": "pipeline / finished 的 Promise 版;与 require('stream').promises 是同一份实现。"
110
+ },
111
+ "timers": {
112
+ "subpath": "timers",
113
+ "status": "partial",
114
+ "note": "setTimeout / clearTimeout / setInterval / clearInterval 就是宿主提供的全局函数本身(Node 的 timers.setTimeout === 全局 setTimeout 也是如此)。setImmediate / clearImmediate 宿主没有,落在 setTimeout(…, 0) 上 —— 因此在 Operit 里它与定时器是同一个队列(Node 里 setImmediate 在 check 阶段、先于定时器)。promisify(setTimeout) 可用(按需补 promisify.custom,宿主已有就不动)。"
115
+ },
116
+ "timers/promises": {
117
+ "subpath": "timers/promises",
118
+ "status": "partial",
119
+ "note": "setTimeout / setImmediate / scheduler.wait / scheduler.yield 已实现并与 Node 对拍(含 value 传递、AbortError)。setInterval 用「每次 await 一个 setTimeout」实现,不是原生 interval,因此延迟会随迭代累积漂移(可迭代与取消语义与 Node 一致)。signal 只按结构检查(aborted / addEventListener),因为没有 AbortController。"
120
+ },
121
+ "child_process": {
122
+ "subpath": "child_process",
123
+ "status": "partial",
124
+ "note": "已实现:exec/execSync/execFile/execFileSync/spawn/spawnSync、ChildProcess 的 spawn/exit/close/error 事件与 stdout/stderr/stdin、pid、exitCode、kill,以及 Node 的错误形态(非零退出码放 error.status、启动失败放 error.code='ENOENT'、maxBuffer 超出抛 ERR_CHILD_PROCESS_STDIO_MAXBUFFER)。差异:宿主只有同步 bridge,所以 spawn 是「先同步跑完、再异步发事件」——没有真并发与背压,长驻进程会阻塞调用方;输出按 UTF-8 解码(驱动用 java.util.Scanner 读取,因为 InputStream.readAllBytes 是 Java 9,Android 8~12 没有),二进制输出会有损;先读 stdout 再读 stderr,若子进程往 stderr 写超过管道缓冲会死锁。未实现:fork(需要 Node 运行时本身)。"
125
+ },
126
+ "net": {
127
+ "subpath": "net",
128
+ "status": "unsupported",
129
+ "note": "刻意不提供。net 需要裸 TCP/UDP socket,技术上可以用 java.net.Socket 实现,但那会让插件绕过 Operit 的工具审批模型:网络访问在 Operit 里是**工具能力**(http_request 等,走用户审批),用裸 socket 另起一套等于绕过它。http/https 已经建在 toolCall('http_request') 之上(见 http 条目);如果将来 Operit 提供原始 socket 类工具,net 可以照同样的方式补上。在那之前,需要网络请用 toolCall / 内建 axios。"
130
+ },
131
+ "http": {
132
+ "subpath": "http",
133
+ "status": "partial",
134
+ "note": "只有**客户端**。建在宿主的 toolCall('http_request') 之上,不直接用 Java socket —— http_request 是 Operit 注册的工具(ToolRegistration.kt:1967),走用户审批;用裸 socket 另起一套等于绕过那个模型。覆盖:request / get、ClientRequest(Writable:setHeader/getHeader/getHeaders/getHeaderNames/hasHeader/removeHeader、write/end、setTimeout、abort)、IncomingMessage(Readable:statusCode/statusMessage/headers(键名全小写)/rawHeaders/httpVersion/url)、STATUS_CODES、METHODS、Agent(无连接池)、globalAgent。与 Node 的差异:createServer / Server 构造时显式抛 ONJ_UNSUPPORTED(沙箱没有可监听的 socket);请求体只支持文本(宿主工具的参数是字符串),二进制上行不做;abort() 只发出 'abort' 事件,无法真正取消已在宿主侧执行的请求(工具调用没有取消通道);没有连接池 / keep-alive / HTTP/2;重定向是否跟随由宿主决定。响应体优先用 contentBase64 还原字节,缺失时才按 UTF-8 解释 content。宿主返回形状取自 HttpResponseData(ToolResultDataClasses.kt:600);形状不对时明确报错,不静默兜底。**尚未真机验证**。"
135
+ },
136
+ "https": {
137
+ "subpath": "https",
138
+ "status": "partial",
139
+ "note": "只有**客户端**。建在宿主的 toolCall('http_request') 之上,不直接用 Java socket —— http_request 是 Operit 注册的工具(ToolRegistration.kt:1967),走用户审批;用裸 socket 另起一套等于绕过那个模型。覆盖:request / get、ClientRequest(Writable:setHeader/getHeader/getHeaders/getHeaderNames/hasHeader/removeHeader、write/end、setTimeout、abort)、IncomingMessage(Readable:statusCode/statusMessage/headers(键名全小写)/rawHeaders/httpVersion/url)、STATUS_CODES、METHODS、Agent(无连接池)、globalAgent。与 Node 的差异:createServer / Server 构造时显式抛 ONJ_UNSUPPORTED(沙箱没有可监听的 socket);请求体只支持文本(宿主工具的参数是字符串),二进制上行不做;abort() 只发出 'abort' 事件,无法真正取消已在宿主侧执行的请求(工具调用没有取消通道);没有连接池 / keep-alive / HTTP/2;重定向是否跟随由宿主决定。响应体优先用 contentBase64 还原字节,缺失时才按 UTF-8 解释 content。宿主返回形状取自 HttpResponseData(ToolResultDataClasses.kt:600);形状不对时明确报错,不静默兜底。**尚未真机验证**。 与 http 是同一套实现(TLS 由宿主那侧处理,沙箱里既没有 socket 也没有证书链可管),只把缺省协议改成 https:。"
140
+ },
141
+ "dns": {
142
+ "subpath": "dns",
143
+ "status": "partial",
144
+ "note": "实现了 **lookup 一族**(getaddrinfo),也就是绝大多数代码真正用到的那部分:lookup / lookupService / promises.lookup / promises.lookupService / getServers / setServers / getDefaultResultOrder / setDefaultResultOrder / 常量(hints 与错误码字符串,数值对齐 Node 而非 libuv 原始值)。底层是 java.net.InetAddress。**resolve 一族(resolve/resolve4/resolve6/resolveAny/resolveCaa/resolveCname/resolveMx/resolveNaptr/resolveNs/resolvePtr/resolveSoa/resolveSrv/resolveTlsa/resolveTxt)与 reverse 显式抛 ONJ_UNSUPPORTED**:它们需要 DNS 记录级查询,而这要 JNDI 的 DNS provider,com.sun.jndi.dns 不在 Android 里 —— 是平台不成立,不是尚未实现。其它差异:接口异步(queueMicrotask)但底层 getaddrinfo 是同步的;getServers() 返回空数组(Android 的 DNS 由 netd 按网络管理,JVM 侧读不到);setServers() 抛 ONJ_UNSUPPORTED(改不了 JVM 解析器);hints 选项接受但不生效;lookupService 的 service 用内置常见端口表,未命中给端口号字符串(Node 走系统的 services 库)。错误形状与实测 Node 对齐:code='ENOTFOUND'、errno=-3008、syscall='getaddrinfo'、hostname,message 为 'getaddrinfo ENOTFOUND <host>'。**尚未真机验证**。"
145
+ },
146
+ "perf_hooks": {
147
+ "subpath": "perf_hooks",
148
+ "status": "partial",
149
+ "note": "performance(now / timeOrigin / mark / measure / getEntries* / clearMarks / clearMeasures)与 constants 已实现并与 Node 对拍。注意 measure 的位置参数形式**只认 mark 名字**、数字不当时间戳(实测 Node 就是如此),数字要当时间戳得用 options 形式 measure(name, {start, end})。未实现:PerformanceObserver、PerformanceEntry 等类、monitorEventLoopDelay、createHistogram —— 保持 undefined,不给空壳。"
150
+ },
151
+ "readline": {
152
+ "subpath": "readline",
153
+ "status": "planned",
154
+ "note": "尚未实现。技术上可行(readline 可以跑在任意流上,不必是真终端),但 Operit 沙箱里没有交互式 stdin,实际价值有限,所以优先级排在最后。OperitPackageManager 应当让构建失败。"
155
+ },
156
+ "constants": {
157
+ "subpath": "constants",
158
+ "status": "partial",
159
+ "note": "合并 fs / os / zlib / crypto 的常量并把 os.constants 的 signals / errno / priority 摊平到顶层(252 个键),含完整的 Linux errno 表(134 项)。给出的是 **Linux/Android** 的数值:O_CREAT / O_EXCL / O_TRUNC / O_APPEND 与 Node 在 Windows 上的不同,这是平台差异。未提供:大部分 libuv 内部常量(只给了少数 UV_FS_* / UV_DIRENT_* 镜像)、Windows 专有常量(WSA* / SIGBREAK)、Brotli 与 Zstd(BROTLI_* / ZSTD_*)以及 ZLIB_VERNUM。测试里有一份「分歧普查」,把这些缺口分类列出来。"
160
+ },
161
+ "module": {
162
+ "subpath": "module",
163
+ "status": "partial",
164
+ "note": "builtinModules(与 BUILTINS.json 的键逐字一致,测试断言两者同步,改契约表时会失败提醒)与 isBuiltin(认 node: 前缀)。createRequire() 显式抛 ONJ_UNSUPPORTED:它依赖 node_modules 逐级查找与 main/exports 解析,而 Operit 的 require 两样都没有。Module 类与 _resolveFilename 等内部接口不提供。"
165
+ },
166
+ "vm": {
167
+ "status": "unsupported",
168
+ "reason": "QuickJS 运行时未暴露独立上下文创建能力。"
169
+ },
170
+ "worker_threads": {
171
+ "status": "unsupported",
172
+ "reason": "QuickJS 运行时为单线程解释器,无 worker 能力。"
173
+ },
174
+ "cluster": {
175
+ "status": "unsupported",
176
+ "reason": "依赖 worker_threads。"
177
+ },
178
+ "async_hooks": {
179
+ "status": "unsupported",
180
+ "reason": "QuickJS 未暴露异步资源跟踪钩子。"
181
+ },
182
+ "inspector": {
183
+ "status": "unsupported",
184
+ "reason": "无 V8 inspector 协议。"
185
+ },
186
+ "repl": {
187
+ "status": "unsupported",
188
+ "reason": "无 stdin/stdout 终端语义。"
189
+ },
190
+ "tty": {
191
+ "subpath": "tty",
192
+ "status": "partial",
193
+ "note": "isatty() 恒为 false(沙箱里没有终端,这正是 supports-color / debug 这类包需要知道的答案)。ReadStream / WriteStream 需要真实终端,构造时显式抛 ONJ_UNSUPPORTED,不给「能 new 但不能用」的空壳。"
194
+ },
195
+ "dns/promises": {
196
+ "subpath": "dns/promises",
197
+ "status": "partial",
198
+ "note": "dns 的 promises 形态,与 require('dns').promises 是同一个对象。差异与 dns 完全一致:lookup 一族可用,resolve 一族与 reverse 显式抛 ONJ_UNSUPPORTED。"
199
+ },
200
+ "console": {
201
+ "subpath": "console",
202
+ "status": "partial",
203
+ "note": "完整的 Node console API(Console 类 + log/info/warn/error/debug/assert/dir/count/countReset/time/timeEnd/timeLog/trace/table/group/groupEnd/clear/profile/profileEnd/timeStamp)。sandbox 的 prelude 只提供 log/info/warn/error 且用 arguments.join(' '),本模块在其上补齐并改用 util.format(所以 '%s' 行为与 Node 一致)。差异:不指定输出流时写 prelude console(Node 是 process.stdout/stderr);clear/profile/profileEnd/timeStamp 与 Node 在非 TTY 下一样是空操作;table 只覆盖常用形态。"
204
+ },
205
+ "util/types": {
206
+ "subpath": "util/types",
207
+ "status": "ready",
208
+ "note": "与 require('util').types 同一个对象。高频依赖。"
209
+ },
210
+ "sys": {
211
+ "subpath": "sys",
212
+ "status": "ready",
213
+ "note": "已废弃的别名,Node 里 require('sys') === require('util'),这里保持同一对象。"
214
+ },
215
+ "punycode": {
216
+ "subpath": "punycode",
217
+ "status": "ready",
218
+ "note": "已废弃但仍被不少包直接 require。实现复用 lib/punycode.ts。version 报 '2.1.1';ucs2.decode 返回的是 UTF-16 码元序列,与 Node 一致。"
219
+ },
220
+ "diagnostics_channel": {
221
+ "subpath": "diagnostics_channel",
222
+ "status": "partial",
223
+ "note": "channel / hasSubscribers / subscribe / unsubscribe / Channel 全部可用(纯发布订阅,不依赖平台)。差异:Channel 的 bindStore / unbindStore / runStores 依赖 AsyncLocalStorage(需要 async_hooks),QuickJS 运行时不提供异步钩子,这三个方法显式抛 ONJ_UNSUPPORTED;tracingChannel 未实现,同样显式拒绝。"
224
+ },
225
+ "stream/consumers": {
226
+ "subpath": "stream/consumers",
227
+ "status": "partial",
228
+ "note": "buffer / text / json / arrayBuffer 可用。差异:blob 显式抛 ONJ_UNSUPPORTED —— 运行时不提供 Blob,与其返回形状相似但类型不对的对象不如明确拒绝;不做 Node 内部的 Readable 品牌校验,只要求对象有 on()。"
229
+ },
230
+ "v8": {
231
+ "subpath": "v8",
232
+ "status": "partial",
233
+ "note": "getHeapStatistics / getHeapSpaceStatistics / getHeapCodeStatistics 可用,但取的是 **JVM 堆**而不是 V8 堆(与 os.totalmem / freemem 的近似同类);getHeapSpaceStatistics 返回空数组(QuickJS 不暴露分空间统计)。serialize / deserialize / setFlagsFromString / cachedDataVersionTag / writeHeapSnapshot / takeCoverage / stopCoverage 一律显式抛 ONJ_UNSUPPORTED:它们要么依赖 V8 的二进制格式,要么是 V8 专有能力。"
234
+ },
235
+ "dgram": {
236
+ "subpath": "dgram",
237
+ "status": "unsupported",
238
+ "note": "刻意不提供,理由与 net 相同:UDP 裸 socket 会让插件绕过 Operit 的工具审批模型(网络访问是工具能力,走用户审批)。需要网络请用 toolCall / 内建 axios。"
239
+ },
240
+ "tls": {
241
+ "subpath": "tls",
242
+ "status": "unsupported",
243
+ "note": "建在 net 之上,net 不提供所以它也做不了。https 已经走 toolCall('http_request'),TLS 由宿主处理。"
244
+ },
245
+ "http2": {
246
+ "subpath": "http2",
247
+ "status": "unsupported",
248
+ "note": "建在 net 之上(HTTP/2 需要长连接与帧控制),net 不提供。http/https 客户端走 toolCall('http_request')。"
249
+ },
250
+ "stream/web": {
251
+ "subpath": "stream/web",
252
+ "status": "unsupported",
253
+ "note": "需要 WHATWG Streams(ReadableStream / WritableStream / TransformStream),Android 的 QuickJS 运行时不提供这些内建。本库实现了 Node 的 stream 模块(含 promises 与 consumers),需要流能力请用 stream。"
254
+ },
255
+ "domain": {
256
+ "subpath": "domain",
257
+ "status": "unsupported",
258
+ "note": "已废弃模块,且它依赖异步上下文追踪(与 async_hooks 同源),运行时不提供。"
259
+ },
260
+ "trace_events": {
261
+ "subpath": "trace_events",
262
+ "status": "unsupported",
263
+ "note": "V8 的 tracing 机制,运行时不是 V8。诊断可观测性请用 diagnostics_channel(已实现)。"
264
+ },
265
+ "wasi": {
266
+ "subpath": "wasi",
267
+ "status": "unsupported",
268
+ "note": "需要 WASM 运行时与 WASI 宿主实现,Android 的 QuickJS 运行时不提供。"
269
+ },
270
+ "inspector/promises": {
271
+ "subpath": "inspector/promises",
272
+ "status": "unsupported",
273
+ "note": "inspector 本身就不支持(需要 V8 inspector 协议),其 promises 形态同理。"
274
+ },
275
+ "_http_agent": {
276
+ "subpath": "_http_agent",
277
+ "status": "unsupported",
278
+ "note": "Node 的**内部**模块(下划线开头)。userland 不应 require 它们;确有包这么做的,说明它依赖 Node 内部实现,本运行时无法提供。已实现的是对应的公开模块:http / https(走 toolCall)。"
279
+ },
280
+ "_http_client": {
281
+ "subpath": "_http_client",
282
+ "status": "unsupported",
283
+ "note": "Node 的**内部**模块(下划线开头)。userland 不应 require 它们;确有包这么做的,说明它依赖 Node 内部实现,本运行时无法提供。已实现的是对应的公开模块:http / https(走 toolCall)。"
284
+ },
285
+ "_http_common": {
286
+ "subpath": "_http_common",
287
+ "status": "unsupported",
288
+ "note": "Node 的**内部**模块(下划线开头)。userland 不应 require 它们;确有包这么做的,说明它依赖 Node 内部实现,本运行时无法提供。已实现的是对应的公开模块:http / https(走 toolCall)。"
289
+ },
290
+ "_http_incoming": {
291
+ "subpath": "_http_incoming",
292
+ "status": "unsupported",
293
+ "note": "Node 的**内部**模块(下划线开头)。userland 不应 require 它们;确有包这么做的,说明它依赖 Node 内部实现,本运行时无法提供。已实现的是对应的公开模块:http / https(走 toolCall)。"
294
+ },
295
+ "_http_outgoing": {
296
+ "subpath": "_http_outgoing",
297
+ "status": "unsupported",
298
+ "note": "Node 的**内部**模块(下划线开头)。userland 不应 require 它们;确有包这么做的,说明它依赖 Node 内部实现,本运行时无法提供。已实现的是对应的公开模块:http / https(走 toolCall)。"
299
+ },
300
+ "_http_server": {
301
+ "subpath": "_http_server",
302
+ "status": "unsupported",
303
+ "note": "Node 的**内部**模块(下划线开头)。userland 不应 require 它们;确有包这么做的,说明它依赖 Node 内部实现,本运行时无法提供。已实现的是对应的公开模块:http / https(走 toolCall)。"
304
+ },
305
+ "_stream_duplex": {
306
+ "subpath": "_stream_duplex",
307
+ "status": "unsupported",
308
+ "note": "Node 的**内部**模块(下划线开头)。userland 不应 require 它们;确有包这么做的,说明它依赖 Node 内部实现,本运行时无法提供。已实现的是对应的公开模块:stream(含 stream/promises、stream/consumers)。"
309
+ },
310
+ "_stream_passthrough": {
311
+ "subpath": "_stream_passthrough",
312
+ "status": "unsupported",
313
+ "note": "Node 的**内部**模块(下划线开头)。userland 不应 require 它们;确有包这么做的,说明它依赖 Node 内部实现,本运行时无法提供。已实现的是对应的公开模块:stream(含 stream/promises、stream/consumers)。"
314
+ },
315
+ "_stream_readable": {
316
+ "subpath": "_stream_readable",
317
+ "status": "unsupported",
318
+ "note": "Node 的**内部**模块(下划线开头)。userland 不应 require 它们;确有包这么做的,说明它依赖 Node 内部实现,本运行时无法提供。已实现的是对应的公开模块:stream(含 stream/promises、stream/consumers)。"
319
+ },
320
+ "_stream_transform": {
321
+ "subpath": "_stream_transform",
322
+ "status": "unsupported",
323
+ "note": "Node 的**内部**模块(下划线开头)。userland 不应 require 它们;确有包这么做的,说明它依赖 Node 内部实现,本运行时无法提供。已实现的是对应的公开模块:stream(含 stream/promises、stream/consumers)。"
324
+ },
325
+ "_stream_wrap": {
326
+ "subpath": "_stream_wrap",
327
+ "status": "unsupported",
328
+ "note": "Node 的**内部**模块(下划线开头)。userland 不应 require 它们;确有包这么做的,说明它依赖 Node 内部实现,本运行时无法提供。已实现的是对应的公开模块:stream(含 stream/promises、stream/consumers)。"
329
+ },
330
+ "_stream_writable": {
331
+ "subpath": "_stream_writable",
332
+ "status": "unsupported",
333
+ "note": "Node 的**内部**模块(下划线开头)。userland 不应 require 它们;确有包这么做的,说明它依赖 Node 内部实现,本运行时无法提供。已实现的是对应的公开模块:stream(含 stream/promises、stream/consumers)。"
334
+ },
335
+ "_tls_common": {
336
+ "subpath": "_tls_common",
337
+ "status": "unsupported",
338
+ "note": "Node 的**内部**模块(下划线开头)。userland 不应 require 它们;确有包这么做的,说明它依赖 Node 内部实现,本运行时无法提供。已实现的是对应的公开模块:https(走 toolCall)。"
339
+ },
340
+ "_tls_wrap": {
341
+ "subpath": "_tls_wrap",
342
+ "status": "unsupported",
343
+ "note": "Node 的**内部**模块(下划线开头)。userland 不应 require 它们;确有包这么做的,说明它依赖 Node 内部实现,本运行时无法提供。已实现的是对应的公开模块:https(走 toolCall)。"
344
+ }
345
+ },
346
+ "packing": {
347
+ "summary": "OperitPackageManager 打包期必须做的裸名处理。Operit 的 require 没有 node_modules 查找:resolveModulePath 对不以 . 或 / 开头的请求原样返回,requireInternal 对 lodash/uuid/axios 之外的一律 return {}(静默)。",
348
+ "rules": [
349
+ "先定位本包在消费方 node_modules 里的**实际安装目录**再拼路径。当前发布形态是带 scope 的 @serveryyswys/node.operit,即 node_modules/@serveryyswys/node.operit/;下面说的 <本包安装目录> 就是它。规则本身与 scope 无关。",
350
+ "所有裸名都要重写,不只是 Node 内建:Node 内建 -> <本包安装目录>/dist/<subpath>.js;npm 包 -> 该包入口文件(main/exports 在打包期解析,运行期没有这个能力)。",
351
+ "lodash / uuid / axios 保持原样(Operit 自带,分别是 lodash 全局、只含 v4 的桩、走 toolCall 的桩)。",
352
+ "改写成相对路径时始终带显式 .js:buildCandidatePaths 用 /\\.[a-z0-9]+$/i 判断有无扩展名,而 node.operit 这个名字本身自带一个点。",
353
+ "相对路径的 .json require **可选地**换成包装模块(module.exports = <json>)。当前 Operit 源码的 executeModule(JsExecutionScriptBuilder.kt:1231)有显式 .json 分支、走 JSON.parse,所以在新构建上不是必需的;生成包装模块只为兼容更早的构建。重写器可以按目标运行时版本决定开不开,产物两种都能跑。",
354
+ "只处理从入口可达的文件:npm 包里的 tests/ 常引用未安装的 devDependency(safer-buffer/tests.js 就是)。",
355
+ "契约表里 status 为 planned / unsupported 的裸名要让构建失败,不能留到运行期静默变成 {}。",
356
+ "扫描 require 必须跳过注释与字符串:node.operit 自己的文档注释里就有 require('<项目>/<本包安装目录>/index.js'),用正则扫会误报成依赖。",
357
+ "把 process(以及 Buffer)注入为**全局**,不要只在入口脚本里 require 一次。实测:supports-color 顶层就是 const {env} = process,没有 process 全局会在 require 时直接抛 'process is not defined'(debug / chalk 都依赖它);注入之后 supports-color 的行为与 Node 完全一致(supportsColorKeys 与 supportsColor.stdout 的取值都相同)。这也会让 debug 之类的包从 browser 分支切回 node 分支。"
358
+ ],
359
+ "verifiedBy": "integration/tools/run.js —— 装真实 npm 包(ms / iconv-lite / safer-buffer),按上述规则打包,用忠实复刻 JsExecutionScriptBuilder.kt 的运行时模拟器加载,再与 Node 原生加载器的结果逐字段比对。",
360
+ "processGlobalEvidence": {
361
+ "withoutInjecting": "supports-color require 抛错:process is not defined;debug 走 browser 分支",
362
+ "withInjecting": "supports-color 导出 [stderr, stdout, supportsColor],stdout=false,与 Node 一致",
363
+ "verifiedBy": "integration/tools/run.js 的「对照实验」一节(同一份打包产物,开/关 injectProcess 各跑一遍)"
364
+ }
365
+ },
366
+ "installDir": "node_modules/@serveryyswys/node.operit",
367
+ "installDirNote": "npm 上带 scope,所以安装路径是 node_modules/@serveryyswys/node.operit/。重写规则本身与 scope 无关:目标是「相对本包实际安装目录」的路径,改 scope 不需要改契约。",
368
+ "runtimeResolution": {
369
+ "note": "打包方(OperitPackageManager / OPM)必须按这些语义产出产物,否则会出现「装好了但 require 不到」。依据是 Operit-src 的 JsExecutionScriptBuilder.kt 与真机实测。",
370
+ "moduleSource": "require 只从 toolpkg 归档读模块:NativeInterface.readToolPkgTextResource(toolPkgId, path)(:675)。完全不碰文件系统 —— 把 node_modules 铺在 /sdcard 上,运行期永远 require 不到,这与有没有重写裸名无关。",
371
+ "requiresProperToolPkg": "必须是正规 toolpkg(有 toolPkgId、入口已注册为 screen)。单文件 .js 沙盒包不行:screenPath 为空、也没有归档资源,所有路径型 require 全部失败(真机实测)。",
372
+ "bareNameFallback": "裸名(不以 ./ 或 / 开头)→ 除 lodash / uuid / axios 外静默返回 {},不抛错(:1288)。这是最难排查的一种失败:报错点不指向 require。",
373
+ "unresolvedPath": "路径型请求解析不到 → 抛 Cannot resolve module \"x\" from \"<root>\"(:1301)。",
374
+ "entryBase": "入口脚本的相对 require 以 dirname(screenPath) 为基准,screenPath = moduleSpec.screen = 入口脚本路径(:1316 / :663)。",
375
+ "nestedBase": "嵌套模块的相对 require 以自身路径为基准(:1242),即标准 CommonJS。",
376
+ "pathNormalization": "normalizePath 丢掉开头的 /,且越界的 .. 直接丢弃,逃不出根(:209)。",
377
+ "extensionRule": "名字命中 /\\.[a-z0-9]+$/i 就只有一个候选、不补 .js(:254)—— 所以重写目标必须显式带扩展名。",
378
+ "jsonModules": ".json 走 JSON.parse(:1231,当前源码)。",
379
+ "conclusion": "重写目标要相对入口脚本所在目录(嵌套模块则是相对自身;在「入口位于包根」的常规布局下两者一致),并且 node_modules 必须进归档。"
380
+ },
381
+ "packagingTool": "OperitPackageManager (OPM)",
382
+ "packagingToolNote": "打包期负责裸名重写与归档的一方。本文档里出现的 OperitPackageManager / OPM 都指它;命令行示例用 opm。"
383
+ }