botversion-sdk 2.3.2 → 2.3.4
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/core.js +21 -1
- package/package.json +1 -1
- package/scanner-sdk/bin/scan-backend.js +2 -2
- package/scanner-sdk/bin/scan-frontend.js +2 -2
- package/scanner-sdk/client.js +1 -1
- package/scanner-sdk/index.js +1 -1
- package/undo/index.js +41 -1
- package/undo/lib/tagger.js +177 -1
- package/undo/lib/undo-route.js +16 -0
package/core.js
CHANGED
|
@@ -18,6 +18,20 @@ function pickOptions(appOrOptions, optionsArg) {
|
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
function startUndo(options) {
|
|
21
|
+
// DEBUG: debug logs for Undo, on only with debug:true or env BOTVERSION_DEBUG=1
|
|
22
|
+
global._botVersionDebug =
|
|
23
|
+
!!(options && options.debug) || process.env.BOTVERSION_DEBUG === "1";
|
|
24
|
+
if (global._botVersionDebug)
|
|
25
|
+
console.log("[bv-undo-debug] startUndo called", {
|
|
26
|
+
hasOptions: !!options,
|
|
27
|
+
undoSetToFalse: !!options && options.undo === false,
|
|
28
|
+
hasApiKey: !!(options && options.apiKey),
|
|
29
|
+
alreadyStarted: !!global._botVersionUndoStarted,
|
|
30
|
+
onVercel: !!process.env.VERCEL,
|
|
31
|
+
nextRuntime: process.env.NEXT_RUNTIME || null,
|
|
32
|
+
pid: process.pid,
|
|
33
|
+
node: process.version,
|
|
34
|
+
});
|
|
21
35
|
try {
|
|
22
36
|
if (!options || options.undo === false || !options.apiKey) {
|
|
23
37
|
return;
|
|
@@ -35,7 +49,13 @@ function startUndo(options) {
|
|
|
35
49
|
} else {
|
|
36
50
|
}
|
|
37
51
|
undo.setApiKey(options.apiKey);
|
|
38
|
-
|
|
52
|
+
if (global._botVersionDebug)
|
|
53
|
+
console.log("[bv-undo-debug] startUndo finished without errors");
|
|
54
|
+
} catch (e) {
|
|
55
|
+
// DEBUG: this error used to be swallowed silently
|
|
56
|
+
if (global._botVersionDebug)
|
|
57
|
+
console.log("[bv-undo-debug] startUndo FAILED:", e && e.message);
|
|
58
|
+
}
|
|
39
59
|
}
|
|
40
60
|
|
|
41
61
|
function init(appOrOptions, optionsArg) {
|
package/package.json
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
1
|
+
#!/usr/bin/env node
|
|
2
2
|
"use strict";
|
|
3
3
|
|
|
4
4
|
var path = require("path");
|
|
@@ -29,7 +29,7 @@ var BotVersionClient = require("../client");
|
|
|
29
29
|
|
|
30
30
|
var apiKey = process.env.BOTVERSION_API_KEY;
|
|
31
31
|
var platformUrl =
|
|
32
|
-
process.env.BOTVERSION_PLATFORM_URL || "
|
|
32
|
+
process.env.BOTVERSION_PLATFORM_URL || "http://localhost:3000";
|
|
33
33
|
|
|
34
34
|
if (!apiKey) {
|
|
35
35
|
console.error(
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
1
|
+
#!/usr/bin/env node
|
|
2
2
|
"use strict";
|
|
3
3
|
|
|
4
4
|
var path = require("path");
|
|
@@ -30,7 +30,7 @@ var sdk = require("../index");
|
|
|
30
30
|
|
|
31
31
|
var apiKey = process.env.BOTVERSION_API_KEY;
|
|
32
32
|
var platformUrl =
|
|
33
|
-
process.env.BOTVERSION_PLATFORM_URL || "
|
|
33
|
+
process.env.BOTVERSION_PLATFORM_URL || "http://localhost:3000";
|
|
34
34
|
|
|
35
35
|
if (!apiKey) {
|
|
36
36
|
console.error(
|
package/scanner-sdk/client.js
CHANGED
|
@@ -11,7 +11,7 @@ const url = require("url");
|
|
|
11
11
|
*/
|
|
12
12
|
function BotVersionClient(options) {
|
|
13
13
|
this.apiKey = options.apiKey;
|
|
14
|
-
this.platformUrl = options.platformUrl || "
|
|
14
|
+
this.platformUrl = options.platformUrl || "http://localhost:3000";
|
|
15
15
|
this.debug = options.debug || false;
|
|
16
16
|
this.timeout = options.timeout || 30000;
|
|
17
17
|
|
package/scanner-sdk/index.js
CHANGED
|
@@ -439,7 +439,7 @@ var BotVersion = {
|
|
|
439
439
|
|
|
440
440
|
this._client = new BotVersionClient({
|
|
441
441
|
apiKey: options.apiKey,
|
|
442
|
-
platformUrl: options.platformUrl || "
|
|
442
|
+
platformUrl: options.platformUrl || "http://localhost:3000",
|
|
443
443
|
debug: options.debug || false,
|
|
444
444
|
timeout: options.timeout || 30000,
|
|
445
445
|
});
|
package/undo/index.js
CHANGED
|
@@ -27,6 +27,18 @@ const { printReport } = require("./lib/report");
|
|
|
27
27
|
|
|
28
28
|
let started = false;
|
|
29
29
|
|
|
30
|
+
// DEBUG: prints only when debug is on
|
|
31
|
+
const dbg = (...a) => {
|
|
32
|
+
if (global._botVersionDebug) console.log("[bv-undo-debug]", ...a);
|
|
33
|
+
};
|
|
34
|
+
const brief = (v) => {
|
|
35
|
+
try {
|
|
36
|
+
return String(JSON.stringify(v)).slice(0, 150);
|
|
37
|
+
} catch (_) {
|
|
38
|
+
return String(v).slice(0, 150);
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
|
|
30
42
|
/**
|
|
31
43
|
* @param {object} [options]
|
|
32
44
|
* @param {string} [options.testHeader] header that marks a request as an "AI request" (default x-botversion-action-id)
|
|
@@ -35,7 +47,11 @@ let started = false;
|
|
|
35
47
|
*/
|
|
36
48
|
function init(options) {
|
|
37
49
|
try {
|
|
38
|
-
if (started)
|
|
50
|
+
if (started) {
|
|
51
|
+
dbg("undo init skipped: already started in this process");
|
|
52
|
+
return { ok: true, alreadyStarted: true };
|
|
53
|
+
}
|
|
54
|
+
dbg("undo init running", { pid: process.pid });
|
|
39
55
|
started = true;
|
|
40
56
|
|
|
41
57
|
const opts = options && typeof options === "object" ? options : {};
|
|
@@ -46,9 +62,21 @@ function init(options) {
|
|
|
46
62
|
|
|
47
63
|
// 1. Request tagger (framework independent).
|
|
48
64
|
const taggerTargets = tagger.install();
|
|
65
|
+
dbg("request listener installed on:", taggerTargets, {
|
|
66
|
+
signedIds: tagger.hasApiKey(),
|
|
67
|
+
header: tagger.getHeaderName(),
|
|
68
|
+
});
|
|
49
69
|
|
|
50
70
|
// 2. Look at the host project.
|
|
51
71
|
const scan = scanner.scan();
|
|
72
|
+
dbg("project scan", {
|
|
73
|
+
hostRoot: scan.hostRoot,
|
|
74
|
+
hasPrisma: !!scan.prisma,
|
|
75
|
+
prismaProvider:
|
|
76
|
+
scan.prisma && scan.prisma.database
|
|
77
|
+
? scan.prisma.database.provider
|
|
78
|
+
: null,
|
|
79
|
+
});
|
|
52
80
|
|
|
53
81
|
// 3. Database hooks. Only the ones that match what the host has..
|
|
54
82
|
// (Final SDK: more hooks are added to this same list.)
|
|
@@ -65,6 +93,16 @@ function init(options) {
|
|
|
65
93
|
: null,
|
|
66
94
|
);
|
|
67
95
|
|
|
96
|
+
dbg("database hooks attached:", {
|
|
97
|
+
pg: brief(pgCopies),
|
|
98
|
+
mysql2: brief(mysql2Copies),
|
|
99
|
+
mongodb: brief(mongodbCopies),
|
|
100
|
+
betterSqlite: brief(betterSqliteCopies),
|
|
101
|
+
sqlite3: brief(sqlite3Copies),
|
|
102
|
+
mssql: brief(mssqlCopies),
|
|
103
|
+
prisma: brief(prismaState),
|
|
104
|
+
});
|
|
105
|
+
|
|
68
106
|
// Database structure (schema only). Runs AFTER the hooks attach so loading Prisma here cannot make the Prisma hook miss it.
|
|
69
107
|
scan.structure = scan.prisma
|
|
70
108
|
? schemaReader.readPrismaStructure(scan.hostRoot)
|
|
@@ -84,8 +122,10 @@ function init(options) {
|
|
|
84
122
|
prismaState,
|
|
85
123
|
});
|
|
86
124
|
|
|
125
|
+
dbg("undo init finished without errors");
|
|
87
126
|
return { ok: true };
|
|
88
127
|
} catch (e) {
|
|
128
|
+
dbg("undo init FAILED:", e && e.message);
|
|
89
129
|
return { ok: false };
|
|
90
130
|
}
|
|
91
131
|
}
|
package/undo/lib/tagger.js
CHANGED
|
@@ -26,6 +26,14 @@ let counter = 0;
|
|
|
26
26
|
let signingKey = null; // derived from the host's API key; the raw key is never kept
|
|
27
27
|
let lastIgnoredLog = 0;
|
|
28
28
|
|
|
29
|
+
// DEBUG: prints only when debug is on
|
|
30
|
+
const dbg = (...a) => {
|
|
31
|
+
if (global._botVersionDebug) console.log("[bv-undo-debug]", ...a);
|
|
32
|
+
};
|
|
33
|
+
const seenEvents = new Set(); // distinct server event names seen (capped)
|
|
34
|
+
let seenRequests = 0;
|
|
35
|
+
const listenerSeen = new WeakSet(); // DEBUG: responses the server-event listener saw
|
|
36
|
+
|
|
29
37
|
function setApiKey(key) {
|
|
30
38
|
try {
|
|
31
39
|
signingKey = actionId.deriveSigningKey(key);
|
|
@@ -43,6 +51,7 @@ function noteIgnored(message) {
|
|
|
43
51
|
const now = Date.now();
|
|
44
52
|
if (now - lastIgnoredLog < 60000) return;
|
|
45
53
|
lastIgnoredLog = now;
|
|
54
|
+
dbg("request ignored:", message);
|
|
46
55
|
}
|
|
47
56
|
|
|
48
57
|
function setHeaderName(name) {
|
|
@@ -146,6 +155,19 @@ function buildStore(req, res) {
|
|
|
146
155
|
res.once("close", () => {
|
|
147
156
|
try {
|
|
148
157
|
const ms = Date.now() - store.startedAt;
|
|
158
|
+
// DEBUG: end-of-request summary, shows whether the database hooks saw the queries
|
|
159
|
+
dbg("AI request finished:", {
|
|
160
|
+
id: String(store.actionId).slice(0, 6),
|
|
161
|
+
method: store.method,
|
|
162
|
+
path: store.path,
|
|
163
|
+
status: res.statusCode,
|
|
164
|
+
ms,
|
|
165
|
+
queries: store.queries,
|
|
166
|
+
writes: store.writes,
|
|
167
|
+
savedSnapshots: store.savedIds.length,
|
|
168
|
+
unsaved: store.unsaved,
|
|
169
|
+
blocked: !!store.blocked,
|
|
170
|
+
});
|
|
149
171
|
} catch (_) {
|
|
150
172
|
/* never break the host */
|
|
151
173
|
}
|
|
@@ -269,7 +291,44 @@ function wrapEmit(proto) {
|
|
|
269
291
|
const original = proto.emit;
|
|
270
292
|
const wrapper = function emit(event, req, res) {
|
|
271
293
|
let store = null;
|
|
294
|
+
// DEBUG: notes each distinct server event once (shows whether this server emits through the patched method)
|
|
295
|
+
if (
|
|
296
|
+
global._botVersionDebug &&
|
|
297
|
+
typeof event === "string" &&
|
|
298
|
+
seenEvents.size < 15 &&
|
|
299
|
+
!seenEvents.has(event)
|
|
300
|
+
) {
|
|
301
|
+
seenEvents.add(event);
|
|
302
|
+
dbg("server event seen:", event, { pid: process.pid });
|
|
303
|
+
}
|
|
272
304
|
if (event === "request") {
|
|
305
|
+
// DEBUG: shows whether requests reach this listener at all (first 3 requests, plus every botversion request)
|
|
306
|
+
let bvSeen = false;
|
|
307
|
+
try {
|
|
308
|
+
if (global._botVersionDebug && res && typeof res === "object")
|
|
309
|
+
listenerSeen.add(res); // DEBUG: marks "the listener saw this request"
|
|
310
|
+
} catch (_) {}
|
|
311
|
+
try {
|
|
312
|
+
if (global._botVersionDebug) {
|
|
313
|
+
seenRequests++;
|
|
314
|
+
const hn = Object.keys((req && req.headers) || {}).filter(
|
|
315
|
+
(k) => k.indexOf("x-botversion-") === 0,
|
|
316
|
+
);
|
|
317
|
+
const p = String((req && req.url) || "")
|
|
318
|
+
.split("?")[0]
|
|
319
|
+
.slice(0, 120);
|
|
320
|
+
bvSeen = hn.length > 0 || p.indexOf("botversion") !== -1;
|
|
321
|
+
if (seenRequests <= 3 || bvSeen)
|
|
322
|
+
dbg("request seen:", {
|
|
323
|
+
n: seenRequests,
|
|
324
|
+
method: req && req.method,
|
|
325
|
+
path: p,
|
|
326
|
+
botversionHeaders: hn,
|
|
327
|
+
hasSigningKey: !!signingKey,
|
|
328
|
+
pid: process.pid,
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
} catch (_) {}
|
|
273
332
|
try {
|
|
274
333
|
// The Undo route is answered here, before the host's framework sees the request.
|
|
275
334
|
if (
|
|
@@ -284,6 +343,13 @@ function wrapEmit(proto) {
|
|
|
284
343
|
guardPreflight(req, res); // never throws; only touches preflight requests that ask for our headers
|
|
285
344
|
try {
|
|
286
345
|
store = buildStore(req, res);
|
|
346
|
+
// DEBUG: shows whether this request was accepted as an AI request
|
|
347
|
+
if (bvSeen)
|
|
348
|
+
dbg(
|
|
349
|
+
"accepted as AI request:",
|
|
350
|
+
!!store,
|
|
351
|
+
store ? { visual: store.visual, confirmed: store.confirmed } : "",
|
|
352
|
+
);
|
|
287
353
|
} catch (_) {
|
|
288
354
|
store = null; // tagging problems must never affect the host
|
|
289
355
|
}
|
|
@@ -298,9 +364,117 @@ function wrapEmit(proto) {
|
|
|
298
364
|
return true;
|
|
299
365
|
}
|
|
300
366
|
|
|
367
|
+
// DEBUG PROBE: watches every response Node finishes, whatever way the host received the request.
|
|
368
|
+
// Compares it with what the server-event listener saw. Prints only when debug is on.
|
|
369
|
+
globalThis.__bvTaggerLoads = (globalThis.__bvTaggerLoads || 0) + 1;
|
|
370
|
+
const PROBE = Symbol.for("botversion.undoExp.probe");
|
|
371
|
+
const probeCount = { all: 0, bv: 0 };
|
|
372
|
+
const probed = new WeakSet();
|
|
373
|
+
|
|
374
|
+
function installResponseProbe() {
|
|
375
|
+
try {
|
|
376
|
+
if (!global._botVersionDebug) return;
|
|
377
|
+
const http = require("http");
|
|
378
|
+
|
|
379
|
+
// Startup facts: which process, which module copy, which Next.js
|
|
380
|
+
let nextVersion = null;
|
|
381
|
+
try {
|
|
382
|
+
nextVersion = require(
|
|
383
|
+
require.resolve("next/package.json", { paths: [process.cwd()] }),
|
|
384
|
+
).version;
|
|
385
|
+
} catch (_) {}
|
|
386
|
+
dbg("probe installed", {
|
|
387
|
+
pid: process.pid,
|
|
388
|
+
uptimeSec: Math.round(process.uptime()),
|
|
389
|
+
taggerCopiesLoaded: globalThis.__bvTaggerLoads,
|
|
390
|
+
script: String(process.argv[1] || "").slice(-60),
|
|
391
|
+
cwd: process.cwd(),
|
|
392
|
+
node: process.version,
|
|
393
|
+
next: nextVersion,
|
|
394
|
+
nextRuntime: process.env.NEXT_RUNTIME || null,
|
|
395
|
+
vercelEnv: process.env.VERCEL_ENV || null,
|
|
396
|
+
region: process.env.VERCEL_REGION || null,
|
|
397
|
+
lambda: !!process.env.AWS_LAMBDA_FUNCTION_NAME,
|
|
398
|
+
emitPatched: !!(
|
|
399
|
+
http.Server &&
|
|
400
|
+
http.Server.prototype.emit &&
|
|
401
|
+
http.Server.prototype.emit[PATCHED]
|
|
402
|
+
),
|
|
403
|
+
});
|
|
404
|
+
|
|
405
|
+
// Does this process ever start a real Node server?
|
|
406
|
+
const SP = http.Server && http.Server.prototype;
|
|
407
|
+
if (SP && typeof SP.listen === "function" && !SP.listen[PROBE]) {
|
|
408
|
+
const origListen = SP.listen;
|
|
409
|
+
const wl = function listen() {
|
|
410
|
+
try {
|
|
411
|
+
dbg("a Node server started listening in this process", {
|
|
412
|
+
pid: process.pid,
|
|
413
|
+
args: Array.prototype.slice
|
|
414
|
+
.call(arguments)
|
|
415
|
+
.filter((a) => typeof a === "number" || typeof a === "string")
|
|
416
|
+
.slice(0, 2),
|
|
417
|
+
});
|
|
418
|
+
} catch (_) {}
|
|
419
|
+
return origListen.apply(this, arguments);
|
|
420
|
+
};
|
|
421
|
+
Object.defineProperty(wl, PROBE, { value: true });
|
|
422
|
+
SP.listen = wl;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
// Watches every finished response.
|
|
426
|
+
const RP = http.ServerResponse && http.ServerResponse.prototype;
|
|
427
|
+
if (!RP || typeof RP.end !== "function") {
|
|
428
|
+
dbg("probe: ServerResponse.end not found, cannot watch responses");
|
|
429
|
+
return;
|
|
430
|
+
}
|
|
431
|
+
if (RP.end[PROBE]) return;
|
|
432
|
+
const origEnd = RP.end;
|
|
433
|
+
const wrapped = function end() {
|
|
434
|
+
try {
|
|
435
|
+
if (!probed.has(this)) {
|
|
436
|
+
probed.add(this);
|
|
437
|
+
const req = this.req;
|
|
438
|
+
const h = (req && req.headers) || {};
|
|
439
|
+
const bvHeaders = Object.keys(h).filter(
|
|
440
|
+
(k) => k.indexOf("x-botversion-") === 0,
|
|
441
|
+
);
|
|
442
|
+
const p = String((req && req.url) || "")
|
|
443
|
+
.split("?")[0]
|
|
444
|
+
.slice(0, 120);
|
|
445
|
+
const isBv = bvHeaders.length > 0 || p.indexOf("botversion") !== -1;
|
|
446
|
+
const log =
|
|
447
|
+
(probeCount.all < 5 && ++probeCount.all) ||
|
|
448
|
+
(isBv && probeCount.bv < 40 && ++probeCount.bv);
|
|
449
|
+
if (log)
|
|
450
|
+
dbg("response finished", {
|
|
451
|
+
pid: process.pid,
|
|
452
|
+
uptimeSec: Math.round(process.uptime()),
|
|
453
|
+
method: req && req.method,
|
|
454
|
+
path: p,
|
|
455
|
+
status: this.statusCode,
|
|
456
|
+
botversionHeaders: bvHeaders,
|
|
457
|
+
listenerSawIt: listenerSeen.has(this),
|
|
458
|
+
insideAiRequest: !!getCurrent(),
|
|
459
|
+
hasSigningKey: !!signingKey,
|
|
460
|
+
undoStartedHere: !!global._botVersionUndoStarted,
|
|
461
|
+
taggerCopiesLoaded: globalThis.__bvTaggerLoads,
|
|
462
|
+
});
|
|
463
|
+
}
|
|
464
|
+
} catch (_) {}
|
|
465
|
+
return origEnd.apply(this, arguments);
|
|
466
|
+
};
|
|
467
|
+
Object.defineProperty(wrapped, PROBE, { value: true });
|
|
468
|
+
RP.end = wrapped;
|
|
469
|
+
} catch (e) {
|
|
470
|
+
dbg("probe could not be installed:", e && e.message);
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
|
|
301
474
|
// Wraps every built-in server type that exists in this Node version.
|
|
302
475
|
function install() {
|
|
303
476
|
const wrapped = [];
|
|
477
|
+
installResponseProbe(); // DEBUG probe, does nothing unless debug is on
|
|
304
478
|
const targets = [
|
|
305
479
|
["http", (m) => m.Server && m.Server.prototype],
|
|
306
480
|
["https", (m) => m.Server && m.Server.prototype],
|
|
@@ -328,7 +502,9 @@ function install() {
|
|
|
328
502
|
for (const proto of protos) {
|
|
329
503
|
if (wrapEmit(proto) && !wrapped.includes(name)) wrapped.push(name);
|
|
330
504
|
}
|
|
331
|
-
} catch (e) {
|
|
505
|
+
} catch (e) {
|
|
506
|
+
dbg("could not wrap", name, ":", e && e.message);
|
|
507
|
+
}
|
|
332
508
|
}
|
|
333
509
|
return wrapped;
|
|
334
510
|
}
|
package/undo/lib/undo-route.js
CHANGED
|
@@ -15,6 +15,11 @@ const undoMssql = require("./undo-mssql");
|
|
|
15
15
|
const PATH = "/botversion-undo";
|
|
16
16
|
const NOTE = "Emails, payments and other outside actions cannot be undone.";
|
|
17
17
|
|
|
18
|
+
// DEBUG: prints only when debug is on
|
|
19
|
+
const dbg = (...a) => {
|
|
20
|
+
if (global._botVersionDebug) console.log("[bv-undo-debug]", ...a);
|
|
21
|
+
};
|
|
22
|
+
|
|
18
23
|
const STATUS_PATH = "/botversion-undo-status";
|
|
19
24
|
|
|
20
25
|
// true only when something saved for this action can still be undone by this browser session.
|
|
@@ -33,6 +38,7 @@ async function statusOf(id, hash) {
|
|
|
33
38
|
]) {
|
|
34
39
|
try {
|
|
35
40
|
const ok = await u.statusAction(id, hash);
|
|
41
|
+
dbg("status check", name, "->", ok);
|
|
36
42
|
if (ok) return true;
|
|
37
43
|
} catch (e) {
|
|
38
44
|
if (!(e instanceof undoPrisma.Refuse && e.code === "no-client"))
|
|
@@ -57,6 +63,11 @@ const CORS = {
|
|
|
57
63
|
function send(res, status, obj) {
|
|
58
64
|
try {
|
|
59
65
|
res.statusCode = status;
|
|
66
|
+
dbg(
|
|
67
|
+
"undo route answered:",
|
|
68
|
+
status,
|
|
69
|
+
String((obj && (obj.code || obj.message)) || "").slice(0, 100),
|
|
70
|
+
);
|
|
60
71
|
for (const k of Object.keys(CORS)) res.setHeader(k, CORS[k]);
|
|
61
72
|
res.setHeader("Content-Type", "application/json");
|
|
62
73
|
// marker lets the widget tell our answer apart from the host's own JSON
|
|
@@ -76,6 +87,11 @@ function handle(req, res, isValidId) {
|
|
|
76
87
|
req.method === "POST" && (label === "status" || label === "undo");
|
|
77
88
|
const isStatus = byLabel ? label === "status" : urlPath === STATUS_PATH;
|
|
78
89
|
if (!byLabel && urlPath !== PATH && !isStatus) return false;
|
|
90
|
+
dbg("undo route matched:", {
|
|
91
|
+
method: req.method,
|
|
92
|
+
path: urlPath,
|
|
93
|
+
label: label || null,
|
|
94
|
+
});
|
|
79
95
|
// Browser permission check (preflight) for cross-domain hosts.
|
|
80
96
|
if (req.method === "OPTIONS") {
|
|
81
97
|
try {
|