sql-dev-inspector 1.0.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +10 -0
- package/package.json +1 -1
- package/README.VI.md +0 -341
- package/docs/PUBLISH-AND-INSTALL.md +0 -267
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.0.1] - 2026-10-19
|
|
3
4
|
|
|
5
|
+
### Changed
|
|
6
|
+
|
|
7
|
+
- CI: publish to npm automatically through trusted publishing (OIDC) when a GitHub Release is published. Provenance is attached automatically.
|
|
8
|
+
|
|
9
|
+
## [1.0.0] - 2026-10-19
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- Initial release.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sql-dev-inspector",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.0.
|
|
4
|
+
"version": "1.0.1",
|
|
5
5
|
"description": "Dev-only SQL inspector for Node apps that talk to MySQL through mysql2 (Drizzle, Knex, Sequelize, TypeORM…): see which SQL each request ran, how transactions and subqueries nest, N+1 and slow queries. Terminal tree, web UI and a floating in-app launcher.",
|
|
6
6
|
"author": "Nhu Duy Thin",
|
|
7
7
|
"license": "MIT",
|
package/README.VI.md
DELETED
|
@@ -1,341 +0,0 @@
|
|
|
1
|
-
# sql-dev-inspector
|
|
2
|
-
|
|
3
|
-
> 🇬🇧 [English README](README.md) — bản chung chung cho cộng đồng. File này (`README.VI.md`) là bản tiếng Việt chi tiết, dành cho tác giả / người bảo trì.
|
|
4
|
-
|
|
5
|
-
> Công cụ **chỉ dùng khi dev** cho mọi ứng dụng Node.js nói chuyện với MySQL qua [`mysql2`](https://github.com/sidorares/node-mysql2).
|
|
6
|
-
> Khi client gọi một API, bạn thấy ngay backend đã chạy **những câu SQL nào, theo thứ tự nào, nằm trong transaction / savepoint nào, subquery lồng mấy tầng, mỗi câu mất bao lâu, trả về bao nhiêu dòng** — kèm cảnh báo N+1, query lặp, query chậm.
|
|
7
|
-
|
|
8
|
-
```
|
|
9
|
-
GET /api/orders/42 → 200 163ms total · 12 queries · 148ms in SQL
|
|
10
|
-
├─ SELECT order_items 3.86ms · 2 rows
|
|
11
|
-
│ select `id`, `sku` from `order_items` where `order_id` = 11
|
|
12
|
-
├─ SELECT customers, orders ⤷subquery×3 (depth 3) 1.50ms · 2 rows
|
|
13
|
-
├─ TRANSACTION [conn 101] committed 10.2ms
|
|
14
|
-
│ ├─ INSERT orders 1.39ms · 1 affected
|
|
15
|
-
│ ├─ SAVEPOINT sp1 [conn 101] rolled-back 4.30ms
|
|
16
|
-
│ │ └─ SELECT 0.18ms ✖ You have an error in your SQL syntax …
|
|
17
|
-
│ └─ SELECT orders 1.33ms · 2 rows
|
|
18
|
-
⚠ Nghi N+1: 4 lần, tổng 8.4ms — select `id`, `sku` from `order_items` where `order_id` = ?
|
|
19
|
-
✖ Lỗi SQL: You have an error in your SQL syntax …
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
## Mục lục
|
|
23
|
-
|
|
24
|
-
1. [Tính năng](#tính-năng)
|
|
25
|
-
2. [Yêu cầu](#yêu-cầu)
|
|
26
|
-
3. [Cài đặt](#cài-đặt)
|
|
27
|
-
4. [Bắt đầu nhanh](#bắt-đầu-nhanh) — Nuxt · Nitro · Express/Connect · `http` thuần · job/cron
|
|
28
|
-
5. [Cách xem kết quả](#cách-xem-kết-quả) — terminal · trang web · nút nổi trong app
|
|
29
|
-
6. [Cảnh báo tự động](#cảnh-báo-tự-động)
|
|
30
|
-
7. [Cấu hình (biến môi trường)](#cấu-hình-biến-môi-trường)
|
|
31
|
-
8. [API](#api)
|
|
32
|
-
9. [Cách hoạt động](#cách-hoạt-động)
|
|
33
|
-
10. [An toàn & quyền riêng tư](#an-toàn--quyền-riêng-tư)
|
|
34
|
-
11. [Giới hạn đã biết](#giới-hạn-đã-biết)
|
|
35
|
-
12. [Xử lý sự cố](#xử-lý-sự-cố)
|
|
36
|
-
13. [Phát triển & test](#phát-triển--test)
|
|
37
|
-
14. [Giấy phép](#giấy-phép)
|
|
38
|
-
|
|
39
|
-
Hướng dẫn đưa lên git public, publish npm và cài vào dự án khác: [docs/PUBLISH-AND-INSTALL.md](docs/PUBLISH-AND-INSTALL.md).
|
|
40
|
-
|
|
41
|
-
## Tính năng
|
|
42
|
-
|
|
43
|
-
- **Gắn câu SQL vào đúng request** (kể cả khi chạy song song, kể cả khi pool connection bị bão hòa) bằng `AsyncLocalStorage`.
|
|
44
|
-
- **Cây lồng nhau**: `begin … commit` thành node transaction, `savepoint … release / rollback to` thành node con, trạng thái committed / rolled-back / open. Hai transaction chạy song song trong cùng request không bị trộn.
|
|
45
|
-
- **Subquery**: đo độ sâu `(SELECT …)` và số subquery; SQL được format theo cấp lồng để đọc như một cái cây.
|
|
46
|
-
- **Cảnh báo**: N+1, query lặp y hệt, query chậm, lỗi SQL, `SELECT *`, subquery sâu, quá nhiều query (và tuỳ chọn: quy ước "SELECT ngoài transaction").
|
|
47
|
-
- **Đa ngôn ngữ**: English, Tiếng Việt, 日本語 — terminal, trang web và nút nổi — thêm ngôn ngữ mới chỉ cần thêm một khối văn bản (xem [Ngôn ngữ](#ngôn-ngữ-i18n)).
|
|
48
|
-
- **Giao diện chuyên nghiệp**: sáng / tối / theo hệ thống, responsive tới cả panel dock hẹp, điều hướng bằng bàn phím, SQL có tô màu cú pháp, biểu đồ waterfall cho từng câu.
|
|
49
|
-
- **Ba cách xem**: cây in ra terminal · trang web live (`/__sql-inspector/`) · **nút nổi** trong chính ứng dụng của bạn (Nuxt tự gắn; ứng dụng khác gắn bằng 1 dòng).
|
|
50
|
-
- **Không sửa code truy vấn**: hoạt động với mọi thứ đi qua `mysql2` — mysql2 thuần, Drizzle (đã kiểm chứng), và về nguyên lý cả Knex / Sequelize / TypeORM… (xem [Giới hạn](#giới-hạn-đã-biết)).
|
|
51
|
-
- **Không phụ thuộc runtime nào** ngoài `mysql2` (peer). Trang web một file, không tải gì từ CDN.
|
|
52
|
-
- **An toàn mặc định**: không bao giờ chạy khi `NODE_ENV=production`; production là no-op hoàn toàn.
|
|
53
|
-
|
|
54
|
-
## Yêu cầu
|
|
55
|
-
|
|
56
|
-
- Node.js **≥ 20**
|
|
57
|
-
- `mysql2` **≥ 3** (peer dependency; đã kiểm chứng với 3.20)
|
|
58
|
-
- Ứng dụng của bạn phải gửi SQL qua `mysql2` (pool, connection, hoặc ORM dùng mysql2 bên dưới)
|
|
59
|
-
|
|
60
|
-
## Cài đặt
|
|
61
|
-
|
|
62
|
-
```bash
|
|
63
|
-
npm install --save-dev sql-dev-inspector
|
|
64
|
-
# hoặc
|
|
65
|
-
pnpm add -D sql-dev-inspector
|
|
66
|
-
yarn add -D sql-dev-inspector
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
> Tên package và các cách cài khác (từ GitHub, từ file `.tgz`) xem [docs/PUBLISH-AND-INSTALL.md](docs/PUBLISH-AND-INSTALL.md).
|
|
70
|
-
> Nếu ứng dụng của bạn import tool trong code chạy cả ở production (ví dụ Express), hãy cài vào `dependencies` thay vì `devDependencies` — tool tự thành no-op khi `NODE_ENV=production`.
|
|
71
|
-
|
|
72
|
-
## Bắt đầu nhanh
|
|
73
|
-
|
|
74
|
-
Trong mọi trường hợp, tool chỉ bật khi `NODE_ENV=development` (hoặc `SQL_INSPECTOR=1`) — xem [Cấu hình](#cấu-hình-biến-môi-trường).
|
|
75
|
-
|
|
76
|
-
### Nuxt 3 / 4
|
|
77
|
-
|
|
78
|
-
```ts
|
|
79
|
-
// nuxt.config.ts
|
|
80
|
-
export default defineNuxtConfig({
|
|
81
|
-
modules: ["sql-dev-inspector/nuxt"]
|
|
82
|
-
})
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
Xong. Module chỉ đăng ký trong `nuxt dev` (không có gì trong `build` / `generate`): plugin Nitro phía server, và nút nổi phía client. Mở `http://localhost:3000/__sql-inspector/`, hoặc bấm nút **SQL** ở góc phải dưới.
|
|
86
|
-
|
|
87
|
-
Nếu app dùng `app.baseURL` (ví dụ `/alps`), đường dẫn là `/alps/__sql-inspector/`.
|
|
88
|
-
|
|
89
|
-
### Nitro thuần (không Nuxt)
|
|
90
|
-
|
|
91
|
-
```ts
|
|
92
|
-
// nitro.config.ts
|
|
93
|
-
export default defineNitroConfig({
|
|
94
|
-
plugins: ["sql-dev-inspector/nitro"]
|
|
95
|
-
})
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
### Express / Connect (và framework nhận middleware kiểu Connect)
|
|
99
|
-
|
|
100
|
-
```ts
|
|
101
|
-
import express from "express"
|
|
102
|
-
import { createSqlInspector } from "sql-dev-inspector"
|
|
103
|
-
|
|
104
|
-
const app = express()
|
|
105
|
-
const sqlInspector = createSqlInspector()
|
|
106
|
-
|
|
107
|
-
app.use(sqlInspector.middleware) // đặt TRƯỚC mọi route / middleware có chạy SQL
|
|
108
|
-
|
|
109
|
-
app.get("/orders/:id", async (req, res) => {
|
|
110
|
-
const [rows] = await pool.query("select * from orders where id = ?", [req.params.id])
|
|
111
|
-
res.json(rows)
|
|
112
|
-
})
|
|
113
|
-
|
|
114
|
-
app.listen(3000)
|
|
115
|
-
// mở http://localhost:3000/__sql-inspector/
|
|
116
|
-
```
|
|
117
|
-
|
|
118
|
-
### Node `http` thuần (hoặc framework khác)
|
|
119
|
-
|
|
120
|
-
```ts
|
|
121
|
-
import http from "node:http"
|
|
122
|
-
import { createSqlInspector } from "sql-dev-inspector"
|
|
123
|
-
|
|
124
|
-
const sqlInspector = createSqlInspector()
|
|
125
|
-
|
|
126
|
-
http.createServer((req, res) => {
|
|
127
|
-
if (sqlInspector.handle(req, res)) return // trang /__sql-inspector do tool phục vụ
|
|
128
|
-
sqlInspector.track(req, res, () => myApp(req, res)) // mọi await bên trong thuộc về request này
|
|
129
|
-
}).listen(3000)
|
|
130
|
-
```
|
|
131
|
-
|
|
132
|
-
### Job / cron / script (không phải HTTP request)
|
|
133
|
-
|
|
134
|
-
```ts
|
|
135
|
-
await sqlInspector.task("nightly-sync", async () => {
|
|
136
|
-
await syncCustomers()
|
|
137
|
-
})
|
|
138
|
-
// hiện trong danh sách với method TASK, tên "nightly-sync"
|
|
139
|
-
```
|
|
140
|
-
|
|
141
|
-
### Nút nổi cho ứng dụng không phải Nuxt
|
|
142
|
-
|
|
143
|
-
Ở phía trình duyệt (cùng origin với server), gọi một lần trong entry của frontend:
|
|
144
|
-
|
|
145
|
-
```ts
|
|
146
|
-
if (import.meta.env.DEV) {
|
|
147
|
-
const { mountSqlInspectorWidget } = await import("sql-dev-inspector/client")
|
|
148
|
-
mountSqlInspectorWidget({ baseURL: "/" }) // baseURL = tiền tố đường dẫn của server
|
|
149
|
-
}
|
|
150
|
-
```
|
|
151
|
-
|
|
152
|
-
Nếu frontend chạy ở origin khác server (ví dụ Vite :5173, API :3000) thì dùng trang `http://localhost:3000/__sql-inspector/` trực tiếp, hoặc proxy `/__sql-inspector` qua dev server của frontend.
|
|
153
|
-
|
|
154
|
-
## Cách xem kết quả
|
|
155
|
-
|
|
156
|
-
### 1. Terminal
|
|
157
|
-
|
|
158
|
-
Mỗi request có chạy SQL in một cây ngay khi response kết thúc (không in request không chạy SQL). Tắt bằng `SQL_INSPECTOR_LOG=0`.
|
|
159
|
-
|
|
160
|
-
### 2. Trang web `/__sql-inspector/`
|
|
161
|
-
|
|
162
|
-
Danh sách request cập nhật live (SSE), có ô tìm kiếm và bộ lọc *Tất cả / Có vấn đề / Lỗi*. Bấm vào request để xem KPI (tổng thời gian, số query, thời gian SQL và tỉ lệ, số transaction, độ sâu subquery), các cảnh báo, và dòng thời gian các câu SQL kèm thanh waterfall. Bấm vào từng câu để xem SQL đã tô màu + format, SQL gốc, parameters, nút copy; bấm vào một cảnh báo để highlight các câu liên quan; đóng/mở từng transaction. "Theo dõi mới nhất" tự nhảy sang request mới. Bàn phím: `/` tìm kiếm, `↑` `↓` (hoặc `j` `k`) request trước/sau, `e` mở/đóng tất cả. Ngôn ngữ và giao diện (hệ thống / sáng / tối) nằm ở thanh trên.
|
|
163
|
-
|
|
164
|
-
### 3. Nút nổi trong app
|
|
165
|
-
|
|
166
|
-
Nút **SQL** nổi ở góc phải dưới. Số trên nút = số query của request gần nhất; vàng khi có cảnh báo, đỏ khi có lỗi.
|
|
167
|
-
|
|
168
|
-
| Thao tác | Cách làm |
|
|
169
|
-
|---|---|
|
|
170
|
-
| Mở / đóng panel | Bấm nút, hoặc `Alt+Shift+S`; `Esc` đóng khi đang focus trong panel |
|
|
171
|
-
| Ẩn / hiện nút | `Alt+Shift+D` (phím mở panel vẫn dùng được khi nút đã ẩn) |
|
|
172
|
-
| Đổi chỗ nút | Kéo nút |
|
|
173
|
-
| Đổi kích thước panel | Kéo mép panel |
|
|
174
|
-
| Dock đáy / dock phải | Hai biểu tượng dock ở đầu panel |
|
|
175
|
-
| Tự mở khi có cảnh báo / lỗi | Menu "⚙ Tuỳ chỉnh" (mặc định tắt) |
|
|
176
|
-
| Mở tab riêng · xoá lịch sử | Biểu tượng ↗ ở đầu panel · "Xoá lịch sử" trong menu tuỳ chỉnh |
|
|
177
|
-
| Tắt hẳn | Menu "⚙ Tuỳ chỉnh" → "Tắt SQL Inspector" (`Alt+Shift+S` bật lại) |
|
|
178
|
-
|
|
179
|
-
Cài đặt lưu trong `localStorage` (`sqlDevInspector.widget`). Panel chỉ tải khi mở lần đầu. Nút dựng bằng DOM thuần trong Shadow DOM: không phụ thuộc Vue/React và không bị CSS của app ảnh hưởng.
|
|
180
|
-
|
|
181
|
-
## Cảnh báo tự động
|
|
182
|
-
|
|
183
|
-
| Loại | Điều kiện | Mức |
|
|
184
|
-
|---|---|---|
|
|
185
|
-
| `n-plus-one` | ≥ 3 câu SELECT cùng "hình dạng" (khác giá trị) trong một request | warn |
|
|
186
|
-
| `duplicate` | cùng một câu SQL y hệt chạy ≥ 2 lần | warn |
|
|
187
|
-
| `slow` | ≥ 100ms (`SQL_INSPECTOR_SLOW_MS`) | warn |
|
|
188
|
-
| `error` | câu bị MySQL từ chối | error |
|
|
189
|
-
| `many-queries` | ≥ 30 câu trong một request | warn |
|
|
190
|
-
| `select-star` | `SELECT *` | info |
|
|
191
|
-
| `deep-subquery` | subquery lồng ≥ 3 tầng | info |
|
|
192
|
-
| `select-in-transaction`, `write-outside-transaction` | **tuỳ chọn** `SQL_INSPECTOR_TX_CONVENTION=1`: quy ước "SELECT ngoài transaction, transaction chỉ cho câu ghi" | info |
|
|
193
|
-
|
|
194
|
-
N+1 so sánh "fingerprint": SQL đã che giá trị literal và gộp `IN (…)` / `VALUES (…)`.
|
|
195
|
-
|
|
196
|
-
## Cấu hình (biến môi trường)
|
|
197
|
-
|
|
198
|
-
| Biến | Mặc định | Ý nghĩa |
|
|
199
|
-
|---|---|---|
|
|
200
|
-
| `NODE_ENV` | — | `production` ⇒ **luôn tắt** (kể cả `SQL_INSPECTOR=1`). `development` ⇒ bật |
|
|
201
|
-
| `SQL_INSPECTOR` | — | `1` bật cả khi `NODE_ENV` không phải development (ví dụ `test`); `0` tắt hẳn |
|
|
202
|
-
| `SQL_INSPECTOR_LANG` | `en` | Ngôn ngữ của terminal (`en`, `vi`, `ja`) và ngôn ngữ khởi đầu của trang web. Chỉ biến này có tác dụng — `LANG` của máy cố ý bị bỏ qua |
|
|
203
|
-
| `SQL_INSPECTOR_LOG` | bật | `0`: không in cây ra terminal |
|
|
204
|
-
| `SQL_INSPECTOR_SLOW_MS` | `100` | Ngưỡng cảnh báo chậm |
|
|
205
|
-
| `SQL_INSPECTOR_MAX_REQUESTS` | `200` | Số request giữ trong bộ nhớ |
|
|
206
|
-
| `SQL_INSPECTOR_MAX_QUERIES` | `1000` | Số câu tối đa giữ cho mỗi request |
|
|
207
|
-
| `SQL_INSPECTOR_TX_CONVENTION` | tắt | `1`: bật 2 cảnh báo quy ước transaction |
|
|
208
|
-
| `NO_COLOR` | — | Tắt màu ở terminal |
|
|
209
|
-
|
|
210
|
-
## API
|
|
211
|
-
|
|
212
|
-
Entry chính `sql-dev-inspector`:
|
|
213
|
-
|
|
214
|
-
```ts
|
|
215
|
-
createSqlInspector(): SqlInspector
|
|
216
|
-
interface SqlInspector {
|
|
217
|
-
enabled: boolean // false ở production / khi tắt: mọi thứ dưới đây là no-op
|
|
218
|
-
middleware(req, res, next): void // Connect/Express
|
|
219
|
-
handle(req, res): boolean // true nếu là URL của tool (đã phục vụ)
|
|
220
|
-
track<T>(req, res, fn: () => T): T // chạy fn như một request được theo dõi
|
|
221
|
-
task<T>(name: string, fn: () => T | Promise<T>): Promise<T> // đơn vị công việc không phải HTTP
|
|
222
|
-
}
|
|
223
|
-
```
|
|
224
|
-
|
|
225
|
-
Mức thấp (cho tích hợp riêng): `startInspector()`, `getInspector()`, `isInspectorEnabled()`, `installTracer(store)`, `runInRequest(trace, fn)`, `TraceStore`, `buildReport(trace, options)`, `buildTree(queries)`, `analyzeSql(sql)`, `fingerprintOf(sql)`, `formatSql(sql)` và toàn bộ kiểu (`QueryEvent`, `RequestTrace`, `RequestReport`, `Insight`…).
|
|
226
|
-
|
|
227
|
-
Các entry khác:
|
|
228
|
-
|
|
229
|
-
| Import | Dùng cho |
|
|
230
|
-
|---|---|
|
|
231
|
-
| `sql-dev-inspector/nuxt` | Nuxt module (`modules: [...]`) |
|
|
232
|
-
| `sql-dev-inspector/nitro` | Nitro plugin (`plugins: [...]`) |
|
|
233
|
-
| `sql-dev-inspector/client` | `mountSqlInspectorWidget({ baseURL })` — nút nổi cho frontend bất kỳ |
|
|
234
|
-
|
|
235
|
-
Các route của tool (đều dưới `/__sql-inspector/`): `GET /` trang web · `GET /api/requests` · `GET /api/requests/:id` · `GET /api/stream` (SSE) · `POST /api/clear`.
|
|
236
|
-
|
|
237
|
-
## Cách hoạt động
|
|
238
|
-
|
|
239
|
-
Mọi câu SQL — dù đến từ `pool.query`, transaction, hay ORM — đều đi qua `Connection.prototype.query/execute` của mysql2. Tool patch đúng điểm đó (một lần, gỡ được) để ghi lại SQL, parameters, thời gian, số dòng, lỗi và **connection nào đã chạy câu lệnh**.
|
|
240
|
-
|
|
241
|
-
Vì sao không dùng cách khác:
|
|
242
|
-
|
|
243
|
-
| Phương án | Hạn chế |
|
|
244
|
-
|---|---|
|
|
245
|
-
| `logger` của ORM (ví dụ Drizzle) | Chỉ có SQL + params; không có thời gian, kết quả, connection ⇒ không dựng được cây transaction/savepoint, không biết request nào |
|
|
246
|
-
| `diagnostics_channel` của mysql2 ≥ 3.20 | Có thời gian nhưng **không cho biết connection** ⇒ hai transaction song song trong một request bị trộn |
|
|
247
|
-
| `general_log` của MySQL | Không biết request nào, không có thời gian/cây lồng, cần quyền trên DB |
|
|
248
|
-
|
|
249
|
-
Gắn query vào request:
|
|
250
|
-
|
|
251
|
-
1. Adapter bọc request handler bằng `AsyncLocalStorage`, nên mọi `await` bên dưới đều thuộc request đó.
|
|
252
|
-
2. `pool.query()` đưa câu lệnh cho connection qua callback; khi mọi connection bận, callback chạy từ context của *request khác*. Tool bọc callback của `Pool.getConnection` bằng `AsyncLocalStorage.bind` để không gán nhầm.
|
|
253
|
-
3. Cây transaction gom theo connection; "subquery lồng" đo bằng độ sâu `(SELECT …)` trên SQL đã che literal (không đếm ngoặc thường).
|
|
254
|
-
|
|
255
|
-
## Ngôn ngữ (i18n)
|
|
256
|
-
|
|
257
|
-
Có sẵn English, Tiếng Việt (`vi`), 日本語 (`ja`).
|
|
258
|
-
|
|
259
|
-
- **Trang web**: ưu tiên lựa chọn đã lưu → `SQL_INSPECTOR_LANG` (nếu đặt) → ngôn ngữ trình duyệt → English. Đổi bất cứ lúc nào ở thanh trên; `?lang=ja` trên URL ghi đè cho lần xem đó.
|
|
260
|
-
- **Nút nổi**: theo ngôn ngữ trình duyệt, hoặc chọn trong menu tuỳ chỉnh (panel tải lại bằng ngôn ngữ đó).
|
|
261
|
-
- **Terminal và trường `message` của API**: `SQL_INSPECTOR_LANG`, mặc định English.
|
|
262
|
-
|
|
263
|
-
Cảnh báo (insight) được trả về dạng dữ liệu (`type` + `params`) cùng với `message` đã dịch sẵn, nên client nào cũng tự diễn đạt lại được.
|
|
264
|
-
|
|
265
|
-
**Thêm ngôn ngữ mới**: sao chép khối `en` trong `src/i18n/messages.ts`, dịch các giá trị (giữ nguyên mọi `{placeholder}`; thêm biến thể `.one` khi số ít khác số nhiều, ví dụ `"term.queries.one"`), thêm mã vào kiểu `Locale` và `LOCALES` trong `src/i18n/index.ts`. `npm test` sẽ fail nếu thiếu key hoặc placeholder.
|
|
266
|
-
|
|
267
|
-
## Style & cô lập
|
|
268
|
-
|
|
269
|
-
Tool không bao giờ được làm giao diện của ứng dụng xấu đi, nên:
|
|
270
|
-
|
|
271
|
-
- **Nút nổi và panel** nằm trong **shadow root**, reset bằng `all: initial`, host là custom element (không phải `<div>`), các reset có độ ưu tiên bằng 0 (`:where`). CSS toàn cục của app (`button { … }`, `* { … }`, `select`, `body > *`) không đụng được vào chúng, và chúng không thêm CSS nào vào trang. Chúng là `position: fixed`, không làm xô lệch layout, không cướp focus.
|
|
272
|
-
- **Trang inspector** là một document riêng (nằm trong `<iframe>` khi dock) nên cũng không chạm được vào trang của bạn. Mọi control gốc (nút, switch, thanh cuộn) đều được vẽ lại, và bộ chọn ngôn ngữ là listbox tự vẽ — popup của `<select>` gốc do hệ điều hành vẽ, CSS không đụng được nên không dùng `<select>` ở bất kỳ đâu (có test kiểm tra), khai báo `color-scheme` để dark mode không rơi về giao diện mặc định của trình duyệt.
|
|
273
|
-
- **Không gọi ra ngoài**: không web font, không CDN, không analytics — chỉ dùng font hệ thống (có cả tiếng Nhật, tiếng Việt).
|
|
274
|
-
- Tôn trọng `prefers-color-scheme`, `prefers-reduced-motion`, focus bàn phím (`:focus-visible`).
|
|
275
|
-
- Nếu app đặt Content-Security-Policy chặt, nút nổi cần `style-src 'unsafe-inline'` (nó chèn một `<style>` vào shadow root) và `frame-src 'self'`. Tool chỉ dùng khi dev; hãy nới chính sách chỉ cho môi trường dev.
|
|
276
|
-
|
|
277
|
-
## An toàn & quyền riêng tư
|
|
278
|
-
|
|
279
|
-
- `NODE_ENV=production` là **hard stop**: không patch gì, middleware chỉ gọi `next()`.
|
|
280
|
-
- Nuxt module chỉ đăng ký trong `nuxt dev`; `build` / `generate` không chứa gì của tool.
|
|
281
|
-
- Dữ liệu chỉ ở **bộ nhớ** của tiến trình dev, không ghi file, không gửi đi đâu, không gọi mạng.
|
|
282
|
-
- ⚠️ **SQL hiển thị gồm cả giá trị thật** (kể cả dữ liệu cá nhân của DB bạn đang trỏ tới). Đừng chia sẻ màn hình / ảnh chụp khi trỏ vào DB staging hoặc production-like.
|
|
283
|
-
- Trang `/__sql-inspector/` không có xác thực: chỉ để chạy ở `localhost`. Đừng mở cổng dev ra mạng chung khi đang bật tool (ví dụ `--host 0.0.0.0`).
|
|
284
|
-
- Trong Nuxt/Nitro, trang được phục vụ trước mọi middleware (không cần đăng nhập, và query xác thực của app không làm nhiễu kết quả).
|
|
285
|
-
|
|
286
|
-
## Giới hạn đã biết
|
|
287
|
-
|
|
288
|
-
- **Chỉ MySQL qua `mysql2`.** PostgreSQL, SQLite, hoặc driver MySQL khác (ví dụ `mariadb`) không được hỗ trợ. ORM không dùng mysql2 bên dưới (ví dụ engine riêng của Prisma) không đi qua điểm patch.
|
|
289
|
-
- **Đã kiểm chứng**: mysql2 thuần (pool, connection, transaction thủ công) và Drizzle ORM. Knex / Sequelize / TypeORM dùng mysql2 nên *về nguyên lý* chạy được, nhưng chưa có test riêng — nếu gặp vấn đề hãy mở issue.
|
|
290
|
-
- **Không biết dòng code nào gọi query**: ORM như Drizzle trả builder dạng thenable nên khi query thật sự chạy, call stack không còn frame của code gọi. (Đã thử, nên không có tính năng "caller".)
|
|
291
|
-
- Một builder tạo trong scope request nhưng `await` ở ngoài scope (ví dụ trả về rồi await sau khi response đóng) sẽ không gắn về request.
|
|
292
|
-
- Câu lệnh chạy ngoài request/task (startup, timer) được gom vào mục `(ngoài request …)`.
|
|
293
|
-
- Request không chạy SQL (asset, HMR) không được lưu.
|
|
294
|
-
- Adapter Express/Connect đã được test với `req`/`res` giả đúng giao diện Connect (chưa có test chạy trên `express` thật); nút nổi ngoài Nuxt (`mountSqlInspectorWidget`) mới được test trong happy-dom.
|
|
295
|
-
- Đã test với `mysql2` 3.20 và Node 24; Node 20+ theo `engines`.
|
|
296
|
-
|
|
297
|
-
## Xử lý sự cố
|
|
298
|
-
|
|
299
|
-
| Triệu chứng | Nguyên nhân thường gặp |
|
|
300
|
-
|---|---|
|
|
301
|
-
| Không thấy gì, không có dòng `[sql-inspector] bật` | `NODE_ENV` không phải `development`: chạy với `NODE_ENV=development` hoặc `SQL_INSPECTOR=1` (và không phải `production`) |
|
|
302
|
-
| Có terminal log nhưng trang `/__sql-inspector/` 404 | Express: `sqlInspector.middleware` phải đặt trước router; Nitro/Nuxt: kiểm tra `app.baseURL` |
|
|
303
|
-
| Query nằm hết trong `(ngoài request …)` | Middleware đặt sau route đã chạy SQL; hoặc SQL chạy trong scope không `await` từ handler (timer, queue) — bọc bằng `sqlInspector.task()` |
|
|
304
|
-
| Nút nổi không hiện | Không phải Nuxt: chưa gọi `mountSqlInspectorWidget`. Nuxt: chỉ có trong `nuxt dev`. Thử `Alt+Shift+D` (có thể đã ẩn) hoặc xoá key `sqlDevInspector.widget` trong localStorage |
|
|
305
|
-
| Query của ORM X không hiện | ORM đó không dùng `mysql2`. Kiểm tra driver bên dưới |
|
|
306
|
-
| Hai bản `mysql2` trong `node_modules` | Tool patch bản mà nó `import` được. Đảm bảo app và tool dùng chung một bản (peer dependency được hoist) |
|
|
307
|
-
|
|
308
|
-
## Phát triển & test
|
|
309
|
-
|
|
310
|
-
```bash
|
|
311
|
-
npm install
|
|
312
|
-
npm run typecheck # tsc --noEmit (src + test)
|
|
313
|
-
npm test # vitest: 131 test
|
|
314
|
-
npm run build # tsc -> dist/
|
|
315
|
-
```
|
|
316
|
-
|
|
317
|
-
Test tích hợp chạy **mysql2 thật + Drizzle thật** với một MySQL giả nói đúng wire protocol (`test/mock-mysql-server.ts`, nối bằng stream trong bộ nhớ nên không cần mở cổng hay cài MySQL): transaction, savepoint lồng, rollback, hai transaction song song, 8 request đồng thời trên pool 3 connection, lỗi SQL, N+1, SSE, gỡ patch, adapter Express/`http`, nút nổi và trang web (happy-dom).
|
|
318
|
-
|
|
319
|
-
Cấu trúc:
|
|
320
|
-
|
|
321
|
-
```
|
|
322
|
-
src/
|
|
323
|
-
├─ index.ts # API công khai
|
|
324
|
-
├─ node.ts # createSqlInspector: Express / http / task
|
|
325
|
-
├─ nitro-plugin.ts # Nitro / Nuxt (server)
|
|
326
|
-
├─ nuxt.ts # Nuxt module (chỉ đăng ký trong dev)
|
|
327
|
-
├─ setup.ts # bật tracer + in terminal, một lần mỗi process
|
|
328
|
-
├─ tracer.ts # patch mysql2 + AsyncLocalStorage
|
|
329
|
-
├─ store.ts # ring buffer request/query + pub/sub
|
|
330
|
-
├─ sql-analyzer.ts # loại câu lệnh, bảng, subquery, fingerprint, format
|
|
331
|
-
├─ report.ts # cây transaction/savepoint + cảnh báo
|
|
332
|
-
├─ terminal.ts # in cây ra terminal
|
|
333
|
-
├─ inspector-server.ts # route /__sql-inspector (UI, JSON, SSE)
|
|
334
|
-
├─ ui.ts # trang web một file
|
|
335
|
-
├─ runtime.ts # cờ môi trường + singleton
|
|
336
|
-
└─ client/ # nút nổi (widget.ts) + plugin client của Nuxt
|
|
337
|
-
```
|
|
338
|
-
|
|
339
|
-
## Giấy phép
|
|
340
|
-
|
|
341
|
-
MIT — xem [LICENSE](LICENSE).
|
|
@@ -1,267 +0,0 @@
|
|
|
1
|
-
# Đưa lên Git public & hướng dẫn cài đặt cho mọi người
|
|
2
|
-
|
|
3
|
-
Tài liệu gồm 3 phần:
|
|
4
|
-
|
|
5
|
-
- **Phần A** — chuẩn bị gói trước khi công khai, và **cái gì đẩy lên git / cái gì không** (A4)
|
|
6
|
-
- **Phần B** — đưa mã nguồn lên Git public (GitHub) và (tuỳ chọn) publish lên npm
|
|
7
|
-
- **Phần C** — hướng dẫn cho người khác cài vào dự án của họ
|
|
8
|
-
|
|
9
|
-
> ⚠️ **Công khai là hành động khó thu hồi.** Mã đã public có thể bị clone, cache, index (kể cả sau khi xoá).
|
|
10
|
-
> Các bước dưới đây **bạn tự thực hiện**; mỗi bước đều ghi rõ tác động. Đừng bỏ qua checklist ở A3.
|
|
11
|
-
|
|
12
|
-
---
|
|
13
|
-
|
|
14
|
-
## Phần A. Chuẩn bị
|
|
15
|
-
|
|
16
|
-
### A1. Thay các chỗ giữ chỗ (placeholder)
|
|
17
|
-
|
|
18
|
-
Tìm và thay trong gói:
|
|
19
|
-
|
|
20
|
-
| Nơi | Cần thay | Ghi chú |
|
|
21
|
-
|---|---|---|
|
|
22
|
-
| `package.json` → `name` | `sql-dev-inspector` | Tên mặc định. Có thể đổi (ví dụ `@your-scope/sql-dev-inspector`); nếu đổi, sửa cả README và mọi `import "sql-dev-inspector/..."` |
|
|
23
|
-
| `package.json` → `author` | `<YOUR NAME OR ORGANIZATION>` | Tên cá nhân hoặc tổ chức hiển thị công khai |
|
|
24
|
-
| `package.json` → `repository.url`, `homepage`, `bugs.url` | `<YOUR-ORG>` | URL repo GitHub sẽ tạo ở B1 |
|
|
25
|
-
| `LICENSE` | `<YOUR NAME OR ORGANIZATION>` | Chủ bản quyền |
|
|
26
|
-
|
|
27
|
-
Lệnh tìm chỗ còn sót:
|
|
28
|
-
|
|
29
|
-
```bash
|
|
30
|
-
grep -rn "YOUR" --exclude-dir=node_modules --exclude-dir=dist .
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
### A2. Chọn giấy phép
|
|
34
|
-
|
|
35
|
-
Gói mặc định dùng **MIT** (cho phép dùng/sửa/phân phối tự do, kể cả thương mại). Nếu tổ chức của bạn yêu cầu giấy phép khác hoặc phải được pháp chế/quản lý duyệt trước khi mở mã nguồn, **hỏi trước khi công khai**, rồi sửa `LICENSE` và `"license"` trong `package.json` cho khớp.
|
|
36
|
-
|
|
37
|
-
### A3. Checklist trước khi public
|
|
38
|
-
|
|
39
|
-
- [ ] Không có bí mật trong mã: không `.env`, token, key, mật khẩu, URL nội bộ. (Gói này không chứa; vẫn nên chạy lại lệnh dưới.)
|
|
40
|
-
- [ ] Không có tên dự án / khách hàng / hạ tầng nội bộ trong mã, test, README, lịch sử git.
|
|
41
|
-
- [ ] Đã đồng ý với giấy phép (A2) và tên tác giả (A1).
|
|
42
|
-
- [ ] `npm install && npm run typecheck && npm test && npm run build` đều thành công.
|
|
43
|
-
|
|
44
|
-
```bash
|
|
45
|
-
grep -rniE "password|secret|token|api[_-]?key|BEGIN (RSA|PRIVATE)" --exclude-dir=node_modules --exclude-dir=dist . | head
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
(Kết quả có thể có vài chữ "token" vô hại trong mã phân tích SQL; hãy đọc từng dòng.)
|
|
49
|
-
|
|
50
|
-
### A4. Cái gì đẩy lên Git, cái gì không
|
|
51
|
-
|
|
52
|
-
Có **ba nơi** khác nhau mà mã đi tới. Mỗi nơi nhận một phần khác nhau:
|
|
53
|
-
|
|
54
|
-
| Nơi | Là gì | Ai thấy |
|
|
55
|
-
|---|---|---|
|
|
56
|
-
| **1. Repo public `sql-dev-inspector`** | Mã nguồn của tool (thư mục `sql-dev-inspector/` trong file zip) | Mọi người |
|
|
57
|
-
| **2. npm registry** (tuỳ chọn, B4) | Bản đã build để cài | Mọi người |
|
|
58
|
-
| **3. Repo nội bộ của dự án (ví dụ Alps)** | Dự án dùng tool | Chỉ nội bộ — **không bao giờ public** |
|
|
59
|
-
|
|
60
|
-
#### 1. Repo public `sql-dev-inspector`
|
|
61
|
-
|
|
62
|
-
| ✅ Đẩy lên (được `git add .` lấy) | Vì sao |
|
|
63
|
-
|---|---|
|
|
64
|
-
| `src/` | Mã nguồn |
|
|
65
|
-
| `test/` | Test, kèm MySQL giả — người đóng góp cần để chạy test |
|
|
66
|
-
| `docs/` | Tài liệu (file này) |
|
|
67
|
-
| `README.md` (English), `README.VI.md` (tiếng Việt), `CHANGELOG.md`, `LICENSE` | Tài liệu và giấy phép |
|
|
68
|
-
| `package.json` | Metadata, scripts, dependencies |
|
|
69
|
-
| `package-lock.json` | Khoá phiên bản — sinh ra sau lần `npm install` đầu tiên, nên commit |
|
|
70
|
-
| `tsconfig.json`, `tsconfig.build.json`, `vitest.config.ts` | Cấu hình build / test |
|
|
71
|
-
| `.gitignore` | Để người khác không vô tình commit rác |
|
|
72
|
-
| `.github/workflows/ci.yml` | CI chạy test mỗi lần push / PR |
|
|
73
|
-
|
|
74
|
-
| ❌ KHÔNG đẩy lên | Vì sao | Đã được chặn bởi |
|
|
75
|
-
|---|---|---|
|
|
76
|
-
| `node_modules/` | Sinh lại bằng `npm install` | `.gitignore` |
|
|
77
|
-
| `dist/` | Sản phẩm build; chỉ đi lên **npm**, không đi lên git | `.gitignore` |
|
|
78
|
-
| `*.tgz`, file `.zip` | Gói phân phối. Muốn chia sẻ thì đính kèm vào *GitHub Release*, đừng commit | `.gitignore` (`*.tgz`) — zip không nằm trong repo |
|
|
79
|
-
| `.env*`, token, key | Bí mật (gói này không có, giữ nguyên như vậy) | tự kiểm tra ở A3 |
|
|
80
|
-
| `.claude/`, `.vite/`, `coverage/`, `.DS_Store`, `*.log` | File của công cụ / máy cá nhân | `.gitignore` |
|
|
81
|
-
|
|
82
|
-
Kiểm tra trước khi commit:
|
|
83
|
-
|
|
84
|
-
```bash
|
|
85
|
-
git status # chỉ thấy các file ✅ ở bảng trên
|
|
86
|
-
git ls-files # danh sách file sẽ nằm trong repo
|
|
87
|
-
git check-ignore -v dist node_modules # xác nhận 2 thư mục này bị bỏ qua
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
#### 2. Cái gì lên npm (khi `npm publish`)
|
|
91
|
-
|
|
92
|
-
Do `files` trong `package.json` quyết định, **không phải** `.gitignore`: chỉ `dist/`, `docs/`, `README.md`, `README.VI.md`, `LICENSE`, `CHANGELOG.md` (+ `package.json`). `src/`, `test/`, cấu hình CI **không** lên npm. Xem trước bằng:
|
|
93
|
-
|
|
94
|
-
```bash
|
|
95
|
-
npm publish --dry-run # hoặc: npm pack --dry-run
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
#### 3. Repo nội bộ của dự án dùng tool (ví dụ Alps)
|
|
99
|
-
|
|
100
|
-
| ✅ Commit vào repo dự án | ❌ Không commit |
|
|
101
|
-
|---|---|
|
|
102
|
-
| Dòng cấu hình bật tool (`modules: ["sql-dev-inspector/nuxt"]` hoặc middleware) | File `.zip` / `.tgz` của tool (`tools/release/`) |
|
|
103
|
-
| Dòng `sql-dev-inspector` trong `devDependencies` + lockfile | `node_modules/`, `dist/`, `.nuxt/` |
|
|
104
|
-
| | Mọi thứ trong thư mục scratch / thử nghiệm |
|
|
105
|
-
|
|
106
|
-
Hai giai đoạn:
|
|
107
|
-
|
|
108
|
-
- **Trước khi tool có repo public / npm** (hiện tại): mã nguồn tool nằm tạm trong repo dự án ở `tools/sql-inspector/`, `nuxt.config.ts` trỏ tới `./tools/sql-inspector/src/nuxt`. Commit cả thư mục `tools/sql-inspector/` (trừ `dist/`, `node_modules/`) và thêm `tools/release/` vào `.gitignore` của dự án.
|
|
109
|
-
- **Sau khi tool đã publish** (khuyến nghị): xoá thư mục `tools/sql-inspector/` khỏi repo dự án, `npm i -D sql-dev-inspector`, đổi `nuxt.config.ts` sang `"sql-dev-inspector/nuxt"`. Từ đó repo public là **nguồn duy nhất**; không giữ hai bản mã nguồn song song.
|
|
110
|
-
|
|
111
|
-
> ⚠️ Không bao giờ đổi repo dự án nội bộ sang Public chỉ để chia sẻ tool. Tool có repo riêng (Phần B) chính là để làm việc này.
|
|
112
|
-
|
|
113
|
-
---
|
|
114
|
-
|
|
115
|
-
## Phần B. Lên Git public
|
|
116
|
-
|
|
117
|
-
### B1. Tạo repo trống trên GitHub
|
|
118
|
-
|
|
119
|
-
1. Vào GitHub → **New repository**.
|
|
120
|
-
2. Đặt tên (khuyến nghị trùng tên package), **không** tick "Add a README / .gitignore / license" (gói đã có sẵn).
|
|
121
|
-
3. Chọn **Public** → *tác động: bất kỳ ai trên Internet đều xem và clone được mã này.* (Nếu chưa chắc, chọn **Private** trước; đổi sang Public sau ở *Settings → General → Danger Zone → Change visibility*.)
|
|
122
|
-
4. Bấm **Create repository**, copy URL (ví dụ `https://github.com/<your-org>/sql-dev-inspector.git`).
|
|
123
|
-
|
|
124
|
-
### B2. Đẩy mã lên
|
|
125
|
-
|
|
126
|
-
Giải nén file zip (hoặc dùng thư mục `sql-dev-inspector/` trong gói), rồi:
|
|
127
|
-
|
|
128
|
-
```bash
|
|
129
|
-
cd sql-dev-inspector
|
|
130
|
-
git init -b main
|
|
131
|
-
git add .
|
|
132
|
-
git status # ← kiểm tra danh sách file: không có node_modules, dist, .env
|
|
133
|
-
git commit -m "feat: initial release 1.0.0"
|
|
134
|
-
git remote add origin https://github.com/<your-org>/sql-dev-inspector.git
|
|
135
|
-
git push -u origin main
|
|
136
|
-
```
|
|
137
|
-
|
|
138
|
-
*Tác động của `git push`: mã nguồn được gửi lên GitHub; nếu repo là Public thì công khai ngay.*
|
|
139
|
-
|
|
140
|
-
> **Đang ở trong monorepo và muốn giữ lịch sử commit riêng của thư mục này?** Dùng `git subtree split` thay vì copy:
|
|
141
|
-
> ```bash
|
|
142
|
-
> git subtree split --prefix=tools/sql-inspector -b sql-inspector-only
|
|
143
|
-
> git push https://github.com/<your-org>/sql-dev-inspector.git sql-inspector-only:main
|
|
144
|
-
> ```
|
|
145
|
-
> Lưu ý: cách này đẩy **toàn bộ lịch sử** của thư mục đó; kiểm tra lịch sử không chứa thông tin nội bộ trước khi push.
|
|
146
|
-
|
|
147
|
-
### B3. Thiết lập repo sau khi đẩy lên
|
|
148
|
-
|
|
149
|
-
1. **CI**: file `.github/workflows/ci.yml` chạy typecheck + build + test trên Node 20/22/24 mỗi lần push / PR. Kiểm tra tab *Actions*.
|
|
150
|
-
2. **Mô tả & topics** (*About* ở trang repo): `mysql`, `mysql2`, `sql`, `devtools`, `drizzle`, `nuxt`, `express`.
|
|
151
|
-
3. **Bảo vệ nhánh `main`** (*Settings → Branches*): yêu cầu PR + CI xanh trước khi merge (khuyến nghị nếu có nhiều người đóng góp).
|
|
152
|
-
4. **Tag phiên bản**:
|
|
153
|
-
```bash
|
|
154
|
-
git tag v1.0.0
|
|
155
|
-
git push origin v1.0.0
|
|
156
|
-
```
|
|
157
|
-
Rồi *Releases → Draft a new release* chọn tag `v1.0.0`, dán nội dung `CHANGELOG.md`.
|
|
158
|
-
|
|
159
|
-
### B4. (Tuỳ chọn) Publish lên npm
|
|
160
|
-
|
|
161
|
-
Chỉ làm khi muốn mọi người `npm install sql-dev-inspector` không cần trỏ vào GitHub.
|
|
162
|
-
|
|
163
|
-
*Tác động: tên package bị chiếm công khai trên npm; mỗi phiên bản đã publish **không thể ghi đè** (chỉ có thể deprecate, và unpublish bị giới hạn).*
|
|
164
|
-
|
|
165
|
-
```bash
|
|
166
|
-
npm view sql-dev-inspector # nếu trả về thông tin => tên đã bị chiếm, hãy đổi tên (A1)
|
|
167
|
-
npm login # đăng nhập tài khoản npm (nên bật 2FA)
|
|
168
|
-
npm publish --dry-run # xem trước danh sách file sẽ lên npm (chỉ dist, docs, README.md, README.VI.md, LICENSE, CHANGELOG)
|
|
169
|
-
npm publish --access public # publish thật (chạy typecheck/build/test qua prepublishOnly)
|
|
170
|
-
```
|
|
171
|
-
|
|
172
|
-
Với package có scope (`@your-scope/...`) bắt buộc `--access public` thì mới public.
|
|
173
|
-
|
|
174
|
-
Phát hành phiên bản mới:
|
|
175
|
-
|
|
176
|
-
```bash
|
|
177
|
-
# sửa CHANGELOG.md, rồi:
|
|
178
|
-
npm version patch # hoặc minor / major (tự tạo commit + tag)
|
|
179
|
-
git push && git push --tags
|
|
180
|
-
npm publish --access public
|
|
181
|
-
```
|
|
182
|
-
|
|
183
|
-
---
|
|
184
|
-
|
|
185
|
-
## Phần C. Hướng dẫn cài đặt cho mọi người
|
|
186
|
-
|
|
187
|
-
> Dán nguyên phần này vào wiki / Slack / README nội bộ nếu cần.
|
|
188
|
-
|
|
189
|
-
### C1. Chọn cách cài
|
|
190
|
-
|
|
191
|
-
| Cách | Khi nào dùng | Lệnh |
|
|
192
|
-
|---|---|---|
|
|
193
|
-
| **npm registry** | Đã publish (B4) | `npm i -D sql-dev-inspector` |
|
|
194
|
-
| **Từ GitHub** | Chưa publish npm, repo đã public | `npm i -D github:<your-org>/sql-dev-inspector` |
|
|
195
|
-
| **Từ GitHub, cố định phiên bản** | Nên dùng thay cho nhánh `main` | `npm i -D github:<your-org>/sql-dev-inspector#v1.0.0` |
|
|
196
|
-
| **File `.tgz`** | Offline / chưa có repo | `npm i -D ./sql-dev-inspector-1.0.0.tgz` |
|
|
197
|
-
| **Link thư mục local** | Đang sửa tool và thử trong dự án khác | `npm i -D ../sql-dev-inspector` (hoặc `pnpm add -D link:../sql-dev-inspector`) |
|
|
198
|
-
|
|
199
|
-
Với pnpm / yarn thay `npm i -D` bằng `pnpm add -D` / `yarn add -D`.
|
|
200
|
-
Cài từ GitHub sẽ tự chạy `prepare` (build `dist/`) nên cần mạng để tải `typescript`.
|
|
201
|
-
|
|
202
|
-
Điều kiện: Node.js ≥ 20, dự án có `mysql2` ≥ 3 (`npm i mysql2` nếu chưa có).
|
|
203
|
-
|
|
204
|
-
### C2. Bật trong dự án
|
|
205
|
-
|
|
206
|
-
**Nuxt** — `nuxt.config.ts`:
|
|
207
|
-
|
|
208
|
-
```ts
|
|
209
|
-
export default defineNuxtConfig({
|
|
210
|
-
modules: ["sql-dev-inspector/nuxt"]
|
|
211
|
-
})
|
|
212
|
-
```
|
|
213
|
-
|
|
214
|
-
**Nitro** — `nitro.config.ts`:
|
|
215
|
-
|
|
216
|
-
```ts
|
|
217
|
-
export default defineNitroConfig({ plugins: ["sql-dev-inspector/nitro"] })
|
|
218
|
-
```
|
|
219
|
-
|
|
220
|
-
**Express / Connect**:
|
|
221
|
-
|
|
222
|
-
```ts
|
|
223
|
-
import { createSqlInspector } from "sql-dev-inspector"
|
|
224
|
-
const sqlInspector = createSqlInspector()
|
|
225
|
-
app.use(sqlInspector.middleware) // trước mọi route có chạy SQL
|
|
226
|
-
```
|
|
227
|
-
|
|
228
|
-
**Node `http` thuần**:
|
|
229
|
-
|
|
230
|
-
```ts
|
|
231
|
-
const sqlInspector = createSqlInspector()
|
|
232
|
-
http.createServer((req, res) => {
|
|
233
|
-
if (sqlInspector.handle(req, res)) return
|
|
234
|
-
sqlInspector.track(req, res, () => app(req, res))
|
|
235
|
-
})
|
|
236
|
-
```
|
|
237
|
-
|
|
238
|
-
**Job / cron**: `await sqlInspector.task("tên-job", async () => { … })`.
|
|
239
|
-
|
|
240
|
-
### C3. Chạy và kiểm tra
|
|
241
|
-
|
|
242
|
-
1. Chạy dev server với `NODE_ENV=development` (`nuxt dev`, `next dev`, `vite`… tự đặt; với script Node thuần: `NODE_ENV=development node server.js`).
|
|
243
|
-
2. Terminal in dòng `[sql-inspector] bật …` (Nuxt/Nitro) — hoặc không in gì cho tới khi có request chạy SQL.
|
|
244
|
-
3. Gọi một API, terminal in cây SQL; mở `http://localhost:<port>/__sql-inspector/`.
|
|
245
|
-
4. Nuxt: nút **SQL** ở góc phải dưới; phím tắt `Alt+Shift+S` (mở/đóng), `Alt+Shift+D` (ẩn/hiện nút).
|
|
246
|
-
|
|
247
|
-
Không thấy gì? Xem mục *Xử lý sự cố* trong [README](../README.VI.md#xử-lý-sự-cố).
|
|
248
|
-
|
|
249
|
-
### C4. Tắt / gỡ
|
|
250
|
-
|
|
251
|
-
- Tắt tạm: chạy với `SQL_INSPECTOR=0`.
|
|
252
|
-
- Tắt từ nút nổi: menu *⚙ Tuỳ chỉnh → Tắt SQL Inspector*.
|
|
253
|
-
- Gỡ hẳn: xoá dòng cấu hình (module / plugin / middleware) rồi `npm rm sql-dev-inspector`.
|
|
254
|
-
|
|
255
|
-
### C5. An toàn
|
|
256
|
-
|
|
257
|
-
- Tool **không chạy ở production** (`NODE_ENV=production` là hard stop), nhưng vẫn nên giữ ở `devDependencies` nếu dự án chỉ dùng cho Nuxt/Nitro dev.
|
|
258
|
-
- SQL hiển thị gồm **giá trị thật** (có thể là dữ liệu cá nhân): đừng chia sẻ màn hình/ảnh chụp khi trỏ vào DB thật; đừng mở cổng dev ra mạng chung khi đang bật tool.
|
|
259
|
-
|
|
260
|
-
### C6. Cập nhật phiên bản
|
|
261
|
-
|
|
262
|
-
```bash
|
|
263
|
-
npm update sql-dev-inspector # từ npm
|
|
264
|
-
npm i -D github:<your-org>/sql-dev-inspector#v1.1.0 # từ GitHub: đổi tag
|
|
265
|
-
```
|
|
266
|
-
|
|
267
|
-
Xem thay đổi ở [CHANGELOG.md](../CHANGELOG.md).
|