├── .gitignore
├── LICENSE
├── README.md
├── lua
├── dbout
│ ├── client.lua
│ ├── cmd.lua
│ ├── config.lua
│ ├── connection.lua
│ ├── init.lua
│ ├── keymap.lua
│ ├── rpc.lua
│ ├── saver.lua
│ ├── snacks.lua
│ ├── ui
│ │ ├── inspector.lua
│ │ ├── queryer.lua
│ │ ├── viewer.lua
│ │ └── winbar.lua
│ └── utils.lua
└── telescope
│ └── _extensions
│ └── dbout.lua
├── package-lock.json
├── package.json
├── server
├── consumer.js
├── db
│ ├── mssql.js
│ ├── mysql.js
│ ├── postgres.js
│ └── sqlite.js
├── driver.js
├── main.js
└── rpc.js
└── stylua.toml
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2025 zongben
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Dbout.nvim
2 |
3 | **dbout.nvim** is a Neovim plugin that helps you connect to databases, execute SQL queries, and display the results in **JSON format**.
4 | No need to switch to external tools — everything happens inside Neovim, making your workflow faster and smoother.
5 |
6 |
7 |
8 | https://github.com/user-attachments/assets/21d4295a-897b-422a-aa69-2d6cde4e555d
9 |
10 | ## Key Features
11 |
12 | - **JSON Result Display**: View query results in a structured JSON format for easy reading and further processing.
13 | - **No More Connection Strings In Your Neovim Config**: All your database connections are securely saved locally on your machine.
14 | - **LSP Support**: Use `sqls` as the SQL language server, and spins up separate LSP instances per database connection to avoid mixing completions across different databases.
15 |
16 | ## Supported Databases
17 |
18 | - SQLite
19 | - PostgreSQL
20 | - MySQL
21 | - MSSQL
22 |
23 | ## Installation
24 |
25 | Requirements:
26 |
27 | - [Nodejs](https://github.com/nodejs/node)
28 | - [sqls](https://github.com/sqls-server/sqls)
29 |
30 | `sqls` is recommended to be installed via [mason.nvim](https://github.com/mason-org/mason.nvim). If you are not using mason, make sure sqls is installed and available in your system PATH.
31 |
32 | With lazy.nvim:
33 |
34 | ```lua
35 | {
36 | "zongben/dbout.nvim",
37 | build = "npm install",
38 | lazy = "VeryLazy",
39 | cmd = { "Dbout" },
40 | config = function()
41 | require("dbout").setup({})
42 | end,
43 | }
44 | ```
45 |
46 | ## Configuration
47 |
48 | The default configuration is as follows:
49 |
50 | ```lua
51 | {
52 | keymaps = {
53 | queryer = {
54 | query = "",
55 | format = "",
56 | open_inspector = "",
57 | },
58 | viewer = {
59 | close = "q",
60 | },
61 | inspector = {
62 | close = "q",
63 | next_tab = "L",
64 | previous_tab = "H",
65 | inspect = "I",
66 | back = "",
67 | },
68 | },
69 | }
70 | ```
71 |
72 | ## Usage
73 |
74 | Use the following commands for database connection management:
75 |
76 | `:Dbout OpenConnection` - Open a new buffer and connect to selected database connection
77 | `:Dbout NewConnection` - Create a new database connection
78 | `:Dbout DeleteConnection` - Delete an existing connection
79 | `:Dbout EditConnection` - Edit an existing connection
80 | `:Dbout AttachConnection` - Attach to selected connection in the current buffer (this is very useful after opening a .sql file)
81 |
82 | After opening or attaching a connection, a buffer for that database connection is created, named Queryer.
83 | Inside the Queryer buffer:
84 |
85 | `F5` - Execute the current SQL query
86 | `F11` - Format SQL
87 | `F12` - Open Inspector
88 |
89 | The Inspector is a buffer used for inspecting database objects.
90 | Within the Inspector buffer:
91 |
92 | `H` and `L` - Switch between tabs
93 | `I` - Inspect more details, such as table columns, triggers, views, etc.
94 |
95 | ### Telescope Extension
96 |
97 | For users with Telescope installed, you can load the dbout extension for easier database connection management:
98 |
99 | ```lua
100 | require("telescope").load_extension("dbout")
101 |
102 | --default config
103 | require("telescope").setup({
104 | extensions = {
105 | dbout = {
106 | keymaps = {
107 | open_connection = "",
108 | new_connection = "n",
109 | delete_connection = "d",
110 | edit_connection = "e",
111 | attach_connection = "a",
112 | },
113 | },
114 | },
115 | })
116 | ```
117 |
118 | Then, you can open the database connection picker by calling `:Telescope dbout` or `require("telescope").extensions.dbout.dbout()`
119 |
120 | ### Snacks Sources
121 |
122 | For users with Snacks installed, dbout automatically registers its sources.
123 | You can open the database connection manager simply by calling `:Dbout`
124 |
125 | ```lua
126 | --default config
127 | require("dbout.snacks").setup({
128 | keymaps = {
129 | open_connection = "",
130 | new_connection = "n",
131 | delete_connection = "d",
132 | edit_connection = "e",
133 | attach_connection = "a",
134 | },
135 | })
136 |
137 | -- You can also configure the source:
138 | Snacks.picker.sources.dbout = {
139 | -- your options here
140 | -- For more details, see:
141 | -- https://github.com/folke/snacks.nvim/blob/main/docs/picker.md
142 | }
143 | ```
144 |
145 | ## NOTES
146 |
147 | When opening a connection, you might see an **Sqls connection error**.
148 | However, based on my tests, Sqls is actually connecting to the server successfully.
149 | This error message seems to be an issue with Sqls itself. For now, I’m not sure how to disable it, so I suggest simply ignoring this error message.
150 |
151 | --
152 |
153 | If you’re using [mason-lspconfig](https://github.com/mason-org/mason-lspconfig.nvim) to automatically start LSP servers, I recommend excluding sqls from it.
154 | dbout will automatically start sqls for you.
155 |
156 | ```lua
157 | require("mason-lspconfig").setup({
158 | automatic_enable = {
159 | exclude = {
160 | "sqls",
161 | },
162 | },
163 | })
164 | ```
165 |
166 | ## TODO
167 |
168 | - [ ] CSV output
169 | - [ ] query history
170 | - [ ] layout system
171 | - [ ] better LSP and tree sitting support
172 | - [ ] mongodb support
173 |
--------------------------------------------------------------------------------
/lua/dbout/client.lua:
--------------------------------------------------------------------------------
1 | local rpc = require("dbout.rpc")
2 |
3 | local send_rpc = function(method, param, cb)
4 | rpc.send_jsonrpc(method, param, function(jsonstr)
5 | cb(jsonstr)
6 | end)
7 | end
8 |
9 | local M = {}
10 |
11 | M.get_table_list = function(id, cb)
12 | send_rpc("get_table_list", { id = id }, cb)
13 | end
14 |
15 | M.get_view_list = function(id, cb)
16 | send_rpc("get_view_list", { id = id }, cb)
17 | end
18 |
19 | M.get_view = function(id, view_name, cb)
20 | send_rpc("get_view", { id = id, view_name = view_name }, cb)
21 | end
22 |
23 | M.get_store_procedure = function(id, procedure_name, cb)
24 | send_rpc("get_store_procedure", { id = id, procedure_name = procedure_name }, cb)
25 | end
26 |
27 | M.get_store_procedure_list = function(id, cb)
28 | send_rpc("get_store_procedure_list", { id = id }, cb)
29 | end
30 |
31 | M.get_function_list = function(id, cb)
32 | send_rpc("get_function_list", { id = id }, cb)
33 | end
34 |
35 | M.get_trigger_list = function(id, table_name, cb)
36 | send_rpc("get_trigger_list", { id = id, table_name = table_name }, cb)
37 | end
38 |
39 | M.get_function = function(id, function_name, cb)
40 | send_rpc("get_function", { id = id, function_name = function_name }, cb)
41 | end
42 |
43 | M.get_table = function(id, table_name, cb)
44 | send_rpc("get_table", { id = id, table_name = table_name }, cb)
45 | end
46 |
47 | M.get_trigger = function(id, trig_name, cb)
48 | send_rpc("get_trigger", { id = id, trig_name = trig_name }, cb)
49 | end
50 |
51 | M.generate_select_sql = function(id, table_name, cb)
52 | send_rpc("generate_select_sql", { id = id, table_name = table_name }, cb)
53 | end
54 |
55 | M.generate_update_sql = function(id, table_name, cb)
56 | send_rpc("generate_update_sql", { id = id, table_name = table_name }, cb)
57 | end
58 |
59 | M.generate_insert_sql = function(id, table_name, cb)
60 | send_rpc("generate_insert_sql", { id = id, table_name = table_name }, cb)
61 | end
62 |
63 | M.query = function(id, sql, cb)
64 | send_rpc("query", { id = id, sql = sql }, cb)
65 | end
66 |
67 | M.format = function(id, sql, cb)
68 | send_rpc("format", { id = id, sql = sql }, cb)
69 | end
70 |
71 | return M
72 |
--------------------------------------------------------------------------------
/lua/dbout/cmd.lua:
--------------------------------------------------------------------------------
1 | local rpc = require("dbout.rpc")
2 | local conn = require("dbout.connection")
3 | local queryer = require("dbout.ui.queryer")
4 |
5 | local args = {
6 | new_connection = "NewConnection",
7 | edit_connection = "EditConnection",
8 | delete_connection = "DeleteConnection",
9 | open_connection = "OpenConnection",
10 | attach_connection = "AttachConnection",
11 | }
12 |
13 | local select_connection = function(cb)
14 | vim.ui.select(conn.get_connections(), {
15 | prompt = "Choose a connection",
16 | format_item = function(item)
17 | return item.name .. " " .. item.db_type .. ":" .. item.connstr
18 | end,
19 | }, function(connection)
20 | if not connection then
21 | return
22 | end
23 | cb(connection)
24 | end)
25 | end
26 |
27 | local new_connection = function()
28 | conn.create_connection({}, function(c)
29 | conn.add_connection(c)
30 | end)
31 | end
32 |
33 | local edit_connection = function()
34 | select_connection(function(c)
35 | conn.create_connection(c, function(cn)
36 | conn.update_connection(cn)
37 | end)
38 | end)
39 | end
40 |
41 | local delete_connection = function()
42 | select_connection(function(c)
43 | conn.remove_connection(c.id)
44 | end)
45 | end
46 |
47 | local open_connection = function()
48 | select_connection(function(c)
49 | conn.open_connection(c, function()
50 | queryer.create_buf(c)
51 | end)
52 | end)
53 | end
54 |
55 | local attach_connection = function()
56 | select_connection(function(c)
57 | conn.open_connection(c, function()
58 | queryer.attach_buf(c, vim.api.nvim_get_current_buf())
59 | end)
60 | end)
61 | end
62 |
63 | local M = {}
64 |
65 | M.init = function()
66 | vim.api.nvim_create_user_command("Dbout", function(opts)
67 | if not rpc.is_alive() then
68 | rpc.server_up()
69 | end
70 |
71 | local cmd = opts.args
72 |
73 | if Snacks and cmd == "" then
74 | require("dbout.snacks").open_picker()
75 | end
76 |
77 | if cmd == args.new_connection then
78 | new_connection()
79 | elseif cmd == args.edit_connection then
80 | edit_connection()
81 | elseif cmd == args.delete_connection then
82 | delete_connection()
83 | elseif cmd == args.open_connection then
84 | open_connection()
85 | elseif cmd == args.attach_connection then
86 | attach_connection()
87 | end
88 | end, {
89 | nargs = "?",
90 | complete = function(_, line, pos)
91 | local arg = line:sub(pos + 1)
92 | local matches = {}
93 | for _, opt in pairs(args) do
94 | if opt:match("^" .. arg) then
95 | table.insert(matches, opt)
96 | end
97 | end
98 | return matches
99 | end,
100 | })
101 | end
102 |
103 | return M
104 |
--------------------------------------------------------------------------------
/lua/dbout/config.lua:
--------------------------------------------------------------------------------
1 | local M = {}
2 |
3 | M.defaults = {
4 | keymaps = {
5 | queryer = {
6 | query = "",
7 | open_inspector = "",
8 | format = "",
9 | },
10 | viewer = {
11 | close = "q",
12 | },
13 | inspector = {
14 | close = "q",
15 | next_tab = "L",
16 | previous_tab = "H",
17 | inspect = "I",
18 | back = "",
19 | },
20 | },
21 | }
22 |
23 | return M
24 |
--------------------------------------------------------------------------------
/lua/dbout/connection.lua:
--------------------------------------------------------------------------------
1 | local saver = require("dbout.saver")
2 | local utils = require("dbout.utils")
3 | local rpc = require("dbout.rpc")
4 |
5 | local connections = {}
6 | local supported_db = { "sqlite3", "postgresql", "mysql", "mssql" }
7 |
8 | local M = {}
9 |
10 | local save = function()
11 | saver.save(connections)
12 | end
13 |
14 | M.init = function()
15 | connections = saver.load() or {}
16 | end
17 |
18 | M.create_connection = function(connection, cb)
19 | local fn = function(db_type)
20 | local name = vim.fn.input("Enter name: ", connection.name or "")
21 | if name == "" then
22 | return
23 | end
24 |
25 | if M.is_conn_exists(connection.id or "", name) then
26 | vim.notify(name .. " is used.", vim.log.levels.ERROR)
27 | return
28 | end
29 |
30 | local connstr = vim.fn.input("Enter " .. db_type .. " connection string: ", connection.connstr or "")
31 | if connstr == "" then
32 | return
33 | end
34 |
35 | cb({
36 | id = connection.id or utils.generate_uuid(),
37 | name = name,
38 | db_type = db_type,
39 | connstr = connstr,
40 | })
41 | end
42 |
43 | if connection.id then
44 | fn(connection.db_type)
45 | return
46 | end
47 |
48 | vim.ui.select(M.get_supported_db(), {
49 | prompt = "Choose a database",
50 | }, function(db_type)
51 | if not db_type then
52 | return
53 | end
54 | fn(db_type)
55 | end)
56 | end
57 |
58 | M.is_conn_exists = function(id, name)
59 | return #vim.tbl_filter(function(c)
60 | return c.id ~= id and c.name == name
61 | end, connections) > 0
62 | end
63 |
64 | M.get_connections = function()
65 | return connections
66 | end
67 |
68 | M.get_supported_db = function()
69 | return supported_db
70 | end
71 |
72 | M.add_connection = function(conn)
73 | table.insert(connections, conn)
74 | save()
75 | end
76 |
77 | M.remove_connection = function(id)
78 | connections = vim.tbl_filter(function(c)
79 | return c.id ~= id
80 | end, connections)
81 | save()
82 | end
83 |
84 | M.update_connection = function(conn)
85 | for _, c in ipairs(connections) do
86 | if c.id == conn.id then
87 | c.name = conn.name
88 | c.db_type = conn.db_type
89 | c.connstr = conn.connstr
90 | save()
91 | return
92 | end
93 | end
94 | end
95 |
96 | M.open_connection = function(conn, cb)
97 | rpc.send_jsonrpc("create_connection", {
98 | id = conn.id,
99 | dbType = conn.db_type,
100 | connStr = conn.connstr,
101 | }, function()
102 | cb()
103 | end)
104 | end
105 |
106 | return M
107 |
--------------------------------------------------------------------------------
/lua/dbout/init.lua:
--------------------------------------------------------------------------------
1 | local config = require("dbout.config")
2 | local keymap = require("dbout.keymap")
3 | local cmd = require("dbout.cmd")
4 | local conn = require("dbout.connection")
5 | local queryer = require("dbout.ui.queryer")
6 |
7 | local M = {}
8 |
9 | M.setup = function(opts)
10 | M.options = vim.tbl_deep_extend("force", config.defaults, opts or {})
11 | conn.init()
12 | keymap.init(M.options.keymaps)
13 | queryer.init()
14 | cmd.init()
15 | end
16 |
17 | return M
18 |
--------------------------------------------------------------------------------
/lua/dbout/keymap.lua:
--------------------------------------------------------------------------------
1 | local viewer = require("dbout.ui.viewer")
2 | local queryer = require("dbout.ui.queryer")
3 | local inspector = require("dbout.ui.inspector")
4 |
5 | local M = {}
6 |
7 | local map = function(bufnr, mode, key, cb)
8 | if key == "" then
9 | return
10 | end
11 | vim.keymap.set(mode, key, cb, { buffer = bufnr, noremap = true, silent = true })
12 | end
13 |
14 | M.init = function(keymaps)
15 | queryer.buffer_keymappings = function(buf)
16 | local q = keymaps.queryer
17 | map(buf, { "i", "v", "n" }, q.query, queryer.query)
18 | map(buf, { "i", "v", "n" }, q.format, queryer.format)
19 | map(buf, { "i", "n" }, q.open_inspector, queryer.open_inspector)
20 | end
21 |
22 | viewer.buffer_keymappings = function(buf)
23 | local v = keymaps.viewer
24 | map(buf, { "n" }, v.close, viewer.close_viewer)
25 | end
26 |
27 | inspector.buffer_keymappings = function(buf)
28 | local i = keymaps.inspector
29 | map(buf, { "n" }, i.close, inspector.close_inspector)
30 | map(buf, { "n" }, i.next_tab, inspector.next_tab)
31 | map(buf, { "n" }, i.previous_tab, inspector.previous_tab)
32 | map(buf, { "n" }, i.inspect, inspector.inspect)
33 | map(buf, { "n" }, i.back, inspector.back)
34 | end
35 | end
36 |
37 | return M
38 |
--------------------------------------------------------------------------------
/lua/dbout/rpc.lua:
--------------------------------------------------------------------------------
1 | local utils = require("dbout.utils")
2 |
3 | local job_id
4 | local callbacks = {}
5 | local buffer = ""
6 |
7 | local M = {}
8 |
9 | M.server_up = function()
10 | local files = vim.api.nvim_get_runtime_file("server/main.js", false)
11 | job_id = vim.fn.jobstart({
12 | "node",
13 | files[1],
14 | }, {
15 | on_stdout = function(_, raw)
16 | for _, chunk in ipairs(raw) do
17 | buffer = buffer .. chunk
18 | end
19 |
20 | local ok, data = pcall(vim.fn.json_decode, buffer)
21 | if not ok then
22 | return
23 | else
24 | buffer = ""
25 | end
26 |
27 | if callbacks[data.id] then
28 | callbacks[data.id](data.result)
29 | callbacks[data.id] = nil
30 | end
31 | end,
32 | on_stderr = function(_, raw)
33 | local data = vim.fn.json_decode(raw)
34 | if data.id and callbacks[data.id] then
35 | callbacks[data.id] = nil
36 | end
37 | vim.notify(data.error.message .. "\n" .. data.error.data, vim.log.levels.ERROR)
38 | end,
39 | })
40 | end
41 |
42 | M.is_alive = function()
43 | return vim.fn.jobwait({ job_id }, 0)[1] == -1
44 | end
45 |
46 | M.send_jsonrpc = function(method, params, cb)
47 | local id = utils.generate_uuid()
48 | local jsonrpc = {
49 | jsonrpc = "2.0",
50 | id = id,
51 | method = method,
52 | params = params,
53 | }
54 | callbacks[id] = cb
55 | local json = vim.fn.json_encode(jsonrpc)
56 | -- vim.notify(json)
57 | vim.fn.chansend(job_id, json .. "\n")
58 | end
59 |
60 | M.send_notification = function(method, params)
61 | local jsonrpc = {
62 | jsonrpc = "2.0",
63 | method = method,
64 | params = params,
65 | }
66 | vim.fn.chansend(job_id, vim.fn.json_encode(jsonrpc) .. "\n")
67 | end
68 |
69 | return M
70 |
--------------------------------------------------------------------------------
/lua/dbout/saver.lua:
--------------------------------------------------------------------------------
1 | local M = {}
2 |
3 | local statepath = vim.fn.stdpath("state")
4 | if type(statepath) == "table" then
5 | statepath = statepath[1]
6 | end
7 | local state_dir = vim.fs.joinpath(statepath, "dbout")
8 | local persist_file = vim.fs.joinpath(state_dir, "db_explorer.json")
9 |
10 | M.save = function(connection)
11 | local json = vim.fn.json_encode(connection)
12 | vim.fn.mkdir(state_dir, "p")
13 | vim.fn.writefile({ json }, persist_file)
14 | end
15 |
16 | M.load = function()
17 | local f = io.open(persist_file, "r")
18 | if not f then
19 | return
20 | end
21 | local content = f:read("*a")
22 | f:close()
23 | return vim.fn.json_decode(content)
24 | end
25 |
26 | return M
27 |
--------------------------------------------------------------------------------
/lua/dbout/snacks.lua:
--------------------------------------------------------------------------------
1 | local conn = require("dbout.connection")
2 | local queryer = require("dbout.ui.queryer")
3 |
4 | local function truncate(text, width)
5 | if #text > width then
6 | return text:sub(1, width - 1) .. "…"
7 | end
8 | return text
9 | end
10 |
11 | local options = {
12 | keymaps = {
13 | open_connection = "",
14 | new_connection = "n",
15 | delete_connection = "d",
16 | edit_connection = "e",
17 | attach_connection = "a",
18 | },
19 | }
20 |
21 | local M = {}
22 |
23 | M.setup = function(opts)
24 | options = vim.tbl_deep_extend("force", options, opts or {})
25 | end
26 |
27 | M.open_picker = function()
28 | ---@class snacks.picker.Config
29 | local config = {
30 | source = "dbout",
31 | title = "Connections",
32 | preview = "none",
33 | layout = {
34 | preset = "select",
35 | },
36 | finder = function()
37 | local items = {}
38 | for index, value in ipairs(conn.get_connections()) do
39 | table.insert(items, {
40 | idx = index,
41 | name = value.name,
42 | text = value.name,
43 | id = value.id,
44 | connstr = value.connstr,
45 | db_type = value.db_type,
46 | })
47 | end
48 | return items
49 | end,
50 | format = function(item)
51 | return {
52 | { string.format("%-15s", truncate(item.name, 15)), "SnacksPickerLabel" },
53 | { item.db_type .. ":" .. item.connstr, "SnacksPickerComment" },
54 | }
55 | end,
56 | win = {
57 | input = {
58 | keys = {
59 | [options.keymaps.open_connection] = { "open_connection", mode = { "n" } },
60 | [options.keymaps.new_connection] = { "new_connection", mode = { "n" } },
61 | [options.keymaps.delete_connection] = { "delete_connection", mode = { "n" } },
62 | [options.keymaps.edit_connection] = { "edit_connection", mode = { "n" } },
63 | [options.keymaps.attach_connection] = { "attach_connection", mode = { "n" } },
64 | },
65 | },
66 | },
67 | actions = {
68 | confirm = function() end,
69 | new_connection = function(picker)
70 | picker:close()
71 | conn.create_connection({}, function(c)
72 | conn.add_connection(c)
73 | M.open_picker()
74 | end)
75 | end,
76 | delete_connection = function(picker, item)
77 | conn.remove_connection(item.id)
78 | picker:find()
79 | end,
80 | edit_connection = function(picker, item)
81 | conn.create_connection(item, function(c)
82 | conn.update_connection(c)
83 | picker:find()
84 | end)
85 | end,
86 | open_connection = function(picker, item)
87 | conn.open_connection(item, function()
88 | picker:close()
89 | queryer.create_buf(item)
90 | end)
91 | end,
92 | attach_connection = function(picker, item)
93 | conn.open_connection(item, function()
94 | picker:close()
95 | queryer.attach_buf(item, vim.api.nvim_get_current_buf())
96 | end)
97 | end,
98 | },
99 | }
100 |
101 | Snacks.picker.pick(config)
102 | end
103 |
104 | return M
105 |
--------------------------------------------------------------------------------
/lua/dbout/ui/inspector.lua:
--------------------------------------------------------------------------------
1 | local utils = require("dbout.utils")
2 | local client = require("dbout.client")
3 | local winbar = require("dbout.ui.winbar")
4 |
5 | local inspector_bufnr
6 | local conn
7 | local queryer_bufnr
8 |
9 | local set_inspector_buf = function()
10 | local tab = winbar.get_current_tab()
11 |
12 | local fn = function(jsonstr)
13 | local lines = utils.split_json(jsonstr)
14 | utils.set_buf_lines(inspector_bufnr, lines)
15 | end
16 |
17 | if tab == "Tables" then
18 | client.get_table_list(conn.id, fn)
19 | elseif tab == "Views" then
20 | client.get_view_list(conn.id, fn)
21 | elseif tab == "StoreProcedures" then
22 | client.get_store_procedure_list(conn.id, fn)
23 | elseif tab == "Functions" then
24 | client.get_function_list(conn.id, fn)
25 | elseif tab == "Columns" then
26 | client.get_table(conn.id, winbar.get_sub_tab_table(), fn)
27 | elseif tab == "Triggers" then
28 | client.get_trigger_list(conn.id, winbar.get_sub_tab_table(), fn)
29 | end
30 | end
31 |
32 | local inspect_view = function()
33 | client.get_view_list(conn.id, function(jsonstr)
34 | local data = vim.fn.json_decode(jsonstr)
35 | vim.ui.select(data.rows, {
36 | prompt = "Inspect a view",
37 | format_item = function(item)
38 | return item.view_name
39 | end,
40 | }, function(view)
41 | if not view then
42 | return
43 | end
44 | client.get_view(conn.id, view.view_name, function(v_jsonstr)
45 | local v = vim.fn.json_decode(v_jsonstr).rows[1].definition
46 | local lines = vim.split(v, "\r?\n")
47 | utils.set_buf_lines(queryer_bufnr, lines)
48 | end)
49 | end)
50 | end)
51 | end
52 |
53 | local inspect_store_procedure = function()
54 | client.get_store_procedure_list(conn.id, function(jsonstr)
55 | local data = vim.fn.json_decode(jsonstr)
56 | vim.ui.select(data.rows, {
57 | prompt = "Inspect a store procedure",
58 | format_item = function(item)
59 | return item.procedure_name
60 | end,
61 | }, function(procedure)
62 | if not procedure then
63 | return
64 | end
65 | client.get_store_procedure(conn.id, procedure.procedure_name, function(sp_jsonstr)
66 | local sp = vim.fn.json_decode(sp_jsonstr).rows[1].definition
67 | local lines = vim.split(sp, "\r?\n")
68 | utils.set_buf_lines(queryer_bufnr, lines)
69 | end)
70 | end)
71 | end)
72 | end
73 |
74 | local inspect_function = function()
75 | client.get_function_list(conn.id, function(jsonstr)
76 | local data = vim.fn.json_decode(jsonstr)
77 | vim.ui.select(data.rows, {
78 | prompt = "Inspect a function",
79 | format_item = function(item)
80 | return item.function_name
81 | end,
82 | }, function(f)
83 | if not f then
84 | return
85 | end
86 | client.get_function(conn.id, f.function_name, function(f_jsonstr)
87 | local sp = vim.fn.json_decode(f_jsonstr).rows[1].definition
88 | local lines = vim.split(sp, "\r?\n")
89 | utils.set_buf_lines(queryer_bufnr, lines)
90 | end)
91 | end)
92 | end)
93 | end
94 |
95 | local inspect_table = function()
96 | client.get_table_list(conn.id, function(jsonstr)
97 | local data = vim.fn.json_decode(jsonstr)
98 | vim.ui.select(data.rows, {
99 | prompt = "Inspect a table",
100 | format_item = function(item)
101 | return item.table_name
102 | end,
103 | }, function(t)
104 | if not t then
105 | return
106 | end
107 | local winnr = utils.get_or_create_buf_win(inspector_bufnr)
108 | vim.api.nvim_win_set_buf(winnr, inspector_bufnr)
109 | winbar.set_sub_tab_table(t.table_name)
110 | winbar.tab_switch(2)
111 | winbar.set_winbar(winnr)
112 | set_inspector_buf()
113 | end)
114 | end)
115 | end
116 |
117 | local inspect_trigger = function()
118 | client.get_trigger_list(conn.id, winbar.get_sub_tab_table(), function(jsonstr)
119 | local data = vim.fn.json_decode(jsonstr)
120 | vim.ui.select(data.rows, {
121 | prompt = "Inspect a trigger",
122 | format_item = function(item)
123 | return item.trigger_name
124 | end,
125 | }, function(t)
126 | if not t then
127 | return
128 | end
129 | client.get_trigger(conn.id, t.trigger_name, function(t_jsonstr)
130 | local sp = vim.fn.json_decode(t_jsonstr).rows[1].definition
131 | local lines = vim.split(sp, "\r?\n")
132 | utils.set_buf_lines(queryer_bufnr, lines)
133 | end)
134 | end)
135 | end)
136 | end
137 |
138 | local inspect_column = function()
139 | local methods = {
140 | "SELECT",
141 | "INSERT",
142 | "UPDATE",
143 | }
144 | vim.ui.select(methods, {
145 | prompt = "Inspect a method",
146 | }, function(m)
147 | if not m then
148 | return
149 | end
150 | local fn = function(s_jsonstr)
151 | local sql = vim.fn.json_decode(s_jsonstr)
152 | local lines = vim.split(sql, "\r?\n")
153 | utils.set_buf_lines(queryer_bufnr, lines)
154 | end
155 | if m == "SELECT" then
156 | client.generate_select_sql(conn.id, winbar.get_sub_tab_table(), fn)
157 | elseif m == "UPDATE" then
158 | client.generate_update_sql(conn.id, winbar.get_sub_tab_table(), fn)
159 | elseif m == "INSERT" then
160 | client.generate_insert_sql(conn.id, winbar.get_sub_tab_table(), fn)
161 | end
162 | end)
163 | end
164 |
165 | local M = {}
166 |
167 | M.buffer_keymappings = nil
168 |
169 | M.open_inspector = function(connection, bufnr)
170 | conn = connection
171 | queryer_bufnr = bufnr
172 |
173 | if inspector_bufnr == nil then
174 | inspector_bufnr = vim.api.nvim_create_buf(false, true)
175 | M.buffer_keymappings(inspector_bufnr)
176 | end
177 | vim.api.nvim_set_option_value("filetype", "json", { buf = inspector_bufnr })
178 |
179 | local winnr = utils.get_or_create_buf_win(inspector_bufnr)
180 | vim.api.nvim_win_set_buf(winnr, inspector_bufnr)
181 | winbar.set_winbar(winnr)
182 | set_inspector_buf()
183 | end
184 |
185 | M.reset = function()
186 | utils.close_buf_win(inspector_bufnr)
187 | winbar.reset()
188 | end
189 |
190 | M.close_inspector = function()
191 | utils.close_buf_win(inspector_bufnr)
192 | end
193 |
194 | M.next_tab = function()
195 | winbar.next_tab()
196 | local winnr = utils.get_buf_win(inspector_bufnr)
197 | winbar.set_winbar(winnr)
198 | set_inspector_buf()
199 | end
200 |
201 | M.previous_tab = function()
202 | winbar.previous_tab()
203 | local winnr = utils.get_buf_win(inspector_bufnr)
204 | winbar.set_winbar(winnr)
205 | set_inspector_buf()
206 | end
207 |
208 | M.inspect = function()
209 | local tab = winbar.get_current_tab()
210 |
211 | if tab == "Tables" then
212 | inspect_table()
213 | elseif tab == "Views" then
214 | inspect_view()
215 | elseif tab == "StoreProcedures" then
216 | if conn.db_type == "sqlite3" then
217 | return
218 | end
219 | inspect_store_procedure()
220 | elseif tab == "Functions" then
221 | if conn.db_type == "sqlite3" then
222 | return
223 | end
224 | inspect_function()
225 | elseif tab == "Triggers" then
226 | inspect_trigger()
227 | elseif tab == "Columns" then
228 | inspect_column()
229 | end
230 | end
231 |
232 | M.back = function()
233 | winbar.back()
234 | local winnr = utils.get_buf_win(inspector_bufnr)
235 | winbar.set_winbar(winnr)
236 | set_inspector_buf()
237 | end
238 |
239 | return M
240 |
--------------------------------------------------------------------------------
/lua/dbout/ui/queryer.lua:
--------------------------------------------------------------------------------
1 | local utils = require("dbout.utils")
2 | local client = require("dbout.client")
3 | local viewer = require("dbout.ui.viewer")
4 | local inspector = require("dbout.ui.inspector")
5 |
6 | local buffer_connection = {}
7 |
8 | local set_winbar = function(name)
9 | return "%#Title#Database:[" .. name .. "]%*"
10 | end
11 |
12 | local visual_select = function()
13 | local start_row, end_row
14 | if vim.fn.mode():match("[vV\22]") then
15 | local v_row = vim.fn.getpos("v")[2]
16 | local c_row = vim.fn.getpos(".")[2]
17 |
18 | if v_row < c_row then
19 | start_row = v_row
20 | end_row = c_row
21 | else
22 | start_row = c_row
23 | end_row = v_row
24 | end
25 | start_row = start_row - 1
26 | else
27 | start_row = 0
28 | end_row = -1
29 | end
30 | return start_row, end_row
31 | end
32 |
33 | local M = {}
34 |
35 | M.buffer_keymappings = nil
36 |
37 | local start_lsp = function(conn)
38 | local lsp_name = "sqls" .. "_" .. conn.name
39 | vim.lsp.config[lsp_name] = {
40 | cmd = { "sqls" },
41 | filetypes = { "sql" },
42 | root_dir = function(bufnr, on_dir)
43 | if buffer_connection[bufnr] and buffer_connection[bufnr].name == conn.name then
44 | on_dir()
45 | end
46 | end,
47 | settings = {
48 | sqls = {
49 | connections = {
50 | {
51 | driver = conn.db_type,
52 | dataSourceName = conn.connstr,
53 | },
54 | },
55 | },
56 | },
57 | }
58 | vim.lsp.enable(lsp_name, true)
59 | end
60 |
61 | local buf_detach_lsp = function(bufnr)
62 | local clients = vim.lsp.get_clients({ bufnr = bufnr })
63 | for _, c in ipairs(clients) do
64 | if c.name:match("^sqls") then
65 | buffer_connection[bufnr] = nil
66 | vim.lsp.buf_detach_client(bufnr, c.id)
67 | end
68 | end
69 | end
70 |
71 | M.init = function()
72 | vim.api.nvim_create_autocmd("BufEnter", {
73 | callback = function(args)
74 | local conn = buffer_connection[args.buf]
75 | if not conn then
76 | return
77 | end
78 | vim.wo.winbar = set_winbar(conn.name)
79 | end,
80 | })
81 | end
82 |
83 | local set_connection_buf = function(connection, bufnr)
84 | vim.api.nvim_set_option_value("filetype", "sql", { buf = bufnr })
85 | buffer_connection[bufnr] = connection
86 |
87 | M.buffer_keymappings(bufnr)
88 |
89 | if vim.api.nvim_get_current_buf() == bufnr then
90 | vim.wo.winbar = set_winbar(connection.name)
91 | end
92 | end
93 |
94 | M.create_buf = function(connection)
95 | local bufnr = vim.api.nvim_create_buf(true, false)
96 | set_connection_buf(connection, bufnr)
97 | utils.switch_win_to_buf(bufnr)
98 | start_lsp(connection)
99 | end
100 |
101 | M.attach_buf = function(connection, bufnr)
102 | buf_detach_lsp(bufnr)
103 | set_connection_buf(connection, bufnr)
104 | utils.switch_win_to_buf(bufnr)
105 | start_lsp(connection)
106 | inspector.reset()
107 | end
108 |
109 | M.query = function()
110 | local win = vim.api.nvim_get_current_win()
111 | local bufnr = vim.api.nvim_win_get_buf(win)
112 |
113 | local start_row, end_row = visual_select()
114 |
115 | local sql = table.concat(vim.api.nvim_buf_get_lines(bufnr, start_row, end_row, false), "\n")
116 | client.query(buffer_connection[bufnr].id, sql, function(jsonstr)
117 | viewer.open_viewer(jsonstr)
118 | end)
119 | end
120 |
121 | M.open_inspector = function()
122 | local win = vim.api.nvim_get_current_win()
123 | local bufnr = vim.api.nvim_win_get_buf(win)
124 | inspector.open_inspector(buffer_connection[bufnr], bufnr)
125 | end
126 |
127 | M.format = function()
128 | local win = vim.api.nvim_get_current_win()
129 | local bufnr = vim.api.nvim_win_get_buf(win)
130 |
131 | local start_row, end_row = visual_select()
132 |
133 | local sql = table.concat(vim.api.nvim_buf_get_lines(bufnr, start_row, end_row, false), "\n")
134 | client.format(buffer_connection[bufnr].id, sql, function(jsonstr)
135 | local str = vim.fn.json_decode(jsonstr)
136 | local lines = vim.split(str, "\r?\n")
137 | utils.set_buf_lines(bufnr, lines)
138 | vim.api.nvim_win_set_buf(win, bufnr)
139 | end)
140 | end
141 |
142 | return M
143 |
--------------------------------------------------------------------------------
/lua/dbout/ui/viewer.lua:
--------------------------------------------------------------------------------
1 | local utils = require("dbout.utils")
2 |
3 | local viewer_bufnr
4 |
5 | local M = {}
6 |
7 | M.buffer_keymappings = nil
8 |
9 | M.open_viewer = function(jsonstr)
10 | if viewer_bufnr == nil then
11 | viewer_bufnr = vim.api.nvim_create_buf(false, true)
12 | M.buffer_keymappings(viewer_bufnr)
13 | end
14 | vim.api.nvim_set_option_value("filetype", "json", { buf = viewer_bufnr })
15 |
16 |
17 | local lines = utils.split_json(jsonstr)
18 | utils.set_buf_lines(viewer_bufnr, lines)
19 |
20 | local winnr = utils.get_or_create_buf_win(viewer_bufnr)
21 | vim.api.nvim_win_set_buf(winnr, viewer_bufnr)
22 | vim.api.nvim_set_option_value("winbar", "%#Title#[Query Result]%*", { win = winnr })
23 | end
24 |
25 | M.close_viewer = function()
26 | utils.close_buf_win(viewer_bufnr)
27 | end
28 |
29 | return M
30 |
--------------------------------------------------------------------------------
/lua/dbout/ui/winbar.lua:
--------------------------------------------------------------------------------
1 | local tab_switch = 1
2 | local tab_state = {
3 | { index = 1, tabs = {
4 | "Tables",
5 | "Views",
6 | "StoreProcedures",
7 | "Functions",
8 | } },
9 | { index = 1, tabs = {
10 | "Columns",
11 | "Triggers",
12 | } },
13 | }
14 | local sub_tab_table_name
15 |
16 | local set_top_winbar = function(winnr)
17 | local state = tab_state[1]
18 | local tab_index = state.index
19 | local tabs = state.tabs
20 |
21 | local bar = {}
22 | for index, tab in ipairs(tabs) do
23 | if index == tab_index then
24 | table.insert(bar, "%#Title#[" .. tab .. "]%*")
25 | else
26 | table.insert(bar, tab)
27 | end
28 | end
29 | vim.api.nvim_set_option_value("winbar", table.concat(bar, "|"), { win = winnr })
30 | vim.api.nvim_win_set_cursor(winnr, { 1, 0 })
31 | end
32 |
33 | local set_sub_winbar = function(winnr)
34 | local state = tab_state[2]
35 |
36 | local bar = {}
37 | table.insert(bar, "<--Back")
38 | table.insert(bar, " %#Directory#" .. sub_tab_table_name .. "%* ")
39 |
40 | for index, tab in ipairs(state.tabs) do
41 | if index == state.index then
42 | table.insert(bar, "%#Title#[" .. tab .. "]%*")
43 | else
44 | table.insert(bar, tab)
45 | end
46 | end
47 |
48 | vim.api.nvim_set_option_value("winbar", table.concat(bar, "|"), { win = winnr })
49 | vim.api.nvim_win_set_cursor(winnr, { 1, 0 })
50 | end
51 |
52 | local M = {}
53 |
54 | M.set_sub_tab_table = function(table_name)
55 | sub_tab_table_name = table_name
56 | end
57 |
58 | M.get_sub_tab_table = function()
59 | return sub_tab_table_name
60 | end
61 |
62 | M.set_winbar = function(winnr)
63 | if tab_switch == 1 then
64 | set_top_winbar(winnr)
65 | elseif tab_switch == 2 then
66 | set_sub_winbar(winnr)
67 | end
68 | end
69 |
70 | M.tab_switch = function(tabnr)
71 | tab_switch = tabnr
72 | end
73 |
74 | M.next_tab = function()
75 | local state = tab_state[tab_switch]
76 | state.index = state.index + 1
77 | if state.index > #state.tabs then
78 | state.index = 1
79 | end
80 | end
81 |
82 | M.previous_tab = function()
83 | local state = tab_state[tab_switch]
84 | state.index = state.index - 1
85 | if state.index < 1 then
86 | state.index = #state.tabs
87 | end
88 | end
89 |
90 | M.get_current_tab = function()
91 | local state = tab_state[tab_switch]
92 | local tab = state.tabs[state.index]
93 | return tab
94 | end
95 |
96 | M.reset = function()
97 | M.tab_switch(1)
98 | tab_state[1].index = 1
99 | tab_state[2].index = 1
100 | end
101 |
102 | M.back = function()
103 | M.tab_switch(1)
104 | tab_state[2].index = 1
105 | end
106 |
107 | return M
108 |
--------------------------------------------------------------------------------
/lua/dbout/utils.lua:
--------------------------------------------------------------------------------
1 | local M = {}
2 |
3 | M.generate_uuid = function()
4 | local random = math.random
5 | local template = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx"
6 | return string.gsub(template, "[xy]", function(c)
7 | local v = (c == "x") and random(0, 0xf) or random(8, 0xb)
8 | return string.format("%x", v)
9 | end)
10 | end
11 |
12 | M.switch_win_to_buf = function(bufnr)
13 | local win = vim.fn.win_findbuf(bufnr)
14 | local winnr
15 | if #win > 0 then
16 | winnr = win[1]
17 | else
18 | winnr = vim.api.nvim_get_current_win()
19 | end
20 |
21 | vim.api.nvim_win_set_buf(winnr, bufnr)
22 | vim.api.nvim_set_current_win(winnr)
23 | end
24 |
25 | M.close_buf_win = function(bufnr)
26 | if bufnr and vim.api.nvim_buf_is_loaded(bufnr) then
27 | local wins = vim.fn.win_findbuf(bufnr)
28 | if #wins > 0 then
29 | vim.api.nvim_win_close(wins[1], true)
30 | end
31 | end
32 | end
33 |
34 | M.get_buf_win = function(bufnr)
35 | local wins = vim.fn.win_findbuf(bufnr)
36 | if #wins == 0 then
37 | return nil
38 | end
39 | return wins[1]
40 | end
41 |
42 | M.create_right_win = function()
43 | vim.cmd("botright vsplit")
44 | return vim.api.nvim_get_current_win()
45 | end
46 |
47 | M.get_or_create_buf_win = function(bufnr)
48 | local winnr = M.get_buf_win(bufnr)
49 | if not winnr then
50 | winnr = M.create_right_win()
51 | end
52 | return winnr
53 | end
54 |
55 | M.split_json = function(jsonstr)
56 | return vim.split(jsonstr, "\n", { plain = true })
57 | end
58 |
59 | M.set_buf_lines = function(buf, lines)
60 | vim.api.nvim_buf_set_lines(buf, 0, -1, false, lines)
61 | end
62 |
63 | return M
64 |
--------------------------------------------------------------------------------
/lua/telescope/_extensions/dbout.lua:
--------------------------------------------------------------------------------
1 | local telescope = require("telescope")
2 | local pickers = require("telescope.pickers")
3 | local finders = require("telescope.finders")
4 | local action_state = require("telescope.actions.state")
5 | local actions = require("telescope.actions")
6 | local conf = require("telescope.config").values
7 | local entry_display = require("telescope.pickers.entry_display")
8 | local conn = require("dbout.connection")
9 | local queryer = require("dbout.ui.queryer")
10 | local rpc = require("dbout.rpc")
11 |
12 | local options = {
13 | keymaps = {
14 | open_connection = "",
15 | new_connection = "n",
16 | delete_connection = "d",
17 | edit_connection = "e",
18 | attach_connection = "a",
19 | },
20 | }
21 |
22 | local M = {}
23 |
24 | local function create_finder(connections)
25 | local displayer = entry_display.create({
26 | separator = " ",
27 | items = {
28 | {
29 | width = 15,
30 | },
31 | {
32 | remaining = true,
33 | },
34 | },
35 | })
36 |
37 | local function make_display(entry)
38 | return displayer({ entry.name, { entry.value.db_type .. ":" .. entry.value.connstr, "Comment" } })
39 | end
40 |
41 | return finders.new_table({
42 | results = connections,
43 | entry_maker = function(entry)
44 | return {
45 | display = make_display,
46 | name = entry.name,
47 | value = entry,
48 | ordinal = entry.name,
49 | }
50 | end,
51 | })
52 | end
53 |
54 | local new_picker = function()
55 | pickers
56 | .new({}, {
57 | prompt_title = "Connections",
58 | finder = create_finder(conn.get_connections()),
59 | sorter = conf.generic_sorter({}),
60 | attach_mappings = function(_, map)
61 | actions.select_default:replace(function() end)
62 |
63 | local key = options.keymaps
64 | map("n", key.open_connection, M.open_connection)
65 | map("n", key.new_connection, M.new_connection)
66 | map("n", key.delete_connection, M.delete_connection)
67 | map("n", key.edit_connection, M.edit_connection)
68 | map("n", key.attach_connection, M.attach_connection)
69 |
70 | return true
71 | end,
72 | })
73 | :find()
74 | end
75 |
76 | local refresh_picker = function(prompt_bufnr)
77 | local picker = action_state.get_current_picker(prompt_bufnr)
78 | if picker then
79 | local finder = create_finder(conn.get_connections())
80 | picker:refresh(finder)
81 | else
82 | M.open_connection_picker()
83 | end
84 | end
85 |
86 | M.open_connection_picker = function()
87 | if not rpc.is_alive() then
88 | rpc.server_up()
89 | end
90 | new_picker()
91 | end
92 |
93 | M.open_connection = function(prompt_bufnr)
94 | local selection = action_state.get_selected_entry()
95 | if not selection then
96 | return false
97 | end
98 |
99 | local connection = selection.value
100 | conn.open_connection(connection, function()
101 | actions.close(prompt_bufnr)
102 | queryer.create_buf(connection)
103 | end)
104 | end
105 |
106 | M.new_connection = function(prompt_bufnr)
107 | actions.close(prompt_bufnr)
108 | conn.create_connection({}, function(c)
109 | conn.add_connection(c)
110 | refresh_picker(prompt_bufnr)
111 | end)
112 | end
113 |
114 | M.delete_connection = function(prompt_bufnr)
115 | local connection = action_state.get_selected_entry().value
116 | conn.remove_connection(connection.id)
117 | refresh_picker(prompt_bufnr)
118 | end
119 |
120 | M.edit_connection = function(prompt_bufnr)
121 | local connection = action_state.get_selected_entry().value
122 | conn.create_connection(connection, function(c)
123 | conn.update_connection(c)
124 | refresh_picker(prompt_bufnr)
125 | end)
126 | end
127 |
128 | M.attach_connection = function(prompt_bufnr)
129 | local connection = action_state.get_selected_entry().value
130 | conn.open_connection(connection, function()
131 | actions.close(prompt_bufnr)
132 | queryer.attach_buf(connection, vim.api.nvim_get_current_buf())
133 | end)
134 | end
135 |
136 | return telescope.register_extension({
137 | setup = function(opts)
138 | options = vim.tbl_deep_extend("force", options, opts or {})
139 | end,
140 | exports = {
141 | dbout = M.open_connection_picker,
142 | },
143 | })
144 |
--------------------------------------------------------------------------------
/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "dbout.nvim",
3 | "lockfileVersion": 3,
4 | "requires": true,
5 | "packages": {
6 | "": {
7 | "dependencies": {
8 | "better-sqlite3": "^12.4.1",
9 | "mssql": "^12.0.0",
10 | "mysql2": "^3.15.2",
11 | "pg": "^8.16.3",
12 | "sql-formatter": "^15.6.10"
13 | }
14 | },
15 | "node_modules/@azure-rest/core-client": {
16 | "version": "2.5.1",
17 | "resolved": "https://registry.npmjs.org/@azure-rest/core-client/-/core-client-2.5.1.tgz",
18 | "integrity": "sha512-EHaOXW0RYDKS5CFffnixdyRPak5ytiCtU7uXDcP/uiY+A6jFRwNGzzJBiznkCzvi5EYpY+YWinieqHb0oY916A==",
19 | "license": "MIT",
20 | "dependencies": {
21 | "@azure/abort-controller": "^2.1.2",
22 | "@azure/core-auth": "^1.10.0",
23 | "@azure/core-rest-pipeline": "^1.22.0",
24 | "@azure/core-tracing": "^1.3.0",
25 | "@typespec/ts-http-runtime": "^0.3.0",
26 | "tslib": "^2.6.2"
27 | },
28 | "engines": {
29 | "node": ">=20.0.0"
30 | }
31 | },
32 | "node_modules/@azure/abort-controller": {
33 | "version": "2.1.2",
34 | "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz",
35 | "integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==",
36 | "license": "MIT",
37 | "dependencies": {
38 | "tslib": "^2.6.2"
39 | },
40 | "engines": {
41 | "node": ">=18.0.0"
42 | }
43 | },
44 | "node_modules/@azure/core-auth": {
45 | "version": "1.10.1",
46 | "resolved": "https://registry.npmjs.org/@azure/core-auth/-/core-auth-1.10.1.tgz",
47 | "integrity": "sha512-ykRMW8PjVAn+RS6ww5cmK9U2CyH9p4Q88YJwvUslfuMmN98w/2rdGRLPqJYObapBCdzBVeDgYWdJnFPFb7qzpg==",
48 | "license": "MIT",
49 | "dependencies": {
50 | "@azure/abort-controller": "^2.1.2",
51 | "@azure/core-util": "^1.13.0",
52 | "tslib": "^2.6.2"
53 | },
54 | "engines": {
55 | "node": ">=20.0.0"
56 | }
57 | },
58 | "node_modules/@azure/core-client": {
59 | "version": "1.10.1",
60 | "resolved": "https://registry.npmjs.org/@azure/core-client/-/core-client-1.10.1.tgz",
61 | "integrity": "sha512-Nh5PhEOeY6PrnxNPsEHRr9eimxLwgLlpmguQaHKBinFYA/RU9+kOYVOQqOrTsCL+KSxrLLl1gD8Dk5BFW/7l/w==",
62 | "license": "MIT",
63 | "dependencies": {
64 | "@azure/abort-controller": "^2.1.2",
65 | "@azure/core-auth": "^1.10.0",
66 | "@azure/core-rest-pipeline": "^1.22.0",
67 | "@azure/core-tracing": "^1.3.0",
68 | "@azure/core-util": "^1.13.0",
69 | "@azure/logger": "^1.3.0",
70 | "tslib": "^2.6.2"
71 | },
72 | "engines": {
73 | "node": ">=20.0.0"
74 | }
75 | },
76 | "node_modules/@azure/core-http-compat": {
77 | "version": "2.3.1",
78 | "resolved": "https://registry.npmjs.org/@azure/core-http-compat/-/core-http-compat-2.3.1.tgz",
79 | "integrity": "sha512-az9BkXND3/d5VgdRRQVkiJb2gOmDU8Qcq4GvjtBmDICNiQ9udFmDk4ZpSB5Qq1OmtDJGlQAfBaS4palFsazQ5g==",
80 | "license": "MIT",
81 | "dependencies": {
82 | "@azure/abort-controller": "^2.1.2",
83 | "@azure/core-client": "^1.10.0",
84 | "@azure/core-rest-pipeline": "^1.22.0"
85 | },
86 | "engines": {
87 | "node": ">=20.0.0"
88 | }
89 | },
90 | "node_modules/@azure/core-lro": {
91 | "version": "2.7.2",
92 | "resolved": "https://registry.npmjs.org/@azure/core-lro/-/core-lro-2.7.2.tgz",
93 | "integrity": "sha512-0YIpccoX8m/k00O7mDDMdJpbr6mf1yWo2dfmxt5A8XVZVVMz2SSKaEbMCeJRvgQ0IaSlqhjT47p4hVIRRy90xw==",
94 | "license": "MIT",
95 | "dependencies": {
96 | "@azure/abort-controller": "^2.0.0",
97 | "@azure/core-util": "^1.2.0",
98 | "@azure/logger": "^1.0.0",
99 | "tslib": "^2.6.2"
100 | },
101 | "engines": {
102 | "node": ">=18.0.0"
103 | }
104 | },
105 | "node_modules/@azure/core-paging": {
106 | "version": "1.6.2",
107 | "resolved": "https://registry.npmjs.org/@azure/core-paging/-/core-paging-1.6.2.tgz",
108 | "integrity": "sha512-YKWi9YuCU04B55h25cnOYZHxXYtEvQEbKST5vqRga7hWY9ydd3FZHdeQF8pyh+acWZvppw13M/LMGx0LABUVMA==",
109 | "license": "MIT",
110 | "dependencies": {
111 | "tslib": "^2.6.2"
112 | },
113 | "engines": {
114 | "node": ">=18.0.0"
115 | }
116 | },
117 | "node_modules/@azure/core-rest-pipeline": {
118 | "version": "1.22.1",
119 | "resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.22.1.tgz",
120 | "integrity": "sha512-UVZlVLfLyz6g3Hy7GNDpooMQonUygH7ghdiSASOOHy97fKj/mPLqgDX7aidOijn+sCMU+WU8NjlPlNTgnvbcGA==",
121 | "license": "MIT",
122 | "dependencies": {
123 | "@azure/abort-controller": "^2.1.2",
124 | "@azure/core-auth": "^1.10.0",
125 | "@azure/core-tracing": "^1.3.0",
126 | "@azure/core-util": "^1.13.0",
127 | "@azure/logger": "^1.3.0",
128 | "@typespec/ts-http-runtime": "^0.3.0",
129 | "tslib": "^2.6.2"
130 | },
131 | "engines": {
132 | "node": ">=20.0.0"
133 | }
134 | },
135 | "node_modules/@azure/core-tracing": {
136 | "version": "1.3.1",
137 | "resolved": "https://registry.npmjs.org/@azure/core-tracing/-/core-tracing-1.3.1.tgz",
138 | "integrity": "sha512-9MWKevR7Hz8kNzzPLfX4EAtGM2b8mr50HPDBvio96bURP/9C+HjdH3sBlLSNNrvRAr5/k/svoH457gB5IKpmwQ==",
139 | "license": "MIT",
140 | "dependencies": {
141 | "tslib": "^2.6.2"
142 | },
143 | "engines": {
144 | "node": ">=20.0.0"
145 | }
146 | },
147 | "node_modules/@azure/core-util": {
148 | "version": "1.13.1",
149 | "resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.13.1.tgz",
150 | "integrity": "sha512-XPArKLzsvl0Hf0CaGyKHUyVgF7oDnhKoP85Xv6M4StF/1AhfORhZudHtOyf2s+FcbuQ9dPRAjB8J2KvRRMUK2A==",
151 | "license": "MIT",
152 | "dependencies": {
153 | "@azure/abort-controller": "^2.1.2",
154 | "@typespec/ts-http-runtime": "^0.3.0",
155 | "tslib": "^2.6.2"
156 | },
157 | "engines": {
158 | "node": ">=20.0.0"
159 | }
160 | },
161 | "node_modules/@azure/identity": {
162 | "version": "4.13.0",
163 | "resolved": "https://registry.npmjs.org/@azure/identity/-/identity-4.13.0.tgz",
164 | "integrity": "sha512-uWC0fssc+hs1TGGVkkghiaFkkS7NkTxfnCH+Hdg+yTehTpMcehpok4PgUKKdyCH+9ldu6FhiHRv84Ntqj1vVcw==",
165 | "license": "MIT",
166 | "dependencies": {
167 | "@azure/abort-controller": "^2.0.0",
168 | "@azure/core-auth": "^1.9.0",
169 | "@azure/core-client": "^1.9.2",
170 | "@azure/core-rest-pipeline": "^1.17.0",
171 | "@azure/core-tracing": "^1.0.0",
172 | "@azure/core-util": "^1.11.0",
173 | "@azure/logger": "^1.0.0",
174 | "@azure/msal-browser": "^4.2.0",
175 | "@azure/msal-node": "^3.5.0",
176 | "open": "^10.1.0",
177 | "tslib": "^2.2.0"
178 | },
179 | "engines": {
180 | "node": ">=20.0.0"
181 | }
182 | },
183 | "node_modules/@azure/keyvault-common": {
184 | "version": "2.0.0",
185 | "resolved": "https://registry.npmjs.org/@azure/keyvault-common/-/keyvault-common-2.0.0.tgz",
186 | "integrity": "sha512-wRLVaroQtOqfg60cxkzUkGKrKMsCP6uYXAOomOIysSMyt1/YM0eUn9LqieAWM8DLcU4+07Fio2YGpPeqUbpP9w==",
187 | "license": "MIT",
188 | "dependencies": {
189 | "@azure/abort-controller": "^2.0.0",
190 | "@azure/core-auth": "^1.3.0",
191 | "@azure/core-client": "^1.5.0",
192 | "@azure/core-rest-pipeline": "^1.8.0",
193 | "@azure/core-tracing": "^1.0.0",
194 | "@azure/core-util": "^1.10.0",
195 | "@azure/logger": "^1.1.4",
196 | "tslib": "^2.2.0"
197 | },
198 | "engines": {
199 | "node": ">=18.0.0"
200 | }
201 | },
202 | "node_modules/@azure/keyvault-keys": {
203 | "version": "4.10.0",
204 | "resolved": "https://registry.npmjs.org/@azure/keyvault-keys/-/keyvault-keys-4.10.0.tgz",
205 | "integrity": "sha512-eDT7iXoBTRZ2n3fLiftuGJFD+yjkiB1GNqzU2KbY1TLYeXeSPVTVgn2eJ5vmRTZ11978jy2Kg2wI7xa9Tyr8ag==",
206 | "license": "MIT",
207 | "dependencies": {
208 | "@azure-rest/core-client": "^2.3.3",
209 | "@azure/abort-controller": "^2.1.2",
210 | "@azure/core-auth": "^1.9.0",
211 | "@azure/core-http-compat": "^2.2.0",
212 | "@azure/core-lro": "^2.7.2",
213 | "@azure/core-paging": "^1.6.2",
214 | "@azure/core-rest-pipeline": "^1.19.0",
215 | "@azure/core-tracing": "^1.2.0",
216 | "@azure/core-util": "^1.11.0",
217 | "@azure/keyvault-common": "^2.0.0",
218 | "@azure/logger": "^1.1.4",
219 | "tslib": "^2.8.1"
220 | },
221 | "engines": {
222 | "node": ">=18.0.0"
223 | }
224 | },
225 | "node_modules/@azure/logger": {
226 | "version": "1.3.0",
227 | "resolved": "https://registry.npmjs.org/@azure/logger/-/logger-1.3.0.tgz",
228 | "integrity": "sha512-fCqPIfOcLE+CGqGPd66c8bZpwAji98tZ4JI9i/mlTNTlsIWslCfpg48s/ypyLxZTump5sypjrKn2/kY7q8oAbA==",
229 | "license": "MIT",
230 | "dependencies": {
231 | "@typespec/ts-http-runtime": "^0.3.0",
232 | "tslib": "^2.6.2"
233 | },
234 | "engines": {
235 | "node": ">=20.0.0"
236 | }
237 | },
238 | "node_modules/@azure/msal-browser": {
239 | "version": "4.25.0",
240 | "resolved": "https://registry.npmjs.org/@azure/msal-browser/-/msal-browser-4.25.0.tgz",
241 | "integrity": "sha512-kbL+Ae7/UC62wSzxirZddYeVnHvvkvAnSZkBqL55X+jaSXTAXfngnNsDM5acEWU0Q/SAv3gEQfxO1igWOn87Pg==",
242 | "license": "MIT",
243 | "dependencies": {
244 | "@azure/msal-common": "15.13.0"
245 | },
246 | "engines": {
247 | "node": ">=0.8.0"
248 | }
249 | },
250 | "node_modules/@azure/msal-common": {
251 | "version": "15.13.0",
252 | "resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-15.13.0.tgz",
253 | "integrity": "sha512-8oF6nj02qX7eE/6+wFT5NluXRHc05AgdCC3fJnkjiJooq8u7BcLmxaYYSwc2AfEkWRMRi6Eyvvbeqk4U4412Ag==",
254 | "license": "MIT",
255 | "engines": {
256 | "node": ">=0.8.0"
257 | }
258 | },
259 | "node_modules/@azure/msal-node": {
260 | "version": "3.8.0",
261 | "resolved": "https://registry.npmjs.org/@azure/msal-node/-/msal-node-3.8.0.tgz",
262 | "integrity": "sha512-23BXm82Mp5XnRhrcd4mrHa0xuUNRp96ivu3nRatrfdAqjoeWAGyD0eEAafxAOHAEWWmdlyFK4ELFcdziXyw2sA==",
263 | "license": "MIT",
264 | "dependencies": {
265 | "@azure/msal-common": "15.13.0",
266 | "jsonwebtoken": "^9.0.0",
267 | "uuid": "^8.3.0"
268 | },
269 | "engines": {
270 | "node": ">=16"
271 | }
272 | },
273 | "node_modules/@js-joda/core": {
274 | "version": "5.6.5",
275 | "resolved": "https://registry.npmjs.org/@js-joda/core/-/core-5.6.5.tgz",
276 | "integrity": "sha512-3zwefSMwHpu8iVUW8YYz227sIv6UFqO31p1Bf1ZH/Vom7CmNyUsXjDBlnNzcuhmOL1XfxZ3nvND42kR23XlbcQ==",
277 | "license": "BSD-3-Clause"
278 | },
279 | "node_modules/@tediousjs/connection-string": {
280 | "version": "0.6.0",
281 | "resolved": "https://registry.npmjs.org/@tediousjs/connection-string/-/connection-string-0.6.0.tgz",
282 | "integrity": "sha512-GxlsW354Vi6QqbUgdPyQVcQjI7cZBdGV5vOYVYuCVDTylx2wl3WHR2HlhcxxHTrMigbelpXsdcZso+66uxPfow==",
283 | "license": "MIT"
284 | },
285 | "node_modules/@types/node": {
286 | "version": "24.7.0",
287 | "resolved": "https://registry.npmjs.org/@types/node/-/node-24.7.0.tgz",
288 | "integrity": "sha512-IbKooQVqUBrlzWTi79E8Fw78l8k1RNtlDDNWsFZs7XonuQSJ8oNYfEeclhprUldXISRMLzBpILuKgPlIxm+/Yw==",
289 | "license": "MIT",
290 | "dependencies": {
291 | "undici-types": "~7.14.0"
292 | }
293 | },
294 | "node_modules/@types/readable-stream": {
295 | "version": "4.0.21",
296 | "resolved": "https://registry.npmjs.org/@types/readable-stream/-/readable-stream-4.0.21.tgz",
297 | "integrity": "sha512-19eKVv9tugr03IgfXlA9UVUVRbW6IuqRO5B92Dl4a6pT7K8uaGrNS0GkxiZD0BOk6PLuXl5FhWl//eX/pzYdTQ==",
298 | "license": "MIT",
299 | "dependencies": {
300 | "@types/node": "*"
301 | }
302 | },
303 | "node_modules/@typespec/ts-http-runtime": {
304 | "version": "0.3.1",
305 | "resolved": "https://registry.npmjs.org/@typespec/ts-http-runtime/-/ts-http-runtime-0.3.1.tgz",
306 | "integrity": "sha512-SnbaqayTVFEA6/tYumdF0UmybY0KHyKwGPBXnyckFlrrKdhWFrL3a2HIPXHjht5ZOElKGcXfD2D63P36btb+ww==",
307 | "license": "MIT",
308 | "dependencies": {
309 | "http-proxy-agent": "^7.0.0",
310 | "https-proxy-agent": "^7.0.0",
311 | "tslib": "^2.6.2"
312 | },
313 | "engines": {
314 | "node": ">=20.0.0"
315 | }
316 | },
317 | "node_modules/abort-controller": {
318 | "version": "3.0.0",
319 | "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
320 | "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==",
321 | "license": "MIT",
322 | "dependencies": {
323 | "event-target-shim": "^5.0.0"
324 | },
325 | "engines": {
326 | "node": ">=6.5"
327 | }
328 | },
329 | "node_modules/agent-base": {
330 | "version": "7.1.4",
331 | "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz",
332 | "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==",
333 | "license": "MIT",
334 | "engines": {
335 | "node": ">= 14"
336 | }
337 | },
338 | "node_modules/argparse": {
339 | "version": "2.0.1",
340 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
341 | "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
342 | "license": "Python-2.0"
343 | },
344 | "node_modules/aws-ssl-profiles": {
345 | "version": "1.1.2",
346 | "resolved": "https://registry.npmjs.org/aws-ssl-profiles/-/aws-ssl-profiles-1.1.2.tgz",
347 | "integrity": "sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g==",
348 | "license": "MIT",
349 | "engines": {
350 | "node": ">= 6.0.0"
351 | }
352 | },
353 | "node_modules/base64-js": {
354 | "version": "1.5.1",
355 | "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
356 | "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
357 | "funding": [
358 | {
359 | "type": "github",
360 | "url": "https://github.com/sponsors/feross"
361 | },
362 | {
363 | "type": "patreon",
364 | "url": "https://www.patreon.com/feross"
365 | },
366 | {
367 | "type": "consulting",
368 | "url": "https://feross.org/support"
369 | }
370 | ],
371 | "license": "MIT"
372 | },
373 | "node_modules/better-sqlite3": {
374 | "version": "12.4.1",
375 | "resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-12.4.1.tgz",
376 | "integrity": "sha512-3yVdyZhklTiNrtg+4WqHpJpFDd+WHTg2oM7UcR80GqL05AOV0xEJzc6qNvFYoEtE+hRp1n9MpN6/+4yhlGkDXQ==",
377 | "hasInstallScript": true,
378 | "license": "MIT",
379 | "dependencies": {
380 | "bindings": "^1.5.0",
381 | "prebuild-install": "^7.1.1"
382 | },
383 | "engines": {
384 | "node": "20.x || 22.x || 23.x || 24.x"
385 | }
386 | },
387 | "node_modules/bindings": {
388 | "version": "1.5.0",
389 | "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
390 | "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
391 | "license": "MIT",
392 | "dependencies": {
393 | "file-uri-to-path": "1.0.0"
394 | }
395 | },
396 | "node_modules/bl": {
397 | "version": "6.1.3",
398 | "resolved": "https://registry.npmjs.org/bl/-/bl-6.1.3.tgz",
399 | "integrity": "sha512-nHB8B5roHlGX5TFsWeiQJijdddZIOHuv1eL2cM2kHnG3qR91CYLsysGe+CvxQfEd23EKD0eJf4lto0frTbddKA==",
400 | "license": "MIT",
401 | "dependencies": {
402 | "@types/readable-stream": "^4.0.0",
403 | "buffer": "^6.0.3",
404 | "inherits": "^2.0.4",
405 | "readable-stream": "^4.2.0"
406 | }
407 | },
408 | "node_modules/buffer": {
409 | "version": "6.0.3",
410 | "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
411 | "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
412 | "funding": [
413 | {
414 | "type": "github",
415 | "url": "https://github.com/sponsors/feross"
416 | },
417 | {
418 | "type": "patreon",
419 | "url": "https://www.patreon.com/feross"
420 | },
421 | {
422 | "type": "consulting",
423 | "url": "https://feross.org/support"
424 | }
425 | ],
426 | "license": "MIT",
427 | "dependencies": {
428 | "base64-js": "^1.3.1",
429 | "ieee754": "^1.2.1"
430 | }
431 | },
432 | "node_modules/buffer-equal-constant-time": {
433 | "version": "1.0.1",
434 | "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
435 | "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==",
436 | "license": "BSD-3-Clause"
437 | },
438 | "node_modules/bundle-name": {
439 | "version": "4.1.0",
440 | "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz",
441 | "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==",
442 | "license": "MIT",
443 | "dependencies": {
444 | "run-applescript": "^7.0.0"
445 | },
446 | "engines": {
447 | "node": ">=18"
448 | },
449 | "funding": {
450 | "url": "https://github.com/sponsors/sindresorhus"
451 | }
452 | },
453 | "node_modules/chownr": {
454 | "version": "1.1.4",
455 | "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
456 | "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==",
457 | "license": "ISC"
458 | },
459 | "node_modules/commander": {
460 | "version": "11.1.0",
461 | "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz",
462 | "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==",
463 | "license": "MIT",
464 | "engines": {
465 | "node": ">=16"
466 | }
467 | },
468 | "node_modules/debug": {
469 | "version": "4.4.3",
470 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
471 | "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
472 | "license": "MIT",
473 | "dependencies": {
474 | "ms": "^2.1.3"
475 | },
476 | "engines": {
477 | "node": ">=6.0"
478 | },
479 | "peerDependenciesMeta": {
480 | "supports-color": {
481 | "optional": true
482 | }
483 | }
484 | },
485 | "node_modules/decompress-response": {
486 | "version": "6.0.0",
487 | "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz",
488 | "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==",
489 | "license": "MIT",
490 | "dependencies": {
491 | "mimic-response": "^3.1.0"
492 | },
493 | "engines": {
494 | "node": ">=10"
495 | },
496 | "funding": {
497 | "url": "https://github.com/sponsors/sindresorhus"
498 | }
499 | },
500 | "node_modules/deep-extend": {
501 | "version": "0.6.0",
502 | "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
503 | "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
504 | "license": "MIT",
505 | "engines": {
506 | "node": ">=4.0.0"
507 | }
508 | },
509 | "node_modules/default-browser": {
510 | "version": "5.2.1",
511 | "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.2.1.tgz",
512 | "integrity": "sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg==",
513 | "license": "MIT",
514 | "dependencies": {
515 | "bundle-name": "^4.1.0",
516 | "default-browser-id": "^5.0.0"
517 | },
518 | "engines": {
519 | "node": ">=18"
520 | },
521 | "funding": {
522 | "url": "https://github.com/sponsors/sindresorhus"
523 | }
524 | },
525 | "node_modules/default-browser-id": {
526 | "version": "5.0.0",
527 | "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.0.tgz",
528 | "integrity": "sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA==",
529 | "license": "MIT",
530 | "engines": {
531 | "node": ">=18"
532 | },
533 | "funding": {
534 | "url": "https://github.com/sponsors/sindresorhus"
535 | }
536 | },
537 | "node_modules/define-lazy-prop": {
538 | "version": "3.0.0",
539 | "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz",
540 | "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==",
541 | "license": "MIT",
542 | "engines": {
543 | "node": ">=12"
544 | },
545 | "funding": {
546 | "url": "https://github.com/sponsors/sindresorhus"
547 | }
548 | },
549 | "node_modules/denque": {
550 | "version": "2.1.0",
551 | "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz",
552 | "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==",
553 | "license": "Apache-2.0",
554 | "engines": {
555 | "node": ">=0.10"
556 | }
557 | },
558 | "node_modules/detect-libc": {
559 | "version": "2.1.0",
560 | "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.0.tgz",
561 | "integrity": "sha512-vEtk+OcP7VBRtQZ1EJ3bdgzSfBjgnEalLTp5zjJrS+2Z1w2KZly4SBdac/WDU3hhsNAZ9E8SC96ME4Ey8MZ7cg==",
562 | "license": "Apache-2.0",
563 | "engines": {
564 | "node": ">=8"
565 | }
566 | },
567 | "node_modules/discontinuous-range": {
568 | "version": "1.0.0",
569 | "resolved": "https://registry.npmjs.org/discontinuous-range/-/discontinuous-range-1.0.0.tgz",
570 | "integrity": "sha512-c68LpLbO+7kP/b1Hr1qs8/BJ09F5khZGTxqxZuhzxpmwJKOgRFHJWIb9/KmqnqHhLdO55aOxFH/EGBvUQbL/RQ==",
571 | "license": "MIT"
572 | },
573 | "node_modules/ecdsa-sig-formatter": {
574 | "version": "1.0.11",
575 | "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
576 | "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
577 | "license": "Apache-2.0",
578 | "dependencies": {
579 | "safe-buffer": "^5.0.1"
580 | }
581 | },
582 | "node_modules/end-of-stream": {
583 | "version": "1.4.5",
584 | "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz",
585 | "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==",
586 | "license": "MIT",
587 | "dependencies": {
588 | "once": "^1.4.0"
589 | }
590 | },
591 | "node_modules/event-target-shim": {
592 | "version": "5.0.1",
593 | "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
594 | "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==",
595 | "license": "MIT",
596 | "engines": {
597 | "node": ">=6"
598 | }
599 | },
600 | "node_modules/events": {
601 | "version": "3.3.0",
602 | "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
603 | "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
604 | "license": "MIT",
605 | "engines": {
606 | "node": ">=0.8.x"
607 | }
608 | },
609 | "node_modules/expand-template": {
610 | "version": "2.0.3",
611 | "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz",
612 | "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==",
613 | "license": "(MIT OR WTFPL)",
614 | "engines": {
615 | "node": ">=6"
616 | }
617 | },
618 | "node_modules/file-uri-to-path": {
619 | "version": "1.0.0",
620 | "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
621 | "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==",
622 | "license": "MIT"
623 | },
624 | "node_modules/fs-constants": {
625 | "version": "1.0.0",
626 | "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
627 | "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==",
628 | "license": "MIT"
629 | },
630 | "node_modules/generate-function": {
631 | "version": "2.3.1",
632 | "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz",
633 | "integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==",
634 | "license": "MIT",
635 | "dependencies": {
636 | "is-property": "^1.0.2"
637 | }
638 | },
639 | "node_modules/github-from-package": {
640 | "version": "0.0.0",
641 | "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz",
642 | "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==",
643 | "license": "MIT"
644 | },
645 | "node_modules/http-proxy-agent": {
646 | "version": "7.0.2",
647 | "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz",
648 | "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==",
649 | "license": "MIT",
650 | "dependencies": {
651 | "agent-base": "^7.1.0",
652 | "debug": "^4.3.4"
653 | },
654 | "engines": {
655 | "node": ">= 14"
656 | }
657 | },
658 | "node_modules/https-proxy-agent": {
659 | "version": "7.0.6",
660 | "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz",
661 | "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==",
662 | "license": "MIT",
663 | "dependencies": {
664 | "agent-base": "^7.1.2",
665 | "debug": "4"
666 | },
667 | "engines": {
668 | "node": ">= 14"
669 | }
670 | },
671 | "node_modules/iconv-lite": {
672 | "version": "0.6.3",
673 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
674 | "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
675 | "license": "MIT",
676 | "dependencies": {
677 | "safer-buffer": ">= 2.1.2 < 3.0.0"
678 | },
679 | "engines": {
680 | "node": ">=0.10.0"
681 | }
682 | },
683 | "node_modules/ieee754": {
684 | "version": "1.2.1",
685 | "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
686 | "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
687 | "funding": [
688 | {
689 | "type": "github",
690 | "url": "https://github.com/sponsors/feross"
691 | },
692 | {
693 | "type": "patreon",
694 | "url": "https://www.patreon.com/feross"
695 | },
696 | {
697 | "type": "consulting",
698 | "url": "https://feross.org/support"
699 | }
700 | ],
701 | "license": "BSD-3-Clause"
702 | },
703 | "node_modules/inherits": {
704 | "version": "2.0.4",
705 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
706 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
707 | "license": "ISC"
708 | },
709 | "node_modules/ini": {
710 | "version": "1.3.8",
711 | "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
712 | "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
713 | "license": "ISC"
714 | },
715 | "node_modules/is-docker": {
716 | "version": "3.0.0",
717 | "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz",
718 | "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==",
719 | "license": "MIT",
720 | "bin": {
721 | "is-docker": "cli.js"
722 | },
723 | "engines": {
724 | "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
725 | },
726 | "funding": {
727 | "url": "https://github.com/sponsors/sindresorhus"
728 | }
729 | },
730 | "node_modules/is-inside-container": {
731 | "version": "1.0.0",
732 | "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz",
733 | "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==",
734 | "license": "MIT",
735 | "dependencies": {
736 | "is-docker": "^3.0.0"
737 | },
738 | "bin": {
739 | "is-inside-container": "cli.js"
740 | },
741 | "engines": {
742 | "node": ">=14.16"
743 | },
744 | "funding": {
745 | "url": "https://github.com/sponsors/sindresorhus"
746 | }
747 | },
748 | "node_modules/is-property": {
749 | "version": "1.0.2",
750 | "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz",
751 | "integrity": "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==",
752 | "license": "MIT"
753 | },
754 | "node_modules/is-wsl": {
755 | "version": "3.1.0",
756 | "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.0.tgz",
757 | "integrity": "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==",
758 | "license": "MIT",
759 | "dependencies": {
760 | "is-inside-container": "^1.0.0"
761 | },
762 | "engines": {
763 | "node": ">=16"
764 | },
765 | "funding": {
766 | "url": "https://github.com/sponsors/sindresorhus"
767 | }
768 | },
769 | "node_modules/js-md4": {
770 | "version": "0.3.2",
771 | "resolved": "https://registry.npmjs.org/js-md4/-/js-md4-0.3.2.tgz",
772 | "integrity": "sha512-/GDnfQYsltsjRswQhN9fhv3EMw2sCpUdrdxyWDOUK7eyD++r3gRhzgiQgc/x4MAv2i1iuQ4lxO5mvqM3vj4bwA==",
773 | "license": "MIT"
774 | },
775 | "node_modules/jsonwebtoken": {
776 | "version": "9.0.2",
777 | "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz",
778 | "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==",
779 | "license": "MIT",
780 | "dependencies": {
781 | "jws": "^3.2.2",
782 | "lodash.includes": "^4.3.0",
783 | "lodash.isboolean": "^3.0.3",
784 | "lodash.isinteger": "^4.0.4",
785 | "lodash.isnumber": "^3.0.3",
786 | "lodash.isplainobject": "^4.0.6",
787 | "lodash.isstring": "^4.0.1",
788 | "lodash.once": "^4.0.0",
789 | "ms": "^2.1.1",
790 | "semver": "^7.5.4"
791 | },
792 | "engines": {
793 | "node": ">=12",
794 | "npm": ">=6"
795 | }
796 | },
797 | "node_modules/jwa": {
798 | "version": "1.4.2",
799 | "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.2.tgz",
800 | "integrity": "sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw==",
801 | "license": "MIT",
802 | "dependencies": {
803 | "buffer-equal-constant-time": "^1.0.1",
804 | "ecdsa-sig-formatter": "1.0.11",
805 | "safe-buffer": "^5.0.1"
806 | }
807 | },
808 | "node_modules/jws": {
809 | "version": "3.2.2",
810 | "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz",
811 | "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==",
812 | "license": "MIT",
813 | "dependencies": {
814 | "jwa": "^1.4.1",
815 | "safe-buffer": "^5.0.1"
816 | }
817 | },
818 | "node_modules/lodash.includes": {
819 | "version": "4.3.0",
820 | "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
821 | "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==",
822 | "license": "MIT"
823 | },
824 | "node_modules/lodash.isboolean": {
825 | "version": "3.0.3",
826 | "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz",
827 | "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==",
828 | "license": "MIT"
829 | },
830 | "node_modules/lodash.isinteger": {
831 | "version": "4.0.4",
832 | "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz",
833 | "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==",
834 | "license": "MIT"
835 | },
836 | "node_modules/lodash.isnumber": {
837 | "version": "3.0.3",
838 | "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz",
839 | "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==",
840 | "license": "MIT"
841 | },
842 | "node_modules/lodash.isplainobject": {
843 | "version": "4.0.6",
844 | "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
845 | "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==",
846 | "license": "MIT"
847 | },
848 | "node_modules/lodash.isstring": {
849 | "version": "4.0.1",
850 | "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz",
851 | "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==",
852 | "license": "MIT"
853 | },
854 | "node_modules/lodash.once": {
855 | "version": "4.1.1",
856 | "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
857 | "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==",
858 | "license": "MIT"
859 | },
860 | "node_modules/long": {
861 | "version": "5.3.2",
862 | "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz",
863 | "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==",
864 | "license": "Apache-2.0"
865 | },
866 | "node_modules/lru-cache": {
867 | "version": "7.18.3",
868 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz",
869 | "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==",
870 | "license": "ISC",
871 | "engines": {
872 | "node": ">=12"
873 | }
874 | },
875 | "node_modules/lru.min": {
876 | "version": "1.1.2",
877 | "resolved": "https://registry.npmjs.org/lru.min/-/lru.min-1.1.2.tgz",
878 | "integrity": "sha512-Nv9KddBcQSlQopmBHXSsZVY5xsdlZkdH/Iey0BlcBYggMd4two7cZnKOK9vmy3nY0O5RGH99z1PCeTpPqszUYg==",
879 | "license": "MIT",
880 | "engines": {
881 | "bun": ">=1.0.0",
882 | "deno": ">=1.30.0",
883 | "node": ">=8.0.0"
884 | },
885 | "funding": {
886 | "type": "github",
887 | "url": "https://github.com/sponsors/wellwelwel"
888 | }
889 | },
890 | "node_modules/mimic-response": {
891 | "version": "3.1.0",
892 | "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz",
893 | "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==",
894 | "license": "MIT",
895 | "engines": {
896 | "node": ">=10"
897 | },
898 | "funding": {
899 | "url": "https://github.com/sponsors/sindresorhus"
900 | }
901 | },
902 | "node_modules/minimist": {
903 | "version": "1.2.8",
904 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
905 | "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
906 | "license": "MIT",
907 | "funding": {
908 | "url": "https://github.com/sponsors/ljharb"
909 | }
910 | },
911 | "node_modules/mkdirp-classic": {
912 | "version": "0.5.3",
913 | "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz",
914 | "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==",
915 | "license": "MIT"
916 | },
917 | "node_modules/moo": {
918 | "version": "0.5.2",
919 | "resolved": "https://registry.npmjs.org/moo/-/moo-0.5.2.tgz",
920 | "integrity": "sha512-iSAJLHYKnX41mKcJKjqvnAN9sf0LMDTXDEvFv+ffuRR9a1MIuXLjMNL6EsnDHSkKLTWNqQQ5uo61P4EbU4NU+Q==",
921 | "license": "BSD-3-Clause"
922 | },
923 | "node_modules/ms": {
924 | "version": "2.1.3",
925 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
926 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
927 | "license": "MIT"
928 | },
929 | "node_modules/mssql": {
930 | "version": "12.0.0",
931 | "resolved": "https://registry.npmjs.org/mssql/-/mssql-12.0.0.tgz",
932 | "integrity": "sha512-FcDQ1Gwe4g3Mhw25R1Onr8N+jmqBTWE/pmtcgxYnAUSIf/vBQMvJfMnyMY8ruOICtBch5+Wgbcfd3REDQSlWpA==",
933 | "license": "MIT",
934 | "dependencies": {
935 | "@tediousjs/connection-string": "^0.6.0",
936 | "commander": "^11.0.0",
937 | "debug": "^4.3.3",
938 | "tarn": "^3.0.2",
939 | "tedious": "^19.0.0"
940 | },
941 | "bin": {
942 | "mssql": "bin/mssql"
943 | },
944 | "engines": {
945 | "node": ">=18"
946 | }
947 | },
948 | "node_modules/mysql2": {
949 | "version": "3.15.2",
950 | "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.15.2.tgz",
951 | "integrity": "sha512-kFm5+jbwR5mC+lo+3Cy46eHiykWSpUtTLOH3GE+AR7GeLq8PgfJcvpMiyVWk9/O53DjQsqm6a3VOOfq7gYWFRg==",
952 | "license": "MIT",
953 | "dependencies": {
954 | "aws-ssl-profiles": "^1.1.1",
955 | "denque": "^2.1.0",
956 | "generate-function": "^2.3.1",
957 | "iconv-lite": "^0.7.0",
958 | "long": "^5.2.1",
959 | "lru.min": "^1.0.0",
960 | "named-placeholders": "^1.1.3",
961 | "seq-queue": "^0.0.5",
962 | "sqlstring": "^2.3.2"
963 | },
964 | "engines": {
965 | "node": ">= 8.0"
966 | }
967 | },
968 | "node_modules/mysql2/node_modules/iconv-lite": {
969 | "version": "0.7.0",
970 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz",
971 | "integrity": "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==",
972 | "license": "MIT",
973 | "dependencies": {
974 | "safer-buffer": ">= 2.1.2 < 3.0.0"
975 | },
976 | "engines": {
977 | "node": ">=0.10.0"
978 | },
979 | "funding": {
980 | "type": "opencollective",
981 | "url": "https://opencollective.com/express"
982 | }
983 | },
984 | "node_modules/named-placeholders": {
985 | "version": "1.1.3",
986 | "resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.3.tgz",
987 | "integrity": "sha512-eLoBxg6wE/rZkJPhU/xRX1WTpkFEwDJEN96oxFrTsqBdbT5ec295Q+CoHrL9IT0DipqKhmGcaZmwOt8OON5x1w==",
988 | "license": "MIT",
989 | "dependencies": {
990 | "lru-cache": "^7.14.1"
991 | },
992 | "engines": {
993 | "node": ">=12.0.0"
994 | }
995 | },
996 | "node_modules/napi-build-utils": {
997 | "version": "2.0.0",
998 | "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-2.0.0.tgz",
999 | "integrity": "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==",
1000 | "license": "MIT"
1001 | },
1002 | "node_modules/native-duplexpair": {
1003 | "version": "1.0.0",
1004 | "resolved": "https://registry.npmjs.org/native-duplexpair/-/native-duplexpair-1.0.0.tgz",
1005 | "integrity": "sha512-E7QQoM+3jvNtlmyfqRZ0/U75VFgCls+fSkbml2MpgWkWyz3ox8Y58gNhfuziuQYGNNQAbFZJQck55LHCnCK6CA==",
1006 | "license": "MIT"
1007 | },
1008 | "node_modules/nearley": {
1009 | "version": "2.20.1",
1010 | "resolved": "https://registry.npmjs.org/nearley/-/nearley-2.20.1.tgz",
1011 | "integrity": "sha512-+Mc8UaAebFzgV+KpI5n7DasuuQCHA89dmwm7JXw3TV43ukfNQ9DnBH3Mdb2g/I4Fdxc26pwimBWvjIw0UAILSQ==",
1012 | "license": "MIT",
1013 | "dependencies": {
1014 | "commander": "^2.19.0",
1015 | "moo": "^0.5.0",
1016 | "railroad-diagrams": "^1.0.0",
1017 | "randexp": "0.4.6"
1018 | },
1019 | "bin": {
1020 | "nearley-railroad": "bin/nearley-railroad.js",
1021 | "nearley-test": "bin/nearley-test.js",
1022 | "nearley-unparse": "bin/nearley-unparse.js",
1023 | "nearleyc": "bin/nearleyc.js"
1024 | },
1025 | "funding": {
1026 | "type": "individual",
1027 | "url": "https://nearley.js.org/#give-to-nearley"
1028 | }
1029 | },
1030 | "node_modules/nearley/node_modules/commander": {
1031 | "version": "2.20.3",
1032 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
1033 | "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
1034 | "license": "MIT"
1035 | },
1036 | "node_modules/node-abi": {
1037 | "version": "3.77.0",
1038 | "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.77.0.tgz",
1039 | "integrity": "sha512-DSmt0OEcLoK4i3NuscSbGjOf3bqiDEutejqENSplMSFA/gmB8mkED9G4pKWnPl7MDU4rSHebKPHeitpDfyH0cQ==",
1040 | "license": "MIT",
1041 | "dependencies": {
1042 | "semver": "^7.3.5"
1043 | },
1044 | "engines": {
1045 | "node": ">=10"
1046 | }
1047 | },
1048 | "node_modules/once": {
1049 | "version": "1.4.0",
1050 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
1051 | "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
1052 | "license": "ISC",
1053 | "dependencies": {
1054 | "wrappy": "1"
1055 | }
1056 | },
1057 | "node_modules/open": {
1058 | "version": "10.2.0",
1059 | "resolved": "https://registry.npmjs.org/open/-/open-10.2.0.tgz",
1060 | "integrity": "sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA==",
1061 | "license": "MIT",
1062 | "dependencies": {
1063 | "default-browser": "^5.2.1",
1064 | "define-lazy-prop": "^3.0.0",
1065 | "is-inside-container": "^1.0.0",
1066 | "wsl-utils": "^0.1.0"
1067 | },
1068 | "engines": {
1069 | "node": ">=18"
1070 | },
1071 | "funding": {
1072 | "url": "https://github.com/sponsors/sindresorhus"
1073 | }
1074 | },
1075 | "node_modules/pg": {
1076 | "version": "8.16.3",
1077 | "resolved": "https://registry.npmjs.org/pg/-/pg-8.16.3.tgz",
1078 | "integrity": "sha512-enxc1h0jA/aq5oSDMvqyW3q89ra6XIIDZgCX9vkMrnz5DFTw/Ny3Li2lFQ+pt3L6MCgm/5o2o8HW9hiJji+xvw==",
1079 | "license": "MIT",
1080 | "dependencies": {
1081 | "pg-connection-string": "^2.9.1",
1082 | "pg-pool": "^3.10.1",
1083 | "pg-protocol": "^1.10.3",
1084 | "pg-types": "2.2.0",
1085 | "pgpass": "1.0.5"
1086 | },
1087 | "engines": {
1088 | "node": ">= 16.0.0"
1089 | },
1090 | "optionalDependencies": {
1091 | "pg-cloudflare": "^1.2.7"
1092 | },
1093 | "peerDependencies": {
1094 | "pg-native": ">=3.0.1"
1095 | },
1096 | "peerDependenciesMeta": {
1097 | "pg-native": {
1098 | "optional": true
1099 | }
1100 | }
1101 | },
1102 | "node_modules/pg-cloudflare": {
1103 | "version": "1.2.7",
1104 | "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.2.7.tgz",
1105 | "integrity": "sha512-YgCtzMH0ptvZJslLM1ffsY4EuGaU0cx4XSdXLRFae8bPP4dS5xL1tNB3k2o/N64cHJpwU7dxKli/nZ2lUa5fLg==",
1106 | "license": "MIT",
1107 | "optional": true
1108 | },
1109 | "node_modules/pg-connection-string": {
1110 | "version": "2.9.1",
1111 | "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.9.1.tgz",
1112 | "integrity": "sha512-nkc6NpDcvPVpZXxrreI/FOtX3XemeLl8E0qFr6F2Lrm/I8WOnaWNhIPK2Z7OHpw7gh5XJThi6j6ppgNoaT1w4w==",
1113 | "license": "MIT"
1114 | },
1115 | "node_modules/pg-int8": {
1116 | "version": "1.0.1",
1117 | "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz",
1118 | "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==",
1119 | "license": "ISC",
1120 | "engines": {
1121 | "node": ">=4.0.0"
1122 | }
1123 | },
1124 | "node_modules/pg-pool": {
1125 | "version": "3.10.1",
1126 | "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.10.1.tgz",
1127 | "integrity": "sha512-Tu8jMlcX+9d8+QVzKIvM/uJtp07PKr82IUOYEphaWcoBhIYkoHpLXN3qO59nAI11ripznDsEzEv8nUxBVWajGg==",
1128 | "license": "MIT",
1129 | "peerDependencies": {
1130 | "pg": ">=8.0"
1131 | }
1132 | },
1133 | "node_modules/pg-protocol": {
1134 | "version": "1.10.3",
1135 | "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.10.3.tgz",
1136 | "integrity": "sha512-6DIBgBQaTKDJyxnXaLiLR8wBpQQcGWuAESkRBX/t6OwA8YsqP+iVSiond2EDy6Y/dsGk8rh/jtax3js5NeV7JQ==",
1137 | "license": "MIT"
1138 | },
1139 | "node_modules/pg-types": {
1140 | "version": "2.2.0",
1141 | "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz",
1142 | "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==",
1143 | "license": "MIT",
1144 | "dependencies": {
1145 | "pg-int8": "1.0.1",
1146 | "postgres-array": "~2.0.0",
1147 | "postgres-bytea": "~1.0.0",
1148 | "postgres-date": "~1.0.4",
1149 | "postgres-interval": "^1.1.0"
1150 | },
1151 | "engines": {
1152 | "node": ">=4"
1153 | }
1154 | },
1155 | "node_modules/pgpass": {
1156 | "version": "1.0.5",
1157 | "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz",
1158 | "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==",
1159 | "license": "MIT",
1160 | "dependencies": {
1161 | "split2": "^4.1.0"
1162 | }
1163 | },
1164 | "node_modules/postgres-array": {
1165 | "version": "2.0.0",
1166 | "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz",
1167 | "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==",
1168 | "license": "MIT",
1169 | "engines": {
1170 | "node": ">=4"
1171 | }
1172 | },
1173 | "node_modules/postgres-bytea": {
1174 | "version": "1.0.0",
1175 | "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz",
1176 | "integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==",
1177 | "license": "MIT",
1178 | "engines": {
1179 | "node": ">=0.10.0"
1180 | }
1181 | },
1182 | "node_modules/postgres-date": {
1183 | "version": "1.0.7",
1184 | "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz",
1185 | "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==",
1186 | "license": "MIT",
1187 | "engines": {
1188 | "node": ">=0.10.0"
1189 | }
1190 | },
1191 | "node_modules/postgres-interval": {
1192 | "version": "1.2.0",
1193 | "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz",
1194 | "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==",
1195 | "license": "MIT",
1196 | "dependencies": {
1197 | "xtend": "^4.0.0"
1198 | },
1199 | "engines": {
1200 | "node": ">=0.10.0"
1201 | }
1202 | },
1203 | "node_modules/prebuild-install": {
1204 | "version": "7.1.3",
1205 | "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.3.tgz",
1206 | "integrity": "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==",
1207 | "license": "MIT",
1208 | "dependencies": {
1209 | "detect-libc": "^2.0.0",
1210 | "expand-template": "^2.0.3",
1211 | "github-from-package": "0.0.0",
1212 | "minimist": "^1.2.3",
1213 | "mkdirp-classic": "^0.5.3",
1214 | "napi-build-utils": "^2.0.0",
1215 | "node-abi": "^3.3.0",
1216 | "pump": "^3.0.0",
1217 | "rc": "^1.2.7",
1218 | "simple-get": "^4.0.0",
1219 | "tar-fs": "^2.0.0",
1220 | "tunnel-agent": "^0.6.0"
1221 | },
1222 | "bin": {
1223 | "prebuild-install": "bin.js"
1224 | },
1225 | "engines": {
1226 | "node": ">=10"
1227 | }
1228 | },
1229 | "node_modules/process": {
1230 | "version": "0.11.10",
1231 | "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
1232 | "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==",
1233 | "license": "MIT",
1234 | "engines": {
1235 | "node": ">= 0.6.0"
1236 | }
1237 | },
1238 | "node_modules/pump": {
1239 | "version": "3.0.3",
1240 | "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz",
1241 | "integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==",
1242 | "license": "MIT",
1243 | "dependencies": {
1244 | "end-of-stream": "^1.1.0",
1245 | "once": "^1.3.1"
1246 | }
1247 | },
1248 | "node_modules/railroad-diagrams": {
1249 | "version": "1.0.0",
1250 | "resolved": "https://registry.npmjs.org/railroad-diagrams/-/railroad-diagrams-1.0.0.tgz",
1251 | "integrity": "sha512-cz93DjNeLY0idrCNOH6PviZGRN9GJhsdm9hpn1YCS879fj4W+x5IFJhhkRZcwVgMmFF7R82UA/7Oh+R8lLZg6A==",
1252 | "license": "CC0-1.0"
1253 | },
1254 | "node_modules/randexp": {
1255 | "version": "0.4.6",
1256 | "resolved": "https://registry.npmjs.org/randexp/-/randexp-0.4.6.tgz",
1257 | "integrity": "sha512-80WNmd9DA0tmZrw9qQa62GPPWfuXJknrmVmLcxvq4uZBdYqb1wYoKTmnlGUchvVWe0XiLupYkBoXVOxz3C8DYQ==",
1258 | "license": "MIT",
1259 | "dependencies": {
1260 | "discontinuous-range": "1.0.0",
1261 | "ret": "~0.1.10"
1262 | },
1263 | "engines": {
1264 | "node": ">=0.12"
1265 | }
1266 | },
1267 | "node_modules/rc": {
1268 | "version": "1.2.8",
1269 | "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
1270 | "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
1271 | "license": "(BSD-2-Clause OR MIT OR Apache-2.0)",
1272 | "dependencies": {
1273 | "deep-extend": "^0.6.0",
1274 | "ini": "~1.3.0",
1275 | "minimist": "^1.2.0",
1276 | "strip-json-comments": "~2.0.1"
1277 | },
1278 | "bin": {
1279 | "rc": "cli.js"
1280 | }
1281 | },
1282 | "node_modules/readable-stream": {
1283 | "version": "4.7.0",
1284 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz",
1285 | "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==",
1286 | "license": "MIT",
1287 | "dependencies": {
1288 | "abort-controller": "^3.0.0",
1289 | "buffer": "^6.0.3",
1290 | "events": "^3.3.0",
1291 | "process": "^0.11.10",
1292 | "string_decoder": "^1.3.0"
1293 | },
1294 | "engines": {
1295 | "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
1296 | }
1297 | },
1298 | "node_modules/ret": {
1299 | "version": "0.1.15",
1300 | "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz",
1301 | "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==",
1302 | "license": "MIT",
1303 | "engines": {
1304 | "node": ">=0.12"
1305 | }
1306 | },
1307 | "node_modules/run-applescript": {
1308 | "version": "7.1.0",
1309 | "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.1.0.tgz",
1310 | "integrity": "sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==",
1311 | "license": "MIT",
1312 | "engines": {
1313 | "node": ">=18"
1314 | },
1315 | "funding": {
1316 | "url": "https://github.com/sponsors/sindresorhus"
1317 | }
1318 | },
1319 | "node_modules/safe-buffer": {
1320 | "version": "5.2.1",
1321 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
1322 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
1323 | "funding": [
1324 | {
1325 | "type": "github",
1326 | "url": "https://github.com/sponsors/feross"
1327 | },
1328 | {
1329 | "type": "patreon",
1330 | "url": "https://www.patreon.com/feross"
1331 | },
1332 | {
1333 | "type": "consulting",
1334 | "url": "https://feross.org/support"
1335 | }
1336 | ],
1337 | "license": "MIT"
1338 | },
1339 | "node_modules/safer-buffer": {
1340 | "version": "2.1.2",
1341 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
1342 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
1343 | "license": "MIT"
1344 | },
1345 | "node_modules/semver": {
1346 | "version": "7.7.2",
1347 | "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
1348 | "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
1349 | "license": "ISC",
1350 | "bin": {
1351 | "semver": "bin/semver.js"
1352 | },
1353 | "engines": {
1354 | "node": ">=10"
1355 | }
1356 | },
1357 | "node_modules/seq-queue": {
1358 | "version": "0.0.5",
1359 | "resolved": "https://registry.npmjs.org/seq-queue/-/seq-queue-0.0.5.tgz",
1360 | "integrity": "sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q=="
1361 | },
1362 | "node_modules/simple-concat": {
1363 | "version": "1.0.1",
1364 | "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz",
1365 | "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==",
1366 | "funding": [
1367 | {
1368 | "type": "github",
1369 | "url": "https://github.com/sponsors/feross"
1370 | },
1371 | {
1372 | "type": "patreon",
1373 | "url": "https://www.patreon.com/feross"
1374 | },
1375 | {
1376 | "type": "consulting",
1377 | "url": "https://feross.org/support"
1378 | }
1379 | ],
1380 | "license": "MIT"
1381 | },
1382 | "node_modules/simple-get": {
1383 | "version": "4.0.1",
1384 | "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz",
1385 | "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==",
1386 | "funding": [
1387 | {
1388 | "type": "github",
1389 | "url": "https://github.com/sponsors/feross"
1390 | },
1391 | {
1392 | "type": "patreon",
1393 | "url": "https://www.patreon.com/feross"
1394 | },
1395 | {
1396 | "type": "consulting",
1397 | "url": "https://feross.org/support"
1398 | }
1399 | ],
1400 | "license": "MIT",
1401 | "dependencies": {
1402 | "decompress-response": "^6.0.0",
1403 | "once": "^1.3.1",
1404 | "simple-concat": "^1.0.0"
1405 | }
1406 | },
1407 | "node_modules/split2": {
1408 | "version": "4.2.0",
1409 | "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz",
1410 | "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==",
1411 | "license": "ISC",
1412 | "engines": {
1413 | "node": ">= 10.x"
1414 | }
1415 | },
1416 | "node_modules/sprintf-js": {
1417 | "version": "1.1.3",
1418 | "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz",
1419 | "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==",
1420 | "license": "BSD-3-Clause"
1421 | },
1422 | "node_modules/sql-formatter": {
1423 | "version": "15.6.10",
1424 | "resolved": "https://registry.npmjs.org/sql-formatter/-/sql-formatter-15.6.10.tgz",
1425 | "integrity": "sha512-0bJOPQrRO/JkjQhiThVayq0hOKnI1tHI+2OTkmT7TGtc6kqS+V7kveeMzRW+RNQGxofmTmet9ILvztyuxv0cJQ==",
1426 | "license": "MIT",
1427 | "dependencies": {
1428 | "argparse": "^2.0.1",
1429 | "nearley": "^2.20.1"
1430 | },
1431 | "bin": {
1432 | "sql-formatter": "bin/sql-formatter-cli.cjs"
1433 | }
1434 | },
1435 | "node_modules/sqlstring": {
1436 | "version": "2.3.3",
1437 | "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.3.tgz",
1438 | "integrity": "sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==",
1439 | "license": "MIT",
1440 | "engines": {
1441 | "node": ">= 0.6"
1442 | }
1443 | },
1444 | "node_modules/string_decoder": {
1445 | "version": "1.3.0",
1446 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
1447 | "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
1448 | "license": "MIT",
1449 | "dependencies": {
1450 | "safe-buffer": "~5.2.0"
1451 | }
1452 | },
1453 | "node_modules/strip-json-comments": {
1454 | "version": "2.0.1",
1455 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
1456 | "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==",
1457 | "license": "MIT",
1458 | "engines": {
1459 | "node": ">=0.10.0"
1460 | }
1461 | },
1462 | "node_modules/tar-fs": {
1463 | "version": "2.1.4",
1464 | "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.4.tgz",
1465 | "integrity": "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==",
1466 | "license": "MIT",
1467 | "dependencies": {
1468 | "chownr": "^1.1.1",
1469 | "mkdirp-classic": "^0.5.2",
1470 | "pump": "^3.0.0",
1471 | "tar-stream": "^2.1.4"
1472 | }
1473 | },
1474 | "node_modules/tar-stream": {
1475 | "version": "2.2.0",
1476 | "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz",
1477 | "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==",
1478 | "license": "MIT",
1479 | "dependencies": {
1480 | "bl": "^4.0.3",
1481 | "end-of-stream": "^1.4.1",
1482 | "fs-constants": "^1.0.0",
1483 | "inherits": "^2.0.3",
1484 | "readable-stream": "^3.1.1"
1485 | },
1486 | "engines": {
1487 | "node": ">=6"
1488 | }
1489 | },
1490 | "node_modules/tar-stream/node_modules/bl": {
1491 | "version": "4.1.0",
1492 | "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
1493 | "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==",
1494 | "license": "MIT",
1495 | "dependencies": {
1496 | "buffer": "^5.5.0",
1497 | "inherits": "^2.0.4",
1498 | "readable-stream": "^3.4.0"
1499 | }
1500 | },
1501 | "node_modules/tar-stream/node_modules/buffer": {
1502 | "version": "5.7.1",
1503 | "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
1504 | "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
1505 | "funding": [
1506 | {
1507 | "type": "github",
1508 | "url": "https://github.com/sponsors/feross"
1509 | },
1510 | {
1511 | "type": "patreon",
1512 | "url": "https://www.patreon.com/feross"
1513 | },
1514 | {
1515 | "type": "consulting",
1516 | "url": "https://feross.org/support"
1517 | }
1518 | ],
1519 | "license": "MIT",
1520 | "dependencies": {
1521 | "base64-js": "^1.3.1",
1522 | "ieee754": "^1.1.13"
1523 | }
1524 | },
1525 | "node_modules/tar-stream/node_modules/readable-stream": {
1526 | "version": "3.6.2",
1527 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
1528 | "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
1529 | "license": "MIT",
1530 | "dependencies": {
1531 | "inherits": "^2.0.3",
1532 | "string_decoder": "^1.1.1",
1533 | "util-deprecate": "^1.0.1"
1534 | },
1535 | "engines": {
1536 | "node": ">= 6"
1537 | }
1538 | },
1539 | "node_modules/tarn": {
1540 | "version": "3.0.2",
1541 | "resolved": "https://registry.npmjs.org/tarn/-/tarn-3.0.2.tgz",
1542 | "integrity": "sha512-51LAVKUSZSVfI05vjPESNc5vwqqZpbXCsU+/+wxlOrUjk2SnFTt97v9ZgQrD4YmxYW1Px6w2KjaDitCfkvgxMQ==",
1543 | "license": "MIT",
1544 | "engines": {
1545 | "node": ">=8.0.0"
1546 | }
1547 | },
1548 | "node_modules/tedious": {
1549 | "version": "19.0.0",
1550 | "resolved": "https://registry.npmjs.org/tedious/-/tedious-19.0.0.tgz",
1551 | "integrity": "sha512-nmxNBAT72mMVCIYp0Ts0Zzd5+LBQjoXlqigCrIjSo2OERSi04vr3EHq3qJxv/zgrSkg7si03SoIIfekTAadA7w==",
1552 | "license": "MIT",
1553 | "dependencies": {
1554 | "@azure/core-auth": "^1.7.2",
1555 | "@azure/identity": "^4.2.1",
1556 | "@azure/keyvault-keys": "^4.4.0",
1557 | "@js-joda/core": "^5.6.1",
1558 | "@types/node": ">=18",
1559 | "bl": "^6.0.11",
1560 | "iconv-lite": "^0.6.3",
1561 | "js-md4": "^0.3.2",
1562 | "native-duplexpair": "^1.0.0",
1563 | "sprintf-js": "^1.1.3"
1564 | },
1565 | "engines": {
1566 | "node": ">=18.17"
1567 | }
1568 | },
1569 | "node_modules/tslib": {
1570 | "version": "2.8.1",
1571 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
1572 | "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
1573 | "license": "0BSD"
1574 | },
1575 | "node_modules/tunnel-agent": {
1576 | "version": "0.6.0",
1577 | "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
1578 | "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==",
1579 | "license": "Apache-2.0",
1580 | "dependencies": {
1581 | "safe-buffer": "^5.0.1"
1582 | },
1583 | "engines": {
1584 | "node": "*"
1585 | }
1586 | },
1587 | "node_modules/undici-types": {
1588 | "version": "7.14.0",
1589 | "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.14.0.tgz",
1590 | "integrity": "sha512-QQiYxHuyZ9gQUIrmPo3IA+hUl4KYk8uSA7cHrcKd/l3p1OTpZcM0Tbp9x7FAtXdAYhlasd60ncPpgu6ihG6TOA==",
1591 | "license": "MIT"
1592 | },
1593 | "node_modules/util-deprecate": {
1594 | "version": "1.0.2",
1595 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
1596 | "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
1597 | "license": "MIT"
1598 | },
1599 | "node_modules/uuid": {
1600 | "version": "8.3.2",
1601 | "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
1602 | "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
1603 | "license": "MIT",
1604 | "bin": {
1605 | "uuid": "dist/bin/uuid"
1606 | }
1607 | },
1608 | "node_modules/wrappy": {
1609 | "version": "1.0.2",
1610 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
1611 | "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
1612 | "license": "ISC"
1613 | },
1614 | "node_modules/wsl-utils": {
1615 | "version": "0.1.0",
1616 | "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-0.1.0.tgz",
1617 | "integrity": "sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw==",
1618 | "license": "MIT",
1619 | "dependencies": {
1620 | "is-wsl": "^3.1.0"
1621 | },
1622 | "engines": {
1623 | "node": ">=18"
1624 | },
1625 | "funding": {
1626 | "url": "https://github.com/sponsors/sindresorhus"
1627 | }
1628 | },
1629 | "node_modules/xtend": {
1630 | "version": "4.0.2",
1631 | "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
1632 | "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
1633 | "license": "MIT",
1634 | "engines": {
1635 | "node": ">=0.4"
1636 | }
1637 | }
1638 | }
1639 | }
1640 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "main": "./server/main.js",
3 | "scripts": {
4 | "start": "node ./server/main.js"
5 | },
6 | "type": "module",
7 | "dependencies": {
8 | "better-sqlite3": "^12.4.1",
9 | "mssql": "^12.0.0",
10 | "mysql2": "^3.15.2",
11 | "pg": "^8.16.3",
12 | "sql-formatter": "^15.6.10"
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/server/consumer.js:
--------------------------------------------------------------------------------
1 | import { driver } from "./driver.js";
2 |
3 | export class Consumer {
4 | static async createConnection(params) {
5 | const { id, dbType, connStr } = params;
6 | return await driver.createConnection(id, dbType, connStr);
7 | }
8 |
9 | static async getTableList(params) {
10 | const { id } = params;
11 | return await driver.getTableList(id);
12 | }
13 |
14 | static async getViewList(params) {
15 | const { id } = params;
16 | return await driver.getViewList(id);
17 | }
18 |
19 | static async getStoreProcedureList(params) {
20 | const { id } = params;
21 | return await driver.getStoreProcedureList(id);
22 | }
23 |
24 | static async getFunctionList(params) {
25 | const { id } = params;
26 | return await driver.getFunctionList(id);
27 | }
28 |
29 | static async getView(params) {
30 | const { id, view_name } = params;
31 | return await driver.getView(id, view_name);
32 | }
33 |
34 | static async getStoreProcedure(params) {
35 | const { id, procedure_name } = params;
36 | return await driver.getStoreProcedure(id, procedure_name);
37 | }
38 |
39 | static async getFunction(params) {
40 | const { id, function_name } = params;
41 | return await driver.getFunction(id, function_name);
42 | }
43 |
44 | static async query(params) {
45 | const { id, sql } = params;
46 | return await driver.query(id, sql);
47 | }
48 |
49 | static async getTable(params) {
50 | const { id, table_name } = params;
51 | return await driver.getTable(id, table_name);
52 | }
53 |
54 | static async getTrigger(params) {
55 | const { id, trig_name } = params;
56 | return await driver.getTrigger(id, trig_name);
57 | }
58 |
59 | static async getTriggerList(params) {
60 | const { id, table_name } = params;
61 | return await driver.getTriggerList(id, table_name);
62 | }
63 |
64 | static async generateSelectSQL(params) {
65 | const { id, table_name } = params;
66 | return await driver.generateSelectSQL(id, table_name);
67 | }
68 |
69 | static async generateInsertSQL(params) {
70 | const { id, table_name } = params;
71 | return await driver.generateInsertSQL(id, table_name);
72 | }
73 |
74 | static async generateUpdateSQL(params) {
75 | const { id, table_name } = params;
76 | return await driver.generateUpdateSQL(id, table_name);
77 | }
78 |
79 | static async format(params) {
80 | const { id, sql } = params;
81 | return await driver.format(id, sql);
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/server/db/mssql.js:
--------------------------------------------------------------------------------
1 | import sql from "mssql";
2 | import { format } from "sql-formatter";
3 |
4 | export class MsSql {
5 | #pool;
6 |
7 | async #init(config) {
8 | this.#pool = await new sql.ConnectionPool(config).connect();
9 | }
10 |
11 | static async createConnection(conn_str) {
12 | const config = sql.ConnectionPool.parseConnectionString(conn_str);
13 | const instance = new MsSql();
14 | await instance.#init(config);
15 | return instance;
16 | }
17 |
18 | format(sql) {
19 | return format(sql, {
20 | language: "tsql",
21 | });
22 | }
23 |
24 | async query(sql) {
25 | const start = Date.now();
26 | const result = await this.#pool.request().query(sql);
27 | const end = Date.now();
28 |
29 | return {
30 | duration: `${end - start}ms`,
31 | total: result.rowsAffected[0],
32 | rows: result.recordset ?? [],
33 | };
34 | }
35 |
36 | async getTableList() {
37 | const sql = `
38 | SELECT TABLE_NAME as table_name
39 | FROM INFORMATION_SCHEMA.TABLES
40 | WHERE TABLE_TYPE = 'BASE TABLE'
41 | ORDER BY TABLE_NAME
42 | `;
43 | return await this.query(sql);
44 | }
45 |
46 | async getViewList() {
47 | const sql = `
48 | SELECT TABLE_NAME as view_name
49 | FROM INFORMATION_SCHEMA.TABLES
50 | WHERE TABLE_TYPE = 'VIEW'
51 | ORDER BY TABLE_NAME
52 | `;
53 | return await this.query(sql);
54 | }
55 |
56 | async getStoreProcedureList() {
57 | const sql = `
58 | SELECT
59 | ROUTINE_SCHEMA as schema_name,
60 | ROUTINE_NAME as procedure_name
61 | FROM INFORMATION_SCHEMA.ROUTINES
62 | WHERE ROUTINE_TYPE = 'PROCEDURE'
63 | ORDER BY ROUTINE_SCHEMA, ROUTINE_NAME;
64 | `;
65 | return await this.query(sql);
66 | }
67 |
68 | async getFunctionList() {
69 | const sql = `
70 | SELECT
71 | ROUTINE_SCHEMA as schema_name,
72 | ROUTINE_NAME as function_name
73 | FROM INFORMATION_SCHEMA.ROUTINES
74 | WHERE ROUTINE_TYPE = 'FUNCTION'
75 | ORDER BY ROUTINE_SCHEMA, ROUTINE_NAME;
76 | `;
77 | return await this.query(sql);
78 | }
79 |
80 | async getView(view_name) {
81 | const sql = `
82 | SELECT VIEW_DEFINITION as 'definition'
83 | FROM INFORMATION_SCHEMA.VIEWS
84 | WHERE TABLE_NAME = '${view_name}'
85 | `;
86 | return await this.query(sql);
87 | }
88 |
89 | async getStoreProcedure(procedure_name) {
90 | const sql = `
91 | SELECT
92 | m.definition AS definition
93 | FROM sys.procedures p
94 | INNER JOIN sys.sql_modules m ON p.object_id = m.object_id
95 | WHERE p.name = '${procedure_name}';
96 | `;
97 | return await this.query(sql);
98 | }
99 |
100 | async getFunction(function_name) {
101 | const sql = `
102 | SELECT
103 | m.definition
104 | FROM sys.objects o
105 | JOIN sys.sql_modules m ON o.object_id = m.object_id
106 | JOIN sys.schemas s ON o.schema_id = s.schema_id
107 | WHERE o.type IN ('FN', 'IF', 'TF')
108 | AND o.name = '${function_name}';
109 | `;
110 | return await this.query(sql);
111 | }
112 |
113 | async getTable(table_name) {
114 | const sql = `
115 | SELECT
116 | c.column_id AS column_id,
117 | c.name AS column_name,
118 | t.name AS data_type,
119 | c.max_length AS max_length,
120 | c.is_nullable AS is_nullable,
121 | dc.definition AS default_value,
122 | MAX(CAST(CASE WHEN i.is_primary_key = 1 THEN 1 ELSE 0 END AS int)) AS is_pk,
123 | MAX(CAST(CASE WHEN i.is_unique = 1 THEN 1 ELSE 0 END AS int)) AS is_unique
124 | FROM sys.columns c
125 | LEFT JOIN sys.types t
126 | ON t.system_type_id = c.system_type_id
127 | AND t.user_type_id = t.system_type_id
128 | LEFT JOIN sys.default_constraints dc
129 | ON dc.object_id = c.default_object_id
130 | LEFT JOIN sys.index_columns ic
131 | ON ic.object_id = c.object_id
132 | AND c.column_id = ic.column_id
133 | LEFT JOIN sys.indexes i
134 | ON i.object_id = c.object_id
135 | AND i.index_id = ic.index_id
136 | WHERE OBJECT_NAME(c.object_id) = '${table_name}'
137 | GROUP BY c.column_id, c.name, t.name, c.max_length, c.is_nullable, dc.definition
138 | ORDER BY c.column_id;
139 | `;
140 | const result = await this.query(sql);
141 | result.rows = result.rows.map((item) => {
142 | return {
143 | column_name: item.column_name,
144 | data_type: item.data_type,
145 | max_length: item.max_length,
146 | is_nullable: item.is_nullable,
147 | default_value: item.default_value,
148 | is_pk: item.is_pk === 1 ? true : false,
149 | is_unique: item.is_unique === 1 ? true : false,
150 | };
151 | });
152 | return result;
153 | }
154 |
155 | async getTrigger(trig_name) {
156 | const sql = `
157 | SELECT m.definition
158 | FROM sys.sql_modules m
159 | JOIN sys.triggers t ON m.object_id = t.object_id
160 | WHERE t.name = '${trig_name}';
161 | `;
162 | return await this.query(sql);
163 | }
164 |
165 | async getTriggerList(table_name) {
166 | const sql = `
167 | SELECT t.name AS trigger_name
168 | FROM sys.triggers t
169 | WHERE t.parent_id = OBJECT_ID('${table_name}');
170 | `;
171 | return await this.query(sql);
172 | }
173 | }
174 |
--------------------------------------------------------------------------------
/server/db/mysql.js:
--------------------------------------------------------------------------------
1 | import mysql from "mysql2/promise";
2 | import { format } from "sql-formatter";
3 |
4 | export class MySql {
5 | #pool;
6 |
7 | async #init(config) {
8 | this.#pool = mysql.createPool(config);
9 | }
10 |
11 | static async createConnection(conn_str) {
12 | const instance = new MySql();
13 | await instance.#init(conn_str);
14 | return instance;
15 | }
16 |
17 | async query(sql) {
18 | const start = Date.now();
19 | const [result, _] = await this.#pool.execute(sql);
20 | const end = Date.now();
21 |
22 | let total, rows;
23 | if (Array.isArray(result)) {
24 | rows = result;
25 | total = result.length;
26 | } else {
27 | rows = [];
28 | total = result.affectedRows;
29 | }
30 | return {
31 | duration: `${end - start}ms`,
32 | total,
33 | rows,
34 | };
35 | }
36 |
37 | format(sql) {
38 | return format(sql, {
39 | language: "mysql",
40 | });
41 | }
42 |
43 | async getTableList() {
44 | const sql = `
45 | SELECT TABLE_NAME as table_name
46 | FROM information_schema.tables
47 | WHERE table_schema = DATABASE()
48 | AND table_type = 'BASE TABLE'
49 | ORDER BY TABLE_NAME
50 | `;
51 | return await this.query(sql);
52 | }
53 |
54 | async getViewList() {
55 | const sql = `
56 | SELECT TABLE_NAME as view_name
57 | FROM information_schema.tables
58 | WHERE table_schema = DATABASE()
59 | AND table_type = 'VIEW'
60 | ORDER BY TABLE_NAME
61 | `;
62 | return await this.query(sql);
63 | }
64 |
65 | async getStoreProcedureList() {
66 | const sql = `
67 | SELECT
68 | ROUTINE_SCHEMA as schema_name,
69 | ROUTINE_NAME as procedure_name
70 | FROM INFORMATION_SCHEMA.ROUTINES
71 | WHERE ROUTINE_TYPE = 'PROCEDURE'
72 | AND ROUTINE_SCHEMA = DATABASE()
73 | ORDER BY ROUTINE_NAME;
74 | `;
75 | return await this.query(sql);
76 | }
77 |
78 | async getFunctionList() {
79 | const sql = `
80 | SELECT
81 | ROUTINE_SCHEMA as schema_name,
82 | ROUTINE_NAME as function_name
83 | FROM INFORMATION_SCHEMA.ROUTINES
84 | WHERE ROUTINE_TYPE = 'FUNCTION'
85 | AND ROUTINE_SCHEMA = DATABASE()
86 | ORDER BY ROUTINE_NAME;
87 | `;
88 | return await this.query(sql);
89 | }
90 |
91 | async getView(view_name) {
92 | const sql = `
93 | SELECT
94 | VIEW_DEFINITION as 'definition'
95 | FROM INFORMATION_SCHEMA.VIEWS
96 | WHERE TABLE_NAME = '${view_name}'
97 | `;
98 | return await this.query(sql);
99 | }
100 |
101 | async getStoreProcedure(procedure_name) {
102 | const sql = `
103 | SELECT
104 | ROUTINE_DEFINITION as 'definition'
105 | FROM information_schema.ROUTINES
106 | WHERE ROUTINE_NAME = '${procedure_name}'
107 | AND ROUTINE_TYPE = 'PROCEDURE';
108 | `;
109 | return await this.query(sql);
110 | }
111 |
112 | async getFunction(function_name) {
113 | const sql = `
114 | SELECT
115 | ROUTINE_DEFINITION as 'definition'
116 | FROM information_schema.ROUTINES
117 | WHERE ROUTINE_NAME = '${function_name}'
118 | AND ROUTINE_TYPE = 'FUNCTION';
119 | `;
120 | return await this.query(sql);
121 | }
122 |
123 | async getTable(table_name) {
124 | const sql = `
125 | SELECT
126 | ORDINAL_POSITION AS column_id,
127 | COLUMN_NAME AS column_name,
128 | DATA_TYPE AS data_type,
129 | CHARACTER_MAXIMUM_LENGTH AS max_length,
130 | (IS_NULLABLE = 'YES') AS is_nullable,
131 | COLUMN_DEFAULT AS default_value,
132 | (COLUMN_KEY = 'PRI') AS is_pk,
133 | (COLUMN_KEY = 'UNI') AS is_unique
134 | FROM INFORMATION_SCHEMA.COLUMNS
135 | WHERE TABLE_SCHEMA = DATABASE()
136 | AND TABLE_NAME = '${table_name}'
137 | ORDER BY ORDINAL_POSITION;
138 | `;
139 | const result = await this.query(sql);
140 | result.rows = result.rows.map((item) => {
141 | return {
142 | column_name: item.column_name,
143 | data_type: item.data_type,
144 | max_length: item.max_length,
145 | is_nullable: item.is_nullable == "1" ? true : false,
146 | default_value: item.default_value,
147 | is_pk: item.is_pk === 1 ? true : false,
148 | is_unique: item.is_unique === 1 ? true : false,
149 | };
150 | });
151 | return result;
152 | }
153 |
154 | async getTriggerList(table_name) {
155 | const sql = `
156 | SELECT TRIGGER_NAME as trigger_name
157 | FROM information_schema.triggers
158 | WHERE EVENT_OBJECT_TABLE = '${table_name}'
159 | AND TRIGGER_SCHEMA = DATABASE();
160 | `;
161 | return await this.query(sql);
162 | }
163 |
164 | async getTrigger(trig_name) {
165 | const sql = `
166 | SELECT ACTION_STATEMENT AS definition
167 | FROM information_schema.triggers
168 | WHERE TRIGGER_NAME = '${trig_name}'
169 | AND TRIGGER_SCHEMA = DATABASE();
170 | `;
171 | return await this.query(sql);
172 | }
173 | }
174 |
--------------------------------------------------------------------------------
/server/db/postgres.js:
--------------------------------------------------------------------------------
1 | import pkg from "pg";
2 | import { format } from "sql-formatter";
3 |
4 | const { Pool } = pkg;
5 |
6 | export class Postgres {
7 | #pool;
8 |
9 | async #init(config) {
10 | this.#pool = new Pool(config);
11 | }
12 |
13 | static async createConnection(conn_str) {
14 | const instance = new Postgres();
15 | await instance.#init({ connectionString: conn_str });
16 | return instance;
17 | }
18 |
19 | async query(sql) {
20 | const client = await this.#pool.connect();
21 | try {
22 | const start = Date.now();
23 | const result = await client.query(sql);
24 | const end = Date.now();
25 |
26 | return {
27 | duration: `${end - start}ms`,
28 | total: result.rowCount,
29 | rows: result.rows,
30 | };
31 | } finally {
32 | client.release();
33 | }
34 | }
35 |
36 | format(sql) {
37 | return format(sql, {
38 | language: "postgresql",
39 | });
40 | }
41 |
42 | async getTableList() {
43 | const sql = `
44 | SELECT table_name
45 | FROM information_schema.tables
46 | WHERE table_schema = 'public'
47 | AND table_type = 'BASE TABLE'
48 | ORDER BY table_name
49 | `;
50 | return await this.query(sql);
51 | }
52 |
53 | async getViewList() {
54 | const sql = `
55 | SELECT table_name as view_name
56 | FROM information_schema.tables
57 | WHERE table_schema = 'public'
58 | AND table_type = 'VIEW'
59 | ORDER BY table_name;
60 | `;
61 | return await this.query(sql);
62 | }
63 |
64 | async getStoreProcedureList() {
65 | const sql = `
66 | SELECT
67 | routine_schema AS schema_name,
68 | routine_name AS procedure_name
69 | FROM information_schema.routines
70 | WHERE routine_type = 'PROCEDURE'
71 | AND routine_schema NOT IN ('pg_catalog', 'information_schema')
72 | ORDER BY routine_schema, routine_name;
73 | `;
74 | return await this.query(sql);
75 | }
76 |
77 | async getFunctionList() {
78 | const sql = `
79 | SELECT
80 | routine_schema AS schema_name,
81 | routine_name AS function_name
82 | FROM information_schema.routines
83 | WHERE routine_type = 'FUNCTION'
84 | AND routine_schema NOT IN ('pg_catalog', 'information_schema')
85 | ORDER BY routine_schema, routine_name;
86 | `;
87 | return await this.query(sql);
88 | }
89 |
90 | async getView(view_name) {
91 | const sql = `
92 | SELECT definition as 'definition'
93 | FROM pg_views
94 | WHERE viewname = '${view_name}'
95 | `;
96 | return await this.query(sql);
97 | }
98 |
99 | async getStoreProcedure(procedure_name) {
100 | const sql = `
101 | SELECT
102 | pg_get_functiondef(p.oid) AS definition
103 | FROM pg_proc p
104 | JOIN pg_namespace n ON n.oid = p.pronamespace
105 | WHERE p.prokind = 'p'
106 | AND p.proname = '${procedure_name}';
107 | `;
108 | return await this.query(sql);
109 | }
110 |
111 | async getFunction(function_name) {
112 | const sql = `
113 | SELECT
114 | pg_get_functiondef(p.oid) AS definition
115 | FROM pg_proc p
116 | JOIN pg_namespace n ON n.oid = p.pronamespace
117 | WHERE p.prokind = 'f'
118 | AND p.proname = '${function_name}';
119 | `;
120 | return await this.query(sql);
121 | }
122 |
123 | async getTable(table_name) {
124 | const sql = `
125 | SELECT
126 | a.attnum AS column_id,
127 | a.attname AS column_name,
128 | format_type(a.atttypid, a.atttypmod) AS data_type,
129 | col.character_maximum_length AS max_length,
130 | NOT a.attnotnull AS is_nullable,
131 | pg_get_expr(ad.adbin, ad.adrelid) AS default_value,
132 | CASE WHEN ct.contype = 'p' THEN 1 ELSE 0 END AS is_pk,
133 | CASE WHEN ct.contype = 'u' THEN 1 ELSE 0 END AS is_unique
134 | FROM pg_attribute a
135 | JOIN pg_class c ON a.attrelid = c.oid
136 | JOIN pg_namespace n ON n.oid = c.relnamespace
137 | LEFT JOIN information_schema.columns col
138 | ON col.table_schema = n.nspname AND col.table_name = c.relname AND col.column_name = a.attname
139 | LEFT JOIN pg_attrdef ad ON ad.adrelid = a.attrelid AND ad.adnum = a.attnum
140 | LEFT JOIN pg_constraint ct ON ct.conrelid = c.oid AND a.attnum = ANY(ct.conkey)
141 | WHERE c.relname = '${table_name}'
142 | AND a.attnum > 0
143 | AND NOT a.attisdropped
144 | GROUP BY a.attnum, a.attname, format_type(a.atttypid, a.atttypmod),
145 | col.character_maximum_length, a.attnotnull, ad.adbin, ad.adrelid, ct.contype
146 | ORDER BY a.attnum;
147 | `;
148 | const result = await this.query(sql);
149 | result.rows = result.rows.map((item) => {
150 | return {
151 | column_name: item.column_name,
152 | data_type: item.data_type,
153 | max_length: item.max_length,
154 | is_nullable: item.is_nullable,
155 | default_value: item.default_value,
156 | is_pk: item.is_pk === 1 ? true : false,
157 | is_unique: item.is_unique === 1 ? true : false,
158 | };
159 | });
160 | return result;
161 | }
162 |
163 | async getTriggerList(table_name) {
164 | const sql = `
165 | SELECT tg.tgname AS trigger_name
166 | FROM pg_trigger tg
167 | JOIN pg_class tbl ON tg.tgrelid = tbl.oid
168 | JOIN pg_namespace ns ON tbl.relnamespace = ns.oid
169 | WHERE tbl.relname = '${table_name}'
170 | AND ns.nspname = 'public'
171 | AND NOT tg.tgisinternal;
172 | `;
173 | return await this.query(sql);
174 | }
175 |
176 | async getTrigger(trig_name) {
177 | const sql = `
178 | SELECT pg_get_triggerdef(t.oid, true) AS definition
179 | FROM pg_trigger t
180 | JOIN pg_class c ON t.tgrelid = c.oid
181 | JOIN pg_namespace n ON c.relnamespace = n.oid
182 | WHERE t.tgname = '${trig_name}'
183 | AND NOT t.tgisinternal;
184 | `;
185 | return await this.query(sql);
186 | }
187 | }
188 |
--------------------------------------------------------------------------------
/server/db/sqlite.js:
--------------------------------------------------------------------------------
1 | import Database from "better-sqlite3";
2 | import { format } from "sql-formatter";
3 |
4 | export class Sqlite {
5 | #db;
6 |
7 | constructor(file_path) {
8 | this.#db = new Database(file_path);
9 | }
10 |
11 | static async createConnection(file_path) {
12 | return new Sqlite(file_path);
13 | }
14 |
15 | query(sql) {
16 | const stmt = this.#db.prepare(sql);
17 |
18 | let total, rows;
19 | const start = Date.now();
20 | try {
21 | rows = stmt.all();
22 | total = rows.length;
23 | } catch (err) {
24 | const info = stmt.run();
25 | rows = [];
26 | total = info.changes;
27 | }
28 | const end = Date.now();
29 |
30 | return {
31 | duration: `${end - start}ms`,
32 | total,
33 | rows,
34 | };
35 | }
36 |
37 | format(sql) {
38 | return format(sql, {
39 | language: "sqlite",
40 | });
41 | }
42 |
43 | getTableList() {
44 | const sql = `
45 | SELECT name as table_name
46 | FROM sqlite_master
47 | WHERE type='table'
48 | AND name NOT LIKE 'sqlite_%'
49 | ORDER BY name;
50 | `;
51 | return this.query(sql);
52 | }
53 |
54 | getViewList() {
55 | const sql = `
56 | SELECT name as view_name
57 | FROM sqlite_master
58 | WHERE type='view'
59 | AND name NOT LIKE 'sqlite_%'
60 | ORDER BY name;
61 | `;
62 | return this.query(sql);
63 | }
64 |
65 | getStoreProcedureList() {
66 | return "Not Supported";
67 | }
68 |
69 | getFunctionList() {
70 | return "Not Supported";
71 | }
72 |
73 | getView(view_name) {
74 | const sql = `
75 | SELECT sql as 'definition'
76 | FROM sqlite_master
77 | WHERE type = 'view'
78 | AND name = '${view_name}'
79 | `;
80 | return this.query(sql);
81 | }
82 |
83 | getStoreProcedure() {
84 | return "Not Supported";
85 | }
86 |
87 | getFunction() {
88 | return "Not Supported";
89 | }
90 |
91 | getTable(table_name) {
92 | const indexes = this.query(`PRAGMA index_list('${table_name}');`);
93 |
94 | const indexMap = {};
95 | for (const idx of indexes.rows) {
96 | if (idx.unique) {
97 | const cols = this.query(`PRAGMA index_info('${idx.name}')`);
98 | for (const col of cols.rows) {
99 | indexMap[col.name] = idx.name;
100 | }
101 | }
102 | }
103 |
104 | const result = this.query(`PRAGMA table_info('${table_name}');`);
105 | result.rows = result.rows.map((item) => {
106 | return {
107 | column_name: item.name,
108 | data_type: item.type,
109 | max_length: null,
110 | is_nullable: item.notnull === 1 ? true : false,
111 | default_value: item.dflt_value,
112 | is_pk: item.pk === 1 ? true : false,
113 | is_unique: indexMap[item.column_name] ? true : false,
114 | };
115 | });
116 | return result;
117 | }
118 |
119 | getTriggerList(table_name) {
120 | const sql = `
121 | SELECT name AS trigger_name
122 | FROM sqlite_master
123 | WHERE type = 'trigger'
124 | AND tbl_name = '${table_name}';
125 | `;
126 | return this.query(sql);
127 | }
128 |
129 | getTrigger(trig_name) {
130 | const sql = `
131 | SELECT sql AS definition
132 | FROM sqlite_master
133 | WHERE type = 'trigger'
134 | AND name = '${trig_name}';
135 | `;
136 | return this.query(sql);
137 | }
138 | }
139 |
--------------------------------------------------------------------------------
/server/driver.js:
--------------------------------------------------------------------------------
1 | import { MsSql } from "./db/mssql.js";
2 | import { MySql } from "./db/mysql.js";
3 | import { Postgres } from "./db/postgres.js";
4 | import { Sqlite } from "./db/sqlite.js";
5 |
6 | const DB_TYPE = {
7 | MSSQL: "mssql",
8 | SQLITE: "sqlite3",
9 | POSTGRES: "postgresql",
10 | MYSQL: "mysql",
11 | };
12 |
13 | const DB_MAP = {
14 | [DB_TYPE.MSSQL]: MsSql,
15 | [DB_TYPE.SQLITE]: Sqlite,
16 | [DB_TYPE.POSTGRES]: Postgres,
17 | [DB_TYPE.MYSQL]: MySql,
18 | };
19 |
20 | class Driver {
21 | #connections = new Map();
22 |
23 | async createConnection(id, db_type, conn_str) {
24 | if (this.#connections.has(id)) {
25 | return "connected";
26 | }
27 |
28 | const db = DB_MAP[db_type];
29 | if (!db) {
30 | throw new Error(`${db_type} is not supported`);
31 | }
32 |
33 | const conn = await db.createConnection(conn_str);
34 | this.#connections.set(id, conn);
35 | return "connected";
36 | }
37 |
38 | async query(id, sql) {
39 | const conn = this.#connections.get(id);
40 | return await conn.query(sql);
41 | }
42 |
43 | async getTableList(id) {
44 | const conn = this.#connections.get(id);
45 | return await conn.getTableList();
46 | }
47 |
48 | async getViewList(id) {
49 | const conn = this.#connections.get(id);
50 | return await conn.getViewList();
51 | }
52 |
53 | async getStoreProcedureList(id) {
54 | const conn = this.#connections.get(id);
55 | return await conn.getStoreProcedureList();
56 | }
57 |
58 | async getFunctionList(id) {
59 | const conn = this.#connections.get(id);
60 | return await conn.getFunctionList();
61 | }
62 |
63 | async getView(id, view_name) {
64 | const conn = this.#connections.get(id);
65 | return await conn.getView(view_name);
66 | }
67 |
68 | async getStoreProcedure(id, procedure_name) {
69 | const conn = this.#connections.get(id);
70 | return await conn.getStoreProcedure(procedure_name);
71 | }
72 |
73 | async getFunction(id, function_name) {
74 | const conn = this.#connections.get(id);
75 | return await conn.getFunction(function_name);
76 | }
77 |
78 | async getTable(id, table_name) {
79 | const conn = this.#connections.get(id);
80 | return await conn.getTable(table_name);
81 | }
82 |
83 | async getTrigger(id, trig_name) {
84 | const conn = this.#connections.get(id);
85 | return await conn.getTrigger(trig_name);
86 | }
87 |
88 | async getTriggerList(id, table_name) {
89 | const conn = this.#connections.get(id);
90 | return await conn.getTriggerList(table_name);
91 | }
92 |
93 | async generateSelectSQL(id, table_name) {
94 | const conn = this.#connections.get(id);
95 | const table = await conn.getTable(table_name);
96 | const columns = table.rows.map((col) => {
97 | return col.column_name;
98 | });
99 | const pkey = table.rows
100 | .filter((col) => col.is_pk)
101 | .map((col) => {
102 | return `${col.column_name} = @${col.column_name}`;
103 | });
104 |
105 | const sql = `SELECT ${columns.join(",")} FROM ${table_name} WHERE ${pkey.join(" AND ")}`;
106 | return conn.format(sql);
107 | }
108 |
109 | async generateUpdateSQL(id, table_name) {
110 | const conn = this.#connections.get(id);
111 | const table = await conn.getTable(table_name);
112 | const columns = table.rows
113 | .filter((col) => !col.is_pk)
114 | .map((col) => {
115 | return `${col.column_name} = @${col.column_name}`;
116 | });
117 | const pkey = table.rows
118 | .filter((col) => col.is_pk)
119 | .map((col) => {
120 | return `${col.column_name} = @${col.column_name}`;
121 | });
122 |
123 | const sql = `UPDATE ${table_name} SET ${columns.join(",")} WHERE ${pkey.join(" AND ")}`;
124 | return conn.format(sql);
125 | }
126 |
127 | async generateInsertSQL(id, table_name) {
128 | const conn = this.#connections.get(id);
129 | const table = await conn.getTable(table_name);
130 | const columns = table.rows.map((col) => {
131 | return col.column_name;
132 | });
133 | const values = table.rows.map((col) => {
134 | return `@${col.column_name}`;
135 | });
136 |
137 | const sql = `INSERT INTO(${columns.join(",")}) VALUES (${values.join(",")})`;
138 | return conn.format(sql);
139 | }
140 |
141 | format(id, sql) {
142 | const conn = this.#connections.get(id);
143 | return conn.format(sql);
144 | }
145 | }
146 |
147 | export const driver = new Driver();
148 |
--------------------------------------------------------------------------------
/server/main.js:
--------------------------------------------------------------------------------
1 | import readline from "readline";
2 | import { RPC } from "./rpc.js";
3 |
4 | const rl = readline.createInterface({
5 | input: process.stdin,
6 | output: process.stdout,
7 | terminal: false,
8 | });
9 |
10 | rl.on("line", async (line) => {
11 | try {
12 | const req = RPC.parseData(line);
13 | RPC.validRequest(req);
14 | const res = await RPC.exec(req);
15 | if (res) {
16 | process.stdout.write(JSON.stringify(res) + "\n");
17 | }
18 | } catch (err) {
19 | process.stderr.write(JSON.stringify(err) + "\n");
20 | }
21 | });
22 |
--------------------------------------------------------------------------------
/server/rpc.js:
--------------------------------------------------------------------------------
1 | import { Consumer } from "./consumer.js";
2 |
3 | const METHODS = {
4 | CREATE_CONNECTION: "create_connection",
5 | GET_TABLE_LIST: "get_table_list",
6 | GET_VIEW_LIST: "get_view_list",
7 | GET_STORE_PROCEDURE_LIST: "get_store_procedure_list",
8 | GET_FUNCTION_LIST: "get_function_list",
9 | GET_VIEW: "get_view",
10 | GET_STORE_PROCEDURE: "get_store_procedure",
11 | GET_FUNCTION: "get_function",
12 | GET_TABLE: "get_table",
13 | GET_TRIGGER: "get_trigger",
14 | GET_TRIGGER_LIST: "get_trigger_list",
15 | GENERATE_SELECT_SQL: "generate_select_sql",
16 | GENERATE_INSERT_SQL: "generate_insert_sql",
17 | GENERATE_UPDATE_SQL: "generate_update_sql",
18 | QUERY: "query",
19 | FORMAT: "format",
20 | };
21 |
22 | const handlers = {
23 | [METHODS.CREATE_CONNECTION]: (params) => Consumer.createConnection(params),
24 | [METHODS.GET_TABLE_LIST]: (params) => Consumer.getTableList(params),
25 | [METHODS.GET_VIEW_LIST]: (params) => Consumer.getViewList(params),
26 | [METHODS.QUERY]: (params) => Consumer.query(params),
27 | [METHODS.GET_STORE_PROCEDURE_LIST]: (params) =>
28 | Consumer.getStoreProcedureList(params),
29 | [METHODS.GET_FUNCTION_LIST]: (params) => Consumer.getFunctionList(params),
30 | [METHODS.GET_VIEW]: (params) => Consumer.getView(params),
31 | [METHODS.GET_STORE_PROCEDURE]: (params) => Consumer.getStoreProcedure(params),
32 | [METHODS.GET_FUNCTION]: (params) => Consumer.getFunction(params),
33 | [METHODS.GET_TABLE]: (params) => Consumer.getTable(params),
34 | [METHODS.GET_TRIGGER]: (params) => Consumer.getTrigger(params),
35 | [METHODS.GET_TRIGGER_LIST]: (params) => Consumer.getTriggerList(params),
36 | [METHODS.GENERATE_SELECT_SQL]: (params) => Consumer.generateSelectSQL(params),
37 | [METHODS.GENERATE_INSERT_SQL]: (params) => Consumer.generateInsertSQL(params),
38 | [METHODS.GENERATE_UPDATE_SQL]: (params) => Consumer.generateUpdateSQL(params),
39 | [METHODS.FORMAT]: (params) => Consumer.format(params),
40 | };
41 |
42 | export class RPC {
43 | static parseData(data) {
44 | try {
45 | return JSON.parse(data);
46 | } catch (err) {
47 | throw this.parseError(err);
48 | }
49 | }
50 |
51 | static validRequest(decoded) {
52 | if (!decoded.jsonrpc) {
53 | throw this.invalidRequest("jsonrpc is required");
54 | }
55 |
56 | if (decoded.jsonrpc != "2.0") {
57 | throw this.invalidRequest("jsonrpc 2.0 only supported");
58 | }
59 |
60 | if (!decoded.method) {
61 | throw this.invalidRequest("method is required");
62 | }
63 |
64 | if (typeof decoded.method !== "string") {
65 | throw this.invalidRequest("method must be a string");
66 | }
67 |
68 | if (decoded.params !== undefined && typeof decoded.params !== "object") {
69 | throw this.invalidRequest(
70 | "params must be an array or object if provided",
71 | );
72 | }
73 |
74 | if (decoded.id !== undefined) {
75 | const t = typeof decoded.id;
76 | if (!(t === "string" || t === "number" || decoded.id === null)) {
77 | throw this.invalidRequest(
78 | "id must be string, number, or null if provided",
79 | );
80 | }
81 | }
82 | }
83 |
84 | static async exec(req) {
85 | const { id, method, params } = req;
86 |
87 | if (!handlers[method]) throw this.methodNotFound(id, `${method} not found`);
88 |
89 | try {
90 | const data = await handlers[method](params);
91 | if (data) {
92 | return this.ok(id, data);
93 | }
94 | } catch (err) {
95 | throw this.internalError(req.id, err.stack);
96 | }
97 | }
98 |
99 | static ok(id, result) {
100 | return {
101 | jsonrpc: "2.0",
102 | result: JSON.stringify(result, null, 2),
103 | id,
104 | };
105 | }
106 |
107 | static methodNotFound(id, data) {
108 | return {
109 | jsonrpc: "2.0",
110 | id,
111 | error: {
112 | code: -32601,
113 | message: "Method not found",
114 | data,
115 | },
116 | };
117 | }
118 |
119 | static parseError(data) {
120 | return {
121 | jsonrpc: "2.0",
122 | error: {
123 | code: -32700,
124 | message: "Parse error",
125 | data,
126 | },
127 | };
128 | }
129 |
130 | static invalidRequest(data) {
131 | return {
132 | jsonrpc: "2.0",
133 | error: {
134 | code: -32600,
135 | message: "Invalid Request",
136 | data,
137 | },
138 | };
139 | }
140 |
141 | static internalError(id, data) {
142 | return {
143 | jsonrpc: "2.0",
144 | id,
145 | error: {
146 | code: -32603,
147 | message: "Internal error",
148 | data,
149 | },
150 | };
151 | }
152 | }
153 |
--------------------------------------------------------------------------------
/stylua.toml:
--------------------------------------------------------------------------------
1 | line_endings = "Unix"
2 | indent_type = "Spaces"
3 | indent_width = 2
4 | quote_style = "AutoPreferDouble"
5 | call_parentheses = "Always"
6 |
--------------------------------------------------------------------------------