{"_id":"@cutticat/payload-monitor","_rev":"10-5883ad65932a5645e5ea7fd44d22ac63","name":"@cutticat/payload-monitor","dist-tags":{"latest":"2.0.3"},"versions":{"2.0.1":{"name":"@cutticat/payload-monitor","version":"2.0.1","keywords":["payload","payloadcms","plugin","monitor","metrics","admin","cutticat"],"author":{"name":"Maksim Victorovich Fomin"},"license":"MIT","_id":"@cutticat/payload-monitor@2.0.1","maintainers":[{"name":"maksim2498","email":"maksim@cutticat.com"}],"homepage":"https://cutticat.com","dist":{"shasum":"fb6ba9b2ab3b051119d13d36856f3edd86696e11","tarball":"https://registry.npmjs.org/@cutticat/payload-monitor/-/payload-monitor-2.0.1.tgz","fileCount":465,"integrity":"sha512-Qvpeg+l//aFFVkVrQ/FlqGcwY5Td7mWnEyx4lucW+wkxUbIWzfV8N6Tmz41CXV81YhwSVBhpBb6Dif6vguv8lw==","signatures":[{"sig":"MEUCIH0t+NXFMszpnsRHDq5lhhlHFGhMdCtg4XydhyKq+8J0AiEA95p1MQvBhO25XILCORVWE4GKe6bi35hipkAbey8b9GM=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":696328},"type":"module","_from":"file:cutticat-payload-monitor-2.0.1.tgz","engines":{"node":">=22.18.0"},"exports":{".":{"types":"./dist/plugin/index.d.mts","import":"./dist/plugin/index.mjs","default":"./dist/plugin/index.mjs"},"./hooks":{"types":"./dist/hooks/index.d.ts","import":"./dist/hooks/index.js","default":"./dist/hooks/index.js"},"./utils":{"types":"./dist/utils/index.d.ts","import":"./dist/utils/index.js","default":"./dist/utils/index.js"},"./schemas":{"types":"./dist/schemas/index.d.ts","import":"./dist/schemas/index.js","default":"./dist/schemas/index.js"},"./collectors":{"types":"./dist/collectors/index.d.mts","import":"./dist/collectors/index.mjs","default":"./dist/collectors/index.mjs"},"./components/client":{"types":"./dist/components/client/index.d.ts","import":"./dist/components/client/index.js","default":"./dist/components/client/index.js"},"./components/server":{"types":"./dist/components/server/index.d.mts","import":"./dist/components/server/index.mjs","default":"./dist/components/server/index.mjs"}},"scripts":{"test":"tsx --tsconfig tsconfig.test.json --test --test-concurrency=1 --test-force-exit \"./tests/**/*.test.ts\"","build":"tsc --noEmit -p ./tsconfig.build.json && tsdown --concurrency 1","clean":"rimraf ./dist ./.tsbuild ./LICENSE.txt","typecheck":"tsc -b","test:watch":"tsx --tsconfig tsconfig.test.json --test --test-concurrency=1 --watch \"./tests/**/*.test.ts\"","test:coverage":"tsx --tsconfig tsconfig.test.json --test --test-concurrency=1 --test-force-exit --experimental-test-coverage \"./tests/**/*.test.ts\"","generate:fixture-payload-types":"cd tests/fixtures/payload && PAYLOAD_CONFIG_PATH=config.ts payload generate:types"},"_npmUser":{"name":"maksim2498","email":"maksim@cutticat.com"},"_resolved":"/tmp/d952f877b5790b3a5e98372715483092/cutticat-payload-monitor-2.0.1.tgz","_integrity":"sha512-Qvpeg+l//aFFVkVrQ/FlqGcwY5Td7mWnEyx4lucW+wkxUbIWzfV8N6Tmz41CXV81YhwSVBhpBb6Dif6vguv8lw==","repository":{"url":"https://gitflic.ru/project/cutticat-npm/payload-monitor","type":"git"},"_npmVersion":"10.9.3","description":"Live host metrics (memory, CPU, disk, uptime) in the Payload CMS admin panel","directories":{},"sideEffects":["**/*.css"],"_nodeVersion":"22.18.0","dependencies":{"zod":"^4.5.4","clsx":"^2.1.1","bytes":"^3.1.2","recharts":"^3.10.1","resolve-pkg":"^3.0.1","@cutticat/ms":"^1.1.0","lucide-react":"^1.46.0","@cutticat/types":"^1.10.0","@cutticat/zod-extras":"^2.4.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.19.2","next":"16.3.0","react":"19.2.6","rimraf":"^6.1.0","tsdown":"0.23.0","payload":"3.88.0","react-dom":"19.2.6","typescript":"^5.9.3","@tsdown/css":"0.23.0","@types/node":"^25.0.3","@types/bytes":"^3.1.6","@types/react":"^19.2.14","@payloadcms/ui":"3.88.0","@payloadcms/next":"3.88.0","@cutticat/md-url-map":"^2.0.0","@payloadcms/db-sqlite":"3.88.0","@payloadcms/translations":"3.88.0"},"peerDependencies":{"next":">=15.0.0","react":">=19.0.0","payload":">=3.80.0 <4.0.0","react-dom":">=19.0.0","@payloadcms/ui":">=3.80.0 <4.0.0","@payloadcms/next":">=3.80.0 <4.0.0","@payloadcms/translations":">=3.80.0 <4.0.0"},"_npmOperationalInternal":{"tmp":"tmp/payload-monitor_2.0.1_1790160933464_0.09990261618157303","host":"s3://npm-registry-packages-npm-production"}},"2.0.2":{"name":"@cutticat/payload-monitor","version":"2.0.2","keywords":["payload","payloadcms","plugin","monitor","metrics","admin","cutticat"],"author":{"name":"Maksim Victorovich Fomin"},"license":"MIT","_id":"@cutticat/payload-monitor@2.0.2","maintainers":[{"name":"maksim2498","email":"maksim@cutticat.com"}],"homepage":"https://cutticat.com","dist":{"shasum":"add49e3790bd80bcd3ffdc06d236553e1a5c15fa","tarball":"https://registry.npmjs.org/@cutticat/payload-monitor/-/payload-monitor-2.0.2.tgz","fileCount":465,"integrity":"sha512-v6BuWDXmPHHapOwY+ZxQXFsXVrtoRmhysLzJBqFaFbqzM05V6Qy9+72RDvZN62BGCTYrwvKJ6f0yv4u9NLa+QA==","signatures":[{"sig":"MEQCIH1S1i8h7+CLF0f2XdSTwYzsXNvz3nlY7UA1nZv2ick4AiBXCfZaKyiWG4sdoUZA+mrokXPBHpjE9yJO4womcMkoEw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIGhOvzg8QpP/fbi4UsBS9LJXxzKaDYMPVl+UonOPB2mMAiEAkpnik0JeqEr35bKEci5Ozk4hTZBEyLx2lbFTGjl/1zg=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":696412},"type":"module","_from":"file:cutticat-payload-monitor-2.0.2.tgz","engines":{"node":">=22.18.0"},"exports":{".":{"types":"./dist/plugin/index.d.mts","import":"./dist/plugin/index.mjs","default":"./dist/plugin/index.mjs"},"./hooks":{"types":"./dist/hooks/index.d.ts","import":"./dist/hooks/index.js","default":"./dist/hooks/index.js"},"./utils":{"types":"./dist/utils/index.d.ts","import":"./dist/utils/index.js","default":"./dist/utils/index.js"},"./schemas":{"types":"./dist/schemas/index.d.ts","import":"./dist/schemas/index.js","default":"./dist/schemas/index.js"},"./collectors":{"types":"./dist/collectors/index.d.mts","import":"./dist/collectors/index.mjs","default":"./dist/collectors/index.mjs"},"./components/client":{"types":"./dist/components/client/index.d.ts","import":"./dist/components/client/index.js","default":"./dist/components/client/index.js"},"./components/server":{"types":"./dist/components/server/index.d.mts","import":"./dist/components/server/index.mjs","default":"./dist/components/server/index.mjs"}},"scripts":{"test":"tsx --tsconfig tsconfig.test.json --test --test-concurrency=1 --test-force-exit \"./tests/**/*.test.ts\"","build":"tsc --noEmit -p ./tsconfig.build.json && tsdown --concurrency 1","clean":"rimraf ./dist ./.tsbuild ./LICENSE.txt","typecheck":"tsc -b","test:watch":"tsx --tsconfig tsconfig.test.json --test --test-concurrency=1 --watch \"./tests/**/*.test.ts\"","test:coverage":"tsx --tsconfig tsconfig.test.json --test --test-concurrency=1 --test-force-exit --experimental-test-coverage \"./tests/**/*.test.ts\"","generate:fixture-payload-types":"cd tests/fixtures/payload && PAYLOAD_CONFIG_PATH=config.ts payload generate:types"},"_npmUser":{"name":"maksim2498","email":"maksim@cutticat.com"},"_resolved":"/tmp/ef56b5709dc1331c809a6e6fe331d986/cutticat-payload-monitor-2.0.2.tgz","_integrity":"sha512-v6BuWDXmPHHapOwY+ZxQXFsXVrtoRmhysLzJBqFaFbqzM05V6Qy9+72RDvZN62BGCTYrwvKJ6f0yv4u9NLa+QA==","repository":{"url":"https://gitflic.ru/project/cutticat-npm/payload-monitor","type":"git"},"_npmVersion":"10.9.3","description":"Live host metrics (memory, CPU, disk, uptime) in the Payload CMS admin panel","directories":{},"sideEffects":["**/*.css"],"_nodeVersion":"22.18.0","dependencies":{"zod":"^4.5.4","clsx":"^2.1.1","bytes":"^3.1.2","recharts":"^3.10.1","resolve-pkg":"^3.0.1","@cutticat/ms":"^1.1.0","lucide-react":"^1.46.0","@cutticat/types":"^1.10.0","@cutticat/zod-extras":"^2.4.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.19.2","next":"16.3.0","react":"19.2.6","rimraf":"^6.1.0","tsdown":"0.23.0","payload":"3.88.0","react-dom":"19.2.6","typescript":"^5.9.3","@tsdown/css":"0.23.0","@types/node":"^25.0.3","@types/bytes":"^3.1.6","@types/react":"^19.2.14","@payloadcms/ui":"3.88.0","@payloadcms/next":"3.88.0","@cutticat/md-url-map":"^2.0.0","@payloadcms/db-sqlite":"3.88.0","@payloadcms/translations":"3.88.0"},"peerDependencies":{"next":">=15.0.0","react":">=19.0.0","payload":">=3.80.0 <4.0.0","react-dom":">=19.0.0","@payloadcms/ui":">=3.80.0 <4.0.0","@payloadcms/next":">=3.80.0 <4.0.0","@payloadcms/translations":">=3.80.0 <4.0.0"},"_npmOperationalInternal":{"tmp":"tmp/payload-monitor_2.0.2_1790166013498_0.08560835510423215","host":"s3://npm-registry-packages-npm-production"}},"2.0.3":{"_id":"@cutticat/payload-monitor@2.0.3","dist":{"shasum":"034d9d5689a47e8e6a0320fae32be556a5ed8c84","tarball":"https://registry.npmjs.org/@cutticat/payload-monitor/-/payload-monitor-2.0.3.tgz","fileCount":465,"integrity":"sha512-/AlfOXqy2l8JnMfZd9PcndypkYf2j10rhAIqP4ADvrJevMKJvGztXpS7CCpPesadQQGg4RfSCPTPvtmcjryv8Q==","signatures":[{"sig":"MEUCIGY7a4kAIfkjgkPCxCHxN/wOLYWRvpxObhRjwjJYuCBPAiEAjbvCVOfdxgOvYespj4i0r9c9bsW5MiVHJdeucP1FKPI=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIF4snPKk1w5EesE302yop+lz7qXKnqejLE0pzfsr+TCnAiBA7loq+sVDZ+nN+Rcqd6IGwDaXJxixXB6UpMmqkELq3w=="}],"unpackedSize":697904},"name":"@cutticat/payload-monitor","type":"module","_from":"file:cutticat-payload-monitor-2.0.3.tgz","author":{"name":"Maksim Victorovich Fomin"},"engines":{"node":">=22.18.0"},"exports":{".":{"types":"./dist/plugin/index.d.mts","import":"./dist/plugin/index.mjs","default":"./dist/plugin/index.mjs"},"./hooks":{"types":"./dist/hooks/index.d.ts","import":"./dist/hooks/index.js","default":"./dist/hooks/index.js"},"./utils":{"types":"./dist/utils/index.d.ts","import":"./dist/utils/index.js","default":"./dist/utils/index.js"},"./schemas":{"types":"./dist/schemas/index.d.ts","import":"./dist/schemas/index.js","default":"./dist/schemas/index.js"},"./collectors":{"types":"./dist/collectors/index.d.mts","import":"./dist/collectors/index.mjs","default":"./dist/collectors/index.mjs"},"./components/client":{"types":"./dist/components/client/index.d.ts","import":"./dist/components/client/index.js","default":"./dist/components/client/index.js"},"./components/server":{"types":"./dist/components/server/index.d.mts","import":"./dist/components/server/index.mjs","default":"./dist/components/server/index.mjs"}},"license":"MIT","scripts":{"test":"tsx --tsconfig tsconfig.test.json --test --test-concurrency=1 --test-force-exit \"./tests/**/*.test.ts\"","build":"tsc --noEmit -p ./tsconfig.build.json && tsdown --concurrency 1","clean":"rimraf ./dist ./.tsbuild ./LICENSE.txt","typecheck":"tsc -b","test:watch":"tsx --tsconfig tsconfig.test.json --test --test-concurrency=1 --watch \"./tests/**/*.test.ts\"","test:coverage":"tsx --tsconfig tsconfig.test.json --test --test-concurrency=1 --test-force-exit --experimental-test-coverage \"./tests/**/*.test.ts\"","generate:fixture-payload-types":"cd tests/fixtures/payload && PAYLOAD_CONFIG_PATH=config.ts payload generate:types"},"version":"2.0.3","_npmUser":{"name":"maksim2498","email":"maksim@cutticat.com"},"homepage":"https://cutticat.com","keywords":["payload","payloadcms","plugin","monitor","metrics","admin","cutticat"],"_resolved":"/tmp/69cf88b4bdaeb3eeb1df6148631d46de/cutticat-payload-monitor-2.0.3.tgz","_integrity":"sha512-/AlfOXqy2l8JnMfZd9PcndypkYf2j10rhAIqP4ADvrJevMKJvGztXpS7CCpPesadQQGg4RfSCPTPvtmcjryv8Q==","repository":{"url":"https://gitflic.ru/project/cutticat-npm/payload-monitor","type":"git"},"_npmVersion":"10.9.3","description":"Live host metrics (memory, CPU, disk, uptime) in the Payload CMS admin panel","directories":{},"maintainers":[{"name":"maksim2498","email":"maksim@cutticat.com"}],"sideEffects":["**/*.css"],"_nodeVersion":"22.18.0","dependencies":{"zod":"^4.5.4","clsx":"^2.1.1","bytes":"^3.1.2","recharts":"^3.10.1","resolve-pkg":"^3.0.1","@cutticat/ms":"^1.1.0","lucide-react":"^1.46.0","@cutticat/types":"^1.10.0","@cutticat/zod-extras":"^2.4.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.19.2","next":"16.3.0","react":"19.2.6","rimraf":"^6.1.0","tsdown":"0.23.0","payload":"3.88.0","react-dom":"19.2.6","typescript":"^5.9.3","@tsdown/css":"0.23.0","@types/node":"^25.0.3","@types/bytes":"^3.1.6","@types/react":"^19.2.14","@payloadcms/ui":"3.88.0","@payloadcms/next":"3.88.0","@cutticat/md-url-map":"^2.0.0","@payloadcms/db-sqlite":"3.88.0","@payloadcms/translations":"3.88.0"},"peerDependencies":{"next":">=15.0.0","react":">=19.0.0","payload":">=3.80.0 <4.0.0","react-dom":">=19.0.0","@payloadcms/ui":">=3.80.0 <4.0.0","@payloadcms/next":">=3.80.0 <4.0.0","@payloadcms/translations":">=3.80.0 <4.0.0"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/payload-monitor_2.0.3_1790199165673_0.09045491259649374"}}},"time":{"created":"2026-09-23T10:55:33.131Z","modified":"2026-09-23T21:32:45.969Z","1.0.0":"2026-09-05T14:32:25.352Z","1.0.1":"2026-09-05T14:37:50.931Z","1.0.2":"2026-09-05T15:01:09.866Z","1.0.3":"2026-09-05T15:05:31.182Z","2.0.0":"2026-09-22T21:58:08.989Z","2.0.1":"2026-09-23T10:55:33.597Z","2.0.2":"2026-09-23T12:20:13.574Z","2.0.3":"2026-09-23T21:32:45.777Z"},"author":{"name":"Maksim Victorovich Fomin"},"license":"MIT","homepage":"https://cutticat.com","keywords":["payload","payloadcms","plugin","monitor","metrics","admin","cutticat"],"repository":{"url":"https://gitflic.ru/project/cutticat-npm/payload-monitor","type":"git"},"description":"Live host metrics (memory, CPU, disk, uptime) in the Payload CMS admin panel","maintainers":[{"name":"maksim2498","email":"maksim@cutticat.com"}],"readme":"# @cutticat/payload-monitor\n\nLive memory, CPU, disk, and uptime in the [Payload CMS](https://payloadcms.com/) 3 admin. The\nMonitor page draws sparklines while you watch. The dashboard widget shows the latest numbers next\nto your collections. Logged-in users can `GET` the same snapshot. Each reading comes from the Node\nprocess and is not stored.\n\nSidebar, cards, and buttons follow the admin language. The built-in copy covers every language\n[Payload](https://payloadcms.com/docs/configuration/i18n) supports.\n\n![Monitor page](<https://gitflic.ru/project/cutticat-npm/payload-monitor/blob/raw?branch=main&file=packages/plugin/screenshots/view.png>)\n\nCPU, memory, event loop, and process, plus the host and the disks you configure. Poll every\n1–30 seconds, pause, or refresh once.\n\n![Dashboard widget](<https://gitflic.ru/project/cutticat-npm/payload-monitor/blob/raw?branch=main&file=packages/plugin/screenshots/widget.png>)\n\nThe same snapshot on the home dashboard: occupancy, uptime, runtime versions, and disk bars.\nNumbers only.\n\n## Contents\n\n- [Overview](#overview)\n- [Installation](#installation)\n- [Quick start](#quick-start)\n- [Configuration](#configuration)\n- [Extending](#extending)\n- [API](#api)\n- [Documentation](#documentation)\n- [Development](#development)\n- [Requirements](#requirements)\n\n## Overview\n\n`monitorPlugin()` registers three things:\n\n- A sidebar page at `/admin/cutticat/monitor`\n- A dashboard widget you can pin on the home screen\n- `GET /api/cutticat/monitor` for logged-in users\n\nThe page, the nav link, and the widget follow the admin language. Switch the locale and the copy\nswitches with it. See [Languages](#languages) to replace a string.\n\nDisks default to `[process.cwd()]`. Point them at the directory that holds uploads or the database\nfiles. Hide a domain from a role, or turn it off. When you want your own screen, swap the view, the\nnav link, or the widget and keep the same endpoint.\n\nThe open page keeps the last 120 samples in memory and draws them with Recharts. The interval is\n1, 2, 5, 10, or 30 seconds (default 5) and is remembered in `localStorage`. The points are not. The\nwidget is a single reading: CPU, memory, event loop, process, host, and disks.\n\nNumbers come from Node (`os`, `fs.statfs`, `process`, `perf_hooks`). On a typical Linux Docker host\nthose calls already describe the machine: `/proc` is the kernel, `statfs` on a volume is the backing\ndisk. The first CPU sample has no interval yet, so `cpu.percent` is omitted until the next poll.\nEvent-loop `mean` and `max` are lag in that window: histogram delay minus the 20ms sampling\nresolution, floored at 0.\n\nCollectors, schemas, and UI are public on `/collectors`, `/schemas`, `/utils`, `/hooks`,\n`/components/client`, and `/components/server`. Use them from a job, a health route, or a custom\nview. Importing `monitorPlugin` does not load RSC or `'use client'` modules.\n\n## Installation\n\n```bash\npnpm add @cutticat/payload-monitor\n```\n\nPeers: `payload`, `@payloadcms/next`, `@payloadcms/translations`, `@payloadcms/ui`, `react`,\n`react-dom` (Payload 3.80–3.x).\n\n## Quick start\n\n```typescript\nimport { buildConfig } from \"payload\"\nimport { monitorPlugin } from \"@cutticat/payload-monitor\"\n\nexport default buildConfig({\n  // ...\n  plugins: [monitorPlugin()],\n})\n```\n\nThen regenerate the admin import map:\n\n```bash\npnpm payload generate:importmap\n```\n\nOpen the admin. **Monitor** is in the sidebar, and the endpoint answers. Logged-in users see every\ndomain. Pin the widget on the home dashboard with `admin.widget.defaultLayout` (see below).\n\n## Configuration\n\nPass options only when the defaults are wrong.\n\n### Disks\n\n`disks` is the list of filesystem paths measured with `statfs`. Point it at the directory that\nactually holds uploads or the database files:\n\n```typescript\nmonitorPlugin({\n  disks: [\"./data\"],\n})\n```\n\n### Access\n\n`access` gates snapshot domains per request. `false` turns a domain off; a function decides for\nthis user. Omitted keys stay visible to every logged-in user:\n\n```typescript\nmonitorPlugin({\n  access: {\n    host: false,\n    disks: ({ req }) => req.user?.role === \"admin\",\n  },\n})\n```\n\n### Admin UI\n\n`admin.page` and `admin.widget` register the sidebar page and the dashboard widget (both default\n`true`). Pass `widget: { defaultLayout: true }` to pin the widget on the home dashboard.\n\n```typescript\nmonitorPlugin({\n  admin: {\n    page: true,\n    widget: { defaultLayout: true },\n  },\n})\n```\n\n### Languages\n\nAdmin copy ships for every Payload language and follows the locale the user already picked. The\nsidebar, the page heading, and the widget share `navLabel`. Replace any string in\n`i18n.translations` under `cutticat.monitor`. Host strings win over the built-in table:\n\n```typescript\ni18n: {\n  translations: {\n    en: {\n      cutticat: { monitor: { navLabel: \"Metrics\" } },\n    },\n  },\n}\n```\n\nCall it from admin code with `t('cutticat:monitor:navLabel')`, or\n`t(toTranslationKey(\"navLabel\"))` if you import the helper.\n\nTo type a host `t()` / `useTranslation` the way Payload documents\n[custom translations](https://payloadcms.com/docs/configuration/i18n), intersect our\n`TranslationsObject` with Payload's built-in table and take `NestedKeysStripped`:\n\n```typescript\nimport type { NestedKeysStripped } from \"@payloadcms/translations\"\nimport { enTranslations } from \"@payloadcms/translations/languages/en\"\nimport type { TranslationsObject } from \"@cutticat/payload-monitor\"\n\nexport type CustomTranslationsObject = TranslationsObject & typeof enTranslations\nexport type CustomTranslationsKeys = NestedKeysStripped<CustomTranslationsObject>\n```\n\n### Components\n\n`components` swaps import-map specifiers (`path#ExportName`) for the view, nav link, and widget.\nUse this when you replace a surface entirely:\n\n```typescript\nmonitorPlugin({\n  components: {\n    view: \"/components/CustomView#CustomView\",\n  },\n})\n```\n\n## Extending\n\nThe package root is the plugin. Collectors, schemas, and UI live on separate subpaths so a Node\nimport of `monitorPlugin` does not load RSC or `'use client'` modules. Reach for those entries when\nyou want a second endpoint, a cron snapshot, extra metrics, or a custom view on the same path.\n\nFrom there:\n\n- Call `collectSnapshot` or a single `collectCpu` / `collectDisks` / … from a job, a\n  health route, or a script. Same numbers as the admin page, no HTTP.\n- Reuse `createHandler` if you only want to change how the route is mounted.\n- Read `endpointPath`, `viewPath`, `viewKey`, `widgetSlug` so a custom view still hits the\n  registered route instead of inventing a parallel string.\n- Keep extra copy in the `cutticat.monitor` namespace with `toTranslationKey`, `namespace`,\n  `translations`, and `TranslationsObject` / `TranslationKeys` / `Languages`.\n- Parse JSON with `SnapshotSchema` from `/schemas`, or compose the built-in `/components/client`\n  cards in your own dashboard. Occupancy percent is `usagePercent` from `/utils`.\n- Poll from a custom `'use client'` view with `useSnapshots` / `useTranslation` from\n  `/hooks`.\n\n`ViewClient` still parses the response with `SnapshotSchema`. That schema is a closed\n`.partial()` object: unknown keys are stripped, and the built-in cards only render known domains.\nCustom metrics you add to a collector will not show up until you swap the view, or compose a view\nfrom `/components/client`.\n\n```typescript\nimport {\n  collectCpu,\n  collectSnapshot,\n} from \"@cutticat/payload-monitor/collectors\"\n\nconst snapshot = await collectSnapshot({\n  disks: [\"./data\"],\n  exclude: [\"host\"],\n})\nconst cpu = collectCpu()\n```\n\n`CollectSnapshotExclude` already accepts any string, so you can list custom keys in\n`exclude` before they exist on `Snapshot`. `access` on the plugin is still typed to known snapshot\ndomains.\n\n## API\n\n### Plugin (`.`)\n\n- `monitorPlugin(options?)` — endpoint, sidebar page, dashboard widget, i18n overlay\n- `PluginOptions` — `{ disks?, access?, admin?, components? }`\n- `MetricAccess` / `MetricAccessMap` — per-domain `true` / `false` / `(args) => boolean`\n\n### HTTP (`.`)\n\n- `createHandler(options?)` — GET handler used by the plugin (`401` without `req.user`)\n- `CreateHandlerOptions` — `{ disks?, access? }`\n\n### Constants (`.`)\n\n- `slug` — `\"@cutticat/payload-monitor\"` (plugin slug and import-map package)\n- `endpointPath` — `\"/cutticat/monitor\"` (under `routes.api`; Payload does not include `/api` here)\n- `viewPath` — `\"/cutticat/monitor\"` (under `routes.admin`)\n- `viewKey` — `\"cutticatMonitor\"` (`admin.components.views`)\n- `widgetSlug` — `\"cutticat-monitor\"` (`admin.dashboard.widgets`)\n\n### i18n (`.`)\n\n- `namespace` — `[\"cutticat\", \"monitor\"]`\n- `translations` — built-in copy for every Payload `acceptedLanguages` code\n- `toTranslationKey(\"navLabel\")` — `\"cutticat:monitor:navLabel\"`\n- `TranslationsObject` — one locale's `cutticat.monitor` tree (Payload\n  `DefaultTranslationsObject` / docs `CustomTranslationsObject`)\n- `TranslationKeys` — `NestedKeysStripped<TranslationsObject>` (`cutticat:monitor:navLabel`)\n- `Languages` — `Record<AcceptedLanguages, TranslationsObject>` (Payload `GenericLanguages`)\n- `Namespace` — path `[\"cutticat\", \"monitor\"]`\n- `NamespaceTranslationsObject` — `{ navLabel, live, cpu, … }` at that path\n- `NamespaceTranslationKeys` — `navLabel` | `live` | …\n\n### Collectors (`/collectors`)\n\n- `collectSnapshot(options?)` — full snapshot; same payload as the endpoint\n- `CollectSnapshotOptions` — `{ disks?: string[]; exclude?: CollectSnapshotExclude[] }`\n- `CollectSnapshotExclude` — known snapshot key, or any string\n- `collectCpu()`, `collectDisks(paths)`, `collectEventLoop()`, `collectHost()`,\n  `collectMemory()`, `collectProcess()` — one domain each\n\n### Admin components (`/components/server`)\n\n- `View`, `NavLink`, `Widget` — Server Components for the Payload import map\n\nApplication code should not import these by hand unless you are replacing a specifier in\n`components`. Default specifiers are\n`@cutticat/payload-monitor/components/server#View` (and the matching nav/widget names).\n\n### Client (`/components/client`)\n\n- `ViewClient` — view: polls, in-memory history, sparklines, disks\n- `WidgetClient` — widget: current CPU / memory / event-loop / process / host / disk\n  numbers\n- `Toolbar` — poll interval, live/pause, refresh\n- `PollIntervalSelector` — interval pills (`presets` defaults to\n  `pollIntervalSelectorDefaultPresetsMs`), also usable on a custom view\n- `LiveButton`, `RefreshButton` — toolbar actions, also usable on a custom view\n- `CpuCard`, `MemoryCard`, `EventLoopCard`, `ProcessCard` — take `samples`\n  (`Sample<CpuSnapshot>[]` and the matching domain type, oldest first; latest row is the hero)\n- `SystemCard`, `DisksCard`, `Card`, `Fact`, `Icon`, `Path`, `Sparkline`, `UsageBar` —\n  pieces for a custom view. Each accepts `className`\n\n### Hooks (`/hooks`)\n\n- `useSnapshots(apiPath, options?)` — poll the monitor endpoint; `snapshots` is a ring\n  buffer of `Sample<Snapshot>` (`historyLimit`, default 1). Default interval is\n  `defaultSnapshotsPollIntervalMs` (5s). Latest reading is `snapshots.at(-1)`\n  (`value` is the snapshot)\n- `defaultSnapshotsPollIntervalMs` — default poll period (`5000`)\n- `useTranslation()` — Payload `useTranslation` with `t()` scoped to `cutticat.monitor`\n\n### Snapshot schemas (`/schemas`)\n\n- `Snapshot`, `SnapshotSchema` — JSON body of `GET /api/cutticat/monitor`\n- Per-domain `*Schema` / inferred types (`CpuSnapshot`, `DiskSnapshot`, …)\n- `Usage` / `BytesUsage` — occupied and total capacity (`total`, `used`)\n\n### Utils (`/utils`)\n\n- `emptyString` — `\"—\"`; placeholder when a formatted value is missing\n- `formatBytes(value)` — `bytes` package output, or `emptyString` when not finite\n- `formatLoad(load)` — `one / five / fifteen` load averages, two decimal places each\n- `formatPercent(value)` — one decimal plus `%`, or `emptyString` when not finite\n- `narrowSnapshotSamples(snapshots, key)` — samples of one snapshot domain; skips polls that omit it\n- `Sample<T>` — `{ at: Date, value: T }`; a value tagged with the time it was recorded\n- `samplesToPoints(samples, toNumber)` — finite `{ at, value: number }` in input order; skips holes\n- `usagePercent(usage)` — occupancy `used / total * 100`, or `0` when `total` is `0`\n\nThe root export is the plugin. Schemas, collectors, utils, hooks, and UI live on the subpaths\nabove.\n\n## Documentation\n\n- [Project structure](<https://gitflic.ru/project/cutticat-npm/payload-monitor/blob?branch=main&file=packages/plugin/documents/STRUCTURE.md>)\n- [Scripts](<https://gitflic.ru/project/cutticat-npm/payload-monitor/blob?branch=main&file=packages/plugin/documents/SCRIPTS.md>)\n- [Style guide](<https://gitflic.ru/project/cutticat-npm/payload-monitor/blob?branch=main&file=documents/STYLE_GUIDE.md>)\n- [Contributing](<https://gitflic.ru/project/cutticat-npm/payload-monitor/blob?branch=main&file=documents/CONTRIBUTING.md>)\n\n## Development\n\nThe git repository is a pnpm workspace. From the repo root:\n\n```bash\npnpm install\ncd packages/plugin\npnpm run build\n```\n\nPlayground: see [`packages/dev`](<https://gitflic.ru/project/cutticat-npm/payload-monitor/blob?branch=main&file=packages/dev>). Contributing:\n[CONTRIBUTING.md](<https://gitflic.ru/project/cutticat-npm/payload-monitor/blob?branch=main&file=documents/CONTRIBUTING.md>).\n\n## Requirements\n\n- Node.js >= 22.18.0\n- pnpm >= 10.17.0\n- Payload CMS 3.80 or later (3.x)\n","readmeFilename":"README.md"}