@quatronic/qore 0.1.4 → 0.1.6
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 +93 -4
- package/dist/chunk-OAU6HJHZ.js +140 -0
- package/dist/cli.js +1102 -371
- package/dist/sentry-GMM4X3FT.js +11262 -0
- package/package.json +3 -2
- package/dist/cli.js.map +0 -1
package/README.md
CHANGED
|
@@ -46,7 +46,26 @@ the portal. Working from a personal fork whose `origin` the portal doesn't
|
|
|
46
46
|
know? As long as an `upstream` remote points at the real repository, that one
|
|
47
47
|
resolves — the context line then says `(upstream)`.
|
|
48
48
|
|
|
49
|
-
|
|
49
|
+
Outside a repository, with a projects folder set (see `qore init`), the
|
|
50
|
+
order is: the project you are standing in; else `[project]` /
|
|
51
|
+
`--project <ref>` (`app`, `app/module`, `tenant/app` or `tenant/app/module`,
|
|
52
|
+
matched against your local checkouts); else an interactive pick. `qore dev`
|
|
53
|
+
takes the reference as an argument (`qore dev <app>`); `qore dev`, `qore env
|
|
54
|
+
pull`, `qore run` and `qore status` take `--project`. `qore run --project`
|
|
55
|
+
only chooses which module's secrets are used; the command still runs in the
|
|
56
|
+
current directory. `qore env pull --project` writes into the located module,
|
|
57
|
+
and a relative `--target` then resolves against that project directory, not
|
|
58
|
+
the directory you ran it from.
|
|
59
|
+
|
|
60
|
+
Logged out with a projects folder set, the local lookup still runs first: a
|
|
61
|
+
folder that holds no projects gives `QORE_PROJECT_NOT_FOUND`; otherwise the
|
|
62
|
+
project is located exactly as when logged in (a match, a picker, or
|
|
63
|
+
`QORE_CONTEXT_REQUIRED` without a terminal), and the login error comes from
|
|
64
|
+
the portal lookup that follows. Only without a projects folder does a logged-out
|
|
65
|
+
command outside a project go straight to the login error.
|
|
66
|
+
|
|
67
|
+
Pass `--module <slug|id>` to pick a module explicitly (it keeps its meaning and,
|
|
68
|
+
like `--app`, still uses the portal lookup when you are not in a project); the flag always wins
|
|
50
69
|
over the git remote. Inside a repository, `qore` still looks up the remote's
|
|
51
70
|
own module (from the cache, or with one extra request) only so the context
|
|
52
71
|
line can tell you when the flag overrides it. If a module is linked to more
|
|
@@ -92,7 +111,9 @@ qore env pull
|
|
|
92
111
|
|
|
93
112
|
- The target file defaults to the module type's own convention (e.g.
|
|
94
113
|
`.env.local`), or `.qore.json`'s `envFile`, or `--target <path>` — always
|
|
95
|
-
|
|
114
|
+
required to stay inside the repository. `envFile` resolves against the
|
|
115
|
+
repository root; `--target` against the current directory, or with
|
|
116
|
+
`--project` against the located project directory.
|
|
96
117
|
- If the file doesn't exist yet, it's seeded from `.env.example` when one is
|
|
97
118
|
present.
|
|
98
119
|
- Existing values you've hand-edited are kept by default. A key the portal
|
|
@@ -301,6 +322,39 @@ If a repository resolves to no module on any portal you're logged in to,
|
|
|
301
322
|
the error lists the portals it tried and, when a staging repository looks
|
|
302
323
|
likely, suggests `qore login --portal staging`.
|
|
303
324
|
|
|
325
|
+
### Projects folder & `qore init`
|
|
326
|
+
|
|
327
|
+
`qore init` is the guided setup. It runs four steps and reports each as
|
|
328
|
+
`done`, `already` or `skipped`, so running it again is safe:
|
|
329
|
+
|
|
330
|
+
1. **Projects folder**: where your apps live (default `~/qore`; `--root <path>`
|
|
331
|
+
sets it without asking). Nothing existing is moved.
|
|
332
|
+
2. **Login**: skipped when you are already logged in, and with `--no-input`.
|
|
333
|
+
3. **Tenant**: `already` when a tenant is active (`done` right after the login
|
|
334
|
+
step logged you in). Otherwise skipped with
|
|
335
|
+
`--no-input` or when you are not logged in (run `qore tenant use <slug>`
|
|
336
|
+
later), skipped with no tenants, selected without a prompt when you have
|
|
337
|
+
one, a picker when you have several.
|
|
338
|
+
4. **First app**: `--clone <app>` (with `--tenant <slug>` to disambiguate)
|
|
339
|
+
clones it; interactively it asks.
|
|
340
|
+
|
|
341
|
+
With `--json`, stdout is one document: `{"projectsRoot": "<path>|null",
|
|
342
|
+
"steps": {"root"|"login"|"tenant"|"clone": {"status", "detail?"}}}`.
|
|
343
|
+
|
|
344
|
+
Apps clone into `<root>/<tenant>/<app>/<module>`. A checkout outside the
|
|
345
|
+
folder registers itself the first time you use it (`qore clone <app> <dir>`,
|
|
346
|
+
`qore dev`, ...); a registered checkout that was deleted is dropped. With a
|
|
347
|
+
projects folder set, `qore dev`, `qore env pull`, `qore run` and `qore status`
|
|
348
|
+
work from any directory (see Repository context).
|
|
349
|
+
|
|
350
|
+
```sh
|
|
351
|
+
qore config root # show the folder and how many projects it holds
|
|
352
|
+
qore config root <path> # set it
|
|
353
|
+
qore config root --unset # clear it; known projects stay findable
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
`qore doctor` checks that the folder exists and is writable.
|
|
357
|
+
|
|
304
358
|
### Workspaces
|
|
305
359
|
|
|
306
360
|
`qore clone` sets up a local directory holding one or more of an app's
|
|
@@ -319,6 +373,9 @@ qore sync # clone any module that's new, fetch the rest
|
|
|
319
373
|
qore sync --pull # ...and fast-forward every clean repository with an upstream
|
|
320
374
|
```
|
|
321
375
|
|
|
376
|
+
- **Where it clones.** Without `[dir]` and with a projects folder set, `qore
|
|
377
|
+
clone` uses `<root>/<tenant>/<app>`. Without a projects folder it behaves as
|
|
378
|
+
described above and prints a tip to run `qore init`.
|
|
322
379
|
- **`--protocol https|ssh`** picks the clone URL (default `https`). `ssh`
|
|
323
380
|
rewrites `https://github.com/o/r` to `git@github.com:o/r.git`; your own
|
|
324
381
|
git `insteadOf` config still applies on top of either.
|
|
@@ -485,8 +542,8 @@ qore whoami --json
|
|
|
485
542
|
| Code | Meaning |
|
|
486
543
|
|------|---------|
|
|
487
544
|
| 0 | Success |
|
|
488
|
-
| 1 | Internal error, `git` is not installed or not on `PATH`, the OS keychain is unavailable/access was denied, or qore itself needs a newer Node (`QORE_NODE_VERSION`, checked by `qore doctor`'s own `node` check against qore's own `process.version`); `qore dev`: its package manager isn't installed (`QORE_PACKAGE_MANAGER`), its install failed (`QORE_INSTALL_FAILED`), Docker is missing (`QORE_DOCKER_MISSING`), not running (`QORE_DOCKER_NOT_RUNNING`) or its compose v2 plugin is missing (`QORE_DOCKER_COMPOSE_MISSING`), a `db:up`/service failed, never became healthy (`QORE_SERVICE_UNHEALTHY`) or its data is incompatible (`QORE_SERVICE_DATA_INCOMPATIBLE`), or the repository's own `engines.node` doesn't match the `node` on `PATH` (`QORE_NODE_VERSION`, a different check from qore's own — `qore doctor`'s `node:<module>` check, run only in a trusted repository) |
|
|
489
|
-
| 2 | Missing or invalid context (e.g. a bad `--portal` value, or no module selected), or the module is part of several apps and no `--app` was given; `qore dev`: a port is already in use (`QORE_PORT_IN_USE`) or the repository's dev setup isn't supported (`QORE_DEV_UNSUPPORTED`) |
|
|
545
|
+
| 1 | Internal error, `git` is not installed or not on `PATH`, the OS keychain is unavailable/access was denied, or qore itself needs a newer Node (`QORE_NODE_VERSION`, checked by `qore doctor`'s own `node` check against qore's own `process.version`); `qore dev`: its package manager isn't installed (`QORE_PACKAGE_MANAGER`), its install failed (`QORE_INSTALL_FAILED`), Docker is missing (`QORE_DOCKER_MISSING`), not running (`QORE_DOCKER_NOT_RUNNING`) or its compose v2 plugin is missing (`QORE_DOCKER_COMPOSE_MISSING`), a `db:up`/service failed, never became healthy (`QORE_SERVICE_UNHEALTHY`) or its data is incompatible (`QORE_SERVICE_DATA_INCOMPATIBLE`), or the repository's own `engines.node` doesn't match the `node` on `PATH` (`QORE_NODE_VERSION`, a different check from qore's own — `qore doctor`'s `node:<module>` check, run only in a trusted repository); or the projects folder isn't writable (`QORE_ROOT_NOT_WRITABLE`, fix its permissions or choose another folder) |
|
|
546
|
+
| 2 | Missing or invalid context (e.g. a bad `--portal` value, or no module selected), or the module is part of several apps and no `--app` was given; `qore dev`: a port is already in use (`QORE_PORT_IN_USE`) or the repository's dev setup isn't supported (`QORE_DEV_UNSUPPORTED`); projects folder: not set and not inside a project, for a logged-in user (`QORE_ROOT_NOT_SET`, run `qore init`; logged out with no folder you get the login error, exit 4, and logged out with a folder the local lookup runs first, so an empty folder still gives `QORE_PROJECT_NOT_FOUND`), not usable as a folder (`QORE_ROOT_INVALID`, pick another with `qore init --root <path>`), or no local project matches the reference or the folder holds none (`QORE_PROJECT_NOT_FOUND`, run `qore clone <app>`) |
|
|
490
547
|
| 4 | Not logged in, session/login expired, login denied, or clock skew |
|
|
491
548
|
| 5 | Access denied — lost tenant access, resource not found, no developer access |
|
|
492
549
|
| 6 | Auth or API temporarily unreachable/unavailable |
|
|
@@ -511,6 +568,38 @@ and never in an environment variable.
|
|
|
511
568
|
- `NODE_EXTRA_CA_CERTS` can point at an additional CA bundle, for portals or
|
|
512
569
|
identity providers behind a corporate proxy with a private root CA.
|
|
513
570
|
|
|
571
|
+
## Privacy
|
|
572
|
+
|
|
573
|
+
`qore` sends crash reports to Quatronic so we can find and fix bugs. It is on by
|
|
574
|
+
default; the first interactive run says so once, on stderr.
|
|
575
|
+
|
|
576
|
+
**What is sent**, to Sentry (EU region, project `qore-cli`):
|
|
577
|
+
|
|
578
|
+
- errors qore did not anticipate — a bug in qore, not an expected error such as
|
|
579
|
+
"not logged in" or "port in use";
|
|
580
|
+
- one health record per run: whether it crashed or not;
|
|
581
|
+
- with each: the qore version, the Node version, the OS, whether it ran in CI, the
|
|
582
|
+
command name (e.g. `env pull`), the stack trace, and the error message;
|
|
583
|
+
- the method, host and status code of the HTTP requests qore made before a crash.
|
|
584
|
+
|
|
585
|
+
**Removed before sending:** tokens, keys and other secrets, environment variable
|
|
586
|
+
values (including the local env qore fetched), argument values, e-mail addresses,
|
|
587
|
+
URL query strings, and your home directory (paths show as `~`). This is pattern-based:
|
|
588
|
+
an error message about a file qore failed to parse can still quote a fragment of it.
|
|
589
|
+
|
|
590
|
+
**Never attached:** your hostname, your user account, your tenant, or an IP address.
|
|
591
|
+
qore sends no field that carries an IP; the address a report arrives from is dropped
|
|
592
|
+
by the Sentry project's "Prevent Storing of IP Addresses" setting, part of its infra setup.
|
|
593
|
+
|
|
594
|
+
**Turning it off** (the first match wins):
|
|
595
|
+
|
|
596
|
+
1. `DO_NOT_TRACK=1`
|
|
597
|
+
2. `QORE_TELEMETRY=0` (or `QORE_TELEMETRY=1` to turn it on)
|
|
598
|
+
3. `qore config telemetry off` (or `on`)
|
|
599
|
+
|
|
600
|
+
`qore config telemetry` and `qore doctor` show the current state and where it
|
|
601
|
+
comes from. A build from source or a fork carries no DSN and sends nothing.
|
|
602
|
+
|
|
514
603
|
## Releasing
|
|
515
604
|
|
|
516
605
|
See [RELEASING.md](./RELEASING.md).
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="885f6de1-0da7-54a5-86df-beaf550bdd8a")}catch(e){}}();
|
|
4
|
+
import { createRequire as __qoreCreateRequire } from "node:module"; const require = __qoreCreateRequire(import.meta.url);
|
|
5
|
+
|
|
6
|
+
// src/core/telemetry/scrub.ts
|
|
7
|
+
var SECRET_ENV_KEY = /TOKEN|SECRET|PASSWORD|PASSWD|PRIVATE|API_?KEY|ACCESS_?KEY|DSN|AUTH|CREDENTIAL|COOKIE|SESSION/i;
|
|
8
|
+
var KEEP_CONTEXTS = /* @__PURE__ */ new Set(["runtime", "os"]);
|
|
9
|
+
var PATTERNS = [
|
|
10
|
+
// an unterminated block runs to the end, so a truncated key is still dropped
|
|
11
|
+
[/-----BEGIN [A-Z0-9 ]{1,40}-----[\s\S]*?(?:-----END [A-Z0-9 ]{1,40}-----|$)/g, "[pem]"],
|
|
12
|
+
// query strings and fragments carry OAuth codes, states and signed-URL tokens
|
|
13
|
+
[/\b([a-z][a-z0-9+.-]{0,30}:\/\/[^\s?#"'<>]*)[?#][^\s"'<>]*/gi, "$1"],
|
|
14
|
+
[/\b(authorization["']?\s*[=:]\s*)(\[redacted\]|"[^"]*"|'[^']*'|[A-Za-z][A-Za-z0-9_-]{0,30}\s+[^\s,;&]+|[^\s,;&]+)/gi, "$1[redacted]"],
|
|
15
|
+
[/\bBearer\s+[A-Za-z0-9._~+/=-]+/gi, "Bearer [redacted]"],
|
|
16
|
+
[/\bBasic\s+[A-Za-z0-9+/=]{8,}/gi, "Basic [redacted]"],
|
|
17
|
+
[/\beyJ[A-Za-z0-9_-]{5,}\.[A-Za-z0-9_-]{5,}\.[A-Za-z0-9_-]*/g, "[jwt]"],
|
|
18
|
+
[/\b(?:gh[pousr]_[A-Za-z0-9]{20,}|github_pat_[A-Za-z0-9_]{20,}|sntr[ysu]_[A-Za-z0-9+/=_-]{20,}|npm_[A-Za-z0-9]{20,}|sk-[A-Za-z0-9_-]{20,}|xox[abpr]-[A-Za-z0-9-]{10,}|[sr]k_(?:live|test)_[A-Za-z0-9]{10,}|(?:AKIA|ASIA)[0-9A-Z]{16})/g, "[token]"],
|
|
19
|
+
// URL credentials, which is also what a DSN's public key looks like
|
|
20
|
+
[/\b([a-z][a-z0-9+.-]{0,30}:\/\/)[^\s/:@]+(?::[^\s/@]*)?@/gi, "$1[redacted]@"],
|
|
21
|
+
[/[A-Za-z0-9._%+-]{1,64}@[A-Za-z0-9-]{1,63}(?:\.[A-Za-z0-9-]{1,63}){0,8}\.[A-Za-z]{2,24}\b/g, "[email]"],
|
|
22
|
+
// affixes are bounded so a long run of key-like characters cannot backtrack quadratically
|
|
23
|
+
[/\b([A-Za-z0-9_.-]{0,40}(?:(?:token|secret|password|passwd|pwd|api[_-]?key|access[_-]?key|private[_-]?key|auth|credential|dsn|session|cookie)[A-Za-z0-9_.-]{0,40}|key))(["']?\s*[=:]\s*)(\[redacted\]|"[^"]*"|'[^']*'|[^\s&,;]+)/gi, "$1$2[redacted]"]
|
|
24
|
+
];
|
|
25
|
+
var escapeRe = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
26
|
+
var longestFirst = (xs, min) => [...new Set(xs.filter((x) => x.length >= min))].sort((a, b) => b.length - a.length);
|
|
27
|
+
function buildScrubContext(o) {
|
|
28
|
+
const words = new Set(o.commandWords);
|
|
29
|
+
const argvValues = o.argv.flatMap((a) => {
|
|
30
|
+
if (a.startsWith("-")) {
|
|
31
|
+
const i = a.indexOf("=");
|
|
32
|
+
return i > 0 ? [a.slice(i + 1)] : [];
|
|
33
|
+
}
|
|
34
|
+
return words.has(a) ? [] : [a];
|
|
35
|
+
});
|
|
36
|
+
const secretEnvValues = Object.entries(o.env).flatMap(([k, v]) => v && SECRET_ENV_KEY.test(k) ? [v] : []);
|
|
37
|
+
return { home: o.home, platform: o.platform, argvValues: longestFirst(argvValues, 3), secretEnvValues: longestFirst(secretEnvValues, 8) };
|
|
38
|
+
}
|
|
39
|
+
function addSecretValues(ctx, values) {
|
|
40
|
+
ctx.secretEnvValues = longestFirst([...ctx.secretEnvValues, ...values], 8);
|
|
41
|
+
}
|
|
42
|
+
function replaceLiteral(s, needle, repl, flags) {
|
|
43
|
+
return s.replace(new RegExp(escapeRe(needle), flags), () => repl);
|
|
44
|
+
}
|
|
45
|
+
function replaceHome(s, ctx) {
|
|
46
|
+
const win = ctx.platform === "win32";
|
|
47
|
+
const plain = [ctx.home, ...win ? [ctx.home.replace(/\\/g, "/")] : []];
|
|
48
|
+
const variants = /* @__PURE__ */ new Set([...plain, ...plain.map((h) => encodeURI(h).replace(/[?#]/g, encodeURIComponent))]);
|
|
49
|
+
let out = s;
|
|
50
|
+
for (const h of [...variants].filter((v) => v.length > 1).sort((a, b) => b.length - a.length)) {
|
|
51
|
+
out = out.replace(new RegExp(`${escapeRe(h)}(?![A-Za-z0-9._-])`, win ? "gi" : "g"), () => "~");
|
|
52
|
+
}
|
|
53
|
+
return out;
|
|
54
|
+
}
|
|
55
|
+
var PKG = "node_modules/@quatronic/qore/";
|
|
56
|
+
var NM = "node_modules/";
|
|
57
|
+
function rewritePath(p, ctx) {
|
|
58
|
+
if (p.startsWith("app://") || !/^(?:file:\/\/|\/|[A-Za-z]:[\\/])/.test(p)) return { path: p };
|
|
59
|
+
let s = p.replace(/^file:\/\//, "");
|
|
60
|
+
if (ctx.platform === "win32") s = s.replace(/\\/g, "/").replace(/^\/(?=[A-Za-z]:)/, "");
|
|
61
|
+
const pkg = s.lastIndexOf(PKG);
|
|
62
|
+
const nm = s.lastIndexOf(NM);
|
|
63
|
+
if (pkg >= 0 && pkg === nm) return { path: `app:///${s.slice(pkg + PKG.length)}`, inApp: true };
|
|
64
|
+
if (nm >= 0) return { path: `app:///${s.slice(nm)}`, inApp: false };
|
|
65
|
+
return { path: `app:///${replaceHome(s, ctx).replace(/^\/+/, "")}` };
|
|
66
|
+
}
|
|
67
|
+
function framePath(p, ctx) {
|
|
68
|
+
return rewritePath(p, ctx).path;
|
|
69
|
+
}
|
|
70
|
+
function scrubText(s, ctx) {
|
|
71
|
+
let out = s;
|
|
72
|
+
for (const v of ctx.secretEnvValues) out = replaceLiteral(out, v, "[env]", "g");
|
|
73
|
+
for (const v of ctx.argvValues) out = replaceLiteral(out, v, "[arg]", "g");
|
|
74
|
+
out = replaceHome(out, ctx);
|
|
75
|
+
for (const [re, repl] of PATTERNS) out = out.replace(re, repl);
|
|
76
|
+
return out;
|
|
77
|
+
}
|
|
78
|
+
function hostOf(url) {
|
|
79
|
+
if (typeof url !== "string") return void 0;
|
|
80
|
+
try {
|
|
81
|
+
return new URL(url).host;
|
|
82
|
+
} catch {
|
|
83
|
+
return void 0;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
function scrubBreadcrumb(b, ctx) {
|
|
87
|
+
if (b.category === "console") return null;
|
|
88
|
+
if (b.type === "http" || b.category === "http" || b.category === "fetch") {
|
|
89
|
+
const d = b.data ?? {};
|
|
90
|
+
return {
|
|
91
|
+
type: b.type,
|
|
92
|
+
category: b.category,
|
|
93
|
+
level: b.level,
|
|
94
|
+
timestamp: b.timestamp,
|
|
95
|
+
data: { method: d.method ?? d["http.method"], host: hostOf(d.url) ?? d.host, status_code: d.status_code }
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
return { ...b, message: b.message === void 0 ? void 0 : scrubText(b.message, ctx), data: void 0 };
|
|
99
|
+
}
|
|
100
|
+
function scrubEvent(e, ctx) {
|
|
101
|
+
e.user = { ip_address: null };
|
|
102
|
+
delete e.server_name;
|
|
103
|
+
delete e.request;
|
|
104
|
+
delete e.extra;
|
|
105
|
+
delete e.modules;
|
|
106
|
+
for (const k of Object.keys(e.contexts ?? {})) if (!KEEP_CONTEXTS.has(k)) delete e.contexts[k];
|
|
107
|
+
if (e.message !== void 0) e.message = scrubText(e.message, ctx);
|
|
108
|
+
if (e.logentry?.message !== void 0) {
|
|
109
|
+
e.logentry.message = scrubText(e.logentry.message, ctx);
|
|
110
|
+
delete e.logentry.params;
|
|
111
|
+
}
|
|
112
|
+
for (const v of e.exception?.values ?? []) {
|
|
113
|
+
if (v.value !== void 0) v.value = scrubText(v.value, ctx);
|
|
114
|
+
for (const f of v.stacktrace?.frames ?? []) {
|
|
115
|
+
for (const k of ["filename", "abs_path"]) {
|
|
116
|
+
if (!f[k]) continue;
|
|
117
|
+
const r = rewritePath(f[k], ctx);
|
|
118
|
+
f[k] = r.path;
|
|
119
|
+
if (r.inApp !== void 0) f.in_app = r.inApp;
|
|
120
|
+
}
|
|
121
|
+
if (f.module) f.module = replaceHome(f.module, ctx);
|
|
122
|
+
delete f.vars;
|
|
123
|
+
delete f.pre_context;
|
|
124
|
+
delete f.context_line;
|
|
125
|
+
delete f.post_context;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
for (const img of e.debug_meta?.images ?? []) if (img.code_file) img.code_file = framePath(img.code_file, ctx);
|
|
129
|
+
if (e.breadcrumbs) e.breadcrumbs = e.breadcrumbs.map((b) => scrubBreadcrumb(b, ctx)).filter((b) => b !== null);
|
|
130
|
+
return e;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export {
|
|
134
|
+
buildScrubContext,
|
|
135
|
+
addSecretValues,
|
|
136
|
+
scrubBreadcrumb,
|
|
137
|
+
scrubEvent
|
|
138
|
+
};
|
|
139
|
+
//# sourceMappingURL=chunk-OAU6HJHZ.js.map
|
|
140
|
+
//# debugId=885f6de1-0da7-54a5-86df-beaf550bdd8a
|