@mushi-mushi/svelte 0.8.4 → 0.9.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/CONTRIBUTING.md CHANGED
@@ -101,6 +101,17 @@ Releases are fully automated. Maintainers don't run `npm publish` by hand.
101
101
 
102
102
  If GitHub's anti-loop protection suppresses the auto re-fire (the squash merge can be attributed to `github-actions[bot]`), trigger the workflow manually: **Actions → release → Run workflow → master**.
103
103
 
104
+ ### Known CI/CD quirks and their automatic safeguards
105
+
106
+ A handful of GitHub-Actions × Changesets edge cases have caused release-pipeline stalls in the past. Each is now caught automatically — keep these in mind when you see the symptom:
107
+
108
+ | Symptom | Root cause | Automatic safeguard |
109
+ | --- | --- | --- |
110
+ | The `Build & Test` required check never registers on the `chore: version packages` PR — the PR stays "Required check missing" forever | `changeset-release/master` is pushed by `github-actions[bot]`. GitHub silently drops the downstream `pull_request` event to prevent bot loops (observed on PR #45, #102, #124). | `ci.yml` now also triggers on `push` to `changeset-release/master`, so `Build & Test` reports against the head commit directly. No empty-commit nudge needed. |
111
+ | Release workflow fails with `No commits between master and changeset-release/master` after merging a PR with a new changeset. | A `.changeset/*.md` file whose YAML frontmatter only targets packages listed in `.changeset/config.json#ignore` (e.g. `@mushi-mushi/server`, `@mushi-mushi/admin`). `changeset version` produces no bumps, the version PR is empty, the next push errors (PR #102 / #121, 2026-05-19). | `pnpm check:changeset-orphans` runs in both `ci.yml` and `release.yml`. PR CI fails with an actionable message naming the orphan file *before* it can reach master. If you legitimately need to record an internal-only change, omit the changeset entirely — the diff lives in git history. |
112
+ | Release workflow's `Audit signatures of installed dependencies` step fails with `npm ETARGET / No matching version found for @mushi-mushi/<pkg>@<ver>` seconds after the publish step succeeded. | npm's registry CDN can take up to ~30s to propagate a freshly-published manifest. The audit step shells out to `npm install` against the just-published version and races the CDN (observed 2026-05-20, run 26149167393). | The audit step retries with exponential backoff (1, 2, 4, 8, 16, 32s — 63s total) before failing. Sigstore signatures are written at publish time, so a one-off audit failure never indicates a corrupted package — `pnpm view <pkg> version` is the ground truth. |
113
+ | Push to `master` after merging a PR doesn't fire the `Release` workflow. | Same anti-loop protection: when a squash merge is attributed to `github-actions[bot]`, GitHub may suppress the downstream `push` trigger. Sporadic — observed twice in the last 60 days. | `release.yml` keeps `workflow_dispatch` as the manual fallback. Recovery: **Actions → Release → Run workflow → master**. The `Build & Verify` job re-runs identically to the auto-fired path. |
114
+
104
115
  ### Adding a brand-new publishable package
105
116
 
106
117
  Trusted Publisher bindings are configured **per package** on `npmjs.com` and require the package to already exist on the registry. New packages therefore need a one-time bootstrap before OIDC can take over.
package/dist/index.cjs CHANGED
@@ -22,24 +22,23 @@ var index_exports = {};
22
22
  __export(index_exports, {
23
23
  createMushiErrorHandler: () => createMushiErrorHandler,
24
24
  getMushi: () => getMushi,
25
- initMushi: () => initMushi
25
+ initMushi: () => initMushi,
26
+ mushiHandleError: () => mushiHandleError
26
27
  });
27
28
  module.exports = __toCommonJS(index_exports);
28
29
  var import_web = require("@mushi-mushi/web");
29
- function toCoreConfig(config) {
30
- return {
31
- projectId: config.projectId,
32
- apiKey: config.apiKey,
33
- ...config.endpoint ? { apiEndpoint: config.endpoint } : {},
34
- ...config.capture !== void 0 ? { capture: config.capture } : {}
35
- };
36
- }
30
+ var isBrowser = () => typeof globalThis !== "undefined" && typeof globalThis.window !== "undefined" && typeof globalThis.document !== "undefined";
37
31
  function initMushi(config) {
38
- return import_web.Mushi.init(toCoreConfig(config));
32
+ if (!isBrowser()) return null;
33
+ return import_web.Mushi.init(config);
39
34
  }
40
35
  function getMushi() {
41
36
  const instance = import_web.Mushi.getInstance();
42
- if (!instance) throw new Error("Call initMushi() first");
37
+ if (!instance) {
38
+ throw new Error(
39
+ "Mushi not initialised \u2014 call initMushi() in src/hooks.client.ts or a top-level +layout.svelte onMount."
40
+ );
41
+ }
43
42
  return instance;
44
43
  }
45
44
  function createMushiErrorHandler() {
@@ -54,9 +53,29 @@ function createMushiErrorHandler() {
54
53
  }
55
54
  };
56
55
  }
56
+ function mushiHandleError(opts = {}) {
57
+ return (input) => {
58
+ const { error, event, status, message } = input;
59
+ const instance = import_web.Mushi.getInstance();
60
+ if (instance) {
61
+ instance.captureException(error, {
62
+ source: "sveltekit-handle-error",
63
+ metadata: {
64
+ route: event?.url?.pathname,
65
+ method: event?.request?.method,
66
+ status,
67
+ message
68
+ }
69
+ }).catch(() => {
70
+ });
71
+ }
72
+ return opts.format?.(error, event);
73
+ };
74
+ }
57
75
  // Annotate the CommonJS export names for ESM import in node:
58
76
  0 && (module.exports = {
59
77
  createMushiErrorHandler,
60
78
  getMushi,
61
- initMushi
79
+ initMushi,
80
+ mushiHandleError
62
81
  });
package/dist/index.d.cts CHANGED
@@ -1,22 +1,38 @@
1
- import { MushiSDKInstance } from '@mushi-mushi/core';
1
+ import { MushiSDKInstance, MushiConfig } from '@mushi-mushi/core';
2
+ export { MushiConfig, MushiReportCategory, MushiSDKInstance } from '@mushi-mushi/core';
2
3
 
3
4
  /**
4
5
  * FILE: packages/svelte/src/index.ts
5
- * PURPOSE: Svelte SDK for Mushi Mushi — delegates entirely to @mushi-mushi/web
6
- * so offline queue, PII scrubber, breadcrumb buffer, and rate limiter
7
- * are all inherited automatically. Mirrors the React provider pattern.
6
+ * PURPOSE: Svelte / SvelteKit SDK for Mushi Mushi — delegates entirely
7
+ * to @mushi-mushi/web so offline queue, PII scrubber, breadcrumb
8
+ * buffer, rate limiter, INP capture, beforeSendFeedback, and
9
+ * onCrashedLastRun are all inherited automatically.
10
+ *
11
+ * Round 8 (2026-05-21):
12
+ * - `MushiConfig` is now the canonical core type. Consumers get the
13
+ * full Round 7 surface (theme, position, locale, beforeSendFeedback,
14
+ * onCrashedLastRun, …) with no narrow re-shape.
15
+ * - SSR guard around `initMushi` so SvelteKit's first server-render
16
+ * doesn't reach for `window`.
17
+ * - `mushiHandleError` is the SvelteKit-shaped server-hook helper
18
+ * for `src/hooks.server.ts` — it returns `App.Error | void` to fit
19
+ * the SvelteKit type contract.
8
20
  */
9
21
 
10
- interface MushiConfig {
11
- projectId: string;
12
- apiKey: string;
13
- endpoint?: string;
14
- capture?: {
15
- discoverInventory?: boolean;
16
- };
17
- }
18
- declare function initMushi(config: MushiConfig): MushiSDKInstance;
22
+ /**
23
+ * Initialise the Mushi SDK. SSR-safe: returns `null` when run on the
24
+ * server (SvelteKit's hooks.server.ts) so the runner can skip wiring
25
+ * up on the wrong side. Mount this from `src/hooks.client.ts`'s
26
+ * `init` export, or from a top-level `+layout.svelte`'s `onMount`.
27
+ */
28
+ declare function initMushi(config: MushiConfig): MushiSDKInstance | null;
19
29
  declare function getMushi(): MushiSDKInstance;
30
+ /**
31
+ * Generic error-handler factory — works in any Svelte / SvelteKit
32
+ * context that surfaces an `{ error, event }` shape. Kept for
33
+ * backwards compatibility; new code should prefer `mushiHandleError`
34
+ * which matches SvelteKit's `handleError` server-hook type exactly.
35
+ */
20
36
  declare function createMushiErrorHandler(): ({ error, event }: {
21
37
  error: unknown;
22
38
  event?: {
@@ -25,5 +41,47 @@ declare function createMushiErrorHandler(): ({ error, event }: {
25
41
  };
26
42
  };
27
43
  }) => void;
44
+ /**
45
+ * SvelteKit `handleError` server-hook helper. Drop into
46
+ * `src/hooks.server.ts` and `src/hooks.client.ts`:
47
+ *
48
+ * ```ts
49
+ * // src/hooks.server.ts
50
+ * import type { HandleServerError } from '@sveltejs/kit'
51
+ * import { mushiHandleError } from '@mushi-mushi/svelte'
52
+ *
53
+ * export const handleError: HandleServerError = mushiHandleError({
54
+ * // optional — the default extracts a stable message from the error
55
+ * format: (error) => ({ message: 'Internal error', code: 'E_INTERNAL' }),
56
+ * })
57
+ * ```
58
+ *
59
+ * The returned hook captures the error to Mushi and forwards the
60
+ * formatted shape to SvelteKit's typed `App.Error` interface so the
61
+ * +error.svelte page receives a consistent payload.
62
+ *
63
+ * Server-side: writes via `Mushi.getInstance()` if `initMushi` was
64
+ * called from `hooks.server.ts`. Otherwise no-ops gracefully.
65
+ */
66
+ interface MushiHandleErrorOptions {
67
+ /** Optional formatter that maps the error to `App.Error`. */
68
+ format?: (error: unknown, event?: SvelteKitErrorEvent) => Record<string, unknown> | void;
69
+ }
70
+ interface SvelteKitErrorEvent {
71
+ url?: {
72
+ pathname?: string;
73
+ };
74
+ request?: {
75
+ method?: string;
76
+ };
77
+ status?: number;
78
+ message?: string;
79
+ }
80
+ declare function mushiHandleError(opts?: MushiHandleErrorOptions): (input: {
81
+ error: unknown;
82
+ event?: SvelteKitErrorEvent;
83
+ status?: number;
84
+ message?: string;
85
+ }) => Record<string, unknown> | void;
28
86
 
29
- export { type MushiConfig, createMushiErrorHandler, getMushi, initMushi };
87
+ export { type MushiHandleErrorOptions, type SvelteKitErrorEvent, createMushiErrorHandler, getMushi, initMushi, mushiHandleError };
package/dist/index.d.ts CHANGED
@@ -1,22 +1,38 @@
1
- import { MushiSDKInstance } from '@mushi-mushi/core';
1
+ import { MushiSDKInstance, MushiConfig } from '@mushi-mushi/core';
2
+ export { MushiConfig, MushiReportCategory, MushiSDKInstance } from '@mushi-mushi/core';
2
3
 
3
4
  /**
4
5
  * FILE: packages/svelte/src/index.ts
5
- * PURPOSE: Svelte SDK for Mushi Mushi — delegates entirely to @mushi-mushi/web
6
- * so offline queue, PII scrubber, breadcrumb buffer, and rate limiter
7
- * are all inherited automatically. Mirrors the React provider pattern.
6
+ * PURPOSE: Svelte / SvelteKit SDK for Mushi Mushi — delegates entirely
7
+ * to @mushi-mushi/web so offline queue, PII scrubber, breadcrumb
8
+ * buffer, rate limiter, INP capture, beforeSendFeedback, and
9
+ * onCrashedLastRun are all inherited automatically.
10
+ *
11
+ * Round 8 (2026-05-21):
12
+ * - `MushiConfig` is now the canonical core type. Consumers get the
13
+ * full Round 7 surface (theme, position, locale, beforeSendFeedback,
14
+ * onCrashedLastRun, …) with no narrow re-shape.
15
+ * - SSR guard around `initMushi` so SvelteKit's first server-render
16
+ * doesn't reach for `window`.
17
+ * - `mushiHandleError` is the SvelteKit-shaped server-hook helper
18
+ * for `src/hooks.server.ts` — it returns `App.Error | void` to fit
19
+ * the SvelteKit type contract.
8
20
  */
9
21
 
10
- interface MushiConfig {
11
- projectId: string;
12
- apiKey: string;
13
- endpoint?: string;
14
- capture?: {
15
- discoverInventory?: boolean;
16
- };
17
- }
18
- declare function initMushi(config: MushiConfig): MushiSDKInstance;
22
+ /**
23
+ * Initialise the Mushi SDK. SSR-safe: returns `null` when run on the
24
+ * server (SvelteKit's hooks.server.ts) so the runner can skip wiring
25
+ * up on the wrong side. Mount this from `src/hooks.client.ts`'s
26
+ * `init` export, or from a top-level `+layout.svelte`'s `onMount`.
27
+ */
28
+ declare function initMushi(config: MushiConfig): MushiSDKInstance | null;
19
29
  declare function getMushi(): MushiSDKInstance;
30
+ /**
31
+ * Generic error-handler factory — works in any Svelte / SvelteKit
32
+ * context that surfaces an `{ error, event }` shape. Kept for
33
+ * backwards compatibility; new code should prefer `mushiHandleError`
34
+ * which matches SvelteKit's `handleError` server-hook type exactly.
35
+ */
20
36
  declare function createMushiErrorHandler(): ({ error, event }: {
21
37
  error: unknown;
22
38
  event?: {
@@ -25,5 +41,47 @@ declare function createMushiErrorHandler(): ({ error, event }: {
25
41
  };
26
42
  };
27
43
  }) => void;
44
+ /**
45
+ * SvelteKit `handleError` server-hook helper. Drop into
46
+ * `src/hooks.server.ts` and `src/hooks.client.ts`:
47
+ *
48
+ * ```ts
49
+ * // src/hooks.server.ts
50
+ * import type { HandleServerError } from '@sveltejs/kit'
51
+ * import { mushiHandleError } from '@mushi-mushi/svelte'
52
+ *
53
+ * export const handleError: HandleServerError = mushiHandleError({
54
+ * // optional — the default extracts a stable message from the error
55
+ * format: (error) => ({ message: 'Internal error', code: 'E_INTERNAL' }),
56
+ * })
57
+ * ```
58
+ *
59
+ * The returned hook captures the error to Mushi and forwards the
60
+ * formatted shape to SvelteKit's typed `App.Error` interface so the
61
+ * +error.svelte page receives a consistent payload.
62
+ *
63
+ * Server-side: writes via `Mushi.getInstance()` if `initMushi` was
64
+ * called from `hooks.server.ts`. Otherwise no-ops gracefully.
65
+ */
66
+ interface MushiHandleErrorOptions {
67
+ /** Optional formatter that maps the error to `App.Error`. */
68
+ format?: (error: unknown, event?: SvelteKitErrorEvent) => Record<string, unknown> | void;
69
+ }
70
+ interface SvelteKitErrorEvent {
71
+ url?: {
72
+ pathname?: string;
73
+ };
74
+ request?: {
75
+ method?: string;
76
+ };
77
+ status?: number;
78
+ message?: string;
79
+ }
80
+ declare function mushiHandleError(opts?: MushiHandleErrorOptions): (input: {
81
+ error: unknown;
82
+ event?: SvelteKitErrorEvent;
83
+ status?: number;
84
+ message?: string;
85
+ }) => Record<string, unknown> | void;
28
86
 
29
- export { type MushiConfig, createMushiErrorHandler, getMushi, initMushi };
87
+ export { type MushiHandleErrorOptions, type SvelteKitErrorEvent, createMushiErrorHandler, getMushi, initMushi, mushiHandleError };
package/dist/index.js CHANGED
@@ -1,19 +1,17 @@
1
1
  // src/index.ts
2
2
  import { Mushi } from "@mushi-mushi/web";
3
- function toCoreConfig(config) {
4
- return {
5
- projectId: config.projectId,
6
- apiKey: config.apiKey,
7
- ...config.endpoint ? { apiEndpoint: config.endpoint } : {},
8
- ...config.capture !== void 0 ? { capture: config.capture } : {}
9
- };
10
- }
3
+ var isBrowser = () => typeof globalThis !== "undefined" && typeof globalThis.window !== "undefined" && typeof globalThis.document !== "undefined";
11
4
  function initMushi(config) {
12
- return Mushi.init(toCoreConfig(config));
5
+ if (!isBrowser()) return null;
6
+ return Mushi.init(config);
13
7
  }
14
8
  function getMushi() {
15
9
  const instance = Mushi.getInstance();
16
- if (!instance) throw new Error("Call initMushi() first");
10
+ if (!instance) {
11
+ throw new Error(
12
+ "Mushi not initialised \u2014 call initMushi() in src/hooks.client.ts or a top-level +layout.svelte onMount."
13
+ );
14
+ }
17
15
  return instance;
18
16
  }
19
17
  function createMushiErrorHandler() {
@@ -28,8 +26,28 @@ function createMushiErrorHandler() {
28
26
  }
29
27
  };
30
28
  }
29
+ function mushiHandleError(opts = {}) {
30
+ return (input) => {
31
+ const { error, event, status, message } = input;
32
+ const instance = Mushi.getInstance();
33
+ if (instance) {
34
+ instance.captureException(error, {
35
+ source: "sveltekit-handle-error",
36
+ metadata: {
37
+ route: event?.url?.pathname,
38
+ method: event?.request?.method,
39
+ status,
40
+ message
41
+ }
42
+ }).catch(() => {
43
+ });
44
+ }
45
+ return opts.format?.(error, event);
46
+ };
47
+ }
31
48
  export {
32
49
  createMushiErrorHandler,
33
50
  getMushi,
34
- initMushi
51
+ initMushi,
52
+ mushiHandleError
35
53
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mushi-mushi/svelte",
3
- "version": "0.8.4",
3
+ "version": "0.9.0",
4
4
  "license": "MIT",
5
5
  "description": "Svelte SDK for Mushi Mushi — context-based init, SvelteKit error hook integration",
6
6
  "main": "./dist/index.js",
@@ -10,8 +10,8 @@
10
10
  "svelte": ">=4"
11
11
  },
12
12
  "dependencies": {
13
- "@mushi-mushi/core": "^1.2.0",
14
- "@mushi-mushi/web": "^1.2.0"
13
+ "@mushi-mushi/core": "^1.5.0",
14
+ "@mushi-mushi/web": "^1.5.0"
15
15
  },
16
16
  "devDependencies": {
17
17
  "eslint": "^10.3.0",