{"_id":"@constructorfleet/extension-watch-history","_rev":"2-87c2eae1d652be34c1f384a98ecd8014","name":"@constructorfleet/extension-watch-history","dist-tags":{"latest":"1.0.1"},"versions":{"1.0.0":{"name":"@constructorfleet/extension-watch-history","version":"1.0.0","license":"MIT","_id":"@constructorfleet/extension-watch-history@1.0.0","maintainers":[{"name":"teagan42","email":"that@teagantotally.rocks"}],"homepage":"https://github.com/constructorfleet/seerr-extensions#readme","bugs":{"url":"https://github.com/constructorfleet/seerr-extensions/issues"},"dist":{"shasum":"78280c4870dd22a6bf6cdeddaaf60aae021c9eb6","tarball":"https://registry.npmjs.org/@constructorfleet/extension-watch-history/-/extension-watch-history-1.0.0.tgz","fileCount":13,"integrity":"sha512-GztQcl1qOvqZD+q6X40zKAXd3S0LFHy4K413jblBs/Eo/Xb08EBAJ9LYZzSEgSJXa/BDzuPW1SLagIIWaiHqFg==","signatures":[{"sig":"MEUCIGAM/7i8heuwwGeBm2a5WxW8kCI1nFAAUjt+IiJnuaSCAiEAoCKbCzh2Cw232n38nyFS281uARPgj5vc/Yt+qwkbcHw=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":38863},"main":"dist/index.js","_from":"file:constructorfleet-extension-watch-history-1.0.0.tgz","scripts":{"build":"tsc --project tsconfig.json && tsc --project tsconfig.panel.json","typecheck":"tsc --project tsconfig.json --noEmit && tsc --project tsconfig.panel.json --noEmit"},"_npmUser":{"name":"teagan42","email":"that@teagantotally.rocks"},"_resolved":"/tmp/b322008bd71b083fef47af65614f4182/constructorfleet-extension-watch-history-1.0.0.tgz","_integrity":"sha512-GztQcl1qOvqZD+q6X40zKAXd3S0LFHy4K413jblBs/Eo/Xb08EBAJ9LYZzSEgSJXa/BDzuPW1SLagIIWaiHqFg==","repository":{"url":"git+https://github.com/constructorfleet/seerr-extensions.git","type":"git","directory":"watch-history"},"_npmVersion":"10.9.8","description":"Reference Seerr extension: records what each user has watched.","directories":{},"_nodeVersion":"22.23.1","dependencies":{"@constructorfleet/extension-sdk":"1.0.0"},"publishConfig":{"registry":"https://npm.pkg.github.com"},"_hasShrinkwrap":false,"devDependencies":{"swr":"2.2.5","zod":"4.3.6","axios":"1.7.7","react":"18.3.1","typeorm":"0.3.29","react-intl":"6.6.8","typescript":"5.4.5","@types/node":"22.19.0","@types/react":"18.3.12","@constructorfleet/extension-ui":"1.0.0"},"peerDependencies":{"zod":"^4.3.6","typeorm":"^0.3.29"},"_npmOperationalInternal":{"tmp":"tmp/extension-watch-history_1.0.0_1786099890687_0.5598039572029949","host":"s3://npm-registry-packages-npm-production"}},"1.0.1":{"name":"@constructorfleet/extension-watch-history","version":"1.0.1","description":"Reference Seerr extension: records what each user has watched.","license":"MIT","main":"dist/index.js","peerDependencies":{"typeorm":"^0.3.29","zod":"^4.3.6"},"dependencies":{"@constructorfleet/extension-sdk":"1.0.1"},"repository":{"type":"git","url":"git+https://github.com/constructorfleet/seerr-extensions.git","directory":"watch-history"},"publishConfig":{"registry":"https://npm.pkg.github.com"},"devDependencies":{"typescript":"5.4.5","@types/node":"22.19.0","typeorm":"0.3.29","zod":"4.3.6","@constructorfleet/extension-ui":"1.0.1","react":"18.3.1","@types/react":"18.3.12","swr":"2.2.5","axios":"1.7.7","react-intl":"6.6.8"},"scripts":{"build":"tsc --project tsconfig.json && tsc --project tsconfig.panel.json","typecheck":"tsc --project tsconfig.json --noEmit && tsc --project tsconfig.panel.json --noEmit"},"_id":"@constructorfleet/extension-watch-history@1.0.1","bugs":{"url":"https://github.com/constructorfleet/seerr-extensions/issues"},"homepage":"https://github.com/constructorfleet/seerr-extensions#readme","_integrity":"sha512-JNWjUGO4WUfVhrOBcV5Frb58QaC52IvLxVj3urpPOjgKoj6O/SMzJ22O7sKCo32OgX+3rEzNR0yWhekiLxFb+g==","_resolved":"/tmp/e34d6c044c6273ddb1908f26580bfbf1/constructorfleet-extension-watch-history-1.0.1.tgz","_from":"file:constructorfleet-extension-watch-history-1.0.1.tgz","_nodeVersion":"22.23.1","_npmVersion":"10.9.8","dist":{"integrity":"sha512-JNWjUGO4WUfVhrOBcV5Frb58QaC52IvLxVj3urpPOjgKoj6O/SMzJ22O7sKCo32OgX+3rEzNR0yWhekiLxFb+g==","shasum":"f7f69a17ec30d602a0792a39281785e4c20b037a","tarball":"https://registry.npmjs.org/@constructorfleet/extension-watch-history/-/extension-watch-history-1.0.1.tgz","fileCount":13,"unpackedSize":38863,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQDbNS+gugWDvu0um+VAFEYE7+11a++S0E0d8Tf1OcnqwQIgc71TtFVk7ZEyG/x1Ssqrvpz6ZVQ8t45aYuqI7SRP3Fk="}]},"_npmUser":{"name":"teagan42","email":"that@teagantotally.rocks"},"directories":{},"maintainers":[{"name":"teagan42","email":"that@teagantotally.rocks"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/extension-watch-history_1.0.1_1786102039852_0.7460177138821802"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-07T10:51:30.552Z","modified":"2026-08-07T11:27:20.168Z","1.0.0":"2026-08-07T10:51:30.825Z","1.0.1":"2026-08-07T11:27:19.997Z"},"bugs":{"url":"https://github.com/constructorfleet/seerr-extensions/issues"},"license":"MIT","homepage":"https://github.com/constructorfleet/seerr-extensions#readme","repository":{"type":"git","url":"git+https://github.com/constructorfleet/seerr-extensions.git","directory":"watch-history"},"description":"Reference Seerr extension: records what each user has watched.","maintainers":[{"name":"teagan42","email":"that@teagantotally.rocks"}],"readme":"# Watch History — reference Seerr extension\n\nRecords what each user has watched, and shows them their own history in a panel.\n\nIts real job is to be the honest end-to-end exercise of the extension SDK. Every\ncapability a manifest can declare is declared here **and actually used**, so if\nthe SDK is missing something an extension needs, this is where it shows up:\n\n| Capability | Where it is used |\n| --- | --- |\n| `store` (entity) | `src/entity/WatchEvent.ts`, one `ext_watch-history_event` table |\n| `store.kv` | the `sync` job's cursor, read back by the panel |\n| `users: read` | `hasPermission` for `view_all`; the job's orphan check |\n| `media: read` | resolving a `tmdbId` when recording a watch |\n| `requests: read` | the `/unwatched` route |\n| `settings: read` | `applicationTitle` in the notification |\n| `jobs` | `sync`, on the manifest's cron schedule |\n| events | `request.available` (writes rows), `media.available` (logged) |\n| routes | `GET/POST /history`, `GET /unwatched` |\n| permissions | `view_own` (default) and `view_all` (`requiresCore: MANAGE_USERS`) |\n| notifications | `milestone` |\n| panel | `dist/panel.js`, sidebar `ClockIcon` |\n\n## Building\n\n```\npnpm build      # both halves; see below for why there are two\npnpm typecheck\n```\n\nTwo tsconfigs, and this is not incidental:\n\n- **`tsconfig.json` → CommonJS.** The host `require()`s the entry point, and the\n  `export =` in `src/index.ts` only means anything under CJS emit.\n- **`tsconfig.panel.json` → ES2022 modules.** The panel is loaded by a browser\n  `import()`. `module: ES2022` is chosen so `tsc` emits bare `from \"react\"` and\n  leaves it alone — those specifiers are exactly what the host's import map\n  rewrites to *its* React. A bundler that inlined React would give the panel a\n  second copy, which renders correctly and then dies on the first hook.\n\n## Installing\n\n```\n# from a checkout\npnpm build\ncp -r . \"${CONFIG_DIRECTORY:-config}/extensions/watch-history\"\n# then restart Seerr and enable it under Settings → Extensions\n```\n\nRestarting is required, not a formality: TypeORM cannot register an entity after\n`DataSource.initialize()`, so an extension contributing a table is only picked up\nat boot.\n\n## Three things worth reading the comments for\n\nThese are the parts that surprised the author, and each is explained where it\nhappens rather than here:\n\n1. **`watchedAt` goes through the SDK's `DbAwareColumn`, and the migration through\n   `resolveColumnType`** — sqlite and Postgres disagree about date types, so a bare\n   `type: 'datetime'` works on a sqlite dev box and fails on a Postgres\n   deployment. Both halves must make the same decision or the migrated schema and\n   the entity metadata disagree; the decorator covers the entity and the string\n   form covers the raw SQL. See `src/entity/WatchEvent.ts` and\n   `src/migration/`.\n2. **The manifest exists twice** — `seerr-extension.json` (what the host reads)\n   and `src/manifest.ts` (what `defineExtension` narrows from). JSON imports widen\n   `true` to `boolean`, which silently defeats the narrowing entirely. See\n   `src/manifest.ts`; a test in the Seerr repo asserts the two agree.\n3. **`userId`/`mediaId` are plain columns, not relations** — a foreign key from an\n   extension table into a core one makes uninstalling a schema problem for core\n   rather than a `DROP TABLE`. The cost is orphan rows, which the `sync` job\n   prunes.\n","readmeFilename":"README.md"}