dsh-dbhub-live 5.2.0-dev.3 → 6.0.0-rc.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/README.en.md +36 -33
- package/README.md +37 -34
- package/lib/adhoc.mjs +108 -12
- package/lib/capability.mjs +97 -13
- package/lib/client.js +705 -315
- package/lib/config.mjs +490 -99
- package/lib/i18n.mjs +68 -2
- package/lib/index.mjs +386 -260
- package/lib/mcp.mjs +245 -49
- package/lib/meta.mjs +275 -267
- package/lib/options.mjs +11 -33
- package/lib/policy.mjs +92 -92
- package/lib/runtime.mjs +80 -11
- package/lib/state.mjs +112 -117
- package/lib/toml.mjs +10 -0
- package/lib/tools.mjs +118 -24
- package/lib/update.mjs +254 -244
- package/package.json +4 -20
- package/AGENTS.md +0 -116
- package/doc/ARCHITECTURE.md +0 -108
- package/doc/CLIENT.md +0 -124
- package/doc/DESENSITIZE.md +0 -56
- package/doc/DEVELOPMENT.md +0 -139
- package/doc/IMPACT-MATRIX.md +0 -36
- package/doc/RELEASE.md +0 -93
- package/doc/REQUIREMENTS.md +0 -177
- package/doc/images/chat-query.png +0 -0
- package/doc/images/row-editor.png +0 -0
- package/doc/images/settings-page.png +0 -0
- package/scripts/desensitize-check.mjs +0 -331
- package/scripts/desensitize.config.mjs +0 -255
- package/scripts/docs-check.mjs +0 -214
- package/scripts/release-preflight.mjs +0 -180
- package/scripts/render-check.mjs +0 -1366
- package/test/adhoc-toml.test.mjs +0 -365
- package/test/auto-dsn.test.mjs +0 -126
- package/test/bridge.test.mjs +0 -227
- package/test/capability.test.mjs +0 -231
- package/test/client-format.test.mjs +0 -515
- package/test/configure-options.test.mjs +0 -244
- package/test/configure-ssh.test.mjs +0 -232
- package/test/copy-from.test.mjs +0 -155
- package/test/env-options.test.mjs +0 -456
- package/test/i18n.test.mjs +0 -37
- package/test/init.test.mjs +0 -163
- package/test/meta.test.mjs +0 -234
- package/test/options.test.mjs +0 -160
- package/test/policy.test.mjs +0 -132
- package/test/resolve-source.test.mjs +0 -82
- package/test/resolve-workspace.test.mjs +0 -115
- package/test/row-cache.test.mjs +0 -237
- package/test/ssh-probe.test.mjs +0 -834
- package/test/state.test.mjs +0 -85
- package/test/test-op-fastpath.test.mjs +0 -208
- package/test/toml.test.mjs +0 -352
- package/test/update.test.mjs +0 -270
- package/test/util.test.mjs +0 -275
- package/test/zero-knowledge.test.mjs +0 -121
package/lib/capability.mjs
CHANGED
|
@@ -12,12 +12,43 @@
|
|
|
12
12
|
// Detection is deliberately file-based (no extra process spawn): the executable
|
|
13
13
|
// we resolved lives inside a package directory (`…/node_modules/.bin/dbhub.cmd`
|
|
14
14
|
// next to `…/node_modules/@bytebase/dbhub/package.json`) or under mise's
|
|
15
|
-
// `npm-bytebase-dbhub/<version>/` layout,
|
|
15
|
+
// `npm-bytebase-dbhub/<version>/` layout, or it is the classic global layout
|
|
16
|
+
// (`<prefix>/bin/dbhub` + `<prefix>/lib/node_modules/@bytebase/dbhub`), and all
|
|
17
|
+
// of them carry the version. An UNKNOWN version still allows both features
|
|
18
|
+
// (R62); the point of covering the standard layouts is that "unknown" stays the
|
|
19
|
+
// exception instead of being the default answer.
|
|
16
20
|
// Pure module: `node:fs` + `node:path` only, no Cordis service.
|
|
17
21
|
|
|
18
|
-
import { existsSync, readFileSync, statSync } from 'node:fs'
|
|
22
|
+
import { existsSync, readFileSync, statSync, realpathSync } from 'node:fs'
|
|
19
23
|
import { dirname, join, resolve } from 'node:path'
|
|
20
24
|
|
|
25
|
+
// Process-wide detection cache, keyed by `<absolute exe path>\0<mtimeMs>`. The
|
|
26
|
+
// answer for one executable is immutable for the life of the process, while a
|
|
27
|
+
// TOML call used to re-walk up to 18 candidate manifests with readFileSync on
|
|
28
|
+
// EVERY tool call (the guard runs before each read-only / tunnelled spawn). The
|
|
29
|
+
// mtime keeps an in-place upgrade (`npm install` over the old prefix) from
|
|
30
|
+
// serving a stale version, and one statSync is microseconds next to that walk.
|
|
31
|
+
const DETECTION_CACHE = new Map()
|
|
32
|
+
|
|
33
|
+
// Production reads the real fs; tests swap single primitives to COUNT the probes
|
|
34
|
+
// (the same seam config.mjs uses for its storage writers). Nothing here reads a
|
|
35
|
+
// hook unless a test installed one. `realpathSync` resolves a shim that is a
|
|
36
|
+
// SYMLINK (nvm / volta / pnpm, and npm -g's `bin/dbhub` link) to the package
|
|
37
|
+
// directory it really lives in.
|
|
38
|
+
const NODE_FS = { existsSync, readFileSync, statSync, realpathSync }
|
|
39
|
+
let fsHooks = NODE_FS
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Replace a subset of the file primitives used by the version probe.
|
|
43
|
+
* @param hooks - `{ existsSync?, readFileSync?, statSync?, realpathSync? }`, or
|
|
44
|
+
* `null` to restore node:fs. Unlisted primitives keep the real implementation.
|
|
45
|
+
* The detection cache is dropped so a swapped fs can never be served a hit.
|
|
46
|
+
*/
|
|
47
|
+
export function setFsHooks(hooks) {
|
|
48
|
+
fsHooks = hooks ? { ...NODE_FS, ...hooks } : NODE_FS
|
|
49
|
+
DETECTION_CACHE.clear()
|
|
50
|
+
}
|
|
51
|
+
|
|
21
52
|
/** Minimum dbhub version whose TOML dialect this plugin generates. */
|
|
22
53
|
export const DBHUB_MIN_VERSION = '1.4.0'
|
|
23
54
|
/** Versions below this predate the TOML tool model entirely. */
|
|
@@ -62,11 +93,27 @@ export function versionFromMisePath(exe) {
|
|
|
62
93
|
return parseVersion(m[1]) ? m[1] : ''
|
|
63
94
|
}
|
|
64
95
|
|
|
96
|
+
/**
|
|
97
|
+
* The real path of an executable, or the given path when it cannot be resolved.
|
|
98
|
+
*
|
|
99
|
+
* A dbhub reached through a link must be walked UP from its TARGET: npm -g puts
|
|
100
|
+
* `bin/dbhub` as a symlink into `lib/node_modules`, and nvm / volta / pnpm shim
|
|
101
|
+
* the same way, so the link's own directory contains no manifest at all.
|
|
102
|
+
*/
|
|
103
|
+
function realExe(raw) {
|
|
104
|
+
try {
|
|
105
|
+
return fsHooks.realpathSync(raw)
|
|
106
|
+
} catch (e) {
|
|
107
|
+
return raw
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
65
111
|
/**
|
|
66
112
|
* Walk up from the executable (bounded) looking for the owning package.json and
|
|
67
113
|
* read its version. Works for the auto-managed install
|
|
68
|
-
* (`<RUNTIME_DIR>/node_modules/@bytebase/dbhub/package.json`)
|
|
69
|
-
* pnpm / mise layout that keeps the manifest above the shim
|
|
114
|
+
* (`<RUNTIME_DIR>/node_modules/@bytebase/dbhub/package.json`), for any npm /
|
|
115
|
+
* pnpm / mise layout that keeps the manifest above the shim, and for the
|
|
116
|
+
* classic global layout (`<prefix>/bin/dbhub` + `<prefix>/lib/node_modules/…`).
|
|
70
117
|
* @returns a version string, or `''`.
|
|
71
118
|
*/
|
|
72
119
|
export function versionFromPackageJson(exe) {
|
|
@@ -74,25 +121,36 @@ export function versionFromPackageJson(exe) {
|
|
|
74
121
|
if (!raw) return ''
|
|
75
122
|
let dir
|
|
76
123
|
try {
|
|
77
|
-
dir = dirname(resolve(raw))
|
|
124
|
+
dir = dirname(realExe(resolve(raw)))
|
|
78
125
|
} catch (e) {
|
|
79
126
|
return ''
|
|
80
127
|
}
|
|
81
128
|
for (let i = 0; i < 6 && dir; i++) {
|
|
82
|
-
//
|
|
129
|
+
// Every layout matters, and all of them must be probed at EVERY level:
|
|
83
130
|
// · `<pkg>/package.json` — the mise shim package that pins dbhub;
|
|
84
|
-
// · `<dir>/node_modules
|
|
131
|
+
// · `<dir>/node_modules/{@bytebase/dbhub,dbhub}/package.json` — what
|
|
85
132
|
// `npm install @bytebase/dbhub --prefix <dir>` produces, i.e. the
|
|
86
|
-
// DEFAULT auto-managed install
|
|
87
|
-
// · `<dir>/node_modules
|
|
133
|
+
// DEFAULT auto-managed install;
|
|
134
|
+
// · `<dir>/lib/node_modules/…` — the npm GLOBAL / nvm / volta prefix
|
|
135
|
+
// (`<prefix>/bin/dbhub` next to `<prefix>/lib/node_modules/…`). This
|
|
136
|
+
// candidate is what keeps a default `npm i -g` install from resolving
|
|
137
|
+
// to '' : an unknown version is ALLOWED by design (R62), so the
|
|
138
|
+
// `< 1.0.0` refusal was unreachable and a `[[tools]] readonly` TOML was
|
|
139
|
+
// handed to a dbhub that ignores it — looking read-only while every
|
|
140
|
+
// write still went through;
|
|
141
|
+
// · `<dir>/../../lib/node_modules/…` — the same prefix seen from a shim
|
|
142
|
+
// that sits one directory deeper (`<prefix>/bin/<sub>/dbhub`).
|
|
88
143
|
for (const candidate of [
|
|
89
144
|
join(dir, 'package.json'),
|
|
90
145
|
join(dir, 'node_modules', '@bytebase', 'dbhub', 'package.json'),
|
|
91
146
|
join(dir, 'node_modules', 'dbhub', 'package.json'),
|
|
147
|
+
join(dir, 'lib', 'node_modules', '@bytebase', 'dbhub', 'package.json'),
|
|
148
|
+
join(dir, 'lib', 'node_modules', 'dbhub', 'package.json'),
|
|
149
|
+
join(dir, '..', '..', 'lib', 'node_modules', '@bytebase', 'dbhub', 'package.json'),
|
|
92
150
|
]) {
|
|
93
151
|
try {
|
|
94
|
-
if (!existsSync(candidate) || !statSync(candidate).isFile()) continue
|
|
95
|
-
const doc = JSON.parse(readFileSync(candidate, 'utf8'))
|
|
152
|
+
if (!fsHooks.existsSync(candidate) || !fsHooks.statSync(candidate).isFile()) continue
|
|
153
|
+
const doc = JSON.parse(fsHooks.readFileSync(candidate, 'utf8'))
|
|
96
154
|
const version = parseVersion(doc && doc.version) ? String(doc.version) : ''
|
|
97
155
|
if (!version) continue
|
|
98
156
|
// Only trust a manifest that IS dbhub: an unrelated package.json above
|
|
@@ -139,19 +197,45 @@ export function capabilitiesOf(rawVersion) {
|
|
|
139
197
|
return { version, readonlyTools: true, ssh: true, warning: '' }
|
|
140
198
|
}
|
|
141
199
|
|
|
200
|
+
/**
|
|
201
|
+
* Detection cache key: the path plus the executable's mtime (0 when it cannot be
|
|
202
|
+
* stat'ed, which keeps the key stable for a layout whose shim does not exist).
|
|
203
|
+
*/
|
|
204
|
+
function cacheKeyOf(raw) {
|
|
205
|
+
let stamp = 0
|
|
206
|
+
if (raw) {
|
|
207
|
+
try {
|
|
208
|
+
stamp = Number(fsHooks.statSync(raw).mtimeMs) || 0
|
|
209
|
+
} catch (e) {
|
|
210
|
+
stamp = 0
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
return raw + '\u0000' + String(stamp)
|
|
214
|
+
}
|
|
215
|
+
|
|
142
216
|
/**
|
|
143
217
|
* Detect the capabilities of one resolved dbhub executable.
|
|
144
218
|
* Never throws and never blocks: an unresolvable version is reported as
|
|
145
219
|
* `unknown` and the features stay enabled (the caller only *uses* this on
|
|
146
220
|
* read-only / SSH environments, and an genuine incompatibility surfaces as a
|
|
147
221
|
* clear dbhub error).
|
|
222
|
+
*
|
|
223
|
+
* Cached per executable (see DETECTION_CACHE); a copy is returned so a caller can
|
|
224
|
+
* never poison the cache.
|
|
148
225
|
* @param exe - resolved dbhub executable path (may be undefined at boot).
|
|
149
226
|
* @returns `{ version, readonlyTools, ssh, warning }`.
|
|
150
227
|
*/
|
|
151
228
|
export function detectDbhubCapabilities(exe) {
|
|
229
|
+
const raw = String(exe === undefined || exe === null ? '' : exe).trim()
|
|
230
|
+
const key = cacheKeyOf(raw)
|
|
231
|
+
const hit = DETECTION_CACHE.get(key)
|
|
232
|
+
if (hit) return { ...hit }
|
|
233
|
+
let value
|
|
152
234
|
try {
|
|
153
|
-
|
|
235
|
+
value = capabilitiesOf(detectVersion(raw))
|
|
154
236
|
} catch (e) {
|
|
155
|
-
|
|
237
|
+
value = { version: '', readonlyTools: true, ssh: true, warning: 'unknown' }
|
|
156
238
|
}
|
|
239
|
+
DETECTION_CACHE.set(key, value)
|
|
240
|
+
return { ...value }
|
|
157
241
|
}
|