@devmonks/notify 0.3.0 → 0.4.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
@@ -119,7 +119,7 @@ const store = drizzleStore(db, { notifications, devices, notificationPrefs, noti
119
119
  });
120
120
  ```
121
121
 
122
- Store methods: `loadRecipient`, `writeInbox` (the inApp write), `recordDelivery` (false if the idempotency key exists: do not send), `finishDelivery`, `touchDevice` (upsert by device id; a token seen under another device id moves), `handleDeviceResult` (device cleanup from a send result) and `pruneDevices`.
122
+ Store methods: `loadRecipient` / `loadRecipients(ids)` (batch, for fan-out), `writeInbox` (the inApp write; returns the new row id, or null when `(type, sourceId, user)` already exists), `recordDelivery` (false if the idempotency key exists: do not send), `finishDelivery`, `touchDevice` (upsert by device id; a token seen under another device id moves), `handleDeviceResult` (device cleanup from a send result), `pruneDevices` and `pruneHistory(days)`.
123
123
 
124
124
  Devices: one row per install (`id` is stable, the token may rotate). A dead address (`deadAddress`) deletes the device at once; any other permanent failure adds a strike and the device is deleted at 3; a success resets the count; retryable failures change nothing. `pruneDevices()` removes devices unseen for `pruneInactiveAfterDays` and does nothing while that is null.
125
125
 
@@ -1,2 +1,2 @@
1
- export { notifyTables, type NotifyTables } from './tables';
2
- export { drizzleStore, MAX_DEVICE_FAILURES, type DrizzleStore, type DrizzleStoreOptions, type UserInfo } from './store';
1
+ export { notifyTables, type NotifyTables } from './tables.js';
2
+ export { drizzleStore, MAX_DEVICE_FAILURES, type DrizzleStore, type DrizzleStoreOptions, type UserInfo } from './store.js';
@@ -1,2 +1,2 @@
1
- export { notifyTables } from './tables';
2
- export { drizzleStore, MAX_DEVICE_FAILURES } from './store';
1
+ export { notifyTables } from './tables.js';
2
+ export { drizzleStore, MAX_DEVICE_FAILURES } from './store.js';
@@ -1,6 +1,6 @@
1
1
  import type { PgDatabase } from 'drizzle-orm/pg-core';
2
- import type { Content, Delivery, Recipient, SendResult } from '../types';
3
- import type { NotifyTables } from './tables';
2
+ import type { Content, Delivery, Recipient, SendResult } from '../types.js';
3
+ import type { NotifyTables } from './tables.js';
4
4
  /** Devices are deleted after this many consecutive permanent failures. */
5
5
  export declare const MAX_DEVICE_FAILURES = 3;
6
6
  export interface UserInfo {
@@ -31,13 +31,14 @@ export declare function drizzleStore(db: AnyPgDb, tables: NotifyTables, opts: Dr
31
31
  loadRecipients(userIds: readonly string[]): Promise<Map<string, Recipient>>;
32
32
  /**
33
33
  * The inApp channel's write. With a `sourceId`, a second write for the same type, source and user
34
- * is ignored. Returns whether a row was inserted.
34
+ * is ignored. Returns the new row's id (e.g. to put in the push data so a tap can mark it read), or
35
+ * null when nothing was inserted.
35
36
  */
36
37
  writeInbox(recipientId: string, content: Content, meta?: {
37
38
  type?: string;
38
39
  sourceId?: string;
39
40
  actorId?: string;
40
- }): Promise<boolean>;
41
+ }): Promise<string | null>;
41
42
  /** Inserts a pending delivery row. False when the idempotency key already exists (do not send again). */
42
43
  recordDelivery(d: Delivery): Promise<boolean>;
43
44
  finishDelivery(d: Delivery, status: "sent" | "failed" | "skipped", attempts: number, error?: string): Promise<void>;
@@ -52,7 +52,8 @@ export function drizzleStore(db, tables, opts) {
52
52
  },
53
53
  /**
54
54
  * The inApp channel's write. With a `sourceId`, a second write for the same type, source and user
55
- * is ignored. Returns whether a row was inserted.
55
+ * is ignored. Returns the new row's id (e.g. to put in the push data so a tap can mark it read), or
56
+ * null when nothing was inserted.
56
57
  */
57
58
  async writeInbox(recipientId, content, meta = {}) {
58
59
  const rows = await db
@@ -70,7 +71,7 @@ export function drizzleStore(db, tables, opts) {
70
71
  })
71
72
  .onConflictDoNothing()
72
73
  .returning({ id: notifications.id });
73
- return rows.length > 0;
74
+ return rows[0]?.id ?? null;
74
75
  },
75
76
  /** Inserts a pending delivery row. False when the idempotency key already exists (do not send again). */
76
77
  async recordDelivery(d) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@devmonks/notify",
3
- "version": "0.3.0",
3
+ "version": "0.4.1",
4
4
  "description": "Plan-then-send notifications with an FCM HTTP v1 push adapter. No DB, no queue; the core entry has no dependencies. Optional email (Resend + React Email) and Drizzle entries.",
5
5
  "license": "MIT",
6
6
  "keywords": [
@@ -23,15 +23,18 @@
23
23
  "exports": {
24
24
  ".": {
25
25
  "types": "./dist/index.d.ts",
26
- "import": "./dist/index.js"
26
+ "import": "./dist/index.js",
27
+ "default": "./dist/index.js"
27
28
  },
28
29
  "./email": {
29
30
  "types": "./dist/email/index.d.ts",
30
- "import": "./dist/email/index.js"
31
+ "import": "./dist/email/index.js",
32
+ "default": "./dist/email/index.js"
31
33
  },
32
34
  "./drizzle": {
33
35
  "types": "./dist/drizzle/index.d.ts",
34
- "import": "./dist/drizzle/index.js"
36
+ "import": "./dist/drizzle/index.js",
37
+ "default": "./dist/drizzle/index.js"
35
38
  }
36
39
  },
37
40
  "files": [
@@ -46,7 +49,8 @@
46
49
  "build": "rm -rf dist && tsc -p tsconfig.build.json",
47
50
  "typecheck": "tsc --noEmit",
48
51
  "test": "vitest run",
49
- "prepublishOnly": "bun run typecheck && bun run test && bun run build"
52
+ "prepublishOnly": "bun run typecheck && bun run test && bun run build && bun run smoke",
53
+ "smoke": "node scripts/smoke.mjs"
50
54
  },
51
55
  "peerDependencies": {
52
56
  "@react-email/components": ">=1",