unified-notification-core 0.1.2 → 0.1.5

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/CHANGELOG.md CHANGED
@@ -1,5 +1,34 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.5
4
+
5
+ - Add provider-agnostic `channelPolicies` with durable per-channel rate windows
6
+ and circuit-breaker cooldowns backed by the new `unc_dispatch_state` schema
7
+ table.
8
+ - Add `NotificationDeliveryError({ retryAfterMs })` so adapters can pass
9
+ provider throttle hints without coupling UNC to provider SDKs; retry-after
10
+ schedules the delivery retry and opens a shared channel cooldown.
11
+ - Report `dispatchUntilIdle()` stop reason `rate-limited` with `deferredUntil`
12
+ when due rows exist but channel policy defers claiming.
13
+ - Keep channel-policy deferrals attempt-free: deferred rows remain pending or
14
+ retrying and other channels can still dispatch in the same worker call.
15
+
16
+ ## 0.1.4
17
+
18
+ - Add `dispatchUntilIdle()` as an explicit bounded drain helper with stable
19
+ worker identity, batch/deadline limits, and high-failure stop defaults so
20
+ application workers do not need to hand-roll dispatch loops.
21
+ - Batch-finalize built-in `in_app` deliveries after claim instead of invoking
22
+ per-row provider-style finalization.
23
+ - Run test files serially to avoid PGlite setup contention in the default
24
+ package check.
25
+
26
+ ## 0.1.3
27
+
28
+ - Dispatch every due delivery created or reused by `publishAndDispatch()` by
29
+ draining its own publication in bounded delivery-id claim pages. The public
30
+ `dispatchDue()` worker limit remains capped per call.
31
+
3
32
  ## 0.1.2
4
33
 
5
34
  - Validate runtime `preferencePolicy` values and dispatch limits before any
package/README.md CHANGED
@@ -74,6 +74,7 @@ export const {
74
74
  notifications,
75
75
  notificationDeliveries,
76
76
  notificationPreferences,
77
+ notificationDispatchState,
77
78
  } = notificationSchema;
78
79
  ```
79
80
 
@@ -106,6 +107,13 @@ schema diff through the application's normal reviewed migration workflow. UNC
106
107
  does not create the index at runtime; correctness is preserved before the index
107
108
  is applied, but legacy fallback reads can be slower.
108
109
 
110
+ Upgrading to `0.1.5` adds the `unc_dispatch_state` table, or the same suffix
111
+ under a custom prefix. That table stores provider-agnostic channel rate-limit
112
+ windows and cooldowns. Generate and apply the schema diff through the
113
+ application's normal reviewed migration workflow before enabling
114
+ `channelPolicies` or adapter `retryAfterMs` hints. UNC never creates the table
115
+ at runtime.
116
+
109
117
  ## Define channels
110
118
 
111
119
  Channel names are plain text, not a PostgreSQL enum. Adding a future channel
@@ -148,7 +156,10 @@ const result = await notificationCore.publishAndDispatch({
148
156
  ```
149
157
 
150
158
  `publish()` only persists. `publishAndDispatch()` persists and immediately
151
- attempts due deliveries. Both use the same durable outbox records.
159
+ attempts every due delivery from that publication. Internally it drains large
160
+ publications in bounded delivery-id claim pages, so broadcasts above 1,000
161
+ deliveries are not left pending just because a single claim wave is capped. Both
162
+ methods use the same durable outbox records.
152
163
 
153
164
  Publication validates the complete JSON payload before opening its transaction.
154
165
  `data`, channel-specific values, and other persisted payload properties must be
@@ -190,25 +201,38 @@ recipients preserve first-seen input order and channels remain unique.
190
201
 
191
202
  A core constructed with a Drizzle `PgTransaction` is publish-only. This lets an
192
203
  application commit its own row and `publish()` atomically. Do not call
193
- `publishAndDispatch()` or `dispatchDue()` on that core: both fail before writing
194
- or invoking an adapter. After the outer transaction commits, dispatch with a
195
- core constructed from the top-level `PgDatabase`.
204
+ `publishAndDispatch()`, `dispatchUntilIdle()`, or `dispatchDue()` on that core:
205
+ all fail before writing or invoking an adapter. After the outer transaction
206
+ commits, dispatch with a core constructed from the top-level `PgDatabase`.
196
207
 
197
- For scheduled delivery or retries, call `dispatchDue()` from infrastructure the
198
- application already owns:
208
+ For scheduled delivery, retries, or queue-style workers, call
209
+ `dispatchUntilIdle()` from infrastructure the application already owns:
199
210
 
200
211
  ```ts
201
- await notificationCore.dispatchDue({
212
+ const result = await notificationCore.dispatchUntilIdle({
202
213
  workerId: process.env.HOSTNAME,
203
214
  limit: 100,
204
215
  concurrency: 10,
216
+ maxBatches: 25,
217
+ deadlineMs: 30_000,
205
218
  });
206
219
  ```
207
220
 
208
221
  `dispatchDue()` accepts `limit` from 1 through 1000 and `concurrency` from 1
209
- through 100. `publishAndDispatch()` accepts the same concurrency range. Runtime
210
- values must be finite positive integers; invalid values fail before publishing,
211
- claiming, or calling a provider.
222
+ through 100; the limit is a per-call worker claim cap. `dispatchUntilIdle()`
223
+ uses the same limit and concurrency boundaries, keeps one stable worker id for
224
+ its drain, stops when no due rows remain, and also stops on `maxBatches`,
225
+ `deadlineMs`, a high-failure batch, or a channel policy deferral. By default a
226
+ batch stops the drain when at least 80% of attempted deliveries fail or
227
+ schedule a retry, which prevents a broken provider from being hammered in a
228
+ tight loop. When due rows exist but a channel rate limit or cooldown blocks
229
+ claiming them, the stop reason is `rate-limited` and `deferredUntil` reports
230
+ the earliest known channel wake-up time. `publishAndDispatch()` accepts the
231
+ same concurrency range and uses capped internal claim pages until every due
232
+ delivery from its own publication has been attempted once, unless a configured
233
+ channel policy defers some rows. Runtime values must be finite positive
234
+ integers; invalid values fail before publishing, claiming, or calling a
235
+ provider.
212
236
 
213
237
  This can run from a cron handler, queue consumer, scheduled function, or an
214
238
  application-owned interval. The package starts no timer and exposes no port.
@@ -218,6 +242,58 @@ Concurrent workers claim rows with `FOR UPDATE SKIP LOCKED`; abandoned
218
242
  a separate claim token, so two attempts from the same worker cannot finalize
219
243
  each other's rows.
220
244
 
245
+ ## Channel dispatch policies
246
+
247
+ UNC can enforce provider-agnostic channel policy without knowing the provider
248
+ SDK. Configure static channel rate windows and circuit-breaker cooldowns when
249
+ creating the core:
250
+
251
+ ```ts
252
+ const notificationCore = createNotificationCore<AppChannel>({
253
+ db,
254
+ adapters,
255
+ channelPolicies: {
256
+ sms: {
257
+ rateLimit: { max: 30, windowMs: 60_000 },
258
+ circuitBreaker: {
259
+ failureRatio: 0.8,
260
+ minAttempts: 20,
261
+ cooldownMs: 5 * 60_000,
262
+ },
263
+ },
264
+ email: {
265
+ rateLimit: { max: 500, windowMs: 60_000 },
266
+ },
267
+ },
268
+ });
269
+ ```
270
+
271
+ Rate limits are durable per channel and shared by concurrent workers through
272
+ the `unc_dispatch_state` table. A row that is deferred by channel policy is not
273
+ claimed and does not consume an attempt. Other channels keep dispatching in the
274
+ same worker call.
275
+
276
+ Circuit breakers are also channel-scoped and durable. After a batch for one
277
+ channel reaches the configured failure ratio and minimum attempted deliveries,
278
+ UNC opens that channel's cooldown. Claimed rows still finalize normally as
279
+ `sent`, `retrying`, or `failed`; the cooldown only prevents another immediate
280
+ wave from hammering the same provider boundary.
281
+
282
+ Adapters can also return provider throttle information without coupling UNC to
283
+ the provider:
284
+
285
+ ```ts
286
+ throw new NotificationDeliveryError("rate_limited", "Provider throttled", {
287
+ retryAfterMs: 120_000,
288
+ });
289
+ ```
290
+
291
+ `retryAfterMs` schedules the failed delivery's next attempt and opens the same
292
+ durable channel cooldown for fresh due rows. It is a finite non-negative number
293
+ no greater than 30 days. It does not replace provider-specific credentials,
294
+ contact lookup, account management, or webhooks; those remain in the adapter and
295
+ application.
296
+
221
297
  ## Preferences
222
298
 
223
299
  Preferences are overrides, not a copied matrix. This keeps storage small when
@@ -357,10 +433,11 @@ throw new NotificationDeliveryError(
357
433
 
358
434
  `NotificationDeliveryError` accepts omitted options or a plain/null-prototype
359
435
  options record. If `retryable` is present it must be an exact boolean; only
360
- omission defaults it to `true`. The code is trimmed, non-empty, PostgreSQL-safe,
361
- and at most 191 characters. The message is non-empty, PostgreSQL-safe, and at
362
- most 10,000 characters. Options are descriptor-captured once before the Error
363
- is constructed.
436
+ omission defaults it to `true`. If `retryAfterMs` is present it must be a finite
437
+ non-negative number no greater than 30 days. The code is trimmed, non-empty,
438
+ PostgreSQL-safe, and at most 191 characters. The message is non-empty,
439
+ PostgreSQL-safe, and at most 10,000 characters. Options are descriptor-captured
440
+ once before the Error is constructed.
364
441
 
365
442
  Unknown errors are retryable. The default backoff is 1 minute, 5 minutes,
366
443
  15 minutes, 1 hour, then 6 hours. Configure `retryDelayMs` and
@@ -451,6 +528,8 @@ and its `DispatchResult` reports the durable state it observed.
451
528
  - No background timers or service runtime.
452
529
  - No assumption that recipient ids are UUIDs.
453
530
  - No assumption that every notification is in-app.
531
+ - Provider-agnostic channel rate/cooldown state is stored in UNC tables, not in
532
+ process memory.
454
533
  - Provider callbacks are invoked only by a top-level-database core, after the
455
534
  claim transaction commits.
456
535
  - Preferences disabled at publication are recorded as `skipped` deliveries for
package/dist/core.d.ts CHANGED
@@ -2,6 +2,35 @@ import { type PgDatabase } from "drizzle-orm/pg-core";
2
2
  import { type NotificationSchema } from "./schema.js";
3
3
  import { PREFERENCE_WILDCARD, type DeliveryAdapters, type DispatchResult, type NotificationLogger, type InboxCursor, type InboxPage, type JsonObject, type PreferenceDefaults, type PreferenceOverride, type PublishInput, type PublishedNotification, type ResolvedPreference } from "./types.js";
4
4
  type AnyPgDatabase = PgDatabase<any, any, any>;
5
+ export type DispatchUntilIdleOptions = {
6
+ limit?: number;
7
+ workerId?: string;
8
+ concurrency?: number;
9
+ maxBatches?: number;
10
+ deadlineMs?: number;
11
+ stopOnFailureRatio?: number;
12
+ stopOnFailureCount?: number;
13
+ };
14
+ export type DispatchUntilIdleStopReason = "idle" | "maxBatches" | "deadline" | "failure-threshold" | "rate-limited";
15
+ export type DispatchUntilIdleResult<TChannel extends string = string> = {
16
+ batches: number;
17
+ reason: DispatchUntilIdleStopReason;
18
+ dispatched: Array<DispatchResult<TChannel>>;
19
+ deferredUntil?: Date;
20
+ };
21
+ export type ChannelRateLimitPolicy = {
22
+ max: number;
23
+ windowMs: number;
24
+ };
25
+ export type ChannelCircuitBreakerPolicy = {
26
+ failureRatio?: number;
27
+ minAttempts?: number;
28
+ cooldownMs?: number;
29
+ };
30
+ export type ChannelDispatchPolicy = {
31
+ rateLimit?: ChannelRateLimitPolicy;
32
+ circuitBreaker?: ChannelCircuitBreakerPolicy;
33
+ };
5
34
  export type NotificationCoreConfig<TChannel extends string, TData extends JsonObject = JsonObject> = {
6
35
  db: AnyPgDatabase;
7
36
  schema?: NotificationSchema;
@@ -10,6 +39,7 @@ export type NotificationCoreConfig<TChannel extends string, TData extends JsonOb
10
39
  preferenceDefaults?: PreferenceDefaults<TChannel>;
11
40
  defaultPreferenceEnabled?: boolean;
12
41
  defaultMaxAttempts?: number;
42
+ channelPolicies?: Partial<Record<TChannel, ChannelDispatchPolicy>>;
13
43
  retryDelayMs?: (attempt: number, error: unknown) => number | Promise<number>;
14
44
  lockTimeoutMs?: number;
15
45
  now?: () => Date;
@@ -31,6 +61,7 @@ export declare class UnifiedNotificationCore<TChannel extends string, TData exte
31
61
  workerId?: string;
32
62
  concurrency?: number;
33
63
  }): Promise<Array<DispatchResult<TChannel>>>;
64
+ dispatchUntilIdle(options?: DispatchUntilIdleOptions): Promise<DispatchUntilIdleResult<TChannel>>;
34
65
  setPreference(preference: PreferenceOverride<TChannel>): Promise<void>;
35
66
  setPreferences(recipientId: string, preferences: ReadonlyArray<Omit<PreferenceOverride<TChannel>, "recipientId">>): Promise<void>;
36
67
  clearPreference(input: {
@@ -1 +1 @@
1
- {"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../src/core.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../src/core.ts"],"names":[],"mappings":"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"}