@carllee1983/dbcli 1.20.1 → 1.20.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -6
- package/assets/SKILL.md +11 -3
- package/assets/SKILL.zh-TW.md +10 -5
- package/assets/reference.md +338 -4
- package/assets/snippets/diag/active-users.mongodb.sql +14 -0
- package/assets/snippets/diag/top-orders-by-city.mongodb.sql +20 -0
- package/dist/cli.mjs +1610 -752
- package/package.json +10 -7
package/dist/cli.mjs
CHANGED
|
@@ -7151,15 +7151,15 @@ var init_config_v2 = __esm(() => {
|
|
|
7151
7151
|
});
|
|
7152
7152
|
|
|
7153
7153
|
// node_modules/lru-cache/dist/esm/node/index.min.js
|
|
7154
|
-
import { tracingChannel as
|
|
7155
|
-
var
|
|
7154
|
+
import { tracingChannel as j, channel as G } from "diagnostics_channel";
|
|
7155
|
+
var w, W, C, D = () => w.hasSubscribers || W.hasSubscribers, I, L, P = (u, e, t2, i) => {
|
|
7156
7156
|
typeof L.emitWarning == "function" ? L.emitWarning(u, e, t2, i) : console.error(`[${t2}] ${e}: ${u}`);
|
|
7157
|
-
}, H = (u) => !
|
|
7157
|
+
}, 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 {
|
|
7158
7158
|
heap;
|
|
7159
7159
|
length;
|
|
7160
7160
|
static #o = false;
|
|
7161
7161
|
static create(e) {
|
|
7162
|
-
let t2 =
|
|
7162
|
+
let t2 = U(e);
|
|
7163
7163
|
if (!t2)
|
|
7164
7164
|
return [];
|
|
7165
7165
|
u.#o = true;
|
|
@@ -7179,12 +7179,11 @@ var S, W, C, D = () => S.hasSubscribers || W.hasSubscribers, U, L, P = (u, e, t2
|
|
|
7179
7179
|
}
|
|
7180
7180
|
}, M;
|
|
7181
7181
|
var init_index_min = __esm(() => {
|
|
7182
|
-
|
|
7183
|
-
W =
|
|
7182
|
+
w = G("lru-cache:metrics");
|
|
7183
|
+
W = j("lru-cache");
|
|
7184
7184
|
C = typeof performance == "object" && performance && typeof performance.now == "function" ? performance : Date;
|
|
7185
|
-
|
|
7185
|
+
I = new Set;
|
|
7186
7186
|
L = typeof process == "object" && process ? process : {};
|
|
7187
|
-
X = Symbol("type");
|
|
7188
7187
|
O = class extends Array {
|
|
7189
7188
|
constructor(e) {
|
|
7190
7189
|
super(e), this.fill(0);
|
|
@@ -7192,12 +7191,12 @@ var init_index_min = __esm(() => {
|
|
|
7192
7191
|
};
|
|
7193
7192
|
M = class u2 {
|
|
7194
7193
|
#o;
|
|
7195
|
-
#
|
|
7194
|
+
#c;
|
|
7196
7195
|
#w;
|
|
7197
|
-
#
|
|
7196
|
+
#O;
|
|
7198
7197
|
#S;
|
|
7199
7198
|
#M;
|
|
7200
|
-
#
|
|
7199
|
+
#I;
|
|
7201
7200
|
#m;
|
|
7202
7201
|
get perf() {
|
|
7203
7202
|
return this.#m;
|
|
@@ -7222,9 +7221,9 @@ var init_index_min = __esm(() => {
|
|
|
7222
7221
|
#s;
|
|
7223
7222
|
#i;
|
|
7224
7223
|
#t;
|
|
7225
|
-
#a;
|
|
7226
|
-
#c;
|
|
7227
7224
|
#l;
|
|
7225
|
+
#u;
|
|
7226
|
+
#a;
|
|
7228
7227
|
#h;
|
|
7229
7228
|
#y;
|
|
7230
7229
|
#r;
|
|
@@ -7233,12 +7232,12 @@ var init_index_min = __esm(() => {
|
|
|
7233
7232
|
#d;
|
|
7234
7233
|
#g;
|
|
7235
7234
|
#T;
|
|
7236
|
-
#
|
|
7235
|
+
#U;
|
|
7237
7236
|
#f;
|
|
7238
|
-
#
|
|
7237
|
+
#x;
|
|
7239
7238
|
static unsafeExposeInternals(e) {
|
|
7240
|
-
return { starts: e.#F, ttls: e.#d, autopurgeTimers: e.#g, sizes: e.#_, keyMap: e.#s, keyList: e.#i, valList: e.#t, next: e.#
|
|
7241
|
-
return e.#
|
|
7239
|
+
return { starts: e.#F, ttls: e.#d, autopurgeTimers: e.#g, sizes: e.#_, keyMap: e.#s, keyList: e.#i, valList: e.#t, next: e.#l, prev: e.#u, get head() {
|
|
7240
|
+
return e.#a;
|
|
7242
7241
|
}, get tail() {
|
|
7243
7242
|
return e.#h;
|
|
7244
7243
|
}, 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) };
|
|
@@ -7247,7 +7246,7 @@ var init_index_min = __esm(() => {
|
|
|
7247
7246
|
return this.#o;
|
|
7248
7247
|
}
|
|
7249
7248
|
get maxSize() {
|
|
7250
|
-
return this.#
|
|
7249
|
+
return this.#c;
|
|
7251
7250
|
}
|
|
7252
7251
|
get calculatedSize() {
|
|
7253
7252
|
return this.#b;
|
|
@@ -7259,53 +7258,53 @@ var init_index_min = __esm(() => {
|
|
|
7259
7258
|
return this.#M;
|
|
7260
7259
|
}
|
|
7261
7260
|
get memoMethod() {
|
|
7262
|
-
return this.#
|
|
7261
|
+
return this.#I;
|
|
7263
7262
|
}
|
|
7264
7263
|
get dispose() {
|
|
7265
7264
|
return this.#w;
|
|
7266
7265
|
}
|
|
7267
7266
|
get onInsert() {
|
|
7268
|
-
return this.#
|
|
7267
|
+
return this.#O;
|
|
7269
7268
|
}
|
|
7270
7269
|
get disposeAfter() {
|
|
7271
7270
|
return this.#S;
|
|
7272
7271
|
}
|
|
7273
7272
|
constructor(e) {
|
|
7274
|
-
let { max: t2 = 0, ttl: i, ttlResolution: s = 1, ttlAutopurge: n, updateAgeOnGet:
|
|
7273
|
+
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;
|
|
7275
7274
|
if (x !== undefined && typeof x?.now != "function")
|
|
7276
7275
|
throw new TypeError("perf option must have a now() method if specified");
|
|
7277
|
-
if (this.#m = x ?? C, t2 !== 0 && !
|
|
7276
|
+
if (this.#m = x ?? C, t2 !== 0 && !T(t2))
|
|
7278
7277
|
throw new TypeError("max option must be a nonnegative integer");
|
|
7279
|
-
let
|
|
7280
|
-
if (!
|
|
7278
|
+
let E = t2 ? U(t2) : Array;
|
|
7279
|
+
if (!E)
|
|
7281
7280
|
throw new Error("invalid max value: " + t2);
|
|
7282
|
-
if (this.#o = t2, this.#
|
|
7283
|
-
if (!this.#
|
|
7281
|
+
if (this.#o = t2, this.#c = d, this.maxEntrySize = f || this.#c, this.sizeCalculation = y, this.sizeCalculation) {
|
|
7282
|
+
if (!this.#c && !this.maxEntrySize)
|
|
7284
7283
|
throw new TypeError("cannot set sizeCalculation without setting maxSize or maxEntrySize");
|
|
7285
7284
|
if (typeof this.sizeCalculation != "function")
|
|
7286
7285
|
throw new TypeError("sizeCalculation set to non-function");
|
|
7287
7286
|
}
|
|
7288
|
-
if (
|
|
7287
|
+
if (S !== undefined && typeof S != "function")
|
|
7289
7288
|
throw new TypeError("memoMethod must be a function if defined");
|
|
7290
|
-
if (this.#
|
|
7289
|
+
if (this.#I = S, l !== undefined && typeof l != "function")
|
|
7291
7290
|
throw new TypeError("fetchMethod must be a function if specified");
|
|
7292
|
-
if (this.#M =
|
|
7293
|
-
if (this.#
|
|
7291
|
+
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) {
|
|
7292
|
+
if (this.#c !== 0 && !T(this.#c))
|
|
7294
7293
|
throw new TypeError("maxSize must be a positive integer if specified");
|
|
7295
|
-
if (!
|
|
7294
|
+
if (!T(this.maxEntrySize))
|
|
7296
7295
|
throw new TypeError("maxEntrySize must be a positive integer if specified");
|
|
7297
7296
|
this.#X();
|
|
7298
7297
|
}
|
|
7299
|
-
if (this.allowStale = !!
|
|
7300
|
-
if (!
|
|
7298
|
+
if (this.allowStale = !!a, this.noDeleteOnStaleGet = !!b, this.updateAgeOnGet = !!r, this.updateAgeOnHas = !!h, this.ttlResolution = T(s) || s === 0 ? s : 1, this.ttlAutopurge = !!n, this.ttl = i || 0, this.ttl) {
|
|
7299
|
+
if (!T(this.ttl))
|
|
7301
7300
|
throw new TypeError("ttl must be a positive integer if specified");
|
|
7302
7301
|
this.#H();
|
|
7303
7302
|
}
|
|
7304
|
-
if (this.#o === 0 && this.ttl === 0 && this.#
|
|
7303
|
+
if (this.#o === 0 && this.ttl === 0 && this.#c === 0)
|
|
7305
7304
|
throw new TypeError("At least one of max, maxSize, or ttl is required");
|
|
7306
|
-
if (!this.ttlAutopurge && !this.#o && !this.#
|
|
7307
|
-
let
|
|
7308
|
-
H(
|
|
7305
|
+
if (!this.ttlAutopurge && !this.#o && !this.#c) {
|
|
7306
|
+
let v = "LRU_CACHE_UNBOUNDED";
|
|
7307
|
+
H(v) && (I.add(v), P("TTL caching without ttlAutopurge, max, or maxSize can result in unbounded memory consumption.", "UnboundedCacheWarning", v, u2));
|
|
7309
7308
|
}
|
|
7310
7309
|
}
|
|
7311
7310
|
getRemainingTTL(e) {
|
|
@@ -7315,75 +7314,75 @@ var init_index_min = __esm(() => {
|
|
|
7315
7314
|
let e = new O(this.#o), t2 = new O(this.#o);
|
|
7316
7315
|
this.#d = e, this.#F = t2;
|
|
7317
7316
|
let i = this.ttlAutopurge ? Array.from({ length: this.#o }) : undefined;
|
|
7318
|
-
this.#g = i, this.#N = (
|
|
7319
|
-
t2[
|
|
7320
|
-
}, this.#D = (
|
|
7321
|
-
t2[
|
|
7317
|
+
this.#g = i, this.#N = (h, a, o = this.#m.now()) => {
|
|
7318
|
+
t2[h] = a !== 0 ? o : 0, e[h] = a, s(h, a);
|
|
7319
|
+
}, this.#D = (h) => {
|
|
7320
|
+
t2[h] = e[h] !== 0 ? this.#m.now() : 0, s(h, e[h]);
|
|
7322
7321
|
};
|
|
7323
|
-
let s = this.ttlAutopurge ? (
|
|
7324
|
-
if (i?.[
|
|
7325
|
-
let
|
|
7326
|
-
this.#p(
|
|
7327
|
-
},
|
|
7328
|
-
|
|
7322
|
+
let s = this.ttlAutopurge ? (h, a) => {
|
|
7323
|
+
if (i?.[h] && (clearTimeout(i[h]), i[h] = undefined), a && a !== 0 && i) {
|
|
7324
|
+
let o = setTimeout(() => {
|
|
7325
|
+
this.#p(h) && this.#E(this.#i[h], "expire");
|
|
7326
|
+
}, a + 1);
|
|
7327
|
+
o.unref && o.unref(), i[h] = o;
|
|
7329
7328
|
}
|
|
7330
7329
|
} : () => {};
|
|
7331
|
-
this.#
|
|
7332
|
-
if (e[
|
|
7333
|
-
let
|
|
7334
|
-
if (!
|
|
7330
|
+
this.#v = (h, a) => {
|
|
7331
|
+
if (e[a]) {
|
|
7332
|
+
let o = e[a], p = t2[a];
|
|
7333
|
+
if (!o || !p)
|
|
7335
7334
|
return;
|
|
7336
|
-
|
|
7337
|
-
let
|
|
7338
|
-
|
|
7335
|
+
h.ttl = o, h.start = p, h.now = n || r();
|
|
7336
|
+
let m = h.now - p;
|
|
7337
|
+
h.remainingTTL = o - m;
|
|
7339
7338
|
}
|
|
7340
7339
|
};
|
|
7341
|
-
let n = 0,
|
|
7342
|
-
let
|
|
7340
|
+
let n = 0, r = () => {
|
|
7341
|
+
let h = this.#m.now();
|
|
7343
7342
|
if (this.ttlResolution > 0) {
|
|
7344
|
-
n =
|
|
7345
|
-
let
|
|
7346
|
-
|
|
7343
|
+
n = h;
|
|
7344
|
+
let a = setTimeout(() => n = 0, this.ttlResolution);
|
|
7345
|
+
a.unref && a.unref();
|
|
7347
7346
|
}
|
|
7348
|
-
return
|
|
7347
|
+
return h;
|
|
7349
7348
|
};
|
|
7350
|
-
this.getRemainingTTL = (
|
|
7351
|
-
let
|
|
7352
|
-
if (
|
|
7349
|
+
this.getRemainingTTL = (h) => {
|
|
7350
|
+
let a = this.#s.get(h);
|
|
7351
|
+
if (a === undefined)
|
|
7353
7352
|
return 0;
|
|
7354
|
-
let
|
|
7355
|
-
if (!
|
|
7353
|
+
let o = e[a], p = t2[a];
|
|
7354
|
+
if (!o || !p)
|
|
7356
7355
|
return 1 / 0;
|
|
7357
|
-
let
|
|
7358
|
-
return
|
|
7359
|
-
}, this.#p = (
|
|
7360
|
-
let
|
|
7361
|
-
return !!
|
|
7356
|
+
let m = (n || r()) - p;
|
|
7357
|
+
return o - m;
|
|
7358
|
+
}, this.#p = (h) => {
|
|
7359
|
+
let a = t2[h], o = e[h];
|
|
7360
|
+
return !!o && !!a && (n || r()) - a > o;
|
|
7362
7361
|
};
|
|
7363
7362
|
}
|
|
7364
7363
|
#D = () => {};
|
|
7365
|
-
#
|
|
7364
|
+
#v = () => {};
|
|
7366
7365
|
#N = () => {};
|
|
7367
7366
|
#p = () => false;
|
|
7368
7367
|
#X() {
|
|
7369
7368
|
let e = new O(this.#o);
|
|
7370
7369
|
this.#b = 0, this.#_ = e, this.#R = (t2) => {
|
|
7371
7370
|
this.#b -= e[t2], e[t2] = 0;
|
|
7372
|
-
}, this.#
|
|
7371
|
+
}, this.#V = (t2, i, s, n) => {
|
|
7373
7372
|
if (this.#e(i))
|
|
7374
7373
|
return 0;
|
|
7375
|
-
if (!
|
|
7374
|
+
if (!T(s))
|
|
7376
7375
|
if (n) {
|
|
7377
7376
|
if (typeof n != "function")
|
|
7378
7377
|
throw new TypeError("sizeCalculation must be a function");
|
|
7379
|
-
if (s = n(i, t2), !
|
|
7378
|
+
if (s = n(i, t2), !T(s))
|
|
7380
7379
|
throw new TypeError("sizeCalculation return invalid (expect positive integer)");
|
|
7381
7380
|
} else
|
|
7382
7381
|
throw new TypeError("invalid size value (must be positive integer). When maxSize or maxEntrySize is used, sizeCalculation or size must be set.");
|
|
7383
7382
|
return s;
|
|
7384
|
-
}, this.#
|
|
7385
|
-
if (e[t2] = i, this.#
|
|
7386
|
-
let n = this.#
|
|
7383
|
+
}, this.#j = (t2, i, s) => {
|
|
7384
|
+
if (e[t2] = i, this.#c) {
|
|
7385
|
+
let n = this.#c - e[t2];
|
|
7387
7386
|
for (;this.#b > n; )
|
|
7388
7387
|
this.#G(true);
|
|
7389
7388
|
}
|
|
@@ -7391,23 +7390,23 @@ var init_index_min = __esm(() => {
|
|
|
7391
7390
|
};
|
|
7392
7391
|
}
|
|
7393
7392
|
#R = (e) => {};
|
|
7394
|
-
#
|
|
7395
|
-
#
|
|
7393
|
+
#j = (e, t2, i) => {};
|
|
7394
|
+
#V = (e, t2, i, s) => {
|
|
7396
7395
|
if (i || s)
|
|
7397
7396
|
throw new TypeError("cannot set size without setting maxSize or maxEntrySize on cache");
|
|
7398
7397
|
return 0;
|
|
7399
7398
|
};
|
|
7400
7399
|
*#A({ allowStale: e = this.allowStale } = {}) {
|
|
7401
7400
|
if (this.#n)
|
|
7402
|
-
for (let t2 = this.#h;this.#
|
|
7403
|
-
t2 = this.#
|
|
7401
|
+
for (let t2 = this.#h;this.#B(t2) && ((e || !this.#p(t2)) && (yield t2), t2 !== this.#a); )
|
|
7402
|
+
t2 = this.#u[t2];
|
|
7404
7403
|
}
|
|
7405
7404
|
*#z({ allowStale: e = this.allowStale } = {}) {
|
|
7406
7405
|
if (this.#n)
|
|
7407
|
-
for (let t2 = this.#
|
|
7408
|
-
t2 = this.#
|
|
7406
|
+
for (let t2 = this.#a;this.#B(t2) && ((e || !this.#p(t2)) && (yield t2), t2 !== this.#h); )
|
|
7407
|
+
t2 = this.#l[t2];
|
|
7409
7408
|
}
|
|
7410
|
-
#
|
|
7409
|
+
#B(e) {
|
|
7411
7410
|
return e !== undefined && this.#s.get(this.#i[e]) === e;
|
|
7412
7411
|
}
|
|
7413
7412
|
*entries() {
|
|
@@ -7464,7 +7463,7 @@ var init_index_min = __esm(() => {
|
|
|
7464
7463
|
purgeStale() {
|
|
7465
7464
|
let e = false;
|
|
7466
7465
|
for (let t2 of this.#z({ allowStale: true }))
|
|
7467
|
-
this.#p(t2) && (this.#
|
|
7466
|
+
this.#p(t2) && (this.#E(this.#i[t2], "expire"), e = true);
|
|
7468
7467
|
return e;
|
|
7469
7468
|
}
|
|
7470
7469
|
info(e) {
|
|
@@ -7476,10 +7475,10 @@ var init_index_min = __esm(() => {
|
|
|
7476
7475
|
return;
|
|
7477
7476
|
let n = { value: s };
|
|
7478
7477
|
if (this.#d && this.#F) {
|
|
7479
|
-
let
|
|
7480
|
-
if (
|
|
7481
|
-
let
|
|
7482
|
-
n.ttl =
|
|
7478
|
+
let r = this.#d[t2], h = this.#F[t2];
|
|
7479
|
+
if (r && h) {
|
|
7480
|
+
let a = r - (this.#m.now() - h);
|
|
7481
|
+
n.ttl = a, n.start = Date.now();
|
|
7483
7482
|
}
|
|
7484
7483
|
}
|
|
7485
7484
|
return this.#_ && (n.size = this.#_[t2]), n;
|
|
@@ -7490,13 +7489,13 @@ var init_index_min = __esm(() => {
|
|
|
7490
7489
|
let i = this.#i[t2], s = this.#t[t2], n = this.#e(s) ? s.__staleWhileFetching : s;
|
|
7491
7490
|
if (n === undefined || i === undefined)
|
|
7492
7491
|
continue;
|
|
7493
|
-
let
|
|
7492
|
+
let r = { value: n };
|
|
7494
7493
|
if (this.#d && this.#F) {
|
|
7495
|
-
|
|
7496
|
-
let
|
|
7497
|
-
|
|
7494
|
+
r.ttl = this.#d[t2];
|
|
7495
|
+
let h = this.#m.now() - this.#F[t2];
|
|
7496
|
+
r.start = Math.floor(Date.now() - h);
|
|
7498
7497
|
}
|
|
7499
|
-
this.#_ && (
|
|
7498
|
+
this.#_ && (r.size = this.#_[t2]), e.unshift([i, r]);
|
|
7500
7499
|
}
|
|
7501
7500
|
return e;
|
|
7502
7501
|
}
|
|
@@ -7507,57 +7506,56 @@ var init_index_min = __esm(() => {
|
|
|
7507
7506
|
let s = Date.now() - i.start;
|
|
7508
7507
|
i.start = this.#m.now() - s;
|
|
7509
7508
|
}
|
|
7510
|
-
this.#
|
|
7509
|
+
this.#W(t2, i.value, i);
|
|
7511
7510
|
}
|
|
7512
7511
|
}
|
|
7513
7512
|
set(e, t2, i = {}) {
|
|
7514
|
-
let { status: s =
|
|
7515
|
-
i.status = s, s && (s.op = "set", s.key = e, t2 !== undefined && (s.value = t2));
|
|
7516
|
-
let n = this.#
|
|
7517
|
-
return s &&
|
|
7513
|
+
let { status: s = w.hasSubscribers ? {} : undefined } = i;
|
|
7514
|
+
i.status = s, s && (s.op = "set", s.key = e, t2 !== undefined && (s.value = t2), s.cache = this);
|
|
7515
|
+
let n = this.#W(e, t2, i);
|
|
7516
|
+
return s && w.hasSubscribers && w.publish(s), n;
|
|
7518
7517
|
}
|
|
7519
|
-
#
|
|
7520
|
-
let { ttl:
|
|
7518
|
+
#W(e, t2, i, s) {
|
|
7519
|
+
let { ttl: n = this.ttl, start: r, noDisposeOnSet: h = this.noDisposeOnSet, sizeCalculation: a = this.sizeCalculation, status: o } = i;
|
|
7521
7520
|
if (t2 === undefined)
|
|
7522
|
-
return
|
|
7523
|
-
let { noUpdateTTL:
|
|
7524
|
-
|
|
7525
|
-
let
|
|
7526
|
-
if (this.maxEntrySize &&
|
|
7527
|
-
return this.#
|
|
7528
|
-
let
|
|
7529
|
-
if (
|
|
7530
|
-
|
|
7521
|
+
return o && (o.set = "deleted"), this.delete(e), this;
|
|
7522
|
+
let { noUpdateTTL: p = this.noUpdateTTL } = i, m = this.#e(t2);
|
|
7523
|
+
o && !m && (o.value = t2);
|
|
7524
|
+
let _ = this.#V(e, t2, i.size || 0, a, o);
|
|
7525
|
+
if (this.maxEntrySize && _ > this.maxEntrySize)
|
|
7526
|
+
return this.#E(e, "set"), o && (o.set = "miss", o.maxEntrySizeExceeded = true), this;
|
|
7527
|
+
let c = this.#n === 0 ? undefined : this.#s.get(e);
|
|
7528
|
+
if (c === undefined)
|
|
7529
|
+
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");
|
|
7531
7530
|
else {
|
|
7532
|
-
this.#L(
|
|
7533
|
-
let
|
|
7534
|
-
if (t2 !==
|
|
7535
|
-
if (
|
|
7536
|
-
|
|
7537
|
-
|
|
7538
|
-
|
|
7539
|
-
|
|
7540
|
-
|
|
7541
|
-
|
|
7542
|
-
|
|
7543
|
-
let
|
|
7544
|
-
|
|
7531
|
+
this.#L(c);
|
|
7532
|
+
let d = this.#t[c];
|
|
7533
|
+
if (t2 !== d) {
|
|
7534
|
+
if (!h)
|
|
7535
|
+
if (this.#e(d)) {
|
|
7536
|
+
d !== s && d.__abortController.abort(new Error("replaced"));
|
|
7537
|
+
let { __staleWhileFetching: f } = d;
|
|
7538
|
+
f !== undefined && f !== t2 && (this.#T && this.#w?.(f, e, "set"), this.#f && this.#r?.push([f, e, "set"]));
|
|
7539
|
+
} else
|
|
7540
|
+
this.#T && this.#w?.(d, e, "set"), this.#f && this.#r?.push([d, e, "set"]);
|
|
7541
|
+
if (this.#R(c), this.#j(c, _, o), this.#t[c] = t2, !m) {
|
|
7542
|
+
let f = d && this.#e(d) ? d.__staleWhileFetching : d, y = f === undefined ? "add" : t2 !== f ? "replace" : "update";
|
|
7543
|
+
o && (o.set = y, f !== undefined && (o.oldValue = f)), this.#x && this.onInsert?.(t2, e, y);
|
|
7545
7544
|
}
|
|
7546
7545
|
} else
|
|
7547
|
-
|
|
7548
|
-
this.#j && this.onInsert?.(t2, e, t2 === g ? "update" : "replace");
|
|
7546
|
+
m || (o && (o.set = "update"), this.#x && this.onInsert?.(t2, e, "update"));
|
|
7549
7547
|
}
|
|
7550
|
-
if (
|
|
7551
|
-
let
|
|
7552
|
-
for (;
|
|
7553
|
-
this.#S?.(...
|
|
7548
|
+
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) {
|
|
7549
|
+
let d = this.#r, f;
|
|
7550
|
+
for (;f = d?.shift(); )
|
|
7551
|
+
this.#S?.(...f);
|
|
7554
7552
|
}
|
|
7555
7553
|
return this;
|
|
7556
7554
|
}
|
|
7557
7555
|
pop() {
|
|
7558
7556
|
try {
|
|
7559
7557
|
for (;this.#n; ) {
|
|
7560
|
-
let e = this.#t[this.#
|
|
7558
|
+
let e = this.#t[this.#a];
|
|
7561
7559
|
if (this.#G(true), this.#e(e)) {
|
|
7562
7560
|
if (e.__staleWhileFetching)
|
|
7563
7561
|
return e.__staleWhileFetching;
|
|
@@ -7573,34 +7571,36 @@ var init_index_min = __esm(() => {
|
|
|
7573
7571
|
}
|
|
7574
7572
|
}
|
|
7575
7573
|
#G(e) {
|
|
7576
|
-
let t2 = this.#
|
|
7577
|
-
|
|
7574
|
+
let t2 = this.#a, i = this.#i[t2], s = this.#t[t2], n = this.#e(s);
|
|
7575
|
+
n && s.__abortController.abort(new Error("evicted"));
|
|
7576
|
+
let r = n ? s.__staleWhileFetching : s;
|
|
7577
|
+
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;
|
|
7578
7578
|
}
|
|
7579
7579
|
has(e, t2 = {}) {
|
|
7580
|
-
let { status: i =
|
|
7581
|
-
t2.status = i, i && (i.op = "has", i.key = e);
|
|
7580
|
+
let { status: i = w.hasSubscribers ? {} : undefined } = t2;
|
|
7581
|
+
t2.status = i, i && (i.op = "has", i.key = e, i.cache = this);
|
|
7582
7582
|
let s = this.#Y(e, t2);
|
|
7583
|
-
return
|
|
7583
|
+
return w.hasSubscribers && w.publish(i), s;
|
|
7584
7584
|
}
|
|
7585
7585
|
#Y(e, t2 = {}) {
|
|
7586
7586
|
let { updateAgeOnHas: i = this.updateAgeOnHas, status: s } = t2, n = this.#s.get(e);
|
|
7587
7587
|
if (n !== undefined) {
|
|
7588
|
-
let
|
|
7589
|
-
if (this.#e(
|
|
7588
|
+
let r = this.#t[n];
|
|
7589
|
+
if (this.#e(r) && r.__staleWhileFetching === undefined)
|
|
7590
7590
|
return false;
|
|
7591
7591
|
if (this.#p(n))
|
|
7592
|
-
s && (s.has = "stale", this.#
|
|
7592
|
+
s && (s.has = "stale", this.#v(s, n));
|
|
7593
7593
|
else
|
|
7594
|
-
return i && this.#D(n), s && (s.has = "hit", this.#
|
|
7594
|
+
return i && this.#D(n), s && (s.has = "hit", this.#v(s, n)), true;
|
|
7595
7595
|
} else
|
|
7596
7596
|
s && (s.has = "miss");
|
|
7597
7597
|
return false;
|
|
7598
7598
|
}
|
|
7599
7599
|
peek(e, t2 = {}) {
|
|
7600
7600
|
let { status: i = D() ? {} : undefined } = t2;
|
|
7601
|
-
i && (i.op = "peek", i.key = e), t2.status = i;
|
|
7601
|
+
i && (i.op = "peek", i.key = e, i.cache = this), t2.status = i;
|
|
7602
7602
|
let s = this.#J(e, t2);
|
|
7603
|
-
return
|
|
7603
|
+
return w.hasSubscribers && w.publish(i), s;
|
|
7604
7604
|
}
|
|
7605
7605
|
#J(e, t2) {
|
|
7606
7606
|
let { status: i, allowStale: s = this.allowStale } = t2, n = this.#s.get(e);
|
|
@@ -7608,39 +7608,39 @@ var init_index_min = __esm(() => {
|
|
|
7608
7608
|
i && (i.peek = n === undefined ? "miss" : "stale");
|
|
7609
7609
|
return;
|
|
7610
7610
|
}
|
|
7611
|
-
let
|
|
7612
|
-
return i && (
|
|
7611
|
+
let r = this.#t[n], h = this.#e(r) ? r.__staleWhileFetching : r;
|
|
7612
|
+
return i && (h !== undefined ? (i.peek = "hit", i.value = h) : i.peek = "miss"), h;
|
|
7613
7613
|
}
|
|
7614
7614
|
#P(e, t2, i, s) {
|
|
7615
7615
|
let n = t2 === undefined ? undefined : this.#t[t2];
|
|
7616
7616
|
if (this.#e(n))
|
|
7617
7617
|
return n;
|
|
7618
|
-
let
|
|
7619
|
-
|
|
7620
|
-
let
|
|
7621
|
-
let { aborted:
|
|
7622
|
-
if (i.status && (
|
|
7623
|
-
return
|
|
7624
|
-
let b =
|
|
7625
|
-
return (
|
|
7626
|
-
},
|
|
7627
|
-
let { aborted:
|
|
7628
|
-
if (this.#t[t2] ===
|
|
7629
|
-
return i.status &&
|
|
7630
|
-
if (
|
|
7631
|
-
throw
|
|
7632
|
-
},
|
|
7633
|
-
let
|
|
7634
|
-
|
|
7635
|
-
(!i.ignoreFetchAbort || i.allowStaleOnFetchAbort) && (
|
|
7636
|
-
});
|
|
7618
|
+
let r = new AbortController, { signal: h } = i;
|
|
7619
|
+
h?.addEventListener("abort", () => r.abort(h.reason), { signal: r.signal });
|
|
7620
|
+
let a = { signal: r.signal, options: i, context: s }, o = (f, y = false) => {
|
|
7621
|
+
let { aborted: l } = r.signal, S = i.ignoreFetchAbort && f !== undefined, F = i.ignoreFetchAbort || !!(i.allowStaleOnFetchAbort && f !== undefined);
|
|
7622
|
+
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)
|
|
7623
|
+
return m(r.signal.reason, F);
|
|
7624
|
+
let b = c, g = this.#t[t2];
|
|
7625
|
+
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;
|
|
7626
|
+
}, p = (f) => (i.status && (i.status.fetchRejected = true, i.status.fetchError = f), m(f, false)), m = (f, y) => {
|
|
7627
|
+
let { aborted: l } = r.signal, S = l && i.allowStaleOnFetchAbort, F = S || i.allowStaleOnFetchRejection, b = F || i.noDeleteOnFetchRejection, g = c;
|
|
7628
|
+
if (this.#t[t2] === c && (!b || !y && g.__staleWhileFetching === undefined ? this.#E(e, "fetch") : S || (this.#t[t2] = g.__staleWhileFetching)), F)
|
|
7629
|
+
return i.status && g.__staleWhileFetching !== undefined && (i.status.returnedStale = true), g.__staleWhileFetching;
|
|
7630
|
+
if (g.__returned === g)
|
|
7631
|
+
throw f;
|
|
7632
|
+
}, _ = (f, y) => {
|
|
7633
|
+
let l = this.#M?.(e, n, a);
|
|
7634
|
+
r.signal.addEventListener("abort", () => {
|
|
7635
|
+
(!i.ignoreFetchAbort || i.allowStaleOnFetchAbort) && (f(undefined), i.allowStaleOnFetchAbort && (f = (S) => o(S, true)));
|
|
7636
|
+
}), l && l instanceof Promise ? l.then((S) => f(S === undefined ? undefined : S), y) : l !== undefined && f(l);
|
|
7637
7637
|
};
|
|
7638
7638
|
i.status && (i.status.fetchDispatched = true);
|
|
7639
|
-
let
|
|
7640
|
-
return t2 === undefined ? (this.#
|
|
7639
|
+
let c = new Promise(_).then(o, p), d = Object.assign(c, { __abortController: r, __staleWhileFetching: n, __returned: undefined });
|
|
7640
|
+
return t2 === undefined ? (this.#W(e, d, { ...a.options, status: undefined }), t2 = this.#s.get(e)) : this.#t[t2] = d, d;
|
|
7641
7641
|
}
|
|
7642
7642
|
#e(e) {
|
|
7643
|
-
if (!this.#
|
|
7643
|
+
if (!this.#U)
|
|
7644
7644
|
return false;
|
|
7645
7645
|
let t2 = e;
|
|
7646
7646
|
return !!t2 && t2 instanceof Promise && t2.hasOwnProperty("__staleWhileFetching") && t2.__abortController instanceof AbortController;
|
|
@@ -7648,29 +7648,29 @@ var init_index_min = __esm(() => {
|
|
|
7648
7648
|
fetch(e, t2 = {}) {
|
|
7649
7649
|
let i = W.hasSubscribers, { status: s = D() ? {} : undefined } = t2;
|
|
7650
7650
|
t2.status = s, s && t2.context && (s.context = t2.context);
|
|
7651
|
-
let n = this.#
|
|
7651
|
+
let n = this.#k(e, t2);
|
|
7652
7652
|
return s && i && (s.trace = true, W.tracePromise(() => n, s).catch(() => {})), n;
|
|
7653
7653
|
}
|
|
7654
|
-
async#
|
|
7655
|
-
let { allowStale: i = this.allowStale, updateAgeOnGet: s = this.updateAgeOnGet, noDeleteOnStaleGet: n = this.noDeleteOnStaleGet, ttl:
|
|
7656
|
-
if (
|
|
7657
|
-
return
|
|
7658
|
-
let
|
|
7654
|
+
async#k(e, t2 = {}) {
|
|
7655
|
+
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;
|
|
7656
|
+
if (l && (l.op = "fetch", l.key = e, y && (l.forceRefresh = true), l.cache = this), !this.#U)
|
|
7657
|
+
return l && (l.fetch = "get"), this.#C(e, { allowStale: i, updateAgeOnGet: s, noDeleteOnStaleGet: n, status: l });
|
|
7658
|
+
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);
|
|
7659
7659
|
if (b === undefined) {
|
|
7660
|
-
|
|
7661
|
-
let
|
|
7662
|
-
return
|
|
7660
|
+
l && (l.fetch = "miss");
|
|
7661
|
+
let g = this.#P(e, b, F, f);
|
|
7662
|
+
return g.__returned = g;
|
|
7663
7663
|
} else {
|
|
7664
|
-
let
|
|
7665
|
-
if (this.#e(
|
|
7666
|
-
let
|
|
7667
|
-
return
|
|
7664
|
+
let g = this.#t[b];
|
|
7665
|
+
if (this.#e(g)) {
|
|
7666
|
+
let v = i && g.__staleWhileFetching !== undefined;
|
|
7667
|
+
return l && (l.fetch = "inflight", v && (l.returnedStale = true)), v ? g.__staleWhileFetching : g.__returned = g;
|
|
7668
7668
|
}
|
|
7669
7669
|
let A = this.#p(b);
|
|
7670
7670
|
if (!y && !A)
|
|
7671
|
-
return
|
|
7672
|
-
let z = this.#P(e, b,
|
|
7673
|
-
return
|
|
7671
|
+
return l && (l.fetch = "hit"), this.#L(b), s && this.#D(b), l && this.#v(l, b), g;
|
|
7672
|
+
let z = this.#P(e, b, F, f), E = z.__staleWhileFetching !== undefined && i;
|
|
7673
|
+
return l && (l.fetch = A ? "stale" : "refresh", E && A && (l.returnedStale = true)), E ? z.__staleWhileFetching : z.__returned = z;
|
|
7674
7674
|
}
|
|
7675
7675
|
}
|
|
7676
7676
|
forceFetch(e, t2 = {}) {
|
|
@@ -7680,55 +7680,55 @@ var init_index_min = __esm(() => {
|
|
|
7680
7680
|
return s && i && (s.trace = true, W.tracePromise(() => n, s).catch(() => {})), n;
|
|
7681
7681
|
}
|
|
7682
7682
|
async#K(e, t2 = {}) {
|
|
7683
|
-
let i = await this.#
|
|
7683
|
+
let i = await this.#k(e, t2);
|
|
7684
7684
|
if (i === undefined)
|
|
7685
7685
|
throw new Error("fetch() returned undefined");
|
|
7686
7686
|
return i;
|
|
7687
7687
|
}
|
|
7688
7688
|
memo(e, t2 = {}) {
|
|
7689
|
-
let { status: i =
|
|
7690
|
-
t2.status = i, i && (i.op = "memo", i.key = e, t2.context && (i.context = t2.context));
|
|
7689
|
+
let { status: i = w.hasSubscribers ? {} : undefined } = t2;
|
|
7690
|
+
t2.status = i, i && (i.op = "memo", i.key = e, t2.context && (i.context = t2.context), i.cache = this);
|
|
7691
7691
|
let s = this.#Q(e, t2);
|
|
7692
|
-
return i && (i.value = s),
|
|
7692
|
+
return i && (i.value = s), w.hasSubscribers && w.publish(i), s;
|
|
7693
7693
|
}
|
|
7694
7694
|
#Q(e, t2 = {}) {
|
|
7695
|
-
let i = this.#
|
|
7695
|
+
let i = this.#I;
|
|
7696
7696
|
if (!i)
|
|
7697
7697
|
throw new Error("no memoMethod provided to constructor");
|
|
7698
|
-
let { context: s, status: n, forceRefresh:
|
|
7699
|
-
n &&
|
|
7700
|
-
let
|
|
7701
|
-
if (n && (n.memo =
|
|
7702
|
-
return
|
|
7703
|
-
let
|
|
7704
|
-
return n && (n.value =
|
|
7698
|
+
let { context: s, status: n, forceRefresh: r, ...h } = t2;
|
|
7699
|
+
n && r && (n.forceRefresh = true);
|
|
7700
|
+
let a = this.#C(e, h), o = r || a === undefined;
|
|
7701
|
+
if (n && (n.memo = o ? "miss" : "hit", o || (n.value = a)), !o)
|
|
7702
|
+
return a;
|
|
7703
|
+
let p = i(e, a, { options: h, context: s });
|
|
7704
|
+
return n && (n.value = p), this.#W(e, p, h), p;
|
|
7705
7705
|
}
|
|
7706
7706
|
get(e, t2 = {}) {
|
|
7707
|
-
let { status: i =
|
|
7708
|
-
t2.status = i, i && (i.op = "get", i.key = e);
|
|
7707
|
+
let { status: i = w.hasSubscribers ? {} : undefined } = t2;
|
|
7708
|
+
t2.status = i, i && (i.op = "get", i.key = e, i.cache = this);
|
|
7709
7709
|
let s = this.#C(e, t2);
|
|
7710
|
-
return i && (s !== undefined && (i.value = s),
|
|
7710
|
+
return i && (s !== undefined && (i.value = s), w.hasSubscribers && w.publish(i)), s;
|
|
7711
7711
|
}
|
|
7712
7712
|
#C(e, t2 = {}) {
|
|
7713
|
-
let { allowStale: i = this.allowStale, updateAgeOnGet: s = this.updateAgeOnGet, noDeleteOnStaleGet: n = this.noDeleteOnStaleGet, status:
|
|
7714
|
-
if (
|
|
7715
|
-
|
|
7713
|
+
let { allowStale: i = this.allowStale, updateAgeOnGet: s = this.updateAgeOnGet, noDeleteOnStaleGet: n = this.noDeleteOnStaleGet, status: r } = t2, h = this.#s.get(e);
|
|
7714
|
+
if (h === undefined) {
|
|
7715
|
+
r && (r.get = "miss");
|
|
7716
7716
|
return;
|
|
7717
7717
|
}
|
|
7718
|
-
let
|
|
7719
|
-
return
|
|
7718
|
+
let a = this.#t[h], o = this.#e(a);
|
|
7719
|
+
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);
|
|
7720
7720
|
}
|
|
7721
7721
|
#$(e, t2) {
|
|
7722
|
-
this.#
|
|
7722
|
+
this.#u[t2] = e, this.#l[e] = t2;
|
|
7723
7723
|
}
|
|
7724
7724
|
#L(e) {
|
|
7725
|
-
e !== this.#h && (e === this.#
|
|
7725
|
+
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);
|
|
7726
7726
|
}
|
|
7727
7727
|
delete(e) {
|
|
7728
|
-
return this.#
|
|
7728
|
+
return this.#E(e, "delete");
|
|
7729
7729
|
}
|
|
7730
|
-
#
|
|
7731
|
-
|
|
7730
|
+
#E(e, t2) {
|
|
7731
|
+
w.hasSubscribers && w.publish({ op: "delete", delete: t2, key: e, cache: this });
|
|
7732
7732
|
let i = false;
|
|
7733
7733
|
if (this.#n !== 0) {
|
|
7734
7734
|
let s = this.#s.get(e);
|
|
@@ -7739,14 +7739,14 @@ var init_index_min = __esm(() => {
|
|
|
7739
7739
|
this.#R(s);
|
|
7740
7740
|
let n = this.#t[s];
|
|
7741
7741
|
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)
|
|
7742
|
-
this.#h = this.#
|
|
7743
|
-
else if (s === this.#
|
|
7744
|
-
this.#
|
|
7742
|
+
this.#h = this.#u[s];
|
|
7743
|
+
else if (s === this.#a)
|
|
7744
|
+
this.#a = this.#l[s];
|
|
7745
7745
|
else {
|
|
7746
|
-
let
|
|
7747
|
-
this.#
|
|
7748
|
-
let
|
|
7749
|
-
this.#
|
|
7746
|
+
let r = this.#u[s];
|
|
7747
|
+
this.#l[r] = this.#l[s];
|
|
7748
|
+
let h = this.#l[s];
|
|
7749
|
+
this.#u[h] = this.#u[s];
|
|
7750
7750
|
}
|
|
7751
7751
|
this.#n--, this.#y.push(s);
|
|
7752
7752
|
}
|
|
@@ -7777,7 +7777,7 @@ var init_index_min = __esm(() => {
|
|
|
7777
7777
|
t2 !== undefined && clearTimeout(t2);
|
|
7778
7778
|
this.#g?.fill(undefined);
|
|
7779
7779
|
}
|
|
7780
|
-
if (this.#_ && this.#_.fill(0), this.#
|
|
7780
|
+
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) {
|
|
7781
7781
|
let t2 = this.#r, i;
|
|
7782
7782
|
for (;i = t2?.shift(); )
|
|
7783
7783
|
this.#S?.(...i);
|
|
@@ -9887,6 +9887,7 @@ class ScreenManager {
|
|
|
9887
9887
|
let output = cursorDown(this.extraLinesUnderPrompt);
|
|
9888
9888
|
output += clearContent ? eraseLines(this.height) : `
|
|
9889
9889
|
`;
|
|
9890
|
+
output += cursorLeft;
|
|
9890
9891
|
output += cursorShow;
|
|
9891
9892
|
this.write(output);
|
|
9892
9893
|
this.rl.close();
|
|
@@ -9921,7 +9922,7 @@ import * as readline2 from "readline";
|
|
|
9921
9922
|
import { AsyncResource as AsyncResource3 } from "async_hooks";
|
|
9922
9923
|
import path from "path";
|
|
9923
9924
|
function getCallSites() {
|
|
9924
|
-
const
|
|
9925
|
+
const savedPrepareStackTrace = Error.prepareStackTrace;
|
|
9925
9926
|
let result = [];
|
|
9926
9927
|
try {
|
|
9927
9928
|
Error.prepareStackTrace = (_, callSites) => {
|
|
@@ -9933,7 +9934,7 @@ function getCallSites() {
|
|
|
9933
9934
|
} catch {
|
|
9934
9935
|
return result;
|
|
9935
9936
|
}
|
|
9936
|
-
Error.prepareStackTrace =
|
|
9937
|
+
Error.prepareStackTrace = savedPrepareStackTrace;
|
|
9937
9938
|
return result;
|
|
9938
9939
|
}
|
|
9939
9940
|
function createPrompt(view) {
|
|
@@ -20845,8 +20846,8 @@ var init_capabilities = __esm(() => {
|
|
|
20845
20846
|
schemaFullScan: cap("limited", "readonly", "Full scan is sampled and document-oriented."),
|
|
20846
20847
|
query: cap("limited", "readonly", "Uses JSON filter or aggregation syntax, not SQL."),
|
|
20847
20848
|
queryLimitGuard: cap("limited", "readonly", "Applies result limits and collection size guard."),
|
|
20848
|
-
queries: cap("limited", "local-write", "Snippet management works
|
|
20849
|
-
q: cap("
|
|
20849
|
+
queries: cap("limited", "local-write", "Snippet management works with MongoDB-specific saved-query limitations."),
|
|
20850
|
+
q: cap("limited", "readonly", "Saved MongoDB snippets require collection frontmatter, accept JSON find/aggregate bodies, and JSON-encode parameter substitutions."),
|
|
20850
20851
|
insert: cap("limited", "db-write", "Document insert is supported with Mongo-specific behavior."),
|
|
20851
20852
|
update: cap("limited", "db-write", "Document update is supported with Mongo-specific behavior."),
|
|
20852
20853
|
delete: cap("limited", "db-write", "Document delete is supported with Mongo-specific behavior."),
|
|
@@ -21776,22 +21777,29 @@ class MongoDBAdapter {
|
|
|
21776
21777
|
const collection = db.collection(collectionName);
|
|
21777
21778
|
const estimatedRowCount = await collection.estimatedDocumentCount();
|
|
21778
21779
|
const requested = options?.sampleSize;
|
|
21779
|
-
const desired = typeof requested === "number" && requested >= 1 ? requested :
|
|
21780
|
+
const desired = typeof requested === "number" && requested >= 1 ? requested : 100;
|
|
21780
21781
|
const sampleSize = Math.min(desired, 1000);
|
|
21781
|
-
const
|
|
21782
|
-
|
|
21783
|
-
|
|
21784
|
-
|
|
21785
|
-
|
|
21786
|
-
|
|
21787
|
-
}
|
|
21788
|
-
|
|
21782
|
+
const method = options?.sampleMethod ?? "random";
|
|
21783
|
+
let samples = [];
|
|
21784
|
+
if (method === "random") {
|
|
21785
|
+
try {
|
|
21786
|
+
samples = await collection.aggregate([{ $sample: { size: sampleSize } }]).toArray();
|
|
21787
|
+
} catch (err) {
|
|
21788
|
+
console.error(`[mongo] $sample failed (${err.message}); falling back to natural order.`);
|
|
21789
|
+
samples = await collection.find().limit(sampleSize).toArray();
|
|
21789
21790
|
}
|
|
21791
|
+
} else {
|
|
21792
|
+
samples = await collection.find().limit(sampleSize).toArray();
|
|
21790
21793
|
}
|
|
21791
|
-
const
|
|
21794
|
+
const accumulator = new Map;
|
|
21795
|
+
for (const doc of samples)
|
|
21796
|
+
accumulateDocPaths(doc, "", accumulator);
|
|
21797
|
+
const denom = Math.max(samples.length, 1);
|
|
21798
|
+
const columns = Array.from(accumulator.entries()).map(([name, info]) => ({
|
|
21792
21799
|
name,
|
|
21793
|
-
type: Array.from(
|
|
21794
|
-
nullable:
|
|
21800
|
+
type: Array.from(info.types).sort().join(" | "),
|
|
21801
|
+
nullable: info.types.has("null") || info.count < denom,
|
|
21802
|
+
presence: info.count / denom
|
|
21795
21803
|
}));
|
|
21796
21804
|
return {
|
|
21797
21805
|
name: collectionName,
|
|
@@ -21836,6 +21844,44 @@ class MongoDBAdapter {
|
|
|
21836
21844
|
};
|
|
21837
21845
|
}
|
|
21838
21846
|
}
|
|
21847
|
+
function detectMongoType(v) {
|
|
21848
|
+
if (v === null || v === undefined)
|
|
21849
|
+
return "null";
|
|
21850
|
+
if (Array.isArray(v))
|
|
21851
|
+
return "array";
|
|
21852
|
+
if (v instanceof Date)
|
|
21853
|
+
return "Date";
|
|
21854
|
+
if (typeof v === "object") {
|
|
21855
|
+
const ctor = v.constructor?.name;
|
|
21856
|
+
if (ctor === "ObjectId")
|
|
21857
|
+
return "ObjectId";
|
|
21858
|
+
if (ctor === "Binary")
|
|
21859
|
+
return "Binary";
|
|
21860
|
+
if (ctor === "Decimal128")
|
|
21861
|
+
return "Decimal128";
|
|
21862
|
+
return "object";
|
|
21863
|
+
}
|
|
21864
|
+
if (typeof v === "string")
|
|
21865
|
+
return "string";
|
|
21866
|
+
if (typeof v === "number")
|
|
21867
|
+
return "number";
|
|
21868
|
+
if (typeof v === "boolean")
|
|
21869
|
+
return "boolean";
|
|
21870
|
+
return "string";
|
|
21871
|
+
}
|
|
21872
|
+
function accumulateDocPaths(doc, prefix, acc) {
|
|
21873
|
+
for (const [k, v] of Object.entries(doc)) {
|
|
21874
|
+
const path3 = prefix === "" ? k : `${prefix}.${k}`;
|
|
21875
|
+
const t2 = detectMongoType(v);
|
|
21876
|
+
const slot = acc.get(path3) ?? { types: new Set, count: 0 };
|
|
21877
|
+
slot.types.add(t2);
|
|
21878
|
+
slot.count += 1;
|
|
21879
|
+
acc.set(path3, slot);
|
|
21880
|
+
if (t2 === "object" && v && typeof v === "object") {
|
|
21881
|
+
accumulateDocPaths(v, path3, acc);
|
|
21882
|
+
}
|
|
21883
|
+
}
|
|
21884
|
+
}
|
|
21839
21885
|
var init_mongodb_adapter = __esm(() => {
|
|
21840
21886
|
init_types2();
|
|
21841
21887
|
});
|
|
@@ -24289,6 +24335,51 @@ var require_table = __commonJS((exports, module) => {
|
|
|
24289
24335
|
module.exports = Table;
|
|
24290
24336
|
});
|
|
24291
24337
|
|
|
24338
|
+
// src/formatters/table-formatter.ts
|
|
24339
|
+
class TableFormatter {
|
|
24340
|
+
format(columns) {
|
|
24341
|
+
const table = new Table({
|
|
24342
|
+
head: ["Column", "Type", "Nullable", "Default", "Key"].map((h) => colors.bold(h)),
|
|
24343
|
+
style: { compact: false, "padding-left": 1, "padding-right": 1 },
|
|
24344
|
+
colWidths: [25, 25, 10, 25, 20]
|
|
24345
|
+
});
|
|
24346
|
+
columns.forEach((col) => {
|
|
24347
|
+
let keyType = "";
|
|
24348
|
+
if (col.primaryKey) {
|
|
24349
|
+
keyType = "PK";
|
|
24350
|
+
} else if (col.foreignKey) {
|
|
24351
|
+
keyType = `FK \u2192 ${col.foreignKey.table}.${col.foreignKey.column}`;
|
|
24352
|
+
}
|
|
24353
|
+
table.push([col.name, col.type, col.nullable ? "YES" : "NO", col.default || "NULL", keyType]);
|
|
24354
|
+
});
|
|
24355
|
+
return table.toString();
|
|
24356
|
+
}
|
|
24357
|
+
}
|
|
24358
|
+
|
|
24359
|
+
class TableListFormatter {
|
|
24360
|
+
format(tables) {
|
|
24361
|
+
const table = new Table({
|
|
24362
|
+
head: ["Table", "Columns", "Rows", "Engine"].map((h) => colors.bold(h)),
|
|
24363
|
+
style: { compact: false, "padding-left": 1, "padding-right": 1 },
|
|
24364
|
+
colWidths: [30, 12, 15, 15]
|
|
24365
|
+
});
|
|
24366
|
+
tables.forEach((t2) => {
|
|
24367
|
+
table.push([
|
|
24368
|
+
t2.name,
|
|
24369
|
+
(t2.columnCount ?? t2.columns.length).toString(),
|
|
24370
|
+
(t2.rowCount ?? "?").toString(),
|
|
24371
|
+
t2.engine || "N/A"
|
|
24372
|
+
]);
|
|
24373
|
+
});
|
|
24374
|
+
return table.toString();
|
|
24375
|
+
}
|
|
24376
|
+
}
|
|
24377
|
+
var Table;
|
|
24378
|
+
var init_table_formatter = __esm(() => {
|
|
24379
|
+
init_colors();
|
|
24380
|
+
Table = require_table();
|
|
24381
|
+
});
|
|
24382
|
+
|
|
24292
24383
|
// src/core/size-category.ts
|
|
24293
24384
|
var exports_size_category = {};
|
|
24294
24385
|
__export(exports_size_category, {
|
|
@@ -24311,6 +24402,240 @@ var init_size_category = __esm(() => {
|
|
|
24311
24402
|
];
|
|
24312
24403
|
});
|
|
24313
24404
|
|
|
24405
|
+
// src/formatters/json-formatter.ts
|
|
24406
|
+
class TableSchemaJSONFormatter {
|
|
24407
|
+
format(table, options) {
|
|
24408
|
+
const spacing = options?.compact ? undefined : 2;
|
|
24409
|
+
const rowCount = table.estimatedRowCount ?? table.rowCount;
|
|
24410
|
+
const output = {
|
|
24411
|
+
name: table.name,
|
|
24412
|
+
estimatedRowCount: rowCount ?? null,
|
|
24413
|
+
sizeCategory: rowCount !== undefined && rowCount !== null ? getSizeCategory(rowCount) : null,
|
|
24414
|
+
tableType: table.tableType ?? "table",
|
|
24415
|
+
columns: table.columns,
|
|
24416
|
+
primaryKey: table.primaryKey || [],
|
|
24417
|
+
foreignKeys: table.foreignKeys || [],
|
|
24418
|
+
indexes: table.indexes || [],
|
|
24419
|
+
metadata: {
|
|
24420
|
+
rowCount: table.rowCount,
|
|
24421
|
+
engine: table.engine
|
|
24422
|
+
}
|
|
24423
|
+
};
|
|
24424
|
+
return JSON.stringify(output, null, spacing);
|
|
24425
|
+
}
|
|
24426
|
+
}
|
|
24427
|
+
var init_json_formatter = __esm(() => {
|
|
24428
|
+
init_size_category();
|
|
24429
|
+
});
|
|
24430
|
+
|
|
24431
|
+
// src/formatters/query-result-formatter.ts
|
|
24432
|
+
class QueryResultFormatter {
|
|
24433
|
+
format(result, options) {
|
|
24434
|
+
const format = options?.format || "table";
|
|
24435
|
+
switch (format) {
|
|
24436
|
+
case "json":
|
|
24437
|
+
return this.formatJSON(result, options?.compact);
|
|
24438
|
+
case "csv":
|
|
24439
|
+
return this.formatCSV(result);
|
|
24440
|
+
case "table":
|
|
24441
|
+
default:
|
|
24442
|
+
return this.formatTable(result);
|
|
24443
|
+
}
|
|
24444
|
+
}
|
|
24445
|
+
formatTable(result) {
|
|
24446
|
+
if (result.rows.length === 0) {
|
|
24447
|
+
return this.formatEmptyTable(result);
|
|
24448
|
+
}
|
|
24449
|
+
const table = new Table2({
|
|
24450
|
+
head: result.columnNames,
|
|
24451
|
+
style: { compact: false, "padding-left": 1, "padding-right": 1 }
|
|
24452
|
+
});
|
|
24453
|
+
result.rows.forEach((row) => {
|
|
24454
|
+
table.push(result.columnNames.map((col) => this.cellToString(row[col])));
|
|
24455
|
+
});
|
|
24456
|
+
let output = table.toString();
|
|
24457
|
+
const footerLines = [];
|
|
24458
|
+
footerLines.push(`Rows: ${result.rowCount}`);
|
|
24459
|
+
if (result.executionTimeMs !== undefined) {
|
|
24460
|
+
footerLines.push(`Execution time: ${result.executionTimeMs}ms`);
|
|
24461
|
+
}
|
|
24462
|
+
if (footerLines.length > 0) {
|
|
24463
|
+
output += `
|
|
24464
|
+
` + footerLines.join(" | ");
|
|
24465
|
+
}
|
|
24466
|
+
if (result.metadata?.securityNotification) {
|
|
24467
|
+
output += `
|
|
24468
|
+
` + result.metadata.securityNotification;
|
|
24469
|
+
}
|
|
24470
|
+
return output;
|
|
24471
|
+
}
|
|
24472
|
+
formatEmptyTable(result) {
|
|
24473
|
+
const table = new Table2({
|
|
24474
|
+
head: result.columnNames,
|
|
24475
|
+
style: { compact: false, "padding-left": 1, "padding-right": 1 }
|
|
24476
|
+
});
|
|
24477
|
+
let output = table.toString();
|
|
24478
|
+
const footerLines = [];
|
|
24479
|
+
footerLines.push(`Rows: ${result.rowCount}`);
|
|
24480
|
+
if (result.executionTimeMs !== undefined) {
|
|
24481
|
+
footerLines.push(`Execution time: ${result.executionTimeMs}ms`);
|
|
24482
|
+
}
|
|
24483
|
+
if (footerLines.length > 0) {
|
|
24484
|
+
output += `
|
|
24485
|
+
` + footerLines.join(" | ");
|
|
24486
|
+
}
|
|
24487
|
+
if (result.metadata?.securityNotification) {
|
|
24488
|
+
output += `
|
|
24489
|
+
` + result.metadata.securityNotification;
|
|
24490
|
+
}
|
|
24491
|
+
return output;
|
|
24492
|
+
}
|
|
24493
|
+
formatJSON(result, compact) {
|
|
24494
|
+
const spacing = compact ? undefined : 2;
|
|
24495
|
+
const output = {
|
|
24496
|
+
rows: result.rows,
|
|
24497
|
+
rowCount: result.rowCount,
|
|
24498
|
+
columnNames: result.columnNames,
|
|
24499
|
+
columnTypes: result.columnTypes,
|
|
24500
|
+
executionTimeMs: result.executionTimeMs,
|
|
24501
|
+
metadata: result.metadata
|
|
24502
|
+
};
|
|
24503
|
+
return JSON.stringify(output, null, spacing);
|
|
24504
|
+
}
|
|
24505
|
+
formatCSV(result) {
|
|
24506
|
+
if (result.rows.length === 0) {
|
|
24507
|
+
let csvOutput = result.columnNames.map((name) => this.escapeCSVField(name)).join(",");
|
|
24508
|
+
if (result.metadata?.securityNotification) {
|
|
24509
|
+
csvOutput += `
|
|
24510
|
+
# ` + result.metadata.securityNotification;
|
|
24511
|
+
}
|
|
24512
|
+
return csvOutput;
|
|
24513
|
+
}
|
|
24514
|
+
const lines = [];
|
|
24515
|
+
lines.push(result.columnNames.map((name) => this.escapeCSVField(name)).join(","));
|
|
24516
|
+
result.rows.forEach((row) => {
|
|
24517
|
+
const csvRow = result.columnNames.map((col) => this.escapeCSVField(row[col])).join(",");
|
|
24518
|
+
lines.push(csvRow);
|
|
24519
|
+
});
|
|
24520
|
+
if (result.metadata?.securityNotification) {
|
|
24521
|
+
lines.push(`# ${result.metadata.securityNotification}`);
|
|
24522
|
+
}
|
|
24523
|
+
return lines.join(`
|
|
24524
|
+
`);
|
|
24525
|
+
}
|
|
24526
|
+
escapeCSVField(value) {
|
|
24527
|
+
if (value === null || value === undefined) {
|
|
24528
|
+
return "";
|
|
24529
|
+
}
|
|
24530
|
+
const str = String(value);
|
|
24531
|
+
if (str.includes(",") || str.includes('"') || str.includes(`
|
|
24532
|
+
`)) {
|
|
24533
|
+
return `"${str.replace(/"/g, '""')}"`;
|
|
24534
|
+
}
|
|
24535
|
+
return str;
|
|
24536
|
+
}
|
|
24537
|
+
cellToString(value) {
|
|
24538
|
+
if (value === null || value === undefined) {
|
|
24539
|
+
return "";
|
|
24540
|
+
}
|
|
24541
|
+
if (typeof value === "object") {
|
|
24542
|
+
return JSON.stringify(value);
|
|
24543
|
+
}
|
|
24544
|
+
return String(value);
|
|
24545
|
+
}
|
|
24546
|
+
}
|
|
24547
|
+
var Table2;
|
|
24548
|
+
var init_query_result_formatter = __esm(() => {
|
|
24549
|
+
Table2 = require_table();
|
|
24550
|
+
});
|
|
24551
|
+
|
|
24552
|
+
// src/formatters/index.ts
|
|
24553
|
+
var init_formatters = __esm(() => {
|
|
24554
|
+
init_table_formatter();
|
|
24555
|
+
init_json_formatter();
|
|
24556
|
+
init_query_result_formatter();
|
|
24557
|
+
});
|
|
24558
|
+
|
|
24559
|
+
// src/core/blacklist-manager.ts
|
|
24560
|
+
class BlacklistManager {
|
|
24561
|
+
config;
|
|
24562
|
+
state;
|
|
24563
|
+
overrideEnabled;
|
|
24564
|
+
constructor(config, overrideEnvValue) {
|
|
24565
|
+
this.config = config;
|
|
24566
|
+
this.overrideEnabled = (overrideEnvValue ?? Bun.env.DBCLI_OVERRIDE_BLACKLIST ?? "") === "true";
|
|
24567
|
+
this.state = this.loadBlacklist();
|
|
24568
|
+
}
|
|
24569
|
+
loadBlacklist() {
|
|
24570
|
+
const tables = new Set;
|
|
24571
|
+
const columns = new Map;
|
|
24572
|
+
const blacklistConfig = this.config.blacklist;
|
|
24573
|
+
if (!blacklistConfig) {
|
|
24574
|
+
return { tables, columns };
|
|
24575
|
+
}
|
|
24576
|
+
if (Array.isArray(blacklistConfig.tables)) {
|
|
24577
|
+
for (const tableName of blacklistConfig.tables) {
|
|
24578
|
+
if (typeof tableName === "string") {
|
|
24579
|
+
tables.add(tableName.toLowerCase());
|
|
24580
|
+
} else {
|
|
24581
|
+
console.warn(`[BlacklistManager] Invalid table name in blacklist config: ${JSON.stringify(tableName)}`);
|
|
24582
|
+
}
|
|
24583
|
+
}
|
|
24584
|
+
} else if (blacklistConfig.tables !== undefined) {
|
|
24585
|
+
console.warn("[BlacklistManager] blacklist.tables must be an array, ignoring");
|
|
24586
|
+
}
|
|
24587
|
+
if (blacklistConfig.columns && typeof blacklistConfig.columns === "object" && !Array.isArray(blacklistConfig.columns)) {
|
|
24588
|
+
for (const [tableName, cols] of Object.entries(blacklistConfig.columns)) {
|
|
24589
|
+
if (typeof tableName !== "string") {
|
|
24590
|
+
console.warn(`[BlacklistManager] Invalid table name key in columns config: ${JSON.stringify(tableName)}`);
|
|
24591
|
+
continue;
|
|
24592
|
+
}
|
|
24593
|
+
if (!Array.isArray(cols)) {
|
|
24594
|
+
console.warn(`[BlacklistManager] blacklist.columns["${tableName}"] must be an array, ignoring`);
|
|
24595
|
+
continue;
|
|
24596
|
+
}
|
|
24597
|
+
const columnSet = new Set;
|
|
24598
|
+
for (const col of cols) {
|
|
24599
|
+
if (typeof col === "string") {
|
|
24600
|
+
columnSet.add(col);
|
|
24601
|
+
} else {
|
|
24602
|
+
console.warn(`[BlacklistManager] Invalid column name in blacklist.columns["${tableName}"]: ${JSON.stringify(col)}`);
|
|
24603
|
+
}
|
|
24604
|
+
}
|
|
24605
|
+
if (columnSet.size > 0) {
|
|
24606
|
+
columns.set(tableName.toLowerCase(), columnSet);
|
|
24607
|
+
}
|
|
24608
|
+
}
|
|
24609
|
+
} else if (blacklistConfig.columns !== undefined) {
|
|
24610
|
+
console.warn("[BlacklistManager] blacklist.columns must be an object, ignoring");
|
|
24611
|
+
}
|
|
24612
|
+
return { tables, columns };
|
|
24613
|
+
}
|
|
24614
|
+
isTableBlacklisted(tableName) {
|
|
24615
|
+
return this.state.tables.has(tableName.toLowerCase());
|
|
24616
|
+
}
|
|
24617
|
+
isColumnBlacklisted(tableName, columnName) {
|
|
24618
|
+
const columnSet = this.state.columns.get(tableName.toLowerCase());
|
|
24619
|
+
if (!columnSet) {
|
|
24620
|
+
return false;
|
|
24621
|
+
}
|
|
24622
|
+
return columnSet.has(columnName);
|
|
24623
|
+
}
|
|
24624
|
+
getBlacklistedColumns(tableName) {
|
|
24625
|
+
const columnSet = this.state.columns.get(tableName.toLowerCase());
|
|
24626
|
+
if (!columnSet) {
|
|
24627
|
+
return [];
|
|
24628
|
+
}
|
|
24629
|
+
return Array.from(columnSet);
|
|
24630
|
+
}
|
|
24631
|
+
canOverrideBlacklist() {
|
|
24632
|
+
return this.overrideEnabled;
|
|
24633
|
+
}
|
|
24634
|
+
getState() {
|
|
24635
|
+
return this.state;
|
|
24636
|
+
}
|
|
24637
|
+
}
|
|
24638
|
+
|
|
24314
24639
|
// src/types/blacklist.ts
|
|
24315
24640
|
var BlacklistError;
|
|
24316
24641
|
var init_blacklist = __esm(() => {
|
|
@@ -24326,6 +24651,87 @@ var init_blacklist = __esm(() => {
|
|
|
24326
24651
|
};
|
|
24327
24652
|
});
|
|
24328
24653
|
|
|
24654
|
+
// src/core/blacklist-validator.ts
|
|
24655
|
+
class BlacklistValidator {
|
|
24656
|
+
manager;
|
|
24657
|
+
constructor(manager) {
|
|
24658
|
+
this.manager = manager;
|
|
24659
|
+
}
|
|
24660
|
+
checkTableBlacklist(operation, tableName, _tableList = []) {
|
|
24661
|
+
if (this.manager.canOverrideBlacklist()) {
|
|
24662
|
+
const message = t_vars("warnings.blacklist_override_used", {
|
|
24663
|
+
operation,
|
|
24664
|
+
table: tableName
|
|
24665
|
+
});
|
|
24666
|
+
console.error(message);
|
|
24667
|
+
return;
|
|
24668
|
+
}
|
|
24669
|
+
if (this.manager.isTableBlacklisted(tableName)) {
|
|
24670
|
+
const message = t_vars("errors.table_blacklisted", {
|
|
24671
|
+
table: tableName,
|
|
24672
|
+
operation
|
|
24673
|
+
});
|
|
24674
|
+
throw new BlacklistError(message, tableName, operation);
|
|
24675
|
+
}
|
|
24676
|
+
}
|
|
24677
|
+
checkColumnBlacklistOnWrite(tableName, fields, operation = "WRITE") {
|
|
24678
|
+
const blacklisted = this.manager.getBlacklistedColumns(tableName);
|
|
24679
|
+
if (blacklisted.length === 0 || fields.length === 0) {
|
|
24680
|
+
return;
|
|
24681
|
+
}
|
|
24682
|
+
const conflicts = fields.filter((f) => blacklisted.includes(f));
|
|
24683
|
+
if (conflicts.length === 0) {
|
|
24684
|
+
return;
|
|
24685
|
+
}
|
|
24686
|
+
if (this.manager.canOverrideBlacklist()) {
|
|
24687
|
+
const warning = t_vars("warnings.blacklist_override_used", {
|
|
24688
|
+
operation,
|
|
24689
|
+
table: tableName
|
|
24690
|
+
});
|
|
24691
|
+
console.error(`${warning} (columns: ${conflicts.join(", ")})`);
|
|
24692
|
+
return;
|
|
24693
|
+
}
|
|
24694
|
+
const message = t_vars("errors.column_blacklisted_write", {
|
|
24695
|
+
table: tableName,
|
|
24696
|
+
operation,
|
|
24697
|
+
columns: conflicts.join(", ")
|
|
24698
|
+
});
|
|
24699
|
+
throw new BlacklistError(message, tableName, operation);
|
|
24700
|
+
}
|
|
24701
|
+
filterColumns(tableName, rows, columnList) {
|
|
24702
|
+
const blacklistedColumns = this.manager.getBlacklistedColumns(tableName);
|
|
24703
|
+
if (blacklistedColumns.length === 0) {
|
|
24704
|
+
return { filteredRows: rows, omittedColumns: [] };
|
|
24705
|
+
}
|
|
24706
|
+
const omittedColumns = columnList.filter((col) => blacklistedColumns.includes(col));
|
|
24707
|
+
if (omittedColumns.length === 0) {
|
|
24708
|
+
return { filteredRows: rows, omittedColumns: [] };
|
|
24709
|
+
}
|
|
24710
|
+
const filteredRows = rows.map((row) => {
|
|
24711
|
+
const newRow = {};
|
|
24712
|
+
for (const [key, value] of Object.entries(row)) {
|
|
24713
|
+
if (!omittedColumns.includes(key)) {
|
|
24714
|
+
newRow[key] = value;
|
|
24715
|
+
}
|
|
24716
|
+
}
|
|
24717
|
+
return newRow;
|
|
24718
|
+
});
|
|
24719
|
+
return { filteredRows, omittedColumns };
|
|
24720
|
+
}
|
|
24721
|
+
buildSecurityNotification(_tableName, omittedColumns) {
|
|
24722
|
+
if (omittedColumns.length === 0) {
|
|
24723
|
+
return "";
|
|
24724
|
+
}
|
|
24725
|
+
return t_vars("security.columns_omitted", {
|
|
24726
|
+
count: omittedColumns.length
|
|
24727
|
+
});
|
|
24728
|
+
}
|
|
24729
|
+
}
|
|
24730
|
+
var init_blacklist_validator = __esm(() => {
|
|
24731
|
+
init_blacklist();
|
|
24732
|
+
init_message_loader();
|
|
24733
|
+
});
|
|
24734
|
+
|
|
24329
24735
|
// src/core/audit/lock.ts
|
|
24330
24736
|
import { hostname } from "os";
|
|
24331
24737
|
import { dirname } from "path";
|
|
@@ -24827,8 +25233,75 @@ var init_integration_helper = __esm(() => {
|
|
|
24827
25233
|
_loggers = new Map;
|
|
24828
25234
|
});
|
|
24829
25235
|
|
|
25236
|
+
// src/core/mongo/path-matcher.ts
|
|
25237
|
+
function compilePatterns(raw) {
|
|
25238
|
+
const patterns = [];
|
|
25239
|
+
const rejected = [];
|
|
25240
|
+
for (const entry of raw) {
|
|
25241
|
+
if (typeof entry !== "string" || entry.length === 0) {
|
|
25242
|
+
rejected.push({ raw: String(entry ?? ""), reason: "must be a non-empty string" });
|
|
25243
|
+
continue;
|
|
25244
|
+
}
|
|
25245
|
+
const segments = entry.split(".");
|
|
25246
|
+
if (segments.length === 0 || segments.some((s) => s.length === 0)) {
|
|
25247
|
+
rejected.push({ raw: entry, reason: "empty path segment" });
|
|
25248
|
+
continue;
|
|
25249
|
+
}
|
|
25250
|
+
const wildcardIndices = segments.map((s, i) => s.includes("*") ? i : -1).filter((i) => i >= 0);
|
|
25251
|
+
if (wildcardIndices.length === 0) {
|
|
25252
|
+
patterns.push({ raw: entry, segments, wildcardTail: false });
|
|
25253
|
+
continue;
|
|
25254
|
+
}
|
|
25255
|
+
const lastIndex = segments.length - 1;
|
|
25256
|
+
const onlyTail = wildcardIndices.length === 1 && wildcardIndices[0] === lastIndex && segments[lastIndex] === "*";
|
|
25257
|
+
if (!onlyTail) {
|
|
25258
|
+
rejected.push({ raw: entry, reason: "wildcard must be the final segment" });
|
|
25259
|
+
continue;
|
|
25260
|
+
}
|
|
25261
|
+
if (segments.length === 1) {
|
|
25262
|
+
rejected.push({ raw: entry, reason: "wildcard must have a parent path" });
|
|
25263
|
+
continue;
|
|
25264
|
+
}
|
|
25265
|
+
patterns.push({ raw: entry, segments: segments.slice(0, -1), wildcardTail: true });
|
|
25266
|
+
}
|
|
25267
|
+
return { patterns, rejected };
|
|
25268
|
+
}
|
|
25269
|
+
function matchAny(path3, patterns) {
|
|
25270
|
+
if (patterns.length === 0)
|
|
25271
|
+
return false;
|
|
25272
|
+
const pathSegments = path3.split(".");
|
|
25273
|
+
for (const pat of patterns) {
|
|
25274
|
+
if (pat.wildcardTail) {
|
|
25275
|
+
if (pathSegments.length < pat.segments.length)
|
|
25276
|
+
continue;
|
|
25277
|
+
let ok = true;
|
|
25278
|
+
for (let i = 0;i < pat.segments.length; i++) {
|
|
25279
|
+
if (pat.segments[i] !== pathSegments[i]) {
|
|
25280
|
+
ok = false;
|
|
25281
|
+
break;
|
|
25282
|
+
}
|
|
25283
|
+
}
|
|
25284
|
+
if (ok)
|
|
25285
|
+
return true;
|
|
25286
|
+
} else {
|
|
25287
|
+
if (pat.segments.length !== pathSegments.length)
|
|
25288
|
+
continue;
|
|
25289
|
+
let ok = true;
|
|
25290
|
+
for (let i = 0;i < pat.segments.length; i++) {
|
|
25291
|
+
if (pat.segments[i] !== pathSegments[i]) {
|
|
25292
|
+
ok = false;
|
|
25293
|
+
break;
|
|
25294
|
+
}
|
|
25295
|
+
}
|
|
25296
|
+
if (ok)
|
|
25297
|
+
return true;
|
|
25298
|
+
}
|
|
25299
|
+
}
|
|
25300
|
+
return false;
|
|
25301
|
+
}
|
|
25302
|
+
|
|
24830
25303
|
// src/core/recovery/types.ts
|
|
24831
|
-
var RECOVERY_SCHEMA_VERSION = 1, RECOVERY_CODES, SchemaCacheMissingError, RECOVERY_CODE_METADATA;
|
|
25304
|
+
var RECOVERY_SCHEMA_VERSION = 1, RECOVERY_CODES, MAX_BRANCH_STEPS = 6, MAX_BRANCH_COUNT = 8, SchemaCacheMissingError, RECOVERY_CODE_METADATA;
|
|
24832
25305
|
var init_types3 = __esm(() => {
|
|
24833
25306
|
RECOVERY_CODES = [
|
|
24834
25307
|
"CONFIG_MISSING",
|
|
@@ -24929,7 +25402,7 @@ var init_types3 = __esm(() => {
|
|
|
24929
25402
|
};
|
|
24930
25403
|
});
|
|
24931
25404
|
|
|
24932
|
-
// src/core/recovery/
|
|
25405
|
+
// src/core/recovery/shell-quote.ts
|
|
24933
25406
|
function shellQuote(value) {
|
|
24934
25407
|
if (value.length === 0)
|
|
24935
25408
|
return "''";
|
|
@@ -24937,6 +25410,8 @@ function shellQuote(value) {
|
|
|
24937
25410
|
return value;
|
|
24938
25411
|
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
24939
25412
|
}
|
|
25413
|
+
|
|
25414
|
+
// src/core/recovery/recovery-steps.ts
|
|
24940
25415
|
function dryRunStepForWrite(ctx, quotedTable, placeholders) {
|
|
24941
25416
|
if (!ctx.writeOperation)
|
|
24942
25417
|
return null;
|
|
@@ -25199,6 +25674,7 @@ function draftsForCode(code, ctx) {
|
|
|
25199
25674
|
}
|
|
25200
25675
|
}
|
|
25201
25676
|
var MAX_RECOVERY_STEPS = 6;
|
|
25677
|
+
var init_recovery_steps = () => {};
|
|
25202
25678
|
|
|
25203
25679
|
// src/core/permission-guard.ts
|
|
25204
25680
|
var exports_permission_guard = {};
|
|
@@ -25821,19 +26297,222 @@ var init_verify_steps = __esm(() => {
|
|
|
25821
26297
|
};
|
|
25822
26298
|
});
|
|
25823
26299
|
|
|
26300
|
+
// src/core/recovery/connection-branches.ts
|
|
26301
|
+
function parseDoctorJson(stdoutSummary) {
|
|
26302
|
+
if (!stdoutSummary || stdoutSummary.length === 0)
|
|
26303
|
+
return null;
|
|
26304
|
+
let raw;
|
|
26305
|
+
try {
|
|
26306
|
+
raw = JSON.parse(stdoutSummary);
|
|
26307
|
+
} catch {
|
|
26308
|
+
return null;
|
|
26309
|
+
}
|
|
26310
|
+
if (typeof raw !== "object" || raw === null)
|
|
26311
|
+
return null;
|
|
26312
|
+
const obj = raw;
|
|
26313
|
+
if (!Array.isArray(obj.results))
|
|
26314
|
+
return null;
|
|
26315
|
+
const entries = [];
|
|
26316
|
+
for (const r of obj.results) {
|
|
26317
|
+
if (typeof r !== "object" || r === null)
|
|
26318
|
+
return null;
|
|
26319
|
+
const e = r;
|
|
26320
|
+
if (typeof e.group !== "string" || typeof e.label !== "string" || typeof e.status !== "string" || typeof e.message !== "string") {
|
|
26321
|
+
return null;
|
|
26322
|
+
}
|
|
26323
|
+
entries.push({ group: e.group, label: e.label, status: e.status, message: e.message });
|
|
26324
|
+
}
|
|
26325
|
+
return { results: entries, hasError: Boolean(obj.hasError) };
|
|
26326
|
+
}
|
|
26327
|
+
function anyKeyword(message, keywords) {
|
|
26328
|
+
const m = message.toLowerCase();
|
|
26329
|
+
return keywords.some((kw) => m.includes(kw));
|
|
26330
|
+
}
|
|
26331
|
+
function matchConnectionBranch(prev, opts = {}) {
|
|
26332
|
+
const doctor = parseDoctorJson(prev.stdoutSummary);
|
|
26333
|
+
if (doctor === null) {
|
|
26334
|
+
opts.trace?.({ outcome: "parse-fail", detail: "doctor JSON parse failed" });
|
|
26335
|
+
return null;
|
|
26336
|
+
}
|
|
26337
|
+
if (doctor.results.every((r) => r.status !== "error")) {
|
|
26338
|
+
opts.trace?.({ outcome: "matched", branchId: "doctor-clean" });
|
|
26339
|
+
return "doctor-clean";
|
|
26340
|
+
}
|
|
26341
|
+
if (doctor.results.some((r) => r.status === "error" && CONFIG_LABELS.has(r.label))) {
|
|
26342
|
+
opts.trace?.({ outcome: "matched", branchId: "doctor-config-missing" });
|
|
26343
|
+
return "doctor-config-missing";
|
|
26344
|
+
}
|
|
26345
|
+
const connectionErrors = doctor.results.filter((r) => r.status === "error" && r.label === "Connection");
|
|
26346
|
+
if (connectionErrors.some((r) => anyKeyword(r.message, AUTH_KEYWORDS))) {
|
|
26347
|
+
opts.trace?.({ outcome: "matched", branchId: "doctor-auth-error" });
|
|
26348
|
+
return "doctor-auth-error";
|
|
26349
|
+
}
|
|
26350
|
+
if (connectionErrors.some((r) => anyKeyword(r.message, NETWORK_KEYWORDS))) {
|
|
26351
|
+
opts.trace?.({ outcome: "matched", branchId: "doctor-network-error" });
|
|
26352
|
+
return "doctor-network-error";
|
|
26353
|
+
}
|
|
26354
|
+
opts.trace?.({ outcome: "no-match" });
|
|
26355
|
+
return null;
|
|
26356
|
+
}
|
|
26357
|
+
function renumber(branchId, drafts) {
|
|
26358
|
+
return drafts.map((d, i) => ({ ...d, order: i + 1, branchId }));
|
|
26359
|
+
}
|
|
26360
|
+
function planDoctorClean() {
|
|
26361
|
+
const drafts = [
|
|
26362
|
+
{
|
|
26363
|
+
command: "dbcli inspect --for-agent",
|
|
26364
|
+
rationale: "Re-anchor in the current context and confirm schemaCache.available; if stale, schema --refresh before retry.",
|
|
26365
|
+
risk: "readonly",
|
|
26366
|
+
expects: "JSON snapshot; check connection.online=true, schemaCache.available."
|
|
26367
|
+
}
|
|
26368
|
+
];
|
|
26369
|
+
return {
|
|
26370
|
+
description: "Doctor reports no errors. Likely a transient failure \u2014 verify baseline state, then retry the original command.",
|
|
26371
|
+
steps: renumber("doctor-clean", drafts)
|
|
26372
|
+
};
|
|
26373
|
+
}
|
|
26374
|
+
function planDoctorConfigMissing() {
|
|
26375
|
+
const drafts = [
|
|
26376
|
+
{
|
|
26377
|
+
command: "dbcli init",
|
|
26378
|
+
rationale: "No usable config; run init to create it.",
|
|
26379
|
+
risk: "write",
|
|
26380
|
+
interactive: true,
|
|
26381
|
+
expects: "Init wizard prompts; new .dbcli written."
|
|
26382
|
+
},
|
|
26383
|
+
{
|
|
26384
|
+
command: "dbcli inspect --no-connect --format json",
|
|
26385
|
+
rationale: "Verify config shape after init.",
|
|
26386
|
+
risk: "readonly",
|
|
26387
|
+
expects: "JSON snapshot with system/permission/blacklist sections populated."
|
|
26388
|
+
}
|
|
26389
|
+
];
|
|
26390
|
+
return {
|
|
26391
|
+
description: "Doctor flagged a config-level failure. Rebuild config before reattempting connection.",
|
|
26392
|
+
steps: renumber("doctor-config-missing", drafts)
|
|
26393
|
+
};
|
|
26394
|
+
}
|
|
26395
|
+
function planDoctorAuthError() {
|
|
26396
|
+
const drafts = [
|
|
26397
|
+
{
|
|
26398
|
+
command: "dbcli init --force",
|
|
26399
|
+
rationale: "Re-run init focused on credentials; --force overwrites the existing config in place.",
|
|
26400
|
+
risk: "write",
|
|
26401
|
+
interactive: true,
|
|
26402
|
+
expects: "Init wizard accepts new user/password; config rewritten."
|
|
26403
|
+
},
|
|
26404
|
+
{
|
|
26405
|
+
command: "dbcli inspect --no-connect --format json",
|
|
26406
|
+
rationale: "Confirm config now resolves credentials.",
|
|
26407
|
+
risk: "readonly",
|
|
26408
|
+
expects: "JSON snapshot reflecting updated credentials."
|
|
26409
|
+
}
|
|
26410
|
+
];
|
|
26411
|
+
return {
|
|
26412
|
+
description: "Doctor confirms credentials were rejected. Re-init with --force to overwrite the credential fields.",
|
|
26413
|
+
steps: renumber("doctor-auth-error", drafts)
|
|
26414
|
+
};
|
|
26415
|
+
}
|
|
26416
|
+
function planDoctorNetworkError(ctx) {
|
|
26417
|
+
const drafts = [
|
|
26418
|
+
{
|
|
26419
|
+
command: "dbcli inspect --no-connect --format json",
|
|
26420
|
+
rationale: "Compare expected vs actual host/port without a live probe.",
|
|
26421
|
+
risk: "readonly",
|
|
26422
|
+
expects: "JSON snapshot with connection.name/host/port."
|
|
26423
|
+
}
|
|
26424
|
+
];
|
|
26425
|
+
if (ctx.connectionName) {
|
|
26426
|
+
drafts.push({
|
|
26427
|
+
command: `dbcli use ${shellQuote(ctx.connectionName)}`,
|
|
26428
|
+
rationale: "Re-select the failing named connection so subsequent commands target it explicitly.",
|
|
26429
|
+
risk: "write",
|
|
26430
|
+
dbWrite: false,
|
|
26431
|
+
expects: "Active connection switched."
|
|
26432
|
+
});
|
|
26433
|
+
}
|
|
26434
|
+
drafts.push({
|
|
26435
|
+
command: "dbcli init --force",
|
|
26436
|
+
rationale: "If addressing is wrong, rewrite host/port via init.",
|
|
26437
|
+
risk: "write",
|
|
26438
|
+
interactive: true,
|
|
26439
|
+
expects: "Init wizard accepts new host/port; config rewritten."
|
|
26440
|
+
});
|
|
26441
|
+
return {
|
|
26442
|
+
description: "Doctor confirms a network-level failure (host / port / DNS / timeout). Inspect expected vs actual addressing, optionally re-select named connection, then re-init host/port.",
|
|
26443
|
+
steps: renumber("doctor-network-error", drafts)
|
|
26444
|
+
};
|
|
26445
|
+
}
|
|
26446
|
+
function buildConnectionBranches(ctx) {
|
|
26447
|
+
const branches = {
|
|
26448
|
+
"doctor-clean": planDoctorClean(),
|
|
26449
|
+
"doctor-config-missing": planDoctorConfigMissing(),
|
|
26450
|
+
"doctor-auth-error": planDoctorAuthError(),
|
|
26451
|
+
"doctor-network-error": planDoctorNetworkError(ctx)
|
|
26452
|
+
};
|
|
26453
|
+
return {
|
|
26454
|
+
branches,
|
|
26455
|
+
branchFork: { after: 1, branchIds: [...CONNECTION_BRANCH_IDS] }
|
|
26456
|
+
};
|
|
26457
|
+
}
|
|
26458
|
+
var CONNECTION_BRANCH_IDS, CONFIG_LABELS, AUTH_KEYWORDS, NETWORK_KEYWORDS, CONNECTION_RESOLVER_KEYWORDS;
|
|
26459
|
+
var init_connection_branches = __esm(() => {
|
|
26460
|
+
CONNECTION_BRANCH_IDS = [
|
|
26461
|
+
"doctor-clean",
|
|
26462
|
+
"doctor-config-missing",
|
|
26463
|
+
"doctor-auth-error",
|
|
26464
|
+
"doctor-network-error"
|
|
26465
|
+
];
|
|
26466
|
+
CONFIG_LABELS = new Set([
|
|
26467
|
+
"Config exists",
|
|
26468
|
+
"Default connection",
|
|
26469
|
+
"V2 config validation",
|
|
26470
|
+
"Config valid"
|
|
26471
|
+
]);
|
|
26472
|
+
AUTH_KEYWORDS = [
|
|
26473
|
+
"auth",
|
|
26474
|
+
"password",
|
|
26475
|
+
"credentials",
|
|
26476
|
+
"credential",
|
|
26477
|
+
"permission denied",
|
|
26478
|
+
"access denied",
|
|
26479
|
+
"login"
|
|
26480
|
+
];
|
|
26481
|
+
NETWORK_KEYWORDS = [
|
|
26482
|
+
"host",
|
|
26483
|
+
"port",
|
|
26484
|
+
"refused",
|
|
26485
|
+
"timeout",
|
|
26486
|
+
"timed out",
|
|
26487
|
+
"unreachable",
|
|
26488
|
+
"enotfound",
|
|
26489
|
+
"econnrefused",
|
|
26490
|
+
"etimedout",
|
|
26491
|
+
"eai_again",
|
|
26492
|
+
"dns"
|
|
26493
|
+
];
|
|
26494
|
+
CONNECTION_RESOLVER_KEYWORDS = {
|
|
26495
|
+
auth: AUTH_KEYWORDS,
|
|
26496
|
+
network: NETWORK_KEYWORDS,
|
|
26497
|
+
configLabels: [...CONFIG_LABELS]
|
|
26498
|
+
};
|
|
26499
|
+
});
|
|
26500
|
+
|
|
25824
26501
|
// src/core/recovery/classify.ts
|
|
25825
26502
|
function classifyError(error, ctx) {
|
|
25826
26503
|
const recoveryError = errorToRecoveryError(error, ctx);
|
|
25827
26504
|
const ctxWithDetails = applyDetailsToContext(ctx, recoveryError);
|
|
25828
26505
|
const recovery = stepsForCode(recoveryError.code, ctxWithDetails);
|
|
25829
26506
|
const verify = verifyForCode(recoveryError.code, ctxWithDetails);
|
|
26507
|
+
const branchExtras = recoveryError.category === "connection" ? buildConnectionBranches(ctxWithDetails) : null;
|
|
25830
26508
|
return {
|
|
25831
26509
|
schemaVersion: RECOVERY_SCHEMA_VERSION,
|
|
25832
26510
|
generatedAt: new Date().toISOString(),
|
|
25833
26511
|
ok: false,
|
|
25834
26512
|
error: recoveryError,
|
|
25835
26513
|
recovery,
|
|
25836
|
-
...verify !== null ? { verify } : {}
|
|
26514
|
+
...verify !== null ? { verify } : {},
|
|
26515
|
+
...branchExtras !== null ? { branches: branchExtras.branches, branchFork: branchExtras.branchFork } : {}
|
|
25837
26516
|
};
|
|
25838
26517
|
}
|
|
25839
26518
|
function errorToRecoveryError(error, ctx) {
|
|
@@ -25924,7 +26603,9 @@ var init_classify = __esm(() => {
|
|
|
25924
26603
|
init_permission_guard();
|
|
25925
26604
|
init_blacklist();
|
|
25926
26605
|
init_types4();
|
|
26606
|
+
init_recovery_steps();
|
|
25927
26607
|
init_verify_steps();
|
|
26608
|
+
init_connection_branches();
|
|
25928
26609
|
init_types3();
|
|
25929
26610
|
});
|
|
25930
26611
|
|
|
@@ -26950,20 +27631,91 @@ var init_next_step_schema = __esm(() => {
|
|
|
26950
27631
|
});
|
|
26951
27632
|
|
|
26952
27633
|
// src/core/recovery/next-step.ts
|
|
26953
|
-
function
|
|
27634
|
+
function resolverFor(code) {
|
|
27635
|
+
switch (code) {
|
|
27636
|
+
case "CONN_REFUSED":
|
|
27637
|
+
case "CONN_AUTH_FAILED":
|
|
27638
|
+
case "CONN_TIMEOUT":
|
|
27639
|
+
case "CONN_HOST_NOT_FOUND":
|
|
27640
|
+
case "CONN_UNKNOWN":
|
|
27641
|
+
return (prev, opts) => matchConnectionBranch(prev, opts);
|
|
27642
|
+
default:
|
|
27643
|
+
return null;
|
|
27644
|
+
}
|
|
27645
|
+
}
|
|
27646
|
+
function assertAfterStep(afterStep) {
|
|
26954
27647
|
if (!Number.isInteger(afterStep)) {
|
|
26955
27648
|
throw new RangeError(`afterStep must be an integer (got ${afterStep})`);
|
|
26956
27649
|
}
|
|
26957
27650
|
if (afterStep < 1) {
|
|
26958
27651
|
throw new RangeError(`afterStep must be >= 1 (got ${afterStep})`);
|
|
26959
27652
|
}
|
|
27653
|
+
}
|
|
27654
|
+
function nextStepFromEnvelope(envelope, afterStep, prevResult, options = {}) {
|
|
27655
|
+
assertAfterStep(afterStep);
|
|
27656
|
+
if (options.branchId !== undefined) {
|
|
27657
|
+
if (!envelope.branches || !envelope.branches[options.branchId]) {
|
|
27658
|
+
const valid = envelope.branches ? Object.keys(envelope.branches).join(", ") : "<none>";
|
|
27659
|
+
throw new RangeError(`Branch '${options.branchId}' not found in envelope (valid: ${valid}).`);
|
|
27660
|
+
}
|
|
27661
|
+
const plan = envelope.branches[options.branchId];
|
|
27662
|
+
if (afterStep > plan.steps.length) {
|
|
27663
|
+
throw new RangeError(`afterStep ${afterStep} exceeds branch '${options.branchId}' length ${plan.steps.length}`);
|
|
27664
|
+
}
|
|
27665
|
+
if (afterStep === plan.steps.length) {
|
|
27666
|
+
return {
|
|
27667
|
+
kind: "done",
|
|
27668
|
+
branchId: options.branchId,
|
|
27669
|
+
cursor: afterStep,
|
|
27670
|
+
totalSteps: plan.steps.length
|
|
27671
|
+
};
|
|
27672
|
+
}
|
|
27673
|
+
return {
|
|
27674
|
+
kind: "step",
|
|
27675
|
+
branchId: options.branchId,
|
|
27676
|
+
step: plan.steps[afterStep],
|
|
27677
|
+
cursor: afterStep + 1,
|
|
27678
|
+
totalSteps: plan.steps.length
|
|
27679
|
+
};
|
|
27680
|
+
}
|
|
26960
27681
|
if (afterStep > envelope.recovery.length) {
|
|
26961
27682
|
throw new RangeError(`afterStep ${afterStep} exceeds plan length ${envelope.recovery.length}`);
|
|
26962
27683
|
}
|
|
26963
|
-
if (
|
|
26964
|
-
|
|
26965
|
-
|
|
27684
|
+
if (envelope.branchFork?.after === afterStep && envelope.branches) {
|
|
27685
|
+
const resolver = resolverFor(envelope.error.code);
|
|
27686
|
+
if (resolver !== null) {
|
|
27687
|
+
const traceSink = options.trace ? (line) => {
|
|
27688
|
+
const tail = line.detail ?? line.branchId ?? "";
|
|
27689
|
+
options.trace(`connection-branches: ${line.outcome}${tail ? ` ${tail}` : ""}`);
|
|
27690
|
+
} : undefined;
|
|
27691
|
+
const branchId = resolver(prevResult, { trace: traceSink });
|
|
27692
|
+
if (branchId !== null) {
|
|
27693
|
+
const plan = envelope.branches[branchId];
|
|
27694
|
+
if (plan && plan.steps.length >= 1) {
|
|
27695
|
+
return {
|
|
27696
|
+
kind: "step",
|
|
27697
|
+
branchId,
|
|
27698
|
+
step: plan.steps[0],
|
|
27699
|
+
cursor: 1,
|
|
27700
|
+
totalSteps: plan.steps.length
|
|
27701
|
+
};
|
|
27702
|
+
}
|
|
27703
|
+
}
|
|
27704
|
+
}
|
|
27705
|
+
}
|
|
27706
|
+
if (afterStep === envelope.recovery.length) {
|
|
27707
|
+
return { kind: "done", cursor: afterStep, totalSteps: envelope.recovery.length };
|
|
27708
|
+
}
|
|
27709
|
+
return {
|
|
27710
|
+
kind: "step",
|
|
27711
|
+
step: envelope.recovery[afterStep],
|
|
27712
|
+
cursor: afterStep + 1,
|
|
27713
|
+
totalSteps: envelope.recovery.length
|
|
27714
|
+
};
|
|
26966
27715
|
}
|
|
27716
|
+
var init_next_step = __esm(() => {
|
|
27717
|
+
init_connection_branches();
|
|
27718
|
+
});
|
|
26967
27719
|
|
|
26968
27720
|
// src/core/recovery/next-render-json.ts
|
|
26969
27721
|
function renderNextJson(result) {
|
|
@@ -26977,6 +27729,12 @@ function renderNextMarkdown(result) {
|
|
|
26977
27729
|
lines.push("");
|
|
26978
27730
|
lines.push(`*Source:* \`${result.source.kind}\` \u2192 \`${result.source.path}\``);
|
|
26979
27731
|
lines.push(`errorCode: \`${result.errorCode}\``);
|
|
27732
|
+
if (result.branchId !== undefined) {
|
|
27733
|
+
lines.push(`**Branch:** \`${result.branchId}\``);
|
|
27734
|
+
if (result.branchDescription !== undefined) {
|
|
27735
|
+
lines.push(`**Branch description:** ${result.branchDescription}`);
|
|
27736
|
+
}
|
|
27737
|
+
}
|
|
26980
27738
|
lines.push("");
|
|
26981
27739
|
if (result.kind === "step" && result.step) {
|
|
26982
27740
|
lines.push(`## Next step (${result.cursor} of ${result.totalSteps})`);
|
|
@@ -27035,12 +27793,15 @@ __export(exports_recovery, {
|
|
|
27035
27793
|
RECOVERY_CODES: () => RECOVERY_CODES,
|
|
27036
27794
|
NEXT_SCHEMA_VERSION: () => NEXT_SCHEMA_VERSION,
|
|
27037
27795
|
MAX_RECOVERY_STEPS: () => MAX_RECOVERY_STEPS,
|
|
27796
|
+
MAX_BRANCH_STEPS: () => MAX_BRANCH_STEPS,
|
|
27797
|
+
MAX_BRANCH_COUNT: () => MAX_BRANCH_COUNT,
|
|
27038
27798
|
LAST_ENVELOPE_PATH: () => LAST_ENVELOPE_PATH,
|
|
27039
27799
|
EXIT_CODE: () => EXIT_CODE,
|
|
27040
27800
|
APPLY_SCHEMA_VERSION: () => APPLY_SCHEMA_VERSION
|
|
27041
27801
|
});
|
|
27042
27802
|
var init_recovery = __esm(() => {
|
|
27043
27803
|
init_types3();
|
|
27804
|
+
init_recovery_steps();
|
|
27044
27805
|
init_classify();
|
|
27045
27806
|
init_render_markdown();
|
|
27046
27807
|
init_emit();
|
|
@@ -27050,6 +27811,7 @@ var init_recovery = __esm(() => {
|
|
|
27050
27811
|
init_verify_steps();
|
|
27051
27812
|
init_apply_verify();
|
|
27052
27813
|
init_next_step_schema();
|
|
27814
|
+
init_next_step();
|
|
27053
27815
|
});
|
|
27054
27816
|
|
|
27055
27817
|
// src/utils/package-root.ts
|
|
@@ -27084,6 +27846,38 @@ var init_package_root = __esm(() => {
|
|
|
27084
27846
|
HERE = import.meta.dir;
|
|
27085
27847
|
});
|
|
27086
27848
|
|
|
27849
|
+
// src/formatters/html-formatter.ts
|
|
27850
|
+
async function generateHtmlReport(payload) {
|
|
27851
|
+
const templatePath = packageAssetPath("ui-template.html");
|
|
27852
|
+
const templateFile = Bun.file(templatePath);
|
|
27853
|
+
if (!await templateFile.exists()) {
|
|
27854
|
+
throw new Error(`UI template not found at ${templatePath}. Please run 'bun run build' first.`);
|
|
27855
|
+
}
|
|
27856
|
+
let html = await templateFile.text();
|
|
27857
|
+
const jsonPayload = JSON.stringify(payload).replace(/</g, "\\u003c");
|
|
27858
|
+
const injection = `window.__DBCLI_PAYLOAD__ = ${jsonPayload};`;
|
|
27859
|
+
html = html.replace("/*DBCLI_PAYLOAD*/", () => injection);
|
|
27860
|
+
return html;
|
|
27861
|
+
}
|
|
27862
|
+
var init_html_formatter = __esm(() => {
|
|
27863
|
+
init_package_root();
|
|
27864
|
+
});
|
|
27865
|
+
|
|
27866
|
+
// src/utils/opener.ts
|
|
27867
|
+
import open2 from "open";
|
|
27868
|
+
async function openInBrowser(target) {
|
|
27869
|
+
if (process.env.DBCLI_NO_OPEN === "1" || false) {
|
|
27870
|
+
console.log(`[Opener] DBCLI_NO_OPEN is set. Skipping browser launch for: ${target}`);
|
|
27871
|
+
return;
|
|
27872
|
+
}
|
|
27873
|
+
try {
|
|
27874
|
+
await open2(target);
|
|
27875
|
+
} catch (err) {
|
|
27876
|
+
console.error(`[Opener] Failed to open ${target}:`, err);
|
|
27877
|
+
}
|
|
27878
|
+
}
|
|
27879
|
+
var init_opener = () => {};
|
|
27880
|
+
|
|
27087
27881
|
// src/utils/levenshtein-distance.ts
|
|
27088
27882
|
function levenshteinDistance(a, b) {
|
|
27089
27883
|
const lenA = a.length;
|
|
@@ -27127,6 +27921,59 @@ function levenshteinDistance(a, b) {
|
|
|
27127
27921
|
return dp[lenB]?.[lenA] ?? 0;
|
|
27128
27922
|
}
|
|
27129
27923
|
|
|
27924
|
+
// src/core/mongo/field-masker.ts
|
|
27925
|
+
function maskMongoRows(rows, collection, blacklist) {
|
|
27926
|
+
const columns = blacklist.columns ?? {};
|
|
27927
|
+
const raw = columns[collection] ?? findCaseInsensitive(columns, collection);
|
|
27928
|
+
if (!raw || raw.length === 0)
|
|
27929
|
+
return rows;
|
|
27930
|
+
const { patterns } = compilePatterns(raw);
|
|
27931
|
+
if (patterns.length === 0)
|
|
27932
|
+
return rows;
|
|
27933
|
+
const idAffected = patterns.some((p) => p.segments.length === 1 && p.segments[0] === "_id" && !p.wildcardTail);
|
|
27934
|
+
if (idAffected) {
|
|
27935
|
+
console.error(`[blacklist] collection '${collection}' blacklists '_id'; read paths still expose _id to preserve document references.`);
|
|
27936
|
+
}
|
|
27937
|
+
return rows.map((row) => maskRecord(row, "", patterns));
|
|
27938
|
+
}
|
|
27939
|
+
function maskRecord(obj, prefix, patterns) {
|
|
27940
|
+
const out = {};
|
|
27941
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
27942
|
+
if (key === "_id" && prefix === "") {
|
|
27943
|
+
out[key] = value;
|
|
27944
|
+
continue;
|
|
27945
|
+
}
|
|
27946
|
+
const path4 = prefix === "" ? key : `${prefix}.${key}`;
|
|
27947
|
+
if (matchAny(path4, patterns)) {
|
|
27948
|
+
out[key] = REDACTED;
|
|
27949
|
+
continue;
|
|
27950
|
+
}
|
|
27951
|
+
out[key] = maskValue(value, path4, patterns);
|
|
27952
|
+
}
|
|
27953
|
+
return out;
|
|
27954
|
+
}
|
|
27955
|
+
function maskValue(value, path4, patterns) {
|
|
27956
|
+
if (value === null || value === undefined)
|
|
27957
|
+
return value;
|
|
27958
|
+
if (Array.isArray(value)) {
|
|
27959
|
+
return value.map((item) => item && typeof item === "object" && !Array.isArray(item) ? maskRecord(item, path4, patterns) : item);
|
|
27960
|
+
}
|
|
27961
|
+
if (typeof value === "object") {
|
|
27962
|
+
return maskRecord(value, path4, patterns);
|
|
27963
|
+
}
|
|
27964
|
+
return value;
|
|
27965
|
+
}
|
|
27966
|
+
function findCaseInsensitive(columns, name) {
|
|
27967
|
+
const target = name.toLowerCase();
|
|
27968
|
+
for (const [k, v] of Object.entries(columns)) {
|
|
27969
|
+
if (k.toLowerCase() === target)
|
|
27970
|
+
return v;
|
|
27971
|
+
}
|
|
27972
|
+
return;
|
|
27973
|
+
}
|
|
27974
|
+
var REDACTED = "[REDACTED]";
|
|
27975
|
+
var init_field_masker = () => {};
|
|
27976
|
+
|
|
27130
27977
|
// src/commands/query-size-guard.ts
|
|
27131
27978
|
var exports_query_size_guard = {};
|
|
27132
27979
|
__export(exports_query_size_guard, {
|
|
@@ -27593,6 +28440,86 @@ var init_redis = __esm(() => {
|
|
|
27593
28440
|
}
|
|
27594
28441
|
};
|
|
27595
28442
|
});
|
|
28443
|
+
|
|
28444
|
+
// src/core/saved-queries/strategies/mongodb.ts
|
|
28445
|
+
function interpolate(body, meta, params) {
|
|
28446
|
+
const declared = new Map(meta.params.map((p) => [p.name, p]));
|
|
28447
|
+
return body.replace(TEMPLATE_RE, (_match, name) => {
|
|
28448
|
+
const spec = declared.get(name);
|
|
28449
|
+
let value = params[name];
|
|
28450
|
+
if (value === undefined) {
|
|
28451
|
+
if (spec?.default !== undefined) {
|
|
28452
|
+
value = spec.default;
|
|
28453
|
+
} else if (spec?.required) {
|
|
28454
|
+
throw new SavedQueryError(`Missing required param '${name}' for snippet '${meta.key}'`, "PARAM_MISSING");
|
|
28455
|
+
} else {
|
|
28456
|
+
value = null;
|
|
28457
|
+
}
|
|
28458
|
+
}
|
|
28459
|
+
return JSON.stringify(value);
|
|
28460
|
+
});
|
|
28461
|
+
}
|
|
28462
|
+
function stripTemplatesForValidation(body) {
|
|
28463
|
+
return body.replace(TEMPLATE_RE, "0");
|
|
28464
|
+
}
|
|
28465
|
+
function describe(v) {
|
|
28466
|
+
if (v === null)
|
|
28467
|
+
return "null";
|
|
28468
|
+
if (Array.isArray(v))
|
|
28469
|
+
return "array";
|
|
28470
|
+
return typeof v;
|
|
28471
|
+
}
|
|
28472
|
+
var TEMPLATE_RE, mongoStrategy;
|
|
28473
|
+
var init_mongodb = __esm(() => {
|
|
28474
|
+
init_types4();
|
|
28475
|
+
TEMPLATE_RE = /\{\{\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*\}\}/g;
|
|
28476
|
+
mongoStrategy = {
|
|
28477
|
+
family: "mongo",
|
|
28478
|
+
validateBody(body, meta, file) {
|
|
28479
|
+
if (!meta.operation) {
|
|
28480
|
+
throw new SavedQueryError(`MongoDB snippet '${meta.key}' must declare 'operation: find' or 'operation: aggregate'`, "MONGO_INVALID_BODY", file);
|
|
28481
|
+
}
|
|
28482
|
+
const probe = stripTemplatesForValidation(body.trim());
|
|
28483
|
+
let parsed;
|
|
28484
|
+
try {
|
|
28485
|
+
parsed = JSON.parse(probe);
|
|
28486
|
+
} catch (e) {
|
|
28487
|
+
throw new SavedQueryError(`MongoDB snippet '${meta.key}' body is not valid JSON: ${e.message}`, "MONGO_INVALID_BODY", file);
|
|
28488
|
+
}
|
|
28489
|
+
if (meta.operation === "find" && (Array.isArray(parsed) || typeof parsed !== "object" || parsed === null)) {
|
|
28490
|
+
throw new SavedQueryError(`MongoDB find snippet '${meta.key}' body must be a JSON object (got ${describe(parsed)})`, "MONGO_INVALID_BODY", file);
|
|
28491
|
+
}
|
|
28492
|
+
if (meta.operation === "aggregate" && !Array.isArray(parsed)) {
|
|
28493
|
+
throw new SavedQueryError(`MongoDB aggregate snippet '${meta.key}' body must be a JSON array (got ${describe(parsed)})`, "MONGO_INVALID_BODY", file);
|
|
28494
|
+
}
|
|
28495
|
+
},
|
|
28496
|
+
prepare(snippet, params, opts) {
|
|
28497
|
+
if (opts.engine !== "mongodb") {
|
|
28498
|
+
throw new SavedQueryError(`MongoDB snippet '${snippet.meta.key}' cannot run on ${opts.engine} connection`, "ENGINE_MISMATCH", snippet.file);
|
|
28499
|
+
}
|
|
28500
|
+
const collection = params.__collection ?? snippet.meta.target;
|
|
28501
|
+
if (!collection || collection.trim() === "") {
|
|
28502
|
+
throw new SavedQueryError(`MongoDB snippet '${snippet.meta.key}' needs a target collection (frontmatter 'target' or CLI --collection).`, "MONGO_MISSING_COLLECTION", snippet.file);
|
|
28503
|
+
}
|
|
28504
|
+
const interpolated = interpolate(snippet.sqlBody, snippet.meta, params);
|
|
28505
|
+
let parsed;
|
|
28506
|
+
try {
|
|
28507
|
+
parsed = JSON.parse(interpolated);
|
|
28508
|
+
} catch (e) {
|
|
28509
|
+
throw new SavedQueryError(`MongoDB snippet '${snippet.meta.key}' body became invalid JSON after parameter substitution: ${e.message}`, "MONGO_INVALID_BODY", snippet.file);
|
|
28510
|
+
}
|
|
28511
|
+
return {
|
|
28512
|
+
driver: { sql: JSON.stringify(parsed), values: [] },
|
|
28513
|
+
rewrittenBody: JSON.stringify(parsed, null, 2),
|
|
28514
|
+
warnings: [],
|
|
28515
|
+
execHints: {
|
|
28516
|
+
collection,
|
|
28517
|
+
mongoOperation: snippet.meta.operation
|
|
28518
|
+
}
|
|
28519
|
+
};
|
|
28520
|
+
}
|
|
28521
|
+
};
|
|
28522
|
+
});
|
|
27596
28523
|
// src/core/saved-queries/strategies/index.ts
|
|
27597
28524
|
function engineFamily(engine) {
|
|
27598
28525
|
if (engine === "postgres" || engine === "mysql")
|
|
@@ -27601,6 +28528,8 @@ function engineFamily(engine) {
|
|
|
27601
28528
|
return "es";
|
|
27602
28529
|
if (engine === "redis")
|
|
27603
28530
|
return "redis";
|
|
28531
|
+
if (engine === "mongodb")
|
|
28532
|
+
return "mongo";
|
|
27604
28533
|
throw new Error(`Unknown engine: ${engine}`);
|
|
27605
28534
|
}
|
|
27606
28535
|
function getStrategy(family) {
|
|
@@ -27611,6 +28540,8 @@ function getStrategy(family) {
|
|
|
27611
28540
|
return esStrategy;
|
|
27612
28541
|
case "redis":
|
|
27613
28542
|
return redisStrategy;
|
|
28543
|
+
case "mongo":
|
|
28544
|
+
return mongoStrategy;
|
|
27614
28545
|
default:
|
|
27615
28546
|
throw new Error(`No strategy registered for family: ${family}`);
|
|
27616
28547
|
}
|
|
@@ -27619,6 +28550,7 @@ var init_strategies = __esm(() => {
|
|
|
27619
28550
|
init_sql();
|
|
27620
28551
|
init_elasticsearch();
|
|
27621
28552
|
init_redis();
|
|
28553
|
+
init_mongodb();
|
|
27622
28554
|
});
|
|
27623
28555
|
|
|
27624
28556
|
// src/core/saved-queries/yaml-mini.ts
|
|
@@ -27753,6 +28685,8 @@ function familyOf(engine) {
|
|
|
27753
28685
|
return "sql";
|
|
27754
28686
|
if (engine === "elasticsearch")
|
|
27755
28687
|
return "es";
|
|
28688
|
+
if (engine === "mongodb")
|
|
28689
|
+
return "mongo";
|
|
27756
28690
|
return "redis";
|
|
27757
28691
|
}
|
|
27758
28692
|
function parseSavedQuery(input) {
|
|
@@ -27826,6 +28760,8 @@ function parseFrontmatter(yaml, input) {
|
|
|
27826
28760
|
const index = typeof raw.index === "string" ? raw.index : undefined;
|
|
27827
28761
|
const intent = normaliseIntent(raw.intent, input);
|
|
27828
28762
|
const visual = normaliseVisual(raw.visual);
|
|
28763
|
+
const target = typeof raw.target === "string" ? raw.target : undefined;
|
|
28764
|
+
const operation = raw.operation === "find" || raw.operation === "aggregate" ? raw.operation : undefined;
|
|
27829
28765
|
return {
|
|
27830
28766
|
meta: {
|
|
27831
28767
|
name: typeof raw.name === "string" ? raw.name : "",
|
|
@@ -27836,7 +28772,9 @@ function parseFrontmatter(yaml, input) {
|
|
|
27836
28772
|
params,
|
|
27837
28773
|
tags,
|
|
27838
28774
|
intent,
|
|
27839
|
-
visual
|
|
28775
|
+
visual,
|
|
28776
|
+
target,
|
|
28777
|
+
operation
|
|
27840
28778
|
},
|
|
27841
28779
|
warnings
|
|
27842
28780
|
};
|
|
@@ -28033,7 +28971,7 @@ var init_parser = __esm(() => {
|
|
|
28033
28971
|
init_types4();
|
|
28034
28972
|
MAX_BYTES = 64 * 1024;
|
|
28035
28973
|
VALID_TYPES = ["int", "string", "float", "bool", "date", "datetime"];
|
|
28036
|
-
VALID_ENGINES = ["postgres", "mysql", "elasticsearch", "redis"];
|
|
28974
|
+
VALID_ENGINES = ["postgres", "mysql", "elasticsearch", "redis", "mongodb"];
|
|
28037
28975
|
INTENT_RE = /^[a-z][a-z0-9.-]*$/;
|
|
28038
28976
|
});
|
|
28039
28977
|
|
|
@@ -28119,7 +29057,13 @@ async function collectFiles(root) {
|
|
|
28119
29057
|
var ENGINE_SUFFIXES;
|
|
28120
29058
|
var init_loader = __esm(() => {
|
|
28121
29059
|
init_parser();
|
|
28122
|
-
ENGINE_SUFFIXES = [
|
|
29060
|
+
ENGINE_SUFFIXES = [
|
|
29061
|
+
"postgres",
|
|
29062
|
+
"mysql",
|
|
29063
|
+
"elasticsearch",
|
|
29064
|
+
"redis",
|
|
29065
|
+
"mongodb"
|
|
29066
|
+
];
|
|
28123
29067
|
});
|
|
28124
29068
|
|
|
28125
29069
|
// src/core/saved-queries/resolver.ts
|
|
@@ -28159,9 +29103,6 @@ var init_resolver = __esm(() => {
|
|
|
28159
29103
|
|
|
28160
29104
|
// src/core/saved-queries/runner.ts
|
|
28161
29105
|
function prepareExecution(snippet, opts, cliParams, fileParams) {
|
|
28162
|
-
if (opts.engine === "mongodb") {
|
|
28163
|
-
throw new SavedQueryError(`Saved queries do not support MongoDB connections`, "ENGINE_MISMATCH", snippet.query.file);
|
|
28164
|
-
}
|
|
28165
29106
|
const declared = snippet.query.meta.engine;
|
|
28166
29107
|
if (declared && declared.length > 0) {
|
|
28167
29108
|
const declaredFamily = engineFamily(declared[0]);
|
|
@@ -28239,6 +29180,77 @@ var init_saved_queries = __esm(() => {
|
|
|
28239
29180
|
init_snippet_paths();
|
|
28240
29181
|
});
|
|
28241
29182
|
|
|
29183
|
+
// src/commands/q-mongo.ts
|
|
29184
|
+
var exports_q_mongo = {};
|
|
29185
|
+
__export(exports_q_mongo, {
|
|
29186
|
+
qMongoBranch: () => qMongoBranch
|
|
29187
|
+
});
|
|
29188
|
+
import { tmpdir as tmpdir2 } from "os";
|
|
29189
|
+
import { join as join18 } from "path";
|
|
29190
|
+
async function qMongoBranch(snippet, prepared, options, config) {
|
|
29191
|
+
const collection = options.collection ?? prepared.execHints?.collection;
|
|
29192
|
+
if (!collection) {
|
|
29193
|
+
throw new Error(`MongoDB snippet '${snippet.query.meta.key}' resolved without a target collection`);
|
|
29194
|
+
}
|
|
29195
|
+
const blacklistManager = new BlacklistManager(config);
|
|
29196
|
+
const blacklistValidator = new BlacklistValidator(blacklistManager);
|
|
29197
|
+
blacklistValidator.checkTableBlacklist("SELECT", collection);
|
|
29198
|
+
if (options.dryRun) {
|
|
29199
|
+
console.log(`Dry-run preview (no execution):`);
|
|
29200
|
+
console.log(`Collection: ${collection}`);
|
|
29201
|
+
console.log(`Operation: ${prepared.execHints?.mongoOperation ?? "find"}`);
|
|
29202
|
+
console.log(prepared.driver.sql);
|
|
29203
|
+
return;
|
|
29204
|
+
}
|
|
29205
|
+
const adapter = AdapterFactory.createMongoDBAdapter(config.connection);
|
|
29206
|
+
await adapter.connect();
|
|
29207
|
+
try {
|
|
29208
|
+
const start = performance.now();
|
|
29209
|
+
const result = await adapter.execute(prepared.driver.sql, [collection]);
|
|
29210
|
+
const executionTimeMs = Math.round(performance.now() - start);
|
|
29211
|
+
const blacklistCfg = config.blacklist ?? { tables: [], columns: {} };
|
|
29212
|
+
const masked = maskMongoRows(result.rows, collection, blacklistCfg);
|
|
29213
|
+
if (options.ui || options.format === "html") {
|
|
29214
|
+
const html = await generateHtmlReport({ meta: snippet.query.meta, rows: masked });
|
|
29215
|
+
if (options.ui) {
|
|
29216
|
+
const tempPath = join18(tmpdir2(), `dbcli-report-${Date.now()}.html`);
|
|
29217
|
+
await Bun.write(tempPath, html);
|
|
29218
|
+
await openInBrowser(tempPath);
|
|
29219
|
+
} else {
|
|
29220
|
+
console.log(html);
|
|
29221
|
+
}
|
|
29222
|
+
} else {
|
|
29223
|
+
const columnNames = masked[0] ? Object.keys(masked[0]) : [];
|
|
29224
|
+
const formatter = new QueryResultFormatter;
|
|
29225
|
+
console.log(formatter.format({
|
|
29226
|
+
rows: masked,
|
|
29227
|
+
rowCount: masked.length,
|
|
29228
|
+
columnNames,
|
|
29229
|
+
columnTypes: [],
|
|
29230
|
+
executionTimeMs,
|
|
29231
|
+
metadata: { statement: "SELECT", affectedRows: 0 }
|
|
29232
|
+
}, { format: options.format ?? "table" }));
|
|
29233
|
+
}
|
|
29234
|
+
await writeAuditEntry(config, "q", options, {
|
|
29235
|
+
success: true,
|
|
29236
|
+
target: collection,
|
|
29237
|
+
sql: prepared.driver.sql,
|
|
29238
|
+
metadata: { rows_affected: masked.length, execution_ms: executionTimeMs }
|
|
29239
|
+
});
|
|
29240
|
+
} finally {
|
|
29241
|
+
await adapter.disconnect();
|
|
29242
|
+
}
|
|
29243
|
+
}
|
|
29244
|
+
var init_q_mongo = __esm(() => {
|
|
29245
|
+
init_adapters();
|
|
29246
|
+
init_blacklist_validator();
|
|
29247
|
+
init_field_masker();
|
|
29248
|
+
init_formatters();
|
|
29249
|
+
init_html_formatter();
|
|
29250
|
+
init_opener();
|
|
29251
|
+
init_integration_helper();
|
|
29252
|
+
});
|
|
29253
|
+
|
|
28242
29254
|
// src/core/saved-queries/fold.ts
|
|
28243
29255
|
function foldVariants(key, variants) {
|
|
28244
29256
|
const sources = unique(variants.map((v) => v.query.source)).sort();
|
|
@@ -28394,7 +29406,7 @@ __export(exports_queries_import, {
|
|
|
28394
29406
|
queriesImport: () => queriesImport
|
|
28395
29407
|
});
|
|
28396
29408
|
import { stat as stat5, mkdir as mkdir8, copyFile as copyFile2 } from "fs/promises";
|
|
28397
|
-
import { basename as basename3, join as
|
|
29409
|
+
import { basename as basename3, join as join20, extname } from "path";
|
|
28398
29410
|
async function queriesImport(filePath, options = {}) {
|
|
28399
29411
|
const cwd = options.cwd ?? process.cwd();
|
|
28400
29412
|
if (extname(filePath) !== ".sql") {
|
|
@@ -28405,9 +29417,9 @@ async function queriesImport(filePath, options = {}) {
|
|
|
28405
29417
|
const baseName = options.as ? options.as.replace(/^@/, "") : basename3(filePath, ".sql").replace(/\.(postgres|mysql)$/, "");
|
|
28406
29418
|
const key = "@" + baseName;
|
|
28407
29419
|
parseSavedQuery({ key, file: filePath, source: "local", text: text2 });
|
|
28408
|
-
const targetDir =
|
|
29420
|
+
const targetDir = join20(cwd, ".dbcli/queries");
|
|
28409
29421
|
await mkdir8(targetDir, { recursive: true });
|
|
28410
|
-
const target =
|
|
29422
|
+
const target = join20(targetDir, basename3(filePath));
|
|
28411
29423
|
if (await Bun.file(target).exists()) {
|
|
28412
29424
|
if (!options.force) {
|
|
28413
29425
|
const ok = await dist_default6({ message: `Overwrite ${target}?`, default: false });
|
|
@@ -28532,7 +29544,7 @@ var init_collect_snippets = __esm(() => {
|
|
|
28532
29544
|
});
|
|
28533
29545
|
|
|
28534
29546
|
// src/core/inspect/collect-schema-cache.ts
|
|
28535
|
-
import { join as
|
|
29547
|
+
import { join as join24 } from "path";
|
|
28536
29548
|
async function collectSchemaCache(opts) {
|
|
28537
29549
|
const warnings = [];
|
|
28538
29550
|
if (opts.system && !SQL_SYSTEMS2.includes(opts.system)) {
|
|
@@ -28542,7 +29554,7 @@ async function collectSchemaCache(opts) {
|
|
|
28542
29554
|
};
|
|
28543
29555
|
}
|
|
28544
29556
|
const root = resolveSchemaPath(opts.dbcliPath, opts.connectionName);
|
|
28545
|
-
const indexPath =
|
|
29557
|
+
const indexPath = join24(root, "index.json");
|
|
28546
29558
|
const file = Bun.file(indexPath);
|
|
28547
29559
|
if (!await file.exists()) {
|
|
28548
29560
|
return { section: { available: false }, warnings };
|
|
@@ -28654,7 +29666,7 @@ var init_suggest_commands = __esm(() => {
|
|
|
28654
29666
|
});
|
|
28655
29667
|
|
|
28656
29668
|
// src/core/inspect/collector.ts
|
|
28657
|
-
import { join as
|
|
29669
|
+
import { join as join25 } from "path";
|
|
28658
29670
|
async function collectInspect(opts) {
|
|
28659
29671
|
const warnings = [];
|
|
28660
29672
|
let config = null;
|
|
@@ -28730,7 +29742,7 @@ async function collectInspect(opts) {
|
|
|
28730
29742
|
return { ...snapWithoutSuggestions, suggestedCommands, warnings };
|
|
28731
29743
|
}
|
|
28732
29744
|
async function hasConfig(configPath) {
|
|
28733
|
-
if (await Bun.file(
|
|
29745
|
+
if (await Bun.file(join25(configPath, "config.json")).exists())
|
|
28734
29746
|
return true;
|
|
28735
29747
|
if (await Bun.file(configPath).exists()) {
|
|
28736
29748
|
const stat6 = await Bun.file(configPath).stat().catch(() => null);
|
|
@@ -28844,8 +29856,8 @@ function renderMarkdown2(snap, options = {}) {
|
|
|
28844
29856
|
lines.push("");
|
|
28845
29857
|
if (snap.warnings.length > 0) {
|
|
28846
29858
|
lines.push("## Warnings");
|
|
28847
|
-
for (const
|
|
28848
|
-
lines.push(`- ${
|
|
29859
|
+
for (const w2 of snap.warnings)
|
|
29860
|
+
lines.push(`- ${w2}`);
|
|
28849
29861
|
lines.push("");
|
|
28850
29862
|
}
|
|
28851
29863
|
return lines.join(`
|
|
@@ -29019,7 +30031,7 @@ var {
|
|
|
29019
30031
|
// package.json
|
|
29020
30032
|
var package_default = {
|
|
29021
30033
|
name: "@carllee1983/dbcli",
|
|
29022
|
-
version: "1.20.
|
|
30034
|
+
version: "1.20.2",
|
|
29023
30035
|
description: "Database CLI for AI agents",
|
|
29024
30036
|
type: "module",
|
|
29025
30037
|
publishConfig: {
|
|
@@ -29079,12 +30091,12 @@ var package_default = {
|
|
|
29079
30091
|
dependencies: {
|
|
29080
30092
|
"cli-table3": "^0.6.5",
|
|
29081
30093
|
commander: "13.0.0",
|
|
29082
|
-
"lru-cache": "^11.
|
|
29083
|
-
"lucide-react": "^1.
|
|
30094
|
+
"lru-cache": "^11.4.0",
|
|
30095
|
+
"lucide-react": "^1.16.0",
|
|
29084
30096
|
mongodb: "^7.2.0",
|
|
29085
30097
|
mysql2: "^3.22.3",
|
|
29086
30098
|
open: "^11.0.0",
|
|
29087
|
-
pg: "^8.
|
|
30099
|
+
pg: "^8.21.0",
|
|
29088
30100
|
picocolors: "^1.1.1",
|
|
29089
30101
|
react: "^19.2.6",
|
|
29090
30102
|
"react-dom": "^19.2.6",
|
|
@@ -29094,19 +30106,22 @@ var package_default = {
|
|
|
29094
30106
|
devDependencies: {
|
|
29095
30107
|
"@eslint/js": "^9.39.4",
|
|
29096
30108
|
"@happy-dom/global-registrator": "^20.9.0",
|
|
29097
|
-
"@inquirer/prompts": "^8.4.
|
|
30109
|
+
"@inquirer/prompts": "^8.4.3",
|
|
29098
30110
|
"@testing-library/react": "^16.3.2",
|
|
29099
30111
|
"@types/bun": "latest",
|
|
29100
30112
|
"@types/react": "^19.2.14",
|
|
29101
30113
|
"@types/react-dom": "^19.2.3",
|
|
29102
30114
|
autoprefixer: "^10.5.0",
|
|
29103
|
-
eslint: "^10.
|
|
30115
|
+
eslint: "^10.4.0",
|
|
29104
30116
|
"happy-dom": "^20.9.0",
|
|
29105
30117
|
postcss: "^8.5.14",
|
|
29106
30118
|
prettier: "^3.8.3",
|
|
29107
30119
|
tailwindcss: "3.4.1",
|
|
29108
30120
|
typescript: "^5.9.3",
|
|
29109
|
-
"typescript-eslint": "^8.59.
|
|
30121
|
+
"typescript-eslint": "^8.59.4"
|
|
30122
|
+
},
|
|
30123
|
+
overrides: {
|
|
30124
|
+
"brace-expansion": "^5.0.6"
|
|
29110
30125
|
}
|
|
29111
30126
|
};
|
|
29112
30127
|
|
|
@@ -29884,191 +30899,7 @@ async function handleMongoDBInit(ctx) {
|
|
|
29884
30899
|
// src/commands/list.ts
|
|
29885
30900
|
init_message_loader();
|
|
29886
30901
|
init_adapters();
|
|
29887
|
-
|
|
29888
|
-
// src/formatters/table-formatter.ts
|
|
29889
|
-
init_colors();
|
|
29890
|
-
var Table = require_table();
|
|
29891
|
-
|
|
29892
|
-
class TableFormatter {
|
|
29893
|
-
format(columns) {
|
|
29894
|
-
const table = new Table({
|
|
29895
|
-
head: ["Column", "Type", "Nullable", "Default", "Key"].map((h) => colors.bold(h)),
|
|
29896
|
-
style: { compact: false, "padding-left": 1, "padding-right": 1 },
|
|
29897
|
-
colWidths: [25, 25, 10, 25, 20]
|
|
29898
|
-
});
|
|
29899
|
-
columns.forEach((col) => {
|
|
29900
|
-
let keyType = "";
|
|
29901
|
-
if (col.primaryKey) {
|
|
29902
|
-
keyType = "PK";
|
|
29903
|
-
} else if (col.foreignKey) {
|
|
29904
|
-
keyType = `FK \u2192 ${col.foreignKey.table}.${col.foreignKey.column}`;
|
|
29905
|
-
}
|
|
29906
|
-
table.push([col.name, col.type, col.nullable ? "YES" : "NO", col.default || "NULL", keyType]);
|
|
29907
|
-
});
|
|
29908
|
-
return table.toString();
|
|
29909
|
-
}
|
|
29910
|
-
}
|
|
29911
|
-
|
|
29912
|
-
class TableListFormatter {
|
|
29913
|
-
format(tables) {
|
|
29914
|
-
const table = new Table({
|
|
29915
|
-
head: ["Table", "Columns", "Rows", "Engine"].map((h) => colors.bold(h)),
|
|
29916
|
-
style: { compact: false, "padding-left": 1, "padding-right": 1 },
|
|
29917
|
-
colWidths: [30, 12, 15, 15]
|
|
29918
|
-
});
|
|
29919
|
-
tables.forEach((t2) => {
|
|
29920
|
-
table.push([
|
|
29921
|
-
t2.name,
|
|
29922
|
-
(t2.columnCount ?? t2.columns.length).toString(),
|
|
29923
|
-
(t2.rowCount ?? "?").toString(),
|
|
29924
|
-
t2.engine || "N/A"
|
|
29925
|
-
]);
|
|
29926
|
-
});
|
|
29927
|
-
return table.toString();
|
|
29928
|
-
}
|
|
29929
|
-
}
|
|
29930
|
-
// src/formatters/json-formatter.ts
|
|
29931
|
-
init_size_category();
|
|
29932
|
-
class TableSchemaJSONFormatter {
|
|
29933
|
-
format(table, options) {
|
|
29934
|
-
const spacing = options?.compact ? undefined : 2;
|
|
29935
|
-
const rowCount = table.estimatedRowCount ?? table.rowCount;
|
|
29936
|
-
const output = {
|
|
29937
|
-
name: table.name,
|
|
29938
|
-
estimatedRowCount: rowCount ?? null,
|
|
29939
|
-
sizeCategory: rowCount !== undefined && rowCount !== null ? getSizeCategory(rowCount) : null,
|
|
29940
|
-
tableType: table.tableType ?? "table",
|
|
29941
|
-
columns: table.columns,
|
|
29942
|
-
primaryKey: table.primaryKey || [],
|
|
29943
|
-
foreignKeys: table.foreignKeys || [],
|
|
29944
|
-
indexes: table.indexes || [],
|
|
29945
|
-
metadata: {
|
|
29946
|
-
rowCount: table.rowCount,
|
|
29947
|
-
engine: table.engine
|
|
29948
|
-
}
|
|
29949
|
-
};
|
|
29950
|
-
return JSON.stringify(output, null, spacing);
|
|
29951
|
-
}
|
|
29952
|
-
}
|
|
29953
|
-
// src/formatters/query-result-formatter.ts
|
|
29954
|
-
var Table2 = require_table();
|
|
29955
|
-
|
|
29956
|
-
class QueryResultFormatter {
|
|
29957
|
-
format(result, options) {
|
|
29958
|
-
const format = options?.format || "table";
|
|
29959
|
-
switch (format) {
|
|
29960
|
-
case "json":
|
|
29961
|
-
return this.formatJSON(result, options?.compact);
|
|
29962
|
-
case "csv":
|
|
29963
|
-
return this.formatCSV(result);
|
|
29964
|
-
case "table":
|
|
29965
|
-
default:
|
|
29966
|
-
return this.formatTable(result);
|
|
29967
|
-
}
|
|
29968
|
-
}
|
|
29969
|
-
formatTable(result) {
|
|
29970
|
-
if (result.rows.length === 0) {
|
|
29971
|
-
return this.formatEmptyTable(result);
|
|
29972
|
-
}
|
|
29973
|
-
const table = new Table2({
|
|
29974
|
-
head: result.columnNames,
|
|
29975
|
-
style: { compact: false, "padding-left": 1, "padding-right": 1 }
|
|
29976
|
-
});
|
|
29977
|
-
result.rows.forEach((row) => {
|
|
29978
|
-
table.push(result.columnNames.map((col) => this.cellToString(row[col])));
|
|
29979
|
-
});
|
|
29980
|
-
let output = table.toString();
|
|
29981
|
-
const footerLines = [];
|
|
29982
|
-
footerLines.push(`Rows: ${result.rowCount}`);
|
|
29983
|
-
if (result.executionTimeMs !== undefined) {
|
|
29984
|
-
footerLines.push(`Execution time: ${result.executionTimeMs}ms`);
|
|
29985
|
-
}
|
|
29986
|
-
if (footerLines.length > 0) {
|
|
29987
|
-
output += `
|
|
29988
|
-
` + footerLines.join(" | ");
|
|
29989
|
-
}
|
|
29990
|
-
if (result.metadata?.securityNotification) {
|
|
29991
|
-
output += `
|
|
29992
|
-
` + result.metadata.securityNotification;
|
|
29993
|
-
}
|
|
29994
|
-
return output;
|
|
29995
|
-
}
|
|
29996
|
-
formatEmptyTable(result) {
|
|
29997
|
-
const table = new Table2({
|
|
29998
|
-
head: result.columnNames,
|
|
29999
|
-
style: { compact: false, "padding-left": 1, "padding-right": 1 }
|
|
30000
|
-
});
|
|
30001
|
-
let output = table.toString();
|
|
30002
|
-
const footerLines = [];
|
|
30003
|
-
footerLines.push(`Rows: ${result.rowCount}`);
|
|
30004
|
-
if (result.executionTimeMs !== undefined) {
|
|
30005
|
-
footerLines.push(`Execution time: ${result.executionTimeMs}ms`);
|
|
30006
|
-
}
|
|
30007
|
-
if (footerLines.length > 0) {
|
|
30008
|
-
output += `
|
|
30009
|
-
` + footerLines.join(" | ");
|
|
30010
|
-
}
|
|
30011
|
-
if (result.metadata?.securityNotification) {
|
|
30012
|
-
output += `
|
|
30013
|
-
` + result.metadata.securityNotification;
|
|
30014
|
-
}
|
|
30015
|
-
return output;
|
|
30016
|
-
}
|
|
30017
|
-
formatJSON(result, compact) {
|
|
30018
|
-
const spacing = compact ? undefined : 2;
|
|
30019
|
-
const output = {
|
|
30020
|
-
rows: result.rows,
|
|
30021
|
-
rowCount: result.rowCount,
|
|
30022
|
-
columnNames: result.columnNames,
|
|
30023
|
-
columnTypes: result.columnTypes,
|
|
30024
|
-
executionTimeMs: result.executionTimeMs,
|
|
30025
|
-
metadata: result.metadata
|
|
30026
|
-
};
|
|
30027
|
-
return JSON.stringify(output, null, spacing);
|
|
30028
|
-
}
|
|
30029
|
-
formatCSV(result) {
|
|
30030
|
-
if (result.rows.length === 0) {
|
|
30031
|
-
let csvOutput = result.columnNames.map((name) => this.escapeCSVField(name)).join(",");
|
|
30032
|
-
if (result.metadata?.securityNotification) {
|
|
30033
|
-
csvOutput += `
|
|
30034
|
-
# ` + result.metadata.securityNotification;
|
|
30035
|
-
}
|
|
30036
|
-
return csvOutput;
|
|
30037
|
-
}
|
|
30038
|
-
const lines = [];
|
|
30039
|
-
lines.push(result.columnNames.map((name) => this.escapeCSVField(name)).join(","));
|
|
30040
|
-
result.rows.forEach((row) => {
|
|
30041
|
-
const csvRow = result.columnNames.map((col) => this.escapeCSVField(row[col])).join(",");
|
|
30042
|
-
lines.push(csvRow);
|
|
30043
|
-
});
|
|
30044
|
-
if (result.metadata?.securityNotification) {
|
|
30045
|
-
lines.push(`# ${result.metadata.securityNotification}`);
|
|
30046
|
-
}
|
|
30047
|
-
return lines.join(`
|
|
30048
|
-
`);
|
|
30049
|
-
}
|
|
30050
|
-
escapeCSVField(value) {
|
|
30051
|
-
if (value === null || value === undefined) {
|
|
30052
|
-
return "";
|
|
30053
|
-
}
|
|
30054
|
-
const str = String(value);
|
|
30055
|
-
if (str.includes(",") || str.includes('"') || str.includes(`
|
|
30056
|
-
`)) {
|
|
30057
|
-
return `"${str.replace(/"/g, '""')}"`;
|
|
30058
|
-
}
|
|
30059
|
-
return str;
|
|
30060
|
-
}
|
|
30061
|
-
cellToString(value) {
|
|
30062
|
-
if (value === null || value === undefined) {
|
|
30063
|
-
return "";
|
|
30064
|
-
}
|
|
30065
|
-
if (typeof value === "object") {
|
|
30066
|
-
return JSON.stringify(value);
|
|
30067
|
-
}
|
|
30068
|
-
return String(value);
|
|
30069
|
-
}
|
|
30070
|
-
}
|
|
30071
|
-
// src/commands/list.ts
|
|
30902
|
+
init_formatters();
|
|
30072
30903
|
init_config();
|
|
30073
30904
|
init_validation();
|
|
30074
30905
|
function requireSqlConnection(connection) {
|
|
@@ -30222,6 +31053,7 @@ async function elasticsearchListBranch(config, format, includeSystem) {
|
|
|
30222
31053
|
import crypto from "crypto";
|
|
30223
31054
|
init_message_loader();
|
|
30224
31055
|
init_adapters();
|
|
31056
|
+
init_formatters();
|
|
30225
31057
|
init_config();
|
|
30226
31058
|
init_config_v2();
|
|
30227
31059
|
init_config_binding();
|
|
@@ -30598,166 +31430,9 @@ class ColumnIndexBuilder {
|
|
|
30598
31430
|
};
|
|
30599
31431
|
}
|
|
30600
31432
|
}
|
|
30601
|
-
// src/core/blacklist-manager.ts
|
|
30602
|
-
class BlacklistManager {
|
|
30603
|
-
config;
|
|
30604
|
-
state;
|
|
30605
|
-
overrideEnabled;
|
|
30606
|
-
constructor(config, overrideEnvValue) {
|
|
30607
|
-
this.config = config;
|
|
30608
|
-
this.overrideEnabled = (overrideEnvValue ?? Bun.env.DBCLI_OVERRIDE_BLACKLIST ?? "") === "true";
|
|
30609
|
-
this.state = this.loadBlacklist();
|
|
30610
|
-
}
|
|
30611
|
-
loadBlacklist() {
|
|
30612
|
-
const tables = new Set;
|
|
30613
|
-
const columns = new Map;
|
|
30614
|
-
const blacklistConfig = this.config.blacklist;
|
|
30615
|
-
if (!blacklistConfig) {
|
|
30616
|
-
return { tables, columns };
|
|
30617
|
-
}
|
|
30618
|
-
if (Array.isArray(blacklistConfig.tables)) {
|
|
30619
|
-
for (const tableName of blacklistConfig.tables) {
|
|
30620
|
-
if (typeof tableName === "string") {
|
|
30621
|
-
tables.add(tableName.toLowerCase());
|
|
30622
|
-
} else {
|
|
30623
|
-
console.warn(`[BlacklistManager] Invalid table name in blacklist config: ${JSON.stringify(tableName)}`);
|
|
30624
|
-
}
|
|
30625
|
-
}
|
|
30626
|
-
} else if (blacklistConfig.tables !== undefined) {
|
|
30627
|
-
console.warn("[BlacklistManager] blacklist.tables must be an array, ignoring");
|
|
30628
|
-
}
|
|
30629
|
-
if (blacklistConfig.columns && typeof blacklistConfig.columns === "object" && !Array.isArray(blacklistConfig.columns)) {
|
|
30630
|
-
for (const [tableName, cols] of Object.entries(blacklistConfig.columns)) {
|
|
30631
|
-
if (typeof tableName !== "string") {
|
|
30632
|
-
console.warn(`[BlacklistManager] Invalid table name key in columns config: ${JSON.stringify(tableName)}`);
|
|
30633
|
-
continue;
|
|
30634
|
-
}
|
|
30635
|
-
if (!Array.isArray(cols)) {
|
|
30636
|
-
console.warn(`[BlacklistManager] blacklist.columns["${tableName}"] must be an array, ignoring`);
|
|
30637
|
-
continue;
|
|
30638
|
-
}
|
|
30639
|
-
const columnSet = new Set;
|
|
30640
|
-
for (const col of cols) {
|
|
30641
|
-
if (typeof col === "string") {
|
|
30642
|
-
columnSet.add(col);
|
|
30643
|
-
} else {
|
|
30644
|
-
console.warn(`[BlacklistManager] Invalid column name in blacklist.columns["${tableName}"]: ${JSON.stringify(col)}`);
|
|
30645
|
-
}
|
|
30646
|
-
}
|
|
30647
|
-
if (columnSet.size > 0) {
|
|
30648
|
-
columns.set(tableName.toLowerCase(), columnSet);
|
|
30649
|
-
}
|
|
30650
|
-
}
|
|
30651
|
-
} else if (blacklistConfig.columns !== undefined) {
|
|
30652
|
-
console.warn("[BlacklistManager] blacklist.columns must be an object, ignoring");
|
|
30653
|
-
}
|
|
30654
|
-
return { tables, columns };
|
|
30655
|
-
}
|
|
30656
|
-
isTableBlacklisted(tableName) {
|
|
30657
|
-
return this.state.tables.has(tableName.toLowerCase());
|
|
30658
|
-
}
|
|
30659
|
-
isColumnBlacklisted(tableName, columnName) {
|
|
30660
|
-
const columnSet = this.state.columns.get(tableName.toLowerCase());
|
|
30661
|
-
if (!columnSet) {
|
|
30662
|
-
return false;
|
|
30663
|
-
}
|
|
30664
|
-
return columnSet.has(columnName);
|
|
30665
|
-
}
|
|
30666
|
-
getBlacklistedColumns(tableName) {
|
|
30667
|
-
const columnSet = this.state.columns.get(tableName.toLowerCase());
|
|
30668
|
-
if (!columnSet) {
|
|
30669
|
-
return [];
|
|
30670
|
-
}
|
|
30671
|
-
return Array.from(columnSet);
|
|
30672
|
-
}
|
|
30673
|
-
canOverrideBlacklist() {
|
|
30674
|
-
return this.overrideEnabled;
|
|
30675
|
-
}
|
|
30676
|
-
getState() {
|
|
30677
|
-
return this.state;
|
|
30678
|
-
}
|
|
30679
|
-
}
|
|
30680
|
-
// src/core/blacklist-validator.ts
|
|
30681
|
-
init_blacklist();
|
|
30682
|
-
init_message_loader();
|
|
30683
|
-
|
|
30684
|
-
class BlacklistValidator {
|
|
30685
|
-
manager;
|
|
30686
|
-
constructor(manager) {
|
|
30687
|
-
this.manager = manager;
|
|
30688
|
-
}
|
|
30689
|
-
checkTableBlacklist(operation, tableName, _tableList = []) {
|
|
30690
|
-
if (this.manager.canOverrideBlacklist()) {
|
|
30691
|
-
const message = t_vars("warnings.blacklist_override_used", {
|
|
30692
|
-
operation,
|
|
30693
|
-
table: tableName
|
|
30694
|
-
});
|
|
30695
|
-
console.error(message);
|
|
30696
|
-
return;
|
|
30697
|
-
}
|
|
30698
|
-
if (this.manager.isTableBlacklisted(tableName)) {
|
|
30699
|
-
const message = t_vars("errors.table_blacklisted", {
|
|
30700
|
-
table: tableName,
|
|
30701
|
-
operation
|
|
30702
|
-
});
|
|
30703
|
-
throw new BlacklistError(message, tableName, operation);
|
|
30704
|
-
}
|
|
30705
|
-
}
|
|
30706
|
-
checkColumnBlacklistOnWrite(tableName, fields, operation = "WRITE") {
|
|
30707
|
-
const blacklisted = this.manager.getBlacklistedColumns(tableName);
|
|
30708
|
-
if (blacklisted.length === 0 || fields.length === 0) {
|
|
30709
|
-
return;
|
|
30710
|
-
}
|
|
30711
|
-
const conflicts = fields.filter((f) => blacklisted.includes(f));
|
|
30712
|
-
if (conflicts.length === 0) {
|
|
30713
|
-
return;
|
|
30714
|
-
}
|
|
30715
|
-
if (this.manager.canOverrideBlacklist()) {
|
|
30716
|
-
const warning = t_vars("warnings.blacklist_override_used", {
|
|
30717
|
-
operation,
|
|
30718
|
-
table: tableName
|
|
30719
|
-
});
|
|
30720
|
-
console.error(`${warning} (columns: ${conflicts.join(", ")})`);
|
|
30721
|
-
return;
|
|
30722
|
-
}
|
|
30723
|
-
const message = t_vars("errors.column_blacklisted_write", {
|
|
30724
|
-
table: tableName,
|
|
30725
|
-
operation,
|
|
30726
|
-
columns: conflicts.join(", ")
|
|
30727
|
-
});
|
|
30728
|
-
throw new BlacklistError(message, tableName, operation);
|
|
30729
|
-
}
|
|
30730
|
-
filterColumns(tableName, rows, columnList) {
|
|
30731
|
-
const blacklistedColumns = this.manager.getBlacklistedColumns(tableName);
|
|
30732
|
-
if (blacklistedColumns.length === 0) {
|
|
30733
|
-
return { filteredRows: rows, omittedColumns: [] };
|
|
30734
|
-
}
|
|
30735
|
-
const omittedColumns = columnList.filter((col) => blacklistedColumns.includes(col));
|
|
30736
|
-
if (omittedColumns.length === 0) {
|
|
30737
|
-
return { filteredRows: rows, omittedColumns: [] };
|
|
30738
|
-
}
|
|
30739
|
-
const filteredRows = rows.map((row) => {
|
|
30740
|
-
const newRow = {};
|
|
30741
|
-
for (const [key, value] of Object.entries(row)) {
|
|
30742
|
-
if (!omittedColumns.includes(key)) {
|
|
30743
|
-
newRow[key] = value;
|
|
30744
|
-
}
|
|
30745
|
-
}
|
|
30746
|
-
return newRow;
|
|
30747
|
-
});
|
|
30748
|
-
return { filteredRows, omittedColumns };
|
|
30749
|
-
}
|
|
30750
|
-
buildSecurityNotification(_tableName, omittedColumns) {
|
|
30751
|
-
if (omittedColumns.length === 0) {
|
|
30752
|
-
return "";
|
|
30753
|
-
}
|
|
30754
|
-
return t_vars("security.columns_omitted", {
|
|
30755
|
-
count: omittedColumns.length
|
|
30756
|
-
});
|
|
30757
|
-
}
|
|
30758
|
-
}
|
|
30759
31433
|
|
|
30760
31434
|
// src/core/index.ts
|
|
31435
|
+
init_blacklist_validator();
|
|
30761
31436
|
init_size_category();
|
|
30762
31437
|
|
|
30763
31438
|
// src/core/health-checker.ts
|
|
@@ -30895,8 +31570,25 @@ init_schema_loader();
|
|
|
30895
31570
|
// src/commands/schema.ts
|
|
30896
31571
|
init_integration_helper();
|
|
30897
31572
|
init_validation();
|
|
31573
|
+
function markRedactedColumns(cols, collection, blacklist) {
|
|
31574
|
+
const raw = (blacklist.columns ?? {})[collection];
|
|
31575
|
+
if (!raw || raw.length === 0)
|
|
31576
|
+
return cols;
|
|
31577
|
+
const { patterns } = compilePatterns(raw);
|
|
31578
|
+
if (patterns.length === 0)
|
|
31579
|
+
return cols;
|
|
31580
|
+
return cols.map((c) => matchAny(c.name, patterns) ? { ...c, redacted: true } : c);
|
|
31581
|
+
}
|
|
31582
|
+
function decorateMongoSchema(schema, meta) {
|
|
31583
|
+
const columns = markRedactedColumns(schema.columns, schema.name, meta.blacklist);
|
|
31584
|
+
return {
|
|
31585
|
+
...schema,
|
|
31586
|
+
columns,
|
|
31587
|
+
...{ sampleMethod: meta.sampleMethod, sampleSize: meta.sampleSize }
|
|
31588
|
+
};
|
|
31589
|
+
}
|
|
30898
31590
|
var ALLOWED_FORMATS2 = ["table", "json"];
|
|
30899
|
-
var schemaCommand = new Command().name("schema").description("Display table schema, scan database schema, or refresh existing schema with detected changes").argument("[table]", "Optional: table name to inspect (if omitted, scans all tables)").option("--format <format>", "Output format: table (default) or json", "table").option("--config <path>", "Path to .dbcli config file", ".dbcli").option("--refresh", "Refresh schema by detecting changes from database", false).option("--reset", "Clear all existing schema data and re-fetch from database", false).option("--force", "Skip confirmation when updating schema data", false).option("--sample-size <n>", "MongoDB only: number of documents to sample for schema inference (default 50, max 1000). Ignored on SQL connections.").option("--recovery", "On failure, emit a structured recovery envelope to stdout (suppresses human stderr message)", false).action(schemaAction);
|
|
31591
|
+
var schemaCommand = new Command().name("schema").description("Display table schema, scan database schema, or refresh existing schema with detected changes").argument("[table]", "Optional: table name to inspect (if omitted, scans all tables)").option("--format <format>", "Output format: table (default) or json", "table").option("--config <path>", "Path to .dbcli config file", ".dbcli").option("--refresh", "Refresh schema by detecting changes from database", false).option("--reset", "Clear all existing schema data and re-fetch from database", false).option("--force", "Skip confirmation when updating schema data", false).option("--sample-size <n>", "MongoDB only: number of documents to sample for schema inference (default 50, max 1000). Ignored on SQL connections.").option("--sample-method <method>", 'MongoDB only: "random" (default, uses $sample) or "natural" (uses find().limit()). Ignored on SQL connections.', "random").option("--recovery", "On failure, emit a structured recovery envelope to stdout (suppresses human stderr message)", false).action(schemaAction);
|
|
30900
31592
|
async function schemaAction(table, options, command) {
|
|
30901
31593
|
let config;
|
|
30902
31594
|
try {
|
|
@@ -30921,6 +31613,17 @@ async function schemaAction(table, options, command) {
|
|
|
30921
31613
|
console.error("--sample-size is MongoDB-only and is being ignored for this connection.");
|
|
30922
31614
|
}
|
|
30923
31615
|
}
|
|
31616
|
+
if (options.sampleMethod && options.sampleMethod !== "random") {
|
|
31617
|
+
if (options.sampleMethod !== "natural") {
|
|
31618
|
+
console.error(`--sample-method must be 'random' or 'natural' (received '${options.sampleMethod}')`);
|
|
31619
|
+
process.exit(1);
|
|
31620
|
+
}
|
|
31621
|
+
if (config.connection.system === "mongodb") {
|
|
31622
|
+
inferenceOptions = { ...inferenceOptions ?? {}, sampleMethod: "natural" };
|
|
31623
|
+
} else {
|
|
31624
|
+
console.error("--sample-method is MongoDB-only and is being ignored for this connection.");
|
|
31625
|
+
}
|
|
31626
|
+
}
|
|
30924
31627
|
const connectionName = await getSchemaIsolationConnectionName(configPath);
|
|
30925
31628
|
let existingSchemaCount;
|
|
30926
31629
|
if (connectionName !== undefined) {
|
|
@@ -30994,15 +31697,20 @@ Key: ${schema.name}`);
|
|
|
30994
31697
|
}
|
|
30995
31698
|
const adapter = AdapterFactory.createAdapter(config.connection);
|
|
30996
31699
|
await adapter.connect();
|
|
31700
|
+
const mongoMeta = config.connection.system === "mongodb" ? {
|
|
31701
|
+
blacklist: config.blacklist ?? { tables: [], columns: {} },
|
|
31702
|
+
sampleMethod: inferenceOptions?.sampleMethod ?? "random",
|
|
31703
|
+
sampleSize: inferenceOptions?.sampleSize ?? 100
|
|
31704
|
+
} : undefined;
|
|
30997
31705
|
try {
|
|
30998
31706
|
if (options.reset) {
|
|
30999
|
-
await handleSchemaReset(adapter, config, options, connectionName, existingSchemaCount, storagePath, inferenceOptions);
|
|
31707
|
+
await handleSchemaReset(adapter, config, options, connectionName, existingSchemaCount, storagePath, inferenceOptions, mongoMeta);
|
|
31000
31708
|
} else if (options.refresh) {
|
|
31001
|
-
await handleSchemaRefresh(adapter, config, options, connectionName, storagePath, inferenceOptions);
|
|
31709
|
+
await handleSchemaRefresh(adapter, config, options, connectionName, storagePath, inferenceOptions, mongoMeta);
|
|
31002
31710
|
} else if (table) {
|
|
31003
|
-
await handleSingleTableSchema(adapter, table, options.format, inferenceOptions);
|
|
31711
|
+
await handleSingleTableSchema(adapter, table, options.format, inferenceOptions, mongoMeta);
|
|
31004
31712
|
} else {
|
|
31005
|
-
await handleFullDatabaseScan(adapter, config, options, connectionName, existingSchemaCount, storagePath, inferenceOptions);
|
|
31713
|
+
await handleFullDatabaseScan(adapter, config, options, connectionName, existingSchemaCount, storagePath, inferenceOptions, mongoMeta);
|
|
31006
31714
|
}
|
|
31007
31715
|
await writeAuditEntry(config, "schema", options, {
|
|
31008
31716
|
success: true,
|
|
@@ -31038,8 +31746,10 @@ Key: ${schema.name}`);
|
|
|
31038
31746
|
process.exit(1);
|
|
31039
31747
|
}
|
|
31040
31748
|
}
|
|
31041
|
-
async function handleSingleTableSchema(adapter, tableName, format, inferenceOptions) {
|
|
31042
|
-
|
|
31749
|
+
async function handleSingleTableSchema(adapter, tableName, format, inferenceOptions, mongoMeta) {
|
|
31750
|
+
let schema = await adapter.getTableSchema(tableName, inferenceOptions);
|
|
31751
|
+
if (mongoMeta)
|
|
31752
|
+
schema = decorateMongoSchema(schema, mongoMeta);
|
|
31043
31753
|
if (format === "json") {
|
|
31044
31754
|
const formatter = new TableSchemaJSONFormatter;
|
|
31045
31755
|
console.log(formatter.format(schema));
|
|
@@ -31083,7 +31793,7 @@ Indexes:`);
|
|
|
31083
31793
|
}
|
|
31084
31794
|
}
|
|
31085
31795
|
}
|
|
31086
|
-
async function handleSchemaRefresh(adapter, config, options, connectionName, storagePath, inferenceOptions) {
|
|
31796
|
+
async function handleSchemaRefresh(adapter, config, options, connectionName, storagePath, inferenceOptions, mongoMeta) {
|
|
31087
31797
|
const diffEngine = new SchemaDiffEngine(adapter, config);
|
|
31088
31798
|
const report = await diffEngine.diff();
|
|
31089
31799
|
if (report.tablesAdded.length === 0 && report.tablesRemoved.length === 0 && Object.keys(report.tablesModified).length === 0) {
|
|
@@ -31106,7 +31816,9 @@ async function handleSchemaRefresh(adapter, config, options, connectionName, sto
|
|
|
31106
31816
|
}
|
|
31107
31817
|
const newSchema = { ...config.schema };
|
|
31108
31818
|
for (const tableName of report.tablesAdded.concat(Object.keys(report.tablesModified))) {
|
|
31109
|
-
|
|
31819
|
+
let fullSchema = await adapter.getTableSchema(tableName, inferenceOptions);
|
|
31820
|
+
if (mongoMeta)
|
|
31821
|
+
fullSchema = decorateMongoSchema(fullSchema, mongoMeta);
|
|
31110
31822
|
newSchema[tableName] = fullSchema;
|
|
31111
31823
|
}
|
|
31112
31824
|
report.tablesRemoved.forEach((t2) => delete newSchema[t2]);
|
|
@@ -31124,7 +31836,7 @@ async function handleSchemaRefresh(adapter, config, options, connectionName, sto
|
|
|
31124
31836
|
await writeSchema(storagePath, updatedConfig, connectionName);
|
|
31125
31837
|
console.log(`\u2705 Schema updated in .dbcli`);
|
|
31126
31838
|
}
|
|
31127
|
-
async function handleSchemaReset(adapter, config, options, connectionName, existingCount, storagePath, inferenceOptions) {
|
|
31839
|
+
async function handleSchemaReset(adapter, config, options, connectionName, existingCount, storagePath, inferenceOptions, mongoMeta) {
|
|
31128
31840
|
if (existingCount > 0 && !options.force) {
|
|
31129
31841
|
const { SchemaLayeredLoader: SchemaLayeredLoader2 } = await Promise.resolve().then(() => (init_schema_loader(), exports_schema_loader));
|
|
31130
31842
|
const loader = new SchemaLayeredLoader2(storagePath, { connectionName });
|
|
@@ -31155,7 +31867,9 @@ async function handleSchemaReset(adapter, config, options, connectionName, exist
|
|
|
31155
31867
|
const schemaData = {};
|
|
31156
31868
|
let processed = 0;
|
|
31157
31869
|
for (const table of tables) {
|
|
31158
|
-
|
|
31870
|
+
let fullSchema = await adapter.getTableSchema(table.name, inferenceOptions);
|
|
31871
|
+
if (mongoMeta)
|
|
31872
|
+
fullSchema = decorateMongoSchema(fullSchema, mongoMeta);
|
|
31159
31873
|
schemaData[table.name] = {
|
|
31160
31874
|
name: fullSchema.name,
|
|
31161
31875
|
columns: fullSchema.columns,
|
|
@@ -31165,7 +31879,8 @@ async function handleSchemaReset(adapter, config, options, connectionName, exist
|
|
|
31165
31879
|
foreignKeys: fullSchema.foreignKeys || [],
|
|
31166
31880
|
indexes: fullSchema.indexes || [],
|
|
31167
31881
|
estimatedRowCount: fullSchema.estimatedRowCount || 0,
|
|
31168
|
-
tableType: fullSchema.tableType || "table"
|
|
31882
|
+
tableType: fullSchema.tableType || "table",
|
|
31883
|
+
...mongoMeta ? { sampleMethod: mongoMeta.sampleMethod, sampleSize: mongoMeta.sampleSize } : {}
|
|
31169
31884
|
};
|
|
31170
31885
|
processed++;
|
|
31171
31886
|
if (processed % 10 === 0 || processed === tables.length) {
|
|
@@ -31192,14 +31907,16 @@ async function handleSchemaReset(adapter, config, options, connectionName, exist
|
|
|
31192
31907
|
\u2705 Schema fetched \u2014 ${tables.length} tables from database`);
|
|
31193
31908
|
}
|
|
31194
31909
|
}
|
|
31195
|
-
async function handleFullDatabaseScan(adapter, config, options, connectionName, existingSchemaCount, storagePath, inferenceOptions) {
|
|
31910
|
+
async function handleFullDatabaseScan(adapter, config, options, connectionName, existingSchemaCount, storagePath, inferenceOptions, mongoMeta) {
|
|
31196
31911
|
console.log(t("schema.scanning_database"));
|
|
31197
31912
|
const tables = await adapter.listTables();
|
|
31198
31913
|
console.log(t_vars("schema.tables_found", { count: tables.length }));
|
|
31199
31914
|
const schemaData = {};
|
|
31200
31915
|
let processed = 0;
|
|
31201
31916
|
for (const table of tables) {
|
|
31202
|
-
|
|
31917
|
+
let fullSchema = await adapter.getTableSchema(table.name, inferenceOptions);
|
|
31918
|
+
if (mongoMeta)
|
|
31919
|
+
fullSchema = decorateMongoSchema(fullSchema, mongoMeta);
|
|
31203
31920
|
schemaData[table.name] = {
|
|
31204
31921
|
name: fullSchema.name,
|
|
31205
31922
|
columns: fullSchema.columns,
|
|
@@ -31209,7 +31926,8 @@ async function handleFullDatabaseScan(adapter, config, options, connectionName,
|
|
|
31209
31926
|
foreignKeys: fullSchema.foreignKeys || [],
|
|
31210
31927
|
indexes: fullSchema.indexes || [],
|
|
31211
31928
|
estimatedRowCount: fullSchema.estimatedRowCount || 0,
|
|
31212
|
-
tableType: fullSchema.tableType || "table"
|
|
31929
|
+
tableType: fullSchema.tableType || "table",
|
|
31930
|
+
...mongoMeta ? { sampleMethod: mongoMeta.sampleMethod, sampleSize: mongoMeta.sampleSize } : {}
|
|
31213
31931
|
};
|
|
31214
31932
|
processed++;
|
|
31215
31933
|
if (processed % 10 === 0 || processed === tables.length) {
|
|
@@ -31265,38 +31983,10 @@ async function writeSchema(configPath, config, connectionName) {
|
|
|
31265
31983
|
// src/commands/query.ts
|
|
31266
31984
|
init_message_loader();
|
|
31267
31985
|
init_adapters();
|
|
31986
|
+
init_formatters();
|
|
31987
|
+
init_html_formatter();
|
|
31988
|
+
init_opener();
|
|
31268
31989
|
import crypto2 from "crypto";
|
|
31269
|
-
|
|
31270
|
-
// src/formatters/html-formatter.ts
|
|
31271
|
-
init_package_root();
|
|
31272
|
-
async function generateHtmlReport(payload) {
|
|
31273
|
-
const templatePath = packageAssetPath("ui-template.html");
|
|
31274
|
-
const templateFile = Bun.file(templatePath);
|
|
31275
|
-
if (!await templateFile.exists()) {
|
|
31276
|
-
throw new Error(`UI template not found at ${templatePath}. Please run 'bun run build' first.`);
|
|
31277
|
-
}
|
|
31278
|
-
let html = await templateFile.text();
|
|
31279
|
-
const jsonPayload = JSON.stringify(payload).replace(/</g, "\\u003c");
|
|
31280
|
-
const injection = `window.__DBCLI_PAYLOAD__ = ${jsonPayload};`;
|
|
31281
|
-
html = html.replace("/*DBCLI_PAYLOAD*/", () => injection);
|
|
31282
|
-
return html;
|
|
31283
|
-
}
|
|
31284
|
-
|
|
31285
|
-
// src/utils/opener.ts
|
|
31286
|
-
import open2 from "open";
|
|
31287
|
-
async function openInBrowser(target) {
|
|
31288
|
-
if (process.env.DBCLI_NO_OPEN === "1" || false) {
|
|
31289
|
-
console.log(`[Opener] DBCLI_NO_OPEN is set. Skipping browser launch for: ${target}`);
|
|
31290
|
-
return;
|
|
31291
|
-
}
|
|
31292
|
-
try {
|
|
31293
|
-
await open2(target);
|
|
31294
|
-
} catch (err) {
|
|
31295
|
-
console.error(`[Opener] Failed to open ${target}:`, err);
|
|
31296
|
-
}
|
|
31297
|
-
}
|
|
31298
|
-
|
|
31299
|
-
// src/commands/query.ts
|
|
31300
31990
|
import { tmpdir } from "os";
|
|
31301
31991
|
import { join as join15 } from "path";
|
|
31302
31992
|
|
|
@@ -31506,9 +32196,11 @@ function inferColumnType(value) {
|
|
|
31506
32196
|
// src/commands/query.ts
|
|
31507
32197
|
init_config();
|
|
31508
32198
|
init_permission_guard();
|
|
32199
|
+
init_blacklist_validator();
|
|
31509
32200
|
init_blacklist();
|
|
31510
32201
|
init_validation();
|
|
31511
32202
|
init_integration_helper();
|
|
32203
|
+
init_field_masker();
|
|
31512
32204
|
function requireSqlConnection2(connection) {
|
|
31513
32205
|
if (!["postgresql", "mysql", "mariadb"].includes(connection.system)) {
|
|
31514
32206
|
throw new Error(`This command requires a SQL connection, got: ${connection.system}`);
|
|
@@ -31688,22 +32380,22 @@ async function mongoQueryBranch(queryStr, options, config) {
|
|
|
31688
32380
|
execution_ms: executionTimeMs
|
|
31689
32381
|
}
|
|
31690
32382
|
});
|
|
31691
|
-
const
|
|
31692
|
-
const
|
|
32383
|
+
const blacklistCfg = config.blacklist ?? { tables: [], columns: {} };
|
|
32384
|
+
const maskedRows = maskMongoRows(result.rows, collection, blacklistCfg);
|
|
32385
|
+
const columnNames = maskedRows[0] ? Object.keys(maskedRows[0]) : [];
|
|
31693
32386
|
const queryResult = {
|
|
31694
|
-
rows:
|
|
31695
|
-
rowCount:
|
|
31696
|
-
columnNames
|
|
32387
|
+
rows: maskedRows,
|
|
32388
|
+
rowCount: maskedRows.length,
|
|
32389
|
+
columnNames
|
|
31697
32390
|
};
|
|
31698
32391
|
const formatter = new QueryResultFormatter;
|
|
31699
32392
|
const output = formatter.format(queryResult, {
|
|
31700
32393
|
format
|
|
31701
32394
|
});
|
|
31702
32395
|
console.log(output);
|
|
31703
|
-
|
|
31704
|
-
if (securityNote) {
|
|
32396
|
+
if ((blacklistCfg.columns[collection] ?? []).length > 0) {
|
|
31705
32397
|
console.log(`
|
|
31706
|
-
\u2139
|
|
32398
|
+
\u2139 Some fields may have been redacted as [REDACTED] per .dbcli blacklist.`);
|
|
31707
32399
|
}
|
|
31708
32400
|
} finally {
|
|
31709
32401
|
await mongoAdapter.disconnect();
|
|
@@ -32241,14 +32933,18 @@ init_message_loader();
|
|
|
32241
32933
|
init_adapters();
|
|
32242
32934
|
init_config();
|
|
32243
32935
|
import crypto3 from "crypto";
|
|
32936
|
+
init_blacklist_validator();
|
|
32244
32937
|
init_blacklist();
|
|
32245
32938
|
init_permission_guard();
|
|
32246
32939
|
init_engine_hints();
|
|
32940
|
+
init_formatters();
|
|
32941
|
+
init_html_formatter();
|
|
32942
|
+
init_opener();
|
|
32247
32943
|
init_integration_helper();
|
|
32248
32944
|
init_saved_queries();
|
|
32249
32945
|
init_strategies();
|
|
32250
|
-
import { tmpdir as
|
|
32251
|
-
import { join as
|
|
32946
|
+
import { tmpdir as tmpdir3 } from "os";
|
|
32947
|
+
import { join as join19 } from "path";
|
|
32252
32948
|
function formatDryRun(input) {
|
|
32253
32949
|
const lines = ["Dry-run preview (no execution):"];
|
|
32254
32950
|
if (input.family === "es") {
|
|
@@ -32284,17 +32980,14 @@ async function qCommand(name, options, command) {
|
|
|
32284
32980
|
if (!config.connection)
|
|
32285
32981
|
throw new Error('Run "dbcli init" first');
|
|
32286
32982
|
const engine = mapSystemToEngine(config.connection.system);
|
|
32287
|
-
if (engine === "mongodb") {
|
|
32288
|
-
throw new SavedQueryError(`Saved queries do not support MongoDB connections`, "ENGINE_MISMATCH");
|
|
32289
|
-
}
|
|
32290
32983
|
const dirs = resolveSnippetDirs(process.cwd());
|
|
32291
32984
|
const map = await loadSnippets(dirs);
|
|
32292
32985
|
const snippet = resolveByName(map, name, engine);
|
|
32293
32986
|
const cliParams = parseCliParams(options.param ?? []);
|
|
32294
32987
|
const fileParams = await readParamFile(options.paramFile);
|
|
32295
32988
|
const prepared = prepareExecution(snippet, { engine, noLimit: options.noLimit === true }, cliParams, fileParams);
|
|
32296
|
-
for (const
|
|
32297
|
-
console.error(`\u26A0 ${
|
|
32989
|
+
for (const w2 of prepared.warnings)
|
|
32990
|
+
console.error(`\u26A0 ${w2}`);
|
|
32298
32991
|
if (prepared.warnings.length > 0)
|
|
32299
32992
|
console.error("");
|
|
32300
32993
|
if (options.dryRun) {
|
|
@@ -32312,6 +33005,11 @@ async function qCommand(name, options, command) {
|
|
|
32312
33005
|
});
|
|
32313
33006
|
return;
|
|
32314
33007
|
}
|
|
33008
|
+
if (engine === "mongodb") {
|
|
33009
|
+
const { qMongoBranch: qMongoBranch2 } = await Promise.resolve().then(() => (init_q_mongo(), exports_q_mongo));
|
|
33010
|
+
await qMongoBranch2(snippet, prepared, options, config);
|
|
33011
|
+
return;
|
|
33012
|
+
}
|
|
32315
33013
|
const blacklistManager = new BlacklistManager(config);
|
|
32316
33014
|
const blacklistValidator = new BlacklistValidator(blacklistManager);
|
|
32317
33015
|
const family = engineFamily(engine);
|
|
@@ -32338,7 +33036,7 @@ async function qCommand(name, options, command) {
|
|
|
32338
33036
|
rows: filtered.filteredRows
|
|
32339
33037
|
});
|
|
32340
33038
|
if (options.ui) {
|
|
32341
|
-
const tempPath =
|
|
33039
|
+
const tempPath = join19(tmpdir3(), `dbcli-report-${Date.now()}.html`);
|
|
32342
33040
|
await Bun.write(tempPath, html);
|
|
32343
33041
|
await openInBrowser(tempPath);
|
|
32344
33042
|
} else {
|
|
@@ -32593,9 +33291,7 @@ async function deriveEngine() {
|
|
|
32593
33291
|
try {
|
|
32594
33292
|
const cfg = await configModule.read(resolveConfigPath(undefined, {}));
|
|
32595
33293
|
if (cfg.connection) {
|
|
32596
|
-
|
|
32597
|
-
if (engine !== "mongodb")
|
|
32598
|
-
return engine;
|
|
33294
|
+
return mapSystemToEngine(cfg.connection.system);
|
|
32599
33295
|
}
|
|
32600
33296
|
} catch {}
|
|
32601
33297
|
return "postgres";
|
|
@@ -32766,7 +33462,7 @@ async function queriesSearch(keywords, options) {
|
|
|
32766
33462
|
process.exit(2);
|
|
32767
33463
|
return;
|
|
32768
33464
|
}
|
|
32769
|
-
const allowed = ["postgres", "mysql", "redis", "elasticsearch", "all"];
|
|
33465
|
+
const allowed = ["postgres", "mysql", "redis", "elasticsearch", "mongodb", "all"];
|
|
32770
33466
|
if (options.engine && !allowed.includes(options.engine)) {
|
|
32771
33467
|
console.error(`Unknown engine '${options.engine}'. Allowed: ${allowed.join(", ")}.`);
|
|
32772
33468
|
process.exit(2);
|
|
@@ -32811,9 +33507,7 @@ async function deriveEngineOrNull() {
|
|
|
32811
33507
|
try {
|
|
32812
33508
|
const cfg = await configModule.read(resolveConfigPath(undefined, {}));
|
|
32813
33509
|
if (cfg.connection) {
|
|
32814
|
-
|
|
32815
|
-
if (e !== "mongodb")
|
|
32816
|
-
return e;
|
|
33510
|
+
return mapSystemToEngine(cfg.connection.system);
|
|
32817
33511
|
}
|
|
32818
33512
|
} catch {}
|
|
32819
33513
|
return null;
|
|
@@ -32861,7 +33555,7 @@ async function queriesSuggest(intent, options) {
|
|
|
32861
33555
|
process.exit(2);
|
|
32862
33556
|
return;
|
|
32863
33557
|
}
|
|
32864
|
-
const allowed = ["postgres", "mysql", "redis", "elasticsearch", "all"];
|
|
33558
|
+
const allowed = ["postgres", "mysql", "redis", "elasticsearch", "mongodb", "all"];
|
|
32865
33559
|
if (options.engine && !allowed.includes(options.engine)) {
|
|
32866
33560
|
console.error(`Unknown engine '${options.engine}'. Allowed: ${allowed.join(", ")}.`);
|
|
32867
33561
|
process.exit(2);
|
|
@@ -33305,6 +33999,7 @@ Parameters:`);
|
|
|
33305
33999
|
// src/commands/insert.ts
|
|
33306
34000
|
init_config();
|
|
33307
34001
|
init_permission_guard();
|
|
34002
|
+
init_blacklist_validator();
|
|
33308
34003
|
init_blacklist();
|
|
33309
34004
|
|
|
33310
34005
|
// src/core/mongo/dry-run-formatter.ts
|
|
@@ -33422,7 +34117,23 @@ function parseWhereClause(whereClause) {
|
|
|
33422
34117
|
|
|
33423
34118
|
// src/core/mongo/dml-plan.ts
|
|
33424
34119
|
init_permission_guard();
|
|
33425
|
-
var
|
|
34120
|
+
var MONGO_OPERATOR_TIER = {
|
|
34121
|
+
$set: "SAFE",
|
|
34122
|
+
$unset: "SAFE",
|
|
34123
|
+
$rename: "RENAME",
|
|
34124
|
+
$inc: "ARITHMETIC",
|
|
34125
|
+
$mul: "ARITHMETIC",
|
|
34126
|
+
$min: "ARITHMETIC",
|
|
34127
|
+
$max: "ARITHMETIC",
|
|
34128
|
+
$currentDate: "ARITHMETIC",
|
|
34129
|
+
$push: "ARRAY",
|
|
34130
|
+
$pull: "ARRAY",
|
|
34131
|
+
$pullAll: "ARRAY",
|
|
34132
|
+
$pop: "ARRAY",
|
|
34133
|
+
$addToSet: "ARRAY",
|
|
34134
|
+
$bit: "BITWISE",
|
|
34135
|
+
$where: "BLOCK"
|
|
34136
|
+
};
|
|
33426
34137
|
var MONGO_BROAD_FILTER_OPERATORS = new Set([
|
|
33427
34138
|
"$regex",
|
|
33428
34139
|
"$in",
|
|
@@ -33466,28 +34177,79 @@ function decide2(factors) {
|
|
|
33466
34177
|
return "WARN";
|
|
33467
34178
|
return "ALLOW";
|
|
33468
34179
|
}
|
|
33469
|
-
function
|
|
34180
|
+
function classifyMongoUpdate(setDoc) {
|
|
33470
34181
|
const fields = new Set;
|
|
33471
|
-
const
|
|
33472
|
-
let
|
|
34182
|
+
const tierFactors = [];
|
|
34183
|
+
let hasBlock = false;
|
|
33473
34184
|
const hasAnyOperator = Object.keys(setDoc).some((k) => k.startsWith("$"));
|
|
33474
34185
|
if (!hasAnyOperator) {
|
|
33475
34186
|
for (const k of Object.keys(setDoc))
|
|
33476
34187
|
fields.add(k);
|
|
33477
|
-
return { fields: Array.from(fields),
|
|
34188
|
+
return { fields: Array.from(fields), tierFactors, hasBlock };
|
|
33478
34189
|
}
|
|
34190
|
+
const seenTiers = new Map;
|
|
33479
34191
|
for (const [op, payload] of Object.entries(setDoc)) {
|
|
33480
|
-
|
|
33481
|
-
|
|
33482
|
-
hasUnsupportedOperator = true;
|
|
34192
|
+
if (!op.startsWith("$")) {
|
|
34193
|
+
fields.add(op);
|
|
33483
34194
|
continue;
|
|
33484
34195
|
}
|
|
33485
34196
|
if (payload && typeof payload === "object" && !Array.isArray(payload)) {
|
|
33486
34197
|
for (const k of Object.keys(payload))
|
|
33487
34198
|
fields.add(k);
|
|
33488
34199
|
}
|
|
34200
|
+
const tier = MONGO_OPERATOR_TIER[op];
|
|
34201
|
+
if (tier === undefined) {
|
|
34202
|
+
hasBlock = true;
|
|
34203
|
+
tierFactors.push({
|
|
34204
|
+
code: "mongo_unknown_operator",
|
|
34205
|
+
severity: "block",
|
|
34206
|
+
message: `Update uses unknown operator '${op}'. Reject by default; add to tier table if intentional.`
|
|
34207
|
+
});
|
|
34208
|
+
continue;
|
|
34209
|
+
}
|
|
34210
|
+
if (tier === "BLOCK") {
|
|
34211
|
+
hasBlock = true;
|
|
34212
|
+
tierFactors.push({
|
|
34213
|
+
code: "mongo_unknown_operator",
|
|
34214
|
+
severity: "block",
|
|
34215
|
+
message: `Update uses '${op}' which executes server-side code. Operation rejected.`
|
|
34216
|
+
});
|
|
34217
|
+
continue;
|
|
34218
|
+
}
|
|
34219
|
+
if (tier === "SAFE")
|
|
34220
|
+
continue;
|
|
34221
|
+
const bucket = seenTiers.get(tier) ?? [];
|
|
34222
|
+
bucket.push(op);
|
|
34223
|
+
seenTiers.set(tier, bucket);
|
|
34224
|
+
}
|
|
34225
|
+
for (const [tier, ops] of seenTiers) {
|
|
34226
|
+
if (tier === "RENAME") {
|
|
34227
|
+
tierFactors.push({
|
|
34228
|
+
code: "mongo_rename_operator",
|
|
34229
|
+
severity: "warn",
|
|
34230
|
+
message: `Update uses ${ops.join(", ")}; field rename does not exfiltrate data but can break readers.`
|
|
34231
|
+
});
|
|
34232
|
+
} else if (tier === "ARITHMETIC") {
|
|
34233
|
+
tierFactors.push({
|
|
34234
|
+
code: "mongo_arithmetic_operator",
|
|
34235
|
+
severity: "warn",
|
|
34236
|
+
message: `Update uses ${ops.join(", ")}; numeric mutation may compound silently.`
|
|
34237
|
+
});
|
|
34238
|
+
} else if (tier === "ARRAY") {
|
|
34239
|
+
tierFactors.push({
|
|
34240
|
+
code: "mongo_array_operator",
|
|
34241
|
+
severity: "warn",
|
|
34242
|
+
message: `Update uses ${ops.join(", ")}; array mutation can grow unboundedly without a size guard.`
|
|
34243
|
+
});
|
|
34244
|
+
} else if (tier === "BITWISE") {
|
|
34245
|
+
tierFactors.push({
|
|
34246
|
+
code: "mongo_bitwise_operator",
|
|
34247
|
+
severity: "warn",
|
|
34248
|
+
message: `Update uses ${ops.join(", ")}; bitwise updates skip type promotion checks.`
|
|
34249
|
+
});
|
|
34250
|
+
}
|
|
33489
34251
|
}
|
|
33490
|
-
return { fields: Array.from(fields),
|
|
34252
|
+
return { fields: Array.from(fields), tierFactors, hasBlock };
|
|
33491
34253
|
}
|
|
33492
34254
|
function hasIdEquality(where) {
|
|
33493
34255
|
if (!("_id" in where))
|
|
@@ -33541,18 +34303,21 @@ function applyTableBlacklist(target, context, factors) {
|
|
|
33541
34303
|
function applyColumnBlacklist(target, fields, context, factors) {
|
|
33542
34304
|
const columns = context.blacklist.columns ?? {};
|
|
33543
34305
|
const lower = target.toLowerCase();
|
|
33544
|
-
let
|
|
34306
|
+
let raw = [];
|
|
33545
34307
|
for (const [t2, cols] of Object.entries(columns)) {
|
|
33546
34308
|
if (t2.toLowerCase() === lower) {
|
|
33547
|
-
|
|
34309
|
+
raw = cols;
|
|
33548
34310
|
break;
|
|
33549
34311
|
}
|
|
33550
34312
|
}
|
|
33551
|
-
if (
|
|
34313
|
+
if (raw.length === 0)
|
|
34314
|
+
return;
|
|
34315
|
+
const { patterns } = compilePatterns(raw);
|
|
34316
|
+
if (patterns.length === 0)
|
|
33552
34317
|
return;
|
|
33553
34318
|
for (const field of fields) {
|
|
33554
|
-
if (
|
|
33555
|
-
pushFactor2(factors, "blacklisted_column", "block", `MongoDB write would touch blacklisted
|
|
34319
|
+
if (matchAny(field, patterns)) {
|
|
34320
|
+
pushFactor2(factors, "blacklisted_column", "block", `MongoDB write would touch blacklisted path ${target}.${field}.`);
|
|
33556
34321
|
}
|
|
33557
34322
|
}
|
|
33558
34323
|
}
|
|
@@ -33601,18 +34366,31 @@ function buildSuggestedCommands2(target, factors) {
|
|
|
33601
34366
|
}
|
|
33602
34367
|
return [];
|
|
33603
34368
|
}
|
|
34369
|
+
function flattenInsertPaths(data, prefix = "") {
|
|
34370
|
+
const out = [];
|
|
34371
|
+
for (const [k, v] of Object.entries(data)) {
|
|
34372
|
+
const path4 = prefix === "" ? k : `${prefix}.${k}`;
|
|
34373
|
+
out.push(path4);
|
|
34374
|
+
if (v && typeof v === "object" && !Array.isArray(v) && !(v instanceof Date)) {
|
|
34375
|
+
const ctor = v.constructor?.name;
|
|
34376
|
+
if (ctor === "Object") {
|
|
34377
|
+
out.push(...flattenInsertPaths(v, path4));
|
|
34378
|
+
}
|
|
34379
|
+
}
|
|
34380
|
+
}
|
|
34381
|
+
return out;
|
|
34382
|
+
}
|
|
33604
34383
|
var analyzeMongoDmlRisk = (intent, context) => {
|
|
33605
34384
|
const factors = [];
|
|
33606
34385
|
applyPermission(intent.operation, context, factors);
|
|
33607
34386
|
applyTableBlacklist(intent.target, context, factors);
|
|
33608
34387
|
if (intent.operation === "insert") {
|
|
33609
|
-
applyColumnBlacklist(intent.target,
|
|
34388
|
+
applyColumnBlacklist(intent.target, flattenInsertPaths(intent.data), context, factors);
|
|
33610
34389
|
} else if (intent.operation === "update") {
|
|
33611
|
-
const
|
|
33612
|
-
|
|
33613
|
-
pushFactor2(factors,
|
|
33614
|
-
|
|
33615
|
-
applyColumnBlacklist(intent.target, fields, context, factors);
|
|
34390
|
+
const cls = classifyMongoUpdate(intent.set);
|
|
34391
|
+
for (const f of cls.tierFactors)
|
|
34392
|
+
pushFactor2(factors, f.code, f.severity, f.message);
|
|
34393
|
+
applyColumnBlacklist(intent.target, cls.fields, context, factors);
|
|
33616
34394
|
const where = intent.where ?? {};
|
|
33617
34395
|
if (Object.keys(where).length === 0) {
|
|
33618
34396
|
pushFactor2(factors, "nonsql_filter_empty", "block", "MongoDB update filter is empty and would match every document.");
|
|
@@ -34278,6 +35056,7 @@ init_adapters();
|
|
|
34278
35056
|
import crypto5 from "crypto";
|
|
34279
35057
|
init_config();
|
|
34280
35058
|
init_permission_guard();
|
|
35059
|
+
init_blacklist_validator();
|
|
34281
35060
|
init_blacklist();
|
|
34282
35061
|
init_integration_helper();
|
|
34283
35062
|
function requireSqlConnection4(connection) {
|
|
@@ -34574,6 +35353,7 @@ init_adapters();
|
|
|
34574
35353
|
import crypto6 from "crypto";
|
|
34575
35354
|
init_config();
|
|
34576
35355
|
init_permission_guard();
|
|
35356
|
+
init_blacklist_validator();
|
|
34577
35357
|
init_blacklist();
|
|
34578
35358
|
init_integration_helper();
|
|
34579
35359
|
function requireSqlConnection5(connection) {
|
|
@@ -34851,12 +35631,16 @@ async function deleteCommand(table, options, command) {
|
|
|
34851
35631
|
// src/commands/export.ts
|
|
34852
35632
|
init_message_loader();
|
|
34853
35633
|
init_adapters();
|
|
35634
|
+
init_formatters();
|
|
35635
|
+
init_html_formatter();
|
|
34854
35636
|
import crypto7 from "crypto";
|
|
34855
35637
|
init_config();
|
|
34856
35638
|
init_permission_guard();
|
|
35639
|
+
init_blacklist_validator();
|
|
34857
35640
|
init_blacklist();
|
|
34858
35641
|
init_integration_helper();
|
|
34859
35642
|
init_engine_hints();
|
|
35643
|
+
init_field_masker();
|
|
34860
35644
|
function requireSqlConnection6(connection) {
|
|
34861
35645
|
if (!["postgresql", "mysql", "mariadb"].includes(connection.system)) {
|
|
34862
35646
|
throw new Error(`This command requires a SQL connection, got: ${connection.system}`);
|
|
@@ -35062,10 +35846,10 @@ async function mongoExportBranch(query, options, config) {
|
|
|
35062
35846
|
await adapter.connect();
|
|
35063
35847
|
try {
|
|
35064
35848
|
const result = await adapter.execute(query, [collection], effectiveLimit !== undefined ? { limit: effectiveLimit } : undefined);
|
|
35065
|
-
const
|
|
35066
|
-
const
|
|
35067
|
-
const visibleColumns =
|
|
35068
|
-
const formatted = formatMongoRows(
|
|
35849
|
+
const blacklistCfg = config.blacklist ?? { tables: [], columns: {} };
|
|
35850
|
+
const maskedRows = maskMongoRows(result.rows, collection, blacklistCfg);
|
|
35851
|
+
const visibleColumns = collectColumnUnion(maskedRows);
|
|
35852
|
+
const formatted = formatMongoRows(maskedRows, visibleColumns, options.format);
|
|
35069
35853
|
if (options.output) {
|
|
35070
35854
|
const file = Bun.file(options.output);
|
|
35071
35855
|
const exists = await file.exists();
|
|
@@ -35078,21 +35862,20 @@ async function mongoExportBranch(query, options, config) {
|
|
|
35078
35862
|
}
|
|
35079
35863
|
await file.write(formatted);
|
|
35080
35864
|
console.error(t_vars("export.exported", {
|
|
35081
|
-
count:
|
|
35865
|
+
count: maskedRows.length,
|
|
35082
35866
|
file: options.output
|
|
35083
35867
|
}));
|
|
35084
35868
|
} else {
|
|
35085
35869
|
console.log(formatted);
|
|
35086
35870
|
}
|
|
35087
|
-
|
|
35088
|
-
|
|
35089
|
-
console.error(`\u2139 ${securityNote}`);
|
|
35871
|
+
if ((blacklistCfg.columns[collection] ?? []).length > 0) {
|
|
35872
|
+
console.error(`\u2139 Some fields may have been redacted as [REDACTED] per .dbcli blacklist.`);
|
|
35090
35873
|
}
|
|
35091
35874
|
await writeAuditEntry(config, "export", options, {
|
|
35092
35875
|
success: true,
|
|
35093
35876
|
target: collection,
|
|
35094
35877
|
metadata: {
|
|
35095
|
-
rows_affected:
|
|
35878
|
+
rows_affected: maskedRows.length,
|
|
35096
35879
|
output_format: options.format,
|
|
35097
35880
|
...options.output && { output_file: options.output }
|
|
35098
35881
|
}
|
|
@@ -35298,15 +36081,15 @@ class AgentTaskError extends Error {
|
|
|
35298
36081
|
}
|
|
35299
36082
|
// src/core/agent-tasks/task-paths.ts
|
|
35300
36083
|
init_package_root();
|
|
35301
|
-
import { join as
|
|
36084
|
+
import { join as join22 } from "path";
|
|
35302
36085
|
function resolveBuiltinDir2() {
|
|
35303
36086
|
return packageAssetPath("tasks");
|
|
35304
36087
|
}
|
|
35305
36088
|
function resolveAgentTaskDirs(workspaceRoot) {
|
|
35306
36089
|
return {
|
|
35307
36090
|
builtinDir: resolveBuiltinDir2(),
|
|
35308
|
-
sharedDir:
|
|
35309
|
-
localDir:
|
|
36091
|
+
sharedDir: join22(workspaceRoot, ".dbcli-shared", "tasks"),
|
|
36092
|
+
localDir: join22(workspaceRoot, ".dbcli", "tasks")
|
|
35310
36093
|
};
|
|
35311
36094
|
}
|
|
35312
36095
|
// src/core/agent-tasks/parser.ts
|
|
@@ -35444,7 +36227,7 @@ function parseSteps(value, input) {
|
|
|
35444
36227
|
}
|
|
35445
36228
|
// src/core/agent-tasks/loader.ts
|
|
35446
36229
|
import { readdir as readdir2 } from "fs/promises";
|
|
35447
|
-
import { join as
|
|
36230
|
+
import { join as join23, relative as relative2, sep as sep2 } from "path";
|
|
35448
36231
|
async function loadAgentTasks(opts, flags) {
|
|
35449
36232
|
const errors3 = [];
|
|
35450
36233
|
const builtin = await walkAndParse2(opts.builtinDir, "builtin", errors3);
|
|
@@ -35501,7 +36284,7 @@ async function safeCollectMd(root) {
|
|
|
35501
36284
|
return;
|
|
35502
36285
|
}
|
|
35503
36286
|
for (const e of entries) {
|
|
35504
|
-
const full =
|
|
36287
|
+
const full = join23(dir, e.name);
|
|
35505
36288
|
if (e.isDirectory())
|
|
35506
36289
|
await walk(full);
|
|
35507
36290
|
else
|
|
@@ -35609,7 +36392,7 @@ function splitArgv(input) {
|
|
|
35609
36392
|
}
|
|
35610
36393
|
|
|
35611
36394
|
// src/core/agent-tasks/planner.ts
|
|
35612
|
-
var
|
|
36395
|
+
var TEMPLATE_RE2 = /\{\{\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*\}\}/g;
|
|
35613
36396
|
function planAgentTask(input) {
|
|
35614
36397
|
const warnings = [];
|
|
35615
36398
|
const resolved = resolveParams(input.task.params, input.params, warnings);
|
|
@@ -35689,7 +36472,7 @@ function coerce2(p, raw) {
|
|
|
35689
36472
|
return value;
|
|
35690
36473
|
}
|
|
35691
36474
|
function applyTemplate(command, values, task) {
|
|
35692
|
-
return command.replace(
|
|
36475
|
+
return command.replace(TEMPLATE_RE2, (_match, key) => {
|
|
35693
36476
|
if (!(key in values)) {
|
|
35694
36477
|
throw new AgentTaskError(`Template references unknown parameter '${key}' in task '${task.name}'`, "TEMPLATE_SYNTAX", task.file);
|
|
35695
36478
|
}
|
|
@@ -35729,8 +36512,8 @@ function renderMarkdownPlan(plan) {
|
|
|
35729
36512
|
});
|
|
35730
36513
|
if (plan.warnings.length > 0) {
|
|
35731
36514
|
lines.push("## Warnings");
|
|
35732
|
-
for (const
|
|
35733
|
-
lines.push(`- ${
|
|
36515
|
+
for (const w2 of plan.warnings)
|
|
36516
|
+
lines.push(`- ${w2}`);
|
|
35734
36517
|
}
|
|
35735
36518
|
return lines.join(`
|
|
35736
36519
|
`);
|
|
@@ -35903,6 +36686,15 @@ function parseParamPairs(pairs) {
|
|
|
35903
36686
|
// src/commands/blacklist.ts
|
|
35904
36687
|
init_message_loader();
|
|
35905
36688
|
init_config();
|
|
36689
|
+
function auditBlacklistPatterns(cfg) {
|
|
36690
|
+
const warnings = [];
|
|
36691
|
+
for (const [collection, raw] of Object.entries(cfg.columns ?? {})) {
|
|
36692
|
+
const { rejected } = compilePatterns(raw);
|
|
36693
|
+
for (const r of rejected)
|
|
36694
|
+
warnings.push({ collection, raw: r.raw, reason: r.reason });
|
|
36695
|
+
}
|
|
36696
|
+
return { warnings };
|
|
36697
|
+
}
|
|
35906
36698
|
var DEFAULT_CONFIG_PATH = ".dbcli";
|
|
35907
36699
|
var VALID_TABLE_NAME = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
|
|
35908
36700
|
var VALID_COLUMN_NAME = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
|
|
@@ -35953,6 +36745,10 @@ async function blacklistList(configPath) {
|
|
|
35953
36745
|
} else {
|
|
35954
36746
|
console.log(`${t("blacklist.columns_label")}: {}`);
|
|
35955
36747
|
}
|
|
36748
|
+
const audit = auditBlacklistPatterns(blacklist);
|
|
36749
|
+
for (const w2 of audit.warnings) {
|
|
36750
|
+
console.error(`\u26A0 blacklist.columns["${w2.collection}"]: '${w2.raw}' is ignored on mongo connections (${w2.reason}).`);
|
|
36751
|
+
}
|
|
35956
36752
|
}
|
|
35957
36753
|
async function blacklistTableAdd(tableName, configPath) {
|
|
35958
36754
|
if (!isValidTableName(tableName)) {
|
|
@@ -36702,8 +37498,8 @@ async function collectReport(opts) {
|
|
|
36702
37498
|
brief: opts.brief,
|
|
36703
37499
|
probeTimeoutMs: opts.probeTimeoutMs
|
|
36704
37500
|
});
|
|
36705
|
-
for (const
|
|
36706
|
-
warnings.push({ severity: "warn", message:
|
|
37501
|
+
for (const w2 of context.warnings) {
|
|
37502
|
+
warnings.push({ severity: "warn", message: w2, source: "inspect" });
|
|
36707
37503
|
}
|
|
36708
37504
|
if (opts.noConnect) {
|
|
36709
37505
|
warnings.push({ severity: "info", message: "diagnostics skipped (no-connect mode)" });
|
|
@@ -36871,9 +37667,9 @@ function renderMarkdown3(snap, options = {}) {
|
|
|
36871
37667
|
}
|
|
36872
37668
|
if (snap.warnings.length > 0) {
|
|
36873
37669
|
lines.push("## Warnings");
|
|
36874
|
-
for (const
|
|
36875
|
-
const src =
|
|
36876
|
-
lines.push(`- [${
|
|
37670
|
+
for (const w2 of snap.warnings) {
|
|
37671
|
+
const src = w2.source ? ` (${w2.source})` : "";
|
|
37672
|
+
lines.push(`- [${w2.severity}]${src} ${w2.message}`);
|
|
36877
37673
|
}
|
|
36878
37674
|
lines.push("");
|
|
36879
37675
|
}
|
|
@@ -37187,8 +37983,8 @@ async function collectGuide(opts) {
|
|
|
37187
37983
|
brief: opts.brief,
|
|
37188
37984
|
probeTimeoutMs: opts.probeTimeoutMs
|
|
37189
37985
|
});
|
|
37190
|
-
for (const
|
|
37191
|
-
warnings.push({ severity: "warn", message:
|
|
37986
|
+
for (const w2 of context.warnings) {
|
|
37987
|
+
warnings.push({ severity: "warn", message: w2, source: "inspect" });
|
|
37192
37988
|
}
|
|
37193
37989
|
let snippets = new Map;
|
|
37194
37990
|
try {
|
|
@@ -37277,9 +38073,9 @@ function renderMarkdown4(snap, options = {}) {
|
|
|
37277
38073
|
lines.push("");
|
|
37278
38074
|
if (snap.warnings.length > 0) {
|
|
37279
38075
|
lines.push("## Warnings");
|
|
37280
|
-
for (const
|
|
37281
|
-
const src =
|
|
37282
|
-
lines.push(`- [${
|
|
38076
|
+
for (const w2 of snap.warnings) {
|
|
38077
|
+
const src = w2.source ? ` (${w2.source})` : "";
|
|
38078
|
+
lines.push(`- [${w2.severity}]${src} ${w2.message}`);
|
|
37283
38079
|
}
|
|
37284
38080
|
lines.push("");
|
|
37285
38081
|
}
|
|
@@ -37479,6 +38275,7 @@ var recoveryCategorySchema = exports_external.enum([
|
|
|
37479
38275
|
"unknown"
|
|
37480
38276
|
]);
|
|
37481
38277
|
var guideRiskSchema = exports_external.enum(["readonly", "dry-run", "write", "unknown"]);
|
|
38278
|
+
var branchIdSchema = exports_external.string().min(1).max(64).regex(/^[a-z0-9-]+$/, "branchId must match /^[a-z0-9-]+$/");
|
|
37482
38279
|
var guideStepSchema = exports_external.object({
|
|
37483
38280
|
order: exports_external.number().int(),
|
|
37484
38281
|
command: exports_external.string().min(1),
|
|
@@ -37489,7 +38286,35 @@ var guideStepSchema = exports_external.object({
|
|
|
37489
38286
|
intent: exports_external.string().optional(),
|
|
37490
38287
|
interactive: exports_external.boolean().optional(),
|
|
37491
38288
|
dbWrite: exports_external.boolean().optional(),
|
|
37492
|
-
placeholders: exports_external.array(exports_external.string()).optional()
|
|
38289
|
+
placeholders: exports_external.array(exports_external.string()).optional(),
|
|
38290
|
+
branchId: branchIdSchema.optional()
|
|
38291
|
+
}).strict();
|
|
38292
|
+
var branchPlanSchema = exports_external.object({
|
|
38293
|
+
description: exports_external.string().min(1),
|
|
38294
|
+
steps: exports_external.array(guideStepSchema).min(1).max(MAX_BRANCH_STEPS)
|
|
38295
|
+
}).strict();
|
|
38296
|
+
var branchesSchema = exports_external.record(branchIdSchema, branchPlanSchema).superRefine((map, ctx) => {
|
|
38297
|
+
const keys = Object.keys(map);
|
|
38298
|
+
if (keys.length > MAX_BRANCH_COUNT) {
|
|
38299
|
+
ctx.addIssue({
|
|
38300
|
+
code: exports_external.ZodIssueCode.custom,
|
|
38301
|
+
message: `branches has ${keys.length} entries; cap is ${MAX_BRANCH_COUNT}`
|
|
38302
|
+
});
|
|
38303
|
+
}
|
|
38304
|
+
for (const [id, plan] of Object.entries(map)) {
|
|
38305
|
+
for (const step of plan.steps) {
|
|
38306
|
+
if (step.branchId !== undefined && step.branchId !== id) {
|
|
38307
|
+
ctx.addIssue({
|
|
38308
|
+
code: exports_external.ZodIssueCode.custom,
|
|
38309
|
+
message: `step.branchId '${step.branchId}' does not match enclosing key '${id}'`
|
|
38310
|
+
});
|
|
38311
|
+
}
|
|
38312
|
+
}
|
|
38313
|
+
}
|
|
38314
|
+
});
|
|
38315
|
+
var branchForkSchema = exports_external.object({
|
|
38316
|
+
after: exports_external.number().int().min(1),
|
|
38317
|
+
branchIds: exports_external.array(branchIdSchema).min(1)
|
|
37493
38318
|
}).strict();
|
|
37494
38319
|
var recoveryEnvelopeSchema = exports_external.object({
|
|
37495
38320
|
schemaVersion: exports_external.literal(1),
|
|
@@ -37510,8 +38335,30 @@ var recoveryEnvelopeSchema = exports_external.object({
|
|
|
37510
38335
|
}).strict().optional()
|
|
37511
38336
|
}).strict(),
|
|
37512
38337
|
recovery: exports_external.array(guideStepSchema),
|
|
37513
|
-
verify: guideStepSchema.optional()
|
|
37514
|
-
|
|
38338
|
+
verify: guideStepSchema.optional(),
|
|
38339
|
+
branches: branchesSchema.optional(),
|
|
38340
|
+
branchFork: branchForkSchema.optional()
|
|
38341
|
+
}).strict().superRefine((env, ctx) => {
|
|
38342
|
+
const hasBranches = env.branches !== undefined;
|
|
38343
|
+
const hasFork = env.branchFork !== undefined;
|
|
38344
|
+
if (hasBranches !== hasFork) {
|
|
38345
|
+
ctx.addIssue({
|
|
38346
|
+
code: exports_external.ZodIssueCode.custom,
|
|
38347
|
+
message: "branches and branchFork must be set together (or both omitted)"
|
|
38348
|
+
});
|
|
38349
|
+
return;
|
|
38350
|
+
}
|
|
38351
|
+
if (hasBranches && hasFork) {
|
|
38352
|
+
const keys = Object.keys(env.branches).sort();
|
|
38353
|
+
const ids = [...env.branchFork.branchIds].sort();
|
|
38354
|
+
if (keys.length !== ids.length || keys.some((k, i) => k !== ids[i])) {
|
|
38355
|
+
ctx.addIssue({
|
|
38356
|
+
code: exports_external.ZodIssueCode.custom,
|
|
38357
|
+
message: "branchFork.branchIds must equal Object.keys(branches)"
|
|
38358
|
+
});
|
|
38359
|
+
}
|
|
38360
|
+
}
|
|
38361
|
+
});
|
|
37515
38362
|
var savedRecoveryEnvelopeSchema = exports_external.object({
|
|
37516
38363
|
schemaVersion: exports_external.literal(1),
|
|
37517
38364
|
id: exports_external.string().optional(),
|
|
@@ -37544,6 +38391,7 @@ function looksLikeSavedEnvelope(x) {
|
|
|
37544
38391
|
}
|
|
37545
38392
|
|
|
37546
38393
|
// src/commands/recover.ts
|
|
38394
|
+
init_next_step();
|
|
37547
38395
|
init_next_step_schema();
|
|
37548
38396
|
init_validation();
|
|
37549
38397
|
var ALLOWED_FORMATS13 = ["json", "markdown"];
|
|
@@ -37654,21 +38502,27 @@ async function runNext(options, source) {
|
|
|
37654
38502
|
throw new RecoverCliError(parsed.reason ?? "--result invalid.", EXIT_CODE.malformed);
|
|
37655
38503
|
}
|
|
37656
38504
|
const env = source.envelope;
|
|
38505
|
+
const branchIdRaw = options.branch;
|
|
37657
38506
|
let outcome;
|
|
37658
38507
|
try {
|
|
37659
|
-
outcome = nextStepFromEnvelope(env, afterStep, parsed.value
|
|
38508
|
+
outcome = nextStepFromEnvelope(env, afterStep, parsed.value, {
|
|
38509
|
+
branchId: branchIdRaw
|
|
38510
|
+
});
|
|
37660
38511
|
} catch (e) {
|
|
37661
38512
|
throw new RecoverCliError(e.message, EXIT_CODE.malformed);
|
|
37662
38513
|
}
|
|
37663
|
-
const totalSteps = env.recovery.length;
|
|
37664
38514
|
if (outcome.kind === "done") {
|
|
37665
38515
|
return {
|
|
37666
38516
|
schemaVersion: NEXT_SCHEMA_VERSION,
|
|
37667
38517
|
kind: "done",
|
|
37668
38518
|
source: { kind: source.kind, path: source.path },
|
|
37669
38519
|
errorCode: env.error.code,
|
|
37670
|
-
cursor:
|
|
37671
|
-
totalSteps
|
|
38520
|
+
cursor: outcome.cursor,
|
|
38521
|
+
totalSteps: outcome.totalSteps,
|
|
38522
|
+
...outcome.branchId !== undefined ? {
|
|
38523
|
+
branchId: outcome.branchId,
|
|
38524
|
+
branchDescription: env.branches?.[outcome.branchId]?.description
|
|
38525
|
+
} : {}
|
|
37672
38526
|
};
|
|
37673
38527
|
}
|
|
37674
38528
|
return {
|
|
@@ -37676,12 +38530,16 @@ async function runNext(options, source) {
|
|
|
37676
38530
|
kind: "step",
|
|
37677
38531
|
source: { kind: source.kind, path: source.path },
|
|
37678
38532
|
errorCode: env.error.code,
|
|
37679
|
-
cursor: outcome.
|
|
37680
|
-
totalSteps,
|
|
37681
|
-
step: outcome.step
|
|
38533
|
+
cursor: outcome.cursor,
|
|
38534
|
+
totalSteps: outcome.totalSteps,
|
|
38535
|
+
step: outcome.step,
|
|
38536
|
+
...outcome.branchId !== undefined ? {
|
|
38537
|
+
branchId: outcome.branchId,
|
|
38538
|
+
branchDescription: env.branches?.[outcome.branchId]?.description
|
|
38539
|
+
} : {}
|
|
37682
38540
|
};
|
|
37683
38541
|
}
|
|
37684
|
-
var recoverCommand = new Command().name("recover").description("Inspect or apply the last recovery plan").option("--apply", "Execute the recovery plan under risk gating", false).option("--from <path>", "Read the envelope from a file instead of .dbcli/last-recovery.json").option("--allow-write <tier>", `Open the risk gate one tier; values: ${ALLOWED_TIERS.join(" | ")}`).option("--no-verify", "Skip the verify step appended after a successful --apply").option("--next", "Look up the single next step in the multi-turn protocol", false).option("--after-step <n>", "For --next: 1-based order of the step the agent just executed").option("--result <value>", "For --next: JSON StepResultSummary (or @<path> to read from a file)").option("--format <format>", "Output format: markdown | json (default: markdown for inspect, json for --apply / --next)").action(async (options) => {
|
|
38542
|
+
var recoverCommand = new Command().name("recover").description("Inspect or apply the last recovery plan").option("--apply", "Execute the recovery plan under risk gating", false).option("--from <path>", "Read the envelope from a file instead of .dbcli/last-recovery.json").option("--allow-write <tier>", `Open the risk gate one tier; values: ${ALLOWED_TIERS.join(" | ")}`).option("--no-verify", "Skip the verify step appended after a successful --apply").option("--next", "Look up the single next step in the multi-turn protocol", false).option("--after-step <n>", "For --next: 1-based order of the step the agent just executed").option("--result <value>", "For --next: JSON StepResultSummary (or @<path> to read from a file)").option("--branch <id>", "For --next: walk a specific branch by id").option("--format <format>", "Output format: markdown | json (default: markdown for inspect, json for --apply / --next)").action(async (options) => {
|
|
37685
38543
|
try {
|
|
37686
38544
|
if (options.next === true && options.apply === true) {
|
|
37687
38545
|
throw new RecoverCliError("--next and --apply cannot be combined.", EXIT_CODE.malformed);
|
|
@@ -37755,7 +38613,7 @@ var recoverCommand = new Command().name("recover").description("Inspect or apply
|
|
|
37755
38613
|
|
|
37756
38614
|
// src/commands/audit.ts
|
|
37757
38615
|
import { rm as rm3, stat as stat7 } from "fs/promises";
|
|
37758
|
-
import { join as
|
|
38616
|
+
import { join as join26 } from "path";
|
|
37759
38617
|
init_message_loader();
|
|
37760
38618
|
init_validation();
|
|
37761
38619
|
init_config();
|
|
@@ -37771,8 +38629,8 @@ var PREFIX_MIN = 4;
|
|
|
37771
38629
|
async function resolveAuditPaths(configPath, config) {
|
|
37772
38630
|
const storagePath = await resolveConfigStoragePath(configPath);
|
|
37773
38631
|
const connName = config.effectiveConnectionName || getGlobalConnectionName() || "default";
|
|
37774
|
-
const auditDir =
|
|
37775
|
-
const auditFile =
|
|
38632
|
+
const auditDir = join26(storagePath, ".dbcli", "audit");
|
|
38633
|
+
const auditFile = join26(auditDir, `${connName}.jsonl`);
|
|
37776
38634
|
return { auditDir, connectionName: connName, auditFile };
|
|
37777
38635
|
}
|
|
37778
38636
|
function isAuditDisabled(config) {
|
|
@@ -37814,7 +38672,7 @@ function renderTable(rows, headers) {
|
|
|
37814
38672
|
const allRows = [headers, ...rows];
|
|
37815
38673
|
const widths = headers.map((_, col) => Math.max(...allRows.map((r) => (r[col] ?? "").length)));
|
|
37816
38674
|
const fmt = (r) => r.map((cell, i) => (cell ?? "").padEnd(widths[i] ?? 0)).join(" ").trimEnd();
|
|
37817
|
-
const sep3 = widths.map((
|
|
38675
|
+
const sep3 = widths.map((w2) => "-".repeat(w2)).join(" ").trimEnd();
|
|
37818
38676
|
return [fmt(headers), sep3, ...rows.map(fmt)].join(`
|
|
37819
38677
|
`);
|
|
37820
38678
|
}
|
|
@@ -38199,7 +39057,7 @@ init_config_binding();
|
|
|
38199
39057
|
init_schema_path();
|
|
38200
39058
|
init_config();
|
|
38201
39059
|
init_integration_helper();
|
|
38202
|
-
import { join as
|
|
39060
|
+
import { join as join27 } from "path";
|
|
38203
39061
|
import { resolveSrv as resolveSrv2 } from "dns/promises";
|
|
38204
39062
|
function requireSqlConnection9(connection) {
|
|
38205
39063
|
if (!["postgresql", "mysql", "mariadb"].includes(connection.system)) {
|
|
@@ -38279,7 +39137,7 @@ var runDoctorChecks = {
|
|
|
38279
39137
|
}
|
|
38280
39138
|
},
|
|
38281
39139
|
async checkConfigExists(configPath, existsFn) {
|
|
38282
|
-
const exists = existsFn ? await existsFn(configPath) : await Bun.file(configPath).exists() || await Bun.file(
|
|
39140
|
+
const exists = existsFn ? await existsFn(configPath) : await Bun.file(configPath).exists() || await Bun.file(join27(configPath, "config.json")).exists();
|
|
38283
39141
|
return {
|
|
38284
39142
|
group: "Configuration",
|
|
38285
39143
|
label: "Config exists",
|
|
@@ -38436,7 +39294,7 @@ var runDoctorChecks = {
|
|
|
38436
39294
|
async checkV2Config(configPath) {
|
|
38437
39295
|
const results = [];
|
|
38438
39296
|
const storagePath = await resolveConfigStoragePath(configPath);
|
|
38439
|
-
const configFile = Bun.file(
|
|
39297
|
+
const configFile = Bun.file(join27(storagePath, "config.json"));
|
|
38440
39298
|
if (!await configFile.exists())
|
|
38441
39299
|
return results;
|
|
38442
39300
|
let raw;
|
|
@@ -38476,7 +39334,7 @@ var runDoctorChecks = {
|
|
|
38476
39334
|
}
|
|
38477
39335
|
for (const [name, conn] of Object.entries(config.connections)) {
|
|
38478
39336
|
if (conn.envFile) {
|
|
38479
|
-
const envPath =
|
|
39337
|
+
const envPath = join27(storagePath, conn.envFile);
|
|
38480
39338
|
const exists = await Bun.file(envPath).exists();
|
|
38481
39339
|
results.push({
|
|
38482
39340
|
group: "Configuration",
|
|
@@ -38695,7 +39553,7 @@ var doctorCommand = new Command("doctor").description("Run diagnostic checks on
|
|
|
38695
39553
|
}
|
|
38696
39554
|
try {
|
|
38697
39555
|
const schemaConnName = await getSchemaIsolationConnectionName(configPath);
|
|
38698
|
-
const indexPath =
|
|
39556
|
+
const indexPath = join27(resolveSchemaPath(storagePath, schemaConnName), "index.json");
|
|
38699
39557
|
const indexFile = Bun.file(indexPath);
|
|
38700
39558
|
let indexParsed = null;
|
|
38701
39559
|
if (await indexFile.exists()) {
|
|
@@ -38749,7 +39607,7 @@ var doctorCommand = new Command("doctor").description("Run diagnostic checks on
|
|
|
38749
39607
|
|
|
38750
39608
|
// src/commands/completion.ts
|
|
38751
39609
|
init_colors();
|
|
38752
|
-
import { join as
|
|
39610
|
+
import { join as join28 } from "path";
|
|
38753
39611
|
import { homedir as homedir3 } from "os";
|
|
38754
39612
|
function extractCommands(program2) {
|
|
38755
39613
|
return program2.commands.map((cmd) => ({
|
|
@@ -38851,11 +39709,11 @@ function getInstallPath2(shell) {
|
|
|
38851
39709
|
const home = homedir3();
|
|
38852
39710
|
switch (shell) {
|
|
38853
39711
|
case "bash":
|
|
38854
|
-
return
|
|
39712
|
+
return join28(home, ".bashrc");
|
|
38855
39713
|
case "zsh":
|
|
38856
|
-
return
|
|
39714
|
+
return join28(home, ".zshrc");
|
|
38857
39715
|
case "fish":
|
|
38858
|
-
return
|
|
39716
|
+
return join28(home, ".config", "fish", "completions", "dbcli.fish");
|
|
38859
39717
|
default:
|
|
38860
39718
|
throw new Error(`Unsupported shell: ${shell}. Supported: bash, zsh, fish`);
|
|
38861
39719
|
}
|
|
@@ -38875,7 +39733,7 @@ var MARKER_END = "# <<< dbcli completion <<<";
|
|
|
38875
39733
|
async function installCompletion(shell, script) {
|
|
38876
39734
|
const targetPath = getInstallPath2(shell);
|
|
38877
39735
|
if (shell === "fish") {
|
|
38878
|
-
const dir =
|
|
39736
|
+
const dir = join28(homedir3(), ".config", "fish", "completions");
|
|
38879
39737
|
await Bun.$`mkdir -p ${dir}`.quiet();
|
|
38880
39738
|
await Bun.file(targetPath).write(script);
|
|
38881
39739
|
console.log(colors.success(`\u2713 Fish completion installed to ${targetPath}`));
|
|
@@ -39108,7 +39966,7 @@ ${t("upgrade.failed")}`));
|
|
|
39108
39966
|
init_config();
|
|
39109
39967
|
init_adapters();
|
|
39110
39968
|
import { createInterface as createInterface2 } from "readline";
|
|
39111
|
-
import { join as
|
|
39969
|
+
import { join as join29 } from "path";
|
|
39112
39970
|
import { homedir as homedir4 } from "os";
|
|
39113
39971
|
|
|
39114
39972
|
// src/core/repl/types.ts
|
|
@@ -39505,6 +40363,7 @@ class HistoryManager {
|
|
|
39505
40363
|
|
|
39506
40364
|
// src/core/repl/repl-engine.ts
|
|
39507
40365
|
init_permission_guard();
|
|
40366
|
+
init_query_result_formatter();
|
|
39508
40367
|
init_message_loader();
|
|
39509
40368
|
var import_picocolors3 = __toESM(require_picocolors(), 1);
|
|
39510
40369
|
|
|
@@ -39839,7 +40698,7 @@ function requireSqlConnection10(connection) {
|
|
|
39839
40698
|
}
|
|
39840
40699
|
return connection;
|
|
39841
40700
|
}
|
|
39842
|
-
var HISTORY_PATH =
|
|
40701
|
+
var HISTORY_PATH = join29(homedir4(), ".dbcli_history");
|
|
39843
40702
|
var MONGO_COMPLETION_EAGER_THRESHOLD = 20;
|
|
39844
40703
|
async function populateMongoColumns(mongoAdapter, collectionNames, threshold = MONGO_COMPLETION_EAGER_THRESHOLD) {
|
|
39845
40704
|
const columnsByTable = {};
|
|
@@ -40589,7 +41448,6 @@ class DDLExecutor {
|
|
|
40589
41448
|
} catch {}
|
|
40590
41449
|
}
|
|
40591
41450
|
}
|
|
40592
|
-
|
|
40593
41451
|
// src/commands/migrate.ts
|
|
40594
41452
|
function requireSqlConnection11(connection) {
|
|
40595
41453
|
if (!["postgresql", "mysql", "mariadb"].includes(connection.system)) {
|
|
@@ -40826,7 +41684,7 @@ init_config();
|
|
|
40826
41684
|
init_errors();
|
|
40827
41685
|
init_message_loader();
|
|
40828
41686
|
init_config_binding();
|
|
40829
|
-
import { join as
|
|
41687
|
+
import { join as join30 } from "path";
|
|
40830
41688
|
async function switchDefault(configPath, name, config) {
|
|
40831
41689
|
if (!config.connections[name]) {
|
|
40832
41690
|
const available = Object.keys(config.connections).join(", ");
|
|
@@ -40849,7 +41707,7 @@ function listConnectionsForDisplay(config) {
|
|
|
40849
41707
|
}
|
|
40850
41708
|
async function ensureV2Config(configPath) {
|
|
40851
41709
|
const storagePath = await resolveConfigStoragePath(configPath);
|
|
40852
|
-
const configFile = Bun.file(
|
|
41710
|
+
const configFile = Bun.file(join30(storagePath, "config.json"));
|
|
40853
41711
|
const legacyFile = Bun.file(configPath);
|
|
40854
41712
|
if (!await configFile.exists() && !await legacyFile.exists()) {
|
|
40855
41713
|
throw new ConfigError(t("init.config_not_found"));
|
|
@@ -40913,7 +41771,7 @@ var useCommand = new Command("use").description("Switch or display the default d
|
|
|
40913
41771
|
|
|
40914
41772
|
// src/cli.ts
|
|
40915
41773
|
init_config();
|
|
40916
|
-
import { join as
|
|
41774
|
+
import { join as join31 } from "path";
|
|
40917
41775
|
var _bgVersionCheckResult;
|
|
40918
41776
|
function shouldSkipBackgroundChecks() {
|
|
40919
41777
|
return process.env.DBCLI_NO_UPDATE_CHECK === "1" || process.env.DBCLI_NO_UPDATE_CHECK === "true" || false;
|
|
@@ -40942,7 +41800,7 @@ program2.hook("preAction", (thisCommand, actionCommand) => {
|
|
|
40942
41800
|
try {
|
|
40943
41801
|
let cache = null;
|
|
40944
41802
|
try {
|
|
40945
|
-
const cacheFile = Bun.file(
|
|
41803
|
+
const cacheFile = Bun.file(join31(configPath, "version-check.json"));
|
|
40946
41804
|
if (await cacheFile.exists()) {
|
|
40947
41805
|
cache = await cacheFile.json();
|
|
40948
41806
|
}
|