@mushi-mushi/web 0.2.0 → 0.3.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 +4 -0
- package/dist/index.cjs +57 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +58 -1
- package/dist/index.js.map +1 -1
- package/package.json +16 -5
package/README.md
CHANGED
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
Browser SDK for Mushi Mushi — embeddable bug reporting widget with Shadow DOM isolation.
|
|
4
4
|
|
|
5
|
+
> **One-command setup:** `npx mushi-mushi` installs this package for vanilla-JS apps (or alongside the framework SDK for Vue, Svelte, Angular).
|
|
6
|
+
>
|
|
7
|
+
> **Framework SDKs:** [`@mushi-mushi/react`](https://npmjs.com/package/@mushi-mushi/react) (Next.js / React) · [`@mushi-mushi/vue`](https://npmjs.com/package/@mushi-mushi/vue) (Nuxt / Vue) · [`@mushi-mushi/svelte`](https://npmjs.com/package/@mushi-mushi/svelte) (SvelteKit / Svelte) · [`@mushi-mushi/angular`](https://npmjs.com/package/@mushi-mushi/angular) · [`@mushi-mushi/react-native`](https://npmjs.com/package/@mushi-mushi/react-native) · [`@mushi-mushi/capacitor`](https://npmjs.com/package/@mushi-mushi/capacitor)
|
|
8
|
+
|
|
5
9
|
## Features
|
|
6
10
|
|
|
7
11
|
- Shadow DOM widget with full CSS isolation from host page
|
package/dist/index.cjs
CHANGED
|
@@ -1545,6 +1545,7 @@ function createInstance(config) {
|
|
|
1545
1545
|
}
|
|
1546
1546
|
const scrubbedDescription = piiScrubber.scrub(preFilter.truncate(description));
|
|
1547
1547
|
const sentryCtx = config.sentry ? captureSentryContext(config.sentry) : void 0;
|
|
1548
|
+
const fingerprintHash = await core.getDeviceFingerprintHash().catch(() => null);
|
|
1548
1549
|
const report = {
|
|
1549
1550
|
id: crypto.randomUUID?.() ?? `mushi_${Date.now()}_${Math.random().toString(36).slice(2)}`,
|
|
1550
1551
|
projectId: config.projectId,
|
|
@@ -1564,6 +1565,7 @@ function createInstance(config) {
|
|
|
1564
1565
|
},
|
|
1565
1566
|
sessionId: core.getSessionId(),
|
|
1566
1567
|
reporterToken: core.getReporterToken(),
|
|
1568
|
+
...fingerprintHash ? { fingerprintHash } : {},
|
|
1567
1569
|
appVersion: config.integrations?.vercel?.analyticsId,
|
|
1568
1570
|
proactiveTrigger: pendingProactiveTrigger ?? void 0,
|
|
1569
1571
|
sentryEventId: sentryCtx?.eventId,
|
|
@@ -1640,6 +1642,58 @@ function createInstance(config) {
|
|
|
1640
1642
|
listeners.clear();
|
|
1641
1643
|
instance = null;
|
|
1642
1644
|
log.debug("Destroyed");
|
|
1645
|
+
},
|
|
1646
|
+
// Wave G4 — unified `captureEvent` API for programmatic/adapter-driven
|
|
1647
|
+
// reports. Skips the widget, runs the same PII scrub + rate limit +
|
|
1648
|
+
// offline-queue path as `submit()`, and returns the server report id.
|
|
1649
|
+
async captureEvent(input) {
|
|
1650
|
+
if (!rateLimiter.tryConsume()) {
|
|
1651
|
+
log.warn("captureEvent throttled \u2014 rate limit exceeded");
|
|
1652
|
+
return null;
|
|
1653
|
+
}
|
|
1654
|
+
const description = piiScrubber.scrub(preFilter.truncate(input.description));
|
|
1655
|
+
const category = input.category ?? "bug";
|
|
1656
|
+
const report = {
|
|
1657
|
+
id: crypto.randomUUID?.() ?? `mushi_${Date.now()}_${Math.random().toString(36).slice(2)}`,
|
|
1658
|
+
projectId: config.projectId,
|
|
1659
|
+
category,
|
|
1660
|
+
description,
|
|
1661
|
+
environment: core.captureEnvironment(),
|
|
1662
|
+
metadata: {
|
|
1663
|
+
...input.metadata ?? {},
|
|
1664
|
+
...userInfo ? { user: userInfo } : {},
|
|
1665
|
+
...input.tags ? { tags: input.tags } : {},
|
|
1666
|
+
...input.error ? { error: input.error } : {},
|
|
1667
|
+
...input.severity ? { severity: input.severity } : {},
|
|
1668
|
+
...input.component ? { component: input.component } : {},
|
|
1669
|
+
...input.source ? { source: input.source } : { source: "captureEvent" }
|
|
1670
|
+
},
|
|
1671
|
+
sessionId: core.getSessionId(),
|
|
1672
|
+
reporterToken: core.getReporterToken(),
|
|
1673
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1674
|
+
};
|
|
1675
|
+
emit("report:submitted", { reportId: report.id });
|
|
1676
|
+
if (typeof navigator !== "undefined" && !navigator.onLine) {
|
|
1677
|
+
await offlineQueue.enqueue(report);
|
|
1678
|
+
emit("report:queued", { reportId: report.id });
|
|
1679
|
+
return null;
|
|
1680
|
+
}
|
|
1681
|
+
const res = await apiClient.submitReport(report);
|
|
1682
|
+
if (res.ok) {
|
|
1683
|
+
emit("report:sent", { reportId: res.data?.reportId });
|
|
1684
|
+
return res.data?.reportId ?? null;
|
|
1685
|
+
}
|
|
1686
|
+
await offlineQueue.enqueue(report);
|
|
1687
|
+
emit("report:failed", { reportId: report.id, error: res.error });
|
|
1688
|
+
return null;
|
|
1689
|
+
},
|
|
1690
|
+
identify(userId, traits) {
|
|
1691
|
+
userInfo = { id: userId, ...traits?.email ? { email: traits.email } : {}, ...traits?.name ? { name: traits.name } : {} };
|
|
1692
|
+
if (traits) {
|
|
1693
|
+
for (const [k, v] of Object.entries(traits)) {
|
|
1694
|
+
if (k !== "email" && k !== "name") customMetadata[`user.${k}`] = v;
|
|
1695
|
+
}
|
|
1696
|
+
}
|
|
1643
1697
|
}
|
|
1644
1698
|
};
|
|
1645
1699
|
return sdk;
|
|
@@ -1661,6 +1715,9 @@ function createNoopInstance() {
|
|
|
1661
1715
|
},
|
|
1662
1716
|
destroy: () => {
|
|
1663
1717
|
instance = null;
|
|
1718
|
+
},
|
|
1719
|
+
captureEvent: async () => null,
|
|
1720
|
+
identify: () => {
|
|
1664
1721
|
}
|
|
1665
1722
|
};
|
|
1666
1723
|
}
|