@mushi-mushi/core 1.22.4 → 1.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +56 -1
- package/dist/index.cjs +249 -31
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +52 -2
- package/dist/index.d.ts +52 -2
- package/dist/index.js +247 -32
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -23,7 +23,7 @@ Core types, API client, and shared utilities for every Mushi SDK package.
|
|
|
23
23
|
|
|
24
24
|
| Type | Purpose |
|
|
25
25
|
|----------------------------|-----------------------------------------------------------------------------------------------|
|
|
26
|
-
| `MushiPreset` | `'production-calm' \| 'beta-loud' \| 'internal-debug' \| 'manual-only'`
|
|
26
|
+
| `MushiPreset` | Posture bundles: `'production-calm' \| 'beta-loud' \| 'internal-debug' \| 'manual-only'` plus the tiers `'minimal' \| 'standard' \| 'full'`. See [Config presets](#config-presets--precedence). |
|
|
27
27
|
| `MushiWidgetAnchor` | Raw-CSS positioning (`top` / `right` / `bottom` / `left`) for the widget launcher. |
|
|
28
28
|
| `MushiPrivacyConfig` | `maskSelectors`, `blockSelectors`, `allowUserRemoveScreenshot` for screenshot redaction. |
|
|
29
29
|
| `MushiUrlMatcher` | `string \| RegExp` element used by `capture.ignoreUrls` and `apiCascade.ignoreUrls`. |
|
|
@@ -46,6 +46,61 @@ Constants: `MUSHI_INTERNAL_HEADER` (`'X-Mushi-Internal'`),
|
|
|
46
46
|
`MUSHI_INTERNAL_INIT_MARKER`, and the `MushiInternalRequestKind` literal union
|
|
47
47
|
are re-exported so framework adapters can build their own self-noise filters.
|
|
48
48
|
|
|
49
|
+
## Config presets & precedence
|
|
50
|
+
|
|
51
|
+
Pass `preset` to pick a posture bundle instead of hand-assembling
|
|
52
|
+
`widget` / `capture` / `proactive` flags. `expandPreset(config)` expands the
|
|
53
|
+
preset into those nested objects; **your explicit config always wins** on every
|
|
54
|
+
key (the merge is per-sub-object, so overriding one `capture` flag keeps the
|
|
55
|
+
rest of the preset's defaults).
|
|
56
|
+
|
|
57
|
+
| Field | `minimal` | `standard` | `full` |
|
|
58
|
+
|----------------------|----------------|--------------------|------------------|
|
|
59
|
+
| Widget | on (`auto`) | on (SDK default) | on (`auto`) |
|
|
60
|
+
| `capture.console` | ✅ | default | ✅ |
|
|
61
|
+
| `capture.network` | ❌ | default | ✅ |
|
|
62
|
+
| `capture.performance`| ❌ | default | ✅ |
|
|
63
|
+
| `capture.screenshot` | `on-report` | default | `auto` |
|
|
64
|
+
| `capture.replay` | `off` | default | `lite` |
|
|
65
|
+
| Proactive triggers | none | default | all on |
|
|
66
|
+
|
|
67
|
+
- **`minimal`** — widget + console capture only, screenshot on report; no
|
|
68
|
+
network/performance/replay, no proactive nudges. Leanest footprint.
|
|
69
|
+
- **`standard`** — today's SDK defaults. Expansion is a **no-op** (the config
|
|
70
|
+
is returned untouched); the preset exists so the intent is explicit and
|
|
71
|
+
documented.
|
|
72
|
+
- **`full`** — every capture channel on (including a self-contained `lite`
|
|
73
|
+
session replay) and all proactive triggers. Loudest / most data.
|
|
74
|
+
|
|
75
|
+
The four legacy postures — `production-calm`, `beta-loud`, `internal-debug`,
|
|
76
|
+
`manual-only` — are still supported and expand the same way.
|
|
77
|
+
|
|
78
|
+
### Precedence
|
|
79
|
+
|
|
80
|
+
Highest wins. `resolveEnvConfig()` only ever supplies
|
|
81
|
+
`projectId` / `apiKey` / `apiEndpoint`, so it never competes with a preset for
|
|
82
|
+
the nested option objects.
|
|
83
|
+
|
|
84
|
+
| Priority | Source | Example |
|
|
85
|
+
|----------|-------------------------------------|-------------------------------------------|
|
|
86
|
+
| 1 (wins) | Explicit config | `capture: { network: true }` |
|
|
87
|
+
| 2 | `preset` | `preset: 'minimal'` → `network: false` |
|
|
88
|
+
| 3 | Environment variables | `NEXT_PUBLIC_MUSHI_*` / `VITE_MUSHI_*` |
|
|
89
|
+
| 4 | SDK defaults | built-in fallbacks |
|
|
90
|
+
|
|
91
|
+
### Validation
|
|
92
|
+
|
|
93
|
+
`validateConfig(config)` runs at init and **fails loud but never throws**: it
|
|
94
|
+
`console.error`s on unknown top-level keys (usually a typo) and on an invalid
|
|
95
|
+
`preset` value, then continues. Set `MUSHI_SILENT=1` to suppress the warnings.
|
|
96
|
+
|
|
97
|
+
```typescript
|
|
98
|
+
import { expandPreset, validateConfig } from '@mushi-mushi/core';
|
|
99
|
+
|
|
100
|
+
validateConfig(config); // warns on typos / bad preset (never throws)
|
|
101
|
+
const resolved = expandPreset(config); // preset → nested objects, explicit wins
|
|
102
|
+
```
|
|
103
|
+
|
|
49
104
|
## Usage
|
|
50
105
|
|
|
51
106
|
```typescript
|
package/dist/index.cjs
CHANGED
|
@@ -601,6 +601,219 @@ function resolveEnvConfig() {
|
|
|
601
601
|
if (apiEndpoint) result.apiEndpoint = apiEndpoint;
|
|
602
602
|
return result;
|
|
603
603
|
}
|
|
604
|
+
var ENV_PREFIXES = ["VITE_", "NEXT_PUBLIC_", "NUXT_PUBLIC_", "EXPO_PUBLIC_", ""];
|
|
605
|
+
var FIELD_SUFFIX = {
|
|
606
|
+
projectId: "MUSHI_PROJECT_ID",
|
|
607
|
+
apiKey: "MUSHI_API_KEY"
|
|
608
|
+
};
|
|
609
|
+
function diagnoseEnvConfig() {
|
|
610
|
+
const resolved = resolveEnvConfig();
|
|
611
|
+
const missing = [];
|
|
612
|
+
if (!resolved.projectId) missing.push("projectId");
|
|
613
|
+
if (!resolved.apiKey) missing.push("apiKey");
|
|
614
|
+
if (missing.length === 0) {
|
|
615
|
+
return { resolved, missing, nearMisses: [], message: null };
|
|
616
|
+
}
|
|
617
|
+
const importMetaEnv = (() => {
|
|
618
|
+
try {
|
|
619
|
+
const env = undefined;
|
|
620
|
+
return typeof env === "object" && env !== null ? env : null;
|
|
621
|
+
} catch {
|
|
622
|
+
return null;
|
|
623
|
+
}
|
|
624
|
+
})();
|
|
625
|
+
const processEnv = (() => {
|
|
626
|
+
try {
|
|
627
|
+
return typeof process !== "undefined" && process.env ? process.env : null;
|
|
628
|
+
} catch {
|
|
629
|
+
return null;
|
|
630
|
+
}
|
|
631
|
+
})();
|
|
632
|
+
const nearMisses = [];
|
|
633
|
+
for (const field of missing) {
|
|
634
|
+
for (const prefix of ENV_PREFIXES) {
|
|
635
|
+
const key = `${prefix}${FIELD_SUFFIX[field]}`;
|
|
636
|
+
if (importMetaEnv && importMetaEnv[key]) {
|
|
637
|
+
nearMisses.push({ field, key, via: "import.meta.env" });
|
|
638
|
+
} else if (processEnv && processEnv[key]) {
|
|
639
|
+
nearMisses.push({ field, key, via: "process.env" });
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
const expectedPrefix = importMetaEnv ? "VITE_MUSHI_*" : "NEXT_PUBLIC_MUSHI_* (Next.js), EXPO_PUBLIC_MUSHI_* (Expo), or MUSHI_* (Node / React Native)";
|
|
644
|
+
const lines = [`[mushi] Missing ${missing.join(" and ")} \u2014 the SDK will not initialize.`];
|
|
645
|
+
for (const m of nearMisses) {
|
|
646
|
+
lines.push(
|
|
647
|
+
`[mushi] Found ${m.key} in ${m.via}, but this runtime did not resolve it \u2014 it is either the wrong prefix for your bundler or not exposed to the client bundle.`
|
|
648
|
+
);
|
|
649
|
+
}
|
|
650
|
+
lines.push(`[mushi] This runtime reads: ${expectedPrefix}. Set the matching variable(s) and restart your dev server.`);
|
|
651
|
+
if (nearMisses.length === 0) {
|
|
652
|
+
lines.push(
|
|
653
|
+
`[mushi] If you already set the variable, check the prefix: a mis-prefixed var is stripped from client bundles and resolves to undefined with no error.`
|
|
654
|
+
);
|
|
655
|
+
}
|
|
656
|
+
return { resolved, missing, nearMisses, message: lines.join("\n") };
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
// src/presets.ts
|
|
660
|
+
var KNOWN_PRESETS = [
|
|
661
|
+
"production-calm",
|
|
662
|
+
"beta-loud",
|
|
663
|
+
"internal-debug",
|
|
664
|
+
"manual-only",
|
|
665
|
+
"minimal",
|
|
666
|
+
"standard",
|
|
667
|
+
"full"
|
|
668
|
+
];
|
|
669
|
+
var KNOWN_CONFIG_KEYS = [
|
|
670
|
+
"projectId",
|
|
671
|
+
"apiKey",
|
|
672
|
+
"apiEndpoint",
|
|
673
|
+
"timeout",
|
|
674
|
+
"maxRetries",
|
|
675
|
+
"circuitBreaker",
|
|
676
|
+
"preset",
|
|
677
|
+
"runtimeConfig",
|
|
678
|
+
"sentry",
|
|
679
|
+
"widget",
|
|
680
|
+
"capture",
|
|
681
|
+
"privacy",
|
|
682
|
+
"proactive",
|
|
683
|
+
"preFilter",
|
|
684
|
+
"integrations",
|
|
685
|
+
"offline",
|
|
686
|
+
"rewards",
|
|
687
|
+
"assistant",
|
|
688
|
+
"debug",
|
|
689
|
+
"enabled",
|
|
690
|
+
"appVersion",
|
|
691
|
+
"beforeSendFeedback",
|
|
692
|
+
"onCrashedLastRun"
|
|
693
|
+
];
|
|
694
|
+
function presetDefaults(preset) {
|
|
695
|
+
switch (preset) {
|
|
696
|
+
case "manual-only":
|
|
697
|
+
return {
|
|
698
|
+
widget: { trigger: "manual", outdatedBanner: "console-only" },
|
|
699
|
+
capture: { console: true, network: true, performance: false, screenshot: "on-report", elementSelector: false },
|
|
700
|
+
proactive: { rageClick: false, longTask: false, apiCascade: false, errorBoundary: false }
|
|
701
|
+
};
|
|
702
|
+
case "beta-loud":
|
|
703
|
+
return {
|
|
704
|
+
widget: { trigger: "auto", outdatedBanner: "banner" },
|
|
705
|
+
capture: { console: true, network: true, performance: true, screenshot: "auto", elementSelector: true },
|
|
706
|
+
proactive: { rageClick: true, longTask: true, apiCascade: true, errorBoundary: true }
|
|
707
|
+
};
|
|
708
|
+
case "internal-debug":
|
|
709
|
+
return {
|
|
710
|
+
widget: { trigger: "auto", outdatedBanner: "banner", brandFooter: true },
|
|
711
|
+
capture: { console: true, network: true, performance: true, screenshot: "auto", elementSelector: true },
|
|
712
|
+
proactive: {
|
|
713
|
+
rageClick: true,
|
|
714
|
+
longTask: true,
|
|
715
|
+
apiCascade: true,
|
|
716
|
+
errorBoundary: true,
|
|
717
|
+
cooldown: { maxProactivePerSession: 10, dismissCooldownHours: 0, suppressAfterDismissals: 99 }
|
|
718
|
+
}
|
|
719
|
+
};
|
|
720
|
+
case "production-calm":
|
|
721
|
+
return {
|
|
722
|
+
widget: { trigger: "auto", outdatedBanner: "console-only" },
|
|
723
|
+
capture: { console: true, network: true, performance: false, screenshot: "on-report", elementSelector: false },
|
|
724
|
+
proactive: { rageClick: false, longTask: false, apiCascade: false, errorBoundary: false }
|
|
725
|
+
};
|
|
726
|
+
// Lean posture: widget on, console capture only, screenshot on-report,
|
|
727
|
+
// no network/performance/replay, no proactive nudges.
|
|
728
|
+
case "minimal":
|
|
729
|
+
return {
|
|
730
|
+
widget: { trigger: "auto" },
|
|
731
|
+
capture: {
|
|
732
|
+
console: true,
|
|
733
|
+
network: false,
|
|
734
|
+
performance: false,
|
|
735
|
+
screenshot: "on-report",
|
|
736
|
+
replay: "off",
|
|
737
|
+
elementSelector: false
|
|
738
|
+
},
|
|
739
|
+
proactive: { rageClick: false, longTask: false, apiCascade: false, errorBoundary: false }
|
|
740
|
+
};
|
|
741
|
+
// Everything-on posture: full capture (incl. self-contained `lite` replay)
|
|
742
|
+
// and every proactive trigger.
|
|
743
|
+
case "full":
|
|
744
|
+
return {
|
|
745
|
+
widget: { trigger: "auto" },
|
|
746
|
+
capture: {
|
|
747
|
+
console: true,
|
|
748
|
+
network: true,
|
|
749
|
+
performance: true,
|
|
750
|
+
screenshot: "auto",
|
|
751
|
+
replay: "lite",
|
|
752
|
+
elementSelector: true
|
|
753
|
+
},
|
|
754
|
+
proactive: { rageClick: true, longTask: true, apiCascade: true, errorBoundary: true }
|
|
755
|
+
};
|
|
756
|
+
// 'standard' and anything unrecognised → no expansion.
|
|
757
|
+
default:
|
|
758
|
+
return void 0;
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
function expandPreset(config) {
|
|
762
|
+
const defaults = presetDefaults(config.preset);
|
|
763
|
+
if (!defaults) return config;
|
|
764
|
+
return {
|
|
765
|
+
...config,
|
|
766
|
+
widget: {
|
|
767
|
+
...defaults.widget,
|
|
768
|
+
...config.widget
|
|
769
|
+
},
|
|
770
|
+
capture: {
|
|
771
|
+
...defaults.capture,
|
|
772
|
+
...config.capture
|
|
773
|
+
},
|
|
774
|
+
proactive: {
|
|
775
|
+
...defaults.proactive,
|
|
776
|
+
...config.proactive,
|
|
777
|
+
cooldown: {
|
|
778
|
+
...defaults.proactive?.cooldown,
|
|
779
|
+
...config.proactive?.cooldown
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
};
|
|
783
|
+
}
|
|
784
|
+
function isSilenced() {
|
|
785
|
+
const truthy = (v) => v === "1" || v === "true";
|
|
786
|
+
try {
|
|
787
|
+
if (typeof process !== "undefined" && process.env && truthy(process.env.MUSHI_SILENT)) return true;
|
|
788
|
+
} catch {
|
|
789
|
+
}
|
|
790
|
+
try {
|
|
791
|
+
const env = undefined;
|
|
792
|
+
if (env && typeof env === "object" && (truthy(env.MUSHI_SILENT) || truthy(env.VITE_MUSHI_SILENT))) return true;
|
|
793
|
+
} catch {
|
|
794
|
+
}
|
|
795
|
+
return false;
|
|
796
|
+
}
|
|
797
|
+
function validateConfig(config) {
|
|
798
|
+
try {
|
|
799
|
+
if (isSilenced()) return;
|
|
800
|
+
if (!config || typeof config !== "object") return;
|
|
801
|
+
const unknownKeys = Object.keys(config).filter((key) => !KNOWN_CONFIG_KEYS.includes(key));
|
|
802
|
+
if (unknownKeys.length > 0) {
|
|
803
|
+
console.error(
|
|
804
|
+
`[mushi] Unknown config key${unknownKeys.length > 1 ? "s" : ""}: ${unknownKeys.map((k) => `\`${k}\``).join(", ")} \u2014 check for typos (see MushiConfig). Ignored.`
|
|
805
|
+
);
|
|
806
|
+
}
|
|
807
|
+
if (config.preset !== void 0 && !KNOWN_PRESETS.includes(config.preset)) {
|
|
808
|
+
console.error(
|
|
809
|
+
`[mushi] Unknown preset \`${String(config.preset)}\` \u2014 expected one of ${KNOWN_PRESETS.map(
|
|
810
|
+
(p) => `'${p}'`
|
|
811
|
+
).join(", ")}. Preset ignored.`
|
|
812
|
+
);
|
|
813
|
+
}
|
|
814
|
+
} catch {
|
|
815
|
+
}
|
|
816
|
+
}
|
|
604
817
|
|
|
605
818
|
// src/pre-filter.ts
|
|
606
819
|
var DEFAULT_MIN_LENGTH = 10;
|
|
@@ -1648,38 +1861,40 @@ function createRateLimiter(config = {}) {
|
|
|
1648
1861
|
return { tryConsume, reset, availableTokens };
|
|
1649
1862
|
}
|
|
1650
1863
|
|
|
1651
|
-
// src/pii-
|
|
1652
|
-
var
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
]
|
|
1672
|
-
var DEFAULT_CONFIG = {
|
|
1673
|
-
emails: true,
|
|
1674
|
-
phones: true,
|
|
1675
|
-
creditCards: true,
|
|
1676
|
-
ssns: true,
|
|
1677
|
-
ipAddresses: false,
|
|
1678
|
-
// Secret tokens default ON — if they leak into a bug report there's no
|
|
1679
|
-
// good reason to ship them to our servers. Cheaper to scrub client-side.
|
|
1680
|
-
secretTokens: true,
|
|
1681
|
-
ipv6: false
|
|
1864
|
+
// src/pii-patterns.json
|
|
1865
|
+
var pii_patterns_default = {
|
|
1866
|
+
patterns: [
|
|
1867
|
+
{ id: "ssn", configKey: "ssns", source: "\\b\\d{3}-\\d{2}-\\d{4}\\b", replacement: "[REDACTED_SSN]" },
|
|
1868
|
+
{ id: "creditCard", configKey: "creditCards", source: "\\b(?:\\d[ -]*){12,18}\\d\\b", replacement: "[REDACTED_CC]" },
|
|
1869
|
+
{ id: "awsAccessKey", configKey: "secretTokens", source: "\\b(?:AKIA|ASIA)[0-9A-Z]{16}\\b", replacement: "[REDACTED_AWS_KEY]" },
|
|
1870
|
+
{ id: "awsSecretKey", configKey: "secretTokens", source: `(?:aws_secret_access_key|secret_access_key)["'\\s:=]+[A-Za-z0-9/+=]{40}\\b`, caseInsensitive: true, replacement: "aws_secret_access_key=[REDACTED_AWS_SECRET]" },
|
|
1871
|
+
{ id: "stripeSecretKey", configKey: "secretTokens", source: "\\b(?:sk|rk)_(?:live|test)_[A-Za-z0-9]{24,}\\b", replacement: "[REDACTED_STRIPE_KEY]" },
|
|
1872
|
+
{ id: "stripePublishableKey", configKey: "secretTokens", source: "\\bpk_(?:live|test)_[A-Za-z0-9]{24,}\\b", replacement: "[REDACTED_STRIPE_PK]" },
|
|
1873
|
+
{ id: "slackToken", configKey: "secretTokens", source: "\\bxox[abpor]-[A-Za-z0-9-]{10,}\\b", replacement: "[REDACTED_SLACK_TOKEN]" },
|
|
1874
|
+
{ id: "githubPatClassic", configKey: "secretTokens", source: "\\bghp_[A-Za-z0-9]{36}\\b", replacement: "[REDACTED_GITHUB_PAT]" },
|
|
1875
|
+
{ id: "githubPatFineGrained", configKey: "secretTokens", source: "\\bgithub_pat_[A-Za-z0-9_]{80,}\\b", replacement: "[REDACTED_GITHUB_PAT]" },
|
|
1876
|
+
{ id: "openaiKey", configKey: "secretTokens", source: "\\bsk-(?:proj-)?[A-Za-z0-9_-]{20,}\\b", replacement: "[REDACTED_OPENAI_KEY]" },
|
|
1877
|
+
{ id: "anthropicKey", configKey: "secretTokens", source: "\\bsk-ant-[A-Za-z0-9_-]{20,}\\b", replacement: "[REDACTED_ANTHROPIC_KEY]" },
|
|
1878
|
+
{ id: "googleKey", configKey: "secretTokens", source: "\\bAIza[0-9A-Za-z_-]{35}\\b", replacement: "[REDACTED_GOOGLE_KEY]" },
|
|
1879
|
+
{ id: "jwt", configKey: "secretTokens", source: "\\beyJ[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+\\b", replacement: "[REDACTED_JWT]" },
|
|
1880
|
+
{ id: "email", configKey: "emails", source: "\\b[A-Za-z0-9._%+\\-]+@[A-Za-z0-9.\\-]+\\.[A-Za-z]{2,}\\b", replacement: "[REDACTED_EMAIL]" },
|
|
1881
|
+
{ id: "phone", configKey: "phones", source: "(?:\\+\\d{1,3}[\\s.-])?\\(?\\d{2,4}\\)?[\\s.-]\\d{3,4}[\\s.-]\\d{3,4}\\b", replacement: "[REDACTED_PHONE]" },
|
|
1882
|
+
{ id: "ipv4", configKey: "ipAddresses", source: "\\b(?:\\d{1,3}\\.){3}\\d{1,3}\\b", replacement: "[REDACTED_IP]", defaultOn: false },
|
|
1883
|
+
{ id: "ipv6", configKey: "ipv6", source: "\\b(?:[A-Fa-f0-9]{1,4}:){2,7}[A-Fa-f0-9]{0,4}\\b", replacement: "[REDACTED_IPV6]", defaultOn: false }
|
|
1884
|
+
]
|
|
1682
1885
|
};
|
|
1886
|
+
|
|
1887
|
+
// src/pii-scrubber.ts
|
|
1888
|
+
var RAW_PATTERNS = pii_patterns_default.patterns;
|
|
1889
|
+
var ORDERED_PATTERNS = RAW_PATTERNS.map((p) => ({
|
|
1890
|
+
key: p.configKey,
|
|
1891
|
+
regex: new RegExp(p.source, p.caseInsensitive ? "gi" : "g"),
|
|
1892
|
+
replacement: p.replacement
|
|
1893
|
+
}));
|
|
1894
|
+
var DEFAULT_CONFIG = RAW_PATTERNS.reduce((acc, p) => {
|
|
1895
|
+
acc[p.configKey] = p.defaultOn !== false;
|
|
1896
|
+
return acc;
|
|
1897
|
+
}, {});
|
|
1683
1898
|
function createPiiScrubber(config = {}) {
|
|
1684
1899
|
const merged = { ...DEFAULT_CONFIG, ...config };
|
|
1685
1900
|
const activePatterns = ORDERED_PATTERNS.filter((p) => merged[p.key]);
|
|
@@ -2204,7 +2419,9 @@ exports.createOfflineQueue = createOfflineQueue;
|
|
|
2204
2419
|
exports.createPiiScrubber = createPiiScrubber;
|
|
2205
2420
|
exports.createPreFilter = createPreFilter;
|
|
2206
2421
|
exports.createRateLimiter = createRateLimiter;
|
|
2422
|
+
exports.diagnoseEnvConfig = diagnoseEnvConfig;
|
|
2207
2423
|
exports.estimateJsonBytes = estimateJsonBytes;
|
|
2424
|
+
exports.expandPreset = expandPreset;
|
|
2208
2425
|
exports.faviconUrlCandidates = faviconUrlCandidates;
|
|
2209
2426
|
exports.formatBytes = formatBytes;
|
|
2210
2427
|
exports.getDeviceFingerprintHash = getDeviceFingerprintHash;
|
|
@@ -2233,5 +2450,6 @@ exports.resolveWidgetAccent = resolveWidgetAccent;
|
|
|
2233
2450
|
exports.safeWidgetHex = safeWidgetHex;
|
|
2234
2451
|
exports.scrubPii = scrubPii;
|
|
2235
2452
|
exports.sha256Hex = sha256Hex;
|
|
2453
|
+
exports.validateConfig = validateConfig;
|
|
2236
2454
|
//# sourceMappingURL=index.cjs.map
|
|
2237
2455
|
//# sourceMappingURL=index.cjs.map
|