mongo.do 0.1.0 → 0.1.1

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 (706) hide show
  1. package/dist/cli/index.d.ts +1 -15
  2. package/dist/cli/index.js +4083 -196
  3. package/dist/cli/index.js.map +1 -1
  4. package/dist/index.d.ts +2740 -20
  5. package/dist/index.js +9375 -27
  6. package/dist/index.js.map +1 -1
  7. package/dist/worker-entrypoint-BEW23Gmp.d.ts +1331 -0
  8. package/dist/worker.d.ts +6 -5
  9. package/dist/worker.js +5477 -18
  10. package/dist/worker.js.map +1 -1
  11. package/package.json +3 -2
  12. package/dist/agentfs/adapters/anthropic.d.ts +0 -176
  13. package/dist/agentfs/adapters/anthropic.d.ts.map +0 -1
  14. package/dist/agentfs/adapters/anthropic.js +0 -629
  15. package/dist/agentfs/adapters/anthropic.js.map +0 -1
  16. package/dist/agentfs/adapters/index.d.ts +0 -21
  17. package/dist/agentfs/adapters/index.d.ts.map +0 -1
  18. package/dist/agentfs/adapters/index.js +0 -23
  19. package/dist/agentfs/adapters/index.js.map +0 -1
  20. package/dist/agentfs/adapters/vercel.d.ts +0 -260
  21. package/dist/agentfs/adapters/vercel.d.ts.map +0 -1
  22. package/dist/agentfs/adapters/vercel.js +0 -288
  23. package/dist/agentfs/adapters/vercel.js.map +0 -1
  24. package/dist/agentfs/glob.d.ts +0 -116
  25. package/dist/agentfs/glob.d.ts.map +0 -1
  26. package/dist/agentfs/glob.js +0 -270
  27. package/dist/agentfs/glob.js.map +0 -1
  28. package/dist/agentfs/grep.d.ts +0 -83
  29. package/dist/agentfs/grep.d.ts.map +0 -1
  30. package/dist/agentfs/grep.js +0 -193
  31. package/dist/agentfs/grep.js.map +0 -1
  32. package/dist/agentfs/index.d.ts +0 -22
  33. package/dist/agentfs/index.d.ts.map +0 -1
  34. package/dist/agentfs/index.js +0 -18
  35. package/dist/agentfs/index.js.map +0 -1
  36. package/dist/agentfs/kv-store.d.ts +0 -128
  37. package/dist/agentfs/kv-store.d.ts.map +0 -1
  38. package/dist/agentfs/kv-store.js +0 -227
  39. package/dist/agentfs/kv-store.js.map +0 -1
  40. package/dist/agentfs/mondo-agent.d.ts +0 -255
  41. package/dist/agentfs/mondo-agent.d.ts.map +0 -1
  42. package/dist/agentfs/mondo-agent.js +0 -879
  43. package/dist/agentfs/mondo-agent.js.map +0 -1
  44. package/dist/agentfs/toolcalls.d.ts +0 -130
  45. package/dist/agentfs/toolcalls.d.ts.map +0 -1
  46. package/dist/agentfs/toolcalls.js +0 -178
  47. package/dist/agentfs/toolcalls.js.map +0 -1
  48. package/dist/agentfs/types.d.ts +0 -171
  49. package/dist/agentfs/types.d.ts.map +0 -1
  50. package/dist/agentfs/types.js +0 -7
  51. package/dist/agentfs/types.js.map +0 -1
  52. package/dist/agentfs/vfs.d.ts +0 -249
  53. package/dist/agentfs/vfs.d.ts.map +0 -1
  54. package/dist/agentfs/vfs.js +0 -469
  55. package/dist/agentfs/vfs.js.map +0 -1
  56. package/dist/cli/index.d.ts.map +0 -1
  57. package/dist/cli/mcp.d.ts +0 -119
  58. package/dist/cli/mcp.d.ts.map +0 -1
  59. package/dist/cli/mcp.js +0 -418
  60. package/dist/cli/mcp.js.map +0 -1
  61. package/dist/cli/server.d.ts +0 -179
  62. package/dist/cli/server.d.ts.map +0 -1
  63. package/dist/cli/server.js +0 -441
  64. package/dist/cli/server.js.map +0 -1
  65. package/dist/client/Collection.d.ts +0 -199
  66. package/dist/client/Collection.d.ts.map +0 -1
  67. package/dist/client/Collection.js +0 -256
  68. package/dist/client/Collection.js.map +0 -1
  69. package/dist/client/Database.d.ts +0 -68
  70. package/dist/client/Database.d.ts.map +0 -1
  71. package/dist/client/Database.js +0 -105
  72. package/dist/client/Database.js.map +0 -1
  73. package/dist/client/MongoClient.d.ts +0 -165
  74. package/dist/client/MongoClient.d.ts.map +0 -1
  75. package/dist/client/MongoClient.js +0 -307
  76. package/dist/client/MongoClient.js.map +0 -1
  77. package/dist/client/aggregation-cursor.d.ts +0 -210
  78. package/dist/client/aggregation-cursor.d.ts.map +0 -1
  79. package/dist/client/aggregation-cursor.js +0 -509
  80. package/dist/client/aggregation-cursor.js.map +0 -1
  81. package/dist/client/bulk-write.d.ts +0 -216
  82. package/dist/client/bulk-write.d.ts.map +0 -1
  83. package/dist/client/bulk-write.js +0 -63
  84. package/dist/client/bulk-write.js.map +0 -1
  85. package/dist/client/change-stream.d.ts +0 -245
  86. package/dist/client/change-stream.d.ts.map +0 -1
  87. package/dist/client/change-stream.js +0 -429
  88. package/dist/client/change-stream.js.map +0 -1
  89. package/dist/client/cursor.d.ts +0 -85
  90. package/dist/client/cursor.d.ts.map +0 -1
  91. package/dist/client/cursor.js +0 -156
  92. package/dist/client/cursor.js.map +0 -1
  93. package/dist/client/http-cursor.d.ts +0 -233
  94. package/dist/client/http-cursor.d.ts.map +0 -1
  95. package/dist/client/http-cursor.js +0 -496
  96. package/dist/client/http-cursor.js.map +0 -1
  97. package/dist/client/index.d.ts +0 -18
  98. package/dist/client/index.d.ts.map +0 -1
  99. package/dist/client/index.js +0 -24
  100. package/dist/client/index.js.map +0 -1
  101. package/dist/client/mongo-client.d.ts +0 -60
  102. package/dist/client/mongo-client.d.ts.map +0 -1
  103. package/dist/client/mongo-client.js +0 -190
  104. package/dist/client/mongo-client.js.map +0 -1
  105. package/dist/client/mongo-collection.d.ts +0 -359
  106. package/dist/client/mongo-collection.d.ts.map +0 -1
  107. package/dist/client/mongo-collection.js +0 -1641
  108. package/dist/client/mongo-collection.js.map +0 -1
  109. package/dist/client/mongo-cursor.d.ts +0 -257
  110. package/dist/client/mongo-cursor.d.ts.map +0 -1
  111. package/dist/client/mongo-cursor.js +0 -621
  112. package/dist/client/mongo-cursor.js.map +0 -1
  113. package/dist/client/mongo-database.d.ts +0 -88
  114. package/dist/client/mongo-database.d.ts.map +0 -1
  115. package/dist/client/mongo-database.js +0 -139
  116. package/dist/client/mongo-database.js.map +0 -1
  117. package/dist/client/session.d.ts +0 -210
  118. package/dist/client/session.d.ts.map +0 -1
  119. package/dist/client/session.js +0 -326
  120. package/dist/client/session.js.map +0 -1
  121. package/dist/durable-object/index-manager.d.ts +0 -173
  122. package/dist/durable-object/index-manager.d.ts.map +0 -1
  123. package/dist/durable-object/index-manager.js +0 -764
  124. package/dist/durable-object/index-manager.js.map +0 -1
  125. package/dist/durable-object/index.d.ts +0 -12
  126. package/dist/durable-object/index.d.ts.map +0 -1
  127. package/dist/durable-object/index.js +0 -8
  128. package/dist/durable-object/index.js.map +0 -1
  129. package/dist/durable-object/mcp-handler.d.ts +0 -52
  130. package/dist/durable-object/mcp-handler.d.ts.map +0 -1
  131. package/dist/durable-object/mcp-handler.js +0 -186
  132. package/dist/durable-object/mcp-handler.js.map +0 -1
  133. package/dist/durable-object/migrations.d.ts +0 -40
  134. package/dist/durable-object/migrations.d.ts.map +0 -1
  135. package/dist/durable-object/migrations.js +0 -121
  136. package/dist/durable-object/migrations.js.map +0 -1
  137. package/dist/durable-object/mondo-database.d.ts +0 -148
  138. package/dist/durable-object/mondo-database.d.ts.map +0 -1
  139. package/dist/durable-object/mondo-database.js +0 -621
  140. package/dist/durable-object/mondo-database.js.map +0 -1
  141. package/dist/durable-object/schema.d.ts +0 -192
  142. package/dist/durable-object/schema.d.ts.map +0 -1
  143. package/dist/durable-object/schema.js +0 -186
  144. package/dist/durable-object/schema.js.map +0 -1
  145. package/dist/embedding/document-serializer.d.ts +0 -118
  146. package/dist/embedding/document-serializer.d.ts.map +0 -1
  147. package/dist/embedding/document-serializer.js +0 -339
  148. package/dist/embedding/document-serializer.js.map +0 -1
  149. package/dist/embedding/embedding-manager.d.ts +0 -136
  150. package/dist/embedding/embedding-manager.d.ts.map +0 -1
  151. package/dist/embedding/embedding-manager.js +0 -176
  152. package/dist/embedding/embedding-manager.js.map +0 -1
  153. package/dist/embedding/index.d.ts +0 -9
  154. package/dist/embedding/index.d.ts.map +0 -1
  155. package/dist/embedding/index.js +0 -9
  156. package/dist/embedding/index.js.map +0 -1
  157. package/dist/executor/aggregation-executor.d.ts +0 -93
  158. package/dist/executor/aggregation-executor.d.ts.map +0 -1
  159. package/dist/executor/aggregation-executor.js +0 -275
  160. package/dist/executor/aggregation-executor.js.map +0 -1
  161. package/dist/executor/function-executor.d.ts +0 -39
  162. package/dist/executor/function-executor.d.ts.map +0 -1
  163. package/dist/executor/function-executor.js +0 -168
  164. package/dist/executor/function-executor.js.map +0 -1
  165. package/dist/executor/index.d.ts +0 -4
  166. package/dist/executor/index.d.ts.map +0 -1
  167. package/dist/executor/index.js +0 -4
  168. package/dist/executor/index.js.map +0 -1
  169. package/dist/executor/vector-search-executor.d.ts +0 -71
  170. package/dist/executor/vector-search-executor.d.ts.map +0 -1
  171. package/dist/executor/vector-search-executor.js +0 -113
  172. package/dist/executor/vector-search-executor.js.map +0 -1
  173. package/dist/index.d.ts.map +0 -1
  174. package/dist/mcp/adapters/anthropic-adapter.d.ts +0 -256
  175. package/dist/mcp/adapters/anthropic-adapter.d.ts.map +0 -1
  176. package/dist/mcp/adapters/anthropic-adapter.js +0 -409
  177. package/dist/mcp/adapters/anthropic-adapter.js.map +0 -1
  178. package/dist/mcp/adapters/base-adapter.d.ts +0 -164
  179. package/dist/mcp/adapters/base-adapter.d.ts.map +0 -1
  180. package/dist/mcp/adapters/base-adapter.js +0 -277
  181. package/dist/mcp/adapters/base-adapter.js.map +0 -1
  182. package/dist/mcp/adapters/errors.d.ts +0 -173
  183. package/dist/mcp/adapters/errors.d.ts.map +0 -1
  184. package/dist/mcp/adapters/errors.js +0 -305
  185. package/dist/mcp/adapters/errors.js.map +0 -1
  186. package/dist/mcp/adapters/index.d.ts +0 -65
  187. package/dist/mcp/adapters/index.d.ts.map +0 -1
  188. package/dist/mcp/adapters/index.js +0 -92
  189. package/dist/mcp/adapters/index.js.map +0 -1
  190. package/dist/mcp/adapters/streaming.d.ts +0 -200
  191. package/dist/mcp/adapters/streaming.d.ts.map +0 -1
  192. package/dist/mcp/adapters/streaming.js +0 -381
  193. package/dist/mcp/adapters/streaming.js.map +0 -1
  194. package/dist/mcp/adapters/vercel-adapter.d.ts +0 -321
  195. package/dist/mcp/adapters/vercel-adapter.d.ts.map +0 -1
  196. package/dist/mcp/adapters/vercel-adapter.js +0 -487
  197. package/dist/mcp/adapters/vercel-adapter.js.map +0 -1
  198. package/dist/mcp/agent.d.ts +0 -192
  199. package/dist/mcp/agent.d.ts.map +0 -1
  200. package/dist/mcp/agent.js +0 -338
  201. package/dist/mcp/agent.js.map +0 -1
  202. package/dist/mcp/cli.d.ts +0 -71
  203. package/dist/mcp/cli.d.ts.map +0 -1
  204. package/dist/mcp/cli.js +0 -218
  205. package/dist/mcp/cli.js.map +0 -1
  206. package/dist/mcp/index.d.ts +0 -15
  207. package/dist/mcp/index.d.ts.map +0 -1
  208. package/dist/mcp/index.js +0 -20
  209. package/dist/mcp/index.js.map +0 -1
  210. package/dist/mcp/sandbox/database-proxy.d.ts +0 -118
  211. package/dist/mcp/sandbox/database-proxy.d.ts.map +0 -1
  212. package/dist/mcp/sandbox/database-proxy.js +0 -154
  213. package/dist/mcp/sandbox/database-proxy.js.map +0 -1
  214. package/dist/mcp/sandbox/index.d.ts +0 -8
  215. package/dist/mcp/sandbox/index.d.ts.map +0 -1
  216. package/dist/mcp/sandbox/index.js +0 -7
  217. package/dist/mcp/sandbox/index.js.map +0 -1
  218. package/dist/mcp/sandbox/miniflare-evaluator.d.ts +0 -72
  219. package/dist/mcp/sandbox/miniflare-evaluator.d.ts.map +0 -1
  220. package/dist/mcp/sandbox/miniflare-evaluator.js +0 -379
  221. package/dist/mcp/sandbox/miniflare-evaluator.js.map +0 -1
  222. package/dist/mcp/sandbox/template.d.ts +0 -48
  223. package/dist/mcp/sandbox/template.d.ts.map +0 -1
  224. package/dist/mcp/sandbox/template.js +0 -147
  225. package/dist/mcp/sandbox/template.js.map +0 -1
  226. package/dist/mcp/sandbox/worker-evaluator.d.ts +0 -160
  227. package/dist/mcp/sandbox/worker-evaluator.d.ts.map +0 -1
  228. package/dist/mcp/sandbox/worker-evaluator.js +0 -217
  229. package/dist/mcp/sandbox/worker-evaluator.js.map +0 -1
  230. package/dist/mcp/server.d.ts +0 -75
  231. package/dist/mcp/server.d.ts.map +0 -1
  232. package/dist/mcp/server.js +0 -278
  233. package/dist/mcp/server.js.map +0 -1
  234. package/dist/mcp/tool-call-auditor.d.ts +0 -188
  235. package/dist/mcp/tool-call-auditor.d.ts.map +0 -1
  236. package/dist/mcp/tool-call-auditor.js +0 -198
  237. package/dist/mcp/tool-call-auditor.js.map +0 -1
  238. package/dist/mcp/tools/do.d.ts +0 -51
  239. package/dist/mcp/tools/do.d.ts.map +0 -1
  240. package/dist/mcp/tools/do.js +0 -113
  241. package/dist/mcp/tools/do.js.map +0 -1
  242. package/dist/mcp/tools/fetch.d.ts +0 -43
  243. package/dist/mcp/tools/fetch.d.ts.map +0 -1
  244. package/dist/mcp/tools/fetch.js +0 -127
  245. package/dist/mcp/tools/fetch.js.map +0 -1
  246. package/dist/mcp/tools/index.d.ts +0 -9
  247. package/dist/mcp/tools/index.d.ts.map +0 -1
  248. package/dist/mcp/tools/index.js +0 -9
  249. package/dist/mcp/tools/index.js.map +0 -1
  250. package/dist/mcp/tools/search.d.ts +0 -60
  251. package/dist/mcp/tools/search.d.ts.map +0 -1
  252. package/dist/mcp/tools/search.js +0 -278
  253. package/dist/mcp/tools/search.js.map +0 -1
  254. package/dist/mcp/transport/http.d.ts +0 -144
  255. package/dist/mcp/transport/http.d.ts.map +0 -1
  256. package/dist/mcp/transport/http.js +0 -545
  257. package/dist/mcp/transport/http.js.map +0 -1
  258. package/dist/mcp/transport/index.d.ts +0 -10
  259. package/dist/mcp/transport/index.d.ts.map +0 -1
  260. package/dist/mcp/transport/index.js +0 -12
  261. package/dist/mcp/transport/index.js.map +0 -1
  262. package/dist/mcp/transport/stdio.d.ts +0 -132
  263. package/dist/mcp/transport/stdio.d.ts.map +0 -1
  264. package/dist/mcp/transport/stdio.js +0 -466
  265. package/dist/mcp/transport/stdio.js.map +0 -1
  266. package/dist/mcp/types.d.ts +0 -476
  267. package/dist/mcp/types.d.ts.map +0 -1
  268. package/dist/mcp/types.js +0 -178
  269. package/dist/mcp/types.js.map +0 -1
  270. package/dist/olap/cdc/cdc-buffer.d.ts +0 -92
  271. package/dist/olap/cdc/cdc-buffer.d.ts.map +0 -1
  272. package/dist/olap/cdc/cdc-buffer.js +0 -146
  273. package/dist/olap/cdc/cdc-buffer.js.map +0 -1
  274. package/dist/olap/cdc/cdc-emitter.d.ts +0 -118
  275. package/dist/olap/cdc/cdc-emitter.d.ts.map +0 -1
  276. package/dist/olap/cdc/cdc-emitter.js +0 -217
  277. package/dist/olap/cdc/cdc-emitter.js.map +0 -1
  278. package/dist/olap/cdc/cdc-schema.d.ts +0 -119
  279. package/dist/olap/cdc/cdc-schema.d.ts.map +0 -1
  280. package/dist/olap/cdc/cdc-schema.js +0 -253
  281. package/dist/olap/cdc/cdc-schema.js.map +0 -1
  282. package/dist/olap/cdc/index.d.ts +0 -10
  283. package/dist/olap/cdc/index.d.ts.map +0 -1
  284. package/dist/olap/cdc/index.js +0 -10
  285. package/dist/olap/cdc/index.js.map +0 -1
  286. package/dist/olap/clickhouse/iceberg.d.ts +0 -164
  287. package/dist/olap/clickhouse/iceberg.d.ts.map +0 -1
  288. package/dist/olap/clickhouse/iceberg.js +0 -138
  289. package/dist/olap/clickhouse/iceberg.js.map +0 -1
  290. package/dist/olap/clickhouse/index.d.ts +0 -14
  291. package/dist/olap/clickhouse/index.d.ts.map +0 -1
  292. package/dist/olap/clickhouse/index.js +0 -14
  293. package/dist/olap/clickhouse/index.js.map +0 -1
  294. package/dist/olap/clickhouse/mapper.d.ts +0 -170
  295. package/dist/olap/clickhouse/mapper.d.ts.map +0 -1
  296. package/dist/olap/clickhouse/mapper.js +0 -654
  297. package/dist/olap/clickhouse/mapper.js.map +0 -1
  298. package/dist/olap/clickhouse/olap-backend.d.ts +0 -181
  299. package/dist/olap/clickhouse/olap-backend.d.ts.map +0 -1
  300. package/dist/olap/clickhouse/olap-backend.js +0 -1083
  301. package/dist/olap/clickhouse/olap-backend.js.map +0 -1
  302. package/dist/olap/clickhouse/query-executor.d.ts +0 -163
  303. package/dist/olap/clickhouse/query-executor.d.ts.map +0 -1
  304. package/dist/olap/clickhouse/query-executor.js +0 -560
  305. package/dist/olap/clickhouse/query-executor.js.map +0 -1
  306. package/dist/olap/clickhouse/query.d.ts +0 -134
  307. package/dist/olap/clickhouse/query.d.ts.map +0 -1
  308. package/dist/olap/clickhouse/query.js +0 -512
  309. package/dist/olap/clickhouse/query.js.map +0 -1
  310. package/dist/olap/stage/index.d.ts +0 -6
  311. package/dist/olap/stage/index.d.ts.map +0 -1
  312. package/dist/olap/stage/index.js +0 -6
  313. package/dist/olap/stage/index.js.map +0 -1
  314. package/dist/olap/stage/parser.d.ts +0 -68
  315. package/dist/olap/stage/parser.d.ts.map +0 -1
  316. package/dist/olap/stage/parser.js +0 -293
  317. package/dist/olap/stage/parser.js.map +0 -1
  318. package/dist/olap/stage/router.d.ts +0 -94
  319. package/dist/olap/stage/router.d.ts.map +0 -1
  320. package/dist/olap/stage/router.js +0 -390
  321. package/dist/olap/stage/router.js.map +0 -1
  322. package/dist/rpc/endpoint.d.ts +0 -52
  323. package/dist/rpc/endpoint.d.ts.map +0 -1
  324. package/dist/rpc/endpoint.js +0 -734
  325. package/dist/rpc/endpoint.js.map +0 -1
  326. package/dist/rpc/index.d.ts +0 -34
  327. package/dist/rpc/index.d.ts.map +0 -1
  328. package/dist/rpc/index.js +0 -45
  329. package/dist/rpc/index.js.map +0 -1
  330. package/dist/rpc/rpc-client.d.ts +0 -275
  331. package/dist/rpc/rpc-client.d.ts.map +0 -1
  332. package/dist/rpc/rpc-client.js +0 -735
  333. package/dist/rpc/rpc-client.js.map +0 -1
  334. package/dist/rpc/rpc-target.d.ts +0 -220
  335. package/dist/rpc/rpc-target.d.ts.map +0 -1
  336. package/dist/rpc/rpc-target.js +0 -500
  337. package/dist/rpc/rpc-target.js.map +0 -1
  338. package/dist/rpc/worker-entrypoint.d.ts +0 -159
  339. package/dist/rpc/worker-entrypoint.d.ts.map +0 -1
  340. package/dist/rpc/worker-entrypoint.js +0 -212
  341. package/dist/rpc/worker-entrypoint.js.map +0 -1
  342. package/dist/server.d.ts +0 -18
  343. package/dist/server.d.ts.map +0 -1
  344. package/dist/server.js +0 -129
  345. package/dist/server.js.map +0 -1
  346. package/dist/studio/components/browser/CollectionItem.d.ts +0 -26
  347. package/dist/studio/components/browser/CollectionItem.d.ts.map +0 -1
  348. package/dist/studio/components/browser/CollectionItem.js +0 -143
  349. package/dist/studio/components/browser/CollectionItem.js.map +0 -1
  350. package/dist/studio/components/browser/CollectionTree.d.ts +0 -45
  351. package/dist/studio/components/browser/CollectionTree.d.ts.map +0 -1
  352. package/dist/studio/components/browser/CollectionTree.js +0 -207
  353. package/dist/studio/components/browser/CollectionTree.js.map +0 -1
  354. package/dist/studio/components/browser/ConnectedDatabaseBrowser.d.ts +0 -51
  355. package/dist/studio/components/browser/ConnectedDatabaseBrowser.d.ts.map +0 -1
  356. package/dist/studio/components/browser/ConnectedDatabaseBrowser.js +0 -185
  357. package/dist/studio/components/browser/ConnectedDatabaseBrowser.js.map +0 -1
  358. package/dist/studio/components/browser/DatabaseBrowser.d.ts +0 -46
  359. package/dist/studio/components/browser/DatabaseBrowser.d.ts.map +0 -1
  360. package/dist/studio/components/browser/DatabaseBrowser.js +0 -304
  361. package/dist/studio/components/browser/DatabaseBrowser.js.map +0 -1
  362. package/dist/studio/components/browser/__tests__/CollectionItem.test.d.ts +0 -5
  363. package/dist/studio/components/browser/__tests__/CollectionItem.test.d.ts.map +0 -1
  364. package/dist/studio/components/browser/__tests__/CollectionItem.test.js +0 -169
  365. package/dist/studio/components/browser/__tests__/CollectionItem.test.js.map +0 -1
  366. package/dist/studio/components/browser/__tests__/CollectionTree.test.d.ts +0 -5
  367. package/dist/studio/components/browser/__tests__/CollectionTree.test.d.ts.map +0 -1
  368. package/dist/studio/components/browser/__tests__/CollectionTree.test.js +0 -203
  369. package/dist/studio/components/browser/__tests__/CollectionTree.test.js.map +0 -1
  370. package/dist/studio/components/browser/__tests__/DatabaseBrowser.e2e.test.d.ts +0 -8
  371. package/dist/studio/components/browser/__tests__/DatabaseBrowser.e2e.test.d.ts.map +0 -1
  372. package/dist/studio/components/browser/__tests__/DatabaseBrowser.e2e.test.js +0 -522
  373. package/dist/studio/components/browser/__tests__/DatabaseBrowser.e2e.test.js.map +0 -1
  374. package/dist/studio/components/browser/__tests__/DatabaseBrowser.test.d.ts +0 -5
  375. package/dist/studio/components/browser/__tests__/DatabaseBrowser.test.d.ts.map +0 -1
  376. package/dist/studio/components/browser/__tests__/DatabaseBrowser.test.js +0 -518
  377. package/dist/studio/components/browser/__tests__/DatabaseBrowser.test.js.map +0 -1
  378. package/dist/studio/components/browser/__tests__/setup.d.ts +0 -5
  379. package/dist/studio/components/browser/__tests__/setup.d.ts.map +0 -1
  380. package/dist/studio/components/browser/__tests__/setup.js +0 -22
  381. package/dist/studio/components/browser/__tests__/setup.js.map +0 -1
  382. package/dist/studio/components/browser/index.d.ts +0 -15
  383. package/dist/studio/components/browser/index.d.ts.map +0 -1
  384. package/dist/studio/components/browser/index.js +0 -10
  385. package/dist/studio/components/browser/index.js.map +0 -1
  386. package/dist/studio/components/browser/types.d.ts +0 -33
  387. package/dist/studio/components/browser/types.d.ts.map +0 -1
  388. package/dist/studio/components/browser/types.js +0 -5
  389. package/dist/studio/components/browser/types.js.map +0 -1
  390. package/dist/studio/components/connection/ConnectionForm.d.ts +0 -59
  391. package/dist/studio/components/connection/ConnectionForm.d.ts.map +0 -1
  392. package/dist/studio/components/connection/ConnectionForm.js +0 -274
  393. package/dist/studio/components/connection/ConnectionForm.js.map +0 -1
  394. package/dist/studio/components/connection/ConnectionList.d.ts +0 -59
  395. package/dist/studio/components/connection/ConnectionList.d.ts.map +0 -1
  396. package/dist/studio/components/connection/ConnectionList.js +0 -286
  397. package/dist/studio/components/connection/ConnectionList.js.map +0 -1
  398. package/dist/studio/components/connection/ConnectionPanel.d.ts +0 -132
  399. package/dist/studio/components/connection/ConnectionPanel.d.ts.map +0 -1
  400. package/dist/studio/components/connection/ConnectionPanel.js +0 -293
  401. package/dist/studio/components/connection/ConnectionPanel.js.map +0 -1
  402. package/dist/studio/components/connection/__tests__/ConnectionPanel.test.d.ts +0 -8
  403. package/dist/studio/components/connection/__tests__/ConnectionPanel.test.d.ts.map +0 -1
  404. package/dist/studio/components/connection/__tests__/ConnectionPanel.test.js +0 -632
  405. package/dist/studio/components/connection/__tests__/ConnectionPanel.test.js.map +0 -1
  406. package/dist/studio/components/connection/__tests__/setup.d.ts +0 -5
  407. package/dist/studio/components/connection/__tests__/setup.d.ts.map +0 -1
  408. package/dist/studio/components/connection/__tests__/setup.js +0 -11
  409. package/dist/studio/components/connection/__tests__/setup.js.map +0 -1
  410. package/dist/studio/components/connection/index.d.ts +0 -10
  411. package/dist/studio/components/connection/index.d.ts.map +0 -1
  412. package/dist/studio/components/connection/index.js +0 -7
  413. package/dist/studio/components/connection/index.js.map +0 -1
  414. package/dist/studio/components/crud/DeleteDocumentDialog.d.ts +0 -91
  415. package/dist/studio/components/crud/DeleteDocumentDialog.d.ts.map +0 -1
  416. package/dist/studio/components/crud/DeleteDocumentDialog.js +0 -273
  417. package/dist/studio/components/crud/DeleteDocumentDialog.js.map +0 -1
  418. package/dist/studio/components/crud/DocumentEditor.d.ts +0 -32
  419. package/dist/studio/components/crud/DocumentEditor.d.ts.map +0 -1
  420. package/dist/studio/components/crud/DocumentEditor.js +0 -546
  421. package/dist/studio/components/crud/DocumentEditor.js.map +0 -1
  422. package/dist/studio/components/crud/InsertDocumentDialog.d.ts +0 -78
  423. package/dist/studio/components/crud/InsertDocumentDialog.d.ts.map +0 -1
  424. package/dist/studio/components/crud/InsertDocumentDialog.js +0 -323
  425. package/dist/studio/components/crud/InsertDocumentDialog.js.map +0 -1
  426. package/dist/studio/components/crud/__tests__/DeleteDocumentDialog.test.d.ts +0 -5
  427. package/dist/studio/components/crud/__tests__/DeleteDocumentDialog.test.d.ts.map +0 -1
  428. package/dist/studio/components/crud/__tests__/DeleteDocumentDialog.test.js +0 -298
  429. package/dist/studio/components/crud/__tests__/DeleteDocumentDialog.test.js.map +0 -1
  430. package/dist/studio/components/crud/__tests__/DocumentEditor.test.d.ts +0 -8
  431. package/dist/studio/components/crud/__tests__/DocumentEditor.test.d.ts.map +0 -1
  432. package/dist/studio/components/crud/__tests__/DocumentEditor.test.js +0 -368
  433. package/dist/studio/components/crud/__tests__/DocumentEditor.test.js.map +0 -1
  434. package/dist/studio/components/crud/__tests__/InsertDocumentDialog.test.d.ts +0 -2
  435. package/dist/studio/components/crud/__tests__/InsertDocumentDialog.test.d.ts.map +0 -1
  436. package/dist/studio/components/crud/__tests__/InsertDocumentDialog.test.js +0 -352
  437. package/dist/studio/components/crud/__tests__/InsertDocumentDialog.test.js.map +0 -1
  438. package/dist/studio/components/crud/__tests__/setup.d.ts +0 -5
  439. package/dist/studio/components/crud/__tests__/setup.d.ts.map +0 -1
  440. package/dist/studio/components/crud/__tests__/setup.js +0 -22
  441. package/dist/studio/components/crud/__tests__/setup.js.map +0 -1
  442. package/dist/studio/components/crud/index.d.ts +0 -12
  443. package/dist/studio/components/crud/index.d.ts.map +0 -1
  444. package/dist/studio/components/crud/index.js +0 -11
  445. package/dist/studio/components/crud/index.js.map +0 -1
  446. package/dist/studio/hooks/useConnection.d.ts +0 -127
  447. package/dist/studio/hooks/useConnection.d.ts.map +0 -1
  448. package/dist/studio/hooks/useConnection.js +0 -414
  449. package/dist/studio/hooks/useConnection.js.map +0 -1
  450. package/dist/studio/hooks/useDatabaseBrowser.d.ts +0 -107
  451. package/dist/studio/hooks/useDatabaseBrowser.d.ts.map +0 -1
  452. package/dist/studio/hooks/useDatabaseBrowser.js +0 -294
  453. package/dist/studio/hooks/useDatabaseBrowser.js.map +0 -1
  454. package/dist/studio/index.d.ts +0 -16
  455. package/dist/studio/index.d.ts.map +0 -1
  456. package/dist/studio/index.js +0 -14
  457. package/dist/studio/index.js.map +0 -1
  458. package/dist/studio/types/connection.d.ts +0 -266
  459. package/dist/studio/types/connection.d.ts.map +0 -1
  460. package/dist/studio/types/connection.js +0 -159
  461. package/dist/studio/types/connection.js.map +0 -1
  462. package/dist/studio/vitest.config.d.ts +0 -3
  463. package/dist/studio/vitest.config.d.ts.map +0 -1
  464. package/dist/studio/vitest.config.js +0 -33
  465. package/dist/studio/vitest.config.js.map +0 -1
  466. package/dist/translator/aggregation-translator.d.ts +0 -51
  467. package/dist/translator/aggregation-translator.d.ts.map +0 -1
  468. package/dist/translator/aggregation-translator.js +0 -324
  469. package/dist/translator/aggregation-translator.js.map +0 -1
  470. package/dist/translator/dialect.d.ts +0 -131
  471. package/dist/translator/dialect.d.ts.map +0 -1
  472. package/dist/translator/dialect.js +0 -276
  473. package/dist/translator/dialect.js.map +0 -1
  474. package/dist/translator/geo-translator.d.ts +0 -91
  475. package/dist/translator/geo-translator.d.ts.map +0 -1
  476. package/dist/translator/geo-translator.js +0 -587
  477. package/dist/translator/geo-translator.js.map +0 -1
  478. package/dist/translator/hybrid-translator.d.ts +0 -70
  479. package/dist/translator/hybrid-translator.d.ts.map +0 -1
  480. package/dist/translator/hybrid-translator.js +0 -193
  481. package/dist/translator/hybrid-translator.js.map +0 -1
  482. package/dist/translator/index.d.ts +0 -13
  483. package/dist/translator/index.d.ts.map +0 -1
  484. package/dist/translator/index.js +0 -11
  485. package/dist/translator/index.js.map +0 -1
  486. package/dist/translator/query-translator.d.ts +0 -211
  487. package/dist/translator/query-translator.d.ts.map +0 -1
  488. package/dist/translator/query-translator.js +0 -1276
  489. package/dist/translator/query-translator.js.map +0 -1
  490. package/dist/translator/search-highlight.d.ts +0 -83
  491. package/dist/translator/search-highlight.d.ts.map +0 -1
  492. package/dist/translator/search-highlight.js +0 -83
  493. package/dist/translator/search-highlight.js.map +0 -1
  494. package/dist/translator/search-translator.d.ts +0 -155
  495. package/dist/translator/search-translator.d.ts.map +0 -1
  496. package/dist/translator/search-translator.js +0 -241
  497. package/dist/translator/search-translator.js.map +0 -1
  498. package/dist/translator/stages/add-fields-stage.d.ts +0 -7
  499. package/dist/translator/stages/add-fields-stage.d.ts.map +0 -1
  500. package/dist/translator/stages/add-fields-stage.js +0 -72
  501. package/dist/translator/stages/add-fields-stage.js.map +0 -1
  502. package/dist/translator/stages/bucket-stage.d.ts +0 -7
  503. package/dist/translator/stages/bucket-stage.d.ts.map +0 -1
  504. package/dist/translator/stages/bucket-stage.js +0 -87
  505. package/dist/translator/stages/bucket-stage.js.map +0 -1
  506. package/dist/translator/stages/count-stage.d.ts +0 -7
  507. package/dist/translator/stages/count-stage.d.ts.map +0 -1
  508. package/dist/translator/stages/count-stage.js +0 -12
  509. package/dist/translator/stages/count-stage.js.map +0 -1
  510. package/dist/translator/stages/expression-translator.d.ts +0 -68
  511. package/dist/translator/stages/expression-translator.d.ts.map +0 -1
  512. package/dist/translator/stages/expression-translator.js +0 -467
  513. package/dist/translator/stages/expression-translator.js.map +0 -1
  514. package/dist/translator/stages/facet-stage.d.ts +0 -13
  515. package/dist/translator/stages/facet-stage.d.ts.map +0 -1
  516. package/dist/translator/stages/facet-stage.js +0 -26
  517. package/dist/translator/stages/facet-stage.js.map +0 -1
  518. package/dist/translator/stages/fusion-stages.d.ts +0 -118
  519. package/dist/translator/stages/fusion-stages.d.ts.map +0 -1
  520. package/dist/translator/stages/fusion-stages.js +0 -201
  521. package/dist/translator/stages/fusion-stages.js.map +0 -1
  522. package/dist/translator/stages/group-stage.d.ts +0 -8
  523. package/dist/translator/stages/group-stage.d.ts.map +0 -1
  524. package/dist/translator/stages/group-stage.js +0 -123
  525. package/dist/translator/stages/group-stage.js.map +0 -1
  526. package/dist/translator/stages/index.d.ts +0 -24
  527. package/dist/translator/stages/index.d.ts.map +0 -1
  528. package/dist/translator/stages/index.js +0 -24
  529. package/dist/translator/stages/index.js.map +0 -1
  530. package/dist/translator/stages/join-optimizer.d.ts +0 -37
  531. package/dist/translator/stages/join-optimizer.d.ts.map +0 -1
  532. package/dist/translator/stages/join-optimizer.js +0 -93
  533. package/dist/translator/stages/join-optimizer.js.map +0 -1
  534. package/dist/translator/stages/limit-stage.d.ts +0 -7
  535. package/dist/translator/stages/limit-stage.d.ts.map +0 -1
  536. package/dist/translator/stages/limit-stage.js +0 -11
  537. package/dist/translator/stages/limit-stage.js.map +0 -1
  538. package/dist/translator/stages/lookup-stage.d.ts +0 -7
  539. package/dist/translator/stages/lookup-stage.d.ts.map +0 -1
  540. package/dist/translator/stages/lookup-stage.js +0 -73
  541. package/dist/translator/stages/lookup-stage.js.map +0 -1
  542. package/dist/translator/stages/match-stage.d.ts +0 -7
  543. package/dist/translator/stages/match-stage.d.ts.map +0 -1
  544. package/dist/translator/stages/match-stage.js +0 -14
  545. package/dist/translator/stages/match-stage.js.map +0 -1
  546. package/dist/translator/stages/optimizer.d.ts +0 -15
  547. package/dist/translator/stages/optimizer.d.ts.map +0 -1
  548. package/dist/translator/stages/optimizer.js +0 -249
  549. package/dist/translator/stages/optimizer.js.map +0 -1
  550. package/dist/translator/stages/parallel-facet.d.ts +0 -47
  551. package/dist/translator/stages/parallel-facet.d.ts.map +0 -1
  552. package/dist/translator/stages/parallel-facet.js +0 -57
  553. package/dist/translator/stages/parallel-facet.js.map +0 -1
  554. package/dist/translator/stages/project-stage.d.ts +0 -8
  555. package/dist/translator/stages/project-stage.d.ts.map +0 -1
  556. package/dist/translator/stages/project-stage.js +0 -145
  557. package/dist/translator/stages/project-stage.js.map +0 -1
  558. package/dist/translator/stages/search-stage.d.ts +0 -60
  559. package/dist/translator/stages/search-stage.d.ts.map +0 -1
  560. package/dist/translator/stages/search-stage.js +0 -89
  561. package/dist/translator/stages/search-stage.js.map +0 -1
  562. package/dist/translator/stages/skip-stage.d.ts +0 -7
  563. package/dist/translator/stages/skip-stage.d.ts.map +0 -1
  564. package/dist/translator/stages/skip-stage.js +0 -11
  565. package/dist/translator/stages/skip-stage.js.map +0 -1
  566. package/dist/translator/stages/sort-stage.d.ts +0 -7
  567. package/dist/translator/stages/sort-stage.d.ts.map +0 -1
  568. package/dist/translator/stages/sort-stage.js +0 -21
  569. package/dist/translator/stages/sort-stage.js.map +0 -1
  570. package/dist/translator/stages/types.d.ts +0 -136
  571. package/dist/translator/stages/types.d.ts.map +0 -1
  572. package/dist/translator/stages/types.js +0 -5
  573. package/dist/translator/stages/types.js.map +0 -1
  574. package/dist/translator/stages/unwind-stage.d.ts +0 -7
  575. package/dist/translator/stages/unwind-stage.d.ts.map +0 -1
  576. package/dist/translator/stages/unwind-stage.js +0 -61
  577. package/dist/translator/stages/unwind-stage.js.map +0 -1
  578. package/dist/translator/stages/vector-search-stage.d.ts +0 -53
  579. package/dist/translator/stages/vector-search-stage.d.ts.map +0 -1
  580. package/dist/translator/stages/vector-search-stage.js +0 -62
  581. package/dist/translator/stages/vector-search-stage.js.map +0 -1
  582. package/dist/translator/update-translator.d.ts +0 -148
  583. package/dist/translator/update-translator.d.ts.map +0 -1
  584. package/dist/translator/update-translator.js +0 -819
  585. package/dist/translator/update-translator.js.map +0 -1
  586. package/dist/translator/vector-translator.d.ts +0 -89
  587. package/dist/translator/vector-translator.d.ts.map +0 -1
  588. package/dist/translator/vector-translator.js +0 -106
  589. package/dist/translator/vector-translator.js.map +0 -1
  590. package/dist/types/env.d.ts +0 -31
  591. package/dist/types/env.d.ts.map +0 -1
  592. package/dist/types/env.js +0 -5
  593. package/dist/types/env.js.map +0 -1
  594. package/dist/types/function.d.ts +0 -65
  595. package/dist/types/function.d.ts.map +0 -1
  596. package/dist/types/function.js +0 -5
  597. package/dist/types/function.js.map +0 -1
  598. package/dist/types/index.d.ts +0 -137
  599. package/dist/types/index.d.ts.map +0 -1
  600. package/dist/types/index.js +0 -13
  601. package/dist/types/index.js.map +0 -1
  602. package/dist/types/mongodb.d.ts +0 -258
  603. package/dist/types/mongodb.d.ts.map +0 -1
  604. package/dist/types/mongodb.js +0 -5
  605. package/dist/types/mongodb.js.map +0 -1
  606. package/dist/types/objectid.d.ts +0 -130
  607. package/dist/types/objectid.d.ts.map +0 -1
  608. package/dist/types/objectid.js +0 -314
  609. package/dist/types/objectid.js.map +0 -1
  610. package/dist/types/rpc.d.ts +0 -313
  611. package/dist/types/rpc.d.ts.map +0 -1
  612. package/dist/types/rpc.js +0 -136
  613. package/dist/types/rpc.js.map +0 -1
  614. package/dist/types/vectorize.d.ts +0 -136
  615. package/dist/types/vectorize.d.ts.map +0 -1
  616. package/dist/types/vectorize.js +0 -8
  617. package/dist/types/vectorize.js.map +0 -1
  618. package/dist/utils/sql-safety.d.ts +0 -64
  619. package/dist/utils/sql-safety.d.ts.map +0 -1
  620. package/dist/utils/sql-safety.js +0 -112
  621. package/dist/utils/sql-safety.js.map +0 -1
  622. package/dist/validation/document-validator.d.ts +0 -195
  623. package/dist/validation/document-validator.d.ts.map +0 -1
  624. package/dist/validation/document-validator.js +0 -529
  625. package/dist/validation/document-validator.js.map +0 -1
  626. package/dist/vectorize/document-serializer.d.ts +0 -119
  627. package/dist/vectorize/document-serializer.d.ts.map +0 -1
  628. package/dist/vectorize/document-serializer.js +0 -320
  629. package/dist/vectorize/document-serializer.js.map +0 -1
  630. package/dist/wire/auth/index.d.ts +0 -5
  631. package/dist/wire/auth/index.d.ts.map +0 -1
  632. package/dist/wire/auth/index.js +0 -5
  633. package/dist/wire/auth/index.js.map +0 -1
  634. package/dist/wire/auth/scram.d.ts +0 -160
  635. package/dist/wire/auth/scram.d.ts.map +0 -1
  636. package/dist/wire/auth/scram.js +0 -425
  637. package/dist/wire/auth/scram.js.map +0 -1
  638. package/dist/wire/backend/interface.d.ts +0 -168
  639. package/dist/wire/backend/interface.d.ts.map +0 -1
  640. package/dist/wire/backend/interface.js +0 -10
  641. package/dist/wire/backend/interface.js.map +0 -1
  642. package/dist/wire/backend/local-sqlite.d.ts +0 -89
  643. package/dist/wire/backend/local-sqlite.d.ts.map +0 -1
  644. package/dist/wire/backend/local-sqlite.js +0 -1002
  645. package/dist/wire/backend/local-sqlite.js.map +0 -1
  646. package/dist/wire/backend/query-router.d.ts +0 -197
  647. package/dist/wire/backend/query-router.d.ts.map +0 -1
  648. package/dist/wire/backend/query-router.js +0 -590
  649. package/dist/wire/backend/query-router.js.map +0 -1
  650. package/dist/wire/backend/validation.d.ts +0 -26
  651. package/dist/wire/backend/validation.d.ts.map +0 -1
  652. package/dist/wire/backend/validation.js +0 -79
  653. package/dist/wire/backend/validation.js.map +0 -1
  654. package/dist/wire/backend/workers-proxy.d.ts +0 -95
  655. package/dist/wire/backend/workers-proxy.d.ts.map +0 -1
  656. package/dist/wire/backend/workers-proxy.js +0 -429
  657. package/dist/wire/backend/workers-proxy.js.map +0 -1
  658. package/dist/wire/commands/admin.d.ts +0 -49
  659. package/dist/wire/commands/admin.d.ts.map +0 -1
  660. package/dist/wire/commands/admin.js +0 -272
  661. package/dist/wire/commands/admin.js.map +0 -1
  662. package/dist/wire/commands/aggregate.d.ts +0 -15
  663. package/dist/wire/commands/aggregate.d.ts.map +0 -1
  664. package/dist/wire/commands/aggregate.js +0 -98
  665. package/dist/wire/commands/aggregate.js.map +0 -1
  666. package/dist/wire/commands/auth.d.ts +0 -58
  667. package/dist/wire/commands/auth.d.ts.map +0 -1
  668. package/dist/wire/commands/auth.js +0 -158
  669. package/dist/wire/commands/auth.js.map +0 -1
  670. package/dist/wire/commands/crud.d.ts +0 -49
  671. package/dist/wire/commands/crud.d.ts.map +0 -1
  672. package/dist/wire/commands/crud.js +0 -336
  673. package/dist/wire/commands/crud.js.map +0 -1
  674. package/dist/wire/commands/hello.d.ts +0 -35
  675. package/dist/wire/commands/hello.d.ts.map +0 -1
  676. package/dist/wire/commands/hello.js +0 -204
  677. package/dist/wire/commands/hello.js.map +0 -1
  678. package/dist/wire/commands/index.d.ts +0 -24
  679. package/dist/wire/commands/index.d.ts.map +0 -1
  680. package/dist/wire/commands/index.js +0 -145
  681. package/dist/wire/commands/index.js.map +0 -1
  682. package/dist/wire/commands/router.d.ts +0 -46
  683. package/dist/wire/commands/router.d.ts.map +0 -1
  684. package/dist/wire/commands/router.js +0 -151
  685. package/dist/wire/commands/router.js.map +0 -1
  686. package/dist/wire/commands/types.d.ts +0 -51
  687. package/dist/wire/commands/types.d.ts.map +0 -1
  688. package/dist/wire/commands/types.js +0 -15
  689. package/dist/wire/commands/types.js.map +0 -1
  690. package/dist/wire/index.d.ts +0 -15
  691. package/dist/wire/index.d.ts.map +0 -1
  692. package/dist/wire/index.js +0 -19
  693. package/dist/wire/index.js.map +0 -1
  694. package/dist/wire/message.d.ts +0 -49
  695. package/dist/wire/message.d.ts.map +0 -1
  696. package/dist/wire/message.js +0 -299
  697. package/dist/wire/message.js.map +0 -1
  698. package/dist/wire/server.d.ts +0 -145
  699. package/dist/wire/server.d.ts.map +0 -1
  700. package/dist/wire/server.js +0 -284
  701. package/dist/wire/server.js.map +0 -1
  702. package/dist/wire/types.d.ts +0 -140
  703. package/dist/wire/types.d.ts.map +0 -1
  704. package/dist/wire/types.js +0 -64
  705. package/dist/wire/types.js.map +0 -1
  706. package/dist/worker.d.ts.map +0 -1
package/dist/cli/index.js CHANGED
@@ -1,219 +1,4106 @@
1
- #!/usr/bin/env bun
2
- /**
3
- * MondoDB CLI Entry Point
4
- *
5
- * Main entry point for the MondoDB command-line interface.
6
- * Provides a MongoDB-compatible database backed by SQLite or Cloudflare Workers.
7
- *
8
- * Usage:
9
- * mongo.do [options]
10
- * bun run src/cli/index.ts [options]
11
- *
12
- * @module cli
13
- */
14
- import { version } from '../../package.json';
15
- import { parseArgs, validateOptions, printHelp, printShutdownMessage, runServer, } from './server.js';
16
- // ============================================================================
17
- // ANSI Color Codes (no external dependencies)
18
- // ============================================================================
19
- const colors = {
20
- reset: '\x1b[0m',
21
- bold: '\x1b[1m',
22
- dim: '\x1b[2m',
23
- // Foreground colors
24
- red: '\x1b[31m',
25
- green: '\x1b[32m',
26
- yellow: '\x1b[33m',
27
- blue: '\x1b[34m',
28
- magenta: '\x1b[35m',
29
- cyan: '\x1b[36m',
30
- white: '\x1b[37m',
1
+ #!/usr/bin/env node
2
+ import { Database } from 'bun:sqlite';
3
+ import { ObjectId, BSON, Binary, Long } from 'bson';
4
+
5
+ var __defProp = Object.defineProperty;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
8
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
9
+ }) : x)(function(x) {
10
+ if (typeof require !== "undefined") return require.apply(this, arguments);
11
+ throw Error('Dynamic require of "' + x + '" is not supported');
12
+ });
13
+ var __esm = (fn, res) => function __init() {
14
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
31
15
  };
32
- /**
33
- * Check if stdout supports colors
34
- */
35
- function supportsColor() {
36
- // Check for NO_COLOR environment variable
37
- if (process.env.NO_COLOR !== undefined) {
38
- return false;
39
- }
40
- // Check for FORCE_COLOR environment variable
41
- if (process.env.FORCE_COLOR !== undefined) {
16
+ var __export = (target, all) => {
17
+ for (var name in all)
18
+ __defProp(target, name, { get: all[name], enumerable: true });
19
+ };
20
+
21
+ // src/utils/sql-safety.ts
22
+ function validateFieldPath(field) {
23
+ if (!field || field.length === 0) {
24
+ throw new Error("Field name cannot be empty");
25
+ }
26
+ if (field.includes("\0")) {
27
+ throw new Error("Field name cannot contain null characters");
28
+ }
29
+ if (!SAFE_FIELD_PATTERN.test(field)) {
30
+ throw new Error(
31
+ `Invalid field name: "${field}". Field names can only contain alphanumeric characters, underscores, dots, hyphens, and dollar signs.`
32
+ );
33
+ }
34
+ if (field.includes("..") || field.startsWith(".") || field.endsWith(".")) {
35
+ throw new Error(
36
+ `Invalid field path: "${field}". Field paths cannot have consecutive, leading, or trailing dots.`
37
+ );
38
+ }
39
+ return field;
40
+ }
41
+ function safeJsonPath(field) {
42
+ const validField = validateFieldPath(field);
43
+ return validField.startsWith("$") ? validField : `$.${validField}`;
44
+ }
45
+ var SAFE_FIELD_PATTERN;
46
+ var init_sql_safety = __esm({
47
+ "src/utils/sql-safety.ts"() {
48
+ SAFE_FIELD_PATTERN = /^[a-zA-Z0-9_.$-]+$/;
49
+ }
50
+ });
51
+
52
+ // src/wire/backend/validation.ts
53
+ function sanitizeDatabaseName(name) {
54
+ if (!name || typeof name !== "string") {
55
+ throw new Error("Database name must be a non-empty string");
56
+ }
57
+ if (name.includes("..") || name.includes("/") || name.includes("\\")) {
58
+ throw new Error(`Invalid database name "${name}": contains path traversal characters`);
59
+ }
60
+ if (name.includes("\0")) {
61
+ throw new Error("Invalid database name: contains null byte");
62
+ }
63
+ if (name.startsWith(".")) {
64
+ throw new Error(`Invalid database name "${name}": cannot start with a dot`);
65
+ }
66
+ if (name.length > 255) {
67
+ throw new Error(`Database name too long: ${name.length} characters (max 255)`);
68
+ }
69
+ const validNameRegex = /^[a-zA-Z0-9_-]+$/;
70
+ if (!validNameRegex.test(name)) {
71
+ throw new Error(
72
+ `Invalid database name "${name}": only alphanumeric characters, underscores, and hyphens are allowed`
73
+ );
74
+ }
75
+ return name;
76
+ }
77
+ function validateCollectionName(name) {
78
+ if (!name || typeof name !== "string") {
79
+ throw new Error("Collection name must be a non-empty string");
80
+ }
81
+ if (name.includes("\0")) {
82
+ throw new Error("Invalid collection name: contains null byte");
83
+ }
84
+ if (name.length > 255) {
85
+ throw new Error(`Collection name too long: ${name.length} characters (max 255)`);
86
+ }
87
+ const validNameRegex = /^[a-zA-Z_][a-zA-Z0-9_.-]*$/;
88
+ if (!validNameRegex.test(name)) {
89
+ throw new Error(
90
+ `Invalid collection name "${name}": must start with a letter or underscore, and contain only alphanumeric characters, underscores, hyphens, and dots`
91
+ );
92
+ }
93
+ if (name.startsWith("system.") && !["system.users", "system.indexes", "system.namespaces"].includes(name)) {
94
+ throw new Error(`Invalid collection name "${name}": cannot use reserved 'system.' prefix`);
95
+ }
96
+ return name;
97
+ }
98
+ var init_validation = __esm({
99
+ "src/wire/backend/validation.ts"() {
100
+ }
101
+ });
102
+
103
+ // src/wire/backend/local-sqlite.ts
104
+ var local_sqlite_exports = {};
105
+ __export(local_sqlite_exports, {
106
+ LocalSQLiteBackend: () => LocalSQLiteBackend,
107
+ sanitizeDatabaseName: () => sanitizeDatabaseName,
108
+ validateCollectionName: () => validateCollectionName
109
+ });
110
+ var DEFAULT_BATCH_SIZE, CURSOR_TIMEOUT_MS2, LocalSQLiteBackend;
111
+ var init_local_sqlite = __esm({
112
+ "src/wire/backend/local-sqlite.ts"() {
113
+ init_sql_safety();
114
+ init_validation();
115
+ init_validation();
116
+ DEFAULT_BATCH_SIZE = 101;
117
+ CURSOR_TIMEOUT_MS2 = 10 * 60 * 1e3;
118
+ LocalSQLiteBackend = class {
119
+ databases = /* @__PURE__ */ new Map();
120
+ cursors = /* @__PURE__ */ new Map();
121
+ nextCursorId = 1n;
122
+ dataDir;
123
+ constructor(dataDir = ".mongodo") {
124
+ this.dataDir = dataDir;
125
+ const fs = __require("fs");
126
+ if (!fs.existsSync(dataDir)) {
127
+ fs.mkdirSync(dataDir, { recursive: true });
128
+ }
129
+ setInterval(() => this.cleanupExpiredCursors(), 6e4);
130
+ }
131
+ /**
132
+ * Get or create a database connection
133
+ */
134
+ getDatabase(name) {
135
+ const safeName = sanitizeDatabaseName(name);
136
+ let db = this.databases.get(safeName);
137
+ if (!db) {
138
+ const dbPath = `${this.dataDir}/${safeName}.sqlite`;
139
+ db = new Database(dbPath);
140
+ this.initializeSchema(db);
141
+ this.databases.set(safeName, db);
142
+ }
143
+ return db;
144
+ }
145
+ /**
146
+ * Initialize the database schema
147
+ */
148
+ initializeSchema(db) {
149
+ db.exec(`
150
+ CREATE TABLE IF NOT EXISTS collections (
151
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
152
+ name TEXT NOT NULL UNIQUE,
153
+ options TEXT DEFAULT '{}'
154
+ );
155
+
156
+ CREATE TABLE IF NOT EXISTS documents (
157
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
158
+ collection_id INTEGER NOT NULL,
159
+ _id TEXT NOT NULL,
160
+ data TEXT NOT NULL DEFAULT '{}',
161
+ FOREIGN KEY (collection_id) REFERENCES collections(id) ON DELETE CASCADE,
162
+ UNIQUE(collection_id, _id)
163
+ );
164
+
165
+ CREATE INDEX IF NOT EXISTS idx_documents_id ON documents(_id);
166
+ CREATE INDEX IF NOT EXISTS idx_documents_collection_id ON documents(collection_id, _id);
167
+
168
+ CREATE TABLE IF NOT EXISTS indexes (
169
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
170
+ collection_id INTEGER NOT NULL,
171
+ name TEXT NOT NULL,
172
+ key TEXT NOT NULL,
173
+ options TEXT DEFAULT '{}',
174
+ FOREIGN KEY (collection_id) REFERENCES collections(id) ON DELETE CASCADE,
175
+ UNIQUE(collection_id, name)
176
+ );
177
+ `);
178
+ }
179
+ /**
180
+ * Get collection ID, creating collection if it doesn't exist
181
+ */
182
+ getOrCreateCollectionId(db, name) {
183
+ const safeName = validateCollectionName(name);
184
+ const existing = db.query("SELECT id FROM collections WHERE name = ?").get(safeName);
185
+ if (existing) {
186
+ return existing.id;
187
+ }
188
+ const result = db.query("INSERT INTO collections (name) VALUES (?) RETURNING id").get(safeName);
189
+ return result.id;
190
+ }
191
+ /**
192
+ * Get collection ID or null if not found
193
+ */
194
+ getCollectionId(db, name) {
195
+ const safeName = validateCollectionName(name);
196
+ const result = db.query("SELECT id FROM collections WHERE name = ?").get(safeName);
197
+ return result?.id ?? null;
198
+ }
199
+ // ============ Database Operations ============
200
+ async listDatabases() {
201
+ const fs = __require("fs");
202
+ const path = __require("path");
203
+ let files = [];
204
+ try {
205
+ files = fs.readdirSync(this.dataDir);
206
+ } catch {
207
+ }
208
+ const databases = [];
209
+ for (const file of files) {
210
+ if (file.endsWith(".sqlite")) {
211
+ const name = file.replace(".sqlite", "");
212
+ const filePath = path.join(this.dataDir, file);
213
+ const stats = fs.statSync(filePath);
214
+ databases.push({
215
+ name,
216
+ sizeOnDisk: stats.size,
217
+ empty: stats.size < 1e3
218
+ });
219
+ }
220
+ }
221
+ if (!databases.find((d) => d.name === "admin")) {
222
+ databases.unshift({ name: "admin", sizeOnDisk: 0, empty: true });
223
+ }
224
+ return databases;
225
+ }
226
+ async createDatabase(name) {
227
+ this.getDatabase(name);
228
+ }
229
+ async dropDatabase(name) {
230
+ const safeName = sanitizeDatabaseName(name);
231
+ const db = this.databases.get(safeName);
232
+ if (db) {
233
+ db.close();
234
+ this.databases.delete(safeName);
235
+ }
236
+ const fs = __require("fs");
237
+ const dbPath = `${this.dataDir}/${safeName}.sqlite`;
238
+ if (fs.existsSync(dbPath)) {
239
+ fs.unlinkSync(dbPath);
240
+ }
241
+ }
242
+ async databaseExists(name) {
243
+ const safeName = sanitizeDatabaseName(name);
244
+ const fs = __require("fs");
245
+ return fs.existsSync(`${this.dataDir}/${safeName}.sqlite`);
246
+ }
247
+ // ============ Collection Operations ============
248
+ async listCollections(dbName, filter) {
249
+ const db = this.getDatabase(dbName);
250
+ let query = "SELECT name, options FROM collections";
251
+ const params = [];
252
+ if (filter?.name && typeof filter.name === "string") {
253
+ query += " WHERE name = ?";
254
+ params.push(filter.name);
255
+ }
256
+ const rows = db.query(query).all(...params);
257
+ return rows.map((row) => ({
258
+ name: row.name,
259
+ type: "collection",
260
+ options: JSON.parse(row.options),
261
+ info: { readOnly: false }
262
+ }));
263
+ }
264
+ async createCollection(dbName, name, options) {
265
+ const safeName = validateCollectionName(name);
266
+ const db = this.getDatabase(dbName);
267
+ const optionsJson = JSON.stringify(options || {});
268
+ db.query("INSERT OR IGNORE INTO collections (name, options) VALUES (?, ?)").run(safeName, optionsJson);
269
+ }
270
+ async dropCollection(dbName, name) {
271
+ const safeName = validateCollectionName(name);
272
+ const db = this.getDatabase(dbName);
273
+ db.query("DELETE FROM collections WHERE name = ?").run(safeName);
274
+ }
275
+ async collectionExists(dbName, name) {
276
+ const safeName = validateCollectionName(name);
277
+ const db = this.getDatabase(dbName);
278
+ const result = db.query("SELECT 1 FROM collections WHERE name = ? LIMIT 1").get(safeName);
279
+ return result !== null;
280
+ }
281
+ async collStats(dbName, collection) {
282
+ const db = this.getDatabase(dbName);
283
+ const collectionId = this.getCollectionId(db, collection);
284
+ if (!collectionId) {
285
+ return {
286
+ ns: `${dbName}.${collection}`,
287
+ count: 0,
288
+ size: 0,
289
+ avgObjSize: 0,
290
+ storageSize: 0,
291
+ totalIndexSize: 0,
292
+ nindexes: 1,
293
+ indexSizes: { _id_: 0 }
294
+ };
295
+ }
296
+ const stats = db.query(`
297
+ SELECT COUNT(*) as count, COALESCE(SUM(LENGTH(data)), 0) as size
298
+ FROM documents WHERE collection_id = ?
299
+ `).get(collectionId);
300
+ return {
301
+ ns: `${dbName}.${collection}`,
302
+ count: stats.count,
303
+ size: stats.size,
304
+ avgObjSize: stats.count > 0 ? stats.size / stats.count : 0,
305
+ storageSize: stats.size,
306
+ totalIndexSize: stats.count * 50,
307
+ nindexes: 1,
308
+ indexSizes: { _id_: stats.count * 50 }
309
+ };
310
+ }
311
+ async dbStats(dbName) {
312
+ const db = this.getDatabase(dbName);
313
+ const collectionStats = db.query("SELECT COUNT(DISTINCT id) as collections FROM collections").get();
314
+ const docStats = db.query("SELECT COUNT(*) as objects, COALESCE(SUM(LENGTH(data)), 0) as dataSize FROM documents").get();
315
+ return {
316
+ db: dbName,
317
+ collections: collectionStats.collections,
318
+ views: 0,
319
+ objects: docStats.objects,
320
+ avgObjSize: docStats.objects > 0 ? docStats.dataSize / docStats.objects : 0,
321
+ dataSize: docStats.dataSize,
322
+ storageSize: docStats.dataSize,
323
+ indexes: collectionStats.collections,
324
+ indexSize: docStats.objects * 50
325
+ };
326
+ }
327
+ // ============ CRUD Operations ============
328
+ async find(dbName, collection, options) {
329
+ const db = this.getDatabase(dbName);
330
+ const collectionId = this.getCollectionId(db, collection);
331
+ if (!collectionId) {
332
+ return { documents: [], cursorId: 0n, hasMore: false };
333
+ }
334
+ let sql = "SELECT _id, data FROM documents WHERE collection_id = ?";
335
+ const params = [collectionId];
336
+ if (options.filter && Object.keys(options.filter).length > 0) {
337
+ const filterSql = this.buildFilterSql(options.filter, params);
338
+ if (filterSql) {
339
+ sql += ` AND (${filterSql})`;
340
+ }
341
+ }
342
+ if (options.sort) {
343
+ const sortClauses = [];
344
+ for (const [field, direction] of Object.entries(options.sort)) {
345
+ const dir = direction === -1 ? "DESC" : "ASC";
346
+ if (field === "_id") {
347
+ sortClauses.push(`_id ${dir}`);
348
+ } else {
349
+ const safePath = safeJsonPath(validateFieldPath(field));
350
+ sortClauses.push(`json_extract(data, '${safePath}') ${dir}`);
351
+ }
352
+ }
353
+ if (sortClauses.length > 0) {
354
+ sql += ` ORDER BY ${sortClauses.join(", ")}`;
355
+ }
356
+ }
357
+ if (options.limit && options.limit > 0) {
358
+ sql += ` LIMIT ${options.limit}`;
359
+ }
360
+ if (options.skip && options.skip > 0) {
361
+ sql += ` OFFSET ${options.skip}`;
362
+ }
363
+ const rows = db.query(sql).all(...params);
364
+ let documents = rows.map((row) => {
365
+ const doc = JSON.parse(row.data);
366
+ doc._id = this.parseId(row._id);
367
+ return doc;
368
+ });
369
+ if (options.projection) {
370
+ documents = documents.map((doc) => this.applyProjection(doc, options.projection));
371
+ }
372
+ const batchSize = options.batchSize || DEFAULT_BATCH_SIZE;
373
+ if (documents.length > batchSize) {
374
+ const cursorId = this.nextCursorId++;
375
+ this.cursors.set(cursorId, {
376
+ id: cursorId,
377
+ namespace: `${dbName}.${collection}`,
378
+ documents,
379
+ position: batchSize,
380
+ batchSize,
381
+ createdAt: Date.now()
382
+ });
383
+ return {
384
+ documents: documents.slice(0, batchSize),
385
+ cursorId,
386
+ hasMore: true
387
+ };
388
+ }
389
+ return { documents, cursorId: 0n, hasMore: false };
390
+ }
391
+ async insertOne(dbName, collection, doc) {
392
+ return this.insertMany(dbName, collection, [doc]);
393
+ }
394
+ async insertMany(dbName, collection, docs) {
395
+ const db = this.getDatabase(dbName);
396
+ const collectionId = this.getOrCreateCollectionId(db, collection);
397
+ const insertedIds = /* @__PURE__ */ new Map();
398
+ let insertedCount = 0;
399
+ const stmt = db.prepare("INSERT INTO documents (collection_id, _id, data) VALUES (?, ?, ?)");
400
+ db.transaction(() => {
401
+ for (let i = 0; i < docs.length; i++) {
402
+ const doc = { ...docs[i] };
403
+ if (!doc._id) {
404
+ doc._id = new ObjectId();
405
+ }
406
+ const idStr = this.serializeId(doc._id);
407
+ const dataJson = JSON.stringify(doc);
408
+ stmt.run(collectionId, idStr, dataJson);
409
+ insertedIds.set(i, doc._id);
410
+ insertedCount++;
411
+ }
412
+ })();
413
+ return { acknowledged: true, insertedIds, insertedCount };
414
+ }
415
+ async updateOne(dbName, collection, filter, update, options) {
416
+ const db = this.getDatabase(dbName);
417
+ const collectionId = this.getCollectionId(db, collection);
418
+ if (!collectionId && !options?.upsert) {
419
+ return { acknowledged: true, matchedCount: 0, modifiedCount: 0, upsertedCount: 0 };
420
+ }
421
+ let sql = "SELECT id, _id, data FROM documents WHERE collection_id = ?";
422
+ const params = [collectionId || 0];
423
+ const filterSql = this.buildFilterSql(filter, params);
424
+ if (filterSql) {
425
+ sql += ` AND (${filterSql})`;
426
+ }
427
+ sql += " LIMIT 1";
428
+ const row = db.query(sql).get(...params);
429
+ if (!row) {
430
+ if (options?.upsert) {
431
+ const cid = this.getOrCreateCollectionId(db, collection);
432
+ const newDoc = { ...filter };
433
+ const updatedDoc2 = this.applyUpdate(newDoc, update);
434
+ if (!updatedDoc2._id) {
435
+ updatedDoc2._id = new ObjectId();
436
+ }
437
+ const idStr = this.serializeId(updatedDoc2._id);
438
+ db.query("INSERT INTO documents (collection_id, _id, data) VALUES (?, ?, ?)").run(
439
+ cid,
440
+ idStr,
441
+ JSON.stringify(updatedDoc2)
442
+ );
443
+ return {
444
+ acknowledged: true,
445
+ matchedCount: 0,
446
+ modifiedCount: 0,
447
+ upsertedId: updatedDoc2._id,
448
+ upsertedCount: 1
449
+ };
450
+ }
451
+ return { acknowledged: true, matchedCount: 0, modifiedCount: 0, upsertedCount: 0 };
452
+ }
453
+ const doc = JSON.parse(row.data);
454
+ doc._id = this.parseId(row._id);
455
+ const updatedDoc = this.applyUpdate(doc, update);
456
+ db.query("UPDATE documents SET data = ? WHERE id = ?").run(JSON.stringify(updatedDoc), row.id);
457
+ return { acknowledged: true, matchedCount: 1, modifiedCount: 1, upsertedCount: 0 };
458
+ }
459
+ async updateMany(dbName, collection, filter, update, options) {
460
+ const db = this.getDatabase(dbName);
461
+ const collectionId = this.getCollectionId(db, collection);
462
+ if (!collectionId) {
463
+ if (options?.upsert) {
464
+ const result = await this.updateOne(dbName, collection, filter, update, options);
465
+ return result;
466
+ }
467
+ return { acknowledged: true, matchedCount: 0, modifiedCount: 0, upsertedCount: 0 };
468
+ }
469
+ let sql = "SELECT id, _id, data FROM documents WHERE collection_id = ?";
470
+ const params = [collectionId];
471
+ const filterSql = this.buildFilterSql(filter, params);
472
+ if (filterSql) {
473
+ sql += ` AND (${filterSql})`;
474
+ }
475
+ const rows = db.query(sql).all(...params);
476
+ if (rows.length === 0 && options?.upsert) {
477
+ const result = await this.updateOne(dbName, collection, filter, update, options);
478
+ return result;
479
+ }
480
+ const stmt = db.prepare("UPDATE documents SET data = ? WHERE id = ?");
481
+ db.transaction(() => {
482
+ for (const row of rows) {
483
+ const doc = JSON.parse(row.data);
484
+ doc._id = this.parseId(row._id);
485
+ const updatedDoc = this.applyUpdate(doc, update);
486
+ stmt.run(JSON.stringify(updatedDoc), row.id);
487
+ }
488
+ })();
489
+ return {
490
+ acknowledged: true,
491
+ matchedCount: rows.length,
492
+ modifiedCount: rows.length,
493
+ upsertedCount: 0
494
+ };
495
+ }
496
+ async deleteOne(dbName, collection, filter) {
497
+ const db = this.getDatabase(dbName);
498
+ const collectionId = this.getCollectionId(db, collection);
499
+ if (!collectionId) {
500
+ return { acknowledged: true, deletedCount: 0 };
501
+ }
502
+ let sql = "SELECT id FROM documents WHERE collection_id = ?";
503
+ const params = [collectionId];
504
+ const filterSql = this.buildFilterSql(filter, params);
505
+ if (filterSql) {
506
+ sql += ` AND (${filterSql})`;
507
+ }
508
+ sql += " LIMIT 1";
509
+ const row = db.query(sql).get(...params);
510
+ if (!row) {
511
+ return { acknowledged: true, deletedCount: 0 };
512
+ }
513
+ db.query("DELETE FROM documents WHERE id = ?").run(row.id);
514
+ return { acknowledged: true, deletedCount: 1 };
515
+ }
516
+ async deleteMany(dbName, collection, filter) {
517
+ const db = this.getDatabase(dbName);
518
+ const collectionId = this.getCollectionId(db, collection);
519
+ if (!collectionId) {
520
+ return { acknowledged: true, deletedCount: 0 };
521
+ }
522
+ let sql = "DELETE FROM documents WHERE collection_id = ?";
523
+ const params = [collectionId];
524
+ const filterSql = this.buildFilterSql(filter, params);
525
+ if (filterSql) {
526
+ sql += ` AND (${filterSql})`;
527
+ }
528
+ const result = db.query(sql).run(...params);
529
+ return { acknowledged: true, deletedCount: result.changes };
530
+ }
531
+ // ============ Count & Distinct ============
532
+ async count(dbName, collection, query) {
533
+ const db = this.getDatabase(dbName);
534
+ const collectionId = this.getCollectionId(db, collection);
535
+ if (!collectionId) {
536
+ return 0;
537
+ }
538
+ let sql = "SELECT COUNT(*) as count FROM documents WHERE collection_id = ?";
539
+ const params = [collectionId];
540
+ if (query && Object.keys(query).length > 0) {
541
+ const filterSql = this.buildFilterSql(query, params);
542
+ if (filterSql) {
543
+ sql += ` AND (${filterSql})`;
544
+ }
545
+ }
546
+ const result = db.query(sql).get(...params);
547
+ return result.count;
548
+ }
549
+ async distinct(dbName, collection, field, query) {
550
+ const db = this.getDatabase(dbName);
551
+ const collectionId = this.getCollectionId(db, collection);
552
+ if (!collectionId) {
553
+ return [];
554
+ }
555
+ let sql;
556
+ if (field === "_id") {
557
+ sql = "SELECT DISTINCT _id as value FROM documents WHERE collection_id = ?";
558
+ } else {
559
+ const safePath = safeJsonPath(validateFieldPath(field));
560
+ sql = `SELECT DISTINCT json_extract(data, '${safePath}') as value FROM documents WHERE collection_id = ?`;
561
+ }
562
+ const params = [collectionId];
563
+ if (query && Object.keys(query).length > 0) {
564
+ const filterSql = this.buildFilterSql(query, params);
565
+ if (filterSql) {
566
+ sql += ` AND (${filterSql})`;
567
+ }
568
+ }
569
+ const rows = db.query(sql).all(...params);
570
+ return rows.map((r) => r.value).filter((v) => v !== null);
571
+ }
572
+ // ============ Aggregation ============
573
+ async aggregate(dbName, collection, pipeline, options) {
574
+ const db = this.getDatabase(dbName);
575
+ const collectionId = this.getCollectionId(db, collection);
576
+ if (!collectionId) {
577
+ return { documents: [], cursorId: 0n, hasMore: false };
578
+ }
579
+ const rows = db.query("SELECT _id, data FROM documents WHERE collection_id = ?").all(collectionId);
580
+ let documents = rows.map((row) => {
581
+ const doc = JSON.parse(row.data);
582
+ doc._id = this.parseId(row._id);
583
+ return doc;
584
+ });
585
+ documents = this.applyPipeline(documents, pipeline);
586
+ const batchSize = options?.batchSize || DEFAULT_BATCH_SIZE;
587
+ if (documents.length > batchSize) {
588
+ const cursorId = this.nextCursorId++;
589
+ this.cursors.set(cursorId, {
590
+ id: cursorId,
591
+ namespace: `${dbName}.${collection}`,
592
+ documents,
593
+ position: batchSize,
594
+ batchSize,
595
+ createdAt: Date.now()
596
+ });
597
+ return {
598
+ documents: documents.slice(0, batchSize),
599
+ cursorId,
600
+ hasMore: true
601
+ };
602
+ }
603
+ return { documents, cursorId: 0n, hasMore: false };
604
+ }
605
+ // ============ Index Operations ============
606
+ async listIndexes(dbName, collection) {
607
+ const db = this.getDatabase(dbName);
608
+ const collectionId = this.getCollectionId(db, collection);
609
+ const indexes = [{ v: 2, key: { _id: 1 }, name: "_id_" }];
610
+ if (!collectionId) {
611
+ return indexes;
612
+ }
613
+ const rows = db.query("SELECT name, key, options FROM indexes WHERE collection_id = ?").all(collectionId);
614
+ for (const row of rows) {
615
+ indexes.push({
616
+ v: 2,
617
+ key: JSON.parse(row.key),
618
+ name: row.name,
619
+ ...JSON.parse(row.options)
620
+ });
621
+ }
622
+ return indexes;
623
+ }
624
+ async createIndexes(dbName, collection, indexes) {
625
+ const db = this.getDatabase(dbName);
626
+ const collectionId = this.getOrCreateCollectionId(db, collection);
627
+ const createdNames = [];
628
+ const stmt = db.prepare(
629
+ "INSERT OR IGNORE INTO indexes (collection_id, name, key, options) VALUES (?, ?, ?, ?)"
630
+ );
631
+ for (const spec of indexes) {
632
+ const name = spec.name || this.generateIndexName(spec.key);
633
+ const keyJson = JSON.stringify(spec.key);
634
+ const options = {};
635
+ if (spec.unique) options.unique = true;
636
+ if (spec.sparse) options.sparse = true;
637
+ const result = stmt.run(collectionId, name, keyJson, JSON.stringify(options));
638
+ if (result.changes > 0) {
639
+ createdNames.push(name);
640
+ }
641
+ }
642
+ return createdNames;
643
+ }
644
+ async dropIndex(dbName, collection, indexName) {
645
+ const db = this.getDatabase(dbName);
646
+ const collectionId = this.getCollectionId(db, collection);
647
+ if (collectionId) {
648
+ db.query("DELETE FROM indexes WHERE collection_id = ? AND name = ?").run(
649
+ collectionId,
650
+ indexName
651
+ );
652
+ }
653
+ }
654
+ async dropIndexes(dbName, collection) {
655
+ const db = this.getDatabase(dbName);
656
+ const collectionId = this.getCollectionId(db, collection);
657
+ if (collectionId) {
658
+ db.query("DELETE FROM indexes WHERE collection_id = ? AND name != '_id_'").run(collectionId);
659
+ }
660
+ }
661
+ // ============ Cursor Management ============
662
+ createCursor(state) {
663
+ this.cursors.set(state.id, state);
664
+ }
665
+ getCursor(id) {
666
+ return this.cursors.get(id);
667
+ }
668
+ advanceCursor(id, count) {
669
+ const cursor = this.cursors.get(id);
670
+ if (!cursor) {
671
+ return [];
672
+ }
673
+ const start = cursor.position;
674
+ const end = Math.min(start + count, cursor.documents.length);
675
+ cursor.position = end;
676
+ return cursor.documents.slice(start, end);
677
+ }
678
+ closeCursor(id) {
679
+ return this.cursors.delete(id);
680
+ }
681
+ cleanupExpiredCursors() {
682
+ const now = Date.now();
683
+ for (const [id, cursor] of this.cursors) {
684
+ if (now - cursor.createdAt > CURSOR_TIMEOUT_MS2) {
685
+ this.cursors.delete(id);
686
+ }
687
+ }
688
+ }
689
+ // ============ Helper Methods ============
690
+ serializeId(id) {
691
+ if (id instanceof ObjectId) {
692
+ return id.toHexString();
693
+ }
694
+ if (typeof id === "object" && id !== null && "$oid" in id) {
695
+ return id.$oid;
696
+ }
697
+ return String(id);
698
+ }
699
+ parseId(idStr) {
700
+ if (/^[0-9a-f]{24}$/i.test(idStr)) {
701
+ return new ObjectId(idStr);
702
+ }
703
+ return idStr;
704
+ }
705
+ generateIndexName(key) {
706
+ return Object.entries(key).map(([field, dir]) => `${field}_${dir}`).join("_");
707
+ }
708
+ /**
709
+ * Build simplified SQL filter from MongoDB query
710
+ */
711
+ buildFilterSql(filter, params) {
712
+ const conditions = [];
713
+ for (const [key, value] of Object.entries(filter)) {
714
+ if (key === "_id") {
715
+ params.push(this.serializeId(value));
716
+ conditions.push("_id = ?");
717
+ } else if (key === "$and" && Array.isArray(value)) {
718
+ const subConditions = value.map((sub) => this.buildFilterSql(sub, params)).filter(Boolean);
719
+ if (subConditions.length > 0) {
720
+ conditions.push(`(${subConditions.join(" AND ")})`);
721
+ }
722
+ } else if (key === "$or" && Array.isArray(value)) {
723
+ const subConditions = value.map((sub) => this.buildFilterSql(sub, params)).filter(Boolean);
724
+ if (subConditions.length > 0) {
725
+ conditions.push(`(${subConditions.join(" OR ")})`);
726
+ }
727
+ } else if (typeof value === "object" && value !== null && !Array.isArray(value)) {
728
+ const safePath = safeJsonPath(validateFieldPath(key));
729
+ for (const [op, opValue] of Object.entries(value)) {
730
+ const path = `json_extract(data, '${safePath}')`;
731
+ switch (op) {
732
+ case "$eq":
733
+ params.push(opValue);
734
+ conditions.push(`${path} = ?`);
735
+ break;
736
+ case "$ne":
737
+ params.push(opValue);
738
+ conditions.push(`${path} != ?`);
739
+ break;
740
+ case "$gt":
741
+ params.push(opValue);
742
+ conditions.push(`${path} > ?`);
743
+ break;
744
+ case "$gte":
745
+ params.push(opValue);
746
+ conditions.push(`${path} >= ?`);
747
+ break;
748
+ case "$lt":
749
+ params.push(opValue);
750
+ conditions.push(`${path} < ?`);
751
+ break;
752
+ case "$lte":
753
+ params.push(opValue);
754
+ conditions.push(`${path} <= ?`);
755
+ break;
756
+ case "$exists":
757
+ conditions.push(opValue ? `${path} IS NOT NULL` : `${path} IS NULL`);
758
+ break;
759
+ case "$in":
760
+ if (Array.isArray(opValue) && opValue.length > 0) {
761
+ const placeholders = opValue.map(() => "?").join(", ");
762
+ params.push(...opValue);
763
+ conditions.push(`${path} IN (${placeholders})`);
764
+ }
765
+ break;
766
+ }
767
+ }
768
+ } else {
769
+ const safePath = safeJsonPath(validateFieldPath(key));
770
+ const sqlValue = typeof value === "boolean" ? value ? 1 : 0 : value;
771
+ params.push(sqlValue);
772
+ conditions.push(`json_extract(data, '${safePath}') = ?`);
773
+ }
774
+ }
775
+ return conditions.join(" AND ");
776
+ }
777
+ applyProjection(doc, projection) {
778
+ const includeFields = /* @__PURE__ */ new Set();
779
+ const excludeFields = /* @__PURE__ */ new Set();
780
+ let isInclusion = false;
781
+ for (const [field, value] of Object.entries(projection)) {
782
+ if (field === "_id" && (value === 0 || value === false)) {
783
+ excludeFields.add("_id");
784
+ continue;
785
+ }
786
+ if (value === 1 || value === true) {
787
+ includeFields.add(field);
788
+ isInclusion = true;
789
+ } else if (value === 0 || value === false) {
790
+ excludeFields.add(field);
791
+ }
792
+ }
793
+ if (isInclusion) {
794
+ const result2 = {};
795
+ if (!excludeFields.has("_id")) {
796
+ result2._id = doc._id;
797
+ }
798
+ for (const field of includeFields) {
799
+ if (field in doc) {
800
+ result2[field] = doc[field];
801
+ }
802
+ }
803
+ return result2;
804
+ }
805
+ const result = { ...doc };
806
+ for (const field of excludeFields) {
807
+ delete result[field];
808
+ }
809
+ return result;
810
+ }
811
+ applyUpdate(doc, update) {
812
+ const result = { ...doc };
813
+ if (update.$set) {
814
+ Object.assign(result, update.$set);
815
+ }
816
+ if (update.$unset) {
817
+ for (const key of Object.keys(update.$unset)) {
818
+ delete result[key];
819
+ }
820
+ }
821
+ if (update.$inc) {
822
+ for (const [key, value] of Object.entries(update.$inc)) {
823
+ const current = result[key] || 0;
824
+ result[key] = current + value;
825
+ }
826
+ }
827
+ if (update.$push) {
828
+ for (const [key, value] of Object.entries(update.$push)) {
829
+ const current = result[key] || [];
830
+ if (typeof value === "object" && value !== null && "$each" in value) {
831
+ current.push(...value.$each);
832
+ } else {
833
+ current.push(value);
834
+ }
835
+ result[key] = current;
836
+ }
837
+ }
838
+ const hasOperators = Object.keys(update).some((k) => k.startsWith("$"));
839
+ if (!hasOperators) {
840
+ const id = result._id;
841
+ for (const key of Object.keys(result)) {
842
+ if (key !== "_id") delete result[key];
843
+ }
844
+ Object.assign(result, update);
845
+ result._id = id;
846
+ }
847
+ return result;
848
+ }
849
+ applyPipeline(documents, pipeline) {
850
+ let result = [...documents];
851
+ for (const stage of pipeline) {
852
+ const entry = Object.entries(stage)[0];
853
+ if (!entry) continue;
854
+ const [op, value] = entry;
855
+ switch (op) {
856
+ case "$match":
857
+ result = result.filter((doc) => this.matchDocument(doc, value));
858
+ break;
859
+ case "$project":
860
+ result = result.map((doc) => this.applyProjection(doc, value));
861
+ break;
862
+ case "$sort":
863
+ result = this.sortDocuments(result, value);
864
+ break;
865
+ case "$limit":
866
+ result = result.slice(0, value);
867
+ break;
868
+ case "$skip":
869
+ result = result.slice(value);
870
+ break;
871
+ case "$count":
872
+ result = [{ [value]: result.length }];
873
+ break;
874
+ case "$sample":
875
+ const size = value.size || 100;
876
+ result = this.shuffleArray(result).slice(0, size);
877
+ break;
878
+ case "$group":
879
+ result = this.groupDocuments(result, value);
880
+ break;
881
+ }
882
+ }
883
+ return result;
884
+ }
885
+ matchDocument(doc, query) {
886
+ for (const [key, value] of Object.entries(query)) {
887
+ if (key === "$and") {
888
+ if (!value.every((q) => this.matchDocument(doc, q))) {
889
+ return false;
890
+ }
891
+ continue;
892
+ }
893
+ if (key === "$or") {
894
+ if (!value.some((q) => this.matchDocument(doc, q))) {
895
+ return false;
896
+ }
897
+ continue;
898
+ }
899
+ const docValue = doc[key];
900
+ if (typeof value === "object" && value !== null && !Array.isArray(value)) {
901
+ for (const [op, opValue] of Object.entries(value)) {
902
+ switch (op) {
903
+ case "$eq":
904
+ if (docValue !== opValue) return false;
905
+ break;
906
+ case "$ne":
907
+ if (docValue === opValue) return false;
908
+ break;
909
+ case "$gt":
910
+ if (!(docValue > opValue)) return false;
911
+ break;
912
+ case "$gte":
913
+ if (!(docValue >= opValue)) return false;
914
+ break;
915
+ case "$lt":
916
+ if (!(docValue < opValue)) return false;
917
+ break;
918
+ case "$lte":
919
+ if (!(docValue <= opValue)) return false;
920
+ break;
921
+ case "$in":
922
+ if (!opValue.includes(docValue)) return false;
923
+ break;
924
+ case "$exists":
925
+ if (opValue && docValue === void 0 || !opValue && docValue !== void 0)
926
+ return false;
927
+ break;
928
+ }
929
+ }
930
+ } else {
931
+ if (docValue !== value) return false;
932
+ }
933
+ }
42
934
  return true;
935
+ }
936
+ sortDocuments(documents, sort) {
937
+ return [...documents].sort((a, b) => {
938
+ for (const [field, direction] of Object.entries(sort)) {
939
+ const aVal = a[field];
940
+ const bVal = b[field];
941
+ const dir = direction === -1 ? -1 : 1;
942
+ if (aVal === bVal) continue;
943
+ if (aVal === void 0 || aVal === null) return dir;
944
+ if (bVal === void 0 || bVal === null) return -dir;
945
+ if (aVal < bVal) return -dir;
946
+ if (aVal > bVal) return dir;
947
+ }
948
+ return 0;
949
+ });
950
+ }
951
+ shuffleArray(array) {
952
+ const result = [...array];
953
+ for (let i = result.length - 1; i > 0; i--) {
954
+ const j = Math.floor(Math.random() * (i + 1));
955
+ const temp = result[i];
956
+ result[i] = result[j];
957
+ result[j] = temp;
958
+ }
959
+ return result;
960
+ }
961
+ groupDocuments(documents, groupSpec) {
962
+ const groups = /* @__PURE__ */ new Map();
963
+ const idSpec = groupSpec._id;
964
+ for (const doc of documents) {
965
+ let groupKey;
966
+ if (idSpec === null) {
967
+ groupKey = "__all__";
968
+ } else if (typeof idSpec === "string" && idSpec.startsWith("$")) {
969
+ groupKey = JSON.stringify(doc[idSpec.slice(1)]);
970
+ } else {
971
+ groupKey = JSON.stringify(idSpec);
972
+ }
973
+ if (!groups.has(groupKey)) {
974
+ groups.set(groupKey, []);
975
+ }
976
+ groups.get(groupKey).push(doc);
977
+ }
978
+ const result = [];
979
+ for (const [key, docs] of groups) {
980
+ const grouped = { _id: key === "__all__" ? null : JSON.parse(key) };
981
+ for (const [field, spec] of Object.entries(groupSpec)) {
982
+ if (field === "_id") continue;
983
+ if (typeof spec === "object" && spec !== null) {
984
+ const [op, value] = Object.entries(spec)[0];
985
+ const fieldPath = typeof value === "string" && value.startsWith("$") ? value.slice(1) : null;
986
+ switch (op) {
987
+ case "$sum":
988
+ if (value === 1) {
989
+ grouped[field] = docs.length;
990
+ } else if (fieldPath) {
991
+ grouped[field] = docs.reduce((sum, doc) => sum + (doc[fieldPath] || 0), 0);
992
+ }
993
+ break;
994
+ case "$avg":
995
+ if (fieldPath) {
996
+ const values = docs.map((doc) => doc[fieldPath]).filter((v) => typeof v === "number");
997
+ grouped[field] = values.length > 0 ? values.reduce((a, b) => a + b, 0) / values.length : null;
998
+ }
999
+ break;
1000
+ case "$first":
1001
+ if (fieldPath && docs.length > 0) {
1002
+ const firstDoc = docs[0];
1003
+ if (firstDoc) {
1004
+ grouped[field] = firstDoc[fieldPath];
1005
+ }
1006
+ }
1007
+ break;
1008
+ case "$last":
1009
+ if (fieldPath && docs.length > 0) {
1010
+ const lastDoc = docs[docs.length - 1];
1011
+ if (lastDoc) {
1012
+ grouped[field] = lastDoc[fieldPath];
1013
+ }
1014
+ }
1015
+ break;
1016
+ }
1017
+ }
1018
+ }
1019
+ result.push(grouped);
1020
+ }
1021
+ return result;
1022
+ }
1023
+ /**
1024
+ * Close all database connections
1025
+ */
1026
+ close() {
1027
+ for (const db of this.databases.values()) {
1028
+ db.close();
1029
+ }
1030
+ this.databases.clear();
1031
+ this.cursors.clear();
1032
+ }
1033
+ };
1034
+ }
1035
+ });
1036
+
1037
+ // src/wire/types.ts
1038
+ var OpCode, OpMsgFlags, DEFAULT_CAPABILITIES;
1039
+ var init_types = __esm({
1040
+ "src/wire/types.ts"() {
1041
+ OpCode = {
1042
+ /** Standard message format for all operations (MongoDB 3.6+) */
1043
+ OP_MSG: 2013,
1044
+ /** Compressed message wrapper */
1045
+ OP_COMPRESSED: 2012,
1046
+ /** Legacy reply to client (removed in 5.1, but still used for backwards compat) */
1047
+ OP_REPLY: 1,
1048
+ /** Legacy query (deprecated, but still used for initial handshake) */
1049
+ OP_QUERY: 2004,
1050
+ /** Legacy get more (removed in 5.1) */
1051
+ OP_GET_MORE: 2005,
1052
+ /** Legacy kill cursors (removed in 5.1) */
1053
+ OP_KILL_CURSORS: 2007
1054
+ };
1055
+ OpMsgFlags = {
1056
+ /** Message ends with CRC-32C checksum */
1057
+ CHECKSUM_PRESENT: 1 << 0,
1058
+ /** More messages follow; don't respond until bit=0 */
1059
+ MORE_TO_COME: 1 << 1,
1060
+ /** Client accepts multiple replies (exhaust cursors) */
1061
+ EXHAUST_ALLOWED: 1 << 16
1062
+ };
1063
+ DEFAULT_CAPABILITIES = {
1064
+ maxBsonObjectSize: 16 * 1024 * 1024,
1065
+ // 16 MiB
1066
+ maxMessageSizeBytes: 48 * 1024 * 1024,
1067
+ // 48 MiB
1068
+ maxWriteBatchSize: 1e5,
1069
+ minWireVersion: 0,
1070
+ maxWireVersion: 17,
1071
+ // MongoDB 6.0
1072
+ logicalSessionTimeoutMinutes: 30,
1073
+ readOnly: false
1074
+ };
1075
+ }
1076
+ });
1077
+ function parseHeader(buffer) {
1078
+ if (buffer.length < HEADER_SIZE) {
1079
+ throw new Error(`Buffer too small for header: ${buffer.length} < ${HEADER_SIZE}`);
1080
+ }
1081
+ return {
1082
+ messageLength: buffer.readInt32LE(0),
1083
+ requestID: buffer.readInt32LE(4),
1084
+ responseTo: buffer.readInt32LE(8),
1085
+ opCode: buffer.readInt32LE(12)
1086
+ };
1087
+ }
1088
+ function parseCString(buffer, offset) {
1089
+ let end = offset;
1090
+ while (end < buffer.length && buffer[end] !== 0) {
1091
+ end++;
1092
+ }
1093
+ const str = buffer.toString("utf8", offset, end);
1094
+ return [str, end + 1];
1095
+ }
1096
+ function parseBSONDocument(buffer, offset) {
1097
+ const length = buffer.readInt32LE(offset);
1098
+ const doc = BSON.deserialize(buffer.subarray(offset, offset + length));
1099
+ return [doc, offset + length];
1100
+ }
1101
+ function parseOpMsg(buffer) {
1102
+ const header = parseHeader(buffer);
1103
+ if (header.opCode !== OpCode.OP_MSG) {
1104
+ throw new Error(`Expected OP_MSG (${OpCode.OP_MSG}), got ${header.opCode}`);
1105
+ }
1106
+ let offset = HEADER_SIZE;
1107
+ const flagBits = buffer.readUInt32LE(offset);
1108
+ offset += 4;
1109
+ const hasChecksum = (flagBits & OpMsgFlags.CHECKSUM_PRESENT) !== 0;
1110
+ const messageEnd = hasChecksum ? buffer.length - 4 : buffer.length;
1111
+ const sections = [];
1112
+ while (offset < messageEnd) {
1113
+ const kind = buffer.readUInt8(offset);
1114
+ offset += 1;
1115
+ if (kind === 0) {
1116
+ const [body, newOffset] = parseBSONDocument(buffer, offset);
1117
+ sections.push({ kind: 0, body });
1118
+ offset = newOffset;
1119
+ } else if (kind === 1) {
1120
+ const sectionSize = buffer.readInt32LE(offset);
1121
+ const sectionEnd = offset + sectionSize;
1122
+ offset += 4;
1123
+ const [identifier, docStart] = parseCString(buffer, offset);
1124
+ offset = docStart;
1125
+ const documents = [];
1126
+ while (offset < sectionEnd) {
1127
+ const [doc, newOffset] = parseBSONDocument(buffer, offset);
1128
+ documents.push(doc);
1129
+ offset = newOffset;
1130
+ }
1131
+ sections.push({ kind: 1, identifier, documents });
1132
+ } else {
1133
+ throw new Error(`Unknown section kind: ${kind}`);
1134
+ }
1135
+ }
1136
+ if (hasChecksum) {
1137
+ return { header, flagBits, sections, checksum: buffer.readUInt32LE(messageEnd) };
1138
+ }
1139
+ return { header, flagBits, sections };
1140
+ }
1141
+ function parseOpQuery(buffer) {
1142
+ const header = parseHeader(buffer);
1143
+ if (header.opCode !== OpCode.OP_QUERY) {
1144
+ throw new Error(`Expected OP_QUERY (${OpCode.OP_QUERY}), got ${header.opCode}`);
1145
+ }
1146
+ let offset = HEADER_SIZE;
1147
+ const flags = buffer.readInt32LE(offset);
1148
+ offset += 4;
1149
+ const [fullCollectionName, afterName] = parseCString(buffer, offset);
1150
+ offset = afterName;
1151
+ const numberToSkip = buffer.readInt32LE(offset);
1152
+ offset += 4;
1153
+ const numberToReturn = buffer.readInt32LE(offset);
1154
+ offset += 4;
1155
+ const [query, afterQuery] = parseBSONDocument(buffer, offset);
1156
+ offset = afterQuery;
1157
+ if (offset < buffer.length) {
1158
+ const [returnFieldsSelector] = parseBSONDocument(buffer, offset);
1159
+ return {
1160
+ header,
1161
+ flags,
1162
+ fullCollectionName,
1163
+ numberToSkip,
1164
+ numberToReturn,
1165
+ query,
1166
+ returnFieldsSelector
1167
+ };
1168
+ }
1169
+ return {
1170
+ header,
1171
+ flags,
1172
+ fullCollectionName,
1173
+ numberToSkip,
1174
+ numberToReturn,
1175
+ query
1176
+ };
1177
+ }
1178
+ function serializeOpMsg(requestID, responseTo, body, additionalSections) {
1179
+ const bodyBson = Buffer.from(BSON.serialize(body));
1180
+ let sectionsSize = 1 + bodyBson.length;
1181
+ const serializedSections = [];
1182
+ const messageLength = HEADER_SIZE + 4 + sectionsSize;
1183
+ const buffer = Buffer.allocUnsafe(messageLength);
1184
+ let offset = 0;
1185
+ buffer.writeInt32LE(messageLength, offset);
1186
+ offset += 4;
1187
+ buffer.writeInt32LE(requestID, offset);
1188
+ offset += 4;
1189
+ buffer.writeInt32LE(responseTo, offset);
1190
+ offset += 4;
1191
+ buffer.writeInt32LE(OpCode.OP_MSG, offset);
1192
+ offset += 4;
1193
+ buffer.writeUInt32LE(0, offset);
1194
+ offset += 4;
1195
+ buffer.writeUInt8(0, offset);
1196
+ offset += 1;
1197
+ bodyBson.copy(buffer, offset);
1198
+ offset += bodyBson.length;
1199
+ for (const sectionBuf of serializedSections) {
1200
+ sectionBuf.copy(buffer, offset);
1201
+ offset += sectionBuf.length;
1202
+ }
1203
+ return buffer;
1204
+ }
1205
+ function serializeOpReply(requestID, responseTo, documents, cursorID = 0n, responseFlags = 0) {
1206
+ const docBuffers = documents.map((doc) => Buffer.from(BSON.serialize(doc)));
1207
+ const docsSize = docBuffers.reduce((sum, buf) => sum + buf.length, 0);
1208
+ const messageLength = HEADER_SIZE + 20 + docsSize;
1209
+ const buffer = Buffer.allocUnsafe(messageLength);
1210
+ let offset = 0;
1211
+ buffer.writeInt32LE(messageLength, offset);
1212
+ offset += 4;
1213
+ buffer.writeInt32LE(requestID, offset);
1214
+ offset += 4;
1215
+ buffer.writeInt32LE(responseTo, offset);
1216
+ offset += 4;
1217
+ buffer.writeInt32LE(OpCode.OP_REPLY, offset);
1218
+ offset += 4;
1219
+ buffer.writeInt32LE(responseFlags, offset);
1220
+ offset += 4;
1221
+ buffer.writeBigInt64LE(cursorID, offset);
1222
+ offset += 8;
1223
+ buffer.writeInt32LE(0, offset);
1224
+ offset += 4;
1225
+ buffer.writeInt32LE(documents.length, offset);
1226
+ offset += 4;
1227
+ for (const docBuf of docBuffers) {
1228
+ docBuf.copy(buffer, offset);
1229
+ offset += docBuf.length;
1230
+ }
1231
+ return buffer;
1232
+ }
1233
+ function parseMessage(buffer) {
1234
+ const header = parseHeader(buffer);
1235
+ switch (header.opCode) {
1236
+ case OpCode.OP_MSG:
1237
+ return parseOpMsg(buffer);
1238
+ case OpCode.OP_QUERY:
1239
+ return parseOpQuery(buffer);
1240
+ default:
1241
+ throw new Error(`Unsupported opcode: ${header.opCode}`);
1242
+ }
1243
+ }
1244
+ function extractCommand(message) {
1245
+ if ("sections" in message) {
1246
+ const section0 = message.sections.find((s) => s.kind === 0);
1247
+ if (!section0) {
1248
+ throw new Error("OP_MSG missing section 0 (body)");
1249
+ }
1250
+ const command = section0.body;
1251
+ const db = command.$db;
1252
+ if (!db) {
1253
+ throw new Error("OP_MSG command missing $db field");
1254
+ }
1255
+ const documentSequences = /* @__PURE__ */ new Map();
1256
+ for (const section of message.sections) {
1257
+ if (section.kind === 1) {
1258
+ documentSequences.set(section.identifier, section.documents);
1259
+ }
43
1260
  }
44
- // Check if running in a TTY
45
- return process.stdout.isTTY ?? false;
1261
+ return { db, command, documentSequences };
1262
+ } else {
1263
+ const parts = message.fullCollectionName.split(".");
1264
+ const db = parts[0] || "admin";
1265
+ const command = message.query;
1266
+ return { db, command, documentSequences: /* @__PURE__ */ new Map() };
1267
+ }
1268
+ }
1269
+ var HEADER_SIZE;
1270
+ var init_message = __esm({
1271
+ "src/wire/message.ts"() {
1272
+ init_types();
1273
+ HEADER_SIZE = 16;
1274
+ }
1275
+ });
1276
+
1277
+ // src/types/rpc.ts
1278
+ function getErrorCodeName(code) {
1279
+ for (const [name, value] of Object.entries(ErrorCode)) {
1280
+ if (value === code) {
1281
+ return name.split("_").map((word) => word.charAt(0) + word.slice(1).toLowerCase()).join("");
1282
+ }
1283
+ }
1284
+ return "UnknownError";
1285
+ }
1286
+ function successResponse(data = {}) {
1287
+ return { ok: 1, ...data };
46
1288
  }
47
- const useColors = supportsColor();
48
- /**
49
- * Apply color to text if colors are supported
50
- */
1289
+ function errorResponse(code, errmsg, codeName) {
1290
+ return {
1291
+ ok: 0,
1292
+ code,
1293
+ codeName: codeName || getErrorCodeName(code),
1294
+ errmsg
1295
+ };
1296
+ }
1297
+ var ErrorCode;
1298
+ var init_rpc = __esm({
1299
+ "src/types/rpc.ts"() {
1300
+ ErrorCode = {
1301
+ OK: 0,
1302
+ INTERNAL_ERROR: 1,
1303
+ BAD_VALUE: 2,
1304
+ NO_SUCH_KEY: 4,
1305
+ GRAPH_CONTAINS_CYCLE: 5,
1306
+ HOST_UNREACHABLE: 6,
1307
+ HOST_NOT_FOUND: 7,
1308
+ UNKNOWN_ERROR: 8,
1309
+ FAILED_TO_PARSE: 9,
1310
+ CANNOT_MUTATE_OBJECT: 10,
1311
+ USER_NOT_FOUND: 11,
1312
+ UNSUPPORTED_FORMAT: 12,
1313
+ UNAUTHORIZED: 13,
1314
+ TYPE_MISMATCH: 14,
1315
+ OVERFLOW: 15,
1316
+ INVALID_LENGTH: 16,
1317
+ PROTOCOL_ERROR: 17,
1318
+ AUTHENTICATION_FAILED: 18,
1319
+ CANNOT_REUSE_OBJECT: 19,
1320
+ ILLEGAL_OPERATION: 20,
1321
+ EMPTY_ARRAY_OPERATION: 21,
1322
+ INVALID_BSON: 22,
1323
+ ALREADY_INITIALIZED: 23,
1324
+ LOCK_TIMEOUT: 24,
1325
+ REMOTE_VALIDATION_ERROR: 25,
1326
+ NAMESPACE_NOT_FOUND: 26,
1327
+ INDEX_NOT_FOUND: 27,
1328
+ PATH_NOT_VIABLE: 28,
1329
+ NON_EXISTENT_PATH: 29,
1330
+ INVALID_PATH: 30,
1331
+ ROLE_NOT_FOUND: 31,
1332
+ ROLES_NOT_RELATED: 32,
1333
+ PRIVILEGE_NOT_FOUND: 33,
1334
+ CANNOT_BACKFILL_ARRAY: 34,
1335
+ COMMAND_NOT_FOUND: 59,
1336
+ DATABASE_NOT_FOUND: 60,
1337
+ LOCATION_ERROR: 16755,
1338
+ DUPLICATE_KEY: 11e3
1339
+ };
1340
+ }
1341
+ });
1342
+
1343
+ // src/wire/commands/types.ts
1344
+ function successResponse2(data = {}) {
1345
+ return successResponse(data);
1346
+ }
1347
+ function errorResponse2(code, errmsg, codeName) {
1348
+ return errorResponse(code, errmsg, codeName);
1349
+ }
1350
+ var init_types2 = __esm({
1351
+ "src/wire/commands/types.ts"() {
1352
+ init_rpc();
1353
+ }
1354
+ });
1355
+ var HelloCommand, PingCommand, BuildInfoCommand, HostInfoCommand, WhatsmyuriCommand, GetLogCommand, GetParameterCommand, GetCmdLineOptsCommand;
1356
+ var init_hello = __esm({
1357
+ "src/wire/commands/hello.ts"() {
1358
+ init_types2();
1359
+ init_types();
1360
+ HelloCommand = class {
1361
+ processId = new ObjectId();
1362
+ counter = 0n;
1363
+ async execute(command, context) {
1364
+ const now = /* @__PURE__ */ new Date();
1365
+ const response = {
1366
+ // Primary fields
1367
+ ismaster: true,
1368
+ isWritablePrimary: true,
1369
+ // Topology version (changes when server state changes)
1370
+ topologyVersion: {
1371
+ processId: this.processId,
1372
+ counter: Long.fromBigInt(this.counter++)
1373
+ },
1374
+ // Size limits
1375
+ maxBsonObjectSize: DEFAULT_CAPABILITIES.maxBsonObjectSize,
1376
+ maxMessageSizeBytes: DEFAULT_CAPABILITIES.maxMessageSizeBytes,
1377
+ maxWriteBatchSize: DEFAULT_CAPABILITIES.maxWriteBatchSize,
1378
+ // Time
1379
+ localTime: now,
1380
+ // Session support
1381
+ logicalSessionTimeoutMinutes: DEFAULT_CAPABILITIES.logicalSessionTimeoutMinutes,
1382
+ // Connection info
1383
+ connectionId: context.connectionId,
1384
+ // Wire version (MongoDB 6.0 = 17)
1385
+ minWireVersion: DEFAULT_CAPABILITIES.minWireVersion,
1386
+ maxWireVersion: DEFAULT_CAPABILITIES.maxWireVersion,
1387
+ // Not read-only
1388
+ readOnly: DEFAULT_CAPABILITIES.readOnly,
1389
+ // Success
1390
+ ok: 1
1391
+ };
1392
+ if (command.hello || command.helloOk) {
1393
+ response.helloOk = true;
1394
+ }
1395
+ if (command.saslSupportedMechs) {
1396
+ response.saslSupportedMechs = ["SCRAM-SHA-256", "SCRAM-SHA-1"];
1397
+ }
1398
+ if (command.compression && Array.isArray(command.compression)) {
1399
+ response.compression = [];
1400
+ }
1401
+ if (command.client) ;
1402
+ return { response };
1403
+ }
1404
+ };
1405
+ PingCommand = class {
1406
+ async execute(_command, _context) {
1407
+ return { response: successResponse2() };
1408
+ }
1409
+ };
1410
+ BuildInfoCommand = class {
1411
+ async execute(_command, _context) {
1412
+ const response = successResponse2({
1413
+ version: "6.0.0-mongo.do",
1414
+ gitVersion: "mongo.do-0.1.0",
1415
+ modules: [],
1416
+ allocator: "system",
1417
+ javascriptEngine: "none",
1418
+ sysInfo: "mongo.do-on-workers",
1419
+ versionArray: [6, 0, 0, 0],
1420
+ openssl: {
1421
+ running: "not-applicable",
1422
+ compiled: "not-applicable"
1423
+ },
1424
+ buildEnvironment: {
1425
+ target_os: "cloudflare-workers",
1426
+ target_arch: "wasm"
1427
+ },
1428
+ bits: 64,
1429
+ debug: false,
1430
+ maxBsonObjectSize: DEFAULT_CAPABILITIES.maxBsonObjectSize,
1431
+ storageEngines: ["sqlite"]
1432
+ });
1433
+ return { response };
1434
+ }
1435
+ };
1436
+ HostInfoCommand = class {
1437
+ async execute(_command, _context) {
1438
+ const now = /* @__PURE__ */ new Date();
1439
+ const response = successResponse2({
1440
+ system: {
1441
+ currentTime: now,
1442
+ hostname: "mongo.do-server",
1443
+ cpuAddrSize: 64,
1444
+ memSizeMB: 512,
1445
+ memLimitMB: 512,
1446
+ numCores: 1,
1447
+ cpuArch: "wasm",
1448
+ numaEnabled: false
1449
+ },
1450
+ os: {
1451
+ type: "cloudflare-workers",
1452
+ name: "MondoDB",
1453
+ version: "0.1.0"
1454
+ },
1455
+ extra: {
1456
+ note: "Running on Cloudflare Workers Durable Objects"
1457
+ }
1458
+ });
1459
+ return { response };
1460
+ }
1461
+ };
1462
+ WhatsmyuriCommand = class {
1463
+ async execute(_command, _context) {
1464
+ return {
1465
+ response: successResponse2({
1466
+ you: "127.0.0.1:0"
1467
+ })
1468
+ };
1469
+ }
1470
+ };
1471
+ GetLogCommand = class {
1472
+ async execute(command, _context) {
1473
+ const logType = command.getLog;
1474
+ if (logType === "*") {
1475
+ return {
1476
+ response: successResponse2({
1477
+ names: ["global", "startupWarnings"]
1478
+ })
1479
+ };
1480
+ }
1481
+ if (logType === "startupWarnings") {
1482
+ return {
1483
+ response: successResponse2({
1484
+ totalLinesWritten: 1,
1485
+ log: [
1486
+ JSON.stringify({
1487
+ t: { $date: (/* @__PURE__ */ new Date()).toISOString() },
1488
+ s: "I",
1489
+ c: "STORAGE",
1490
+ msg: "MondoDB using SQLite storage engine"
1491
+ })
1492
+ ]
1493
+ })
1494
+ };
1495
+ }
1496
+ return {
1497
+ response: successResponse2({
1498
+ totalLinesWritten: 0,
1499
+ log: []
1500
+ })
1501
+ };
1502
+ }
1503
+ };
1504
+ GetParameterCommand = class {
1505
+ async execute(command, _context) {
1506
+ const param = command.getParameter;
1507
+ const parameters = {
1508
+ featureCompatibilityVersion: { version: "6.0" },
1509
+ authenticationMechanisms: ["SCRAM-SHA-256", "SCRAM-SHA-1"]
1510
+ };
1511
+ if (param === "*") {
1512
+ return { response: successResponse2(parameters) };
1513
+ }
1514
+ if (typeof param === "string" && param in parameters) {
1515
+ return {
1516
+ response: successResponse2({
1517
+ [param]: parameters[param]
1518
+ })
1519
+ };
1520
+ }
1521
+ return { response: successResponse2({}) };
1522
+ }
1523
+ };
1524
+ GetCmdLineOptsCommand = class {
1525
+ async execute(_command, _context) {
1526
+ return {
1527
+ response: successResponse2({
1528
+ argv: ["mongo.do-server"],
1529
+ parsed: {
1530
+ storage: {
1531
+ engine: "sqlite"
1532
+ }
1533
+ }
1534
+ })
1535
+ };
1536
+ }
1537
+ };
1538
+ }
1539
+ });
1540
+
1541
+ // src/wire/commands/admin.ts
1542
+ var ListDatabasesCommand, ListCollectionsCommand, CreateCommand, DropCommand, DropDatabaseCommand, CollStatsCommand, DbStatsCommand, ServerStatusCommand;
1543
+ var init_admin = __esm({
1544
+ "src/wire/commands/admin.ts"() {
1545
+ init_types2();
1546
+ ListDatabasesCommand = class {
1547
+ constructor(backend) {
1548
+ this.backend = backend;
1549
+ }
1550
+ async execute(command, _context) {
1551
+ const databases = await this.backend.listDatabases();
1552
+ const nameOnly = command.nameOnly === true;
1553
+ let filteredDbs = databases;
1554
+ if (command.filter && typeof command.filter === "object") {
1555
+ const filter = command.filter;
1556
+ if (filter.name) {
1557
+ if (typeof filter.name === "string") {
1558
+ filteredDbs = databases.filter((db) => db.name === filter.name);
1559
+ } else if (filter.name.$regex) {
1560
+ const regex = new RegExp(filter.name.$regex, filter.name.$options);
1561
+ filteredDbs = databases.filter((db) => regex.test(db.name));
1562
+ }
1563
+ }
1564
+ }
1565
+ const totalSize = filteredDbs.reduce((sum, db) => sum + db.sizeOnDisk, 0);
1566
+ if (nameOnly) {
1567
+ return {
1568
+ response: successResponse2({
1569
+ databases: filteredDbs.map((db) => ({ name: db.name }))
1570
+ })
1571
+ };
1572
+ }
1573
+ return {
1574
+ response: successResponse2({
1575
+ databases: filteredDbs,
1576
+ totalSize,
1577
+ totalSizeMb: totalSize / (1024 * 1024)
1578
+ })
1579
+ };
1580
+ }
1581
+ };
1582
+ ListCollectionsCommand = class {
1583
+ constructor(backend) {
1584
+ this.backend = backend;
1585
+ }
1586
+ async execute(command, context) {
1587
+ const db = context.db;
1588
+ const filter = command.filter;
1589
+ const nameOnly = command.nameOnly === true;
1590
+ const collections = await this.backend.listCollections(db, filter);
1591
+ if (nameOnly) {
1592
+ return {
1593
+ response: successResponse2({
1594
+ cursor: {
1595
+ id: 0n,
1596
+ ns: `${db}.$cmd.listCollections`,
1597
+ firstBatch: collections.map((c) => ({ name: c.name, type: c.type }))
1598
+ }
1599
+ })
1600
+ };
1601
+ }
1602
+ return {
1603
+ response: successResponse2({
1604
+ cursor: {
1605
+ id: 0n,
1606
+ ns: `${db}.$cmd.listCollections`,
1607
+ firstBatch: collections
1608
+ }
1609
+ })
1610
+ };
1611
+ }
1612
+ };
1613
+ CreateCommand = class {
1614
+ constructor(backend) {
1615
+ this.backend = backend;
1616
+ }
1617
+ async execute(command, context) {
1618
+ const collectionName = command.create;
1619
+ if (!collectionName || typeof collectionName !== "string") {
1620
+ return {
1621
+ response: errorResponse2(ErrorCode.BAD_VALUE, "create requires a string collection name")
1622
+ };
1623
+ }
1624
+ const options = {};
1625
+ if (command.capped) options.capped = command.capped;
1626
+ if (command.size) options.size = command.size;
1627
+ if (command.max) options.max = command.max;
1628
+ if (command.validator) options.validator = command.validator;
1629
+ if (command.validationLevel) options.validationLevel = command.validationLevel;
1630
+ if (command.validationAction) options.validationAction = command.validationAction;
1631
+ await this.backend.createCollection(context.db, collectionName, options);
1632
+ return { response: successResponse2() };
1633
+ }
1634
+ };
1635
+ DropCommand = class {
1636
+ constructor(backend) {
1637
+ this.backend = backend;
1638
+ }
1639
+ async execute(command, context) {
1640
+ const collectionName = command.drop;
1641
+ if (!collectionName || typeof collectionName !== "string") {
1642
+ return {
1643
+ response: errorResponse2(ErrorCode.BAD_VALUE, "drop requires a string collection name")
1644
+ };
1645
+ }
1646
+ const exists = await this.backend.collectionExists(context.db, collectionName);
1647
+ if (!exists) {
1648
+ return {
1649
+ response: errorResponse2(
1650
+ ErrorCode.NAMESPACE_NOT_FOUND,
1651
+ `ns not found: ${context.db}.${collectionName}`
1652
+ )
1653
+ };
1654
+ }
1655
+ await this.backend.dropCollection(context.db, collectionName);
1656
+ return {
1657
+ response: successResponse2({
1658
+ nIndexesWas: 1,
1659
+ ns: `${context.db}.${collectionName}`
1660
+ })
1661
+ };
1662
+ }
1663
+ };
1664
+ DropDatabaseCommand = class {
1665
+ constructor(backend) {
1666
+ this.backend = backend;
1667
+ }
1668
+ async execute(_command, context) {
1669
+ await this.backend.dropDatabase(context.db);
1670
+ return {
1671
+ response: successResponse2({
1672
+ dropped: context.db
1673
+ })
1674
+ };
1675
+ }
1676
+ };
1677
+ CollStatsCommand = class {
1678
+ constructor(backend) {
1679
+ this.backend = backend;
1680
+ }
1681
+ async execute(command, context) {
1682
+ const collectionName = command.collStats;
1683
+ if (!collectionName || typeof collectionName !== "string") {
1684
+ return {
1685
+ response: errorResponse2(ErrorCode.BAD_VALUE, "collStats requires a collection name")
1686
+ };
1687
+ }
1688
+ const exists = await this.backend.collectionExists(context.db, collectionName);
1689
+ if (!exists) {
1690
+ return {
1691
+ response: errorResponse2(
1692
+ ErrorCode.NAMESPACE_NOT_FOUND,
1693
+ `Collection [${context.db}.${collectionName}] not found`
1694
+ )
1695
+ };
1696
+ }
1697
+ const stats = await this.backend.collStats(context.db, collectionName);
1698
+ return {
1699
+ response: successResponse2({
1700
+ ...stats,
1701
+ wiredTiger: {},
1702
+ // Empty for SQLite
1703
+ indexDetails: {},
1704
+ scaleFactor: 1
1705
+ })
1706
+ };
1707
+ }
1708
+ };
1709
+ DbStatsCommand = class {
1710
+ constructor(backend) {
1711
+ this.backend = backend;
1712
+ }
1713
+ async execute(command, context) {
1714
+ const scale = typeof command.scale === "number" ? command.scale : 1;
1715
+ const stats = await this.backend.dbStats(context.db);
1716
+ return {
1717
+ response: successResponse2({
1718
+ db: stats.db,
1719
+ collections: stats.collections,
1720
+ views: stats.views,
1721
+ objects: stats.objects,
1722
+ avgObjSize: stats.avgObjSize,
1723
+ dataSize: stats.dataSize / scale,
1724
+ storageSize: stats.storageSize / scale,
1725
+ indexes: stats.indexes,
1726
+ indexSize: stats.indexSize / scale,
1727
+ totalSize: (stats.dataSize + stats.indexSize) / scale,
1728
+ scaleFactor: scale,
1729
+ fsUsedSize: stats.storageSize / scale,
1730
+ fsTotalSize: stats.storageSize * 10 / scale
1731
+ // Estimate
1732
+ })
1733
+ };
1734
+ }
1735
+ };
1736
+ ServerStatusCommand = class {
1737
+ startTime = /* @__PURE__ */ new Date();
1738
+ constructor(_backend) {
1739
+ }
1740
+ async execute(_command, _context) {
1741
+ const now = /* @__PURE__ */ new Date();
1742
+ const uptimeSeconds = Math.floor((now.getTime() - this.startTime.getTime()) / 1e3);
1743
+ return {
1744
+ response: successResponse2({
1745
+ host: "mongo.do-server",
1746
+ version: "6.0.0-mongo.do",
1747
+ process: "mongo.do-server",
1748
+ pid: process.pid || 1,
1749
+ uptime: uptimeSeconds,
1750
+ uptimeMillis: uptimeSeconds * 1e3,
1751
+ uptimeEstimate: uptimeSeconds,
1752
+ localTime: now,
1753
+ connections: {
1754
+ current: 1,
1755
+ available: 100,
1756
+ totalCreated: 1,
1757
+ active: 1
1758
+ },
1759
+ opcounters: {
1760
+ insert: 0,
1761
+ query: 0,
1762
+ update: 0,
1763
+ delete: 0,
1764
+ getmore: 0,
1765
+ command: 0
1766
+ },
1767
+ mem: {
1768
+ bits: 64,
1769
+ resident: 50,
1770
+ virtual: 100,
1771
+ supported: true
1772
+ },
1773
+ storageEngine: {
1774
+ name: "sqlite",
1775
+ supportsCommittedReads: true,
1776
+ oldestRequiredTimestampForCrashRecovery: null,
1777
+ supportsPendingDrops: false,
1778
+ dropPendingIdents: 0,
1779
+ supportsSnapshotReadConcern: true,
1780
+ readOnly: false,
1781
+ persistent: true,
1782
+ backupCursorOpen: false
1783
+ },
1784
+ asserts: {
1785
+ regular: 0,
1786
+ warning: 0,
1787
+ msg: 0,
1788
+ user: 0,
1789
+ tripwire: 0,
1790
+ rollovers: 0
1791
+ },
1792
+ network: {
1793
+ bytesIn: 0,
1794
+ bytesOut: 0,
1795
+ numRequests: 0
1796
+ }
1797
+ })
1798
+ };
1799
+ }
1800
+ };
1801
+ }
1802
+ });
1803
+ var FindCommand, InsertCommand, UpdateCommand, DeleteCommand, CountCommand, DistinctCommand, GetMoreCommand, KillCursorsCommand;
1804
+ var init_crud = __esm({
1805
+ "src/wire/commands/crud.ts"() {
1806
+ init_types2();
1807
+ FindCommand = class {
1808
+ constructor(backend) {
1809
+ this.backend = backend;
1810
+ }
1811
+ async execute(command, context) {
1812
+ const collection = command.find;
1813
+ if (!collection || typeof collection !== "string") {
1814
+ return {
1815
+ response: errorResponse2(ErrorCode.BAD_VALUE, "find requires a collection name")
1816
+ };
1817
+ }
1818
+ const options = {
1819
+ filter: command.filter,
1820
+ projection: command.projection,
1821
+ sort: command.sort,
1822
+ limit: command.limit,
1823
+ skip: command.skip,
1824
+ batchSize: command.batchSize || 101,
1825
+ hint: command.hint,
1826
+ collation: command.collation,
1827
+ allowDiskUse: command.allowDiskUse
1828
+ };
1829
+ if (command.singleBatch === true) {
1830
+ options.batchSize = options.limit || 1e6;
1831
+ }
1832
+ const result = await this.backend.find(context.db, collection, options);
1833
+ return {
1834
+ response: successResponse2({
1835
+ cursor: {
1836
+ id: Long.fromBigInt(result.cursorId),
1837
+ ns: `${context.db}.${collection}`,
1838
+ firstBatch: result.documents
1839
+ }
1840
+ })
1841
+ };
1842
+ }
1843
+ };
1844
+ InsertCommand = class {
1845
+ constructor(backend) {
1846
+ this.backend = backend;
1847
+ }
1848
+ async execute(command, context) {
1849
+ const collection = command.insert;
1850
+ if (!collection || typeof collection !== "string") {
1851
+ return {
1852
+ response: errorResponse2(ErrorCode.BAD_VALUE, "insert requires a collection name")
1853
+ };
1854
+ }
1855
+ let documents = command.documents;
1856
+ if (!documents && context.documentSequences.has("documents")) {
1857
+ documents = context.documentSequences.get("documents");
1858
+ }
1859
+ if (!documents || !Array.isArray(documents) || documents.length === 0) {
1860
+ return {
1861
+ response: errorResponse2(ErrorCode.BAD_VALUE, "insert requires documents array")
1862
+ };
1863
+ }
1864
+ const ordered = command.ordered !== false;
1865
+ try {
1866
+ const result = await this.backend.insertMany(context.db, collection, documents);
1867
+ return {
1868
+ response: successResponse2({
1869
+ n: result.insertedCount
1870
+ })
1871
+ };
1872
+ } catch (error) {
1873
+ if (ordered) {
1874
+ return {
1875
+ response: errorResponse2(
1876
+ ErrorCode.INTERNAL_ERROR,
1877
+ error instanceof Error ? error.message : "Insert failed"
1878
+ )
1879
+ };
1880
+ }
1881
+ throw error;
1882
+ }
1883
+ }
1884
+ };
1885
+ UpdateCommand = class {
1886
+ constructor(backend) {
1887
+ this.backend = backend;
1888
+ }
1889
+ async execute(command, context) {
1890
+ const collection = command.update;
1891
+ if (!collection || typeof collection !== "string") {
1892
+ return {
1893
+ response: errorResponse2(ErrorCode.BAD_VALUE, "update requires a collection name")
1894
+ };
1895
+ }
1896
+ let updates = command.updates;
1897
+ if (!updates && context.documentSequences.has("updates")) {
1898
+ updates = context.documentSequences.get("updates");
1899
+ }
1900
+ if (!updates || !Array.isArray(updates) || updates.length === 0) {
1901
+ return {
1902
+ response: errorResponse2(ErrorCode.BAD_VALUE, "update requires updates array")
1903
+ };
1904
+ }
1905
+ let totalMatched = 0;
1906
+ let totalModified = 0;
1907
+ let upserted = [];
1908
+ for (let i = 0; i < updates.length; i++) {
1909
+ const op = updates[i];
1910
+ const filter = op?.q;
1911
+ const update = op?.u;
1912
+ const multi = op?.multi === true;
1913
+ const upsert = op?.upsert === true;
1914
+ const arrayFilters = op?.arrayFilters;
1915
+ const result = multi ? await this.backend.updateMany(context.db, collection, filter, update, {
1916
+ upsert,
1917
+ arrayFilters
1918
+ }) : await this.backend.updateOne(context.db, collection, filter, update, {
1919
+ upsert,
1920
+ arrayFilters
1921
+ });
1922
+ totalMatched += result.matchedCount;
1923
+ totalModified += result.modifiedCount;
1924
+ if (result.upsertedId !== void 0) {
1925
+ upserted.push({ index: i, _id: result.upsertedId });
1926
+ }
1927
+ }
1928
+ const response = {
1929
+ n: totalMatched,
1930
+ nModified: totalModified,
1931
+ ok: 1
1932
+ };
1933
+ if (upserted.length > 0) {
1934
+ response.upserted = upserted;
1935
+ }
1936
+ return { response };
1937
+ }
1938
+ };
1939
+ DeleteCommand = class {
1940
+ constructor(backend) {
1941
+ this.backend = backend;
1942
+ }
1943
+ async execute(command, context) {
1944
+ const collection = command.delete;
1945
+ if (!collection || typeof collection !== "string") {
1946
+ return {
1947
+ response: errorResponse2(ErrorCode.BAD_VALUE, "delete requires a collection name")
1948
+ };
1949
+ }
1950
+ let deletes = command.deletes;
1951
+ if (!deletes && context.documentSequences.has("deletes")) {
1952
+ deletes = context.documentSequences.get("deletes");
1953
+ }
1954
+ if (!deletes || !Array.isArray(deletes) || deletes.length === 0) {
1955
+ return {
1956
+ response: errorResponse2(ErrorCode.BAD_VALUE, "delete requires deletes array")
1957
+ };
1958
+ }
1959
+ let totalDeleted = 0;
1960
+ for (const op of deletes) {
1961
+ const filter = op.q;
1962
+ const limit = op.limit;
1963
+ const result = limit === 0 || limit === void 0 ? await this.backend.deleteMany(context.db, collection, filter) : await this.backend.deleteOne(context.db, collection, filter);
1964
+ totalDeleted += result.deletedCount;
1965
+ }
1966
+ return {
1967
+ response: successResponse2({
1968
+ n: totalDeleted
1969
+ })
1970
+ };
1971
+ }
1972
+ };
1973
+ CountCommand = class {
1974
+ constructor(backend) {
1975
+ this.backend = backend;
1976
+ }
1977
+ async execute(command, context) {
1978
+ const collection = command.count;
1979
+ if (!collection || typeof collection !== "string") {
1980
+ return {
1981
+ response: errorResponse2(ErrorCode.BAD_VALUE, "count requires a collection name")
1982
+ };
1983
+ }
1984
+ const query = command.query;
1985
+ const count = await this.backend.count(context.db, collection, query);
1986
+ let adjustedCount = count;
1987
+ if (command.skip && typeof command.skip === "number") {
1988
+ adjustedCount = Math.max(0, adjustedCount - command.skip);
1989
+ }
1990
+ if (command.limit && typeof command.limit === "number" && command.limit > 0) {
1991
+ adjustedCount = Math.min(adjustedCount, command.limit);
1992
+ }
1993
+ return {
1994
+ response: successResponse2({
1995
+ n: adjustedCount
1996
+ })
1997
+ };
1998
+ }
1999
+ };
2000
+ DistinctCommand = class {
2001
+ constructor(backend) {
2002
+ this.backend = backend;
2003
+ }
2004
+ async execute(command, context) {
2005
+ const collection = command.distinct;
2006
+ if (!collection || typeof collection !== "string") {
2007
+ return {
2008
+ response: errorResponse2(ErrorCode.BAD_VALUE, "distinct requires a collection name")
2009
+ };
2010
+ }
2011
+ const key = command.key;
2012
+ if (!key || typeof key !== "string") {
2013
+ return {
2014
+ response: errorResponse2(ErrorCode.BAD_VALUE, "distinct requires a key field")
2015
+ };
2016
+ }
2017
+ const query = command.query;
2018
+ const values = await this.backend.distinct(context.db, collection, key, query);
2019
+ return {
2020
+ response: successResponse2({
2021
+ values
2022
+ })
2023
+ };
2024
+ }
2025
+ };
2026
+ GetMoreCommand = class {
2027
+ constructor(backend) {
2028
+ this.backend = backend;
2029
+ }
2030
+ async execute(command, context) {
2031
+ const cursorId = command.getMore;
2032
+ const collection = command.collection;
2033
+ const batchSize = command.batchSize || 101;
2034
+ if (cursorId === void 0) {
2035
+ return {
2036
+ response: errorResponse2(ErrorCode.BAD_VALUE, "getMore requires a cursor id")
2037
+ };
2038
+ }
2039
+ let cursorBigInt;
2040
+ if (typeof cursorId === "bigint") {
2041
+ cursorBigInt = cursorId;
2042
+ } else if (cursorId instanceof Long) {
2043
+ cursorBigInt = cursorId.toBigInt();
2044
+ } else {
2045
+ cursorBigInt = BigInt(cursorId);
2046
+ }
2047
+ const cursor = this.backend.getCursor(cursorBigInt);
2048
+ if (!cursor) {
2049
+ return {
2050
+ response: errorResponse2(
2051
+ ErrorCode.NAMESPACE_NOT_FOUND,
2052
+ `cursor id ${cursorId} not found`
2053
+ )
2054
+ };
2055
+ }
2056
+ const documents = this.backend.advanceCursor(cursorBigInt, batchSize);
2057
+ const updatedCursor = this.backend.getCursor(cursorBigInt);
2058
+ const hasMore = updatedCursor ? updatedCursor.position < updatedCursor.documents.length : false;
2059
+ if (!hasMore) {
2060
+ this.backend.closeCursor(cursorBigInt);
2061
+ }
2062
+ return {
2063
+ response: successResponse2({
2064
+ cursor: {
2065
+ id: hasMore ? Long.fromBigInt(cursorBigInt) : Long.ZERO,
2066
+ ns: `${context.db}.${collection}`,
2067
+ nextBatch: documents
2068
+ }
2069
+ })
2070
+ };
2071
+ }
2072
+ };
2073
+ KillCursorsCommand = class {
2074
+ constructor(backend) {
2075
+ this.backend = backend;
2076
+ }
2077
+ async execute(command, _context) {
2078
+ const cursors = command.cursors;
2079
+ if (!cursors || !Array.isArray(cursors)) {
2080
+ return {
2081
+ response: errorResponse2(ErrorCode.BAD_VALUE, "killCursors requires cursors array")
2082
+ };
2083
+ }
2084
+ const cursorsKilled = [];
2085
+ const cursorsNotFound = [];
2086
+ const cursorsAlive = [];
2087
+ const cursorsUnknown = [];
2088
+ for (const cursorId of cursors) {
2089
+ let cursorBigInt;
2090
+ if (typeof cursorId === "bigint") {
2091
+ cursorBigInt = cursorId;
2092
+ } else if (cursorId instanceof Long) {
2093
+ cursorBigInt = cursorId.toBigInt();
2094
+ } else {
2095
+ cursorBigInt = BigInt(cursorId);
2096
+ }
2097
+ const killed = this.backend.closeCursor(cursorBigInt);
2098
+ const longId = Long.fromBigInt(cursorBigInt);
2099
+ if (killed) {
2100
+ cursorsKilled.push(longId);
2101
+ } else {
2102
+ cursorsNotFound.push(longId);
2103
+ }
2104
+ }
2105
+ return {
2106
+ response: successResponse2({
2107
+ cursorsKilled,
2108
+ cursorsNotFound,
2109
+ cursorsAlive,
2110
+ cursorsUnknown
2111
+ })
2112
+ };
2113
+ }
2114
+ };
2115
+ }
2116
+ });
2117
+ var AggregateCommand;
2118
+ var init_aggregate = __esm({
2119
+ "src/wire/commands/aggregate.ts"() {
2120
+ init_types2();
2121
+ AggregateCommand = class {
2122
+ constructor(backend) {
2123
+ this.backend = backend;
2124
+ }
2125
+ async execute(command, context) {
2126
+ const collection = command.aggregate;
2127
+ if (!collection || typeof collection !== "string") {
2128
+ return {
2129
+ response: errorResponse2(ErrorCode.BAD_VALUE, "aggregate requires a collection name")
2130
+ };
2131
+ }
2132
+ const pipeline = command.pipeline;
2133
+ if (!pipeline || !Array.isArray(pipeline)) {
2134
+ return {
2135
+ response: errorResponse2(ErrorCode.BAD_VALUE, "aggregate requires a pipeline array")
2136
+ };
2137
+ }
2138
+ if (collection === "1" || collection === 1) {
2139
+ return this.handleDatabaseAggregation(pipeline, context);
2140
+ }
2141
+ const batchSize = command.cursor?.batchSize || 101;
2142
+ const allowDiskUse = command.allowDiskUse;
2143
+ const lastStage = pipeline[pipeline.length - 1];
2144
+ const hasOutputStage = lastStage && ("$out" in lastStage || "$merge" in lastStage);
2145
+ try {
2146
+ const result = await this.backend.aggregate(context.db, collection, pipeline, {
2147
+ batchSize,
2148
+ allowDiskUse
2149
+ });
2150
+ if (hasOutputStage) {
2151
+ return {
2152
+ response: successResponse2()
2153
+ };
2154
+ }
2155
+ return {
2156
+ response: successResponse2({
2157
+ cursor: {
2158
+ id: Long.fromBigInt(result.cursorId),
2159
+ ns: `${context.db}.${collection}`,
2160
+ firstBatch: result.documents
2161
+ }
2162
+ })
2163
+ };
2164
+ } catch (error) {
2165
+ return {
2166
+ response: errorResponse2(
2167
+ ErrorCode.INTERNAL_ERROR,
2168
+ error instanceof Error ? error.message : "Aggregation failed"
2169
+ )
2170
+ };
2171
+ }
2172
+ }
2173
+ async handleDatabaseAggregation(pipeline, context) {
2174
+ const firstStage = pipeline[0];
2175
+ if (firstStage && "$listLocalSessions" in firstStage) {
2176
+ return {
2177
+ response: successResponse2({
2178
+ cursor: {
2179
+ id: Long.ZERO,
2180
+ ns: `${context.db}.$cmd.aggregate`,
2181
+ firstBatch: []
2182
+ }
2183
+ })
2184
+ };
2185
+ }
2186
+ if (firstStage && "$currentOp" in firstStage) {
2187
+ return {
2188
+ response: successResponse2({
2189
+ cursor: {
2190
+ id: Long.ZERO,
2191
+ ns: `${context.db}.$cmd.aggregate`,
2192
+ firstBatch: []
2193
+ }
2194
+ })
2195
+ };
2196
+ }
2197
+ return {
2198
+ response: errorResponse2(
2199
+ ErrorCode.COMMAND_NOT_FOUND,
2200
+ "Database-level aggregation not supported"
2201
+ )
2202
+ };
2203
+ }
2204
+ };
2205
+ }
2206
+ });
2207
+ var ListIndexesCommand, CreateIndexesCommand, DropIndexesCommand;
2208
+ var init_commands = __esm({
2209
+ "src/wire/commands/index.ts"() {
2210
+ init_types2();
2211
+ ListIndexesCommand = class {
2212
+ constructor(backend) {
2213
+ this.backend = backend;
2214
+ }
2215
+ async execute(command, context) {
2216
+ const collection = command.listIndexes;
2217
+ if (!collection || typeof collection !== "string") {
2218
+ return {
2219
+ response: errorResponse2(ErrorCode.BAD_VALUE, "listIndexes requires a collection name")
2220
+ };
2221
+ }
2222
+ const exists = await this.backend.collectionExists(context.db, collection);
2223
+ if (!exists) {
2224
+ return {
2225
+ response: errorResponse2(
2226
+ ErrorCode.NAMESPACE_NOT_FOUND,
2227
+ `ns not found: ${context.db}.${collection}`
2228
+ )
2229
+ };
2230
+ }
2231
+ const indexes = await this.backend.listIndexes(context.db, collection);
2232
+ return {
2233
+ response: successResponse2({
2234
+ cursor: {
2235
+ id: Long.ZERO,
2236
+ ns: `${context.db}.${collection}`,
2237
+ firstBatch: indexes
2238
+ }
2239
+ })
2240
+ };
2241
+ }
2242
+ };
2243
+ CreateIndexesCommand = class {
2244
+ constructor(backend) {
2245
+ this.backend = backend;
2246
+ }
2247
+ async execute(command, context) {
2248
+ const collection = command.createIndexes;
2249
+ if (!collection || typeof collection !== "string") {
2250
+ return {
2251
+ response: errorResponse2(ErrorCode.BAD_VALUE, "createIndexes requires a collection name")
2252
+ };
2253
+ }
2254
+ const indexes = command.indexes;
2255
+ if (!indexes || !Array.isArray(indexes) || indexes.length === 0) {
2256
+ return {
2257
+ response: errorResponse2(ErrorCode.BAD_VALUE, "createIndexes requires indexes array")
2258
+ };
2259
+ }
2260
+ const indexSpecs = indexes.map((idx) => ({
2261
+ key: idx.key,
2262
+ name: idx.name,
2263
+ unique: idx.unique,
2264
+ sparse: idx.sparse,
2265
+ background: idx.background,
2266
+ expireAfterSeconds: idx.expireAfterSeconds,
2267
+ partialFilterExpression: idx.partialFilterExpression
2268
+ }));
2269
+ let existingIndexes = [];
2270
+ try {
2271
+ const existing = await this.backend.listIndexes(context.db, collection);
2272
+ existingIndexes = existing.map((idx) => idx.name);
2273
+ } catch {
2274
+ }
2275
+ const createdNames = await this.backend.createIndexes(context.db, collection, indexSpecs);
2276
+ const numIndexesBefore = existingIndexes.length;
2277
+ const numIndexesAfter = numIndexesBefore + createdNames.length;
2278
+ return {
2279
+ response: successResponse2({
2280
+ numIndexesBefore,
2281
+ numIndexesAfter,
2282
+ createdCollectionAutomatically: false,
2283
+ note: createdNames.length > 0 ? void 0 : "all indexes already exist"
2284
+ })
2285
+ };
2286
+ }
2287
+ };
2288
+ DropIndexesCommand = class {
2289
+ constructor(backend) {
2290
+ this.backend = backend;
2291
+ }
2292
+ async execute(command, context) {
2293
+ const collection = command.dropIndexes;
2294
+ if (!collection || typeof collection !== "string") {
2295
+ return {
2296
+ response: errorResponse2(ErrorCode.BAD_VALUE, "dropIndexes requires a collection name")
2297
+ };
2298
+ }
2299
+ const index = command.index;
2300
+ if (index === "*") {
2301
+ await this.backend.dropIndexes(context.db, collection);
2302
+ return {
2303
+ response: successResponse2({
2304
+ msg: "non-_id indexes dropped"
2305
+ })
2306
+ };
2307
+ }
2308
+ if (typeof index === "string") {
2309
+ if (index === "_id_") {
2310
+ return {
2311
+ response: errorResponse2(
2312
+ ErrorCode.ILLEGAL_OPERATION,
2313
+ "cannot drop _id index"
2314
+ )
2315
+ };
2316
+ }
2317
+ await this.backend.dropIndex(context.db, collection, index);
2318
+ return {
2319
+ response: successResponse2({
2320
+ nIndexesWas: 1
2321
+ })
2322
+ };
2323
+ }
2324
+ if (Array.isArray(index)) {
2325
+ for (const name of index) {
2326
+ if (name === "_id_") continue;
2327
+ await this.backend.dropIndex(context.db, collection, name);
2328
+ }
2329
+ return { response: successResponse2() };
2330
+ }
2331
+ if (typeof index === "object") {
2332
+ return {
2333
+ response: errorResponse2(
2334
+ ErrorCode.BAD_VALUE,
2335
+ "dropping index by key specification not yet supported"
2336
+ )
2337
+ };
2338
+ }
2339
+ return {
2340
+ response: errorResponse2(ErrorCode.BAD_VALUE, "invalid index specification")
2341
+ };
2342
+ }
2343
+ };
2344
+ }
2345
+ });
2346
+ function requiresAuthentication(commandName) {
2347
+ return !UNAUTHENTICATED_COMMANDS.has(commandName);
2348
+ }
2349
+ var SaslStartCommand, SaslContinueCommand, AuthenticateCommand, LogoutCommand, UNAUTHENTICATED_COMMANDS;
2350
+ var init_auth = __esm({
2351
+ "src/wire/commands/auth.ts"() {
2352
+ init_types2();
2353
+ SaslStartCommand = class {
2354
+ constructor(authenticator) {
2355
+ this.authenticator = authenticator;
2356
+ }
2357
+ async execute(command, context) {
2358
+ const mechanism = command.mechanism;
2359
+ const payload = command.payload;
2360
+ const options = command.options;
2361
+ if (!mechanism) {
2362
+ return {
2363
+ response: errorResponse2(
2364
+ ErrorCode.BAD_VALUE,
2365
+ "saslStart requires mechanism field"
2366
+ )
2367
+ };
2368
+ }
2369
+ if (!payload) {
2370
+ return {
2371
+ response: errorResponse2(
2372
+ ErrorCode.BAD_VALUE,
2373
+ "saslStart requires payload field"
2374
+ )
2375
+ };
2376
+ }
2377
+ let authDb = context.db;
2378
+ if (options?.authdb) {
2379
+ authDb = options.authdb;
2380
+ }
2381
+ const result = await this.authenticator.saslStart(mechanism, payload, authDb);
2382
+ if (!result.success) {
2383
+ return {
2384
+ response: errorResponse2(
2385
+ ErrorCode.AUTHENTICATION_FAILED,
2386
+ result.error || "Authentication failed"
2387
+ )
2388
+ };
2389
+ }
2390
+ return {
2391
+ response: successResponse2({
2392
+ conversationId: result.conversationId,
2393
+ payload: new Binary(result.payload),
2394
+ done: result.done
2395
+ })
2396
+ };
2397
+ }
2398
+ };
2399
+ SaslContinueCommand = class {
2400
+ constructor(authenticator) {
2401
+ this.authenticator = authenticator;
2402
+ }
2403
+ async execute(command, context) {
2404
+ const conversationId = command.conversationId;
2405
+ const payload = command.payload;
2406
+ if (conversationId === void 0 || conversationId === null) {
2407
+ return {
2408
+ response: errorResponse2(
2409
+ ErrorCode.BAD_VALUE,
2410
+ "saslContinue requires conversationId field"
2411
+ )
2412
+ };
2413
+ }
2414
+ if (!payload) {
2415
+ return {
2416
+ response: errorResponse2(
2417
+ ErrorCode.BAD_VALUE,
2418
+ "saslContinue requires payload field"
2419
+ )
2420
+ };
2421
+ }
2422
+ const result = await this.authenticator.saslContinue(conversationId, payload);
2423
+ if (!result.success) {
2424
+ return {
2425
+ response: errorResponse2(
2426
+ ErrorCode.AUTHENTICATION_FAILED,
2427
+ result.error || "Authentication failed"
2428
+ )
2429
+ };
2430
+ }
2431
+ if (result.done) {
2432
+ const user = this.authenticator.getConversationUser(conversationId);
2433
+ if (user && context.setAuthenticated) {
2434
+ context.setAuthenticated(user.username, user.db);
2435
+ }
2436
+ this.authenticator.cleanupConversation(conversationId);
2437
+ }
2438
+ return {
2439
+ response: successResponse2({
2440
+ conversationId: result.conversationId,
2441
+ payload: new Binary(result.payload),
2442
+ done: result.done
2443
+ })
2444
+ };
2445
+ }
2446
+ };
2447
+ AuthenticateCommand = class {
2448
+ async execute(_command, _context) {
2449
+ return {
2450
+ response: errorResponse2(
2451
+ ErrorCode.AUTHENTICATION_FAILED,
2452
+ "Legacy authenticate command is not supported. Use SCRAM-SHA-256 via saslStart/saslContinue."
2453
+ )
2454
+ };
2455
+ }
2456
+ };
2457
+ LogoutCommand = class {
2458
+ constructor(clearAuthentication) {
2459
+ this.clearAuthentication = clearAuthentication;
2460
+ }
2461
+ async execute(_command, context) {
2462
+ this.clearAuthentication(context.connectionId);
2463
+ return {
2464
+ response: successResponse2({
2465
+ // MongoDB returns ok: 1 for logout
2466
+ })
2467
+ };
2468
+ }
2469
+ };
2470
+ UNAUTHENTICATED_COMMANDS = /* @__PURE__ */ new Set([
2471
+ // Handshake commands
2472
+ "hello",
2473
+ "ismaster",
2474
+ "isMaster",
2475
+ "buildInfo",
2476
+ "buildinfo",
2477
+ // Authentication commands
2478
+ "saslStart",
2479
+ "saslContinue",
2480
+ "authenticate",
2481
+ "logout",
2482
+ // Basic connectivity
2483
+ "ping",
2484
+ "whatsmyuri",
2485
+ // Required for driver initialization
2486
+ "getParameter",
2487
+ "getCmdLineOpts"
2488
+ ]);
2489
+ }
2490
+ });
2491
+ async function createScramCredentials(username, password, db, iterationCount = 15e3) {
2492
+ const saltBytes = new Uint8Array(16);
2493
+ crypto.getRandomValues(saltBytes);
2494
+ const salt = Buffer.from(saltBytes).toString("base64");
2495
+ const saltedPassword = await pbkdf2Sha256(password, saltBytes, iterationCount);
2496
+ const clientKey = await hmacSha256(saltedPassword, "Client Key");
2497
+ const storedKey = await sha256(clientKey);
2498
+ const serverKey = await hmacSha256(saltedPassword, "Server Key");
2499
+ return {
2500
+ username,
2501
+ salt,
2502
+ storedKey: storedKey.toString("base64"),
2503
+ serverKey: serverKey.toString("base64"),
2504
+ iterationCount,
2505
+ db
2506
+ };
2507
+ }
2508
+ async function pbkdf2Sha256(password, salt, iterations) {
2509
+ const encoder = new TextEncoder();
2510
+ const keyMaterial = await crypto.subtle.importKey(
2511
+ "raw",
2512
+ encoder.encode(password),
2513
+ "PBKDF2",
2514
+ false,
2515
+ ["deriveBits"]
2516
+ );
2517
+ const derivedBits = await crypto.subtle.deriveBits(
2518
+ {
2519
+ name: "PBKDF2",
2520
+ salt: new Uint8Array(salt),
2521
+ iterations,
2522
+ hash: "SHA-256"
2523
+ },
2524
+ keyMaterial,
2525
+ 256
2526
+ // 32 bytes
2527
+ );
2528
+ return Buffer.from(derivedBits);
2529
+ }
2530
+ async function sha256(data) {
2531
+ const hashBuffer = await crypto.subtle.digest("SHA-256", new Uint8Array(data));
2532
+ return Buffer.from(hashBuffer);
2533
+ }
2534
+ async function hmacSha256(key, message) {
2535
+ const cryptoKey = await crypto.subtle.importKey(
2536
+ "raw",
2537
+ new Uint8Array(key),
2538
+ { name: "HMAC", hash: "SHA-256" },
2539
+ false,
2540
+ ["sign"]
2541
+ );
2542
+ const signature = await crypto.subtle.sign(
2543
+ "HMAC",
2544
+ cryptoKey,
2545
+ new TextEncoder().encode(message)
2546
+ );
2547
+ return Buffer.from(signature);
2548
+ }
2549
+ var ScramAuthenticator, InMemoryCredentialsProvider;
2550
+ var init_scram = __esm({
2551
+ "src/wire/auth/scram.ts"() {
2552
+ ScramAuthenticator = class {
2553
+ constructor(credentialsProvider) {
2554
+ this.credentialsProvider = credentialsProvider;
2555
+ }
2556
+ conversations = /* @__PURE__ */ new Map();
2557
+ nextConversationId = 1;
2558
+ /**
2559
+ * Handle saslStart command - begin authentication
2560
+ *
2561
+ * @param mechanism - Should be "SCRAM-SHA-256"
2562
+ * @param payload - Client's first message (Binary or Buffer)
2563
+ * @param db - Authentication database
2564
+ */
2565
+ async saslStart(mechanism, payload, db) {
2566
+ if (mechanism !== "SCRAM-SHA-256") {
2567
+ return {
2568
+ success: false,
2569
+ done: true,
2570
+ error: `Mechanism ${mechanism} is not supported. Only SCRAM-SHA-256 is available.`
2571
+ };
2572
+ }
2573
+ const payloadBytes = payload instanceof Binary ? payload.buffer : Buffer.from(payload);
2574
+ const clientFirstMessage = payloadBytes.toString("utf-8");
2575
+ const parsed = this.parseClientFirstMessage(clientFirstMessage);
2576
+ if (!parsed) {
2577
+ return {
2578
+ success: false,
2579
+ done: true,
2580
+ error: "Invalid client-first-message format"
2581
+ };
2582
+ }
2583
+ const { username, clientNonce, clientFirstMessageBare } = parsed;
2584
+ const credentials = await this.credentialsProvider.getCredentials(username, db);
2585
+ if (!credentials) {
2586
+ const fakeSalt = await this.generateSalt();
2587
+ const serverNonce2 = clientNonce + await this.generateNonce();
2588
+ const iterationCount = 15e3;
2589
+ const conversationId2 = this.nextConversationId++;
2590
+ this.conversations.set(conversationId2, {
2591
+ username,
2592
+ db,
2593
+ clientNonce,
2594
+ serverNonce: serverNonce2,
2595
+ salt: fakeSalt,
2596
+ iterationCount,
2597
+ clientFirstMessageBare,
2598
+ serverFirstMessage: "",
2599
+ step: "init"
2600
+ });
2601
+ const serverFirstMessage2 = `r=${serverNonce2},s=${fakeSalt},i=${iterationCount}`;
2602
+ const conv2 = this.conversations.get(conversationId2);
2603
+ conv2.serverFirstMessage = serverFirstMessage2;
2604
+ conv2.step = "challenge";
2605
+ return {
2606
+ success: true,
2607
+ conversationId: conversationId2,
2608
+ payload: Buffer.from(serverFirstMessage2, "utf-8"),
2609
+ done: false
2610
+ };
2611
+ }
2612
+ const serverNonce = clientNonce + await this.generateNonce();
2613
+ const conversationId = this.nextConversationId++;
2614
+ this.conversations.set(conversationId, {
2615
+ username,
2616
+ db,
2617
+ clientNonce,
2618
+ serverNonce,
2619
+ salt: credentials.salt,
2620
+ iterationCount: credentials.iterationCount,
2621
+ clientFirstMessageBare,
2622
+ serverFirstMessage: "",
2623
+ step: "init"
2624
+ });
2625
+ const serverFirstMessage = `r=${serverNonce},s=${credentials.salt},i=${credentials.iterationCount}`;
2626
+ const conv = this.conversations.get(conversationId);
2627
+ conv.serverFirstMessage = serverFirstMessage;
2628
+ conv.step = "challenge";
2629
+ return {
2630
+ success: true,
2631
+ conversationId,
2632
+ payload: Buffer.from(serverFirstMessage, "utf-8"),
2633
+ done: false
2634
+ };
2635
+ }
2636
+ /**
2637
+ * Handle saslContinue command - continue authentication
2638
+ *
2639
+ * @param conversationId - Conversation ID from saslStart
2640
+ * @param payload - Client's response message
2641
+ */
2642
+ async saslContinue(conversationId, payload) {
2643
+ const conv = this.conversations.get(conversationId);
2644
+ if (!conv) {
2645
+ return {
2646
+ success: false,
2647
+ done: true,
2648
+ error: "Invalid conversation ID"
2649
+ };
2650
+ }
2651
+ const payloadBytes = payload instanceof Binary ? payload.buffer : Buffer.from(payload);
2652
+ const clientMessage = payloadBytes.toString("utf-8");
2653
+ if (conv.step === "challenge") {
2654
+ const parsed = this.parseClientFinalMessage(clientMessage);
2655
+ if (!parsed) {
2656
+ this.conversations.delete(conversationId);
2657
+ return {
2658
+ success: false,
2659
+ done: true,
2660
+ error: "Invalid client-final-message format"
2661
+ };
2662
+ }
2663
+ const { clientProof, nonce, clientFinalMessageWithoutProof } = parsed;
2664
+ if (nonce !== conv.serverNonce) {
2665
+ this.conversations.delete(conversationId);
2666
+ return {
2667
+ success: false,
2668
+ done: true,
2669
+ error: "Authentication failed: nonce mismatch"
2670
+ };
2671
+ }
2672
+ const credentials = await this.credentialsProvider.getCredentials(
2673
+ conv.username,
2674
+ conv.db
2675
+ );
2676
+ if (!credentials) {
2677
+ this.conversations.delete(conversationId);
2678
+ return {
2679
+ success: false,
2680
+ done: true,
2681
+ error: "Authentication failed"
2682
+ };
2683
+ }
2684
+ const verified = await this.verifyClientProof(
2685
+ conv,
2686
+ clientProof,
2687
+ clientFinalMessageWithoutProof,
2688
+ credentials
2689
+ );
2690
+ if (!verified.success) {
2691
+ this.conversations.delete(conversationId);
2692
+ return {
2693
+ success: false,
2694
+ done: true,
2695
+ error: "Authentication failed"
2696
+ };
2697
+ }
2698
+ conv.step = "complete";
2699
+ const serverFinalMessage = `v=${verified.serverSignature}`;
2700
+ return {
2701
+ success: true,
2702
+ conversationId,
2703
+ payload: Buffer.from(serverFinalMessage, "utf-8"),
2704
+ done: true
2705
+ };
2706
+ }
2707
+ this.conversations.delete(conversationId);
2708
+ return {
2709
+ success: false,
2710
+ done: true,
2711
+ error: "Unexpected conversation state"
2712
+ };
2713
+ }
2714
+ /**
2715
+ * Parse client-first-message
2716
+ * Format: gs2-header n=username,r=client-nonce
2717
+ * gs2-header is typically "n,," (no channel binding, no authzid)
2718
+ */
2719
+ parseClientFirstMessage(message) {
2720
+ const match = message.match(/^([nyp])(=([^,]*))?,,(.+)$/);
2721
+ if (!match) return null;
2722
+ const clientFirstMessageBare = match[4];
2723
+ if (!clientFirstMessageBare) return null;
2724
+ const parts = /* @__PURE__ */ new Map();
2725
+ for (const part of clientFirstMessageBare.split(",")) {
2726
+ const eqIdx = part.indexOf("=");
2727
+ if (eqIdx > 0) {
2728
+ parts.set(part.slice(0, eqIdx), part.slice(eqIdx + 1));
2729
+ }
2730
+ }
2731
+ const username = parts.get("n");
2732
+ const clientNonce = parts.get("r");
2733
+ if (!username || !clientNonce) return null;
2734
+ const decodedUsername = username.replace(/=2C/g, ",").replace(/=3D/g, "=");
2735
+ return { username: decodedUsername, clientNonce, clientFirstMessageBare };
2736
+ }
2737
+ /**
2738
+ * Parse client-final-message
2739
+ * Format: c=channel-binding,r=nonce,p=client-proof
2740
+ */
2741
+ parseClientFinalMessage(message) {
2742
+ const proofMatch = message.match(/,p=([A-Za-z0-9+/=]+)$/);
2743
+ if (!proofMatch) return null;
2744
+ const clientProof = proofMatch[1];
2745
+ const clientFinalMessageWithoutProof = message.slice(
2746
+ 0,
2747
+ message.length - proofMatch[0].length
2748
+ );
2749
+ const parts = /* @__PURE__ */ new Map();
2750
+ for (const part of clientFinalMessageWithoutProof.split(",")) {
2751
+ const eqIdx = part.indexOf("=");
2752
+ if (eqIdx > 0) {
2753
+ parts.set(part.slice(0, eqIdx), part.slice(eqIdx + 1));
2754
+ }
2755
+ }
2756
+ const channelBinding = parts.get("c");
2757
+ const nonce = parts.get("r");
2758
+ if (!channelBinding || !nonce || !clientProof) return null;
2759
+ return { channelBinding, nonce, clientProof, clientFinalMessageWithoutProof };
2760
+ }
2761
+ /**
2762
+ * Verify client proof and generate server signature
2763
+ */
2764
+ async verifyClientProof(conv, clientProofBase64, clientFinalMessageWithoutProof, credentials) {
2765
+ try {
2766
+ const authMessage = `${conv.clientFirstMessageBare},${conv.serverFirstMessage},${clientFinalMessageWithoutProof}`;
2767
+ const storedKey = Buffer.from(credentials.storedKey, "base64");
2768
+ const serverKey = Buffer.from(credentials.serverKey, "base64");
2769
+ const clientSignature = await this.hmacSha256(storedKey, authMessage);
2770
+ const clientProof = Buffer.from(clientProofBase64, "base64");
2771
+ const clientKey = Buffer.alloc(clientProof.length);
2772
+ for (let i = 0; i < clientProof.length; i++) {
2773
+ clientKey[i] = (clientProof[i] ?? 0) ^ (clientSignature[i] ?? 0);
2774
+ }
2775
+ const computedStoredKey = await this.sha256(clientKey);
2776
+ if (!this.timingSafeEqual(computedStoredKey, storedKey)) {
2777
+ return { success: false };
2778
+ }
2779
+ const serverSignature = await this.hmacSha256(serverKey, authMessage);
2780
+ return {
2781
+ success: true,
2782
+ serverSignature: serverSignature.toString("base64")
2783
+ };
2784
+ } catch {
2785
+ return { success: false };
2786
+ }
2787
+ }
2788
+ /**
2789
+ * Generate a random nonce
2790
+ */
2791
+ async generateNonce() {
2792
+ const bytes = new Uint8Array(24);
2793
+ crypto.getRandomValues(bytes);
2794
+ return Buffer.from(bytes).toString("base64");
2795
+ }
2796
+ /**
2797
+ * Generate a random salt
2798
+ */
2799
+ async generateSalt() {
2800
+ const bytes = new Uint8Array(16);
2801
+ crypto.getRandomValues(bytes);
2802
+ return Buffer.from(bytes).toString("base64");
2803
+ }
2804
+ /**
2805
+ * Compute SHA-256 hash
2806
+ */
2807
+ async sha256(data) {
2808
+ const hashBuffer = await crypto.subtle.digest("SHA-256", new Uint8Array(data));
2809
+ return Buffer.from(hashBuffer);
2810
+ }
2811
+ /**
2812
+ * Compute HMAC-SHA-256
2813
+ */
2814
+ async hmacSha256(key, message) {
2815
+ const cryptoKey = await crypto.subtle.importKey(
2816
+ "raw",
2817
+ new Uint8Array(key),
2818
+ { name: "HMAC", hash: "SHA-256" },
2819
+ false,
2820
+ ["sign"]
2821
+ );
2822
+ const signature = await crypto.subtle.sign(
2823
+ "HMAC",
2824
+ cryptoKey,
2825
+ new TextEncoder().encode(message)
2826
+ );
2827
+ return Buffer.from(signature);
2828
+ }
2829
+ /**
2830
+ * Timing-safe comparison
2831
+ */
2832
+ timingSafeEqual(a, b) {
2833
+ if (a.length !== b.length) return false;
2834
+ let result = 0;
2835
+ for (let i = 0; i < a.length; i++) {
2836
+ result |= (a[i] ?? 0) ^ (b[i] ?? 0);
2837
+ }
2838
+ return result === 0;
2839
+ }
2840
+ /**
2841
+ * Clean up a conversation
2842
+ */
2843
+ cleanupConversation(conversationId) {
2844
+ this.conversations.delete(conversationId);
2845
+ }
2846
+ /**
2847
+ * Get conversation username for successful auth
2848
+ */
2849
+ getConversationUser(conversationId) {
2850
+ const conv = this.conversations.get(conversationId);
2851
+ if (!conv || conv.step !== "complete") return null;
2852
+ return { username: conv.username, db: conv.db };
2853
+ }
2854
+ };
2855
+ InMemoryCredentialsProvider = class {
2856
+ credentials = /* @__PURE__ */ new Map();
2857
+ /**
2858
+ * Add a user with a password
2859
+ */
2860
+ async addUser(username, password, db, roles) {
2861
+ const creds = await createScramCredentials(username, password, db);
2862
+ if (roles) {
2863
+ creds.roles = roles;
2864
+ }
2865
+ this.credentials.set(`${db}.${username}`, creds);
2866
+ }
2867
+ /**
2868
+ * Add pre-computed credentials
2869
+ */
2870
+ addCredentials(credentials) {
2871
+ this.credentials.set(`${credentials.db}.${credentials.username}`, credentials);
2872
+ }
2873
+ /**
2874
+ * Get credentials for a user
2875
+ */
2876
+ async getCredentials(username, db) {
2877
+ return this.credentials.get(`${db}.${username}`) || null;
2878
+ }
2879
+ /**
2880
+ * Remove a user
2881
+ */
2882
+ removeUser(username, db) {
2883
+ return this.credentials.delete(`${db}.${username}`);
2884
+ }
2885
+ /**
2886
+ * Check if a user exists
2887
+ */
2888
+ hasUser(username, db) {
2889
+ return this.credentials.has(`${db}.${username}`);
2890
+ }
2891
+ };
2892
+ }
2893
+ });
2894
+
2895
+ // src/wire/commands/router.ts
2896
+ var CommandRouter;
2897
+ var init_router = __esm({
2898
+ "src/wire/commands/router.ts"() {
2899
+ init_types2();
2900
+ init_hello();
2901
+ init_admin();
2902
+ init_crud();
2903
+ init_aggregate();
2904
+ init_commands();
2905
+ init_auth();
2906
+ init_scram();
2907
+ CommandRouter = class {
2908
+ handlers;
2909
+ authEnabled;
2910
+ authenticator;
2911
+ getConnectionState;
2912
+ setConnectionAuthenticated;
2913
+ clearConnectionAuthentication;
2914
+ constructor(backend, options = {}) {
2915
+ this.authEnabled = options.authEnabled ?? false;
2916
+ this.getConnectionState = options.getConnectionState;
2917
+ this.setConnectionAuthenticated = options.setConnectionAuthenticated;
2918
+ this.clearConnectionAuthentication = options.clearConnectionAuthentication;
2919
+ if (options.credentialsProvider) {
2920
+ this.authenticator = new ScramAuthenticator(options.credentialsProvider);
2921
+ }
2922
+ this.handlers = /* @__PURE__ */ new Map([
2923
+ // Handshake & discovery
2924
+ ["hello", new HelloCommand()],
2925
+ ["ismaster", new HelloCommand()],
2926
+ ["isMaster", new HelloCommand()],
2927
+ // System info
2928
+ ["ping", new PingCommand()],
2929
+ ["buildInfo", new BuildInfoCommand()],
2930
+ ["buildinfo", new BuildInfoCommand()],
2931
+ ["hostInfo", new HostInfoCommand()],
2932
+ ["whatsmyuri", new WhatsmyuriCommand()],
2933
+ ["getLog", new GetLogCommand()],
2934
+ ["getParameter", new GetParameterCommand()],
2935
+ ["getCmdLineOpts", new GetCmdLineOptsCommand()],
2936
+ // Admin commands
2937
+ ["listDatabases", new ListDatabasesCommand(backend)],
2938
+ ["listCollections", new ListCollectionsCommand(backend)],
2939
+ ["create", new CreateCommand(backend)],
2940
+ ["drop", new DropCommand(backend)],
2941
+ ["dropDatabase", new DropDatabaseCommand(backend)],
2942
+ ["collStats", new CollStatsCommand(backend)],
2943
+ ["dbStats", new DbStatsCommand(backend)],
2944
+ ["serverStatus", new ServerStatusCommand(backend)],
2945
+ // CRUD
2946
+ ["find", new FindCommand(backend)],
2947
+ ["insert", new InsertCommand(backend)],
2948
+ ["update", new UpdateCommand(backend)],
2949
+ ["delete", new DeleteCommand(backend)],
2950
+ ["count", new CountCommand(backend)],
2951
+ ["distinct", new DistinctCommand(backend)],
2952
+ ["getMore", new GetMoreCommand(backend)],
2953
+ ["killCursors", new KillCursorsCommand(backend)],
2954
+ // Aggregation
2955
+ ["aggregate", new AggregateCommand(backend)],
2956
+ // Indexes
2957
+ ["listIndexes", new ListIndexesCommand(backend)],
2958
+ ["createIndexes", new CreateIndexesCommand(backend)],
2959
+ ["dropIndexes", new DropIndexesCommand(backend)]
2960
+ ]);
2961
+ if (this.authenticator) {
2962
+ this.handlers.set("saslStart", new SaslStartCommand(this.authenticator));
2963
+ this.handlers.set("saslContinue", new SaslContinueCommand(this.authenticator));
2964
+ }
2965
+ this.handlers.set("authenticate", new AuthenticateCommand());
2966
+ if (this.clearConnectionAuthentication) {
2967
+ this.handlers.set("logout", new LogoutCommand(this.clearConnectionAuthentication));
2968
+ }
2969
+ }
2970
+ /**
2971
+ * Route a command to its handler
2972
+ */
2973
+ async route(command, context) {
2974
+ const commandName = Object.keys(command).find((key) => !key.startsWith("$"));
2975
+ if (!commandName) {
2976
+ return {
2977
+ response: errorResponse2(
2978
+ ErrorCode.COMMAND_NOT_FOUND,
2979
+ "no command found in request"
2980
+ )
2981
+ };
2982
+ }
2983
+ if (this.authEnabled && requiresAuthentication(commandName)) {
2984
+ const connState = this.getConnectionState?.(context.connectionId);
2985
+ if (!connState?.authenticated) {
2986
+ return {
2987
+ response: errorResponse2(
2988
+ ErrorCode.UNAUTHORIZED,
2989
+ `command ${commandName} requires authentication`
2990
+ )
2991
+ };
2992
+ }
2993
+ }
2994
+ const handler = this.handlers.get(commandName);
2995
+ if (!handler) {
2996
+ const lowerName = commandName.toLowerCase();
2997
+ for (const [name, h] of this.handlers) {
2998
+ if (name.toLowerCase() === lowerName) {
2999
+ return this.executeHandler(h, command, context, commandName);
3000
+ }
3001
+ }
3002
+ return {
3003
+ response: errorResponse2(
3004
+ ErrorCode.COMMAND_NOT_FOUND,
3005
+ `no such command: '${commandName}'`
3006
+ )
3007
+ };
3008
+ }
3009
+ return this.executeHandler(handler, command, context, commandName);
3010
+ }
3011
+ async executeHandler(handler, command, context, commandName) {
3012
+ try {
3013
+ if (commandName === "saslStart" || commandName === "saslContinue") {
3014
+ const authContext = {
3015
+ ...context,
3016
+ setAuthenticated: (username, db) => {
3017
+ this.setConnectionAuthenticated?.(context.connectionId, username, db);
3018
+ }
3019
+ };
3020
+ return await handler.execute(command, authContext);
3021
+ }
3022
+ return await handler.execute(command, context);
3023
+ } catch (error) {
3024
+ const message = error instanceof Error ? error.message : String(error);
3025
+ console.error(`Error executing command '${commandName}':`, message);
3026
+ return {
3027
+ response: errorResponse2(ErrorCode.INTERNAL_ERROR, message)
3028
+ };
3029
+ }
3030
+ }
3031
+ /**
3032
+ * Check if a command exists
3033
+ */
3034
+ hasCommand(name) {
3035
+ return this.handlers.has(name);
3036
+ }
3037
+ /**
3038
+ * Register a new command handler
3039
+ */
3040
+ registerCommand(name, handler) {
3041
+ this.handlers.set(name, handler);
3042
+ }
3043
+ };
3044
+ }
3045
+ });
3046
+
3047
+ // src/wire/server.ts
3048
+ var server_exports = {};
3049
+ __export(server_exports, {
3050
+ WireProtocolServer: () => WireProtocolServer,
3051
+ createServer: () => createServer
3052
+ });
3053
+ async function createServer(backend, options = {}) {
3054
+ const server = new WireProtocolServer(backend, options);
3055
+ await server.start();
3056
+ return server;
3057
+ }
3058
+ var DEFAULT_OPTIONS, WireProtocolServer;
3059
+ var init_server = __esm({
3060
+ "src/wire/server.ts"() {
3061
+ init_message();
3062
+ init_router();
3063
+ init_types();
3064
+ init_auth();
3065
+ init_scram();
3066
+ init_auth();
3067
+ DEFAULT_OPTIONS = {
3068
+ port: 27017,
3069
+ host: "localhost",
3070
+ verbose: false
3071
+ };
3072
+ WireProtocolServer = class {
3073
+ options;
3074
+ router;
3075
+ connections = /* @__PURE__ */ new Map();
3076
+ nextConnectionId = 1;
3077
+ nextRequestId = 1;
3078
+ // Use unknown to avoid typing issues with Bun.listen union types
3079
+ server = null;
3080
+ authenticator = null;
3081
+ constructor(backend, options = {}) {
3082
+ this.options = { ...DEFAULT_OPTIONS, ...options };
3083
+ this.router = new CommandRouter(backend);
3084
+ if (this.options.auth?.enabled) {
3085
+ const credentialsProvider = new InMemoryCredentialsProvider();
3086
+ credentialsProvider.addUser(
3087
+ this.options.auth.username,
3088
+ this.options.auth.password,
3089
+ "admin"
3090
+ // Default auth database
3091
+ ).then(() => {
3092
+ console.log(`Authentication enabled for user: ${this.options.auth.username}`);
3093
+ });
3094
+ this.authenticator = new ScramAuthenticator(credentialsProvider);
3095
+ this.router.registerCommand("saslStart", new SaslStartCommand(this.authenticator));
3096
+ this.router.registerCommand("saslContinue", new SaslContinueCommand(this.authenticator));
3097
+ this.router.registerCommand("logout", new LogoutCommand((connId) => {
3098
+ const conn = this.connections.get(connId);
3099
+ if (conn) {
3100
+ conn.authenticated = false;
3101
+ }
3102
+ }));
3103
+ }
3104
+ }
3105
+ /**
3106
+ * Start the server
3107
+ */
3108
+ async start() {
3109
+ const { port, host, verbose, tls } = this.options;
3110
+ const socketHandlers = {
3111
+ open: (socket) => {
3112
+ const connectionId = this.nextConnectionId++;
3113
+ socket.data = { connectionId, buffer: Buffer.alloc(0) };
3114
+ this.connections.set(connectionId, {
3115
+ id: connectionId,
3116
+ authenticated: false,
3117
+ compressionEnabled: false,
3118
+ cursors: /* @__PURE__ */ new Map()
3119
+ });
3120
+ if (verbose) {
3121
+ const connType = tls ? "TLS connection" : "Connection";
3122
+ console.log(`[${connectionId}] ${connType} opened`);
3123
+ }
3124
+ },
3125
+ data: async (socket, data) => {
3126
+ socket.data.buffer = Buffer.concat([socket.data.buffer, data]);
3127
+ await this.processBuffer(socket);
3128
+ },
3129
+ close: (socket) => {
3130
+ const connId = socket.data.connectionId;
3131
+ if (verbose) {
3132
+ console.log(`[${connId}] Connection closed`);
3133
+ }
3134
+ this.connections.delete(connId);
3135
+ },
3136
+ error: (socket, error) => {
3137
+ const { connectionId } = socket.data;
3138
+ console.error(`[${connectionId}] Socket error:`, error);
3139
+ }
3140
+ };
3141
+ if (tls) {
3142
+ this.server = Bun.listen({
3143
+ hostname: host,
3144
+ port,
3145
+ socket: socketHandlers,
3146
+ tls: this.buildTlsConfig(tls)
3147
+ });
3148
+ console.log(`mongo.do wire protocol server listening on TLS ${host}:${port}`);
3149
+ } else {
3150
+ this.server = Bun.listen({
3151
+ hostname: host,
3152
+ port,
3153
+ socket: socketHandlers
3154
+ });
3155
+ console.log(`mongo.do wire protocol server listening on TCP ${host}:${port}`);
3156
+ }
3157
+ }
3158
+ /**
3159
+ * Build TLS configuration object from TlsOptions
3160
+ */
3161
+ buildTlsConfig(tlsOptions) {
3162
+ const config = {
3163
+ key: tlsOptions.key,
3164
+ cert: tlsOptions.cert
3165
+ };
3166
+ if (tlsOptions.ca !== void 0) {
3167
+ config.ca = tlsOptions.ca;
3168
+ }
3169
+ if (tlsOptions.passphrase !== void 0) {
3170
+ config.passphrase = tlsOptions.passphrase;
3171
+ }
3172
+ if (tlsOptions.requestCert !== void 0) {
3173
+ config.requestCert = tlsOptions.requestCert;
3174
+ }
3175
+ if (tlsOptions.rejectUnauthorized !== void 0) {
3176
+ config.rejectUnauthorized = tlsOptions.rejectUnauthorized;
3177
+ }
3178
+ if (tlsOptions.minVersion !== void 0) {
3179
+ config.minVersion = tlsOptions.minVersion;
3180
+ }
3181
+ if (tlsOptions.maxVersion !== void 0) {
3182
+ config.maxVersion = tlsOptions.maxVersion;
3183
+ }
3184
+ if (tlsOptions.serverName !== void 0) {
3185
+ config.serverName = tlsOptions.serverName;
3186
+ }
3187
+ if (tlsOptions.ALPNProtocols !== void 0) {
3188
+ config.ALPNProtocols = tlsOptions.ALPNProtocols;
3189
+ }
3190
+ return config;
3191
+ }
3192
+ /**
3193
+ * Stop the server
3194
+ */
3195
+ async stop() {
3196
+ if (this.server) {
3197
+ this.server.stop();
3198
+ this.server = null;
3199
+ console.log("Server stopped");
3200
+ }
3201
+ }
3202
+ /**
3203
+ * Process accumulated buffer for complete messages
3204
+ */
3205
+ async processBuffer(socket) {
3206
+ const { connectionId, buffer } = socket.data;
3207
+ while (buffer.length >= 4) {
3208
+ const messageLength = buffer.readInt32LE(0);
3209
+ if (buffer.length < messageLength) {
3210
+ break;
3211
+ }
3212
+ const messageBuffer = buffer.subarray(0, messageLength);
3213
+ socket.data.buffer = buffer.subarray(messageLength);
3214
+ try {
3215
+ const response = await this.handleMessage(connectionId, messageBuffer);
3216
+ if (response) {
3217
+ socket.write(response);
3218
+ }
3219
+ } catch (error) {
3220
+ console.error(`[${connectionId}] Error handling message:`, error);
3221
+ const errorResponse3 = serializeOpMsg(
3222
+ this.nextRequestId++,
3223
+ messageBuffer.readInt32LE(4),
3224
+ // responseTo = requestID
3225
+ { ok: 0, errmsg: error instanceof Error ? error.message : "Unknown error", code: 1 }
3226
+ );
3227
+ socket.write(errorResponse3);
3228
+ }
3229
+ }
3230
+ }
3231
+ /**
3232
+ * Handle a single message
3233
+ */
3234
+ async handleMessage(connectionId, buffer) {
3235
+ const message = parseMessage(buffer);
3236
+ const { db, command, documentSequences } = extractCommand(message);
3237
+ const cmdName = Object.keys(command).find((k) => !k.startsWith("$"));
3238
+ if (this.options.verbose) {
3239
+ console.log(`[${connectionId}] ${cmdName} on ${db}`);
3240
+ }
3241
+ const connection = this.connections.get(connectionId);
3242
+ if (this.options.auth?.enabled && connection) {
3243
+ const isAuthRequired = requiresAuthentication(cmdName || "");
3244
+ if (isAuthRequired && !connection.authenticated) {
3245
+ const errorResult = {
3246
+ ok: 0,
3247
+ errmsg: "Authentication required. Use SCRAM-SHA-256 to authenticate.",
3248
+ code: 13,
3249
+ // Unauthorized
3250
+ codeName: "Unauthorized"
3251
+ };
3252
+ if (message.header.opCode === OpCode.OP_QUERY) {
3253
+ return serializeOpReply(this.nextRequestId++, message.header.requestID, [errorResult]);
3254
+ } else {
3255
+ return serializeOpMsg(this.nextRequestId++, message.header.requestID, errorResult);
3256
+ }
3257
+ }
3258
+ }
3259
+ const context = {
3260
+ db,
3261
+ connectionId,
3262
+ requestId: message.header.requestID,
3263
+ documentSequences,
3264
+ // Pass auth info for SASL handlers
3265
+ auth: this.options.auth
3266
+ };
3267
+ if (connection !== void 0) {
3268
+ context.connection = connection;
3269
+ }
3270
+ const result = await this.router.route(command, context);
3271
+ if (cmdName === "saslContinue" && result.response.ok === 1 && result.response.done === true) {
3272
+ if (connection) {
3273
+ connection.authenticated = true;
3274
+ }
3275
+ }
3276
+ if (message.header.opCode === OpCode.OP_QUERY) {
3277
+ return serializeOpReply(
3278
+ this.nextRequestId++,
3279
+ message.header.requestID,
3280
+ [result.response]
3281
+ );
3282
+ } else {
3283
+ return serializeOpMsg(
3284
+ this.nextRequestId++,
3285
+ message.header.requestID,
3286
+ result.response
3287
+ );
3288
+ }
3289
+ }
3290
+ /**
3291
+ * Get server address info
3292
+ */
3293
+ get address() {
3294
+ return {
3295
+ host: this.options.host,
3296
+ port: this.options.port,
3297
+ tls: this.isTls
3298
+ };
3299
+ }
3300
+ /**
3301
+ * Check if server is using TLS
3302
+ */
3303
+ get isTls() {
3304
+ return this.options.tls !== void 0;
3305
+ }
3306
+ /**
3307
+ * Get the MongoDB connection string for this server
3308
+ * Returns mongodb:// for non-TLS or mongodb+srv:// style for TLS
3309
+ */
3310
+ get connectionString() {
3311
+ const { host, port } = this.options;
3312
+ const protocol = this.isTls ? "mongodb+ssl" : "mongodb";
3313
+ return `${protocol}://${host}:${port}`;
3314
+ }
3315
+ };
3316
+ }
3317
+ });
3318
+
3319
+ // package.json
3320
+ var version = "0.1.1";
3321
+
3322
+ // src/wire/backend/workers-proxy.ts
3323
+ var MongoProxyError = class extends Error {
3324
+ code;
3325
+ codeName;
3326
+ constructor(message, code, codeName) {
3327
+ super(message);
3328
+ this.name = "MongoProxyError";
3329
+ this.code = code;
3330
+ if (codeName) {
3331
+ this.codeName = codeName;
3332
+ }
3333
+ }
3334
+ };
3335
+ var CURSOR_TIMEOUT_MS = 10 * 60 * 1e3;
3336
+ var RETRYABLE_STATUS_CODES = /* @__PURE__ */ new Set([408, 429, 500, 502, 503, 504]);
3337
+ var NON_RETRYABLE_ERROR_CODES = /* @__PURE__ */ new Set([
3338
+ 2,
3339
+ // BadValue
3340
+ 13,
3341
+ // Unauthorized
3342
+ 26,
3343
+ // NamespaceNotFound
3344
+ 59,
3345
+ // CommandNotFound
3346
+ 11e3
3347
+ // DuplicateKey
3348
+ ]);
3349
+ var WorkersProxyBackend = class {
3350
+ endpoint;
3351
+ authToken;
3352
+ timeout;
3353
+ retries;
3354
+ retryDelay;
3355
+ cursors = /* @__PURE__ */ new Map();
3356
+ constructor(options) {
3357
+ if (!options.endpoint) {
3358
+ throw new Error("WorkersProxyBackend requires an endpoint URL");
3359
+ }
3360
+ try {
3361
+ new URL(options.endpoint);
3362
+ } catch {
3363
+ throw new Error(`WorkersProxyBackend endpoint is not a valid URL: ${options.endpoint}`);
3364
+ }
3365
+ this.endpoint = options.endpoint;
3366
+ if (options.authToken) {
3367
+ this.authToken = options.authToken;
3368
+ }
3369
+ this.timeout = options.timeout ?? 3e4;
3370
+ this.retries = options.retries ?? 0;
3371
+ this.retryDelay = options.retryDelay ?? 1e3;
3372
+ }
3373
+ // ==========================================================================
3374
+ // Private Helper Methods
3375
+ // ==========================================================================
3376
+ /**
3377
+ * Make an RPC call to the Workers endpoint
3378
+ */
3379
+ async rpc(request, attempt = 0) {
3380
+ const headers = {
3381
+ "Content-Type": "application/json"
3382
+ };
3383
+ if (this.authToken) {
3384
+ headers["Authorization"] = `Bearer ${this.authToken}`;
3385
+ }
3386
+ try {
3387
+ const response = await fetch(this.endpoint, {
3388
+ method: "POST",
3389
+ headers,
3390
+ body: JSON.stringify(request),
3391
+ signal: AbortSignal.timeout(this.timeout)
3392
+ });
3393
+ if (!response.ok && !response.headers.get("Content-Type")?.includes("application/json")) {
3394
+ const error = new Error(`HTTP error: ${response.status} ${response.statusText}`);
3395
+ if (RETRYABLE_STATUS_CODES.has(response.status) && attempt < this.retries) {
3396
+ await this.delay(this.retryDelay);
3397
+ return this.rpc(request, attempt + 1);
3398
+ }
3399
+ throw error;
3400
+ }
3401
+ let data;
3402
+ try {
3403
+ data = await response.json();
3404
+ } catch {
3405
+ throw new Error("Invalid JSON response from RPC endpoint");
3406
+ }
3407
+ if (data.ok === 0) {
3408
+ const error = new MongoProxyError(data.error, data.code, data.codeName);
3409
+ if (NON_RETRYABLE_ERROR_CODES.has(data.code)) {
3410
+ throw error;
3411
+ }
3412
+ throw error;
3413
+ }
3414
+ return data.result;
3415
+ } catch (error) {
3416
+ if (attempt < this.retries && error instanceof Error && !("code" in error && NON_RETRYABLE_ERROR_CODES.has(error.code))) {
3417
+ await this.delay(this.retryDelay);
3418
+ return this.rpc(request, attempt + 1);
3419
+ }
3420
+ throw error;
3421
+ }
3422
+ }
3423
+ /**
3424
+ * Delay for a specified number of milliseconds
3425
+ */
3426
+ delay(ms) {
3427
+ return new Promise((resolve) => setTimeout(resolve, ms));
3428
+ }
3429
+ /**
3430
+ * Convert cursor ID from string to bigint
3431
+ */
3432
+ parseCursorId(cursorId) {
3433
+ if (typeof cursorId === "bigint") return cursorId;
3434
+ return BigInt(cursorId);
3435
+ }
3436
+ // ==========================================================================
3437
+ // Database Operations
3438
+ // ==========================================================================
3439
+ async listDatabases() {
3440
+ return this.rpc({ method: "listDatabases" });
3441
+ }
3442
+ async createDatabase(name) {
3443
+ await this.rpc({ method: "createDatabase", db: name });
3444
+ }
3445
+ async dropDatabase(name) {
3446
+ await this.rpc({ method: "dropDatabase", db: name });
3447
+ }
3448
+ async databaseExists(name) {
3449
+ return this.rpc({ method: "databaseExists", db: name });
3450
+ }
3451
+ // ==========================================================================
3452
+ // Collection Operations
3453
+ // ==========================================================================
3454
+ async listCollections(db, filter) {
3455
+ const request = {
3456
+ method: "listCollections",
3457
+ db
3458
+ };
3459
+ if (filter) {
3460
+ request.filter = filter;
3461
+ }
3462
+ return this.rpc(request);
3463
+ }
3464
+ async createCollection(db, name, options) {
3465
+ const request = {
3466
+ method: "createCollection",
3467
+ db,
3468
+ collection: name
3469
+ };
3470
+ if (options) {
3471
+ request.options = options;
3472
+ }
3473
+ await this.rpc(request);
3474
+ }
3475
+ async dropCollection(db, name) {
3476
+ await this.rpc({
3477
+ method: "dropCollection",
3478
+ db,
3479
+ collection: name
3480
+ });
3481
+ }
3482
+ async collectionExists(db, name) {
3483
+ return this.rpc({
3484
+ method: "collectionExists",
3485
+ db,
3486
+ collection: name
3487
+ });
3488
+ }
3489
+ async collStats(db, collection) {
3490
+ return this.rpc({
3491
+ method: "collStats",
3492
+ db,
3493
+ collection
3494
+ });
3495
+ }
3496
+ async dbStats(db) {
3497
+ return this.rpc({
3498
+ method: "dbStats",
3499
+ db
3500
+ });
3501
+ }
3502
+ // ==========================================================================
3503
+ // CRUD Operations
3504
+ // ==========================================================================
3505
+ async find(db, collection, options) {
3506
+ const request = {
3507
+ method: "find",
3508
+ db,
3509
+ collection
3510
+ };
3511
+ if (options.filter) {
3512
+ request.filter = options.filter;
3513
+ }
3514
+ const findOptions = {};
3515
+ if (options.projection) findOptions.projection = options.projection;
3516
+ if (options.sort) findOptions.sort = options.sort;
3517
+ if (options.limit !== void 0) findOptions.limit = options.limit;
3518
+ if (options.skip !== void 0) findOptions.skip = options.skip;
3519
+ if (options.batchSize !== void 0) findOptions.batchSize = options.batchSize;
3520
+ if (options.hint) findOptions.hint = options.hint;
3521
+ if (options.comment) findOptions.comment = options.comment;
3522
+ if (options.allowDiskUse !== void 0) findOptions.allowDiskUse = options.allowDiskUse;
3523
+ if (options.collation) findOptions.collation = options.collation;
3524
+ if (Object.keys(findOptions).length > 0) {
3525
+ request.options = findOptions;
3526
+ }
3527
+ const result = await this.rpc(request);
3528
+ return {
3529
+ documents: result.documents,
3530
+ cursorId: this.parseCursorId(result.cursorId),
3531
+ hasMore: result.hasMore
3532
+ };
3533
+ }
3534
+ async insertOne(db, collection, doc) {
3535
+ const result = await this.rpc({
3536
+ method: "insertOne",
3537
+ db,
3538
+ collection,
3539
+ document: doc
3540
+ });
3541
+ return {
3542
+ acknowledged: result.acknowledged,
3543
+ insertedIds: new Map(Object.entries(result.insertedIds).map(([k, v]) => [Number(k), v])),
3544
+ insertedCount: result.insertedCount
3545
+ };
3546
+ }
3547
+ async insertMany(db, collection, docs) {
3548
+ const result = await this.rpc({
3549
+ method: "insertMany",
3550
+ db,
3551
+ collection,
3552
+ documents: docs
3553
+ });
3554
+ return {
3555
+ acknowledged: result.acknowledged,
3556
+ insertedIds: new Map(Object.entries(result.insertedIds).map(([k, v]) => [Number(k), v])),
3557
+ insertedCount: result.insertedCount
3558
+ };
3559
+ }
3560
+ async updateOne(db, collection, filter, update, options) {
3561
+ const request = {
3562
+ method: "updateOne",
3563
+ db,
3564
+ collection,
3565
+ filter,
3566
+ update
3567
+ };
3568
+ if (options) {
3569
+ request.options = options;
3570
+ }
3571
+ return this.rpc(request);
3572
+ }
3573
+ async updateMany(db, collection, filter, update, options) {
3574
+ const request = {
3575
+ method: "updateMany",
3576
+ db,
3577
+ collection,
3578
+ filter,
3579
+ update
3580
+ };
3581
+ if (options) {
3582
+ request.options = options;
3583
+ }
3584
+ return this.rpc(request);
3585
+ }
3586
+ async deleteOne(db, collection, filter) {
3587
+ return this.rpc({
3588
+ method: "deleteOne",
3589
+ db,
3590
+ collection,
3591
+ filter
3592
+ });
3593
+ }
3594
+ async deleteMany(db, collection, filter) {
3595
+ return this.rpc({
3596
+ method: "deleteMany",
3597
+ db,
3598
+ collection,
3599
+ filter
3600
+ });
3601
+ }
3602
+ // ==========================================================================
3603
+ // Count and Distinct
3604
+ // ==========================================================================
3605
+ async count(db, collection, query) {
3606
+ const request = {
3607
+ method: "count",
3608
+ db,
3609
+ collection
3610
+ };
3611
+ if (query) {
3612
+ request.query = query;
3613
+ }
3614
+ return this.rpc(request);
3615
+ }
3616
+ async distinct(db, collection, field, query) {
3617
+ const request = {
3618
+ method: "distinct",
3619
+ db,
3620
+ collection,
3621
+ field
3622
+ };
3623
+ if (query) {
3624
+ request.query = query;
3625
+ }
3626
+ return this.rpc(request);
3627
+ }
3628
+ // ==========================================================================
3629
+ // Aggregation
3630
+ // ==========================================================================
3631
+ async aggregate(db, collection, pipeline, options) {
3632
+ const request = {
3633
+ method: "aggregate",
3634
+ db,
3635
+ collection,
3636
+ pipeline
3637
+ };
3638
+ if (options) {
3639
+ request.options = options;
3640
+ }
3641
+ const result = await this.rpc(request);
3642
+ return {
3643
+ documents: result.documents,
3644
+ cursorId: this.parseCursorId(result.cursorId),
3645
+ hasMore: result.hasMore
3646
+ };
3647
+ }
3648
+ // ==========================================================================
3649
+ // Index Operations
3650
+ // ==========================================================================
3651
+ async listIndexes(db, collection) {
3652
+ return this.rpc({
3653
+ method: "listIndexes",
3654
+ db,
3655
+ collection
3656
+ });
3657
+ }
3658
+ async createIndexes(db, collection, indexes) {
3659
+ return this.rpc({
3660
+ method: "createIndexes",
3661
+ db,
3662
+ collection,
3663
+ options: { indexes }
3664
+ });
3665
+ }
3666
+ async dropIndex(db, collection, indexName) {
3667
+ await this.rpc({
3668
+ method: "dropIndex",
3669
+ db,
3670
+ collection,
3671
+ options: { indexName }
3672
+ });
3673
+ }
3674
+ async dropIndexes(db, collection) {
3675
+ await this.rpc({
3676
+ method: "dropIndexes",
3677
+ db,
3678
+ collection
3679
+ });
3680
+ }
3681
+ // ==========================================================================
3682
+ // Cursor Management
3683
+ // ==========================================================================
3684
+ createCursor(state) {
3685
+ this.cursors.set(state.id, state);
3686
+ }
3687
+ getCursor(id) {
3688
+ return this.cursors.get(id);
3689
+ }
3690
+ advanceCursor(id, count) {
3691
+ const cursor = this.cursors.get(id);
3692
+ if (!cursor) {
3693
+ return [];
3694
+ }
3695
+ const start = cursor.position;
3696
+ const end = Math.min(start + count, cursor.documents.length);
3697
+ cursor.position = end;
3698
+ return cursor.documents.slice(start, end);
3699
+ }
3700
+ closeCursor(id) {
3701
+ return this.cursors.delete(id);
3702
+ }
3703
+ cleanupExpiredCursors() {
3704
+ const now = Date.now();
3705
+ for (const [id, cursor] of this.cursors) {
3706
+ if (now - cursor.createdAt > CURSOR_TIMEOUT_MS) {
3707
+ this.cursors.delete(id);
3708
+ }
3709
+ }
3710
+ }
3711
+ };
3712
+
3713
+ // src/cli/server.ts
3714
+ var LocalSQLiteBackend2;
3715
+ var WireProtocolServer2;
3716
+ async function loadBunModules() {
3717
+ if (!LocalSQLiteBackend2) {
3718
+ const localModule = await Promise.resolve().then(() => (init_local_sqlite(), local_sqlite_exports));
3719
+ LocalSQLiteBackend2 = localModule.LocalSQLiteBackend;
3720
+ }
3721
+ if (!WireProtocolServer2) {
3722
+ const serverModule = await Promise.resolve().then(() => (init_server(), server_exports));
3723
+ WireProtocolServer2 = serverModule.WireProtocolServer;
3724
+ }
3725
+ }
3726
+ function parseArgs(args) {
3727
+ const options = {
3728
+ port: 27017,
3729
+ host: "localhost",
3730
+ dataDir: "./data",
3731
+ verbose: false,
3732
+ help: false
3733
+ };
3734
+ for (let i = 0; i < args.length; i++) {
3735
+ const arg = args[i];
3736
+ if (!arg) continue;
3737
+ if (arg === "--help" || arg === "-h") {
3738
+ options.help = true;
3739
+ continue;
3740
+ }
3741
+ if (arg === "--verbose" || arg === "-v") {
3742
+ options.verbose = true;
3743
+ continue;
3744
+ }
3745
+ if (arg.startsWith("--port=")) {
3746
+ options.port = parseInt(arg.slice(7), 10);
3747
+ continue;
3748
+ }
3749
+ if (arg.startsWith("-p=")) {
3750
+ options.port = parseInt(arg.slice(3), 10);
3751
+ continue;
3752
+ }
3753
+ if (arg === "--port" || arg === "-p") {
3754
+ const nextArg = args[++i];
3755
+ if (nextArg) {
3756
+ options.port = parseInt(nextArg, 10);
3757
+ }
3758
+ continue;
3759
+ }
3760
+ if (arg.startsWith("--host=")) {
3761
+ options.host = arg.slice(7);
3762
+ continue;
3763
+ }
3764
+ if (arg.startsWith("-H=")) {
3765
+ options.host = arg.slice(3);
3766
+ continue;
3767
+ }
3768
+ if (arg === "--host" || arg === "-H") {
3769
+ const nextArg = args[++i];
3770
+ if (nextArg) {
3771
+ options.host = nextArg;
3772
+ }
3773
+ continue;
3774
+ }
3775
+ if (arg.startsWith("--data=")) {
3776
+ options.dataDir = arg.slice(7);
3777
+ continue;
3778
+ }
3779
+ if (arg.startsWith("-d=")) {
3780
+ options.dataDir = arg.slice(3);
3781
+ continue;
3782
+ }
3783
+ if (arg === "--data" || arg === "-d") {
3784
+ const nextArg = args[++i];
3785
+ if (nextArg) {
3786
+ options.dataDir = nextArg;
3787
+ }
3788
+ continue;
3789
+ }
3790
+ if (arg.startsWith("--remote=")) {
3791
+ options.remote = arg.slice(9);
3792
+ continue;
3793
+ }
3794
+ if (arg.startsWith("-r=")) {
3795
+ options.remote = arg.slice(3);
3796
+ continue;
3797
+ }
3798
+ if (arg === "--remote" || arg === "-r") {
3799
+ const nextArg = args[++i];
3800
+ if (nextArg) {
3801
+ options.remote = nextArg;
3802
+ }
3803
+ continue;
3804
+ }
3805
+ }
3806
+ return options;
3807
+ }
3808
+ function validateOptions(options) {
3809
+ const errors = [];
3810
+ if (typeof options.port !== "number" || isNaN(options.port) || !Number.isInteger(options.port) || options.port < 1 || options.port > 65535) {
3811
+ errors.push(`Invalid port: ${options.port}. Port must be an integer between 1 and 65535.`);
3812
+ }
3813
+ if (!options.host || typeof options.host !== "string" || options.host.trim() === "") {
3814
+ errors.push("Invalid host: host cannot be empty");
3815
+ }
3816
+ if (!options.remote) {
3817
+ if (!options.dataDir || typeof options.dataDir !== "string" || options.dataDir.trim() === "") {
3818
+ errors.push("Invalid data directory: path cannot be empty");
3819
+ }
3820
+ }
3821
+ if (options.remote !== void 0) {
3822
+ if (!options.remote || typeof options.remote !== "string" || options.remote.trim() === "") {
3823
+ errors.push("Invalid remote URL: URL cannot be empty. Use https://your-worker.workers.dev");
3824
+ } else {
3825
+ try {
3826
+ const url = new URL(options.remote);
3827
+ if (url.protocol !== "http:" && url.protocol !== "https:") {
3828
+ errors.push(`Invalid remote URL: protocol must be http or https, got "${url.protocol.slice(0, -1)}"`);
3829
+ }
3830
+ } catch {
3831
+ errors.push(`Invalid remote URL: "${options.remote}" is not a valid URL. Use https://your-worker.workers.dev`);
3832
+ }
3833
+ }
3834
+ }
3835
+ return {
3836
+ valid: errors.length === 0,
3837
+ errors
3838
+ };
3839
+ }
3840
+ async function createBackend(options) {
3841
+ if (options.remote) {
3842
+ return new WorkersProxyBackend({
3843
+ endpoint: options.remote
3844
+ });
3845
+ }
3846
+ await loadBunModules();
3847
+ return new LocalSQLiteBackend2(options.dataDir);
3848
+ }
3849
+ function printHelp() {
3850
+ console.log(`
3851
+ Usage: mongo.do serve [options]
3852
+
3853
+ Start a MongoDB wire protocol server backed by SQLite.
3854
+
3855
+ Options:
3856
+ -p, --port <port> Port to listen on (default: 27017)
3857
+ -H, --host <host> Host to bind to (default: localhost)
3858
+ -d, --data <path> Data directory for local SQLite storage (default: ./data)
3859
+ -r, --remote <url> Proxy/forward to remote Cloudflare Workers endpoint
3860
+ -v, --verbose Enable verbose logging
3861
+ -V, --version Show version number
3862
+ -h, --help Show this help message
3863
+
3864
+ Examples:
3865
+ # Start local server on default port
3866
+ mongo.do serve
3867
+
3868
+ # Start on custom port with verbose logging
3869
+ mongo.do serve --port 27018 --verbose
3870
+
3871
+ # Bind to all interfaces
3872
+ mongo.do serve --host 0.0.0.0
3873
+
3874
+ # Use custom data directory
3875
+ mongo.do serve --data /var/lib/mongodo
3876
+
3877
+ # Proxy to remote Cloudflare Workers
3878
+ mongo.do serve --remote https://my-mongo-do.workers.dev
3879
+
3880
+ # Combine options
3881
+ mongo.do serve --port 27018 --host 0.0.0.0 --verbose
3882
+ `);
3883
+ }
3884
+ function printShutdownMessage() {
3885
+ console.log("MondoDB server gracefully shutdown. Clean stop complete.");
3886
+ }
3887
+ async function runServer(options, backend) {
3888
+ const validationResult = validateOptions(options);
3889
+ if (!validationResult.valid) {
3890
+ throw new Error(validationResult.errors[0]);
3891
+ }
3892
+ const serverBackend = await createBackend(options);
3893
+ if (options.remote && true) {
3894
+ try {
3895
+ await serverBackend.listDatabases();
3896
+ } catch (e) {
3897
+ throw new Error(`Failed to connect to remote worker: ${options.remote}. Network unreachable or worker not responding.`);
3898
+ }
3899
+ }
3900
+ await loadBunModules();
3901
+ const wireServer = new WireProtocolServer2(serverBackend, {
3902
+ port: options.port,
3903
+ host: options.host,
3904
+ verbose: options.verbose
3905
+ });
3906
+ let running = false;
3907
+ let acceptingConnections = false;
3908
+ let connectionCount = 0;
3909
+ const handleSignal = async () => {
3910
+ if (running) {
3911
+ await controller.stop();
3912
+ }
3913
+ };
3914
+ const sigintHandler = handleSignal;
3915
+ const sigtermHandler = handleSignal;
3916
+ const controller = {
3917
+ get isRunning() {
3918
+ return running;
3919
+ },
3920
+ get isAcceptingConnections() {
3921
+ return acceptingConnections;
3922
+ },
3923
+ get activeConnections() {
3924
+ return connectionCount;
3925
+ },
3926
+ get address() {
3927
+ return { host: options.host, port: options.port };
3928
+ },
3929
+ async stop() {
3930
+ if (!running) return;
3931
+ running = false;
3932
+ acceptingConnections = false;
3933
+ connectionCount = 0;
3934
+ await wireServer.stop();
3935
+ if ("close" in serverBackend && typeof serverBackend.close === "function") {
3936
+ await serverBackend.close();
3937
+ }
3938
+ process.removeListener("SIGINT", sigintHandler);
3939
+ process.removeListener("SIGTERM", sigtermHandler);
3940
+ }
3941
+ };
3942
+ process.on("SIGINT", sigintHandler);
3943
+ process.on("SIGTERM", sigtermHandler);
3944
+ try {
3945
+ await wireServer.start();
3946
+ running = true;
3947
+ acceptingConnections = true;
3948
+ } catch (e) {
3949
+ process.removeListener("SIGINT", sigintHandler);
3950
+ process.removeListener("SIGTERM", sigtermHandler);
3951
+ if (e instanceof Error && e.message.includes("EADDRINUSE")) {
3952
+ throw new Error(`Port ${options.port} is already in use (EADDRINUSE)`);
3953
+ }
3954
+ throw e;
3955
+ }
3956
+ return controller;
3957
+ }
3958
+
3959
+ // src/cli/index.ts
3960
+ var colors = {
3961
+ reset: "\x1B[0m",
3962
+ bold: "\x1B[1m",
3963
+ dim: "\x1B[2m",
3964
+ // Foreground colors
3965
+ red: "\x1B[31m",
3966
+ green: "\x1B[32m",
3967
+ yellow: "\x1B[33m",
3968
+ blue: "\x1B[34m",
3969
+ magenta: "\x1B[35m",
3970
+ cyan: "\x1B[36m",
3971
+ white: "\x1B[37m"
3972
+ };
3973
+ function supportsColor() {
3974
+ if (process.env.NO_COLOR !== void 0) {
3975
+ return false;
3976
+ }
3977
+ if (process.env.FORCE_COLOR !== void 0) {
3978
+ return true;
3979
+ }
3980
+ return process.stdout.isTTY ?? false;
3981
+ }
3982
+ var useColors = supportsColor();
51
3983
  function colorize(text, color) {
52
- if (!useColors)
53
- return text;
54
- return `${colors[color]}${text}${colors.reset}`;
55
- }
56
- // ============================================================================
57
- // Output Functions
58
- // ============================================================================
59
- /**
60
- * Print the ASCII banner for MondoDB
61
- */
3984
+ if (!useColors) return text;
3985
+ return `${colors[color]}${text}${colors.reset}`;
3986
+ }
62
3987
  function printBanner() {
63
- const banner = `
64
- ${colorize('MondoDB', 'cyan')} ${colorize(`v${version}`, 'dim')}
65
- ${colorize('MongoDB-compatible database backed by SQLite', 'dim')}
3988
+ const banner = `
3989
+ ${colorize("MondoDB", "cyan")} ${colorize(`v${version}`, "dim")}
3990
+ ${colorize("MongoDB-compatible database backed by SQLite", "dim")}
66
3991
  `;
67
- console.log(banner);
3992
+ console.log(banner);
68
3993
  }
69
- /**
70
- * Print version information
71
- */
72
3994
  function printVersion() {
73
- console.log(`mongo.do version ${version}`);
3995
+ console.log(`mongo.do version ${version}`);
74
3996
  }
75
- /**
76
- * Print an error message
77
- */
78
3997
  function printError(message) {
79
- console.error(`${colorize('error:', 'red')} ${message}`);
3998
+ console.error(`${colorize("error:", "red")} ${message}`);
80
3999
  }
81
- /**
82
- * Print enhanced startup message with colors
83
- */
84
4000
  function printColoredStartupMessage(options) {
85
- const connectionString = `mongodb://${options.host}:${options.port}`;
86
- console.log('');
87
- if (options.remote) {
88
- console.log(`${colorize('Mode:', 'bold')} ${colorize('Proxy/Remote', 'magenta')}`);
89
- console.log(`${colorize('Connect:', 'bold')} ${colorize(connectionString, 'cyan')}`);
90
- console.log(`${colorize('Proxying to:', 'bold')} ${colorize(options.remote, 'blue')}`);
91
- }
92
- else {
93
- console.log(`${colorize('Mode:', 'bold')} ${colorize('Local/SQLite', 'green')}`);
94
- console.log(`${colorize('Connect:', 'bold')} ${colorize(connectionString, 'cyan')}`);
95
- console.log(`${colorize('Data directory:', 'bold')} ${options.dataDir}`);
96
- }
97
- if (options.verbose) {
98
- console.log(`${colorize('Verbose logging:', 'bold')} ${colorize('enabled', 'yellow')}`);
99
- }
100
- console.log('');
101
- console.log(`${colorize('Ready to accept connections.', 'green')} Press ${colorize('Ctrl+C', 'bold')} to stop.`);
102
- console.log('');
103
- }
104
- /**
105
- * Parse command line arguments with version flag support
106
- */
4001
+ const connectionString = `mongodb://${options.host}:${options.port}`;
4002
+ console.log("");
4003
+ if (options.remote) {
4004
+ console.log(`${colorize("Mode:", "bold")} ${colorize("Proxy/Remote", "magenta")}`);
4005
+ console.log(`${colorize("Connect:", "bold")} ${colorize(connectionString, "cyan")}`);
4006
+ console.log(`${colorize("Proxying to:", "bold")} ${colorize(options.remote, "blue")}`);
4007
+ } else {
4008
+ console.log(`${colorize("Mode:", "bold")} ${colorize("Local/SQLite", "green")}`);
4009
+ console.log(`${colorize("Connect:", "bold")} ${colorize(connectionString, "cyan")}`);
4010
+ console.log(`${colorize("Data directory:", "bold")} ${options.dataDir}`);
4011
+ }
4012
+ if (options.verbose) {
4013
+ console.log(`${colorize("Verbose logging:", "bold")} ${colorize("enabled", "yellow")}`);
4014
+ }
4015
+ console.log("");
4016
+ console.log(`${colorize("Ready to accept connections.", "green")} Press ${colorize("Ctrl+C", "bold")} to stop.`);
4017
+ console.log("");
4018
+ }
107
4019
  function parseArgsExtended(args) {
108
- const baseOptions = parseArgs(args);
109
- // Check for version flag
110
- const hasVersion = args.some((arg) => arg === '--version' || arg === '-V');
111
- return {
112
- ...baseOptions,
113
- version: hasVersion,
114
- };
4020
+ const baseOptions = parseArgs(args);
4021
+ const hasVersion = args.some(
4022
+ (arg) => arg === "--version" || arg === "-V"
4023
+ );
4024
+ return {
4025
+ ...baseOptions,
4026
+ version: hasVersion
4027
+ };
115
4028
  }
116
- // ============================================================================
117
- // Main Entry Point
118
- // ============================================================================
119
- /**
120
- * Main CLI function
121
- */
122
4029
  async function main() {
4030
+ try {
4031
+ const options = parseArgsExtended(process.argv.slice(2));
4032
+ if (options.version) {
4033
+ printVersion();
4034
+ process.exit(0);
4035
+ }
4036
+ if (options.help) {
4037
+ printHelp();
4038
+ process.exit(0);
4039
+ }
123
4040
  try {
124
- // Parse arguments
125
- const options = parseArgsExtended(process.argv.slice(2));
126
- // Handle --version flag
127
- if (options.version) {
128
- printVersion();
129
- process.exit(0);
130
- }
131
- // Handle --help flag
132
- if (options.help) {
133
- printHelp();
134
- process.exit(0);
135
- }
136
- // Validate options
137
- try {
138
- validateOptions(options);
139
- }
140
- catch (error) {
141
- if (error instanceof Error) {
142
- printError(error.message);
143
- }
144
- else {
145
- printError('Invalid options');
146
- }
147
- console.log('');
148
- console.log(`Run ${colorize('mongo.do --help', 'cyan')} for usage information.`);
149
- process.exit(1);
150
- }
151
- // Print banner
152
- printBanner();
153
- // Start the server
154
- const controller = await runServer(options);
155
- // Print startup message
156
- printColoredStartupMessage(options);
157
- // Handle graceful shutdown
158
- const shutdown = async (signal) => {
159
- console.log('');
160
- console.log(`${colorize(`Received ${signal}, shutting down...`, 'yellow')}`);
161
- try {
162
- await controller.stop();
163
- printShutdownMessage();
164
- process.exit(0);
165
- }
166
- catch (error) {
167
- printError(`Error during shutdown: ${error instanceof Error ? error.message : 'Unknown error'}`);
168
- process.exit(1);
169
- }
170
- };
171
- // Register signal handlers
172
- process.on('SIGINT', () => shutdown('SIGINT'));
173
- process.on('SIGTERM', () => shutdown('SIGTERM'));
174
- // Handle uncaught exceptions
175
- process.on('uncaughtException', (error) => {
176
- printError(`Uncaught exception: ${error.message}`);
177
- if (options.verbose) {
178
- console.error(error.stack);
179
- }
180
- process.exit(1);
181
- });
182
- // Handle unhandled promise rejections
183
- process.on('unhandledRejection', (reason) => {
184
- printError(`Unhandled rejection: ${reason instanceof Error ? reason.message : String(reason)}`);
185
- if (options.verbose && reason instanceof Error) {
186
- console.error(reason.stack);
187
- }
188
- process.exit(1);
189
- });
4041
+ validateOptions(options);
4042
+ } catch (error) {
4043
+ if (error instanceof Error) {
4044
+ printError(error.message);
4045
+ } else {
4046
+ printError("Invalid options");
4047
+ }
4048
+ console.log("");
4049
+ console.log(`Run ${colorize("mongo.do --help", "cyan")} for usage information.`);
4050
+ process.exit(1);
190
4051
  }
191
- catch (error) {
192
- // Handle startup errors gracefully
193
- if (error instanceof Error) {
194
- printError(error.message);
195
- // Provide helpful hints for common errors
196
- if (error.message.includes('EADDRINUSE')) {
197
- console.log('');
198
- console.log(`${colorize('Hint:', 'yellow')} The port is already in use. Try a different port with ${colorize('--port', 'cyan')}.`);
199
- }
200
- else if (error.message.includes('EACCES')) {
201
- console.log('');
202
- console.log(`${colorize('Hint:', 'yellow')} Permission denied. Ports below 1024 require root privileges.`);
203
- console.log(` Try using a port number above 1024, e.g., ${colorize('--port=27017', 'cyan')}.`);
204
- }
205
- else if (error.message.includes('Failed to connect to remote')) {
206
- console.log('');
207
- console.log(`${colorize('Hint:', 'yellow')} Could not connect to the remote worker.`);
208
- console.log(` Check that the URL is correct and the worker is running.`);
209
- }
210
- }
211
- else {
212
- printError('An unexpected error occurred');
213
- }
4052
+ printBanner();
4053
+ const controller = await runServer(options);
4054
+ printColoredStartupMessage(options);
4055
+ const shutdown = async (signal) => {
4056
+ console.log("");
4057
+ console.log(`${colorize(`Received ${signal}, shutting down...`, "yellow")}`);
4058
+ try {
4059
+ await controller.stop();
4060
+ printShutdownMessage();
4061
+ process.exit(0);
4062
+ } catch (error) {
4063
+ printError(`Error during shutdown: ${error instanceof Error ? error.message : "Unknown error"}`);
214
4064
  process.exit(1);
4065
+ }
4066
+ };
4067
+ process.on("SIGINT", () => shutdown("SIGINT"));
4068
+ process.on("SIGTERM", () => shutdown("SIGTERM"));
4069
+ process.on("uncaughtException", (error) => {
4070
+ printError(`Uncaught exception: ${error.message}`);
4071
+ if (options.verbose) {
4072
+ console.error(error.stack);
4073
+ }
4074
+ process.exit(1);
4075
+ });
4076
+ process.on("unhandledRejection", (reason) => {
4077
+ printError(`Unhandled rejection: ${reason instanceof Error ? reason.message : String(reason)}`);
4078
+ if (options.verbose && reason instanceof Error) {
4079
+ console.error(reason.stack);
4080
+ }
4081
+ process.exit(1);
4082
+ });
4083
+ } catch (error) {
4084
+ if (error instanceof Error) {
4085
+ printError(error.message);
4086
+ if (error.message.includes("EADDRINUSE")) {
4087
+ console.log("");
4088
+ console.log(`${colorize("Hint:", "yellow")} The port is already in use. Try a different port with ${colorize("--port", "cyan")}.`);
4089
+ } else if (error.message.includes("EACCES")) {
4090
+ console.log("");
4091
+ console.log(`${colorize("Hint:", "yellow")} Permission denied. Ports below 1024 require root privileges.`);
4092
+ console.log(` Try using a port number above 1024, e.g., ${colorize("--port=27017", "cyan")}.`);
4093
+ } else if (error.message.includes("Failed to connect to remote")) {
4094
+ console.log("");
4095
+ console.log(`${colorize("Hint:", "yellow")} Could not connect to the remote worker.`);
4096
+ console.log(` Check that the URL is correct and the worker is running.`);
4097
+ }
4098
+ } else {
4099
+ printError("An unexpected error occurred");
215
4100
  }
4101
+ process.exit(1);
4102
+ }
216
4103
  }
217
- // Run the CLI
218
4104
  main();
4105
+ //# sourceMappingURL=index.js.map
219
4106
  //# sourceMappingURL=index.js.map