@ai-matrx/kit 0.7.2 → 0.7.3
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/CHANGELOG.md +8 -0
- package/README.md +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/toast.cjs.map +1 -1
- package/dist/toast.d.cts +3 -2
- package/dist/toast.d.ts +3 -2
- package/dist/toast.js.map +1 -1
- package/package.json +2 -8
package/dist/toast.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/toast.ts"],"sourcesContent":["/**\n * @ai-matrx/kit/toast — the captured sonner wrapper, as a factory.\n *\n * A bare `toast.error(...)` from \"sonner\" is INVISIBLE to any error-capture\n * sink — every modern sonner call site silently bypasses error capture (the\n * exact hole matrx-frontend found in its marketing feature, 2026-07-20).\n * `createMatrxToast` returns a drop-in `toast` whose API is identical to the\n * one you pass in — `error` and `warning` additionally feed the injected\n * capture sink. A user seeing the failure is not evidence that it is minor,\n * so error toasts stay red unless a specific downgrade rule says otherwise.\n * Success/info/etc. pass straight through untouched.\n *\n * Ported from matrx-frontend `lib/toast.ts` with the two seams inverted:\n *\n * - `sonner` is NOT imported: the host passes its own `toast` object into the\n * factory (`createMatrxToast({ toast })`). That removes the peer-resolution\n * problem entirely — this module has zero dependencies — and the input is\n * typed STRUCTURALLY (callable + `.error` + `.warning`) so the returned\n * `toast` keeps the host's full sonner type, and no `.d.ts` in this package\n * references \"sonner\".
|
|
1
|
+
{"version":3,"sources":["../src/toast.ts"],"sourcesContent":["/**\n * @ai-matrx/kit/toast — the captured sonner wrapper, as a factory.\n *\n * A bare `toast.error(...)` from \"sonner\" is INVISIBLE to any error-capture\n * sink — every modern sonner call site silently bypasses error capture (the\n * exact hole matrx-frontend found in its marketing feature, 2026-07-20).\n * `createMatrxToast` returns a drop-in `toast` whose API is identical to the\n * one you pass in — `error` and `warning` additionally feed the injected\n * capture sink. A user seeing the failure is not evidence that it is minor,\n * so error toasts stay red unless a specific downgrade rule says otherwise.\n * Success/info/etc. pass straight through untouched.\n *\n * Ported from matrx-frontend `lib/toast.ts` with the two seams inverted:\n *\n * - `sonner` is NOT imported: the host passes its own `toast` object into the\n * factory (`createMatrxToast({ toast })`). That removes the peer-resolution\n * problem entirely — this module has zero dependencies — and the input is\n * typed STRUCTURALLY (callable + `.error` + `.warning`) so the returned\n * `toast` keeps the host's full sonner type, and no `.d.ts` in this package\n * references \"sonner\". Consequently `sonner` is NOT declared in the manifest\n * at all (X3: advisory peers are banned — nothing resolves it, so nothing\n * declares it; it remains a devDependency purely for the type-compat test).\n * - `captureError` from the app's diagnostics store becomes the injected\n * `capture?: (info) => void`. Omitted, capture is a no-op and every call\n * forwards identically (the original's payload shape is preserved exactly:\n * `source: \"user-toast\"`, the `[warning] ` prefix, the \"Error toast\"\n * fallback, `raw: { kind, message?, data }`). A throwing `capture` never\n * breaks the toast.\n *\n * Usage (once, in the host app):\n * import { toast as sonnerToast } from \"sonner\";\n * export const { toast, toastErrorAlreadyCaptured } =\n * createMatrxToast({ toast: sonnerToast, capture: captureError });\n */\n\nimport type { ReactNode } from \"react\";\n\n/** What sonner accepts as a toast title (structural: sonner's `titleT`). */\nexport type ToastMessage = ReactNode | (() => ReactNode);\n\n/** Structural stand-in for sonner's `ExternalToast` options bag. */\nexport interface ToastData {\n description?: unknown;\n [key: string]: unknown;\n}\n\n/**\n * The structural surface this factory needs from the injected toast object:\n * callable, with `error` and `warning` methods. sonner's `toast` satisfies\n * this for every version this package targets. Deliberate typing choices so\n * the REAL sonner object is assignable without a cast under\n * `strictFunctionTypes`: the call signature uses `never[]` (accepts any\n * function — consumers call through their own `T`, never this signature),\n * and `error`/`warning` use METHOD syntax for bivariant parameter checks\n * against sonner's `ExternalToast`.\n */\nexport interface SonnerLikeToast {\n (...args: never[]): string | number;\n error(message: ToastMessage, data?: ToastData): string | number;\n warning(message: ToastMessage, data?: ToastData): string | number;\n}\n\n/** The payload handed to the injected capture sink — the original's shape. */\nexport interface CapturedToastInfo {\n source: \"user-toast\";\n message: string;\n userMessage: string;\n raw: {\n kind: \"error\" | \"warning\";\n message: string | undefined;\n data: ToastData | undefined;\n };\n}\n\nexport interface CreateMatrxToastOptions<T extends SonnerLikeToast> {\n /** The host's sonner `toast` object (or any structural equivalent). */\n toast: T;\n /**\n * Error-capture sink fed by `.error` / `.warning`. Omitted: no-op.\n * Must never be load-bearing — a throw here is swallowed.\n */\n capture?: (info: CapturedToastInfo) => void;\n}\n\nexport interface MatrxToast<T extends SonnerLikeToast> {\n /** Drop-in replacement for the injected `toast`, with error/warning capture. */\n toast: T;\n /**\n * Render an error toast when the originating failure was already captured\n * at its canonical boundary. Only for aggregate/derived UI notices; the\n * caller must be able to name the upstream capture seam.\n */\n toastErrorAlreadyCaptured: T[\"error\"];\n}\n\nfunction messageText(message: ToastMessage, data?: ToastData): string {\n const description =\n data && typeof data.description === \"string\" ? data.description : \"\";\n const title = typeof message === \"string\" ? message : \"\";\n return [title, description].filter(Boolean).join(\" — \") || \"Error toast\";\n}\n\n/** Build the captured toast pair around the host's sonner `toast` object. */\nexport function createMatrxToast<T extends SonnerLikeToast>({\n toast: hostToast,\n capture,\n}: CreateMatrxToastOptions<T>): MatrxToast<T> {\n if (typeof hostToast !== \"function\") {\n throw new Error(\n \"createMatrxToast: options.toast must be the sonner `toast` object (or a structural equivalent) — got \" +\n typeof hostToast,\n );\n }\n\n function captureToast(\n kind: \"error\" | \"warning\",\n message: ToastMessage,\n data?: ToastData,\n ): void {\n if (!capture) return;\n try {\n capture({\n source: \"user-toast\",\n message: `${kind === \"warning\" ? \"[warning] \" : \"\"}${messageText(message, data)}`,\n userMessage: messageText(message, data),\n raw: {\n kind,\n message: typeof message === \"string\" ? message : undefined,\n data,\n },\n });\n } catch {\n /* capture must never break the toast */\n }\n }\n\n const error: SonnerLikeToast[\"error\"] = (message, data) => {\n captureToast(\"error\", message, data);\n return hostToast.error(message, data);\n };\n\n const warning: SonnerLikeToast[\"warning\"] = (message, data) => {\n captureToast(\"warning\", message, data);\n return hostToast.warning(message, data);\n };\n\n // The constraint's call signature is `never[]` (see SonnerLikeToast), so\n // forwarding the base call goes through a widened alias of the host object.\n const forward = hostToast as unknown as (\n ...args: Parameters<T>\n ) => ReturnType<T>;\n const toast: T = Object.assign(\n ((...args: Parameters<T>) => forward(...args)) as unknown as T,\n hostToast,\n { error, warning },\n );\n\n const toastErrorAlreadyCaptured = ((\n message: ToastMessage,\n data?: ToastData,\n ) => hostToast.error(message, data)) as unknown as T[\"error\"];\n\n return { toast, toastErrorAlreadyCaptured };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AA+FA,SAAS,YAAY,SAAuB,MAA0B;AACpE,QAAM,cACJ,QAAQ,OAAO,KAAK,gBAAgB,WAAW,KAAK,cAAc;AACpE,QAAM,QAAQ,OAAO,YAAY,WAAW,UAAU;AACtD,SAAO,CAAC,OAAO,WAAW,EAAE,OAAO,OAAO,EAAE,KAAK,UAAK,KAAK;AAC7D;AAGO,SAAS,iBAA4C;AAAA,EAC1D,OAAO;AAAA,EACP;AACF,GAA8C;AAC5C,MAAI,OAAO,cAAc,YAAY;AACnC,UAAM,IAAI;AAAA,MACR,+GACE,OAAO;AAAA,IACX;AAAA,EACF;AAEA,WAAS,aACP,MACA,SACA,MACM;AACN,QAAI,CAAC,QAAS;AACd,QAAI;AACF,cAAQ;AAAA,QACN,QAAQ;AAAA,QACR,SAAS,GAAG,SAAS,YAAY,eAAe,EAAE,GAAG,YAAY,SAAS,IAAI,CAAC;AAAA,QAC/E,aAAa,YAAY,SAAS,IAAI;AAAA,QACtC,KAAK;AAAA,UACH;AAAA,UACA,SAAS,OAAO,YAAY,WAAW,UAAU;AAAA,UACjD;AAAA,QACF;AAAA,MACF,CAAC;AAAA,IACH,QAAQ;AAAA,IAER;AAAA,EACF;AAEA,QAAM,QAAkC,CAAC,SAAS,SAAS;AACzD,iBAAa,SAAS,SAAS,IAAI;AACnC,WAAO,UAAU,MAAM,SAAS,IAAI;AAAA,EACtC;AAEA,QAAM,UAAsC,CAAC,SAAS,SAAS;AAC7D,iBAAa,WAAW,SAAS,IAAI;AACrC,WAAO,UAAU,QAAQ,SAAS,IAAI;AAAA,EACxC;AAIA,QAAM,UAAU;AAGhB,QAAM,QAAW,OAAO;AAAA,KACrB,IAAI,SAAwB,QAAQ,GAAG,IAAI;AAAA,IAC5C;AAAA,IACA,EAAE,OAAO,QAAQ;AAAA,EACnB;AAEA,QAAM,6BAA6B,CACjC,SACA,SACG,UAAU,MAAM,SAAS,IAAI;AAElC,SAAO,EAAE,OAAO,0BAA0B;AAC5C;","names":[]}
|
package/dist/toast.d.cts
CHANGED
|
@@ -19,8 +19,9 @@ import { ReactNode } from 'react';
|
|
|
19
19
|
* problem entirely — this module has zero dependencies — and the input is
|
|
20
20
|
* typed STRUCTURALLY (callable + `.error` + `.warning`) so the returned
|
|
21
21
|
* `toast` keeps the host's full sonner type, and no `.d.ts` in this package
|
|
22
|
-
* references "sonner".
|
|
23
|
-
*
|
|
22
|
+
* references "sonner". Consequently `sonner` is NOT declared in the manifest
|
|
23
|
+
* at all (X3: advisory peers are banned — nothing resolves it, so nothing
|
|
24
|
+
* declares it; it remains a devDependency purely for the type-compat test).
|
|
24
25
|
* - `captureError` from the app's diagnostics store becomes the injected
|
|
25
26
|
* `capture?: (info) => void`. Omitted, capture is a no-op and every call
|
|
26
27
|
* forwards identically (the original's payload shape is preserved exactly:
|
package/dist/toast.d.ts
CHANGED
|
@@ -19,8 +19,9 @@ import { ReactNode } from 'react';
|
|
|
19
19
|
* problem entirely — this module has zero dependencies — and the input is
|
|
20
20
|
* typed STRUCTURALLY (callable + `.error` + `.warning`) so the returned
|
|
21
21
|
* `toast` keeps the host's full sonner type, and no `.d.ts` in this package
|
|
22
|
-
* references "sonner".
|
|
23
|
-
*
|
|
22
|
+
* references "sonner". Consequently `sonner` is NOT declared in the manifest
|
|
23
|
+
* at all (X3: advisory peers are banned — nothing resolves it, so nothing
|
|
24
|
+
* declares it; it remains a devDependency purely for the type-compat test).
|
|
24
25
|
* - `captureError` from the app's diagnostics store becomes the injected
|
|
25
26
|
* `capture?: (info) => void`. Omitted, capture is a no-op and every call
|
|
26
27
|
* forwards identically (the original's payload shape is preserved exactly:
|
package/dist/toast.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/toast.ts"],"sourcesContent":["/**\n * @ai-matrx/kit/toast — the captured sonner wrapper, as a factory.\n *\n * A bare `toast.error(...)` from \"sonner\" is INVISIBLE to any error-capture\n * sink — every modern sonner call site silently bypasses error capture (the\n * exact hole matrx-frontend found in its marketing feature, 2026-07-20).\n * `createMatrxToast` returns a drop-in `toast` whose API is identical to the\n * one you pass in — `error` and `warning` additionally feed the injected\n * capture sink. A user seeing the failure is not evidence that it is minor,\n * so error toasts stay red unless a specific downgrade rule says otherwise.\n * Success/info/etc. pass straight through untouched.\n *\n * Ported from matrx-frontend `lib/toast.ts` with the two seams inverted:\n *\n * - `sonner` is NOT imported: the host passes its own `toast` object into the\n * factory (`createMatrxToast({ toast })`). That removes the peer-resolution\n * problem entirely — this module has zero dependencies — and the input is\n * typed STRUCTURALLY (callable + `.error` + `.warning`) so the returned\n * `toast` keeps the host's full sonner type, and no `.d.ts` in this package\n * references \"sonner\".
|
|
1
|
+
{"version":3,"sources":["../src/toast.ts"],"sourcesContent":["/**\n * @ai-matrx/kit/toast — the captured sonner wrapper, as a factory.\n *\n * A bare `toast.error(...)` from \"sonner\" is INVISIBLE to any error-capture\n * sink — every modern sonner call site silently bypasses error capture (the\n * exact hole matrx-frontend found in its marketing feature, 2026-07-20).\n * `createMatrxToast` returns a drop-in `toast` whose API is identical to the\n * one you pass in — `error` and `warning` additionally feed the injected\n * capture sink. A user seeing the failure is not evidence that it is minor,\n * so error toasts stay red unless a specific downgrade rule says otherwise.\n * Success/info/etc. pass straight through untouched.\n *\n * Ported from matrx-frontend `lib/toast.ts` with the two seams inverted:\n *\n * - `sonner` is NOT imported: the host passes its own `toast` object into the\n * factory (`createMatrxToast({ toast })`). That removes the peer-resolution\n * problem entirely — this module has zero dependencies — and the input is\n * typed STRUCTURALLY (callable + `.error` + `.warning`) so the returned\n * `toast` keeps the host's full sonner type, and no `.d.ts` in this package\n * references \"sonner\". Consequently `sonner` is NOT declared in the manifest\n * at all (X3: advisory peers are banned — nothing resolves it, so nothing\n * declares it; it remains a devDependency purely for the type-compat test).\n * - `captureError` from the app's diagnostics store becomes the injected\n * `capture?: (info) => void`. Omitted, capture is a no-op and every call\n * forwards identically (the original's payload shape is preserved exactly:\n * `source: \"user-toast\"`, the `[warning] ` prefix, the \"Error toast\"\n * fallback, `raw: { kind, message?, data }`). A throwing `capture` never\n * breaks the toast.\n *\n * Usage (once, in the host app):\n * import { toast as sonnerToast } from \"sonner\";\n * export const { toast, toastErrorAlreadyCaptured } =\n * createMatrxToast({ toast: sonnerToast, capture: captureError });\n */\n\nimport type { ReactNode } from \"react\";\n\n/** What sonner accepts as a toast title (structural: sonner's `titleT`). */\nexport type ToastMessage = ReactNode | (() => ReactNode);\n\n/** Structural stand-in for sonner's `ExternalToast` options bag. */\nexport interface ToastData {\n description?: unknown;\n [key: string]: unknown;\n}\n\n/**\n * The structural surface this factory needs from the injected toast object:\n * callable, with `error` and `warning` methods. sonner's `toast` satisfies\n * this for every version this package targets. Deliberate typing choices so\n * the REAL sonner object is assignable without a cast under\n * `strictFunctionTypes`: the call signature uses `never[]` (accepts any\n * function — consumers call through their own `T`, never this signature),\n * and `error`/`warning` use METHOD syntax for bivariant parameter checks\n * against sonner's `ExternalToast`.\n */\nexport interface SonnerLikeToast {\n (...args: never[]): string | number;\n error(message: ToastMessage, data?: ToastData): string | number;\n warning(message: ToastMessage, data?: ToastData): string | number;\n}\n\n/** The payload handed to the injected capture sink — the original's shape. */\nexport interface CapturedToastInfo {\n source: \"user-toast\";\n message: string;\n userMessage: string;\n raw: {\n kind: \"error\" | \"warning\";\n message: string | undefined;\n data: ToastData | undefined;\n };\n}\n\nexport interface CreateMatrxToastOptions<T extends SonnerLikeToast> {\n /** The host's sonner `toast` object (or any structural equivalent). */\n toast: T;\n /**\n * Error-capture sink fed by `.error` / `.warning`. Omitted: no-op.\n * Must never be load-bearing — a throw here is swallowed.\n */\n capture?: (info: CapturedToastInfo) => void;\n}\n\nexport interface MatrxToast<T extends SonnerLikeToast> {\n /** Drop-in replacement for the injected `toast`, with error/warning capture. */\n toast: T;\n /**\n * Render an error toast when the originating failure was already captured\n * at its canonical boundary. Only for aggregate/derived UI notices; the\n * caller must be able to name the upstream capture seam.\n */\n toastErrorAlreadyCaptured: T[\"error\"];\n}\n\nfunction messageText(message: ToastMessage, data?: ToastData): string {\n const description =\n data && typeof data.description === \"string\" ? data.description : \"\";\n const title = typeof message === \"string\" ? message : \"\";\n return [title, description].filter(Boolean).join(\" — \") || \"Error toast\";\n}\n\n/** Build the captured toast pair around the host's sonner `toast` object. */\nexport function createMatrxToast<T extends SonnerLikeToast>({\n toast: hostToast,\n capture,\n}: CreateMatrxToastOptions<T>): MatrxToast<T> {\n if (typeof hostToast !== \"function\") {\n throw new Error(\n \"createMatrxToast: options.toast must be the sonner `toast` object (or a structural equivalent) — got \" +\n typeof hostToast,\n );\n }\n\n function captureToast(\n kind: \"error\" | \"warning\",\n message: ToastMessage,\n data?: ToastData,\n ): void {\n if (!capture) return;\n try {\n capture({\n source: \"user-toast\",\n message: `${kind === \"warning\" ? \"[warning] \" : \"\"}${messageText(message, data)}`,\n userMessage: messageText(message, data),\n raw: {\n kind,\n message: typeof message === \"string\" ? message : undefined,\n data,\n },\n });\n } catch {\n /* capture must never break the toast */\n }\n }\n\n const error: SonnerLikeToast[\"error\"] = (message, data) => {\n captureToast(\"error\", message, data);\n return hostToast.error(message, data);\n };\n\n const warning: SonnerLikeToast[\"warning\"] = (message, data) => {\n captureToast(\"warning\", message, data);\n return hostToast.warning(message, data);\n };\n\n // The constraint's call signature is `never[]` (see SonnerLikeToast), so\n // forwarding the base call goes through a widened alias of the host object.\n const forward = hostToast as unknown as (\n ...args: Parameters<T>\n ) => ReturnType<T>;\n const toast: T = Object.assign(\n ((...args: Parameters<T>) => forward(...args)) as unknown as T,\n hostToast,\n { error, warning },\n );\n\n const toastErrorAlreadyCaptured = ((\n message: ToastMessage,\n data?: ToastData,\n ) => hostToast.error(message, data)) as unknown as T[\"error\"];\n\n return { toast, toastErrorAlreadyCaptured };\n}\n"],"mappings":";;;AA+FA,SAAS,YAAY,SAAuB,MAA0B;AACpE,QAAM,cACJ,QAAQ,OAAO,KAAK,gBAAgB,WAAW,KAAK,cAAc;AACpE,QAAM,QAAQ,OAAO,YAAY,WAAW,UAAU;AACtD,SAAO,CAAC,OAAO,WAAW,EAAE,OAAO,OAAO,EAAE,KAAK,UAAK,KAAK;AAC7D;AAGO,SAAS,iBAA4C;AAAA,EAC1D,OAAO;AAAA,EACP;AACF,GAA8C;AAC5C,MAAI,OAAO,cAAc,YAAY;AACnC,UAAM,IAAI;AAAA,MACR,+GACE,OAAO;AAAA,IACX;AAAA,EACF;AAEA,WAAS,aACP,MACA,SACA,MACM;AACN,QAAI,CAAC,QAAS;AACd,QAAI;AACF,cAAQ;AAAA,QACN,QAAQ;AAAA,QACR,SAAS,GAAG,SAAS,YAAY,eAAe,EAAE,GAAG,YAAY,SAAS,IAAI,CAAC;AAAA,QAC/E,aAAa,YAAY,SAAS,IAAI;AAAA,QACtC,KAAK;AAAA,UACH;AAAA,UACA,SAAS,OAAO,YAAY,WAAW,UAAU;AAAA,UACjD;AAAA,QACF;AAAA,MACF,CAAC;AAAA,IACH,QAAQ;AAAA,IAER;AAAA,EACF;AAEA,QAAM,QAAkC,CAAC,SAAS,SAAS;AACzD,iBAAa,SAAS,SAAS,IAAI;AACnC,WAAO,UAAU,MAAM,SAAS,IAAI;AAAA,EACtC;AAEA,QAAM,UAAsC,CAAC,SAAS,SAAS;AAC7D,iBAAa,WAAW,SAAS,IAAI;AACrC,WAAO,UAAU,QAAQ,SAAS,IAAI;AAAA,EACxC;AAIA,QAAM,UAAU;AAGhB,QAAM,QAAW,OAAO;AAAA,KACrB,IAAI,SAAwB,QAAQ,GAAG,IAAI;AAAA,IAC5C;AAAA,IACA,EAAE,OAAO,QAAQ;AAAA,EACnB;AAEA,QAAM,6BAA6B,CACjC,SACA,SACG,UAAU,MAAM,SAAS,IAAI;AAElC,SAAO,EAAE,OAAO,0BAA0B;AAC5C;","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ai-matrx/kit",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.3",
|
|
4
4
|
"description": "The always-include AI Matrx kit: the little primitives every Matrx app speaks — autosave that never loses a keystroke, stale-response guards, clipboard with graceful fallbacks — one per subpath, tree-shaken to what you use.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -270,13 +270,7 @@
|
|
|
270
270
|
"tailwind-merge": "^3.6.0"
|
|
271
271
|
},
|
|
272
272
|
"peerDependencies": {
|
|
273
|
-
"react": ">=18.0.0"
|
|
274
|
-
"sonner": ">=1.0.0"
|
|
275
|
-
},
|
|
276
|
-
"peerDependenciesMeta": {
|
|
277
|
-
"sonner": {
|
|
278
|
-
"optional": true
|
|
279
|
-
}
|
|
273
|
+
"react": ">=18.0.0"
|
|
280
274
|
},
|
|
281
275
|
"devDependencies": {
|
|
282
276
|
"@arethetypeswrong/cli": "^0.18.5",
|