@ai-matrx/kit

中文文档
0.45.48发布于 2026/10/30MITTypeScriptESM + CJS近 30 天下载 10.6万

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.

原始使用文档
文档目录3 节
  1. Host wiring: /url-state
  2. Points and cost ( /format ): unit vs placement
  3. Design

@ai-matrx/kit

The always-include AI Matrx kit: the little primitives every Matrx application speaks, one capability per subpath, tree-shaken to what you use. React is the only required peer; only two subpaths carry runtime dependencies, each because the dependency IS the capability: /json-format (json5 — tolerant parsing is the feature), /idb-store (idb — the typed IndexedDB wrapper is the engine). (The QR decoder moved to @ai-matrx/capture/qr.)

The confirm DIALOG is not here — the opener is. Since 0.9.0 the body (ConfirmDialog, ConfirmDialogHost) lives in @ai-matrx/design-system, which owns the AlertDialog, the shipped motion layer and the overlay scrim token. Mount <ConfirmDialogHost /> from there once at your app root, then call confirm() from @ai-matrx/kit/confirm-opener anywhere. Since 0.10.0 that opener is a thin specialisation of @ai-matrx/kit/opener — the same engine any app can use for its own imperative dialogs. One surface, one owner: kit re-exports none of the dialog.

npm install @ai-matrx/kit
SubpathExportWhat it does
@ai-matrx/kit/autosaveuseAutosaveDebounced autosave with in-flight coalescing, a UI status (idle/unsaved/saving/saved/error), loud non-throwing failures that re-queue the payload, and flush-on-unmount so no keystroke is ever lost.
@ai-matrx/kit/latest-requestuseLatestRequestMakes a superseded async response impossible to apply: claim an attempt, then check the predicate before every state write after an await. Kills the out-of-order-response bug (the wrong record under a confident label) at the only moment that matters — apply time. Render-stable by construction.
@ai-matrx/kit/clipboarduseClipboard, copyTextCopy/paste text, links, and images with the browser quirks solved: canvas→PNG re-encode for image copy, Safari clipboard.read feature detection, param-stripping link copy. Notifier injected — wrap your own toast.
@ai-matrx/kit/transfer-jsonnormalizeTransferJson, ContentTransferError, JsonThe dependency-free JSON-transfer validator and shapes Alchemy and the table copy contract share.

Surface handles omit own object properties whose captured value is undefined, recursively, so host optional fields retain absent-value semantics. normalizeTransferJson(value) stays strict by default; a caller must explicitly pass { omitUndefinedObjectProperties: true } to request the same object-only omission. Array undefined entries or sparse slots still fail at their JSON pointer.

| @ai-matrx/kit/search-scoring | filterAndSortBySearch, computeSearchScore, matchesSearch, idMatchesQuery | Relevance-weighted search ranking — title above description, exact above prefix above includes, pasted-UUID matching — instead of the naive .includes() filter. | | @ai-matrx/kit/concurrency | runWithConcurrency | Bounded worker pool over an array with per-item failure isolation and a cooperative shouldStart() cancel hook. | | @ai-matrx/kit/text-case | formatText, createFormatter | Acronym-aware normalization of messy DB/API strings into title/sentence case with word-replacement overrides. | | @ai-matrx/kit/drafts | useDurableDraft + the local-drafts store | User-authored text that survives anything: write-through localStorage drafts, restore on mount, key-change adoption, cleared only after content durably landed. | | @ai-matrx/kit/opener | createOpener, Opener, OpenerHostController, OpenerAbortError | THE opener pattern, once. Build an imperative await open(request) for any global dialog: pure TS, zero React, so hundreds of call sites (thunks, utils, sync handlers) import it at near-zero cost while the heavy body stays behind a lazy host. You get the whole contract for free — one host at a time, requests queued in call order before the host hydrates, never a silent default answer, a console scream naming the component to mount when a request waits with no host, opt-in dedupe so a double-clicked action cannot stack two dialogs, and opt-in AbortSignal cancellation. State lives on a globalThis Symbol.for(slot), so host and caller find each other across packages AND across ESM/CJS module graphs. | | @ai-matrx/kit/credential-generator | generateCredentialSecret, CREDENTIAL_GENERATION_TECHNICAL_LIMITS | A pure local Web Crypto password/passphrase generator. Hosts supply validated feature limits within the published technical work ceilings; the generator never stores, logs, fetches, or falls back from secure entropy. | | @ai-matrx/kit/opener-react | useOpenerHost | The mount side of an opener: registers the component as THE host, drains queued requests one at a time, and hands back { request, open, settle }. React only — no markup, no CSS — so the dialog body stays entirely yours. | | @ai-matrx/kit/outbound | withReferral, openOutbound, stripReferral, isOutboundUrl, outboundAnchorProps, rehypeOutboundReferral, configureOutboundReferral | THE door for every link that leaves AI Matrx. Tags third-party links with utm_source=aimatrx.com&utm_medium=referral (one knob), keeps the existing query and fragment exactly, skips our domains, other schemes and signed/credential URLs. Pure — legal in Server Components. | | @ai-matrx/kit/outbound-react | OutboundLink, OutboundMarkdownLink, outboundMarkdownComponents, installOutboundReferralDecorator | The link element (drop-in <a>, new tab, rel="noopener" — the referrer is kept) and the react-markdown a renderer. Stamped "use client": Server Components import it as a client reference; renderToStaticMarkup emails still render it. | | @ai-matrx/kit/outbound-decorator | OutboundReferralDecorator | Mount once at an app root: tags any raw third-party anchor in the document at the moment it is used (click, middle-click, context menu). Client-only. | | @ai-matrx/kit/confirm-opener | confirm, ConfirmOptions | The window.confirm replacement's imperative half — pure TS, zero React, zero radix, no "use client", so a Redux thunk, a util or a sync handler can import it at near-zero bundle cost. await confirm({ title, description, variant: "destructive" }) resolves true/false; pre-mount calls queue and concurrent calls present one at a time; with no host mounted it stays pending forever rather than inventing a silent default. Needs <ConfirmDialogHost /> from @ai-matrx/design-system mounted once — the two share one registry through a globalThis slot. | | @ai-matrx/kit/toast | createMatrxToast | The captured sonner wrapper as a factory: pass your sonner toast in, get a drop-in toast back whose .error/.warning also feed your injected error-capture sink, plus toastErrorAlreadyCaptured for notices whose failure was already captured upstream. No sonner import — and sonner is not declared as a dependency or peer at all. | | @ai-matrx/kit/reversible | reversibleTier, countReversible, isReversibleUndoShortcut | The reversible action's core: the announcement shape, the teach → guide → plain policy keyed on what a person has done before, each tier's window, the ⌘Z-never-in-a-text-field rule, and the found-at link. Pure; the host draws it. | | @ai-matrx/kit/invalidation | registerInvalidationCallback, fireInvalidation | Zero-import, name-keyed callback registry that breaks import edges into heavy chunk clusters: the heavy cluster registers at its own module init, the ubiquitous module fires by name. Unregistered names are a deliberate no-op; a throwing callback screams and never breaks the caller. Keep your key constants in ONE host module. | | @ai-matrx/kit/delimiter-guard | guardMarkdownDelimiters (+ guardMathDelimiters, guardRunawayLinks, reportDelimiterViolations) | Keeps one stray streamed delimiter from swallowing a whole section: a $$ that would turn prose into a red KaTeX error span, or an unclosed [ that would turn a section into one giant link, gets invisibly neutralized while real math and links keep rendering. Pure; report violations loudly via the optional injected capture sink. | | @ai-matrx/kit/json-format | detectJson, formatJsonText, stringifyJson | "Is this text JSON, and what shape should it be in?" Detection survives code fences, surrounding prose, and tolerant (JSON5) input — looksLikeJson gates offering, ok gates running. The writer does minify / width-aware compact (inline + pack) / pretty, key sorting, fence add/strip/preserve. Never throws, never mangles text it did not parse. | | @ai-matrx/kit/idle-scheduler | useIdleTask, useIdleReady, useIdleGate, useIdleRegister + registerIdleTask, onFlushComplete, whenPageIdle | Priority-aware deferred execution: work waits for document load → paint → true browser idle (scheduler.postTask / requestIdleCallback / MessageChannel fallback, hidden tabs still flush), then runs 1-first…5-last. Zero re-renders to register; one re-render for the ready signal. | | @ai-matrx/kit/url-state | useUrlState + codecs, useMirroredUrlState, useUrlSearchParams, commitUrlParams | The URL as the source of truth for view state: refresh, copied links, and Back/Forward reproduce the same view. Codecs (string/enum/boolean/positive-integer/JSON) omit defaults so pristine URLs stay clean; discrete decisions push, high-frequency text replaces; every write notifies every other URL-backed control on the page. | | @ai-matrx/kit/idb-store | DBStoreManager, PublicStoreManager, FeatureStore, getIdbStoreSingleton | Typed, versioned IndexedDB stores over idb: subclass, declare your object stores/indexes in setupStores, and every operation resolves { data, error } — never throws, before or after init. Hold each store's one instance with getIdbStoreSingleton(key, create) (a globalThis slot, so the ESM and CJS graphs share it). | | @ai-matrx/kit/color-util | findNearestTailwindColor, getColorFromTailwind, formatTailwindColor, format* normalizers, createColorNormalizer, tailwindColors | The bidirectional Tailwind-token color mapping with zero dependencies: token → hex lookups (including fuzzy input like "skyblue598"), and hex/rgb() → nearest token by perceptual CIEDE2000 distance (bit-identical to the colord lab plugin; a colord instance also plugs straight into the structural { delta(hex) } seam). Plus the pure paste-anything input normalizers and the injected-validity normalizeColorInput waterfall. | | @ai-matrx/kit/react-tree | treeContainsComponent | Safe React children-tree scan for optional a11y children (is a DialogDescription anywhere under these children?): walks elements, arrays, fragments, iterables, and portals by hand, and SKIPS a non-renderable child with a loud dev scream instead of crashing at the probe like React.Children.toArray would. | | @ai-matrx/kit/format | formatDurationMs / Seconds / Minutes, formatRelativeTime, formatAbsoluteDate, parseTimestamp, durationMsBetween, formatFileSize, getInitials, avatarPaletteIndex | THE one home for the tiny display formatters nothing else owns, with the display decision made ONCE per voice. Durations speak clock (9:04), compact (5.2s, 1m 30s), coarse (45 min, 3d 4h) or long (45 minutes, 3 days — the voice that goes inside a sentence; parts: 2 for an exact length a person chose, 1 hour 30 minutes), and round: "down" makes any of them safe for a countdown. Relative stamps speak short, long or locale-aware intl, all three in BOTH directions — "2d ago" and "in 2d" — with a sub-minute future magnitude reading "just now" because that much is clock skew, and suffix: false for a dense column whose header already says "Age" or "Due" (it drops " ago" and "in " alike), and absolute: "date" for a suffixed stamp in a fixed-width cell (past a year it prints 8/26/2025, not a date+time that overflows); absoluteAfter + absolute: "monthDay" + minUnit: "minute" is the feed voice ("now", "14m", "3d", then "Sep 3"). Durations also speak the macOS desktop voice (long + parts: 2 + abbreviate — 2 hr 5 min) and the timesheet clock (granularity: "minute" — 0:45); formatFileSize(b, { base: 1000 }) is Finder's (45.3 GB, 512 bytes); formatPercent(x, { maxDigits: 1 }) drops a needless .0. The unit is always in the name — there is deliberately no formatDuration. It also owns the HONEST NUMBER contract: formatUsd (with digits: "trim" for a price — $0.075, $1.50 — and digits: "whole" for a plan price — $19, $19.50), formatMoney (any ISO currency, unit: "minor" | "major" required — €19.50, ¥1,500), formatCount (compact decimalsBelow: 100 for a tabular 12.3k), formatPercentFromFraction, safeRatio and sumKnown refuse to invent a value — unknown reads as UNKNOWN_DISPLAY ("—"), a measured 0 still reads as 0, and sumKnown hands back how many values it could NOT measure beside the total, so ?? 0 is never the easy path into an aggregate. |

credential-generator bundles the EFF Large Wordlist (7,776 entries; SHA-256 addd35536511597a02fa0a9ff1e5284677b8883b83e986e43f15a3db996b903e). EFF's copyright policy makes its original material available under CC-BY 4.0.

More subpaths are on the roadmap: copy-for-ai.

Host wiring: /url-state

No wiring is required. The module writes through the History API (history.pushState/replaceState) and dispatches its own sync event — this is exactly how it runs inside the Next.js App Router host it was extracted from; do NOT pass the Next.js router. Inject a router only when your host's router must observe or perform the URL writes (react-router, a memory router in tests, a native shell):

import { setUrlStateRouter } from "@ai-matrx/kit/url-state";

setUrlStateRouter({
  push: (url) => myRouter.navigate(url),               // full relative URL: pathname?query#hash
  replace: (url) => myRouter.navigate(url, { replace: true }),
  // Optional: where the current URL is read from (default: window.location)
  getLocation: () => ({ pathname, search, hash }),
});

Call it once at app boot (setUrlStateRouter(null) removes it). With no router injected, behavior is byte-identical to the Matrx frontend original.

Points and cost (/format): unit vs placement

formatCost / formatPoints / usdToPoints settle the UNIT (Arman, 2026-09-27: members see points, only a system admin who asked sees dollars). They do not license showing a price. WHERE a price may appear is the 2026-10-18 rule (law 14, common-docs/policies/points-and-money-in-the-ui.md): only where the person is deciding or investigating (a battle, a picker, a details page, a history table, a bulk/repeating confirm step, billing, admin), never where they are doing their work (chat, results, receipts, toasts, buttons).

Design

  • One package, many subpaths — you always include the kit; you only bundle what you import.
  • Injected hosts (the clipboard notifier), opinionated behavior (the autosave status contract, the apply-time guard). The opinions are the product.
  • ESM + CommonJS conditions with matching declarations, proven from the packed tarball. The "use client" boundary is stamped per chunk: React-touching subpaths carry it, pure ones (search-scoring, concurrency, text-case, invalidation, delimiter-guard, json-format, idb-store, color-util, react-tree, credential-generator) ship unstamped and RSC-safe.

MIT © AI Matrx

版本与发布记录

@ai-matrx/kit 共发布 162 个版本,首次发布于 2026/08/29;过去 12 个月发布了 162 个版本。

版本发布日期距今
0.45.48latest2026/10/306 天前
0.45.472026/10/288 天前
0.45.462026/10/2610 天前
0.45.452026/10/2611 天前
0.45.442026/10/2611 天前
0.45.432026/10/2511 天前

关于 @ai-matrx/kit 的常见问题

@ai-matrx/kit 是什么?

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.

如何安装 @ai-matrx/kit?

在项目目录运行 npm install @ai-matrx/kit,或使用 pnpm add / yarn add / bun add。它还提供命令行工具 matrx-check-outbound-referral,可以用 npx matrx-check-outbound-referral 直接运行。

@ai-matrx/kit 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@ai-matrx/kit 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@ai-matrx/kit 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=20。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@ai-matrx/kit 可以商用吗?

@ai-matrx/kit 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@ai-matrx/kit 的下载量有多少?

根据 npm 官方下载统计,@ai-matrx/kit 在 2026/10/05 – 2026/11/03 这 30 天内被下载 106,034 次,日均约 3,534 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@ai-matrx/kit 还在维护吗?

最新版本 0.45.48 发布于 2026/10/30(6 天前);至今共发布 162 个版本,其中过去 12 个月发布了 162 个;首次发布于 2026/08/29。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。