@carllee1983/dbcli 1.56.0 → 1.58.0
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/.cursor/rules/dbcli.mdc +20 -2
- package/.cursor/skills/dbcli/reference.md +53 -3
- package/.github/skills/dbcli/SKILL.md +20 -2
- package/.github/skills/dbcli/reference.md +53 -3
- package/CHANGELOG.md +56 -0
- package/assets/SKILL.md +20 -2
- package/assets/SKILL.zh-TW.md +15 -1
- package/assets/reference.md +53 -3
- package/dist/cli-runtime.mjs +1160 -618
- package/dist/cli.mjs +4 -2
- package/dist/core.d.ts +223 -146
- package/dist/core.mjs +481 -371
- package/package.json +4 -2
- package/plugins/dbcli-agent/skills/dbcli/SKILL.md +20 -2
- package/plugins/dbcli-agent/skills/dbcli/reference.md +53 -3
- package/skills/dbcli/SKILL.md +20 -2
- package/skills/dbcli/reference.md +53 -3
package/dist/core.mjs
CHANGED
|
@@ -118,24 +118,24 @@ var require_picocolors = __commonJS((exports, module) => {
|
|
|
118
118
|
|
|
119
119
|
// node_modules/lru-cache/dist/esm/node/index.min.js
|
|
120
120
|
import { tracingChannel as j, channel as G } from "diagnostics_channel";
|
|
121
|
-
var w, W, C, D = () => w.hasSubscribers || W.hasSubscribers, I, L, P = (u, e,
|
|
122
|
-
typeof L.emitWarning == "function" ? L.emitWarning(u, e,
|
|
121
|
+
var w, W, C, D = () => w.hasSubscribers || W.hasSubscribers, I, L, P = (u, e, t2, i) => {
|
|
122
|
+
typeof L.emitWarning == "function" ? L.emitWarning(u, e, t2, i) : console.error(`[${t2}] ${e}: ${u}`);
|
|
123
123
|
}, H = (u) => !I.has(u), T = (u) => !!u && u === Math.floor(u) && u > 0 && isFinite(u), U = (u) => T(u) ? u <= Math.pow(2, 8) ? Uint8Array : u <= Math.pow(2, 16) ? Uint16Array : u <= Math.pow(2, 32) ? Uint32Array : u <= Number.MAX_SAFE_INTEGER ? O : null : null, O, R = class u {
|
|
124
124
|
heap;
|
|
125
125
|
length;
|
|
126
126
|
static #o = false;
|
|
127
127
|
static create(e) {
|
|
128
|
-
let
|
|
129
|
-
if (!
|
|
128
|
+
let t2 = U(e);
|
|
129
|
+
if (!t2)
|
|
130
130
|
return [];
|
|
131
131
|
u.#o = true;
|
|
132
|
-
let i = new u(e,
|
|
132
|
+
let i = new u(e, t2);
|
|
133
133
|
return u.#o = false, i;
|
|
134
134
|
}
|
|
135
|
-
constructor(e,
|
|
135
|
+
constructor(e, t2) {
|
|
136
136
|
if (!u.#o)
|
|
137
137
|
throw new TypeError("instantiate Stack using Stack.create(n)");
|
|
138
|
-
this.heap = new
|
|
138
|
+
this.heap = new t2(e), this.length = 0;
|
|
139
139
|
}
|
|
140
140
|
push(e) {
|
|
141
141
|
this.heap[this.length++] = e;
|
|
@@ -206,7 +206,7 @@ var init_index_min = __esm(() => {
|
|
|
206
206
|
return e.#a;
|
|
207
207
|
}, get tail() {
|
|
208
208
|
return e.#h;
|
|
209
|
-
}, free: e.#y, isBackgroundFetch: (
|
|
209
|
+
}, free: e.#y, isBackgroundFetch: (t2) => e.#e(t2), backgroundFetch: (t2, i, s, n) => e.#P(t2, i, s, n), moveToTail: (t2) => e.#L(t2), indexes: (t2) => e.#A(t2), rindexes: (t2) => e.#z(t2), isStale: (t2) => e.#p(t2) };
|
|
210
210
|
}
|
|
211
211
|
get max() {
|
|
212
212
|
return this.#o;
|
|
@@ -236,15 +236,15 @@ var init_index_min = __esm(() => {
|
|
|
236
236
|
return this.#S;
|
|
237
237
|
}
|
|
238
238
|
constructor(e) {
|
|
239
|
-
let { max:
|
|
239
|
+
let { max: t2 = 0, ttl: i, ttlResolution: s = 1, ttlAutopurge: n, updateAgeOnGet: r, updateAgeOnHas: h, allowStale: a, dispose: o, onInsert: p, disposeAfter: m, noDisposeOnSet: _, noUpdateTTL: c, maxSize: d = 0, maxEntrySize: f = 0, sizeCalculation: y, fetchMethod: l, memoMethod: S, noDeleteOnFetchRejection: F, noDeleteOnStaleGet: b, allowStaleOnFetchRejection: g, allowStaleOnFetchAbort: A, ignoreFetchAbort: z, perf: x } = e;
|
|
240
240
|
if (x !== undefined && typeof x?.now != "function")
|
|
241
241
|
throw new TypeError("perf option must have a now() method if specified");
|
|
242
|
-
if (this.#m = x ?? C,
|
|
242
|
+
if (this.#m = x ?? C, t2 !== 0 && !T(t2))
|
|
243
243
|
throw new TypeError("max option must be a nonnegative integer");
|
|
244
|
-
let E =
|
|
244
|
+
let E = t2 ? U(t2) : Array;
|
|
245
245
|
if (!E)
|
|
246
|
-
throw new Error("invalid max value: " +
|
|
247
|
-
if (this.#o =
|
|
246
|
+
throw new Error("invalid max value: " + t2);
|
|
247
|
+
if (this.#o = t2, this.#c = d, this.maxEntrySize = f || this.#c, this.sizeCalculation = y, this.sizeCalculation) {
|
|
248
248
|
if (!this.#c && !this.maxEntrySize)
|
|
249
249
|
throw new TypeError("cannot set sizeCalculation without setting maxSize or maxEntrySize");
|
|
250
250
|
if (typeof this.sizeCalculation != "function")
|
|
@@ -254,7 +254,7 @@ var init_index_min = __esm(() => {
|
|
|
254
254
|
throw new TypeError("memoMethod must be a function if defined");
|
|
255
255
|
if (this.#I = S, l !== undefined && typeof l != "function")
|
|
256
256
|
throw new TypeError("fetchMethod must be a function if specified");
|
|
257
|
-
if (this.#M = l, this.#U = !!l, this.#s = new Map, this.#i = Array.from({ length:
|
|
257
|
+
if (this.#M = l, this.#U = !!l, this.#s = new Map, this.#i = Array.from({ length: t2 }).fill(undefined), this.#t = Array.from({ length: t2 }).fill(undefined), this.#l = new E(t2), this.#u = new E(t2), this.#a = 0, this.#h = 0, this.#y = R.create(t2), this.#n = 0, this.#b = 0, typeof o == "function" && (this.#w = o), typeof p == "function" && (this.#O = p), typeof m == "function" ? (this.#S = m, this.#r = []) : (this.#S = undefined, this.#r = undefined), this.#T = !!this.#w, this.#x = !!this.#O, this.#f = !!this.#S, this.noDisposeOnSet = !!_, this.noUpdateTTL = !!c, this.noDeleteOnFetchRejection = !!F, this.allowStaleOnFetchRejection = !!g, this.allowStaleOnFetchAbort = !!A, this.ignoreFetchAbort = !!z, this.maxEntrySize !== 0) {
|
|
258
258
|
if (this.#c !== 0 && !T(this.#c))
|
|
259
259
|
throw new TypeError("maxSize must be a positive integer if specified");
|
|
260
260
|
if (!T(this.maxEntrySize))
|
|
@@ -277,13 +277,13 @@ var init_index_min = __esm(() => {
|
|
|
277
277
|
return this.#s.has(e) ? 1 / 0 : 0;
|
|
278
278
|
}
|
|
279
279
|
#H() {
|
|
280
|
-
let e = new O(this.#o),
|
|
281
|
-
this.#d = e, this.#F =
|
|
280
|
+
let e = new O(this.#o), t2 = new O(this.#o);
|
|
281
|
+
this.#d = e, this.#F = t2;
|
|
282
282
|
let i = this.ttlAutopurge ? Array.from({ length: this.#o }) : undefined;
|
|
283
283
|
this.#g = i, this.#N = (h, a, o = this.#m.now()) => {
|
|
284
|
-
|
|
284
|
+
t2[h] = a !== 0 ? o : 0, e[h] = a, s(h, a);
|
|
285
285
|
}, this.#D = (h) => {
|
|
286
|
-
|
|
286
|
+
t2[h] = e[h] !== 0 ? this.#m.now() : 0, s(h, e[h]);
|
|
287
287
|
};
|
|
288
288
|
let s = this.ttlAutopurge ? (h, a) => {
|
|
289
289
|
if (i?.[h] && (clearTimeout(i[h]), i[h] = undefined), a && a !== 0 && i) {
|
|
@@ -295,7 +295,7 @@ var init_index_min = __esm(() => {
|
|
|
295
295
|
} : () => {};
|
|
296
296
|
this.#v = (h, a) => {
|
|
297
297
|
if (e[a]) {
|
|
298
|
-
let o = e[a], p =
|
|
298
|
+
let o = e[a], p = t2[a];
|
|
299
299
|
if (!o || !p)
|
|
300
300
|
return;
|
|
301
301
|
h.ttl = o, h.start = p, h.now = n || r();
|
|
@@ -316,13 +316,13 @@ var init_index_min = __esm(() => {
|
|
|
316
316
|
let a = this.#s.get(h);
|
|
317
317
|
if (a === undefined)
|
|
318
318
|
return 0;
|
|
319
|
-
let o = e[a], p =
|
|
319
|
+
let o = e[a], p = t2[a];
|
|
320
320
|
if (!o || !p)
|
|
321
321
|
return 1 / 0;
|
|
322
322
|
let m = (n || r()) - p;
|
|
323
323
|
return o - m;
|
|
324
324
|
}, this.#p = (h) => {
|
|
325
|
-
let a =
|
|
325
|
+
let a = t2[h], o = e[h];
|
|
326
326
|
return !!o && !!a && (n || r()) - a > o;
|
|
327
327
|
};
|
|
328
328
|
}
|
|
@@ -332,45 +332,45 @@ var init_index_min = __esm(() => {
|
|
|
332
332
|
#p = () => false;
|
|
333
333
|
#X() {
|
|
334
334
|
let e = new O(this.#o);
|
|
335
|
-
this.#b = 0, this.#_ = e, this.#R = (
|
|
336
|
-
this.#b -= e[
|
|
337
|
-
}, this.#V = (
|
|
335
|
+
this.#b = 0, this.#_ = e, this.#R = (t2) => {
|
|
336
|
+
this.#b -= e[t2], e[t2] = 0;
|
|
337
|
+
}, this.#V = (t2, i, s, n) => {
|
|
338
338
|
if (this.#e(i))
|
|
339
339
|
return 0;
|
|
340
340
|
if (!T(s))
|
|
341
341
|
if (n) {
|
|
342
342
|
if (typeof n != "function")
|
|
343
343
|
throw new TypeError("sizeCalculation must be a function");
|
|
344
|
-
if (s = n(i,
|
|
344
|
+
if (s = n(i, t2), !T(s))
|
|
345
345
|
throw new TypeError("sizeCalculation return invalid (expect positive integer)");
|
|
346
346
|
} else
|
|
347
347
|
throw new TypeError("invalid size value (must be positive integer). When maxSize or maxEntrySize is used, sizeCalculation or size must be set.");
|
|
348
348
|
return s;
|
|
349
|
-
}, this.#j = (
|
|
350
|
-
if (e[
|
|
351
|
-
let n = this.#c - e[
|
|
349
|
+
}, this.#j = (t2, i, s) => {
|
|
350
|
+
if (e[t2] = i, this.#c) {
|
|
351
|
+
let n = this.#c - e[t2];
|
|
352
352
|
for (;this.#b > n; )
|
|
353
353
|
this.#G(true);
|
|
354
354
|
}
|
|
355
|
-
this.#b += e[
|
|
355
|
+
this.#b += e[t2], s && (s.entrySize = i, s.totalCalculatedSize = this.#b);
|
|
356
356
|
};
|
|
357
357
|
}
|
|
358
358
|
#R = (e) => {};
|
|
359
|
-
#j = (e,
|
|
360
|
-
#V = (e,
|
|
359
|
+
#j = (e, t2, i) => {};
|
|
360
|
+
#V = (e, t2, i, s) => {
|
|
361
361
|
if (i || s)
|
|
362
362
|
throw new TypeError("cannot set size without setting maxSize or maxEntrySize on cache");
|
|
363
363
|
return 0;
|
|
364
364
|
};
|
|
365
365
|
*#A({ allowStale: e = this.allowStale } = {}) {
|
|
366
366
|
if (this.#n)
|
|
367
|
-
for (let
|
|
368
|
-
|
|
367
|
+
for (let t2 = this.#h;this.#B(t2) && ((e || !this.#p(t2)) && (yield t2), t2 !== this.#a); )
|
|
368
|
+
t2 = this.#u[t2];
|
|
369
369
|
}
|
|
370
370
|
*#z({ allowStale: e = this.allowStale } = {}) {
|
|
371
371
|
if (this.#n)
|
|
372
|
-
for (let
|
|
373
|
-
|
|
372
|
+
for (let t2 = this.#a;this.#B(t2) && ((e || !this.#p(t2)) && (yield t2), t2 !== this.#h); )
|
|
373
|
+
t2 = this.#l[t2];
|
|
374
374
|
}
|
|
375
375
|
#B(e) {
|
|
376
376
|
return e !== undefined && this.#s.get(this.#i[e]) === e;
|
|
@@ -385,14 +385,14 @@ var init_index_min = __esm(() => {
|
|
|
385
385
|
}
|
|
386
386
|
*keys() {
|
|
387
387
|
for (let e of this.#A()) {
|
|
388
|
-
let
|
|
389
|
-
|
|
388
|
+
let t2 = this.#i[e];
|
|
389
|
+
t2 !== undefined && !this.#e(this.#t[e]) && (yield t2);
|
|
390
390
|
}
|
|
391
391
|
}
|
|
392
392
|
*rkeys() {
|
|
393
393
|
for (let e of this.#z()) {
|
|
394
|
-
let
|
|
395
|
-
|
|
394
|
+
let t2 = this.#i[e];
|
|
395
|
+
t2 !== undefined && !this.#e(this.#t[e]) && (yield t2);
|
|
396
396
|
}
|
|
397
397
|
}
|
|
398
398
|
*values() {
|
|
@@ -407,109 +407,109 @@ var init_index_min = __esm(() => {
|
|
|
407
407
|
return this.entries();
|
|
408
408
|
}
|
|
409
409
|
[Symbol.toStringTag] = "LRUCache";
|
|
410
|
-
find(e,
|
|
410
|
+
find(e, t2 = {}) {
|
|
411
411
|
for (let i of this.#A()) {
|
|
412
412
|
let s = this.#t[i], n = this.#e(s) ? s.__staleWhileFetching : s;
|
|
413
413
|
if (n !== undefined && e(n, this.#i[i], this))
|
|
414
|
-
return this.#C(this.#i[i],
|
|
414
|
+
return this.#C(this.#i[i], t2);
|
|
415
415
|
}
|
|
416
416
|
}
|
|
417
|
-
forEach(e,
|
|
417
|
+
forEach(e, t2 = this) {
|
|
418
418
|
for (let i of this.#A()) {
|
|
419
419
|
let s = this.#t[i], n = this.#e(s) ? s.__staleWhileFetching : s;
|
|
420
|
-
n !== undefined && e.call(
|
|
420
|
+
n !== undefined && e.call(t2, n, this.#i[i], this);
|
|
421
421
|
}
|
|
422
422
|
}
|
|
423
|
-
rforEach(e,
|
|
423
|
+
rforEach(e, t2 = this) {
|
|
424
424
|
for (let i of this.#z()) {
|
|
425
425
|
let s = this.#t[i], n = this.#e(s) ? s.__staleWhileFetching : s;
|
|
426
|
-
n !== undefined && e.call(
|
|
426
|
+
n !== undefined && e.call(t2, n, this.#i[i], this);
|
|
427
427
|
}
|
|
428
428
|
}
|
|
429
429
|
purgeStale() {
|
|
430
430
|
let e = false;
|
|
431
|
-
for (let
|
|
432
|
-
this.#p(
|
|
431
|
+
for (let t2 of this.#z({ allowStale: true }))
|
|
432
|
+
this.#p(t2) && (this.#E(this.#i[t2], "expire"), e = true);
|
|
433
433
|
return e;
|
|
434
434
|
}
|
|
435
435
|
info(e) {
|
|
436
|
-
let
|
|
437
|
-
if (
|
|
436
|
+
let t2 = this.#s.get(e);
|
|
437
|
+
if (t2 === undefined)
|
|
438
438
|
return;
|
|
439
|
-
let i = this.#t[
|
|
439
|
+
let i = this.#t[t2], s = this.#e(i) ? i.__staleWhileFetching : i;
|
|
440
440
|
if (s === undefined)
|
|
441
441
|
return;
|
|
442
442
|
let n = { value: s };
|
|
443
443
|
if (this.#d && this.#F) {
|
|
444
|
-
let r = this.#d[
|
|
444
|
+
let r = this.#d[t2], h = this.#F[t2];
|
|
445
445
|
if (r && h) {
|
|
446
446
|
let a = r - (this.#m.now() - h);
|
|
447
447
|
n.ttl = a, n.start = Date.now();
|
|
448
448
|
}
|
|
449
449
|
}
|
|
450
|
-
return this.#_ && (n.size = this.#_[
|
|
450
|
+
return this.#_ && (n.size = this.#_[t2]), n;
|
|
451
451
|
}
|
|
452
452
|
dump() {
|
|
453
453
|
let e = [];
|
|
454
|
-
for (let
|
|
455
|
-
let i = this.#i[
|
|
454
|
+
for (let t2 of this.#A({ allowStale: true })) {
|
|
455
|
+
let i = this.#i[t2], s = this.#t[t2], n = this.#e(s) ? s.__staleWhileFetching : s;
|
|
456
456
|
if (n === undefined || i === undefined)
|
|
457
457
|
continue;
|
|
458
458
|
let r = { value: n };
|
|
459
459
|
if (this.#d && this.#F) {
|
|
460
|
-
r.ttl = this.#d[
|
|
461
|
-
let h = this.#m.now() - this.#F[
|
|
460
|
+
r.ttl = this.#d[t2];
|
|
461
|
+
let h = this.#m.now() - this.#F[t2];
|
|
462
462
|
r.start = Math.floor(Date.now() - h);
|
|
463
463
|
}
|
|
464
|
-
this.#_ && (r.size = this.#_[
|
|
464
|
+
this.#_ && (r.size = this.#_[t2]), e.unshift([i, r]);
|
|
465
465
|
}
|
|
466
466
|
return e;
|
|
467
467
|
}
|
|
468
468
|
load(e) {
|
|
469
469
|
this.clear();
|
|
470
|
-
for (let [
|
|
470
|
+
for (let [t2, i] of e) {
|
|
471
471
|
if (i.start) {
|
|
472
472
|
let s = Date.now() - i.start;
|
|
473
473
|
i.start = this.#m.now() - s;
|
|
474
474
|
}
|
|
475
|
-
this.#W(
|
|
475
|
+
this.#W(t2, i.value, i);
|
|
476
476
|
}
|
|
477
477
|
}
|
|
478
|
-
set(e,
|
|
478
|
+
set(e, t2, i = {}) {
|
|
479
479
|
let { status: s = w.hasSubscribers ? {} : undefined } = i;
|
|
480
|
-
i.status = s, s && (s.op = "set", s.key = e,
|
|
481
|
-
let n = this.#W(e,
|
|
480
|
+
i.status = s, s && (s.op = "set", s.key = e, t2 !== undefined && (s.value = t2), s.cache = this);
|
|
481
|
+
let n = this.#W(e, t2, i);
|
|
482
482
|
return s && w.hasSubscribers && w.publish(s), n;
|
|
483
483
|
}
|
|
484
|
-
#W(e,
|
|
484
|
+
#W(e, t2, i, s) {
|
|
485
485
|
let { ttl: n = this.ttl, start: r, noDisposeOnSet: h = this.noDisposeOnSet, sizeCalculation: a = this.sizeCalculation, status: o } = i;
|
|
486
|
-
if (
|
|
486
|
+
if (t2 === undefined)
|
|
487
487
|
return o && (o.set = "deleted"), this.delete(e), this;
|
|
488
|
-
let { noUpdateTTL: p = this.noUpdateTTL } = i, m = this.#e(
|
|
489
|
-
o && !m && (o.value =
|
|
490
|
-
let _ = this.#V(e,
|
|
488
|
+
let { noUpdateTTL: p = this.noUpdateTTL } = i, m = this.#e(t2);
|
|
489
|
+
o && !m && (o.value = t2);
|
|
490
|
+
let _ = this.#V(e, t2, i.size || 0, a, o);
|
|
491
491
|
if (this.maxEntrySize && _ > this.maxEntrySize)
|
|
492
492
|
return this.#E(e, "set"), o && (o.set = "miss", o.maxEntrySizeExceeded = true), this;
|
|
493
493
|
let c = this.#n === 0 ? undefined : this.#s.get(e);
|
|
494
494
|
if (c === undefined)
|
|
495
|
-
c = this.#n === 0 ? this.#h : this.#y.length !== 0 ? this.#y.pop() : this.#n === this.#o ? this.#G(false) : this.#n, this.#i[c] = e, this.#t[c] =
|
|
495
|
+
c = this.#n === 0 ? this.#h : this.#y.length !== 0 ? this.#y.pop() : this.#n === this.#o ? this.#G(false) : this.#n, this.#i[c] = e, this.#t[c] = t2, this.#s.set(e, c), this.#l[this.#h] = c, this.#u[c] = this.#h, this.#h = c, this.#n++, this.#j(c, _, o), o && (o.set = "add"), p = false, this.#x && !m && this.#O?.(t2, e, "add");
|
|
496
496
|
else {
|
|
497
497
|
this.#L(c);
|
|
498
498
|
let d = this.#t[c];
|
|
499
|
-
if (
|
|
499
|
+
if (t2 !== d) {
|
|
500
500
|
if (!h)
|
|
501
501
|
if (this.#e(d)) {
|
|
502
502
|
d !== s && d.__abortController.abort(new Error("replaced"));
|
|
503
503
|
let { __staleWhileFetching: f } = d;
|
|
504
|
-
f !== undefined && f !==
|
|
504
|
+
f !== undefined && f !== t2 && (this.#T && this.#w?.(f, e, "set"), this.#f && this.#r?.push([f, e, "set"]));
|
|
505
505
|
} else
|
|
506
506
|
this.#T && this.#w?.(d, e, "set"), this.#f && this.#r?.push([d, e, "set"]);
|
|
507
|
-
if (this.#R(c), this.#j(c, _, o), this.#t[c] =
|
|
508
|
-
let f = d && this.#e(d) ? d.__staleWhileFetching : d, y = f === undefined ? "add" :
|
|
509
|
-
o && (o.set = y, f !== undefined && (o.oldValue = f)), this.#x && this.onInsert?.(
|
|
507
|
+
if (this.#R(c), this.#j(c, _, o), this.#t[c] = t2, !m) {
|
|
508
|
+
let f = d && this.#e(d) ? d.__staleWhileFetching : d, y = f === undefined ? "add" : t2 !== f ? "replace" : "update";
|
|
509
|
+
o && (o.set = y, f !== undefined && (o.oldValue = f)), this.#x && this.onInsert?.(t2, e, y);
|
|
510
510
|
}
|
|
511
511
|
} else
|
|
512
|
-
m || (o && (o.set = "update"), this.#x && this.onInsert?.(
|
|
512
|
+
m || (o && (o.set = "update"), this.#x && this.onInsert?.(t2, e, "update"));
|
|
513
513
|
}
|
|
514
514
|
if (n !== 0 && !this.#d && this.#H(), this.#d && (p || this.#N(c, n, r), o && this.#v(o, c)), !h && this.#f && this.#r) {
|
|
515
515
|
let d = this.#r, f;
|
|
@@ -530,26 +530,26 @@ var init_index_min = __esm(() => {
|
|
|
530
530
|
}
|
|
531
531
|
} finally {
|
|
532
532
|
if (this.#f && this.#r) {
|
|
533
|
-
let e = this.#r,
|
|
534
|
-
for (;
|
|
535
|
-
this.#S?.(...
|
|
533
|
+
let e = this.#r, t2;
|
|
534
|
+
for (;t2 = e?.shift(); )
|
|
535
|
+
this.#S?.(...t2);
|
|
536
536
|
}
|
|
537
537
|
}
|
|
538
538
|
}
|
|
539
539
|
#G(e) {
|
|
540
|
-
let
|
|
540
|
+
let t2 = this.#a, i = this.#i[t2], s = this.#t[t2], n = this.#e(s);
|
|
541
541
|
n && s.__abortController.abort(new Error("evicted"));
|
|
542
542
|
let r = n ? s.__staleWhileFetching : s;
|
|
543
|
-
return (this.#T || this.#f) && r !== undefined && (this.#T && this.#w?.(r, i, "evict"), this.#f && this.#r?.push([r, i, "evict"])), this.#R(
|
|
543
|
+
return (this.#T || this.#f) && r !== undefined && (this.#T && this.#w?.(r, i, "evict"), this.#f && this.#r?.push([r, i, "evict"])), this.#R(t2), this.#g?.[t2] && (clearTimeout(this.#g[t2]), this.#g[t2] = undefined), e && (this.#i[t2] = undefined, this.#t[t2] = undefined, this.#y.push(t2)), this.#n === 1 ? (this.#a = this.#h = 0, this.#y.length = 0) : this.#a = this.#l[t2], this.#s.delete(i), this.#n--, t2;
|
|
544
544
|
}
|
|
545
|
-
has(e,
|
|
546
|
-
let { status: i = w.hasSubscribers ? {} : undefined } =
|
|
547
|
-
|
|
548
|
-
let s = this.#Y(e,
|
|
545
|
+
has(e, t2 = {}) {
|
|
546
|
+
let { status: i = w.hasSubscribers ? {} : undefined } = t2;
|
|
547
|
+
t2.status = i, i && (i.op = "has", i.key = e, i.cache = this);
|
|
548
|
+
let s = this.#Y(e, t2);
|
|
549
549
|
return w.hasSubscribers && w.publish(i), s;
|
|
550
550
|
}
|
|
551
|
-
#Y(e,
|
|
552
|
-
let { updateAgeOnHas: i = this.updateAgeOnHas, status: s } =
|
|
551
|
+
#Y(e, t2 = {}) {
|
|
552
|
+
let { updateAgeOnHas: i = this.updateAgeOnHas, status: s } = t2, n = this.#s.get(e);
|
|
553
553
|
if (n !== undefined) {
|
|
554
554
|
let r = this.#t[n];
|
|
555
555
|
if (this.#e(r) && r.__staleWhileFetching === undefined)
|
|
@@ -562,14 +562,14 @@ var init_index_min = __esm(() => {
|
|
|
562
562
|
s && (s.has = "miss");
|
|
563
563
|
return false;
|
|
564
564
|
}
|
|
565
|
-
peek(e,
|
|
566
|
-
let { status: i = D() ? {} : undefined } =
|
|
567
|
-
i && (i.op = "peek", i.key = e, i.cache = this),
|
|
568
|
-
let s = this.#J(e,
|
|
565
|
+
peek(e, t2 = {}) {
|
|
566
|
+
let { status: i = D() ? {} : undefined } = t2;
|
|
567
|
+
i && (i.op = "peek", i.key = e, i.cache = this), t2.status = i;
|
|
568
|
+
let s = this.#J(e, t2);
|
|
569
569
|
return w.hasSubscribers && w.publish(i), s;
|
|
570
570
|
}
|
|
571
|
-
#J(e,
|
|
572
|
-
let { status: i, allowStale: s = this.allowStale } =
|
|
571
|
+
#J(e, t2) {
|
|
572
|
+
let { status: i, allowStale: s = this.allowStale } = t2, n = this.#s.get(e);
|
|
573
573
|
if (n === undefined || !s && this.#p(n)) {
|
|
574
574
|
i && (i.peek = n === undefined ? "miss" : "stale");
|
|
575
575
|
return;
|
|
@@ -577,8 +577,8 @@ var init_index_min = __esm(() => {
|
|
|
577
577
|
let r = this.#t[n], h = this.#e(r) ? r.__staleWhileFetching : r;
|
|
578
578
|
return i && (h !== undefined ? (i.peek = "hit", i.value = h) : i.peek = "miss"), h;
|
|
579
579
|
}
|
|
580
|
-
#P(e,
|
|
581
|
-
let n =
|
|
580
|
+
#P(e, t2, i, s) {
|
|
581
|
+
let n = t2 === undefined ? undefined : this.#t[t2];
|
|
582
582
|
if (this.#e(n))
|
|
583
583
|
return n;
|
|
584
584
|
let r = new AbortController, { signal: h } = i;
|
|
@@ -587,11 +587,11 @@ var init_index_min = __esm(() => {
|
|
|
587
587
|
let { aborted: l } = r.signal, S = i.ignoreFetchAbort && f !== undefined, F = i.ignoreFetchAbort || !!(i.allowStaleOnFetchAbort && f !== undefined);
|
|
588
588
|
if (i.status && (l && !y ? (i.status.fetchAborted = true, i.status.fetchError = r.signal.reason, S && (i.status.fetchAbortIgnored = true)) : i.status.fetchResolved = true), l && !S && !y)
|
|
589
589
|
return m(r.signal.reason, F);
|
|
590
|
-
let b = c, g = this.#t[
|
|
591
|
-
return (g === c || g === undefined && S && y) && (f === undefined ? b.__staleWhileFetching !== undefined ? this.#t[
|
|
590
|
+
let b = c, g = this.#t[t2];
|
|
591
|
+
return (g === c || g === undefined && S && y) && (f === undefined ? b.__staleWhileFetching !== undefined ? this.#t[t2] = b.__staleWhileFetching : this.#E(e, "fetch") : (i.status && (i.status.fetchUpdated = true), this.#W(e, f, a.options, b))), f;
|
|
592
592
|
}, p = (f) => (i.status && (i.status.fetchRejected = true, i.status.fetchError = f), m(f, false)), m = (f, y) => {
|
|
593
593
|
let { aborted: l } = r.signal, S = l && i.allowStaleOnFetchAbort, F = S || i.allowStaleOnFetchRejection, b = F || i.noDeleteOnFetchRejection, g = c;
|
|
594
|
-
if (this.#t[
|
|
594
|
+
if (this.#t[t2] === c && (!b || !y && g.__staleWhileFetching === undefined ? this.#E(e, "fetch") : S || (this.#t[t2] = g.__staleWhileFetching)), F)
|
|
595
595
|
return i.status && g.__staleWhileFetching !== undefined && (i.status.returnedStale = true), g.__staleWhileFetching;
|
|
596
596
|
if (g.__returned === g)
|
|
597
597
|
throw f;
|
|
@@ -603,22 +603,22 @@ var init_index_min = __esm(() => {
|
|
|
603
603
|
};
|
|
604
604
|
i.status && (i.status.fetchDispatched = true);
|
|
605
605
|
let c = new Promise(_).then(o, p), d = Object.assign(c, { __abortController: r, __staleWhileFetching: n, __returned: undefined });
|
|
606
|
-
return
|
|
606
|
+
return t2 === undefined ? (this.#W(e, d, { ...a.options, status: undefined }), t2 = this.#s.get(e)) : this.#t[t2] = d, d;
|
|
607
607
|
}
|
|
608
608
|
#e(e) {
|
|
609
609
|
if (!this.#U)
|
|
610
610
|
return false;
|
|
611
|
-
let
|
|
612
|
-
return !!
|
|
611
|
+
let t2 = e;
|
|
612
|
+
return !!t2 && t2 instanceof Promise && t2.hasOwnProperty("__staleWhileFetching") && t2.__abortController instanceof AbortController;
|
|
613
613
|
}
|
|
614
|
-
fetch(e,
|
|
615
|
-
let i = W.hasSubscribers, { status: s = D() ? {} : undefined } =
|
|
616
|
-
|
|
617
|
-
let n = this.#k(e,
|
|
614
|
+
fetch(e, t2 = {}) {
|
|
615
|
+
let i = W.hasSubscribers, { status: s = D() ? {} : undefined } = t2;
|
|
616
|
+
t2.status = s, s && t2.context && (s.context = t2.context);
|
|
617
|
+
let n = this.#k(e, t2);
|
|
618
618
|
return s && i && (s.trace = true, W.tracePromise(() => n, s).catch(() => {})), n;
|
|
619
619
|
}
|
|
620
|
-
async#k(e,
|
|
621
|
-
let { allowStale: i = this.allowStale, updateAgeOnGet: s = this.updateAgeOnGet, noDeleteOnStaleGet: n = this.noDeleteOnStaleGet, ttl: r = this.ttl, noDisposeOnSet: h = this.noDisposeOnSet, size: a = 0, sizeCalculation: o = this.sizeCalculation, noUpdateTTL: p = this.noUpdateTTL, noDeleteOnFetchRejection: m = this.noDeleteOnFetchRejection, allowStaleOnFetchRejection: _ = this.allowStaleOnFetchRejection, ignoreFetchAbort: c = this.ignoreFetchAbort, allowStaleOnFetchAbort: d = this.allowStaleOnFetchAbort, context: f, forceRefresh: y = false, status: l, signal: S } =
|
|
620
|
+
async#k(e, t2 = {}) {
|
|
621
|
+
let { allowStale: i = this.allowStale, updateAgeOnGet: s = this.updateAgeOnGet, noDeleteOnStaleGet: n = this.noDeleteOnStaleGet, ttl: r = this.ttl, noDisposeOnSet: h = this.noDisposeOnSet, size: a = 0, sizeCalculation: o = this.sizeCalculation, noUpdateTTL: p = this.noUpdateTTL, noDeleteOnFetchRejection: m = this.noDeleteOnFetchRejection, allowStaleOnFetchRejection: _ = this.allowStaleOnFetchRejection, ignoreFetchAbort: c = this.ignoreFetchAbort, allowStaleOnFetchAbort: d = this.allowStaleOnFetchAbort, context: f, forceRefresh: y = false, status: l, signal: S } = t2;
|
|
622
622
|
if (l && (l.op = "fetch", l.key = e, y && (l.forceRefresh = true), l.cache = this), !this.#U)
|
|
623
623
|
return l && (l.fetch = "get"), this.#C(e, { allowStale: i, updateAgeOnGet: s, noDeleteOnStaleGet: n, status: l });
|
|
624
624
|
let F = { allowStale: i, updateAgeOnGet: s, noDeleteOnStaleGet: n, ttl: r, noDisposeOnSet: h, size: a, sizeCalculation: o, noUpdateTTL: p, noDeleteOnFetchRejection: m, allowStaleOnFetchRejection: _, allowStaleOnFetchAbort: d, ignoreFetchAbort: c, status: l, signal: S }, b = this.#s.get(e);
|
|
@@ -639,29 +639,29 @@ var init_index_min = __esm(() => {
|
|
|
639
639
|
return l && (l.fetch = A ? "stale" : "refresh", E && A && (l.returnedStale = true)), E ? z.__staleWhileFetching : z.__returned = z;
|
|
640
640
|
}
|
|
641
641
|
}
|
|
642
|
-
forceFetch(e,
|
|
643
|
-
let i = W.hasSubscribers, { status: s = D() ? {} : undefined } =
|
|
644
|
-
|
|
645
|
-
let n = this.#K(e,
|
|
642
|
+
forceFetch(e, t2 = {}) {
|
|
643
|
+
let i = W.hasSubscribers, { status: s = D() ? {} : undefined } = t2;
|
|
644
|
+
t2.status = s, s && t2.context && (s.context = t2.context);
|
|
645
|
+
let n = this.#K(e, t2);
|
|
646
646
|
return s && i && (s.trace = true, W.tracePromise(() => n, s).catch(() => {})), n;
|
|
647
647
|
}
|
|
648
|
-
async#K(e,
|
|
649
|
-
let i = await this.#k(e,
|
|
648
|
+
async#K(e, t2 = {}) {
|
|
649
|
+
let i = await this.#k(e, t2);
|
|
650
650
|
if (i === undefined)
|
|
651
651
|
throw new Error("fetch() returned undefined");
|
|
652
652
|
return i;
|
|
653
653
|
}
|
|
654
|
-
memo(e,
|
|
655
|
-
let { status: i = w.hasSubscribers ? {} : undefined } =
|
|
656
|
-
|
|
657
|
-
let s = this.#Q(e,
|
|
654
|
+
memo(e, t2 = {}) {
|
|
655
|
+
let { status: i = w.hasSubscribers ? {} : undefined } = t2;
|
|
656
|
+
t2.status = i, i && (i.op = "memo", i.key = e, t2.context && (i.context = t2.context), i.cache = this);
|
|
657
|
+
let s = this.#Q(e, t2);
|
|
658
658
|
return i && (i.value = s), w.hasSubscribers && w.publish(i), s;
|
|
659
659
|
}
|
|
660
|
-
#Q(e,
|
|
660
|
+
#Q(e, t2 = {}) {
|
|
661
661
|
let i = this.#I;
|
|
662
662
|
if (!i)
|
|
663
663
|
throw new Error("no memoMethod provided to constructor");
|
|
664
|
-
let { context: s, status: n, forceRefresh: r, ...h } =
|
|
664
|
+
let { context: s, status: n, forceRefresh: r, ...h } = t2;
|
|
665
665
|
n && r && (n.forceRefresh = true);
|
|
666
666
|
let a = this.#C(e, h), o = r || a === undefined;
|
|
667
667
|
if (n && (n.memo = o ? "miss" : "hit", o || (n.value = a)), !o)
|
|
@@ -669,14 +669,14 @@ var init_index_min = __esm(() => {
|
|
|
669
669
|
let p = i(e, a, { options: h, context: s });
|
|
670
670
|
return n && (n.value = p), this.#W(e, p, h), p;
|
|
671
671
|
}
|
|
672
|
-
get(e,
|
|
673
|
-
let { status: i = w.hasSubscribers ? {} : undefined } =
|
|
674
|
-
|
|
675
|
-
let s = this.#C(e,
|
|
672
|
+
get(e, t2 = {}) {
|
|
673
|
+
let { status: i = w.hasSubscribers ? {} : undefined } = t2;
|
|
674
|
+
t2.status = i, i && (i.op = "get", i.key = e, i.cache = this);
|
|
675
|
+
let s = this.#C(e, t2);
|
|
676
676
|
return i && (s !== undefined && (i.value = s), w.hasSubscribers && w.publish(i)), s;
|
|
677
677
|
}
|
|
678
|
-
#C(e,
|
|
679
|
-
let { allowStale: i = this.allowStale, updateAgeOnGet: s = this.updateAgeOnGet, noDeleteOnStaleGet: n = this.noDeleteOnStaleGet, status: r } =
|
|
678
|
+
#C(e, t2 = {}) {
|
|
679
|
+
let { allowStale: i = this.allowStale, updateAgeOnGet: s = this.updateAgeOnGet, noDeleteOnStaleGet: n = this.noDeleteOnStaleGet, status: r } = t2, h = this.#s.get(e);
|
|
680
680
|
if (h === undefined) {
|
|
681
681
|
r && (r.get = "miss");
|
|
682
682
|
return;
|
|
@@ -684,8 +684,8 @@ var init_index_min = __esm(() => {
|
|
|
684
684
|
let a = this.#t[h], o = this.#e(a);
|
|
685
685
|
return r && this.#v(r, h), this.#p(h) ? o ? (r && (r.get = "stale-fetching"), i && a.__staleWhileFetching !== undefined ? (r && (r.returnedStale = true), a.__staleWhileFetching) : undefined) : (n || this.#E(e, "expire"), r && (r.get = "stale"), i ? (r && (r.returnedStale = true), a) : undefined) : (r && (r.get = o ? "fetching" : "hit"), this.#L(h), s && this.#D(h), o ? a.__staleWhileFetching : a);
|
|
686
686
|
}
|
|
687
|
-
#$(e,
|
|
688
|
-
this.#u[
|
|
687
|
+
#$(e, t2) {
|
|
688
|
+
this.#u[t2] = e, this.#l[e] = t2;
|
|
689
689
|
}
|
|
690
690
|
#L(e) {
|
|
691
691
|
e !== this.#h && (e === this.#a ? this.#a = this.#l[e] : this.#$(this.#u[e], this.#l[e]), this.#$(this.#h, e), this.#h = e);
|
|
@@ -693,18 +693,18 @@ var init_index_min = __esm(() => {
|
|
|
693
693
|
delete(e) {
|
|
694
694
|
return this.#E(e, "delete");
|
|
695
695
|
}
|
|
696
|
-
#E(e,
|
|
697
|
-
w.hasSubscribers && w.publish({ op: "delete", delete:
|
|
696
|
+
#E(e, t2) {
|
|
697
|
+
w.hasSubscribers && w.publish({ op: "delete", delete: t2, key: e, cache: this });
|
|
698
698
|
let i = false;
|
|
699
699
|
if (this.#n !== 0) {
|
|
700
700
|
let s = this.#s.get(e);
|
|
701
701
|
if (s !== undefined)
|
|
702
702
|
if (this.#g?.[s] && (clearTimeout(this.#g?.[s]), this.#g[s] = undefined), i = true, this.#n === 1)
|
|
703
|
-
this.#q(
|
|
703
|
+
this.#q(t2);
|
|
704
704
|
else {
|
|
705
705
|
this.#R(s);
|
|
706
706
|
let n = this.#t[s];
|
|
707
|
-
if (this.#e(n) ? n.__abortController.abort(new Error("deleted")) : (this.#T || this.#f) && (this.#T && this.#w?.(n, e,
|
|
707
|
+
if (this.#e(n) ? n.__abortController.abort(new Error("deleted")) : (this.#T || this.#f) && (this.#T && this.#w?.(n, e, t2), this.#f && this.#r?.push([n, e, t2])), this.#s.delete(e), this.#i[s] = undefined, this.#t[s] = undefined, s === this.#h)
|
|
708
708
|
this.#h = this.#u[s];
|
|
709
709
|
else if (s === this.#a)
|
|
710
710
|
this.#a = this.#l[s];
|
|
@@ -728,24 +728,24 @@ var init_index_min = __esm(() => {
|
|
|
728
728
|
return this.#q("delete");
|
|
729
729
|
}
|
|
730
730
|
#q(e) {
|
|
731
|
-
for (let
|
|
732
|
-
let i = this.#t[
|
|
731
|
+
for (let t2 of this.#z({ allowStale: true })) {
|
|
732
|
+
let i = this.#t[t2];
|
|
733
733
|
if (this.#e(i))
|
|
734
734
|
i.__abortController.abort(new Error("deleted"));
|
|
735
735
|
else {
|
|
736
|
-
let s = this.#i[
|
|
736
|
+
let s = this.#i[t2];
|
|
737
737
|
this.#T && this.#w?.(i, s, e), this.#f && this.#r?.push([i, s, e]);
|
|
738
738
|
}
|
|
739
739
|
}
|
|
740
740
|
if (this.#s.clear(), this.#t.fill(undefined), this.#i.fill(undefined), this.#d && this.#F) {
|
|
741
741
|
this.#d.fill(0), this.#F.fill(0);
|
|
742
|
-
for (let
|
|
743
|
-
|
|
742
|
+
for (let t2 of this.#g ?? [])
|
|
743
|
+
t2 !== undefined && clearTimeout(t2);
|
|
744
744
|
this.#g?.fill(undefined);
|
|
745
745
|
}
|
|
746
746
|
if (this.#_ && this.#_.fill(0), this.#a = 0, this.#h = 0, this.#y.length = 0, this.#b = 0, this.#n = 0, this.#f && this.#r) {
|
|
747
|
-
let
|
|
748
|
-
for (;i =
|
|
747
|
+
let t2 = this.#r, i;
|
|
748
|
+
for (;i = t2?.shift(); )
|
|
749
749
|
this.#S?.(...i);
|
|
750
750
|
}
|
|
751
751
|
}
|
|
@@ -1679,6 +1679,12 @@ var messages_default = {
|
|
|
1679
1679
|
invalid_config: "Invalid configuration: {field}",
|
|
1680
1680
|
connection_failed: "Failed to connect to database: {message}",
|
|
1681
1681
|
permission_denied: "Permission denied (required: {required})",
|
|
1682
|
+
permission_requires_level: "{type} operation requires {minimum} permission or higher (current level: {permission})",
|
|
1683
|
+
elasticsearch_requires_level: "Elasticsearch {type} operation requires {minimum} permission or higher (current level: {permission})",
|
|
1684
|
+
escalated_write_requires_admin: "This statement opens as a read but contains an executable {keyword}. A write hidden inside a read statement requires admin permission (current level: {permission}).",
|
|
1685
|
+
multiple_statements_refused: "SQL containing multiple statements is refused below admin permission, because only the first statement determines the permission check. Run each statement separately.",
|
|
1686
|
+
unknown_statement_query_only: "Unrecognised SQL statement (current level: query-only). Security policy requires read-write+ for unknown statements. If this is a legitimate read-only statement, please open an issue at https://github.com/CarlLee1983/dbcli/issues.",
|
|
1687
|
+
permission_denied_reason: "Permission denied: {reason}",
|
|
1682
1688
|
table_not_found: "Table not found: {table}",
|
|
1683
1689
|
unsupported_lang: "Language '{lang}' not supported, using English",
|
|
1684
1690
|
invalid_json: "Invalid JSON: {message}",
|
|
@@ -1700,7 +1706,8 @@ Provide options: --env-host, --env-port, --env-user, --env-password, --env-datab
|
|
|
1700
1706
|
Or use interactive mode: run "dbcli init --use-env-refs" without --no-interactive`,
|
|
1701
1707
|
env_var_not_defined: `Cannot test connection: environment variable {envKey} is not defined.
|
|
1702
1708
|
Set {envKey} in .env or environment variables.
|
|
1703
|
-
Hint: run 'export {envKey}=<value>' and retry
|
|
1709
|
+
Hint: run 'export {envKey}=<value>' and retry`,
|
|
1710
|
+
invalid_output_format: "--format {format} is not supported here \u2014 use text or json"
|
|
1704
1711
|
},
|
|
1705
1712
|
success: {
|
|
1706
1713
|
inserted: "Successfully inserted {count} row(s)",
|
|
@@ -1711,19 +1718,22 @@ Hint: run 'export {envKey}=<value>' and retry`
|
|
|
1711
1718
|
insert: {
|
|
1712
1719
|
description: "Insert data into a table",
|
|
1713
1720
|
prompt_data: "Enter JSON data to insert: ",
|
|
1714
|
-
confirm: "Insert {count} row(s) into {table}? (y/n): "
|
|
1721
|
+
confirm: "Insert {count} row(s) into {table}? (y/n): ",
|
|
1722
|
+
elasticsearch_unsupported: "Elasticsearch does not support the insert command; for now, use an external tool (e.g. curl or Kibana DevTools) to write documents"
|
|
1715
1723
|
},
|
|
1716
1724
|
update: {
|
|
1717
1725
|
description: "Update data in a table",
|
|
1718
1726
|
prompt_where: "Enter WHERE clause (e.g., id=1): ",
|
|
1719
1727
|
prompt_set: 'Enter JSON updates (e.g., {"status": "active"}): ',
|
|
1720
|
-
confirm: "Update rows in {table}? (y/n): "
|
|
1728
|
+
confirm: "Update rows in {table}? (y/n): ",
|
|
1729
|
+
elasticsearch_unsupported: "Elasticsearch does not support the update command; for now, use an external tool (e.g. curl or Kibana DevTools) to update documents"
|
|
1721
1730
|
},
|
|
1722
1731
|
delete: {
|
|
1723
1732
|
description: "Delete data from a table",
|
|
1724
1733
|
prompt_where: "Enter WHERE clause (e.g., id=1): ",
|
|
1725
1734
|
confirm: "Delete rows from {table}? (y/n): ",
|
|
1726
|
-
admin_only: "Delete command requires data-admin or admin permission"
|
|
1735
|
+
admin_only: "Delete command requires data-admin or admin permission",
|
|
1736
|
+
elasticsearch_unsupported: "Elasticsearch does not support the delete command; for now, use an external tool (e.g. curl or Kibana DevTools) to delete documents"
|
|
1727
1737
|
},
|
|
1728
1738
|
export: {
|
|
1729
1739
|
description: "Export query results",
|
|
@@ -1798,6 +1808,20 @@ Reference: {referencePath}`,
|
|
|
1798
1808
|
add_enum_description: "Create an enum type (PostgreSQL only)",
|
|
1799
1809
|
alter_enum_description: "Add a value to an enum type",
|
|
1800
1810
|
drop_enum_description: "Drop an enum type"
|
|
1811
|
+
},
|
|
1812
|
+
password: {
|
|
1813
|
+
description: "Change the password of a single connection, leaving every other setting untouched",
|
|
1814
|
+
arg_connection: "Connection name (defaults to the current default connection)",
|
|
1815
|
+
opt_stdin: "Read the new password from stdin (for rotation scripts)",
|
|
1816
|
+
opt_password: "New password given inline (visible in shell history and process list)",
|
|
1817
|
+
opt_skip_test: "Skip verifying the new password against the database before saving",
|
|
1818
|
+
prompt: "New password for connection '{name}'",
|
|
1819
|
+
source_conflict: "--password and --stdin cannot be used together; pick one source.",
|
|
1820
|
+
needs_source: "No terminal available for a masked prompt. Pass the value with --stdin or --password.",
|
|
1821
|
+
empty: "The new password is empty; nothing was changed.",
|
|
1822
|
+
updated: "Password for connection '{name}' updated \u2192 {envFile} ({varName})",
|
|
1823
|
+
converted: 'The literal password in config.json was replaced by a {{ "$env": "{varName}" }} reference; later rotations only touch the env file.',
|
|
1824
|
+
skipped_test: "Verification skipped (--skip-test): the new password was not checked against the database."
|
|
1801
1825
|
}
|
|
1802
1826
|
};
|
|
1803
1827
|
// resources/lang/zh-TW/messages.json
|
|
@@ -1959,6 +1983,12 @@ var messages_default2 = {
|
|
|
1959
1983
|
invalid_config: "\u914D\u7F6E\u7121\u6548\uFF1A{field}",
|
|
1960
1984
|
connection_failed: "\u7121\u6CD5\u9023\u63A5\u5230\u8CC7\u6599\u5EAB\uFF1A{message}",
|
|
1961
1985
|
permission_denied: "\u6B0A\u9650\u88AB\u62D2\uFF08\u9700\u8981\uFF1A{required}\uFF09",
|
|
1986
|
+
permission_requires_level: "{type} \u64CD\u4F5C\u9700\u8981 {minimum} \u4EE5\u4E0A\u7684\u6B0A\u9650\uFF08\u76EE\u524D\u5C64\u7D1A\uFF1A{permission}\uFF09",
|
|
1987
|
+
elasticsearch_requires_level: "Elasticsearch {type} \u64CD\u4F5C\u9700\u8981 {minimum} \u4EE5\u4E0A\u7684\u6B0A\u9650\uFF08\u76EE\u524D\u5C64\u7D1A\uFF1A{permission}\uFF09",
|
|
1988
|
+
escalated_write_requires_admin: "\u6B64\u8A9E\u53E5\u8868\u9762\u4E0A\u662F\u8B80\u53D6\uFF0C\u4F46\u5BE6\u969B\u5305\u542B\u53EF\u57F7\u884C\u7684 {keyword}\u3002\u8B80\u53D6\u8A9E\u53E5\u4E2D\u96B1\u85CF\u5BEB\u5165\u64CD\u4F5C\u9700\u8981 admin \u6B0A\u9650\uFF08\u76EE\u524D\u5C64\u7D1A\uFF1A{permission}\uFF09\u3002",
|
|
1989
|
+
multiple_statements_refused: "\u4F4E\u65BC admin \u6B0A\u9650\u6642\u62D2\u7D55\u57F7\u884C\u5305\u542B\u591A\u500B\u8A9E\u53E5\u7684 SQL\uFF0C\u56E0\u70BA\u6B0A\u9650\u6AA2\u67E5\u53EA\u6703\u4F9D\u64DA\u7B2C\u4E00\u500B\u8A9E\u53E5\u5224\u65B7\u3002\u8ACB\u5C07\u5404\u8A9E\u53E5\u5206\u958B\u57F7\u884C\u3002",
|
|
1990
|
+
unknown_statement_query_only: "\u7121\u6CD5\u8FA8\u8B58\u7684 SQL \u8A9E\u53E5\uFF08\u76EE\u524D\u5C64\u7D1A\uFF1Aquery-only\uFF09\u3002\u5B89\u5168\u653F\u7B56\u8981\u6C42\u672A\u77E5\u8A9E\u53E5\u81F3\u5C11\u9700\u8981 read-write \u4EE5\u4E0A\u6B0A\u9650\u3002\u82E5\u9019\u5176\u5BE6\u662F\u5408\u6CD5\u7684\u552F\u8B80\u8A9E\u53E5\uFF0C\u8ACB\u81F3 https://github.com/CarlLee1983/dbcli/issues \u63D0\u51FA\u8B70\u984C\u3002",
|
|
1991
|
+
permission_denied_reason: "\u6B0A\u9650\u88AB\u62D2\uFF1A{reason}",
|
|
1962
1992
|
table_not_found: "\u627E\u4E0D\u5230\u8868\u683C\uFF1A{table}",
|
|
1963
1993
|
unsupported_lang: "\u4E0D\u652F\u63F4\u7684\u8A9E\u8A00 '{lang}'\uFF0C\u4F7F\u7528\u82F1\u6587",
|
|
1964
1994
|
invalid_json: "\u7121\u6548\u7684 JSON\uFF1A{message}",
|
|
@@ -1980,7 +2010,8 @@ var messages_default2 = {
|
|
|
1980
2010
|
\u6216\u4F7F\u7528\u4E92\u52D5\u6A21\u5F0F\uFF1A\u57F7\u884C "dbcli init --use-env-refs"\uFF08\u4E0D\u52A0 --no-interactive\uFF09`,
|
|
1981
2011
|
env_var_not_defined: `\u7121\u6CD5\u6E2C\u8A66\u9023\u7DDA\uFF1A\u74B0\u5883\u8B8A\u6578 {envKey} \u672A\u5B9A\u7FA9\u3002
|
|
1982
2012
|
\u8ACB\u5728 .env \u6216\u74B0\u5883\u8B8A\u6578\u4E2D\u8A2D\u5B9A {envKey}\u3002
|
|
1983
|
-
\u63D0\u793A\uFF1A\u57F7\u884C 'export {envKey}=<value>' \u5F8C\u91CD\u8A66
|
|
2013
|
+
\u63D0\u793A\uFF1A\u57F7\u884C 'export {envKey}=<value>' \u5F8C\u91CD\u8A66`,
|
|
2014
|
+
invalid_output_format: "\u7121\u6CD5\u4F7F\u7528 --format {format}\uFF0C\u8ACB\u4F7F\u7528 text \u6216 json"
|
|
1984
2015
|
},
|
|
1985
2016
|
success: {
|
|
1986
2017
|
inserted: "\u6210\u529F\u63D2\u5165 {count} \u5217",
|
|
@@ -1991,19 +2022,22 @@ var messages_default2 = {
|
|
|
1991
2022
|
insert: {
|
|
1992
2023
|
description: "\u63D2\u5165\u8CC7\u6599\u5230\u8868\u683C",
|
|
1993
2024
|
prompt_data: "\u8F38\u5165\u8981\u63D2\u5165\u7684 JSON \u8CC7\u6599\uFF1A",
|
|
1994
|
-
confirm: "\u5C07 {count} \u5217\u63D2\u5165\u5230 {table}\uFF1F (y/n)\uFF1A"
|
|
2025
|
+
confirm: "\u5C07 {count} \u5217\u63D2\u5165\u5230 {table}\uFF1F (y/n)\uFF1A",
|
|
2026
|
+
elasticsearch_unsupported: "Elasticsearch \u4E0D\u652F\u63F4 insert \u6307\u4EE4\uFF1B\u76EE\u524D\u8ACB\u4F7F\u7528\u5916\u90E8\u5DE5\u5177\uFF08\u5982 curl \u6216 Kibana DevTools\uFF09\u9032\u884C\u6587\u4EF6\u5BEB\u5165"
|
|
1995
2027
|
},
|
|
1996
2028
|
update: {
|
|
1997
2029
|
description: "\u66F4\u65B0\u8868\u683C\u4E2D\u7684\u8CC7\u6599",
|
|
1998
2030
|
prompt_where: "\u8F38\u5165 WHERE \u5B50\u53E5 (\u4F8B\u5982\uFF1Aid=1)\uFF1A",
|
|
1999
2031
|
prompt_set: '\u8F38\u5165 JSON \u66F4\u65B0 (\u4F8B\u5982\uFF1A{"status": "active"})\uFF1A',
|
|
2000
|
-
confirm: "\u66F4\u65B0 {table} \u4E2D\u7684\u5217\uFF1F (y/n)\uFF1A"
|
|
2032
|
+
confirm: "\u66F4\u65B0 {table} \u4E2D\u7684\u5217\uFF1F (y/n)\uFF1A",
|
|
2033
|
+
elasticsearch_unsupported: "Elasticsearch \u4E0D\u652F\u63F4 update \u6307\u4EE4\uFF1B\u76EE\u524D\u8ACB\u4F7F\u7528\u5916\u90E8\u5DE5\u5177\uFF08\u5982 curl \u6216 Kibana DevTools\uFF09\u9032\u884C\u6587\u4EF6\u66F4\u65B0"
|
|
2001
2034
|
},
|
|
2002
2035
|
delete: {
|
|
2003
2036
|
description: "\u522A\u9664\u8868\u683C\u4E2D\u7684\u8CC7\u6599",
|
|
2004
2037
|
prompt_where: "\u8F38\u5165 WHERE \u5B50\u53E5 (\u4F8B\u5982\uFF1Aid=1)\uFF1A",
|
|
2005
2038
|
confirm: "\u522A\u9664 {table} \u4E2D\u7684\u5217\uFF1F (y/n)\uFF1A",
|
|
2006
|
-
admin_only: "\u522A\u9664\u547D\u4EE4\u9700\u8981 data-admin \u6216 admin \u6B0A\u9650"
|
|
2039
|
+
admin_only: "\u522A\u9664\u547D\u4EE4\u9700\u8981 data-admin \u6216 admin \u6B0A\u9650",
|
|
2040
|
+
elasticsearch_unsupported: "Elasticsearch \u4E0D\u652F\u63F4 delete \u6307\u4EE4\uFF1B\u76EE\u524D\u8ACB\u4F7F\u7528\u5916\u90E8\u5DE5\u5177\uFF08\u5982 curl \u6216 Kibana DevTools\uFF09\u9032\u884C\u6587\u4EF6\u522A\u9664"
|
|
2007
2041
|
},
|
|
2008
2042
|
export: {
|
|
2009
2043
|
description: "\u532F\u51FA\u67E5\u8A62\u7D50\u679C",
|
|
@@ -2078,6 +2112,20 @@ var messages_default2 = {
|
|
|
2078
2112
|
add_enum_description: "\u5EFA\u7ACB\u5217\u8209\u578B\u5225\uFF08\u50C5 PostgreSQL\uFF09",
|
|
2079
2113
|
alter_enum_description: "\u65B0\u589E\u5217\u8209\u503C",
|
|
2080
2114
|
drop_enum_description: "\u522A\u9664\u5217\u8209\u578B\u5225"
|
|
2115
|
+
},
|
|
2116
|
+
password: {
|
|
2117
|
+
description: "\u53EA\u8B8A\u66F4\u55AE\u4E00\u9023\u7DDA\u7684\u5BC6\u78BC\uFF0C\u5176\u9918\u8A2D\u5B9A\u539F\u5C01\u4E0D\u52D5",
|
|
2118
|
+
arg_connection: "\u9023\u7DDA\u540D\u7A31\uFF08\u7701\u7565\u6642\u6539\u9810\u8A2D\u9023\u7DDA\uFF09",
|
|
2119
|
+
opt_stdin: "\u5F9E stdin \u8B80\u53D6\u65B0\u5BC6\u78BC\uFF08\u4F9B\u8F2A\u66FF\u8173\u672C\u4F7F\u7528\uFF09",
|
|
2120
|
+
opt_password: "\u76F4\u63A5\u5E36\u5165\u65B0\u5BC6\u78BC\uFF08\u6703\u7559\u5728 shell \u6B77\u53F2\u8207\u884C\u7A0B\u5217\u8868\uFF09",
|
|
2121
|
+
opt_skip_test: "\u5B58\u6A94\u524D\u4E0D\u5148\u7528\u65B0\u5BC6\u78BC\u9023\u7DDA\u9A57\u8B49",
|
|
2122
|
+
prompt: "\u9023\u7DDA '{name}' \u7684\u65B0\u5BC6\u78BC",
|
|
2123
|
+
source_conflict: "--password \u8207 --stdin \u53EA\u80FD\u64C7\u4E00\u3002",
|
|
2124
|
+
needs_source: "\u6C92\u6709\u7D42\u7AEF\u6A5F\u53EF\u505A\u906E\u853D\u8F38\u5165\uFF0C\u8ACB\u6539\u7528 --stdin \u6216 --password \u50B3\u5165\u3002",
|
|
2125
|
+
empty: "\u65B0\u5BC6\u78BC\u662F\u7A7A\u7684\uFF0C\u672A\u505A\u4EFB\u4F55\u8B8A\u66F4\u3002",
|
|
2126
|
+
updated: "\u5DF2\u66F4\u65B0\u9023\u7DDA '{name}' \u7684\u5BC6\u78BC \u2192 {envFile}\uFF08{varName}\uFF09",
|
|
2127
|
+
converted: 'config.json \u88E1\u7684\u660E\u6587\u5BC6\u78BC\u5DF2\u6539\u6210 {{ "$env": "{varName}" }} \u53C3\u7167\uFF0C\u4E4B\u5F8C\u8F2A\u66FF\u53EA\u6703\u52D5 env \u6A94\u3002',
|
|
2128
|
+
skipped_test: "\u5DF2\u8DF3\u904E\u9A57\u8B49\uFF08--skip-test\uFF09\uFF1A\u65B0\u5BC6\u78BC\u672A\u7D93\u8CC7\u6599\u5EAB\u78BA\u8A8D\u3002"
|
|
2081
2129
|
}
|
|
2082
2130
|
};
|
|
2083
2131
|
// resources/lang/en/shell.json
|
|
@@ -2124,11 +2172,61 @@ var shell_default2 = {
|
|
|
2124
2172
|
rows_display: "{count} \u7B46\u8CC7\u6599",
|
|
2125
2173
|
unknown_command: "\u672A\u77E5\u6307\u4EE4\uFF1A'{command}'\u3002\u8F38\u5165 '.help' \u67E5\u770B\u53EF\u7528\u6307\u4EE4\u3002"
|
|
2126
2174
|
};
|
|
2175
|
+
// resources/lang/en/ceremony.json
|
|
2176
|
+
var ceremony_default = {
|
|
2177
|
+
updated: "Updated {count} row(s) in {table}",
|
|
2178
|
+
deleted: "Deleted {count} row(s) from {table}",
|
|
2179
|
+
inserted: "Inserted {count} row(s) into {table}",
|
|
2180
|
+
matched_nothing: "No rows matched in {table} \u2014 nothing changed",
|
|
2181
|
+
cancelled: "Cancelled. {table} was not changed",
|
|
2182
|
+
dry_run: "Preview only. {table} was not changed",
|
|
2183
|
+
elapsed: "Took {seconds}s",
|
|
2184
|
+
failed: "Failed: {reason}",
|
|
2185
|
+
unknown_error: "unknown error",
|
|
2186
|
+
confirm_sql: "Generated SQL:",
|
|
2187
|
+
confirm_command: "Command to run:",
|
|
2188
|
+
confirm_params: "Parameters:",
|
|
2189
|
+
confirm_destructive_warning: "\u26A0\uFE0F Warning: DELETE operation is destructive and cannot be undone!",
|
|
2190
|
+
confirm_destructive_prompt: "Are you sure you want to execute this DELETE operation? This cannot be undone.",
|
|
2191
|
+
confirm_destructive_warning_ddl: "\u26A0\uFE0F Warning: this schema change is destructive and cannot be undone!",
|
|
2192
|
+
confirm_ddl_prompt: "Are you sure you want to run this {operation}? This cannot be undone.",
|
|
2193
|
+
confirm_prompt: "Proceed with this operation?",
|
|
2194
|
+
recovery_none: "This cannot be undone automatically \u2014 restore from a backup to get the previous values back.",
|
|
2195
|
+
recovery_retry: "Re-run with --recovery to write a recovery plan, then read it with: dbcli recover",
|
|
2196
|
+
blacklist_hint: "Run `dbcli blacklist list` to see what is protected"
|
|
2197
|
+
};
|
|
2198
|
+
// resources/lang/zh-TW/ceremony.json
|
|
2199
|
+
var ceremony_default2 = {
|
|
2200
|
+
updated: "\u5DF2\u66F4\u65B0 {table} \u7684 {count} \u5217",
|
|
2201
|
+
deleted: "\u5DF2\u5F9E {table} \u522A\u9664 {count} \u5217",
|
|
2202
|
+
inserted: "\u5DF2\u5BEB\u5165 {count} \u5217\u5230 {table}",
|
|
2203
|
+
matched_nothing: "{table} \u6C92\u6709\u4EFB\u4F55\u5217\u7B26\u5408\u689D\u4EF6\uFF0C\u8CC7\u6599\u672A\u8B8A\u52D5",
|
|
2204
|
+
cancelled: "\u5DF2\u53D6\u6D88\uFF0C{table} \u672A\u8B8A\u52D5",
|
|
2205
|
+
dry_run: "\u50C5\u9810\u89BD\uFF0C{table} \u672A\u8B8A\u52D5",
|
|
2206
|
+
elapsed: "\u8017\u6642 {seconds} \u79D2",
|
|
2207
|
+
failed: "\u5931\u6557\uFF1A{reason}",
|
|
2208
|
+
unknown_error: "\u672A\u77E5\u7684\u932F\u8AA4",
|
|
2209
|
+
confirm_sql: "\u7522\u751F\u7684 SQL\uFF1A",
|
|
2210
|
+
confirm_command: "\u5373\u5C07\u57F7\u884C\u7684\u6307\u4EE4\uFF1A",
|
|
2211
|
+
confirm_params: "\u53C3\u6578\uFF1A",
|
|
2212
|
+
confirm_destructive_warning: "\u26A0\uFE0F \u8B66\u544A\uFF1ADELETE \u5177\u7834\u58DE\u6027\uFF0C\u57F7\u884C\u5F8C\u7121\u6CD5\u5FA9\u539F\uFF01",
|
|
2213
|
+
confirm_destructive_prompt: "\u78BA\u5B9A\u8981\u57F7\u884C\u9019\u500B DELETE \u55CE\uFF1F\u6B64\u64CD\u4F5C\u7121\u6CD5\u5FA9\u539F\u3002",
|
|
2214
|
+
confirm_destructive_warning_ddl: "\u26A0\uFE0F \u8B66\u544A\uFF1A\u9019\u500B schema \u8B8A\u66F4\u5177\u7834\u58DE\u6027\uFF0C\u57F7\u884C\u5F8C\u7121\u6CD5\u5FA9\u539F\uFF01",
|
|
2215
|
+
confirm_ddl_prompt: "\u78BA\u5B9A\u8981\u57F7\u884C\u9019\u500B {operation} \u55CE\uFF1F\u6B64\u64CD\u4F5C\u7121\u6CD5\u5FA9\u539F\u3002",
|
|
2216
|
+
confirm_prompt: "\u8981\u7E7C\u7E8C\u57F7\u884C\u9019\u500B\u64CD\u4F5C\u55CE\uFF1F",
|
|
2217
|
+
recovery_none: "\u6B64\u64CD\u4F5C\u7121\u6CD5\u81EA\u52D5\u9084\u539F\uFF0C\u8981\u53D6\u56DE\u5148\u524D\u7684\u8CC7\u6599\u8ACB\u5F9E\u5099\u4EFD\u56DE\u5FA9\u3002",
|
|
2218
|
+
recovery_retry: "\u52A0\u4E0A --recovery \u91CD\u8DD1\u53EF\u7522\u751F\u56DE\u5FA9\u8A08\u756B\uFF0C\u518D\u7528 dbcli recover \u8B80\u53D6",
|
|
2219
|
+
blacklist_hint: "\u57F7\u884C `dbcli blacklist list` \u67E5\u770B\u53D7\u4FDD\u8B77\u7684\u9805\u76EE"
|
|
2220
|
+
};
|
|
2127
2221
|
|
|
2128
2222
|
// src/i18n/message-loader.ts
|
|
2129
2223
|
var BUNDLED_MESSAGES = {
|
|
2130
|
-
en: { ...messages_default, shell: shell_default },
|
|
2131
|
-
"zh-TW": {
|
|
2224
|
+
en: { ...messages_default, shell: shell_default, ceremony: ceremony_default },
|
|
2225
|
+
"zh-TW": {
|
|
2226
|
+
...messages_default2,
|
|
2227
|
+
shell: shell_default2,
|
|
2228
|
+
ceremony: ceremony_default2
|
|
2229
|
+
}
|
|
2132
2230
|
};
|
|
2133
2231
|
|
|
2134
2232
|
class MessageLoader {
|
|
@@ -2191,6 +2289,7 @@ class MessageLoader {
|
|
|
2191
2289
|
}
|
|
2192
2290
|
}
|
|
2193
2291
|
var messageLoader = MessageLoader.getInstance();
|
|
2292
|
+
var t = (key) => messageLoader.t(key);
|
|
2194
2293
|
var t_vars = (key, vars) => messageLoader.interpolate(key, vars);
|
|
2195
2294
|
|
|
2196
2295
|
// src/utils/colors.ts
|
|
@@ -3268,12 +3367,12 @@ function detectMongoType(v) {
|
|
|
3268
3367
|
function accumulateDocPaths(doc, prefix, acc) {
|
|
3269
3368
|
for (const [k, v] of Object.entries(doc)) {
|
|
3270
3369
|
const path = prefix === "" ? k : `${prefix}.${k}`;
|
|
3271
|
-
const
|
|
3370
|
+
const t2 = detectMongoType(v);
|
|
3272
3371
|
const slot = acc.get(path) ?? { types: new Set, count: 0 };
|
|
3273
|
-
slot.types.add(
|
|
3372
|
+
slot.types.add(t2);
|
|
3274
3373
|
slot.count += 1;
|
|
3275
3374
|
acc.set(path, slot);
|
|
3276
|
-
if (
|
|
3375
|
+
if (t2 === "object" && v && typeof v === "object") {
|
|
3277
3376
|
accumulateDocPaths(v, path, acc);
|
|
3278
3377
|
}
|
|
3279
3378
|
}
|
|
@@ -4784,18 +4883,7 @@ function continuesIdentifier(sql, index) {
|
|
|
4784
4883
|
return run.replace(/^[0-9]+(?:[eE][0-9]+)?/, "").length > 0;
|
|
4785
4884
|
}
|
|
4786
4885
|
|
|
4787
|
-
// src/core/permission-
|
|
4788
|
-
class PermissionError extends Error {
|
|
4789
|
-
classification;
|
|
4790
|
-
requiredPermission;
|
|
4791
|
-
constructor(message, classification, requiredPermission) {
|
|
4792
|
-
super(message);
|
|
4793
|
-
this.classification = classification;
|
|
4794
|
-
this.requiredPermission = requiredPermission;
|
|
4795
|
-
this.name = "PermissionError";
|
|
4796
|
-
Object.setPrototypeOf(this, PermissionError.prototype);
|
|
4797
|
-
}
|
|
4798
|
-
}
|
|
4886
|
+
// src/core/permission/sql-analysis.ts
|
|
4799
4887
|
function normalizeSQL(sql) {
|
|
4800
4888
|
return sql.replace(/--[^\n]*\n/g, `
|
|
4801
4889
|
`).replace(/\/\*[\s\S]*?\*\//g, " ").trim().replace(/\s+/g, " ");
|
|
@@ -5042,6 +5130,19 @@ function determineConfidence(type, _keyword, _sql) {
|
|
|
5042
5130
|
function removeParameterMarkers(sql) {
|
|
5043
5131
|
return sql.replace(/\$\d+/g, "").replace(/\?/g, "");
|
|
5044
5132
|
}
|
|
5133
|
+
|
|
5134
|
+
// src/core/permission-guard.ts
|
|
5135
|
+
class PermissionError extends Error {
|
|
5136
|
+
classification;
|
|
5137
|
+
requiredPermission;
|
|
5138
|
+
constructor(message, classification, requiredPermission) {
|
|
5139
|
+
super(message);
|
|
5140
|
+
this.classification = classification;
|
|
5141
|
+
this.requiredPermission = requiredPermission;
|
|
5142
|
+
this.name = "PermissionError";
|
|
5143
|
+
Object.setPrototypeOf(this, PermissionError.prototype);
|
|
5144
|
+
}
|
|
5145
|
+
}
|
|
5045
5146
|
function classifyStatement(sql) {
|
|
5046
5147
|
const normalized = normalizeSQL(sql);
|
|
5047
5148
|
const stripped = stripCommentsAndStrings(normalized);
|
|
@@ -5108,15 +5209,38 @@ function checkPermission(sql, permission, dialect) {
|
|
|
5108
5209
|
if (permission !== "admin" && containsMultipleStatements(sql, dialect)) {
|
|
5109
5210
|
return {
|
|
5110
5211
|
allowed: false,
|
|
5111
|
-
reason: "
|
|
5112
|
-
classification
|
|
5212
|
+
reason: t("errors.multiple_statements_refused"),
|
|
5213
|
+
classification,
|
|
5214
|
+
requiredPermission: "admin"
|
|
5113
5215
|
};
|
|
5114
5216
|
}
|
|
5217
|
+
return checkPermissionForClassification(classification, permission);
|
|
5218
|
+
}
|
|
5219
|
+
var TIER_GRANTS = [
|
|
5220
|
+
{ permission: "query-only", types: ["SELECT", "SHOW", "DESCRIBE", "EXPLAIN"] },
|
|
5221
|
+
{ permission: "read-write", types: ["INSERT", "UPDATE"] },
|
|
5222
|
+
{ permission: "data-admin", types: ["DELETE"] }
|
|
5223
|
+
];
|
|
5224
|
+
function minimumPermissionFor(type) {
|
|
5225
|
+
return TIER_GRANTS.find((tier) => tier.types.includes(type))?.permission ?? "admin";
|
|
5226
|
+
}
|
|
5227
|
+
function refusalReason(type, permission) {
|
|
5228
|
+
return t_vars("errors.permission_requires_level", {
|
|
5229
|
+
type,
|
|
5230
|
+
minimum: minimumPermissionFor(type),
|
|
5231
|
+
permission
|
|
5232
|
+
});
|
|
5233
|
+
}
|
|
5234
|
+
function checkPermissionForClassification(classification, permission) {
|
|
5115
5235
|
if (permission !== "admin" && classification.escalatedFrom) {
|
|
5116
5236
|
return {
|
|
5117
5237
|
allowed: false,
|
|
5118
|
-
reason:
|
|
5119
|
-
|
|
5238
|
+
reason: t_vars("errors.escalated_write_requires_admin", {
|
|
5239
|
+
keyword: classification.escalatedFrom,
|
|
5240
|
+
permission
|
|
5241
|
+
}),
|
|
5242
|
+
classification,
|
|
5243
|
+
requiredPermission: "admin"
|
|
5120
5244
|
};
|
|
5121
5245
|
}
|
|
5122
5246
|
if (permission === "admin") {
|
|
@@ -5126,62 +5250,51 @@ function checkPermission(sql, permission, dialect) {
|
|
|
5126
5250
|
classification
|
|
5127
5251
|
};
|
|
5128
5252
|
}
|
|
5129
|
-
|
|
5130
|
-
|
|
5131
|
-
|
|
5132
|
-
return {
|
|
5133
|
-
allowed: true,
|
|
5134
|
-
reason: `${classification.type} operation allowed in data-admin mode`,
|
|
5135
|
-
classification
|
|
5136
|
-
};
|
|
5137
|
-
}
|
|
5138
|
-
return {
|
|
5139
|
-
allowed: false,
|
|
5140
|
-
reason: `${classification.type} operation requires admin permission`,
|
|
5141
|
-
classification
|
|
5142
|
-
};
|
|
5143
|
-
}
|
|
5144
|
-
if (permission === "read-write") {
|
|
5145
|
-
const allowedTypes = ["SELECT", "INSERT", "UPDATE", "SHOW", "DESCRIBE", "EXPLAIN"];
|
|
5146
|
-
if (allowedTypes.includes(classification.type)) {
|
|
5147
|
-
return {
|
|
5148
|
-
allowed: true,
|
|
5149
|
-
reason: `${classification.type} operation allowed in read-write mode`,
|
|
5150
|
-
classification
|
|
5151
|
-
};
|
|
5152
|
-
}
|
|
5153
|
-
return {
|
|
5154
|
-
allowed: false,
|
|
5155
|
-
reason: `${classification.type} operation requires data-admin or admin permission`,
|
|
5156
|
-
classification
|
|
5157
|
-
};
|
|
5158
|
-
}
|
|
5159
|
-
if (permission === "query-only") {
|
|
5160
|
-
const allowedTypes = ["SELECT", "SHOW", "DESCRIBE", "EXPLAIN"];
|
|
5253
|
+
const tierIndex = TIER_GRANTS.findIndex((tier) => tier.permission === permission);
|
|
5254
|
+
if (tierIndex !== -1) {
|
|
5255
|
+
const allowedTypes = TIER_GRANTS.slice(0, tierIndex + 1).flatMap((tier) => tier.types);
|
|
5161
5256
|
if (allowedTypes.includes(classification.type)) {
|
|
5162
5257
|
return {
|
|
5163
5258
|
allowed: true,
|
|
5164
|
-
reason: `${classification.type} operation allowed in
|
|
5259
|
+
reason: `${classification.type} operation allowed in ${permission} mode`,
|
|
5165
5260
|
classification
|
|
5166
5261
|
};
|
|
5167
5262
|
}
|
|
5168
|
-
const isUnknown = classification.type === "UNKNOWN";
|
|
5263
|
+
const isUnknown = permission === "query-only" && classification.type === "UNKNOWN";
|
|
5169
5264
|
return {
|
|
5170
5265
|
allowed: false,
|
|
5171
|
-
reason: isUnknown ?
|
|
5172
|
-
classification
|
|
5266
|
+
reason: isUnknown ? t("errors.unknown_statement_query_only") : refusalReason(classification.type, permission),
|
|
5267
|
+
classification,
|
|
5268
|
+
requiredPermission: isUnknown ? "read-write" : minimumPermissionFor(classification.type)
|
|
5173
5269
|
};
|
|
5174
5270
|
}
|
|
5175
5271
|
return {
|
|
5176
5272
|
allowed: false,
|
|
5177
5273
|
reason: `Unknown permission level: ${permission}`,
|
|
5178
|
-
classification
|
|
5274
|
+
classification,
|
|
5275
|
+
requiredPermission: "admin"
|
|
5276
|
+
};
|
|
5277
|
+
}
|
|
5278
|
+
function classificationForType(type) {
|
|
5279
|
+
return {
|
|
5280
|
+
type,
|
|
5281
|
+
isDangerous: isDestructiveOperation(type),
|
|
5282
|
+
keywords: [type],
|
|
5283
|
+
isComposite: false,
|
|
5284
|
+
confidence: "HIGH"
|
|
5179
5285
|
};
|
|
5180
5286
|
}
|
|
5287
|
+
function enforcePermissionForType(type, permission) {
|
|
5288
|
+
const classification = classificationForType(type);
|
|
5289
|
+
const result = checkPermissionForClassification(classification, permission);
|
|
5290
|
+
if (!result.allowed) {
|
|
5291
|
+
throw new PermissionError(result.reason, classification, minimumPermissionFor(type));
|
|
5292
|
+
}
|
|
5293
|
+
}
|
|
5181
5294
|
function enforcePermission(sql, permission, dialect) {
|
|
5182
5295
|
const result = checkPermission(sql, permission, dialect);
|
|
5183
5296
|
if (!result.allowed) {
|
|
5184
|
-
throw new PermissionError(result.reason, result.classification,
|
|
5297
|
+
throw new PermissionError(result.reason, result.classification, result.requiredPermission ?? "admin");
|
|
5185
5298
|
}
|
|
5186
5299
|
return result.classification;
|
|
5187
5300
|
}
|
|
@@ -5285,7 +5398,7 @@ function extractTableNameFromError(errorMessage) {
|
|
|
5285
5398
|
async function getAllTablesFromAdapter(adapter) {
|
|
5286
5399
|
try {
|
|
5287
5400
|
const tables = await adapter.listTables();
|
|
5288
|
-
return tables.map((
|
|
5401
|
+
return tables.map((t2) => t2.name);
|
|
5289
5402
|
} catch (error) {
|
|
5290
5403
|
console.warn("Failed to list tables for suggestions:", error);
|
|
5291
5404
|
return [];
|
|
@@ -5937,100 +6050,6 @@ function inferColumnType(value) {
|
|
|
5937
6050
|
}
|
|
5938
6051
|
return "unknown";
|
|
5939
6052
|
}
|
|
5940
|
-
// src/utils/prompts.ts
|
|
5941
|
-
var promptsUnavailableReported = false;
|
|
5942
|
-
async function loadInquirer() {
|
|
5943
|
-
try {
|
|
5944
|
-
return await import("@inquirer/prompts");
|
|
5945
|
-
} catch (error) {
|
|
5946
|
-
if (!promptsUnavailableReported) {
|
|
5947
|
-
promptsUnavailableReported = true;
|
|
5948
|
-
const reason = error instanceof Error ? error.message : String(error);
|
|
5949
|
-
process.stderr.write(`[dbcli] rich interactive prompts are unavailable (${reason}); falling back to plain-text input
|
|
5950
|
-
`);
|
|
5951
|
-
}
|
|
5952
|
-
return;
|
|
5953
|
-
}
|
|
5954
|
-
}
|
|
5955
|
-
async function readLineFromStdin(prompt = "") {
|
|
5956
|
-
return new Promise((resolve) => {
|
|
5957
|
-
if (prompt) {
|
|
5958
|
-
process.stdout.write(prompt);
|
|
5959
|
-
}
|
|
5960
|
-
let data = "";
|
|
5961
|
-
const chunks = [];
|
|
5962
|
-
const onData = (chunk) => {
|
|
5963
|
-
chunks.push(chunk);
|
|
5964
|
-
data = Buffer.concat(chunks).toString();
|
|
5965
|
-
const lines = data.split(`
|
|
5966
|
-
`);
|
|
5967
|
-
if (lines.length > 1) {
|
|
5968
|
-
process.stdin.pause();
|
|
5969
|
-
process.stdin.removeListener("data", onData);
|
|
5970
|
-
process.stdin.removeListener("end", onEnd);
|
|
5971
|
-
resolve((lines[0] ?? "").trim());
|
|
5972
|
-
}
|
|
5973
|
-
};
|
|
5974
|
-
const onEnd = () => {
|
|
5975
|
-
process.stdin.removeListener("data", onData);
|
|
5976
|
-
resolve(data.trim());
|
|
5977
|
-
};
|
|
5978
|
-
process.stdin.on("data", onData);
|
|
5979
|
-
process.stdin.on("end", onEnd);
|
|
5980
|
-
process.stdin.resume();
|
|
5981
|
-
});
|
|
5982
|
-
}
|
|
5983
|
-
async function textFallback(message, defaultValue) {
|
|
5984
|
-
const displayMessage = defaultValue ? `${message} [${defaultValue}]: ` : `${message}: `;
|
|
5985
|
-
const answer = await readLineFromStdin(displayMessage);
|
|
5986
|
-
return answer.trim() || defaultValue || "";
|
|
5987
|
-
}
|
|
5988
|
-
async function selectFallback(message, choices) {
|
|
5989
|
-
console.log(message);
|
|
5990
|
-
choices.forEach((choice, index) => {
|
|
5991
|
-
console.log(` ${index + 1}) ${choice}`);
|
|
5992
|
-
});
|
|
5993
|
-
const answer = await readLineFromStdin("Select option (number): ");
|
|
5994
|
-
const selectedIndex = parseInt(answer, 10) - 1;
|
|
5995
|
-
if (selectedIndex >= 0 && selectedIndex < choices.length) {
|
|
5996
|
-
return choices[selectedIndex] ?? choices[0] ?? "";
|
|
5997
|
-
}
|
|
5998
|
-
return choices[0] ?? "";
|
|
5999
|
-
}
|
|
6000
|
-
async function confirmFallback(message) {
|
|
6001
|
-
const answer = await readLineFromStdin(`${message} (y/n): `);
|
|
6002
|
-
return answer.toLowerCase() === "y" || answer.toLowerCase() === "yes";
|
|
6003
|
-
}
|
|
6004
|
-
async function text(message, defaultValue) {
|
|
6005
|
-
if (!process.stdin.isTTY)
|
|
6006
|
-
return textFallback(message, defaultValue);
|
|
6007
|
-
const inquirer = await loadInquirer();
|
|
6008
|
-
if (!inquirer)
|
|
6009
|
-
return textFallback(message, defaultValue);
|
|
6010
|
-
return await inquirer.input({ message, default: defaultValue });
|
|
6011
|
-
}
|
|
6012
|
-
async function select(message, choices) {
|
|
6013
|
-
if (!process.stdin.isTTY)
|
|
6014
|
-
return await selectFallback(message, choices);
|
|
6015
|
-
const inquirer = await loadInquirer();
|
|
6016
|
-
if (!inquirer)
|
|
6017
|
-
return await selectFallback(message, choices);
|
|
6018
|
-
return await inquirer.select({ message, choices });
|
|
6019
|
-
}
|
|
6020
|
-
async function confirm(message) {
|
|
6021
|
-
if (!process.stdin.isTTY)
|
|
6022
|
-
return await confirmFallback(message);
|
|
6023
|
-
const inquirer = await loadInquirer();
|
|
6024
|
-
if (!inquirer)
|
|
6025
|
-
return await confirmFallback(message);
|
|
6026
|
-
return await inquirer.confirm({ message });
|
|
6027
|
-
}
|
|
6028
|
-
var promptUser = {
|
|
6029
|
-
text,
|
|
6030
|
-
select,
|
|
6031
|
-
confirm
|
|
6032
|
-
};
|
|
6033
|
-
|
|
6034
6053
|
// src/types/blacklist.ts
|
|
6035
6054
|
class BlacklistError extends Error {
|
|
6036
6055
|
tableName;
|
|
@@ -6078,8 +6097,8 @@ class DataExecutor {
|
|
|
6078
6097
|
const timestamp = new Date().toISOString();
|
|
6079
6098
|
try {
|
|
6080
6099
|
this.checkBlacklist("INSERT", tableName);
|
|
6081
|
-
|
|
6082
|
-
return await this.executeMutation("insert", this.buildInsertSql(tableName, data, schema), timestamp, options, {
|
|
6100
|
+
enforcePermissionForType("INSERT", this.permission);
|
|
6101
|
+
return await this.executeMutation("insert", this.buildInsertSql(tableName, data, schema), timestamp, options, { destructive: false });
|
|
6083
6102
|
} catch (error) {
|
|
6084
6103
|
return this.handleMutationError("insert", timestamp, error);
|
|
6085
6104
|
}
|
|
@@ -6088,8 +6107,8 @@ class DataExecutor {
|
|
|
6088
6107
|
const timestamp = new Date().toISOString();
|
|
6089
6108
|
try {
|
|
6090
6109
|
this.checkBlacklist("UPDATE", tableName);
|
|
6091
|
-
|
|
6092
|
-
return await this.executeMutation("update", this.buildUpdateSql(tableName, data, where, schema), timestamp, options, {
|
|
6110
|
+
enforcePermissionForType("UPDATE", this.permission);
|
|
6111
|
+
return await this.executeMutation("update", this.buildUpdateSql(tableName, data, where, schema), timestamp, options, { destructive: false });
|
|
6093
6112
|
} catch (error) {
|
|
6094
6113
|
return this.handleMutationError("update", timestamp, error);
|
|
6095
6114
|
}
|
|
@@ -6098,19 +6117,8 @@ class DataExecutor {
|
|
|
6098
6117
|
const timestamp = new Date().toISOString();
|
|
6099
6118
|
try {
|
|
6100
6119
|
this.checkBlacklist("DELETE", tableName);
|
|
6101
|
-
|
|
6102
|
-
|
|
6103
|
-
status: "error",
|
|
6104
|
-
operation: "delete",
|
|
6105
|
-
rows_affected: 0,
|
|
6106
|
-
timestamp,
|
|
6107
|
-
error: "Permission denied: DELETE operation requires Data-Admin or Admin permission."
|
|
6108
|
-
};
|
|
6109
|
-
}
|
|
6110
|
-
return await this.executeMutation("delete", this.buildDeleteSql(tableName, where, schema), timestamp, options, {
|
|
6111
|
-
warning: "\u26A0\uFE0F Warning: DELETE operation is destructive and cannot be undone!",
|
|
6112
|
-
prompt: "Are you sure you want to execute this DELETE operation? This cannot be undone."
|
|
6113
|
-
});
|
|
6120
|
+
enforcePermissionForType("DELETE", this.permission);
|
|
6121
|
+
return await this.executeMutation("delete", this.buildDeleteSql(tableName, where, schema), timestamp, options, { destructive: true });
|
|
6114
6122
|
} catch (error) {
|
|
6115
6123
|
return this.handleMutationError("delete", timestamp, error);
|
|
6116
6124
|
}
|
|
@@ -6124,31 +6132,31 @@ class DataExecutor {
|
|
|
6124
6132
|
checkBlacklist(operation, tableName) {
|
|
6125
6133
|
this.blacklistValidator?.checkTableBlacklist(operation, tableName, []);
|
|
6126
6134
|
}
|
|
6127
|
-
async executeMutation(operation, statement, timestamp, options,
|
|
6135
|
+
async executeMutation(operation, statement, timestamp, options, { destructive }) {
|
|
6128
6136
|
if (options?.dryRun) {
|
|
6129
|
-
return this.
|
|
6137
|
+
return this.outcomeResult("dry_run", operation, 0, timestamp, statement.sql);
|
|
6130
6138
|
}
|
|
6131
6139
|
if (!options?.force) {
|
|
6132
|
-
if (
|
|
6133
|
-
|
|
6134
|
-
${confirmation.warning}`);
|
|
6140
|
+
if (!options?.confirm) {
|
|
6141
|
+
throw new Error(`Refusing to ${operation} without confirmation: no confirmation handler was supplied. ` + "Pass options.confirm to ask the user, or options.force to proceed unattended.");
|
|
6135
6142
|
}
|
|
6136
|
-
|
|
6137
|
-
|
|
6138
|
-
|
|
6139
|
-
|
|
6140
|
-
|
|
6141
|
-
|
|
6142
|
-
|
|
6143
|
-
|
|
6143
|
+
const proceed = await options.confirm({
|
|
6144
|
+
operation,
|
|
6145
|
+
engine: "sql",
|
|
6146
|
+
sql: statement.sql,
|
|
6147
|
+
params: statement.params,
|
|
6148
|
+
destructive
|
|
6149
|
+
});
|
|
6150
|
+
if (!proceed) {
|
|
6151
|
+
return this.outcomeResult("cancelled", operation, 0, timestamp, statement.sql);
|
|
6144
6152
|
}
|
|
6145
6153
|
}
|
|
6146
6154
|
const result = await this.adapter.execute(statement.sql, statement.params);
|
|
6147
|
-
return this.
|
|
6155
|
+
return this.outcomeResult("success", operation, result.affectedRows, timestamp, statement.sql);
|
|
6148
6156
|
}
|
|
6149
|
-
|
|
6157
|
+
outcomeResult(status, operation, rowsAffected, timestamp, sql) {
|
|
6150
6158
|
return {
|
|
6151
|
-
status
|
|
6159
|
+
status,
|
|
6152
6160
|
operation,
|
|
6153
6161
|
rows_affected: rowsAffected,
|
|
6154
6162
|
timestamp,
|
|
@@ -6159,13 +6167,13 @@ Parameters:`);
|
|
|
6159
6167
|
if (error instanceof BlacklistError) {
|
|
6160
6168
|
throw error;
|
|
6161
6169
|
}
|
|
6162
|
-
if (error instanceof PermissionError
|
|
6170
|
+
if (error instanceof PermissionError) {
|
|
6163
6171
|
return {
|
|
6164
6172
|
status: "error",
|
|
6165
6173
|
operation,
|
|
6166
6174
|
rows_affected: 0,
|
|
6167
6175
|
timestamp,
|
|
6168
|
-
error:
|
|
6176
|
+
error: t_vars("errors.permission_denied_reason", { reason: error.message })
|
|
6169
6177
|
};
|
|
6170
6178
|
}
|
|
6171
6179
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
@@ -6427,8 +6435,8 @@ var ZodParsedType = util.arrayToEnum([
|
|
|
6427
6435
|
"set"
|
|
6428
6436
|
]);
|
|
6429
6437
|
var getParsedType = (data) => {
|
|
6430
|
-
const
|
|
6431
|
-
switch (
|
|
6438
|
+
const t2 = typeof data;
|
|
6439
|
+
switch (t2) {
|
|
6432
6440
|
case "undefined":
|
|
6433
6441
|
return ZodParsedType.undefined;
|
|
6434
6442
|
case "string":
|
|
@@ -10755,43 +10763,11 @@ function listConnections(config) {
|
|
|
10755
10763
|
});
|
|
10756
10764
|
}
|
|
10757
10765
|
// src/core/config-v2-mutations.ts
|
|
10758
|
-
import { join as join8 } from "path";
|
|
10759
10766
|
var SQL_SYSTEMS = ["postgresql", "mysql", "mariadb"];
|
|
10760
10767
|
function envVarNameFor(connName, field) {
|
|
10761
10768
|
const slug = connName.toUpperCase().replace(/[^A-Z0-9]+/g, "_").replace(/^_+|_+$/g, "");
|
|
10762
10769
|
return `DBCLI_${slug}_${field.toUpperCase()}`;
|
|
10763
10770
|
}
|
|
10764
|
-
async function writeConnectionSecret(projectPath, connName, field, value) {
|
|
10765
|
-
assertConfigMutationApproved();
|
|
10766
|
-
if (value.includes(`
|
|
10767
|
-
`) || value.includes("\r")) {
|
|
10768
|
-
throw new Error("secret value \u4E0D\u53EF\u5305\u542B\u63DB\u884C\u5B57\u5143");
|
|
10769
|
-
}
|
|
10770
|
-
const config = await readV2Config(projectPath);
|
|
10771
|
-
const conn = config.connections[connName];
|
|
10772
|
-
if (!conn)
|
|
10773
|
-
throw new Error(`\u9023\u7DDA '${connName}' \u4E0D\u5B58\u5728`);
|
|
10774
|
-
const storagePath = await resolveConfigStoragePath(projectPath);
|
|
10775
|
-
const envFile = conn.envFile ?? `.env.${connName}`;
|
|
10776
|
-
const envPath = join8(storagePath, envFile);
|
|
10777
|
-
const varName = envVarNameFor(connName, field);
|
|
10778
|
-
let content = "";
|
|
10779
|
-
const file = Bun.file(envPath);
|
|
10780
|
-
if (await file.exists())
|
|
10781
|
-
content = await file.text();
|
|
10782
|
-
const line = `${varName}=${value}`;
|
|
10783
|
-
const re = new RegExp(`^${varName}=.*$`, "m");
|
|
10784
|
-
if (re.test(content)) {
|
|
10785
|
-
content = content.replace(re, line);
|
|
10786
|
-
} else {
|
|
10787
|
-
content = content.length && !content.endsWith(`
|
|
10788
|
-
`) ? `${content}
|
|
10789
|
-
${line}
|
|
10790
|
-
` : `${content}${line}
|
|
10791
|
-
`;
|
|
10792
|
-
}
|
|
10793
|
-
await Bun.write(envPath, content);
|
|
10794
|
-
}
|
|
10795
10771
|
function removeConnection(config, name) {
|
|
10796
10772
|
if (!(name in config.connections))
|
|
10797
10773
|
throw new Error(`\u9023\u7DDA '${name}' \u4E0D\u5B58\u5728`);
|
|
@@ -10853,6 +10829,135 @@ function upsertConnection(config, input) {
|
|
|
10853
10829
|
connections: { ...config.connections, [input.name]: connection }
|
|
10854
10830
|
};
|
|
10855
10831
|
}
|
|
10832
|
+
// src/core/connection-credential.ts
|
|
10833
|
+
import { join as join8 } from "path";
|
|
10834
|
+
|
|
10835
|
+
// src/core/env-file-writer.ts
|
|
10836
|
+
import { chmod as chmod2, mkdir as mkdir3, readFile as readFile2, writeFile } from "fs/promises";
|
|
10837
|
+
import { dirname as dirname2 } from "path";
|
|
10838
|
+
var SECRET_FILE_MODE = 384;
|
|
10839
|
+
function escapeForRegExp(value) {
|
|
10840
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
10841
|
+
}
|
|
10842
|
+
async function upsertEnvVar(envPath, varName, value) {
|
|
10843
|
+
let content = "";
|
|
10844
|
+
try {
|
|
10845
|
+
content = await readFile2(envPath, "utf8");
|
|
10846
|
+
} catch (cause) {
|
|
10847
|
+
const code = cause.code;
|
|
10848
|
+
if (code !== "ENOENT")
|
|
10849
|
+
throw cause;
|
|
10850
|
+
await mkdir3(dirname2(envPath), { recursive: true });
|
|
10851
|
+
}
|
|
10852
|
+
const line = `${varName}="${value}"`;
|
|
10853
|
+
const existing = new RegExp(`^${escapeForRegExp(varName)}=.*$`, "m");
|
|
10854
|
+
if (existing.test(content)) {
|
|
10855
|
+
content = content.replace(existing, () => line);
|
|
10856
|
+
} else {
|
|
10857
|
+
content = content.length && !content.endsWith(`
|
|
10858
|
+
`) ? `${content}
|
|
10859
|
+
${line}
|
|
10860
|
+
` : `${content}${line}
|
|
10861
|
+
`;
|
|
10862
|
+
}
|
|
10863
|
+
await writeFile(envPath, content, { mode: SECRET_FILE_MODE });
|
|
10864
|
+
await chmod2(envPath, SECRET_FILE_MODE);
|
|
10865
|
+
}
|
|
10866
|
+
|
|
10867
|
+
// src/core/connection-credential.ts
|
|
10868
|
+
var DEFAULT_ENV_FILE = ".env.local";
|
|
10869
|
+
var V1_VAR_NAME = "DBCLI_PASSWORD";
|
|
10870
|
+
var V1_CONNECTION_NAME = "default";
|
|
10871
|
+
async function readRawConfig(storagePath) {
|
|
10872
|
+
const configPath = join8(storagePath, "config.json");
|
|
10873
|
+
const file = Bun.file(configPath);
|
|
10874
|
+
if (!await file.exists()) {
|
|
10875
|
+
throw new ConfigError(`\u627E\u4E0D\u5230\u8A2D\u5B9A\u6A94\uFF1A${configPath}`);
|
|
10876
|
+
}
|
|
10877
|
+
return JSON.parse(await file.text());
|
|
10878
|
+
}
|
|
10879
|
+
function envRefName(value) {
|
|
10880
|
+
if (typeof value === "object" && value !== null && "$env" in value) {
|
|
10881
|
+
return String(value.$env);
|
|
10882
|
+
}
|
|
10883
|
+
return;
|
|
10884
|
+
}
|
|
10885
|
+
async function resolvePasswordTarget(projectPath, connectionName) {
|
|
10886
|
+
const storagePath = await resolveConfigStoragePath(projectPath);
|
|
10887
|
+
const raw = await readRawConfig(storagePath);
|
|
10888
|
+
if (detectConfigVersion(raw) !== 2) {
|
|
10889
|
+
if (connectionName && connectionName !== V1_CONNECTION_NAME) {
|
|
10890
|
+
throw new ConfigError(`\u9019\u662F v1 \u8A2D\u5B9A\uFF0C\u53EA\u6709\u4E00\u689D\u9023\u7DDA\uFF0C\u7121\u6CD5\u6307\u5B9A\u9023\u7DDA\u540D\u7A31 '${connectionName}'\u3002` + `\u9700\u8981\u591A\u9023\u7DDA\u8ACB\u5148\u7528 dbcli init --conn-name <name> \u5347\u7D1A\u5230 v2\u3002`);
|
|
10891
|
+
}
|
|
10892
|
+
const connection2 = raw.connection ?? {};
|
|
10893
|
+
const customRef = envRefName(connection2.password);
|
|
10894
|
+
if (customRef !== undefined && customRef !== V1_VAR_NAME) {
|
|
10895
|
+
throw new ConfigError(`\u9019\u500B v1 \u8A2D\u5B9A\u7684\u5BC6\u78BC\u4F86\u81EA\u74B0\u5883\u8B8A\u6578 '${customRef}'\uFF0Cdbcli \u7121\u6CD5\u4EE3\u70BA\u8F2A\u66FF\u3002` + `\u8ACB\u76F4\u63A5\u66F4\u65B0\u8A72\u74B0\u5883\u8B8A\u6578\uFF0C\u6216\u7528 dbcli init --conn-name <name> \u5347\u7D1A\u5230 v2 \u5F8C\u518D\u8F2A\u66FF\u3002`);
|
|
10896
|
+
}
|
|
10897
|
+
return {
|
|
10898
|
+
connection: V1_CONNECTION_NAME,
|
|
10899
|
+
envFile: DEFAULT_ENV_FILE,
|
|
10900
|
+
varName: V1_VAR_NAME,
|
|
10901
|
+
convertedToEnvRef: false
|
|
10902
|
+
};
|
|
10903
|
+
}
|
|
10904
|
+
const config = await readV2Config(projectPath);
|
|
10905
|
+
const targetName = connectionName ?? config.default;
|
|
10906
|
+
const connection = config.connections[targetName];
|
|
10907
|
+
if (!connection) {
|
|
10908
|
+
throw new ConfigError(connectionNotFoundMessage(targetName, Object.keys(config.connections)));
|
|
10909
|
+
}
|
|
10910
|
+
const referencedVar = envRefName(connection.password);
|
|
10911
|
+
return {
|
|
10912
|
+
connection: targetName,
|
|
10913
|
+
envFile: connection.envFile ?? DEFAULT_ENV_FILE,
|
|
10914
|
+
varName: referencedVar ?? envVarNameFor(targetName, "password"),
|
|
10915
|
+
convertedToEnvRef: referencedVar === undefined
|
|
10916
|
+
};
|
|
10917
|
+
}
|
|
10918
|
+
function assertSingleLine(value) {
|
|
10919
|
+
if (value.includes(`
|
|
10920
|
+
`) || value.includes("\r")) {
|
|
10921
|
+
throw new ConfigError("\u5BC6\u78BC\u4E0D\u53EF\u5305\u542B\u63DB\u884C\u5B57\u5143");
|
|
10922
|
+
}
|
|
10923
|
+
}
|
|
10924
|
+
async function stripV1LiteralPassword(storagePath, raw) {
|
|
10925
|
+
const connection = raw.connection ?? {};
|
|
10926
|
+
if (typeof connection.password !== "string")
|
|
10927
|
+
return;
|
|
10928
|
+
const stripped = { ...raw, connection: { ...connection } };
|
|
10929
|
+
delete stripped.connection.password;
|
|
10930
|
+
await writeConfigWithIntegrity(storagePath, JSON.stringify(stripped, null, 2));
|
|
10931
|
+
}
|
|
10932
|
+
async function setConnectionPassword(projectPath, connectionName, password) {
|
|
10933
|
+
assertConfigMutationApproved();
|
|
10934
|
+
assertSingleLine(password);
|
|
10935
|
+
const target = await resolvePasswordTarget(projectPath, connectionName);
|
|
10936
|
+
const storagePath = await resolveConfigStoragePath(projectPath);
|
|
10937
|
+
const raw = await readRawConfig(storagePath);
|
|
10938
|
+
await upsertEnvVar(join8(storagePath, target.envFile), target.varName, password);
|
|
10939
|
+
if (detectConfigVersion(raw) !== 2) {
|
|
10940
|
+
await stripV1LiteralPassword(storagePath, raw);
|
|
10941
|
+
return target;
|
|
10942
|
+
}
|
|
10943
|
+
const config = await readV2Config(projectPath);
|
|
10944
|
+
const connection = config.connections[target.connection];
|
|
10945
|
+
const needsEnvFile = connection.envFile === undefined;
|
|
10946
|
+
if (target.convertedToEnvRef || needsEnvFile) {
|
|
10947
|
+
await writeV2Config(projectPath, {
|
|
10948
|
+
...config,
|
|
10949
|
+
connections: {
|
|
10950
|
+
...config.connections,
|
|
10951
|
+
[target.connection]: {
|
|
10952
|
+
...connection,
|
|
10953
|
+
envFile: target.envFile,
|
|
10954
|
+
...target.convertedToEnvRef && { password: { $env: target.varName } }
|
|
10955
|
+
}
|
|
10956
|
+
}
|
|
10957
|
+
});
|
|
10958
|
+
}
|
|
10959
|
+
return target;
|
|
10960
|
+
}
|
|
10856
10961
|
// src/utils/config-error-format.ts
|
|
10857
10962
|
var SUPPORTED_SYSTEMS = [
|
|
10858
10963
|
"postgresql",
|
|
@@ -10938,7 +11043,7 @@ function isZodError(error) {
|
|
|
10938
11043
|
|
|
10939
11044
|
// src/core/config.ts
|
|
10940
11045
|
import { join as join9 } from "path";
|
|
10941
|
-
import { mkdir as
|
|
11046
|
+
import { mkdir as mkdir4 } from "fs/promises";
|
|
10942
11047
|
// src/agent-core/env-ref.ts
|
|
10943
11048
|
function resolveEnvRef(value, fieldName, env = process.env) {
|
|
10944
11049
|
if (typeof value === "string")
|
|
@@ -11008,7 +11113,11 @@ function resolveEnvReferences(config, env, parentKey) {
|
|
|
11008
11113
|
}
|
|
11009
11114
|
function parseEnvPassword(content) {
|
|
11010
11115
|
const match = content.match(/^DBCLI_PASSWORD=(.+)$/m);
|
|
11011
|
-
|
|
11116
|
+
if (match?.[1] == null)
|
|
11117
|
+
return null;
|
|
11118
|
+
const raw = match[1].trim();
|
|
11119
|
+
const quoted = raw.startsWith('"') && raw.endsWith('"') || raw.startsWith("'") && raw.endsWith("'");
|
|
11120
|
+
return quoted && raw.length >= 2 ? raw.slice(1, -1) : raw;
|
|
11012
11121
|
}
|
|
11013
11122
|
var configModule = {
|
|
11014
11123
|
async read(path, connectionName, options = {}) {
|
|
@@ -11187,7 +11296,7 @@ ${formatConfigValidationError(error, raw)}`);
|
|
|
11187
11296
|
isDirectory = false;
|
|
11188
11297
|
}
|
|
11189
11298
|
if (isDirectory || path.endsWith(".dbcli") || path === storagePath && isDirectory) {
|
|
11190
|
-
await
|
|
11299
|
+
await mkdir4(storagePath, { recursive: true });
|
|
11191
11300
|
const hasEnvReferences = isEnvReference(config.connection.password);
|
|
11192
11301
|
if (hasEnvReferences) {
|
|
11193
11302
|
const configJson = JSON.stringify(config, null, 2);
|
|
@@ -11543,9 +11652,10 @@ var readConfig = (path, connectionName) => configModule.read(path, connectionNam
|
|
|
11543
11652
|
export {
|
|
11544
11653
|
writeV2Config,
|
|
11545
11654
|
writeProjectBinding,
|
|
11546
|
-
writeConnectionSecret,
|
|
11547
11655
|
upsertConnection,
|
|
11548
11656
|
setDefaultConnection,
|
|
11657
|
+
setConnectionPassword,
|
|
11658
|
+
resolvePasswordTarget,
|
|
11549
11659
|
resolveConnection,
|
|
11550
11660
|
resolveConfigStoragePath,
|
|
11551
11661
|
removeConnection,
|