{"_id":"@absolutejs/sync-pack-triage","_rev":"4-fed50c2ba6dd867af189ff4b2d78ef71","name":"@absolutejs/sync-pack-triage","dist-tags":{"latest":"0.3.0"},"versions":{"0.1.0":{"name":"@absolutejs/sync-pack-triage","version":"0.1.0","keywords":["absolutejs","sync","sync-pack","triage","inbox","snooze","unread"],"author":"Alex Kahn","license":"Apache-2.0","_id":"@absolutejs/sync-pack-triage@0.1.0","maintainers":[{"name":"alexkahndev","email":"alexkahn2019@gmail.com"}],"homepage":"https://github.com/absolutejs/sync-packs/tree/main/triage","bugs":{"url":"https://github.com/absolutejs/sync-packs/issues"},"dist":{"shasum":"7e803e2f7b4f5fe8e5bd8869d3017f137206ee18","tarball":"https://registry.npmjs.org/@absolutejs/sync-pack-triage/-/sync-pack-triage-0.1.0.tgz","fileCount":10,"integrity":"sha512-0ls+91MJE8EIyRATsZNzqRXAaDx+LIC2xY+MUls93NOMj+l6CsiSROxFL1/0fOw6cRYLb2aQ16z5AMxN/WIt8g==","signatures":[{"sig":"MEUCIQDWgSMclKoHSeaaPQrX3x5xvrYmPgH3kz6l3Nq0iRmFgwIgNBcB68687WBFX3X+7YHZswPLLQ95MHl5KtUsycnYy4o=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":517613},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","shasum":"7e803e2f7b4f5fe8e5bd8869d3017f137206ee18","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js"},"./manifest":{"types":"./dist/manifest.d.ts","import":"./dist/manifest.js","default":"./dist/manifest.js"},"./manifest.json":"./dist/manifest.json"},"scripts":{"test":"bun test","build":"rm -rf dist && bun build src/index.ts src/manifest.ts --outdir dist --sourcemap --target=bun --external @absolutejs/sync && tsc --project tsconfig.build.json && absolute-manifest emit","format":"prettier --write \"./**/*.{ts,json,md}\"","release":"bun run format && bun run typecheck && bun run test && bun run build && bun publish","typecheck":"tsc --noEmit"},"_npmUser":{"name":"alexkahndev","email":"alexkahn2019@gmail.com"},"_integrity":"sha512-0ls+91MJE8EIyRATsZNzqRXAaDx+LIC2xY+MUls93NOMj+l6CsiSROxFL1/0fOw6cRYLb2aQ16z5AMxN/WIt8g==","absolutejs":{"runtimePeers":{"@absolutejs/sync":{"range":">=2.11.0 <3","tested":"2.11.0","buildExternals":["@absolutejs/sync"],"artifactImports":["@absolutejs/sync/engine"]}},"manifestContract":2},"repository":{"url":"https://github.com/absolutejs/sync-packs.git","type":"git","directory":"triage"},"_npmVersion":"10.8.3","description":"Per-actor triage pack for @absolutejs/sync — unread/seen, snooze that resurfaces on new activity, dismiss that sticks, and mute, over any host resource","directories":{},"_nodeVersion":"24.3.0","dependencies":{"@sinclair/typebox":"^0.34.0","@absolutejs/manifest":"^0.7.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"prettier":"3.5.3","@types/bun":"1.3.14","typescript":"5.8.3","@absolutejs/sync":"2.11.0"},"peerDependencies":{"@absolutejs/sync":">=2.11.0 <3"},"_npmOperationalInternal":{"tmp":"tmp/sync-pack-triage_0.1.0_1785512636485_0.14804076537850652","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@absolutejs/sync-pack-triage","version":"0.1.1","keywords":["absolutejs","sync","sync-pack","triage","inbox","snooze","unread"],"author":{"name":"Alex Kahn"},"license":"Apache-2.0","_id":"@absolutejs/sync-pack-triage@0.1.1","maintainers":[{"name":"alexkahndev","email":"alexkahn2019@gmail.com"}],"homepage":"https://github.com/absolutejs/sync-packs/tree/main/triage","bugs":{"url":"https://github.com/absolutejs/sync-packs/issues"},"dist":{"shasum":"830b51183efbfe07dc7160f1e85af4775a571423","tarball":"https://registry.npmjs.org/@absolutejs/sync-pack-triage/-/sync-pack-triage-0.1.1.tgz","fileCount":10,"integrity":"sha512-q7Ot3GH9gL1KUTlV40IB/ewDwlRiWA9gq52OB9T9EmFeFcmSdFj+AcHb4AVLjdcfCEzRbBc54YF0othhEDLA0w==","signatures":[{"sig":"MEUCIQCp3sLVzDfScSAXgHES7nTINi4txl5Pbn2V1owXnAnXnQIgJTbP4TLUrg06grIJ3OmOAVRr2B9T5k2Uq+i916QSduY=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":525605},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js"},"./manifest":{"types":"./dist/manifest.d.ts","import":"./dist/manifest.js","default":"./dist/manifest.js"},"./manifest.json":"./dist/manifest.json"},"gitHead":"ba7c2594b58ad9e1cd434195d96823ba678f2260","scripts":{"test":"bun test","build":"rm -rf dist && bun build src/index.ts src/manifest.ts --outdir dist --sourcemap --target=bun --external @absolutejs/sync && tsc --project tsconfig.build.json && absolute-manifest emit","format":"prettier --write \"./**/*.{ts,json,md}\"","release":"bun run format && bun run typecheck && bun run test && bun run build && bun publish","typecheck":"tsc --noEmit"},"_npmUser":{"name":"alexkahndev","email":"alexkahn2019@gmail.com"},"absolutejs":{"manifestContract":2},"repository":{"url":"git+https://github.com/absolutejs/sync-packs.git","type":"git","directory":"triage"},"_npmVersion":"10.9.2","description":"Per-actor triage pack for @absolutejs/sync — unread/seen, snooze that resurfaces on new activity, dismiss that sticks, and mute, over any host resource","directories":{},"_nodeVersion":"22.14.0","dependencies":{"@sinclair/typebox":"^0.34.0","@absolutejs/manifest":"^0.9.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"prettier":"3.5.3","@types/bun":"1.3.14","typescript":"5.8.3","@absolutejs/sync":"2.11.0"},"peerDependencies":{"@absolutejs/sync":">=2.11.0 <3"},"_npmOperationalInternal":{"tmp":"tmp/sync-pack-triage_0.1.1_1787720844853_0.7999135248230262","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@absolutejs/sync-pack-triage","version":"0.2.0","keywords":["absolutejs","sync","sync-pack","triage","inbox","snooze","unread"],"author":{"name":"Alex Kahn"},"license":"Apache-2.0","_id":"@absolutejs/sync-pack-triage@0.2.0","maintainers":[{"name":"alexkahndev","email":"alexkahn2019@gmail.com"}],"homepage":"https://github.com/absolutejs/sync-packs/tree/main/triage","bugs":{"url":"https://github.com/absolutejs/sync-packs/issues"},"dist":{"shasum":"7a32bca788ef4aa6f79f11607b74efcd1dbea6b2","tarball":"https://registry.npmjs.org/@absolutejs/sync-pack-triage/-/sync-pack-triage-0.2.0.tgz","fileCount":10,"integrity":"sha512-pkMJmyvLXZoPDy/W4CjbBSQPTCcngO8Q5rW8xpwMtNaWmcezd1QPUwixG+tAF/6AFuRnQkQVlRclPF6zNdusWQ==","signatures":[{"sig":"MEUCIQDTMPPbARWG4ymR1zeR9UNUaS+dzWr2ZbBkKr6+Elvp3QIgSGaImXR5JKg1TrzN0jFf3SFE2Epafd1D3uohPn7ZqUE=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":526231},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js"},"./manifest":{"types":"./dist/manifest.d.ts","import":"./dist/manifest.js","default":"./dist/manifest.js"},"./manifest.json":"./dist/manifest.json"},"gitHead":"f6a9d1a741b1b3f39977cea64ba6931b3f2f61db","scripts":{"test":"bun test","build":"rm -rf dist && bun build src/index.ts src/manifest.ts --outdir dist --sourcemap --target=bun --external @absolutejs/sync && tsc --project tsconfig.build.json && absolute-manifest emit","format":"prettier --write \"./**/*.{ts,json,md}\"","release":"bun run format && bun run typecheck && bun run test && bun run build && bun publish","typecheck":"tsc --noEmit"},"_npmUser":{"name":"alexkahndev","email":"alexkahn2019@gmail.com"},"absolutejs":{"sync":{"localSchema":{"version":1,"localData":{"mutations":[{"match":"*triage*","protection":"required","sensitivity":"private","onProtectionUnavailable":"memory-only"}],"collections":[{"match":"*triage*","protection":"required","sensitivity":"private","evictionPriority":"critical","onProtectionUnavailable":"memory-only"}]}}},"manifestContract":2},"repository":{"url":"git+https://github.com/absolutejs/sync-packs.git","type":"git","directory":"triage"},"_npmVersion":"10.9.2","description":"Per-actor triage pack for @absolutejs/sync — unread/seen, snooze that resurfaces on new activity, dismiss that sticks, and mute, over any host resource","directories":{},"_nodeVersion":"22.14.0","dependencies":{"@sinclair/typebox":"^0.34.0","@absolutejs/manifest":"^0.9.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"prettier":"3.5.3","@types/bun":"1.3.14","typescript":"5.8.3","@absolutejs/sync":"2.28.0"},"peerDependencies":{"@absolutejs/sync":">=2.11.0 <3"},"_npmOperationalInternal":{"tmp":"tmp/sync-pack-triage_0.2.0_1787723211788_0.11385862090131704","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@absolutejs/sync-pack-triage","version":"0.3.0","description":"Per-actor triage pack for @absolutejs/sync — unread/seen, snooze that resurfaces on new activity, dismiss that sticks, and mute, over any host resource","repository":{"type":"git","url":"git+https://github.com/absolutejs/sync-packs.git","directory":"triage"},"homepage":"https://github.com/absolutejs/sync-packs/tree/main/triage","bugs":{"url":"https://github.com/absolutejs/sync-packs/issues"},"main":"./dist/index.js","module":"./dist/index.js","types":"./dist/index.d.ts","type":"module","license":"Apache-2.0","author":{"name":"Alex Kahn"},"publishConfig":{"access":"public"},"keywords":["absolutejs","sync","sync-pack","triage","inbox","snooze","unread"],"scripts":{"build":"rm -rf dist && bun build src/index.ts src/manifest.ts --outdir dist --sourcemap --target=bun --external @absolutejs/sync && tsc --project tsconfig.build.json && absolute-manifest emit","test":"bun test","typecheck":"tsc --noEmit","format":"prettier --write \"./**/*.{ts,json,md}\"","release":"bun run format && bun run typecheck && bun run test && bun run build && bun publish"},"peerDependencies":{"@absolutejs/sync":">=2.11.0 <3"},"devDependencies":{"@absolutejs/sync":"2.29.0","@types/bun":"1.3.14","prettier":"3.5.3","typescript":"5.8.3"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js"},"./manifest":{"types":"./dist/manifest.d.ts","import":"./dist/manifest.js","default":"./dist/manifest.js"},"./manifest.json":"./dist/manifest.json"},"absolutejs":{"manifestContract":2,"sync":{"localSchema":{"version":1,"localData":{"collections":[{"match":"*triage*","sensitivity":"private","protection":"required","onProtectionUnavailable":"memory-only","evictionPriority":"critical"}],"mutations":[{"match":"*triage*","sensitivity":"private","protection":"required","onProtectionUnavailable":"memory-only","conflict":{"strategy":"client-wins","maxAttempts":1}}]}}}},"dependencies":{"@absolutejs/manifest":"^0.9.0","@sinclair/typebox":"^0.34.0"},"_id":"@absolutejs/sync-pack-triage@0.3.0","gitHead":"70fac17d77643bafa53a933112c69a65b06245e9","_nodeVersion":"22.14.0","_npmVersion":"10.9.2","dist":{"integrity":"sha512-A+qkueDFoEokZM/r+EO34ksUPfg13MNCFIYgGRdtO18xGaUyQaFzE/KicqAAri4Kk7xefaRlCYH77UwO4B7CVw==","shasum":"46dcf02cee1419e574ad28a0f3cd23ee2d6c4008","tarball":"https://registry.npmjs.org/@absolutejs/sync-pack-triage/-/sync-pack-triage-0.3.0.tgz","fileCount":10,"unpackedSize":526352,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQC+AK0wjo0kAc80T+CAkPji7YwI9acN30HILQ9VMNEDawIhANJlKckjInaf7XLd5qq8D7cvlRrhU+6k3NeqUV0/HbLn"}]},"_npmUser":{"name":"alexkahndev","email":"alexkahn2019@gmail.com"},"directories":{},"maintainers":[{"name":"alexkahndev","email":"alexkahn2019@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/sync-pack-triage_0.3.0_1787729601442_0.2274848698266445"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-31T15:43:56.312Z","modified":"2026-08-26T07:33:21.801Z","0.1.0":"2026-07-31T15:43:56.668Z","0.1.1":"2026-08-26T05:07:25.040Z","0.2.0":"2026-08-26T05:46:51.974Z","0.3.0":"2026-08-26T07:33:21.638Z"},"bugs":{"url":"https://github.com/absolutejs/sync-packs/issues"},"author":{"name":"Alex Kahn"},"license":"Apache-2.0","homepage":"https://github.com/absolutejs/sync-packs/tree/main/triage","keywords":["absolutejs","sync","sync-pack","triage","inbox","snooze","unread"],"repository":{"type":"git","url":"git+https://github.com/absolutejs/sync-packs.git","directory":"triage"},"description":"Per-actor triage pack for @absolutejs/sync — unread/seen, snooze that resurfaces on new activity, dismiss that sticks, and mute, over any host resource","maintainers":[{"name":"alexkahndev","email":"alexkahn2019@gmail.com"}],"readme":"# @absolutejs/sync-pack-triage\n\nPer-actor triage state for [`@absolutejs/sync`](https://github.com/absolutejs/sync): unread/seen, snooze, dismiss, and mute over any resource your app already owns.\n\nEvery product with a backlog — an inbox, a task list, a review queue, a deal room — grows the same four controls, and every product rebuilds them. This pack owns one `triage` table keyed by `(actorId, resourceKind, resourceId)` and gives you the mutations and the owner-scoped live collection to drive them.\n\n```bash\nbun add @absolutejs/sync-pack-triage\n```\n\n```ts\nimport { createSyncEngine } from \"@absolutejs/sync/engine\";\nimport { createTriagePack } from \"@absolutejs/sync-pack-triage\";\n\nconst engine = createSyncEngine();\nengine.registerPack(createTriagePack({ getActorId: (ctx) => ctx.userId }));\n\nawait engine.runMutation(\n  \"triage:snooze\",\n  {\n    resourceId: \"thread-9\",\n    resourceKind: \"thread\",\n    snoozedUntil: Date.now() + 86_400_000,\n  },\n  { userId: \"alice\" },\n);\n\nconst view = await engine.subscribe({\n  collection: \"triage\",\n  ctx: { userId: \"alice\" },\n  onDiff: (diff) => render(diff),\n  params: { resourceKind: \"thread\", status: \"active\" },\n});\n```\n\n## The two rules that matter\n\n**Dismiss sticks.** New activity does not resurrect something the actor put away. A \"dismiss\" that quietly means \"hide until it changes\" brings the item back at the worst possible moment, and the actor stops trusting the control. Only `triage:restore` undoes a dismiss.\n\n**Snooze resurfaces.** A snoozed item comes back the moment the other side acts — not when its timer happens to expire. Waiting out a three-day snooze while a reply sits hidden is how a deal dies. This is the Gmail norm and the one people expect.\n\nBoth live in one pure function, so you can apply the same rule inside your own SQL-backed list query without instantiating the pack:\n\n```ts\nimport { triageVisibility, isUnread } from \"@absolutejs/sync-pack-triage\";\n\ntriageVisibility(row, { lastActivityAt: thread.lastMessageAt }); // 'active' | 'snoozed' | 'dismissed'\nisUnread(row, thread.lastMessageAt); // never looked, or changed since they did\n```\n\nPass `lastActivityAt` and a snooze ends early when the resource changes. Omit it and a snooze ends only on its timer.\n\n## Mutations\n\n| Mutation                        | Args                                        | Effect                                                              |\n| ------------------------------- | ------------------------------------------- | ------------------------------------------------------------------- |\n| `triage:seen`                   | `{resourceKind, resourceId}`                | Stamps `lastSeenAt`                                                 |\n| `triage:unread`                 | `{resourceKind, resourceId}`                | Clears `lastSeenAt`                                                 |\n| `triage:snooze`                 | `{resourceKind, resourceId, snoozedUntil?}` | `status: 'snoozed'`; `snoozedUntil: null` sleeps until new activity |\n| `triage:dismiss`                | `{resourceKind, resourceId}`                | `status: 'dismissed'`, stamps `dismissedAt`                         |\n| `triage:restore`                | `{resourceKind, resourceId}`                | Back to `status: 'active'`                                          |\n| `triage:mute` / `triage:unmute` | `{resourceKind, resourceId}`                | Stop/resume notifying, without putting it away                      |\n| `triage:bulk`                   | `{action, resources[], snoozedUntil?}`      | One round-trip, one diff, for a multi-select                        |\n\nRow ids are `${actorId}:${resourceKind}:${resourceId}`, so every mutation is an idempotent upsert and a row's owner is recoverable from its key. Read and write permissions are owner-scoped and enforced against the stored row, not the client's payload.\n\n## Config\n\n```ts\ncreateTriagePack({\n  getActorId: (ctx) => ctx.userId, // default reads ctx.userId\n  prefix: \"team_\", // namespaces table, collection, mutations, schedule\n  store: myPostgresTriageStore, // default is per-instance in-memory\n  now: () => Date.now(),\n  maxBulkSize: 500,\n  wakeCron: \"*/5 * * * *\", // null to skip registering the sweep\n});\n```\n\n`store` is three functions — `all`, `getById`, and a `TableWriter` — and both reads may be async, so you can back triage with your real database rather than a mirror.\n\nThe `wakeCron` sweep only exists to turn an expired snooze into a live change event. Reads are already correct without it, because `triageVisibility` resolves expiry at read time; a host that hasn't wired the `scheduled` plugin still behaves correctly, just without a push at the moment of expiry.\n\n## Subscription params\n\n`{ resourceKind?, status? }`. Both are optional; `status` is resolved with `triageVisibility` at the current time and **without** a per-row activity timestamp, because this pack owns triage state and not your activity feed. If you want activity-aware resurfacing inside a live query, join this table in your own collection and call `triageVisibility` there with your own timestamp.\n\n## License\n\nApache-2.0\n","readmeFilename":"README.md"}