@happyvertical/smrt-messages 0.60.8 → 0.60.10

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.
Files changed (38) hide show
  1. package/AGENTS.md +17 -0
  2. package/README.md +40 -0
  3. package/agents/notification-outbox.md +116 -0
  4. package/dist/chunks/{AccountCollection-O-zbituV.js → AccountCollection-By48bdwt.js} +2 -2
  5. package/dist/chunks/{AccountCollection-O-zbituV.js.map → AccountCollection-By48bdwt.js.map} +1 -1
  6. package/dist/chunks/{Email-MRtj6D2s.js → Email-CMUK3aWU.js} +3 -3
  7. package/dist/chunks/{Email-MRtj6D2s.js.map → Email-CMUK3aWU.js.map} +1 -1
  8. package/dist/chunks/{EmailFolder-qpOwfo_O.js → EmailFolder-DLJvqNqI.js} +2 -2
  9. package/dist/chunks/{EmailFolder-qpOwfo_O.js.map → EmailFolder-DLJvqNqI.js.map} +1 -1
  10. package/dist/chunks/{Message-5Xz9tauF.js → Message-DXpqot5f.js} +52 -5
  11. package/dist/chunks/Message-DXpqot5f.js.map +1 -0
  12. package/dist/chunks/{MessageCollection-m1C6fDwS.js → MessageCollection-CMGaSGBc.js} +2 -2
  13. package/dist/chunks/{MessageCollection-m1C6fDwS.js.map → MessageCollection-CMGaSGBc.js.map} +1 -1
  14. package/dist/chunks/__smrt-register__-CaGLtiEU.js +6 -0
  15. package/dist/chunks/__smrt-register__-CaGLtiEU.js.map +1 -0
  16. package/dist/collections/NotificationDeliveryCollection.d.ts +6 -0
  17. package/dist/collections/NotificationDeliveryCollection.d.ts.map +1 -0
  18. package/dist/index.d.ts +3 -0
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +780 -38
  21. package/dist/index.js.map +1 -1
  22. package/dist/manifest.json +1135 -89
  23. package/dist/models/Message.d.ts +15 -0
  24. package/dist/models/Message.d.ts.map +1 -1
  25. package/dist/models/NotificationDelivery.d.ts +128 -0
  26. package/dist/models/NotificationDelivery.d.ts.map +1 -0
  27. package/dist/senders/EmailSender.d.ts +9 -0
  28. package/dist/senders/EmailSender.d.ts.map +1 -1
  29. package/dist/services/NotificationOutboxService.d.ts +226 -0
  30. package/dist/services/NotificationOutboxService.d.ts.map +1 -0
  31. package/dist/smrt-knowledge.json +470 -9
  32. package/dist/smrt-knowledge.okf.md +155 -0
  33. package/dist/types.d.ts +6 -0
  34. package/dist/types.d.ts.map +1 -1
  35. package/package.json +17 -16
  36. package/dist/chunks/Message-5Xz9tauF.js.map +0 -1
  37. package/dist/chunks/__smrt-register__-DwNoP4GB.js +0 -6
  38. package/dist/chunks/__smrt-register__-DwNoP4GB.js.map +0 -1
@@ -6,6 +6,8 @@
6
6
  import '../__smrt-register__.js';
7
7
  import { SmrtObject } from '@happyvertical/smrt-core';
8
8
  import type { MessageOptions, MessageSendResult, SendMessageOptions, SendStatus } from "../types.js";
9
+ /** `metadata` key recording that the last failed send may have been accepted. */
10
+ export declare const SEND_OUTCOME_UNKNOWN_METADATA_KEY = "sendOutcomeUnknown";
9
11
  export declare class Message extends SmrtObject {
10
12
  tenantId: string | null;
11
13
  accountId: string;
@@ -94,6 +96,19 @@ export declare class Message extends SmrtObject {
94
96
  * Send this message via its account's sender
95
97
  */
96
98
  send(options?: SendMessageOptions): Promise<MessageSendResult>;
99
+ /**
100
+ * Whether the latest failed send may still have been accepted by the
101
+ * provider (see `MessageSendResult.outcomeUnknown`).
102
+ */
103
+ isSendOutcomeUnknown(): boolean;
104
+ /**
105
+ * Release a send claim whose sender is gone (a crash or lost lease left the
106
+ * row in `sending`): move it to `failed` with an unknown outcome so the
107
+ * owner of the delivery decision can send it again. Returns false, changing
108
+ * nothing, unless the stored row is still `sending`. Only for callers that
109
+ * have established that no live sender holds the claim.
110
+ */
111
+ abandonSendAttempt(reason: string): Promise<boolean>;
97
112
  /**
98
113
  * Retry sending a failed message
99
114
  */
@@ -1 +1 @@
1
- {"version":3,"file":"Message.d.ts","sourceRoot":"","sources":["../../src/models/Message.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,yBAAyB,CAAC;AACjC,OAAO,EAIL,UAAU,EAIX,MAAM,0BAA0B,CAAC;AAElC,OAAO,KAAK,EACV,cAAc,EACd,iBAAiB,EACjB,kBAAkB,EAClB,UAAU,EACX,MAAM,aAAU,CAAC;AAElB,qBAOa,OAAQ,SAAQ,UAAU;IAErC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAQ;IAM/B,SAAS,SAAM;IAQf,SAAS,EAAE,MAAM,GAAG,IAAI,CAAQ;IAGhC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAQ;IAKjC,aAAa,SAAM;IAEnB,QAAQ,SAAM;IAEd,OAAO,SAAM;IAEb,IAAI,SAAM;IAEV,WAAW,SAAM;IAEjB,QAAQ,SAAM;IAEd,WAAW,SAAM;IAEjB,IAAI,EAAE,IAAI,GAAG,IAAI,CAAQ;IAEzB,MAAM,UAAS;IAEf,SAAS,UAAS;IAElB,cAAc,UAAS;IAEvB,IAAI,SAAK;IAIT,QAAQ,SAAM;IAOd,UAAU,EAAE,UAAU,CAAW;IAEjC,MAAM,EAAE,IAAI,GAAG,IAAI,CAAQ;IAE3B,SAAS,SAAM;IAEf,UAAU,SAAK;IAEf,UAAU,SAAK;IAEf,eAAe,EAAE,IAAI,GAAG,IAAI,CAAQ;IAGpC,kBAAkB,SAAM;IAIxB,SAAS,OAAc;IAEvB,SAAS,OAAc;gBAEX,OAAO,GAAE,cAAmB;YAqC1B,qBAAqB;IAuDnC;;OAEG;IACH,cAAc,IAAI,KAAK,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAS3D;;OAEG;IACH,cAAc,CAAC,SAAS,EAAE,KAAK,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,GAAG,IAAI;IAI1E;;OAEG;IACH,WAAW,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAStC;;OAEG;IACH,WAAW,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAIhD;;OAEG;IACG,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAM/B;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAMjC;;OAEG;IACG,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;IAMpC;;OAEG;IACH,QAAQ,IAAI,OAAO;IAInB;;OAEG;IACH,UAAU,CAAC,SAAS,SAAM,GAAG,MAAM;IAMnC;;OAEG;IACG,UAAU;IAWV,WAAW;IASjB;;OAEG;IACG,iBAAiB,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;IAW7C;;OAEG;IACG,cAAc;IAapB;;OAEG;IACG,IAAI,CAAC,OAAO,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAkJpE;;OAEG;IACG,SAAS,CAAC,OAAO,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAwBzE;;;;;;;;OAQG;IACH,SAAS,CAAC,YAAY,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IASjD;;OAEG;IACH,WAAW,CAAC,QAAQ,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO;IA0BvD;;OAEG;IACH,aAAa,IAAI,OAAO;IAyBxB;;OAEG;IACH,SAAS,CAAC,eAAe,IAAI,MAAM;CAapC"}
1
+ {"version":3,"file":"Message.d.ts","sourceRoot":"","sources":["../../src/models/Message.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,yBAAyB,CAAC;AACjC,OAAO,EAIL,UAAU,EAIX,MAAM,0BAA0B,CAAC;AAElC,OAAO,KAAK,EACV,cAAc,EACd,iBAAiB,EACjB,kBAAkB,EAClB,UAAU,EACX,MAAM,aAAU,CAAC;AAElB,iFAAiF;AACjF,eAAO,MAAM,iCAAiC,uBAAuB,CAAC;AA8BtE,qBAOa,OAAQ,SAAQ,UAAU;IAErC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAQ;IAM/B,SAAS,SAAM;IAQf,SAAS,EAAE,MAAM,GAAG,IAAI,CAAQ;IAGhC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAQ;IAKjC,aAAa,SAAM;IAEnB,QAAQ,SAAM;IAEd,OAAO,SAAM;IAEb,IAAI,SAAM;IAEV,WAAW,SAAM;IAEjB,QAAQ,SAAM;IAEd,WAAW,SAAM;IAEjB,IAAI,EAAE,IAAI,GAAG,IAAI,CAAQ;IAEzB,MAAM,UAAS;IAEf,SAAS,UAAS;IAElB,cAAc,UAAS;IAEvB,IAAI,SAAK;IAIT,QAAQ,SAAM;IAOd,UAAU,EAAE,UAAU,CAAW;IAEjC,MAAM,EAAE,IAAI,GAAG,IAAI,CAAQ;IAE3B,SAAS,SAAM;IAEf,UAAU,SAAK;IAEf,UAAU,SAAK;IAEf,eAAe,EAAE,IAAI,GAAG,IAAI,CAAQ;IAGpC,kBAAkB,SAAM;IAIxB,SAAS,OAAc;IAEvB,SAAS,OAAc;gBAEX,OAAO,GAAE,cAAmB;YAqC1B,qBAAqB;IA8DnC;;OAEG;IACH,cAAc,IAAI,KAAK,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAS3D;;OAEG;IACH,cAAc,CAAC,SAAS,EAAE,KAAK,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,GAAG,IAAI;IAI1E;;OAEG;IACH,WAAW,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAStC;;OAEG;IACH,WAAW,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAIhD;;OAEG;IACG,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAM/B;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAMjC;;OAEG;IACG,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;IAMpC;;OAEG;IACH,QAAQ,IAAI,OAAO;IAInB;;OAEG;IACH,UAAU,CAAC,SAAS,SAAM,GAAG,MAAM;IAMnC;;OAEG;IACG,UAAU;IAWV,WAAW;IASjB;;OAEG;IACG,iBAAiB,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;IAW7C;;OAEG;IACG,cAAc;IAapB;;OAEG;IACG,IAAI,CAAC,OAAO,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAoJpE;;;OAGG;IACH,oBAAoB,IAAI,OAAO;IAO/B;;;;;;OAMG;IACG,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAiB1D;;OAEG;IACG,SAAS,CAAC,OAAO,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAwBzE;;;;;;;;OAQG;IACH,SAAS,CAAC,YAAY,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IASjD;;OAEG;IACH,WAAW,CAAC,QAAQ,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO;IA0BvD;;OAEG;IACH,aAAa,IAAI,OAAO;IAyBxB;;OAEG;IACH,SAAS,CAAC,eAAe,IAAI,MAAM;CAapC"}
@@ -0,0 +1,128 @@
1
+ import type { SmrtObjectOptions } from '@happyvertical/smrt-core';
2
+ import '../__smrt-register__.js';
3
+ import { SmrtObject } from '@happyvertical/smrt-core';
4
+ /** Channels the notification outbox can deliver through. */
5
+ export type NotificationDeliveryChannel = 'email';
6
+ export declare const NOTIFICATION_DELIVERY_CHANNELS: readonly NotificationDeliveryChannel[];
7
+ /**
8
+ * Where a delivery is in its lifecycle.
9
+ *
10
+ * - `pending`: waiting for `nextAttemptAt`.
11
+ * - `sending`: leased by one dispatcher until `leaseExpiresAt`.
12
+ * - `sent`: the provider accepted it (terminal).
13
+ * - `failed`: rejected for good or out of attempts (terminal).
14
+ * - `uncertain`: handed to a provider whose outcome is unknown; waits for
15
+ * reconciliation and is never resent automatically.
16
+ * - `cancelled`: suppressed by the host before handoff (terminal).
17
+ */
18
+ export type NotificationDeliveryStatus = 'pending' | 'sending' | 'sent' | 'failed' | 'uncertain' | 'cancelled';
19
+ export interface NotificationDeliveryOptions extends SmrtObjectOptions {
20
+ tenantId?: string;
21
+ recipientUserId?: string;
22
+ channel?: NotificationDeliveryChannel;
23
+ sourceRef?: string;
24
+ kind?: string;
25
+ subject?: string;
26
+ textBody?: string;
27
+ href?: string;
28
+ recipientAddress?: string;
29
+ recipientName?: string;
30
+ accountId?: string;
31
+ messageId?: string | null;
32
+ status?: NotificationDeliveryStatus;
33
+ stateVersion?: number;
34
+ transitionId?: string;
35
+ attempts?: number;
36
+ maxAttempts?: number;
37
+ nextAttemptAt?: Date;
38
+ leaseToken?: string | null;
39
+ leaseExpiresAt?: Date | null;
40
+ handedOffAt?: Date | null;
41
+ deliveredAt?: Date | null;
42
+ providerMessageId?: string;
43
+ lastError?: string;
44
+ }
45
+ /** Column values a lease transition may change (camelCase field names). */
46
+ export type NotificationDeliveryTransition = Partial<Pick<NotificationDelivery, 'messageId' | 'status' | 'attempts' | 'nextAttemptAt' | 'leaseToken' | 'leaseExpiresAt' | 'handedOffAt' | 'deliveredAt' | 'providerMessageId' | 'lastError'>>;
47
+ /**
48
+ * One durable, source-keyed notification delivery to one person over one
49
+ * external channel (the outbox row behind `NotificationOutboxService`).
50
+ *
51
+ * `sourceRef` is the idempotency key: one row per
52
+ * `(tenant, recipient, channel, sourceRef)` (the conflict identity), and that
53
+ * row produces at most one outbound `Message`. The recipient address is a
54
+ * snapshot taken from the host's recipient resolver at enqueue time, never a
55
+ * caller-chosen address.
56
+ *
57
+ * Every state change after creation goes through {@link transition}, a
58
+ * compare-and-set on `stateVersion`, so concurrent dispatchers cannot both
59
+ * hold the lease or overwrite each other's outcome. Generated REST/MCP/CLI
60
+ * are off: rows carry recipient addresses and are reached only through the
61
+ * service.
62
+ */
63
+ export declare class NotificationDelivery extends SmrtObject {
64
+ tenantId: string;
65
+ /** The person being told (`smrt-users:User`, uuid). */
66
+ recipientUserId: string;
67
+ /** Delivery channel; only `email` today. */
68
+ channel: NotificationDeliveryChannel;
69
+ /** Idempotency key for the underlying event (see class docs). */
70
+ sourceRef: string;
71
+ /** Host-defined type, e.g. `project-question.asked`. */
72
+ kind: string;
73
+ /** Email subject line. */
74
+ subject: string;
75
+ /** Plain-text body; the deep link is appended on its own line. */
76
+ textBody: string;
77
+ /** Absolute deep link on the host's configured origin (no credentials). */
78
+ href: string;
79
+ /** Address snapshot from the host recipient resolver. */
80
+ recipientAddress: string;
81
+ /** Display name snapshot from the host recipient resolver. */
82
+ recipientName: string;
83
+ /** Sender `EmailAccount` in the same tenant. */
84
+ accountId: string;
85
+ /** The single outbound `Message` (created under the first lease). */
86
+ messageId: string | null;
87
+ status: NotificationDeliveryStatus;
88
+ /** Compare-and-set counter; bumped by every transition. */
89
+ stateVersion: number;
90
+ /** Unique id of the transition that wrote the current state. */
91
+ transitionId: string;
92
+ /** Leases acquired so far (provider handoffs are a subset). */
93
+ attempts: number;
94
+ /** Lease budget before the delivery fails for good. */
95
+ maxAttempts: number;
96
+ /** Earliest time a dispatcher may lease a `pending` row. */
97
+ nextAttemptAt: Date;
98
+ /** Proof of the current lease holder; cleared when the lease ends. */
99
+ leaseToken: string | null;
100
+ /** When the current lease lapses and the row becomes recoverable. */
101
+ leaseExpiresAt: Date | null;
102
+ /** Set just before the current attempt reaches the provider. */
103
+ handedOffAt: Date | null;
104
+ /** When the provider accepted the message. */
105
+ deliveredAt: Date | null;
106
+ /** Provider message id, when the provider returns one. */
107
+ providerMessageId: string;
108
+ /** The latest failure or uncertainty reason. */
109
+ lastError: string;
110
+ constructor(options?: NotificationDeliveryOptions);
111
+ /** Whether no further automatic work will happen on this row. */
112
+ get isSettled(): boolean;
113
+ /**
114
+ * Apply `changes` only if the stored row is still at `stateVersion` (and,
115
+ * when `leaseToken` is given, still held by that lease). Returns whether
116
+ * this caller won; on success the instance reflects the stored row.
117
+ *
118
+ * PostgreSQL and remote LibSQL evaluate the guard in one conditional
119
+ * UPDATE; local embedded engines use the process write queue, matching
120
+ * `Message.send()`'s claim. The durable row is re-read either way, and the
121
+ * write is recognised by its unique `transitionId`, because DuckDB's update
122
+ * result over-reports affected rows.
123
+ */
124
+ transition(changes: NotificationDeliveryTransition, expected?: {
125
+ leaseToken?: string;
126
+ }): Promise<boolean>;
127
+ }
128
+ //# sourceMappingURL=NotificationDelivery.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NotificationDelivery.d.ts","sourceRoot":"","sources":["../../src/models/NotificationDelivery.ts"],"names":[],"mappings":"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"}
@@ -23,4 +23,13 @@ export declare class EmailSender implements MessageSenderInterface {
23
23
  */
24
24
  private collectAttachments;
25
25
  }
26
+ /**
27
+ * Whether a provider send error proves the message was not accepted: the
28
+ * server answered with an SMTP reply code, the SDK classified it as an
29
+ * authentication/validation failure, a send error accepted no recipient, or
30
+ * the connection was never made. Anything else (a timeout, a reset
31
+ * connection, an unclassified error) may have happened after the server took
32
+ * the message, so its outcome is unknown.
33
+ */
34
+ export declare function isDefiniteSendRejection(error: unknown): boolean;
26
35
  //# sourceMappingURL=EmailSender.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"EmailSender.d.ts","sourceRoot":"","sources":["../../src/senders/EmailSender.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAc,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACpE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,oBAAiB,CAAC;AAC7C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAAwB,CAAC;AAC3D,OAAO,KAAK,EACV,sBAAsB,EACtB,iBAAiB,EACjB,gBAAgB,EACjB,MAAM,aAAU,CAAC;AAElB,qBAAa,WAAY,YAAW,sBAAsB;IACxD,QAAQ,CAAC,YAAY,WAAW;IAChC,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,OAAO,CAAe;gBAElB,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,YAAY;IAKtD,OAAO,IAAI,OAAO;IAIZ,IAAI,CACR,OAAO,EAAE,KAAK,EACd,OAAO,CAAC,EAAE,gBAAgB,GACzB,OAAO,CAAC,iBAAiB,CAAC;IA8D7B;;;;;;;;OAQG;YACW,kBAAkB;CAyEjC"}
1
+ {"version":3,"file":"EmailSender.d.ts","sourceRoot":"","sources":["../../src/senders/EmailSender.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAc,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACpE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,oBAAiB,CAAC;AAC7C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAAwB,CAAC;AAC3D,OAAO,KAAK,EACV,sBAAsB,EACtB,iBAAiB,EACjB,gBAAgB,EACjB,MAAM,aAAU,CAAC;AAElB,qBAAa,WAAY,YAAW,sBAAsB;IACxD,QAAQ,CAAC,YAAY,WAAW;IAChC,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,OAAO,CAAe;gBAElB,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,YAAY;IAKtD,OAAO,IAAI,OAAO;IAIZ,IAAI,CACR,OAAO,EAAE,KAAK,EACd,OAAO,CAAC,EAAE,gBAAgB,GACzB,OAAO,CAAC,iBAAiB,CAAC;IA+D7B;;;;;;;;OAQG;YACW,kBAAkB;CAyEjC;AAkBD;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAmB/D"}
@@ -0,0 +1,226 @@
1
+ import { type SmrtClassOptions } from '@happyvertical/smrt-core';
2
+ import type { Message } from '../models/Message.js';
3
+ import type { NotificationDelivery, NotificationDeliveryChannel } from '../models/NotificationDelivery.js';
4
+ import { type MessagingPrincipal } from '../permissions.js';
5
+ /** What a transport knows about one provider handoff. */
6
+ export type NotificationTransportOutcome = {
7
+ status: 'accepted';
8
+ providerMessageId?: string;
9
+ } | {
10
+ status: 'rejected';
11
+ error: string;
12
+ retryable: boolean;
13
+ } | {
14
+ status: 'unknown';
15
+ error: string;
16
+ };
17
+ /** What a transport can say about an earlier handoff during recovery. */
18
+ export type NotificationTransportReconciliation = NotificationTransportOutcome | {
19
+ status: 'not-sent';
20
+ };
21
+ export interface NotificationTransportRequest {
22
+ delivery: NotificationDelivery;
23
+ /** The delivery's single outbound message (an `Email` for `email`). */
24
+ message: Message;
25
+ /** Stable per delivery; pass it to providers that dedupe on a key. */
26
+ idempotencyKey: string;
27
+ }
28
+ /**
29
+ * Hands one outbound message to a provider. The default
30
+ * ({@link messageSendTransport}) delivers through `Message.send()` and the
31
+ * message's account sender; tests and hosts with their own provider inject
32
+ * another.
33
+ */
34
+ export interface NotificationTransport {
35
+ readonly name: string;
36
+ /**
37
+ * True only when the provider deduplicates on `idempotencyKey`, so sending
38
+ * again after an unknown outcome cannot deliver twice. Then an unknown
39
+ * outcome is retried; otherwise it becomes `uncertain`.
40
+ */
41
+ readonly idempotent?: boolean;
42
+ send(request: NotificationTransportRequest): Promise<NotificationTransportOutcome>;
43
+ /**
44
+ * After a crash or lease loss following a handoff, report what is known
45
+ * from durable state. Omit when nothing can be known (outcome: uncertain).
46
+ */
47
+ reconcile?(request: NotificationTransportRequest): Promise<NotificationTransportReconciliation>;
48
+ }
49
+ /**
50
+ * Delivers through the canonical `Message.send()` (account → provider sender)
51
+ * and reconciles from the message's own `sendStatus`.
52
+ *
53
+ * SMTP and the SDK email providers take no idempotency key, so this
54
+ * transport is not idempotent: a handoff whose outcome is lost stays
55
+ * `uncertain` instead of risking a second email.
56
+ */
57
+ export declare const messageSendTransport: NotificationTransport;
58
+ export type NotificationOutboxDenialReason = 'permission' | 'recipient' | 'sender' | 'link';
59
+ /** Thrown when the host's policy refuses an enqueue; nothing is stored. */
60
+ export declare class NotificationOutboxDeniedError extends Error {
61
+ readonly reason: NotificationOutboxDenialReason;
62
+ constructor(reason: NotificationOutboxDenialReason, message: string);
63
+ }
64
+ export interface NotificationRecipientRequest {
65
+ tenantId: string;
66
+ recipientUserId: string;
67
+ channel: NotificationDeliveryChannel;
68
+ }
69
+ export interface NotificationRecipient {
70
+ address: string;
71
+ name?: string;
72
+ }
73
+ export interface NotificationSuppressionRequest extends NotificationRecipientRequest {
74
+ kind: string;
75
+ sourceRef: string;
76
+ }
77
+ export interface NotificationOutboxOptions {
78
+ db: SmrtClassOptions['db'];
79
+ /**
80
+ * Host authorization for recipients: the address of `recipientUserId` when
81
+ * the host allows notifying them in `tenantId` (e.g. a member of that
82
+ * tenant), otherwise null, which denies the enqueue. Callers never supply
83
+ * an address.
84
+ */
85
+ resolveRecipient(request: NotificationRecipientRequest): Promise<NotificationRecipient | null> | NotificationRecipient | null;
86
+ /** The sending `EmailAccount` id for a tenant (deployment setup). */
87
+ resolveSenderAccountId(request: {
88
+ tenantId: string;
89
+ }): Promise<string | null> | string | null;
90
+ /** Absolute http(s) URL deep links are built on, e.g. `https://app.example.com`. */
91
+ linkBaseUrl: string;
92
+ /** Optional opt-out hook, checked at enqueue and again before handoff. */
93
+ isSuppressed?(request: NotificationSuppressionRequest): Promise<boolean> | boolean;
94
+ /** Provider seam; defaults to {@link messageSendTransport}. */
95
+ transport?: NotificationTransport;
96
+ /**
97
+ * When set, enqueue and reconcile require `messages.send` in the tenant.
98
+ * Omit only for trusted system code that performs its own authorization.
99
+ */
100
+ principal?: MessagingPrincipal;
101
+ /** Lease length; must exceed the slowest provider handoff (default 5 min). */
102
+ leaseMs?: number;
103
+ /** Lease budget per delivery (default 5). */
104
+ maxAttempts?: number;
105
+ /** Delay before attempt `n + 1` after `n` failed (default 1 min · 2ⁿ⁻¹, ≤ 1 h). */
106
+ retryDelayMs?(attempts: number): number;
107
+ /** Clock (tests). */
108
+ now?(): Date;
109
+ }
110
+ export interface NotificationEmailInput {
111
+ tenantId: string;
112
+ recipientUserId: string;
113
+ /** Idempotency key for the event, e.g. `project-question:<id>:asked`. */
114
+ sourceRef: string;
115
+ /** Host-defined type, e.g. `project-question.asked`. */
116
+ kind: string;
117
+ /** One line; CR/LF are rejected. */
118
+ subject: string;
119
+ /** Plain-text body; the deep link is appended on its own line. */
120
+ text: string;
121
+ /** Host-relative path of the deep link (`/portal/...`). */
122
+ path: string;
123
+ /** Do not send before this time (default: now). */
124
+ notBefore?: Date;
125
+ }
126
+ export interface NotificationEnqueueResult {
127
+ delivery: NotificationDelivery;
128
+ /** False when `sourceRef` matched an existing delivery (returned untouched). */
129
+ created: boolean;
130
+ }
131
+ export type NotificationDispatchOutcome = 'sent' | 'retry-scheduled' | 'failed' | 'uncertain' | 'cancelled' | 'lease-lost';
132
+ export interface NotificationDispatchReport {
133
+ /** Rows this call won a lease on. */
134
+ leased: number;
135
+ outcomes: Array<{
136
+ deliveryId: string;
137
+ tenantId: string;
138
+ outcome: NotificationDispatchOutcome;
139
+ }>;
140
+ }
141
+ export interface NotificationDispatchOptions {
142
+ /** Tenants to dispatch; omit to discover due rows across all tenants. */
143
+ tenantIds?: readonly string[];
144
+ /** Maximum rows to lease in this call (default 25, max 200). */
145
+ limit?: number;
146
+ }
147
+ export type NotificationReconcileOutcome = 'sent' | 'retry' | 'failed';
148
+ /**
149
+ * The id of a delivery's one outbound message: a name-based uuid derived from
150
+ * the delivery id, so every dispatcher computes the same identity.
151
+ */
152
+ export declare function notificationDeliveryMessageId(deliveryId: string): Promise<string>;
153
+ /** The correlation id that ties a delivery to its one outbound message. */
154
+ export declare function notificationDeliveryCorrelationId(deliveryId: string): string;
155
+ /**
156
+ * Build an absolute deep link from a host-relative `path` on `baseUrl`.
157
+ *
158
+ * The link always stays on the configured origin (no `//host`, backslash, or
159
+ * scheme tricks) and never carries credentials: the destination is an
160
+ * ordinary authenticated route, so the recipient signs in as themselves.
161
+ */
162
+ export declare function buildNotificationLink(baseUrl: string, path: string): string;
163
+ /**
164
+ * Source-keyed, durable notification email outbox.
165
+ *
166
+ * `enqueueEmail()` stores one `NotificationDelivery` per
167
+ * `(tenant, recipient, email, sourceRef)` — a repeated event returns the
168
+ * existing row — after the host has authorized the recipient and sender.
169
+ * `dispatchDue()` leases due rows with a compare-and-set, creates the single
170
+ * outbound `Email` under the lease, hands it to the transport, and records
171
+ * the outcome; it is safe to run from several workers at once and to crash
172
+ * at any point. See `packages/messages/agents/notification-outbox.md`.
173
+ */
174
+ export declare class NotificationOutboxService {
175
+ private readonly options;
176
+ private readonly transport;
177
+ private readonly leaseMs;
178
+ private readonly maxAttempts;
179
+ private readonly retryDelayMs;
180
+ private readonly now;
181
+ constructor(options: NotificationOutboxOptions);
182
+ private collection;
183
+ private authorize;
184
+ /** Store one email delivery for the event unless `sourceRef` already has one. */
185
+ enqueueEmail(input: NotificationEmailInput): Promise<NotificationEnqueueResult>;
186
+ /** Lease and deliver due rows; returns what happened to each leased row. */
187
+ dispatchDue(options?: NotificationDispatchOptions): Promise<NotificationDispatchReport>;
188
+ /** Deliveries waiting for a reconciliation decision, oldest first. */
189
+ listUncertain(options: {
190
+ tenantId: string;
191
+ limit?: number;
192
+ }): Promise<NotificationDelivery[]>;
193
+ /**
194
+ * Settle an `uncertain` delivery after checking the provider out of band:
195
+ * `sent` (it arrived), `failed` (give up), or `retry` (send again,
196
+ * accepting the risk of a duplicate; a message left claimed by a dead
197
+ * sender is released first). Returns false when the row is not uncertain
198
+ * any more, or for `retry` when the message is recorded as sent.
199
+ */
200
+ reconcile(input: {
201
+ tenantId: string;
202
+ deliveryId: string;
203
+ outcome: NotificationReconcileOutcome;
204
+ note?: string;
205
+ }): Promise<boolean>;
206
+ private requireSenderAccount;
207
+ private isSuppressed;
208
+ private findDue;
209
+ /** Lease one candidate and carry it to an outcome; null when not leased. */
210
+ private dispatchOne;
211
+ private recoverHandoff;
212
+ private applyOutcome;
213
+ private scheduleRetry;
214
+ /** End the lease in a terminal status; reports lease loss instead of overwriting. */
215
+ private settle;
216
+ private endLease;
217
+ private loadMessage;
218
+ /**
219
+ * The delivery's single outbound `Email`, created under the lease. Its id
220
+ * is derived from the delivery id and inserted insert-only, so a stale
221
+ * dispatcher that resumes after its lease was taken over hits the stored
222
+ * row (a unique violation) instead of creating a second email.
223
+ */
224
+ private ensureMessage;
225
+ }
226
+ //# sourceMappingURL=NotificationOutboxService.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NotificationOutboxService.d.ts","sourceRoot":"","sources":["../../src/services/NotificationOutboxService.ts"],"names":[],"mappings":"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"}