@ours.network/notifications 1.0.1 → 1.0.3-nightly.1

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/README.md CHANGED
@@ -55,7 +55,7 @@ Responses are never cached. User and producer credentials have separate scopes.
55
55
  | POST `/api/v1/devices` | User | `{ "subscription": PushSubscriptionJSON }` → device `id` |
56
56
  | POST `/api/v1/devices/delete` | User | `{ "id": "device-id" }`, only that user's device |
57
57
  | GET `/api/v1/devices/status?id=...` | User | `{ "active": true }` |
58
- | GET `/api/v1/inbox?limit=50&before=...` | User | Items, shared unread count, revision, next cursor |
58
+ | GET `/api/v1/inbox?limit=50&before=...&unread=true` | User | Items, shared unread count, revision, next cursor; with `unread=true` only unread items and `filter: "unread"` |
59
59
  | GET `/api/v1/unread-evidence?target=TARGET_JSON[&target=ALIAS_JSON]&revision=OBSERVED_REVISION&limit=100&after=...` | User | Capability `unread-evidence/1`: one conversation's records created at or before the observed revision and still unread, oldest first (limit 1-200). A record read since that revision is absent, so a caller comparing with that revision's count sees it as incomplete. Items omit title and body. A cursor whose record was deleted, or that this scope and revision could not have returned, answers 409. Services without the route answer 404 |
60
60
  | GET `/api/v1/summary` | User | Shared unread count, revision, per-chat source/identity/count, and `sections: {chats, tasks}`; mission-associated rows (task and room targets, or any row with a `taskId`) count under `chats`, agent rows without a `taskId` field count in neither section (as before), and `tasks` is always 0 (kept for compatibility) |
61
61
  | POST `/api/v1/read-target` | User | `{ "target": { "kind": "agent", "agentId": "agent" }, "revision": OBSERVED_REVISION }`, reads only this chat up to the revision captured before its history load |
package/dist/server.js CHANGED
@@ -134,7 +134,10 @@ export function createNotificationService(config, send) {
134
134
  const limit = Number(url.searchParams.get('limit') ?? 50);
135
135
  if (!Number.isInteger(limit) || limit < 1 || limit > 100)
136
136
  throw new HttpError(400, 'invalid limit');
137
- result = store.inbox(user, url.searchParams.get('before') ?? undefined, limit);
137
+ const unread = url.searchParams.get('unread');
138
+ if (unread !== null && unread !== 'true' && unread !== 'false')
139
+ throw new HttpError(400, 'invalid unread filter');
140
+ result = store.inbox(user, url.searchParams.get('before') ?? undefined, limit, unread === 'true');
138
141
  }
139
142
  else if (req.method === 'GET' && url.pathname === '/api/v1/unread-evidence') {
140
143
  // Capability `unread-evidence/1`: a separate route, so a service without it answers
package/dist/store.d.ts CHANGED
@@ -74,7 +74,9 @@ export declare class Store {
74
74
  deleteDevice(userId: string, id: string): boolean;
75
75
  device(userId: string, id: string): Device | undefined;
76
76
  deviceStatus(userId: string, id: string): boolean;
77
- inbox(userId: string, before?: string, limit?: number): {
77
+ /** Newest first. With `unread`, only unread records; the cursor may name a record that has been read since. */
78
+ inbox(userId: string, before?: string, limit?: number, unread?: boolean): {
79
+ filter?: "unread" | undefined;
78
80
  items: Notification[];
79
81
  unread: number;
80
82
  revision: number;
package/dist/store.js CHANGED
@@ -313,14 +313,16 @@ export class Store {
313
313
  }
314
314
  device(userId, id) { const d = this.state.devices.find(d => d.id === id && d.userId === userId); return d ? structuredClone(d) : undefined; }
315
315
  deviceStatus(userId, id) { return this.state.devices.some(d => d.id === id && d.userId === userId); }
316
- inbox(userId, before, limit = 50) {
316
+ /** Newest first. With `unread`, only unread records; the cursor may name a record that has been read since. */
317
+ inbox(userId, before, limit = 50, unread = false) {
317
318
  const all = this.state.notifications.filter(n => n.userId === userId);
318
319
  const index = before ? all.findIndex(n => n.id === before) : all.length;
319
320
  if (index < 0)
320
321
  throw new HttpError(400, 'invalid cursor');
321
- const items = all.slice(Math.max(0, index - limit), index).reverse();
322
+ const older = unread ? all.slice(0, index).filter(n => !n.readAt) : all.slice(0, index);
323
+ const items = older.slice(Math.max(0, older.length - limit)).reverse();
322
324
  return { items, unread: all.filter(n => !n.readAt).length, revision: this.state.revision,
323
- nextCursor: index > limit ? items.at(-1)?.id : null };
325
+ nextCursor: older.length > limit ? items.at(-1)?.id : null, ...(unread ? { filter: 'unread' } : {}) };
324
326
  }
325
327
  /**
326
328
  * One conversation's unread evidence as of an observed revision, oldest first.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ours.network/notifications",
3
- "version": "1.0.1",
3
+ "version": "1.0.3-nightly.1",
4
4
  "description": "Authenticated web push delivery and shared notification inbox",
5
5
  "type": "module",
6
6
  "license": "FSL-1.1-Apache-2.0",