atoo-studio 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.github.md +322 -0
- package/README.md +112 -0
- package/README.npm.md +112 -0
- package/bin/atoo-studio.js +90 -0
- package/dist/src/agents/claude-code-terminal/adapter.d.ts +42 -0
- package/dist/src/agents/claude-code-terminal/adapter.js +166 -0
- package/dist/src/agents/claude-code-terminal/index.d.ts +13 -0
- package/dist/src/agents/claude-code-terminal/index.js +45 -0
- package/dist/src/agents/claude-code-terminal/spawner.d.ts +9 -0
- package/dist/src/agents/claude-code-terminal/spawner.js +37 -0
- package/dist/src/agents/claude-code-terminal-chatro/adapter.d.ts +51 -0
- package/dist/src/agents/claude-code-terminal-chatro/adapter.js +301 -0
- package/dist/src/agents/claude-code-terminal-chatro/index.d.ts +13 -0
- package/dist/src/agents/claude-code-terminal-chatro/index.js +45 -0
- package/dist/src/agents/claude-code-terminal-chatro/jsonl-watcher.d.ts +67 -0
- package/dist/src/agents/claude-code-terminal-chatro/jsonl-watcher.js +431 -0
- package/dist/src/agents/claude-code-terminal-chatro/spawner.d.ts +9 -0
- package/dist/src/agents/claude-code-terminal-chatro/spawner.js +37 -0
- package/dist/src/agents/codex-terminal/adapter.d.ts +40 -0
- package/dist/src/agents/codex-terminal/adapter.js +160 -0
- package/dist/src/agents/codex-terminal/index.d.ts +13 -0
- package/dist/src/agents/codex-terminal/index.js +47 -0
- package/dist/src/agents/codex-terminal/spawner.d.ts +9 -0
- package/dist/src/agents/codex-terminal/spawner.js +56 -0
- package/dist/src/agents/codex-terminal-chatro/adapter.d.ts +58 -0
- package/dist/src/agents/codex-terminal-chatro/adapter.js +266 -0
- package/dist/src/agents/codex-terminal-chatro/index.d.ts +13 -0
- package/dist/src/agents/codex-terminal-chatro/index.js +50 -0
- package/dist/src/agents/codex-terminal-chatro/jsonl-watcher.d.ts +36 -0
- package/dist/src/agents/codex-terminal-chatro/jsonl-watcher.js +205 -0
- package/dist/src/agents/codex-terminal-chatro/spawner.d.ts +9 -0
- package/dist/src/agents/codex-terminal-chatro/spawner.js +57 -0
- package/dist/src/agents/lib/chain-builder.d.ts +21 -0
- package/dist/src/agents/lib/chain-builder.js +139 -0
- package/dist/src/agents/lib/claude/fs-sessions.d.ts +31 -0
- package/dist/src/agents/lib/claude/fs-sessions.js +329 -0
- package/dist/src/agents/lib/claude/jsonl-writer.d.ts +32 -0
- package/dist/src/agents/lib/claude/jsonl-writer.js +342 -0
- package/dist/src/agents/lib/claude/workspace-trust.d.ts +1 -0
- package/dist/src/agents/lib/claude/workspace-trust.js +29 -0
- package/dist/src/agents/lib/codex/fs-sessions.d.ts +34 -0
- package/dist/src/agents/lib/codex/fs-sessions.js +255 -0
- package/dist/src/agents/lib/codex/jsonl-mapper.d.ts +11 -0
- package/dist/src/agents/lib/codex/jsonl-mapper.js +154 -0
- package/dist/src/agents/lib/codex/jsonl-writer.d.ts +8 -0
- package/dist/src/agents/lib/codex/jsonl-writer.js +440 -0
- package/dist/src/agents/lib/fs-tracking.d.ts +36 -0
- package/dist/src/agents/lib/fs-tracking.js +109 -0
- package/dist/src/agents/lib/pty-activity-tracker.d.ts +37 -0
- package/dist/src/agents/lib/pty-activity-tracker.js +105 -0
- package/dist/src/agents/lib/session-id-utils.d.ts +46 -0
- package/dist/src/agents/lib/session-id-utils.js +147 -0
- package/dist/src/agents/lib/session-precreate.d.ts +17 -0
- package/dist/src/agents/lib/session-precreate.js +177 -0
- package/dist/src/agents/registry.d.ts +72 -0
- package/dist/src/agents/registry.js +337 -0
- package/dist/src/agents/types.d.ts +135 -0
- package/dist/src/agents/types.js +1 -0
- package/dist/src/auth/crypto-key.d.ts +6 -0
- package/dist/src/auth/crypto-key.js +45 -0
- package/dist/src/auth/middleware.d.ts +18 -0
- package/dist/src/auth/middleware.js +54 -0
- package/dist/src/auth/password.d.ts +2 -0
- package/dist/src/auth/password.js +12 -0
- package/dist/src/auth/session.d.ts +10 -0
- package/dist/src/auth/session.js +33 -0
- package/dist/src/auth/totp.d.ts +12 -0
- package/dist/src/auth/totp.js +61 -0
- package/dist/src/auth/webauthn.d.ts +6 -0
- package/dist/src/auth/webauthn.js +117 -0
- package/dist/src/config.d.ts +10 -0
- package/dist/src/config.js +16 -0
- package/dist/src/database/connection-manager.d.ts +25 -0
- package/dist/src/database/connection-manager.js +211 -0
- package/dist/src/database/discovery/container.d.ts +6 -0
- package/dist/src/database/discovery/container.js +226 -0
- package/dist/src/database/discovery/env-parser.d.ts +9 -0
- package/dist/src/database/discovery/env-parser.js +525 -0
- package/dist/src/database/discovery/local-files.d.ts +6 -0
- package/dist/src/database/discovery/local-files.js +58 -0
- package/dist/src/database/discovery/port-scan.d.ts +7 -0
- package/dist/src/database/discovery/port-scan.js +61 -0
- package/dist/src/database/drivers/cassandra.d.ts +12 -0
- package/dist/src/database/drivers/cassandra.js +91 -0
- package/dist/src/database/drivers/clickhouse.d.ts +11 -0
- package/dist/src/database/drivers/clickhouse.js +127 -0
- package/dist/src/database/drivers/elasticsearch.d.ts +12 -0
- package/dist/src/database/drivers/elasticsearch.js +169 -0
- package/dist/src/database/drivers/influxdb.d.ts +14 -0
- package/dist/src/database/drivers/influxdb.js +194 -0
- package/dist/src/database/drivers/memcached.d.ts +11 -0
- package/dist/src/database/drivers/memcached.js +117 -0
- package/dist/src/database/drivers/mongodb.d.ts +12 -0
- package/dist/src/database/drivers/mongodb.js +128 -0
- package/dist/src/database/drivers/mysql.d.ts +11 -0
- package/dist/src/database/drivers/mysql.js +112 -0
- package/dist/src/database/drivers/neo4j.d.ts +11 -0
- package/dist/src/database/drivers/neo4j.js +158 -0
- package/dist/src/database/drivers/postgresql.d.ts +11 -0
- package/dist/src/database/drivers/postgresql.js +133 -0
- package/dist/src/database/drivers/redis.d.ts +11 -0
- package/dist/src/database/drivers/redis.js +91 -0
- package/dist/src/database/drivers/sqlite.d.ts +10 -0
- package/dist/src/database/drivers/sqlite.js +100 -0
- package/dist/src/database/query-stream.d.ts +5 -0
- package/dist/src/database/query-stream.js +75 -0
- package/dist/src/database/types.d.ts +71 -0
- package/dist/src/database/types.js +1 -0
- package/dist/src/events/index.d.ts +3 -0
- package/dist/src/events/index.js +3 -0
- package/dist/src/events/types.d.ts +214 -0
- package/dist/src/events/types.js +22 -0
- package/dist/src/events/wire.d.ts +114 -0
- package/dist/src/events/wire.js +296 -0
- package/dist/src/fs-monitor-types.d.ts +24 -0
- package/dist/src/fs-monitor-types.js +1 -0
- package/dist/src/fs-monitor.d.ts +80 -0
- package/dist/src/fs-monitor.js +637 -0
- package/dist/src/handlers/auth.d.ts +1 -0
- package/dist/src/handlers/auth.js +170 -0
- package/dist/src/handlers/changes.d.ts +1 -0
- package/dist/src/handlers/changes.js +203 -0
- package/dist/src/handlers/containers.d.ts +12 -0
- package/dist/src/handlers/containers.js +379 -0
- package/dist/src/handlers/databases.d.ts +3 -0
- package/dist/src/handlers/databases.js +327 -0
- package/dist/src/handlers/environments.d.ts +3 -0
- package/dist/src/handlers/environments.js +286 -0
- package/dist/src/handlers/github.d.ts +1 -0
- package/dist/src/handlers/github.js +153 -0
- package/dist/src/handlers/projects.d.ts +1 -0
- package/dist/src/handlers/projects.js +895 -0
- package/dist/src/handlers/ssh.d.ts +1 -0
- package/dist/src/handlers/ssh.js +162 -0
- package/dist/src/handlers/users.d.ts +1 -0
- package/dist/src/handlers/users.js +195 -0
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.js +228 -0
- package/dist/src/mcp/config.d.ts +32 -0
- package/dist/src/mcp/config.js +227 -0
- package/dist/src/mcp/server.d.ts +1 -0
- package/dist/src/mcp/server.js +574 -0
- package/dist/src/serial/cuse-device.d.ts +19 -0
- package/dist/src/serial/cuse-device.js +260 -0
- package/dist/src/serial/manager.d.ts +63 -0
- package/dist/src/serial/manager.js +206 -0
- package/dist/src/serial/pty-pair.d.ts +16 -0
- package/dist/src/serial/pty-pair.js +68 -0
- package/dist/src/services/fs-browser.d.ts +14 -0
- package/dist/src/services/fs-browser.js +98 -0
- package/dist/src/services/git-ops.d.ts +78 -0
- package/dist/src/services/git-ops.js +288 -0
- package/dist/src/services/github-ops.d.ts +104 -0
- package/dist/src/services/github-ops.js +192 -0
- package/dist/src/services/obfuscation.d.ts +2 -0
- package/dist/src/services/obfuscation.js +16 -0
- package/dist/src/services/preview/headless-backend.d.ts +62 -0
- package/dist/src/services/preview/headless-backend.js +698 -0
- package/dist/src/services/preview/injected-scripts.d.ts +9 -0
- package/dist/src/services/preview/injected-scripts.js +232 -0
- package/dist/src/services/preview/preview-backend.d.ts +92 -0
- package/dist/src/services/preview/preview-backend.js +15 -0
- package/dist/src/services/preview/universal-setter.d.ts +7 -0
- package/dist/src/services/preview/universal-setter.js +46 -0
- package/dist/src/services/preview-manager.d.ts +50 -0
- package/dist/src/services/preview-manager.js +216 -0
- package/dist/src/services/project-watcher.d.ts +6 -0
- package/dist/src/services/project-watcher.js +307 -0
- package/dist/src/services/remote-fs-browser.d.ts +11 -0
- package/dist/src/services/remote-fs-browser.js +50 -0
- package/dist/src/services/remote-git-ops.d.ts +71 -0
- package/dist/src/services/remote-git-ops.js +215 -0
- package/dist/src/services/session-search.d.ts +56 -0
- package/dist/src/services/session-search.js +303 -0
- package/dist/src/services/ssh-manager.d.ts +44 -0
- package/dist/src/services/ssh-manager.js +359 -0
- package/dist/src/session-writer.d.ts +9 -0
- package/dist/src/session-writer.js +66 -0
- package/dist/src/spawner.d.ts +56 -0
- package/dist/src/spawner.js +135 -0
- package/dist/src/state/db.d.ts +214 -0
- package/dist/src/state/db.js +897 -0
- package/dist/src/state/store.d.ts +37 -0
- package/dist/src/state/store.js +108 -0
- package/dist/src/state/types.d.ts +13 -0
- package/dist/src/state/types.js +1 -0
- package/dist/src/web/devtools-proxy.d.ts +7 -0
- package/dist/src/web/devtools-proxy.js +176 -0
- package/dist/src/web/port-proxy.d.ts +15 -0
- package/dist/src/web/port-proxy.js +124 -0
- package/dist/src/web/preview-ws.d.ts +5 -0
- package/dist/src/web/preview-ws.js +207 -0
- package/dist/src/web/server.d.ts +6 -0
- package/dist/src/web/server.js +1694 -0
- package/dist/src/ws/agent-ws.d.ts +5 -0
- package/dist/src/ws/agent-ws.js +93 -0
- package/frontend/dist/assets/_basePickBy-B-LibQ4-.js +1 -0
- package/frontend/dist/assets/_baseUniq-CprifHap.js +1 -0
- package/frontend/dist/assets/_createAssigner-ByDUqGii.js +1 -0
- package/frontend/dist/assets/abap-DuT-3z4x.js +1 -0
- package/frontend/dist/assets/addon-fit-CxQet2ja.js +1 -0
- package/frontend/dist/assets/addon-web-links-D_jRkPIl.js +1 -0
- package/frontend/dist/assets/apex-B-em86xX.js +1 -0
- package/frontend/dist/assets/api-SUPuHhSY.js +2 -0
- package/frontend/dist/assets/arc-Z0_eVteO.js +1 -0
- package/frontend/dist/assets/architecture-PBZL5I3N-hvVXGhqd.js +1 -0
- package/frontend/dist/assets/architectureDiagram-2XIMDMQ5-DiHPxX4j.js +36 -0
- package/frontend/dist/assets/array-CwG8vNfn.js +1 -0
- package/frontend/dist/assets/auth-store-R7eW5SVu.js +1 -0
- package/frontend/dist/assets/azcli-Bg9wQloi.js +1 -0
- package/frontend/dist/assets/bat-BM46z99L.js +1 -0
- package/frontend/dist/assets/bicep-DcBsJUfh.js +2 -0
- package/frontend/dist/assets/blockDiagram-WCTKOSBZ-C40u_hLo.js +132 -0
- package/frontend/dist/assets/c4Diagram-IC4MRINW-Ct7LjWFQ.js +10 -0
- package/frontend/dist/assets/cameligo-zw7JTtim.js +1 -0
- package/frontend/dist/assets/channel-ClCsE6HN.js +1 -0
- package/frontend/dist/assets/chunk-4BX2VUAB-zZ6P90VO.js +1 -0
- package/frontend/dist/assets/chunk-55IACEB6-DXllTDQl.js +1 -0
- package/frontend/dist/assets/chunk-7E7YKBS2-7zRaOLjj.js +1 -0
- package/frontend/dist/assets/chunk-7R4GIKGN-Csst1274.js +80 -0
- package/frontend/dist/assets/chunk-C72U2L5F-_JbQPbLN.js +1 -0
- package/frontend/dist/assets/chunk-CFjPhJqf.js +1 -0
- package/frontend/dist/assets/chunk-EGIJ26TM-B--aFyPw.js +1 -0
- package/frontend/dist/assets/chunk-FMBD7UC4-DVR34RNb.js +15 -0
- package/frontend/dist/assets/chunk-GEFDOKGD-CnmN6cC8.js +2 -0
- package/frontend/dist/assets/chunk-JSJVCQXG-CWxHBzeJ.js +1 -0
- package/frontend/dist/assets/chunk-KX2RTZJC-DkRk56s7.js +1 -0
- package/frontend/dist/assets/chunk-KYZI473N-DCCsG2dK.js +53 -0
- package/frontend/dist/assets/chunk-L3YUKLVL-C-DkZTMr.js +1 -0
- package/frontend/dist/assets/chunk-MX3YWQON-OUdzv5sZ.js +1 -0
- package/frontend/dist/assets/chunk-NQ4KR5QH-Bpu9FsM7.js +220 -0
- package/frontend/dist/assets/chunk-O4XLMI2P-BMLK6_ib.js +7 -0
- package/frontend/dist/assets/chunk-OZEHJAEY-CNNiJtG0.js +1 -0
- package/frontend/dist/assets/chunk-PQ6SQG4A-evVHD3KM.js +1 -0
- package/frontend/dist/assets/chunk-PU5JKC2W-DPFTYuvl.js +70 -0
- package/frontend/dist/assets/chunk-QZHKN3VN-JRdddPvu.js +1 -0
- package/frontend/dist/assets/chunk-R5LLSJPH-CHQzVVOV.js +1 -0
- package/frontend/dist/assets/chunk-WL4C6EOR-BNFU6IIi.js +189 -0
- package/frontend/dist/assets/chunk-XIRO2GV7-98T93G85.js +1 -0
- package/frontend/dist/assets/chunk-XZSTWKYB-BcW3cyNp.js +94 -0
- package/frontend/dist/assets/chunk-YBOYWFTD-BgKO1qAJ.js +1 -0
- package/frontend/dist/assets/classDiagram-VBA2DB6C-DikXzgcD.js +1 -0
- package/frontend/dist/assets/classDiagram-v2-RAHNMMFH-D7E3tQUK.js +1 -0
- package/frontend/dist/assets/clojure-FspFoNNQ.js +1 -0
- package/frontend/dist/assets/clone-mOXuZa7C.js +1 -0
- package/frontend/dist/assets/codicon-ngg6Pgfi.ttf +0 -0
- package/frontend/dist/assets/coffee-13n8Bk2W.js +1 -0
- package/frontend/dist/assets/cose-bilkent-S5V4N54A-zUOWQqLe.js +1 -0
- package/frontend/dist/assets/cpp-BVm2xGEs.js +1 -0
- package/frontend/dist/assets/csharp-D2kAWmUm.js +1 -0
- package/frontend/dist/assets/csp-Ezvgpf0e.js +1 -0
- package/frontend/dist/assets/css-CYxRwcFy.js +3 -0
- package/frontend/dist/assets/css.worker-Cd5h-ZOL.js +89 -0
- package/frontend/dist/assets/cssMode-CrXej49V.js +1 -0
- package/frontend/dist/assets/cypher-jg3SGErc.js +1 -0
- package/frontend/dist/assets/cytoscape.esm-kyyvzxNV.js +321 -0
- package/frontend/dist/assets/dagre-DH4bgZO7.js +1 -0
- package/frontend/dist/assets/dagre-KLK3FWXG-DNSqDkwT.js +4 -0
- package/frontend/dist/assets/dart-179jqhK4.js +1 -0
- package/frontend/dist/assets/defaultLocale-Dda4OpKy.js +1 -0
- package/frontend/dist/assets/diagram-E7M64L7V-RqPNT5Vs.js +24 -0
- package/frontend/dist/assets/diagram-IFDJBPK2-B-5NRyaE.js +43 -0
- package/frontend/dist/assets/diagram-P4PSJMXO-BrP69Hk0.js +24 -0
- package/frontend/dist/assets/dist-CU_Nb1G5.js +1 -0
- package/frontend/dist/assets/dockerfile-CIAtSGxS.js +1 -0
- package/frontend/dist/assets/ecl-CGVKfDxD.js +1 -0
- package/frontend/dist/assets/editor-Br_kD0ds.css +1 -0
- package/frontend/dist/assets/editor.api2-YXkDn0Gm.js +872 -0
- package/frontend/dist/assets/editor.main-fBaXZjJ0.js +6 -0
- package/frontend/dist/assets/elixir-BZ-6w0y3.js +1 -0
- package/frontend/dist/assets/erDiagram-INFDFZHY-BYiB9NYg.js +70 -0
- package/frontend/dist/assets/flow9-CVuOjTMv.js +1 -0
- package/frontend/dist/assets/flowDiagram-PKNHOUZH-Cwq47rsR.js +162 -0
- package/frontend/dist/assets/freemarker2-DM-pztJU.js +3 -0
- package/frontend/dist/assets/fsharp-q0pGJYr6.js +1 -0
- package/frontend/dist/assets/ganttDiagram-A5KZAMGK-Dnx3szD9.js +292 -0
- package/frontend/dist/assets/gitGraph-HDMCJU4V-COlTQ7bA.js +1 -0
- package/frontend/dist/assets/gitGraphDiagram-K3NZZRJ6-BaUxboNc.js +65 -0
- package/frontend/dist/assets/go-dzSPfdEO.js +1 -0
- package/frontend/dist/assets/graphlib-kEFlkt3U.js +1 -0
- package/frontend/dist/assets/graphql-CG4OUoEV.js +1 -0
- package/frontend/dist/assets/handlebars-BbK53Vec.js +1 -0
- package/frontend/dist/assets/hcl-Cy14JPk3.js +1 -0
- package/frontend/dist/assets/html-DYtTQNOG.js +1 -0
- package/frontend/dist/assets/html.worker-BjVEKLoU.js +502 -0
- package/frontend/dist/assets/htmlMode-C6GTouth.js +1 -0
- package/frontend/dist/assets/index-DMLxes_u.js +157 -0
- package/frontend/dist/assets/index-DmzeqkB1.css +1 -0
- package/frontend/dist/assets/info-3K5VOQVL-DBtHyA4C.js +1 -0
- package/frontend/dist/assets/infoDiagram-LFFYTUFH-yBXLgMPI.js +2 -0
- package/frontend/dist/assets/ini-Pbg8HGVD.js +1 -0
- package/frontend/dist/assets/init-D6KNwrax.js +1 -0
- package/frontend/dist/assets/ishikawaDiagram-PHBUUO56-Bld4two_.js +70 -0
- package/frontend/dist/assets/java-BmVu6Qrl.js +1 -0
- package/frontend/dist/assets/javascript-PbfQEdcJ.js +1 -0
- package/frontend/dist/assets/journeyDiagram-4ABVD52K-4HyMd4R2.js +139 -0
- package/frontend/dist/assets/json.worker-DqU5Wxnl.js +58 -0
- package/frontend/dist/assets/jsonMode-CASsGppE.js +7 -0
- package/frontend/dist/assets/julia-3cGnieBq.js +1 -0
- package/frontend/dist/assets/kanban-definition-K7BYSVSG-DpgsZmpG.js +89 -0
- package/frontend/dist/assets/katex-CEw3x5bf.js +261 -0
- package/frontend/dist/assets/kotlin-BuWkVcfV.js +1 -0
- package/frontend/dist/assets/less-CJ_VPy2C.js +2 -0
- package/frontend/dist/assets/lexon-BygAuZPu.js +1 -0
- package/frontend/dist/assets/line-CA_wh_TY.js +1 -0
- package/frontend/dist/assets/linear-BAcLW45z.js +1 -0
- package/frontend/dist/assets/liquid-kz84dle6.js +1 -0
- package/frontend/dist/assets/lspLanguageFeatures-C7hAHFn1.js +4 -0
- package/frontend/dist/assets/lua-C8Xs3dCx.js +1 -0
- package/frontend/dist/assets/m3-DTJeKBk4.js +1 -0
- package/frontend/dist/assets/markdown-QCgx8JqZ.js +1 -0
- package/frontend/dist/assets/math-D0YcMJAn.js +1 -0
- package/frontend/dist/assets/mdx-yRw0ap-E.js +1 -0
- package/frontend/dist/assets/mermaid-parser.core-DAeTodBQ.js +4 -0
- package/frontend/dist/assets/mindmap-definition-YRQLILUH-CoNlFyVl.js +68 -0
- package/frontend/dist/assets/mips-DopWaYgE.js +1 -0
- package/frontend/dist/assets/monaco.contribution-DeY0Qei-.js +2 -0
- package/frontend/dist/assets/msdax-BDis4ARV.js +1 -0
- package/frontend/dist/assets/mysql-BV6MLsOI.js +1 -0
- package/frontend/dist/assets/objective-c-B1UuzKs6.js +1 -0
- package/frontend/dist/assets/ordinal-jM7S0YHN.js +1 -0
- package/frontend/dist/assets/packet-RMMSAZCW-FF6-Tmai.js +1 -0
- package/frontend/dist/assets/pascal-BkvESCrc.js +1 -0
- package/frontend/dist/assets/pascaligo-lTy0kZYr.js +1 -0
- package/frontend/dist/assets/path-DNPd7Py7.js +1 -0
- package/frontend/dist/assets/perl-CrtUPXLV.js +1 -0
- package/frontend/dist/assets/pgsql-B9IbNWx2.js +1 -0
- package/frontend/dist/assets/php-CXvQBY2p.js +1 -0
- package/frontend/dist/assets/pie-UPGHQEXC-CFvXY2o-.js +1 -0
- package/frontend/dist/assets/pieDiagram-SKSYHLDU-CM_hbCcn.js +30 -0
- package/frontend/dist/assets/pla-DxBxuqWu.js +1 -0
- package/frontend/dist/assets/postiats-OkEuT5YF.js +1 -0
- package/frontend/dist/assets/powerquery-CMx5Tq4K.js +1 -0
- package/frontend/dist/assets/powershell-CstRxrEc.js +1 -0
- package/frontend/dist/assets/preload-helper-D4M6sveU.js +1 -0
- package/frontend/dist/assets/protobuf-Bx0Z-uRj.js +2 -0
- package/frontend/dist/assets/pug--W8vanWl.js +1 -0
- package/frontend/dist/assets/python-DA0rnlw3.js +1 -0
- package/frontend/dist/assets/qsharp-CRtr0YbN.js +1 -0
- package/frontend/dist/assets/quadrantDiagram-337W2JSQ-B3n3IUhC.js +7 -0
- package/frontend/dist/assets/r-C6E1d6iv.js +1 -0
- package/frontend/dist/assets/radar-KQ55EAFF-MPZu7SdX.js +1 -0
- package/frontend/dist/assets/razor-yd73uata.js +1 -0
- package/frontend/dist/assets/redis-Dx13voP3.js +1 -0
- package/frontend/dist/assets/redshift-D66HwlyV.js +1 -0
- package/frontend/dist/assets/requirementDiagram-Z7DCOOCP-CorP7L7F.js +73 -0
- package/frontend/dist/assets/restructuredtext-DQT2NKJ2.js +1 -0
- package/frontend/dist/assets/rough.esm-DxAX5Vpo.js +1 -0
- package/frontend/dist/assets/ruby-iFXI8hwH.js +1 -0
- package/frontend/dist/assets/rust-CSKiei34.js +1 -0
- package/frontend/dist/assets/sankeyDiagram-WA2Y5GQK-RDx6Bd-B.js +10 -0
- package/frontend/dist/assets/sb-Bo3ttdP2.js +1 -0
- package/frontend/dist/assets/scala-BC1D-Nxp.js +1 -0
- package/frontend/dist/assets/scheme-Z4OAo4Lv.js +1 -0
- package/frontend/dist/assets/scss-BvrdPs6B.js +3 -0
- package/frontend/dist/assets/sequenceDiagram-2WXFIKYE-JMqJSFq6.js +145 -0
- package/frontend/dist/assets/shell-Bh_aCyF-.js +1 -0
- package/frontend/dist/assets/solidity-CWHj6tSe.js +1 -0
- package/frontend/dist/assets/sophia-raoNtKtm.js +1 -0
- package/frontend/dist/assets/sparql-XzmoGnue.js +1 -0
- package/frontend/dist/assets/sql-BD0i9Gvg.js +1 -0
- package/frontend/dist/assets/src-Bn-kKzs7.js +1 -0
- package/frontend/dist/assets/st-DtVKyms6.js +1 -0
- package/frontend/dist/assets/stateDiagram-RAJIS63D-CgFfENdy.js +1 -0
- package/frontend/dist/assets/stateDiagram-v2-FVOUBMTO-C4Hh2P-U.js +1 -0
- package/frontend/dist/assets/swift--UZs77wT.js +1 -0
- package/frontend/dist/assets/systemverilog-CDnBSWUd.js +1 -0
- package/frontend/dist/assets/tcl-DdCEuTHZ.js +1 -0
- package/frontend/dist/assets/timeline-definition-YZTLITO2-BnatPBR5.js +61 -0
- package/frontend/dist/assets/treemap-KZPCXAKY-qb1Pl9la.js +1 -0
- package/frontend/dist/assets/ts.worker-DyPAEIuH.js +67719 -0
- package/frontend/dist/assets/tsMode-iuvyEpyO.js +11 -0
- package/frontend/dist/assets/twig-SSL-Altf.js +1 -0
- package/frontend/dist/assets/typescript-17918Hud.js +1 -0
- package/frontend/dist/assets/typespec-BT7S0ETg.js +1 -0
- package/frontend/dist/assets/vb-CrIgucua.js +1 -0
- package/frontend/dist/assets/vennDiagram-LZ73GAT5-DygS4Zzd.js +34 -0
- package/frontend/dist/assets/wgsl-BeKc3oEp.js +298 -0
- package/frontend/dist/assets/workers-DTfwKVoM.js +1 -0
- package/frontend/dist/assets/xml-CBMr_Wbw.js +1 -0
- package/frontend/dist/assets/xterm-BrP-ENHg.css +1 -0
- package/frontend/dist/assets/xterm-CBX2m0YM.js +36 -0
- package/frontend/dist/assets/xychartDiagram-JWTSCODW-D6wY1Jwd.js +7 -0
- package/frontend/dist/assets/yaml-CTjCH7Bv.js +1 -0
- package/frontend/dist/fonts/inter-300.ttf +0 -0
- package/frontend/dist/fonts/inter-400.ttf +0 -0
- package/frontend/dist/fonts/inter-500.ttf +0 -0
- package/frontend/dist/fonts/inter-600.ttf +0 -0
- package/frontend/dist/fonts/inter-700.ttf +0 -0
- package/frontend/dist/index.html +49 -0
- package/frontend/dist/logo_192x192.png +0 -0
- package/frontend/dist/logo_32x32.png +0 -0
- package/frontend/dist/logo_512x512.png +0 -0
- package/frontend/dist/logo_64x64.png +0 -0
- package/frontend/dist/logobg_192x192.png +0 -0
- package/frontend/dist/logobg_512x512.png +0 -0
- package/frontend/dist/logobg_64x64.png +0 -0
- package/frontend/dist/manifest.json +25 -0
- package/frontend/dist/sw.js +22 -0
- package/package.json +74 -7
- package/preload/Makefile +12 -0
- package/preload/atoo-studio-preload.c +647 -0
- package/preload/atoo-studio-preload.so +0 -0
- package/setup-cuse.sh +260 -0
- package/setup.sh +81 -0
- package/src/serial/native/binding.gyp +10 -0
- package/src/serial/native/pty_pair.c +222 -0
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import argon2 from 'argon2';
|
|
2
|
+
export async function hashPassword(plain) {
|
|
3
|
+
return argon2.hash(plain, {
|
|
4
|
+
type: argon2.argon2id,
|
|
5
|
+
memoryCost: 65536,
|
|
6
|
+
timeCost: 3,
|
|
7
|
+
parallelism: 1,
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
export async function verifyPassword(plain, hash) {
|
|
11
|
+
return argon2.verify(hash, plain);
|
|
12
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type User } from '../state/db.js';
|
|
2
|
+
import type { Request, Response } from 'express';
|
|
3
|
+
export declare const SESSION_COOKIE_NAME = "atoo_studio_sid";
|
|
4
|
+
export declare const SESSION_MAX_AGE: number;
|
|
5
|
+
export declare function createSession(userId: string, req: Request): string;
|
|
6
|
+
export declare function getSessionUser(sessionId: string): User | null;
|
|
7
|
+
export declare function destroySession(sessionId: string): void;
|
|
8
|
+
export declare function destroyAllUserSessions(userId: string): void;
|
|
9
|
+
export declare function setSessionCookie(res: Response, sessionId: string): void;
|
|
10
|
+
export declare function clearSessionCookie(res: Response): void;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
2
|
+
import { db } from '../state/db.js';
|
|
3
|
+
export const SESSION_COOKIE_NAME = 'atoo_studio_sid';
|
|
4
|
+
export const SESSION_MAX_AGE = 30 * 24 * 60 * 60 * 1000; // 30 days
|
|
5
|
+
export function createSession(userId, req) {
|
|
6
|
+
const sessionId = uuidv4();
|
|
7
|
+
const expiresAt = new Date(Date.now() + SESSION_MAX_AGE).toISOString();
|
|
8
|
+
const ip = req.ip || req.socket.remoteAddress || '';
|
|
9
|
+
const ua = req.headers['user-agent'] || '';
|
|
10
|
+
db.createAuthSession(sessionId, userId, expiresAt, ip, ua);
|
|
11
|
+
return sessionId;
|
|
12
|
+
}
|
|
13
|
+
export function getSessionUser(sessionId) {
|
|
14
|
+
return db.getAuthSessionUser(sessionId);
|
|
15
|
+
}
|
|
16
|
+
export function destroySession(sessionId) {
|
|
17
|
+
db.deleteAuthSession(sessionId);
|
|
18
|
+
}
|
|
19
|
+
export function destroyAllUserSessions(userId) {
|
|
20
|
+
db.deleteAllUserAuthSessions(userId);
|
|
21
|
+
}
|
|
22
|
+
export function setSessionCookie(res, sessionId) {
|
|
23
|
+
res.cookie(SESSION_COOKIE_NAME, sessionId, {
|
|
24
|
+
httpOnly: true,
|
|
25
|
+
secure: true,
|
|
26
|
+
sameSite: 'strict',
|
|
27
|
+
maxAge: SESSION_MAX_AGE,
|
|
28
|
+
path: '/',
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
export function clearSessionCookie(res) {
|
|
32
|
+
res.clearCookie(SESSION_COOKIE_NAME, { path: '/' });
|
|
33
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare function generateTotpSecret(username: string): Promise<{
|
|
2
|
+
secret: string;
|
|
3
|
+
otpauthUri: string;
|
|
4
|
+
qrDataUrl: string;
|
|
5
|
+
}>;
|
|
6
|
+
export declare function verifyTotpToken(secret: string, token: string): boolean;
|
|
7
|
+
export declare function saveTotpSecret(userId: string, secret: string): void;
|
|
8
|
+
export declare function getTotpSecret(userId: string): string | null;
|
|
9
|
+
export declare function getUnverifiedTotpSecret(userId: string): string | null;
|
|
10
|
+
export declare function markTotpVerified(userId: string): void;
|
|
11
|
+
export declare function removeTotpSecret(userId: string): void;
|
|
12
|
+
export declare function hasTotpEnabled(userId: string): boolean;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { TOTP, Secret } from 'otpauth';
|
|
2
|
+
import QRCode from 'qrcode';
|
|
3
|
+
import { encrypt, decrypt } from './crypto-key.js';
|
|
4
|
+
import { db } from '../state/db.js';
|
|
5
|
+
const ISSUER = 'Atoo Studio';
|
|
6
|
+
export async function generateTotpSecret(username) {
|
|
7
|
+
const secret = new Secret({ size: 20 });
|
|
8
|
+
const totp = new TOTP({
|
|
9
|
+
issuer: ISSUER,
|
|
10
|
+
label: username,
|
|
11
|
+
algorithm: 'SHA1',
|
|
12
|
+
digits: 6,
|
|
13
|
+
period: 30,
|
|
14
|
+
secret,
|
|
15
|
+
});
|
|
16
|
+
const otpauthUri = totp.toString();
|
|
17
|
+
const qrDataUrl = await QRCode.toDataURL(otpauthUri);
|
|
18
|
+
return {
|
|
19
|
+
secret: secret.base32,
|
|
20
|
+
otpauthUri,
|
|
21
|
+
qrDataUrl,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
export function verifyTotpToken(secret, token) {
|
|
25
|
+
const totp = new TOTP({
|
|
26
|
+
issuer: ISSUER,
|
|
27
|
+
algorithm: 'SHA1',
|
|
28
|
+
digits: 6,
|
|
29
|
+
period: 30,
|
|
30
|
+
secret: Secret.fromBase32(secret),
|
|
31
|
+
});
|
|
32
|
+
// Allow 1 period of drift
|
|
33
|
+
const delta = totp.validate({ token, window: 1 });
|
|
34
|
+
return delta !== null;
|
|
35
|
+
}
|
|
36
|
+
export function saveTotpSecret(userId, secret) {
|
|
37
|
+
const encrypted = encrypt(secret);
|
|
38
|
+
db.saveTotpSecret(userId, encrypted);
|
|
39
|
+
}
|
|
40
|
+
export function getTotpSecret(userId) {
|
|
41
|
+
const row = db.getTotpSecret(userId);
|
|
42
|
+
if (!row || !row.verified)
|
|
43
|
+
return null;
|
|
44
|
+
return decrypt(row.secret_encrypted);
|
|
45
|
+
}
|
|
46
|
+
export function getUnverifiedTotpSecret(userId) {
|
|
47
|
+
const row = db.getTotpSecret(userId);
|
|
48
|
+
if (!row)
|
|
49
|
+
return null;
|
|
50
|
+
return decrypt(row.secret_encrypted);
|
|
51
|
+
}
|
|
52
|
+
export function markTotpVerified(userId) {
|
|
53
|
+
db.markTotpVerified(userId);
|
|
54
|
+
}
|
|
55
|
+
export function removeTotpSecret(userId) {
|
|
56
|
+
db.deleteTotpSecret(userId);
|
|
57
|
+
}
|
|
58
|
+
export function hasTotpEnabled(userId) {
|
|
59
|
+
const row = db.getTotpSecret(userId);
|
|
60
|
+
return !!row && !!row.verified;
|
|
61
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type User } from '../state/db.js';
|
|
2
|
+
export declare function getRegistrationOptions(user: User, rpID: string): Promise<import("@simplewebauthn/server").PublicKeyCredentialCreationOptionsJSON>;
|
|
3
|
+
export declare function verifyAndSaveRegistration(user: User, rpID: string, origin: string, response: any, deviceName?: string): Promise<boolean>;
|
|
4
|
+
export declare function getAuthOptions(userId: string, rpID: string): Promise<import("@simplewebauthn/server").PublicKeyCredentialRequestOptionsJSON>;
|
|
5
|
+
export declare function verifyAuth(userId: string, rpID: string, origin: string, response: any): Promise<boolean>;
|
|
6
|
+
export declare function getUsersWithPasskeys(): string[];
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { generateRegistrationOptions, verifyRegistrationResponse, generateAuthenticationOptions, verifyAuthenticationResponse, } from '@simplewebauthn/server';
|
|
2
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
3
|
+
import { db } from '../state/db.js';
|
|
4
|
+
const RP_NAME = 'Atoo Studio';
|
|
5
|
+
// In-memory challenge store (short-lived, keyed by usedId)
|
|
6
|
+
const challenges = new Map();
|
|
7
|
+
function storeChallenge(userId, challenge) {
|
|
8
|
+
challenges.set(userId, { challenge, expires: Date.now() + 5 * 60 * 1000 });
|
|
9
|
+
}
|
|
10
|
+
function getChallenge(userId) {
|
|
11
|
+
const entry = challenges.get(userId);
|
|
12
|
+
if (!entry || entry.expires < Date.now()) {
|
|
13
|
+
challenges.delete(userId);
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
challenges.delete(userId);
|
|
17
|
+
return entry.challenge;
|
|
18
|
+
}
|
|
19
|
+
export async function getRegistrationOptions(user, rpID) {
|
|
20
|
+
const existingPasskeys = db.listPasskeys(user.id);
|
|
21
|
+
const options = await generateRegistrationOptions({
|
|
22
|
+
rpName: RP_NAME,
|
|
23
|
+
rpID,
|
|
24
|
+
userName: user.username,
|
|
25
|
+
userDisplayName: user.display_name,
|
|
26
|
+
attestationType: 'none',
|
|
27
|
+
excludeCredentials: existingPasskeys.map((pk) => ({
|
|
28
|
+
id: pk.credential_id,
|
|
29
|
+
transports: pk.transports ? JSON.parse(pk.transports) : undefined,
|
|
30
|
+
})),
|
|
31
|
+
authenticatorSelection: {
|
|
32
|
+
residentKey: 'preferred',
|
|
33
|
+
userVerification: 'preferred',
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
storeChallenge(user.id, options.challenge);
|
|
37
|
+
return options;
|
|
38
|
+
}
|
|
39
|
+
export async function verifyAndSaveRegistration(user, rpID, origin, response, deviceName) {
|
|
40
|
+
const expectedChallenge = getChallenge(user.id);
|
|
41
|
+
if (!expectedChallenge)
|
|
42
|
+
return false;
|
|
43
|
+
let verification;
|
|
44
|
+
try {
|
|
45
|
+
verification = await verifyRegistrationResponse({
|
|
46
|
+
response,
|
|
47
|
+
expectedChallenge,
|
|
48
|
+
expectedOrigin: origin,
|
|
49
|
+
expectedRPID: rpID,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
if (!verification.verified || !verification.registrationInfo)
|
|
56
|
+
return false;
|
|
57
|
+
const { credential } = verification.registrationInfo;
|
|
58
|
+
db.createPasskey({
|
|
59
|
+
id: uuidv4(),
|
|
60
|
+
user_id: user.id,
|
|
61
|
+
credential_id: credential.id,
|
|
62
|
+
public_key: Buffer.from(credential.publicKey).toString('base64'),
|
|
63
|
+
counter: credential.counter,
|
|
64
|
+
transports: response.response?.transports ? JSON.stringify(response.response.transports) : null,
|
|
65
|
+
device_name: deviceName || null,
|
|
66
|
+
});
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
69
|
+
export async function getAuthOptions(userId, rpID) {
|
|
70
|
+
const passkeys = db.listPasskeys(userId);
|
|
71
|
+
const options = await generateAuthenticationOptions({
|
|
72
|
+
rpID,
|
|
73
|
+
allowCredentials: passkeys.map((pk) => ({
|
|
74
|
+
id: pk.credential_id,
|
|
75
|
+
transports: pk.transports ? JSON.parse(pk.transports) : undefined,
|
|
76
|
+
})),
|
|
77
|
+
userVerification: 'preferred',
|
|
78
|
+
});
|
|
79
|
+
storeChallenge(userId, options.challenge);
|
|
80
|
+
return options;
|
|
81
|
+
}
|
|
82
|
+
export async function verifyAuth(userId, rpID, origin, response) {
|
|
83
|
+
const expectedChallenge = getChallenge(userId);
|
|
84
|
+
if (!expectedChallenge)
|
|
85
|
+
return false;
|
|
86
|
+
// Find the credential being used
|
|
87
|
+
const credentialId = response.id;
|
|
88
|
+
const passkey = db.findPasskeyByCredentialId(credentialId);
|
|
89
|
+
if (!passkey || passkey.user_id !== userId)
|
|
90
|
+
return false;
|
|
91
|
+
let verification;
|
|
92
|
+
try {
|
|
93
|
+
verification = await verifyAuthenticationResponse({
|
|
94
|
+
response,
|
|
95
|
+
expectedChallenge,
|
|
96
|
+
expectedOrigin: origin,
|
|
97
|
+
expectedRPID: rpID,
|
|
98
|
+
credential: {
|
|
99
|
+
id: passkey.credential_id,
|
|
100
|
+
publicKey: Buffer.from(passkey.public_key, 'base64'),
|
|
101
|
+
counter: passkey.counter,
|
|
102
|
+
transports: passkey.transports ? JSON.parse(passkey.transports) : undefined,
|
|
103
|
+
},
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
if (!verification.verified)
|
|
110
|
+
return false;
|
|
111
|
+
// Update counter
|
|
112
|
+
db.updatePasskeyCounter(passkey.id, verification.authenticationInfo.newCounter);
|
|
113
|
+
return true;
|
|
114
|
+
}
|
|
115
|
+
export function getUsersWithPasskeys() {
|
|
116
|
+
return db.getUserIdsWithPasskeys();
|
|
117
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare const PROJECT_ROOT: string;
|
|
2
|
+
export declare const PROXY_PORT = 8081;
|
|
3
|
+
export declare const WEB_PORT = 3010;
|
|
4
|
+
export declare const CERTS_DIR: string;
|
|
5
|
+
export declare const CA_CERT_PATH: string;
|
|
6
|
+
export declare const CA_KEY_PATH: string;
|
|
7
|
+
export declare const WEB_CERT_PATH: string;
|
|
8
|
+
export declare const WEB_KEY_PATH: string;
|
|
9
|
+
export declare const CDP_PORT_START = 9300;
|
|
10
|
+
export declare const CDP_PORT_END = 9399;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import { fileURLToPath } from 'url';
|
|
3
|
+
// Resolve the project root — works for both tsx (src/config.ts) and compiled (dist/src/config.js)
|
|
4
|
+
const __config_dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
5
|
+
export const PROJECT_ROOT = __config_dirname.includes('/dist/src')
|
|
6
|
+
? path.resolve(__config_dirname, '../..') // dist/src/ → project root
|
|
7
|
+
: path.resolve(__config_dirname, '..'); // src/ → project root
|
|
8
|
+
export const PROXY_PORT = 8081;
|
|
9
|
+
export const WEB_PORT = 3010;
|
|
10
|
+
export const CERTS_DIR = path.join(PROJECT_ROOT, 'certs') + '/';
|
|
11
|
+
export const CA_CERT_PATH = `${CERTS_DIR}ca.pem`;
|
|
12
|
+
export const CA_KEY_PATH = `${CERTS_DIR}ca-key.pem`;
|
|
13
|
+
export const WEB_CERT_PATH = `${CERTS_DIR}web-cert.pem`;
|
|
14
|
+
export const WEB_KEY_PATH = `${CERTS_DIR}web-key.pem`;
|
|
15
|
+
export const CDP_PORT_START = 9300;
|
|
16
|
+
export const CDP_PORT_END = 9399;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { ConnectionParams, DbType, QueryResult, SchemaInfo, TableInfo } from './types.js';
|
|
2
|
+
declare class ConnectionManager {
|
|
3
|
+
private connections;
|
|
4
|
+
private cleanupInterval;
|
|
5
|
+
constructor();
|
|
6
|
+
connect(dbType: DbType, params: ConnectionParams, name?: string, readonly?: boolean): Promise<string>;
|
|
7
|
+
disconnect(connectionId: string): Promise<void>;
|
|
8
|
+
query(connectionId: string, sql: string, limit?: number, timeoutMs?: number): Promise<QueryResult>;
|
|
9
|
+
getTables(connectionId: string): Promise<TableInfo[]>;
|
|
10
|
+
describeTable(connectionId: string, table: string): Promise<SchemaInfo>;
|
|
11
|
+
getDatabases(connectionId: string): Promise<string[]>;
|
|
12
|
+
getActiveConnections(): Array<{
|
|
13
|
+
id: string;
|
|
14
|
+
name: string;
|
|
15
|
+
db_type: DbType;
|
|
16
|
+
connected: boolean;
|
|
17
|
+
readonly: boolean;
|
|
18
|
+
}>;
|
|
19
|
+
private getDefaultPort;
|
|
20
|
+
private getConn;
|
|
21
|
+
private cleanupIdle;
|
|
22
|
+
shutdown(): Promise<void>;
|
|
23
|
+
}
|
|
24
|
+
export declare const connectionManager: ConnectionManager;
|
|
25
|
+
export {};
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
2
|
+
// Tier 1 drivers — always available (deps already in package.json)
|
|
3
|
+
import { PostgreSQLDriver } from './drivers/postgresql.js';
|
|
4
|
+
import { SQLiteDriver } from './drivers/sqlite.js';
|
|
5
|
+
import { MySQLDriver } from './drivers/mysql.js';
|
|
6
|
+
import { RedisDriver } from './drivers/redis.js';
|
|
7
|
+
import { MongoDBDriver } from './drivers/mongodb.js';
|
|
8
|
+
import { sshManager } from '../services/ssh-manager.js';
|
|
9
|
+
// Tier 2+3 drivers — loaded lazily so missing npm packages don't crash the server
|
|
10
|
+
async function loadDriver(name) {
|
|
11
|
+
try {
|
|
12
|
+
switch (name) {
|
|
13
|
+
case 'elasticsearch': return (await import('./drivers/elasticsearch.js')).ElasticsearchDriver;
|
|
14
|
+
case 'clickhouse': return (await import('./drivers/clickhouse.js')).ClickHouseDriver;
|
|
15
|
+
case 'neo4j': return (await import('./drivers/neo4j.js')).Neo4jDriver;
|
|
16
|
+
case 'influxdb': return (await import('./drivers/influxdb.js')).InfluxDBDriver;
|
|
17
|
+
case 'cassandra': return (await import('./drivers/cassandra.js')).CassandraDriver;
|
|
18
|
+
case 'memcached': return (await import('./drivers/memcached.js')).MemcachedDriver;
|
|
19
|
+
default: throw new Error(`Unknown driver: ${name}`);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
catch (err) {
|
|
23
|
+
if (err.code === 'ERR_MODULE_NOT_FOUND' || err.code === 'MODULE_NOT_FOUND') {
|
|
24
|
+
throw new Error(`Driver for ${name} is not installed. Run: npm install ${getPackageName(name)}`);
|
|
25
|
+
}
|
|
26
|
+
throw err;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
function getPackageName(driver) {
|
|
30
|
+
const map = {
|
|
31
|
+
elasticsearch: '@elastic/elasticsearch',
|
|
32
|
+
clickhouse: '@clickhouse/client', neo4j: 'neo4j-driver',
|
|
33
|
+
influxdb: '@influxdata/influxdb-client', cassandra: 'cassandra-driver',
|
|
34
|
+
memcached: 'memjs',
|
|
35
|
+
};
|
|
36
|
+
return map[driver] || driver;
|
|
37
|
+
}
|
|
38
|
+
const IDLE_TIMEOUT_MS = 30 * 60 * 1000; // 30 minutes
|
|
39
|
+
/** Statements that modify data — blocked in readonly mode. */
|
|
40
|
+
const WRITE_PATTERN = /^\s*(INSERT|UPDATE|DELETE|DROP|CREATE|ALTER|TRUNCATE|REPLACE|MERGE|GRANT|REVOKE)\b/i;
|
|
41
|
+
async function createDriver(dbType) {
|
|
42
|
+
// Tier 1 — always available
|
|
43
|
+
switch (dbType) {
|
|
44
|
+
case 'postgresql':
|
|
45
|
+
case 'cockroachdb':
|
|
46
|
+
return new PostgreSQLDriver();
|
|
47
|
+
case 'sqlite':
|
|
48
|
+
return new SQLiteDriver();
|
|
49
|
+
case 'mysql':
|
|
50
|
+
case 'mariadb':
|
|
51
|
+
return new MySQLDriver();
|
|
52
|
+
case 'redis':
|
|
53
|
+
return new RedisDriver();
|
|
54
|
+
case 'mongodb':
|
|
55
|
+
return new MongoDBDriver();
|
|
56
|
+
}
|
|
57
|
+
// Tier 2+3 — lazy loaded
|
|
58
|
+
const driverMap = {
|
|
59
|
+
elasticsearch: 'elasticsearch', opensearch: 'elasticsearch',
|
|
60
|
+
clickhouse: 'clickhouse', neo4j: 'neo4j', influxdb: 'influxdb',
|
|
61
|
+
cassandra: 'cassandra', scylladb: 'cassandra', memcached: 'memcached',
|
|
62
|
+
};
|
|
63
|
+
const driverName = driverMap[dbType];
|
|
64
|
+
if (!driverName)
|
|
65
|
+
throw new Error(`Unsupported database type: ${dbType}`);
|
|
66
|
+
const DriverClass = await loadDriver(driverName);
|
|
67
|
+
return new DriverClass();
|
|
68
|
+
}
|
|
69
|
+
class ConnectionManager {
|
|
70
|
+
connections = new Map();
|
|
71
|
+
cleanupInterval;
|
|
72
|
+
constructor() {
|
|
73
|
+
this.cleanupInterval = setInterval(() => this.cleanupIdle(), 60_000);
|
|
74
|
+
}
|
|
75
|
+
async connect(dbType, params, name, readonly = false) {
|
|
76
|
+
const driver = await createDriver(dbType);
|
|
77
|
+
// SSH tunnel: if ssh_connection_id is specified, create a local port forward
|
|
78
|
+
let effectiveParams = { ...params };
|
|
79
|
+
if (params.ssh_connection_id) {
|
|
80
|
+
if (!sshManager.isConnected(params.ssh_connection_id)) {
|
|
81
|
+
throw new Error('SSH connection is not active. Connect to the SSH host first.');
|
|
82
|
+
}
|
|
83
|
+
const remotePort = params.ssh_remote_port || params.port || this.getDefaultPort(dbType);
|
|
84
|
+
const localPort = await sshManager.getOrCreateForwardTunnel(params.ssh_connection_id, remotePort);
|
|
85
|
+
// Override host/port to go through the tunnel
|
|
86
|
+
effectiveParams = { ...params, host: '127.0.0.1', port: localPort };
|
|
87
|
+
// Clear connection_string since we're routing through tunnel
|
|
88
|
+
delete effectiveParams.connection_string;
|
|
89
|
+
}
|
|
90
|
+
// For SQLite, enforce readonly at the driver level
|
|
91
|
+
if (readonly && dbType === 'sqlite') {
|
|
92
|
+
effectiveParams = { ...effectiveParams, _readonly: true };
|
|
93
|
+
}
|
|
94
|
+
await driver.connect(effectiveParams);
|
|
95
|
+
// For PostgreSQL/CockroachDB, set default transaction read-only
|
|
96
|
+
if (readonly && (dbType === 'postgresql' || dbType === 'cockroachdb')) {
|
|
97
|
+
try {
|
|
98
|
+
await driver.query('SET default_transaction_read_only = ON');
|
|
99
|
+
}
|
|
100
|
+
catch { }
|
|
101
|
+
}
|
|
102
|
+
// For MySQL/MariaDB, set read-only session variable
|
|
103
|
+
if (readonly && (dbType === 'mysql' || dbType === 'mariadb')) {
|
|
104
|
+
try {
|
|
105
|
+
await driver.query('SET SESSION TRANSACTION READ ONLY');
|
|
106
|
+
}
|
|
107
|
+
catch { }
|
|
108
|
+
}
|
|
109
|
+
const id = uuidv4();
|
|
110
|
+
this.connections.set(id, {
|
|
111
|
+
id,
|
|
112
|
+
db_type: dbType,
|
|
113
|
+
driver,
|
|
114
|
+
params,
|
|
115
|
+
name: name || `${dbType}@${params.host || params.filename || 'localhost'}`,
|
|
116
|
+
readonly,
|
|
117
|
+
created_at: Date.now(),
|
|
118
|
+
last_used: Date.now(),
|
|
119
|
+
});
|
|
120
|
+
return id;
|
|
121
|
+
}
|
|
122
|
+
async disconnect(connectionId) {
|
|
123
|
+
const conn = this.connections.get(connectionId);
|
|
124
|
+
if (!conn)
|
|
125
|
+
throw new Error('Connection not found');
|
|
126
|
+
await conn.driver.disconnect();
|
|
127
|
+
this.connections.delete(connectionId);
|
|
128
|
+
}
|
|
129
|
+
async query(connectionId, sql, limit = 100, timeoutMs) {
|
|
130
|
+
const conn = this.getConn(connectionId);
|
|
131
|
+
conn.last_used = Date.now();
|
|
132
|
+
// Enforce readonly at the application level as an extra safeguard
|
|
133
|
+
if (conn.readonly && WRITE_PATTERN.test(sql)) {
|
|
134
|
+
throw new Error('Connection is read-only. Write operations are not allowed.');
|
|
135
|
+
}
|
|
136
|
+
// Apply timeout if specified
|
|
137
|
+
if (timeoutMs && timeoutMs > 0) {
|
|
138
|
+
return Promise.race([
|
|
139
|
+
conn.driver.query(sql, limit),
|
|
140
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error(`Query timed out after ${timeoutMs}ms`)), timeoutMs)),
|
|
141
|
+
]);
|
|
142
|
+
}
|
|
143
|
+
return conn.driver.query(sql, limit);
|
|
144
|
+
}
|
|
145
|
+
async getTables(connectionId) {
|
|
146
|
+
const conn = this.getConn(connectionId);
|
|
147
|
+
conn.last_used = Date.now();
|
|
148
|
+
return conn.driver.getTables();
|
|
149
|
+
}
|
|
150
|
+
async describeTable(connectionId, table) {
|
|
151
|
+
const conn = this.getConn(connectionId);
|
|
152
|
+
conn.last_used = Date.now();
|
|
153
|
+
return conn.driver.describeTable(table);
|
|
154
|
+
}
|
|
155
|
+
async getDatabases(connectionId) {
|
|
156
|
+
const conn = this.getConn(connectionId);
|
|
157
|
+
conn.last_used = Date.now();
|
|
158
|
+
if (conn.driver.getDatabases)
|
|
159
|
+
return conn.driver.getDatabases();
|
|
160
|
+
return [];
|
|
161
|
+
}
|
|
162
|
+
getActiveConnections() {
|
|
163
|
+
return [...this.connections.values()].map(c => ({
|
|
164
|
+
id: c.id,
|
|
165
|
+
name: c.name,
|
|
166
|
+
db_type: c.db_type,
|
|
167
|
+
connected: c.driver.isConnected(),
|
|
168
|
+
readonly: c.readonly,
|
|
169
|
+
}));
|
|
170
|
+
}
|
|
171
|
+
getDefaultPort(dbType) {
|
|
172
|
+
const ports = {
|
|
173
|
+
postgresql: 5432, cockroachdb: 26257, mysql: 3306, mariadb: 3306,
|
|
174
|
+
redis: 6379, mongodb: 27017, elasticsearch: 9200, opensearch: 9200,
|
|
175
|
+
clickhouse: 8123, neo4j: 7687, influxdb: 8086, cassandra: 9042,
|
|
176
|
+
scylladb: 9042, memcached: 11211,
|
|
177
|
+
};
|
|
178
|
+
return ports[dbType] || 5432;
|
|
179
|
+
}
|
|
180
|
+
getConn(id) {
|
|
181
|
+
const conn = this.connections.get(id);
|
|
182
|
+
if (!conn)
|
|
183
|
+
throw new Error('Connection not found');
|
|
184
|
+
if (!conn.driver.isConnected())
|
|
185
|
+
throw new Error('Connection is closed');
|
|
186
|
+
return conn;
|
|
187
|
+
}
|
|
188
|
+
async cleanupIdle() {
|
|
189
|
+
const now = Date.now();
|
|
190
|
+
for (const [id, conn] of this.connections) {
|
|
191
|
+
if (now - conn.last_used > IDLE_TIMEOUT_MS) {
|
|
192
|
+
try {
|
|
193
|
+
await conn.driver.disconnect();
|
|
194
|
+
}
|
|
195
|
+
catch { }
|
|
196
|
+
this.connections.delete(id);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
async shutdown() {
|
|
201
|
+
clearInterval(this.cleanupInterval);
|
|
202
|
+
for (const conn of this.connections.values()) {
|
|
203
|
+
try {
|
|
204
|
+
await conn.driver.disconnect();
|
|
205
|
+
}
|
|
206
|
+
catch { }
|
|
207
|
+
}
|
|
208
|
+
this.connections.clear();
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
export const connectionManager = new ConnectionManager();
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { DiscoveredDatabase } from '../types.js';
|
|
2
|
+
export declare function discoverContainerDatabases(): Promise<DiscoveredDatabase[]>;
|
|
3
|
+
/**
|
|
4
|
+
* Parse docker-compose.yml for database services (without running containers).
|
|
5
|
+
*/
|
|
6
|
+
export declare function parseComposeFile(projectDir: string): DiscoveredDatabase[];
|