@web-ts-toolkit/message-service 0.40.1 → 0.41.0

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 (6) hide show
  1. package/README.md +161 -29
  2. package/index.d.mts +1118 -36
  3. package/index.d.ts +1118 -36
  4. package/index.js +1153 -157
  5. package/index.mjs +1139 -157
  6. package/package.json +8 -4
package/index.d.mts CHANGED
@@ -25,6 +25,13 @@ interface PrepareResult {
25
25
  interface ActionContext {
26
26
  message: IMessage | IMessageArchive;
27
27
  user: MessageUser;
28
+ /**
29
+ * Stable, persisted idempotency key for this action attempt. Handlers that
30
+ * call external systems must pass this key to those systems or otherwise
31
+ * deduplicate by it; the service cannot make arbitrary external side effects
32
+ * exactly-once.
33
+ */
34
+ actionAttemptId?: string;
28
35
  getModel: (name: string) => mongoose.Model<unknown>;
29
36
  expireSession?: (sessionId: string) => Promise<void>;
30
37
  refundPayment?: (sessionId: string) => Promise<void>;
@@ -111,10 +118,19 @@ interface InterpolationResult {
111
118
  */
112
119
  type Usertype = 'sender' | 'receiver';
113
120
 
121
+ declare class TemplateRegistryValidationError extends Error {
122
+ static [Symbol.hasInstance](value: unknown): boolean;
123
+ constructor(message: string);
124
+ }
114
125
  /**
115
- * In-memory registry for message templates.
126
+ * In-memory registry for trusted message-template code.
116
127
  * Templates are looked up by their `templateCd`.
117
128
  *
129
+ * The registry validates action metadata and stores a frozen shallow snapshot of
130
+ * authorization/action-critical structure. Function fields keep their original
131
+ * identity, but mutating the object passed to `register()` later cannot change
132
+ * registered action authorization or handlers accidentally.
133
+ *
118
134
  * Recommended: create one `TemplateRegistry` per app and pass it to
119
135
  * `MessageService({ registry })`. Use the `defaultRegistry` only for
120
136
  * simple cases or quick experiments.
@@ -154,9 +170,6 @@ declare class TemplateRegistry {
154
170
  */
155
171
  clear(): void;
156
172
  }
157
- /**
158
- * Default global registry instance.
159
- */
160
173
  declare const defaultRegistry: TemplateRegistry;
161
174
  /**
162
175
  * Check if a given actionCd exists in a registered template.
@@ -177,6 +190,8 @@ interface IMessageContent {
177
190
  */
178
191
  type MessageType = 'notification' | 'request' | 'reminder' | 'approval' | (string & {});
179
192
  type UserId = mongoose.Types.ObjectId | string;
193
+ type ActionLifecycleState = 'active' | 'processing' | 'retryable';
194
+ type ActionNotificationState = 'none' | 'pending' | 'sent' | 'failed';
180
195
  /**
181
196
  * Minimal user shape accepted by MessageService methods.
182
197
  * `displayName` is optional but templates that interpolate `{{displayName}}`
@@ -188,9 +203,11 @@ interface MessageUser {
188
203
  roles?: string[];
189
204
  displayName?: string;
190
205
  }
191
- interface IMessageMethods {
206
+ interface IMessageRelationshipMethods {
192
207
  isSender(user: MessageUser): boolean;
193
208
  isReceiver(user: MessageUser): boolean;
209
+ }
210
+ interface IMessageMethods extends IMessageRelationshipMethods {
194
211
  archive(actionCd: string, archivedBy: UserId, registry: TemplateRegistry): Promise<void>;
195
212
  }
196
213
  /**
@@ -215,7 +232,15 @@ interface IBaseMessage {
215
232
  payload: Record<string, unknown>;
216
233
  display: Record<string, unknown>;
217
234
  clientRequestId: string | null;
235
+ clientRequestOwnerId: string | null;
218
236
  clientRequestItemIndex: number | null;
237
+ actionState: ActionLifecycleState;
238
+ actionCd: string | null;
239
+ actionAttemptId: string | null;
240
+ actionClaimedBy: string | null;
241
+ actionClaimedAt: Date | null;
242
+ actionLeaseExpiresAt: Date | null;
243
+ actionFailureMessage: string | null;
219
244
  createdAt: Date;
220
245
  updatedAt: Date;
221
246
  }
@@ -223,12 +248,16 @@ type MongooseQueryHelpers = Record<string, unknown>;
223
248
  type IMessage = mongoose.Document<unknown, MongooseQueryHelpers, IMessageMethods> & IBaseMessage & IMessageMethods & {
224
249
  __v?: number;
225
250
  };
226
- type IMessageArchive = mongoose.Document<unknown, MongooseQueryHelpers, IMessageMethods> & IBaseMessage & {
251
+ type IMessageArchive = mongoose.Document<unknown, MongooseQueryHelpers, IMessageRelationshipMethods> & IBaseMessage & {
227
252
  actionCd: string;
228
253
  archivedBy: UserId;
229
254
  archivedAt: Date;
255
+ actionAttemptId: string | null;
256
+ actionNotificationState: ActionNotificationState;
257
+ actionNotificationError: string | null;
258
+ actionNotificationAttemptedAt: Date | null;
230
259
  __v?: number;
231
- } & IMessageMethods;
260
+ } & IMessageRelationshipMethods;
232
261
 
233
262
  /** Model name constants — use these when calling mongoose.model() or getModel() */
234
263
  declare const MESSAGE_MODEL_NAME = "Message";
@@ -279,19 +308,34 @@ declare const MessageContentSchema: mongoose.Schema<any, mongoose.Model<any, any
279
308
  declare const BaseMessageFields: Record<string, mongoose.SchemaTypeOptions<unknown>>;
280
309
 
281
310
  type EmailNotifier = (email: string, title: string, message: string) => Promise<void> | void;
311
+ type EmailDeliveryFailureStage = 'recipientLookup' | 'notifier';
312
+ interface EmailDeliveryFailureEvent {
313
+ stage: EmailDeliveryFailureStage;
314
+ error: unknown;
315
+ messageId: unknown;
316
+ recipientId: UserId;
317
+ title: string;
318
+ }
282
319
  interface MessageSchemaConfig {
283
320
  /**
284
- * Called on every message save (unless excluded) to send an email
285
- * notification to the recipient. Pass `null` (the default) to disable.
321
+ * Called for newly created, non-transactional messages (unless excluded) to
322
+ * send a best-effort email notification to the recipient. Pass `null` (the
323
+ * default) to disable.
286
324
  *
287
325
  * When `null`, no pre-save hook is registered at all.
288
326
  */
289
327
  emailNotifier?: EmailNotifier | null;
290
328
  /**
291
- * Message titles (lowercased, after trim) that should NOT trigger email
292
- * notifications. Comparison is case-insensitive and matches the *compiled*
293
- * title — i.e. the interpolated result. Use this to suppress emails for
294
- * low-priority messages.
329
+ * Called when recipient lookup or notifier delivery fails. The message save
330
+ * has already succeeded and is not rolled back. If this hook throws, that
331
+ * secondary failure is swallowed to preserve the best-effort delivery
332
+ * contract.
333
+ */
334
+ onEmailDeliveryFailure?: (event: EmailDeliveryFailureEvent) => void | Promise<void>;
335
+ /**
336
+ * Message titles that should NOT trigger email notifications. Exclusions and
337
+ * rendered titles are compared with the same trim + lowercase normalization
338
+ * against the compiled title — i.e. the interpolated result.
295
339
  */
296
340
  emailNotificationExclusions?: string[];
297
341
  /**
@@ -303,12 +347,19 @@ interface MessageSchemaConfig {
303
347
  * `buildMessageSchema` does a sanity check to give a clear error if not.
304
348
  */
305
349
  userModelName?: string;
350
+ /**
351
+ * Connection used for eager model-registration checks when configuring
352
+ * connection-local schemas. Runtime document methods and hooks still use the
353
+ * hydrated document's own connection.
354
+ */
355
+ connection?: mongoose.Connection;
306
356
  /**
307
357
  * Name of the Mongoose model used for archived messages.
308
358
  * Defaults to `'MessageArchive'`. Used by the `archive()` instance method.
309
359
  */
310
360
  archiveModelName?: string;
311
361
  }
362
+ type MessageModel = mongoose.Model<IBaseMessage, object, IMessageMethods>;
312
363
  /**
313
364
  * Build a fresh Message schema with the given configuration.
314
365
  * Prefer this over the default `MessageSchema` export when you need
@@ -318,28 +369,904 @@ interface MessageSchemaConfig {
318
369
  * be registered with Mongoose before calling this function. The schema
319
370
  * factory checks this eagerly to fail fast.
320
371
  */
321
- declare function buildMessageSchema(config?: MessageSchemaConfig): mongoose.Schema;
372
+ declare function buildMessageSchema(config?: MessageSchemaConfig): mongoose.Schema<IBaseMessage, MessageModel, IMessageMethods>;
322
373
  /**
323
374
  * Default Message schema with no email notifier and no pre-save hook.
324
375
  * Provided for backwards compatibility and simple use cases.
325
376
  * Use `buildMessageSchema(config)` when you need custom behavior.
326
377
  */
327
- declare const MessageSchema: mongoose.Schema;
378
+ declare const MessageSchema: mongoose.Schema<IBaseMessage, MessageModel, IMessageMethods, {}, {}, {}, mongoose.DefaultSchemaOptions, IBaseMessage, mongoose.Document<unknown, {}, IBaseMessage, {
379
+ id: string;
380
+ }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
381
+ _id: mongoose.Types.ObjectId;
382
+ } & {
383
+ __v: number;
384
+ }, "id" | keyof IMessageMethods> & mongoose.HydratedDocumentOverrides<{
385
+ id: string;
386
+ } & IMessageMethods>, {
387
+ templateCd?: mongoose.SchemaDefinitionProperty<string, IBaseMessage, mongoose.Document<unknown, {}, IBaseMessage, {
388
+ id: string;
389
+ }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
390
+ _id: mongoose.Types.ObjectId;
391
+ } & {
392
+ __v: number;
393
+ }, "id" | keyof IMessageMethods> & mongoose.HydratedDocumentOverrides<{
394
+ id: string;
395
+ } & IMessageMethods>> | undefined;
396
+ type?: mongoose.SchemaDefinitionProperty<MessageType, IBaseMessage, mongoose.Document<unknown, {}, IBaseMessage, {
397
+ id: string;
398
+ }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
399
+ _id: mongoose.Types.ObjectId;
400
+ } & {
401
+ __v: number;
402
+ }, "id" | keyof IMessageMethods> & mongoose.HydratedDocumentOverrides<{
403
+ id: string;
404
+ } & IMessageMethods>> | undefined;
405
+ fromUser?: mongoose.SchemaDefinitionProperty<UserId | null, IBaseMessage, mongoose.Document<unknown, {}, IBaseMessage, {
406
+ id: string;
407
+ }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
408
+ _id: mongoose.Types.ObjectId;
409
+ } & {
410
+ __v: number;
411
+ }, "id" | keyof IMessageMethods> & mongoose.HydratedDocumentOverrides<{
412
+ id: string;
413
+ } & IMessageMethods>> | undefined;
414
+ toUser?: mongoose.SchemaDefinitionProperty<UserId | null, IBaseMessage, mongoose.Document<unknown, {}, IBaseMessage, {
415
+ id: string;
416
+ }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
417
+ _id: mongoose.Types.ObjectId;
418
+ } & {
419
+ __v: number;
420
+ }, "id" | keyof IMessageMethods> & mongoose.HydratedDocumentOverrides<{
421
+ id: string;
422
+ } & IMessageMethods>> | undefined;
423
+ toRoles?: mongoose.SchemaDefinitionProperty<string[], IBaseMessage, mongoose.Document<unknown, {}, IBaseMessage, {
424
+ id: string;
425
+ }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
426
+ _id: mongoose.Types.ObjectId;
427
+ } & {
428
+ __v: number;
429
+ }, "id" | keyof IMessageMethods> & mongoose.HydratedDocumentOverrides<{
430
+ id: string;
431
+ } & IMessageMethods>> | undefined;
432
+ senderContent?: mongoose.SchemaDefinitionProperty<IMessageContent, IBaseMessage, mongoose.Document<unknown, {}, IBaseMessage, {
433
+ id: string;
434
+ }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
435
+ _id: mongoose.Types.ObjectId;
436
+ } & {
437
+ __v: number;
438
+ }, "id" | keyof IMessageMethods> & mongoose.HydratedDocumentOverrides<{
439
+ id: string;
440
+ } & IMessageMethods>> | undefined;
441
+ receiverContent?: mongoose.SchemaDefinitionProperty<IMessageContent, IBaseMessage, mongoose.Document<unknown, {}, IBaseMessage, {
442
+ id: string;
443
+ }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
444
+ _id: mongoose.Types.ObjectId;
445
+ } & {
446
+ __v: number;
447
+ }, "id" | keyof IMessageMethods> & mongoose.HydratedDocumentOverrides<{
448
+ id: string;
449
+ } & IMessageMethods>> | undefined;
450
+ documents?: mongoose.SchemaDefinitionProperty<mongoose.Types.ObjectId[], IBaseMessage, mongoose.Document<unknown, {}, IBaseMessage, {
451
+ id: string;
452
+ }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
453
+ _id: mongoose.Types.ObjectId;
454
+ } & {
455
+ __v: number;
456
+ }, "id" | keyof IMessageMethods> & mongoose.HydratedDocumentOverrides<{
457
+ id: string;
458
+ } & IMessageMethods>> | undefined;
459
+ paymentSession?: mongoose.SchemaDefinitionProperty<string | null, IBaseMessage, mongoose.Document<unknown, {}, IBaseMessage, {
460
+ id: string;
461
+ }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
462
+ _id: mongoose.Types.ObjectId;
463
+ } & {
464
+ __v: number;
465
+ }, "id" | keyof IMessageMethods> & mongoose.HydratedDocumentOverrides<{
466
+ id: string;
467
+ } & IMessageMethods>> | undefined;
468
+ paymentCd?: mongoose.SchemaDefinitionProperty<string, IBaseMessage, mongoose.Document<unknown, {}, IBaseMessage, {
469
+ id: string;
470
+ }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
471
+ _id: mongoose.Types.ObjectId;
472
+ } & {
473
+ __v: number;
474
+ }, "id" | keyof IMessageMethods> & mongoose.HydratedDocumentOverrides<{
475
+ id: string;
476
+ } & IMessageMethods>> | undefined;
477
+ payload?: mongoose.SchemaDefinitionProperty<Record<string, unknown>, IBaseMessage, mongoose.Document<unknown, {}, IBaseMessage, {
478
+ id: string;
479
+ }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
480
+ _id: mongoose.Types.ObjectId;
481
+ } & {
482
+ __v: number;
483
+ }, "id" | keyof IMessageMethods> & mongoose.HydratedDocumentOverrides<{
484
+ id: string;
485
+ } & IMessageMethods>> | undefined;
486
+ display?: mongoose.SchemaDefinitionProperty<Record<string, unknown>, IBaseMessage, mongoose.Document<unknown, {}, IBaseMessage, {
487
+ id: string;
488
+ }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
489
+ _id: mongoose.Types.ObjectId;
490
+ } & {
491
+ __v: number;
492
+ }, "id" | keyof IMessageMethods> & mongoose.HydratedDocumentOverrides<{
493
+ id: string;
494
+ } & IMessageMethods>> | undefined;
495
+ clientRequestId?: mongoose.SchemaDefinitionProperty<string | null, IBaseMessage, mongoose.Document<unknown, {}, IBaseMessage, {
496
+ id: string;
497
+ }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
498
+ _id: mongoose.Types.ObjectId;
499
+ } & {
500
+ __v: number;
501
+ }, "id" | keyof IMessageMethods> & mongoose.HydratedDocumentOverrides<{
502
+ id: string;
503
+ } & IMessageMethods>> | undefined;
504
+ clientRequestOwnerId?: mongoose.SchemaDefinitionProperty<string | null, IBaseMessage, mongoose.Document<unknown, {}, IBaseMessage, {
505
+ id: string;
506
+ }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
507
+ _id: mongoose.Types.ObjectId;
508
+ } & {
509
+ __v: number;
510
+ }, "id" | keyof IMessageMethods> & mongoose.HydratedDocumentOverrides<{
511
+ id: string;
512
+ } & IMessageMethods>> | undefined;
513
+ clientRequestItemIndex?: mongoose.SchemaDefinitionProperty<number | null, IBaseMessage, mongoose.Document<unknown, {}, IBaseMessage, {
514
+ id: string;
515
+ }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
516
+ _id: mongoose.Types.ObjectId;
517
+ } & {
518
+ __v: number;
519
+ }, "id" | keyof IMessageMethods> & mongoose.HydratedDocumentOverrides<{
520
+ id: string;
521
+ } & IMessageMethods>> | undefined;
522
+ actionState?: mongoose.SchemaDefinitionProperty<ActionLifecycleState, IBaseMessage, mongoose.Document<unknown, {}, IBaseMessage, {
523
+ id: string;
524
+ }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
525
+ _id: mongoose.Types.ObjectId;
526
+ } & {
527
+ __v: number;
528
+ }, "id" | keyof IMessageMethods> & mongoose.HydratedDocumentOverrides<{
529
+ id: string;
530
+ } & IMessageMethods>> | undefined;
531
+ actionCd?: mongoose.SchemaDefinitionProperty<string | null, IBaseMessage, mongoose.Document<unknown, {}, IBaseMessage, {
532
+ id: string;
533
+ }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
534
+ _id: mongoose.Types.ObjectId;
535
+ } & {
536
+ __v: number;
537
+ }, "id" | keyof IMessageMethods> & mongoose.HydratedDocumentOverrides<{
538
+ id: string;
539
+ } & IMessageMethods>> | undefined;
540
+ actionAttemptId?: mongoose.SchemaDefinitionProperty<string | null, IBaseMessage, mongoose.Document<unknown, {}, IBaseMessage, {
541
+ id: string;
542
+ }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
543
+ _id: mongoose.Types.ObjectId;
544
+ } & {
545
+ __v: number;
546
+ }, "id" | keyof IMessageMethods> & mongoose.HydratedDocumentOverrides<{
547
+ id: string;
548
+ } & IMessageMethods>> | undefined;
549
+ actionClaimedBy?: mongoose.SchemaDefinitionProperty<string | null, IBaseMessage, mongoose.Document<unknown, {}, IBaseMessage, {
550
+ id: string;
551
+ }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
552
+ _id: mongoose.Types.ObjectId;
553
+ } & {
554
+ __v: number;
555
+ }, "id" | keyof IMessageMethods> & mongoose.HydratedDocumentOverrides<{
556
+ id: string;
557
+ } & IMessageMethods>> | undefined;
558
+ actionClaimedAt?: mongoose.SchemaDefinitionProperty<Date | null, IBaseMessage, mongoose.Document<unknown, {}, IBaseMessage, {
559
+ id: string;
560
+ }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
561
+ _id: mongoose.Types.ObjectId;
562
+ } & {
563
+ __v: number;
564
+ }, "id" | keyof IMessageMethods> & mongoose.HydratedDocumentOverrides<{
565
+ id: string;
566
+ } & IMessageMethods>> | undefined;
567
+ actionLeaseExpiresAt?: mongoose.SchemaDefinitionProperty<Date | null, IBaseMessage, mongoose.Document<unknown, {}, IBaseMessage, {
568
+ id: string;
569
+ }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
570
+ _id: mongoose.Types.ObjectId;
571
+ } & {
572
+ __v: number;
573
+ }, "id" | keyof IMessageMethods> & mongoose.HydratedDocumentOverrides<{
574
+ id: string;
575
+ } & IMessageMethods>> | undefined;
576
+ actionFailureMessage?: mongoose.SchemaDefinitionProperty<string | null, IBaseMessage, mongoose.Document<unknown, {}, IBaseMessage, {
577
+ id: string;
578
+ }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
579
+ _id: mongoose.Types.ObjectId;
580
+ } & {
581
+ __v: number;
582
+ }, "id" | keyof IMessageMethods> & mongoose.HydratedDocumentOverrides<{
583
+ id: string;
584
+ } & IMessageMethods>> | undefined;
585
+ createdAt?: mongoose.SchemaDefinitionProperty<Date, IBaseMessage, mongoose.Document<unknown, {}, IBaseMessage, {
586
+ id: string;
587
+ }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
588
+ _id: mongoose.Types.ObjectId;
589
+ } & {
590
+ __v: number;
591
+ }, "id" | keyof IMessageMethods> & mongoose.HydratedDocumentOverrides<{
592
+ id: string;
593
+ } & IMessageMethods>> | undefined;
594
+ updatedAt?: mongoose.SchemaDefinitionProperty<Date, IBaseMessage, mongoose.Document<unknown, {}, IBaseMessage, {
595
+ id: string;
596
+ }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
597
+ _id: mongoose.Types.ObjectId;
598
+ } & {
599
+ __v: number;
600
+ }, "id" | keyof IMessageMethods> & mongoose.HydratedDocumentOverrides<{
601
+ id: string;
602
+ } & IMessageMethods>> | undefined;
603
+ }, IBaseMessage>;
328
604
 
605
+ type MessageArchiveSchemaFields = IBaseMessage & {
606
+ actionCd: string;
607
+ archivedBy: unknown;
608
+ archivedAt: Date;
609
+ actionAttemptId: string | null;
610
+ actionNotificationState: 'none' | 'pending' | 'sent' | 'failed';
611
+ actionNotificationError: string | null;
612
+ actionNotificationAttemptedAt: Date | null;
613
+ };
614
+ type MessageArchiveModel = mongoose.Model<MessageArchiveSchemaFields, object, IMessageRelationshipMethods>;
329
615
  /**
330
616
  * Build a fresh MessageArchive schema.
331
617
  * Mirrors the default Message schema but adds archive-specific fields
332
618
  * (actionCd, archivedBy, archivedAt) and no pre-save email hook.
333
619
  */
334
- declare function buildMessageArchiveSchema(): mongoose.Schema;
620
+ declare function buildMessageArchiveSchema(): mongoose.Schema<MessageArchiveSchemaFields, MessageArchiveModel, IMessageRelationshipMethods>;
335
621
  /**
336
622
  * Default MessageArchive schema. Provided for backwards compatibility.
337
623
  * Use `buildMessageArchiveSchema()` if you need a fresh instance.
338
624
  */
339
- declare const MessageArchiveSchema: mongoose.Schema;
625
+ declare const MessageArchiveSchema: mongoose.Schema<MessageArchiveSchemaFields, MessageArchiveModel, IMessageRelationshipMethods, {}, {}, {}, mongoose.DefaultSchemaOptions, MessageArchiveSchemaFields, mongoose.Document<unknown, {}, MessageArchiveSchemaFields, {
626
+ id: string;
627
+ }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
628
+ actionCd: string;
629
+ archivedBy: unknown;
630
+ archivedAt: Date;
631
+ actionAttemptId: string | null;
632
+ actionNotificationState: "none" | "pending" | "sent" | "failed";
633
+ actionNotificationError: string | null;
634
+ actionNotificationAttemptedAt: Date | null;
635
+ } & {
636
+ _id: mongoose.Types.ObjectId;
637
+ } & {
638
+ __v: number;
639
+ }, "id" | keyof IMessageRelationshipMethods> & mongoose.HydratedDocumentOverrides<{
640
+ id: string;
641
+ } & IMessageRelationshipMethods>, {
642
+ templateCd?: mongoose.SchemaDefinitionProperty<string, MessageArchiveSchemaFields, mongoose.Document<unknown, {}, MessageArchiveSchemaFields, {
643
+ id: string;
644
+ }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
645
+ actionCd: string;
646
+ archivedBy: unknown;
647
+ archivedAt: Date;
648
+ actionAttemptId: string | null;
649
+ actionNotificationState: "none" | "pending" | "sent" | "failed";
650
+ actionNotificationError: string | null;
651
+ actionNotificationAttemptedAt: Date | null;
652
+ } & {
653
+ _id: mongoose.Types.ObjectId;
654
+ } & {
655
+ __v: number;
656
+ }, "id" | keyof IMessageRelationshipMethods> & mongoose.HydratedDocumentOverrides<{
657
+ id: string;
658
+ } & IMessageRelationshipMethods>> | undefined;
659
+ type?: mongoose.SchemaDefinitionProperty<MessageType, MessageArchiveSchemaFields, mongoose.Document<unknown, {}, MessageArchiveSchemaFields, {
660
+ id: string;
661
+ }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
662
+ actionCd: string;
663
+ archivedBy: unknown;
664
+ archivedAt: Date;
665
+ actionAttemptId: string | null;
666
+ actionNotificationState: "none" | "pending" | "sent" | "failed";
667
+ actionNotificationError: string | null;
668
+ actionNotificationAttemptedAt: Date | null;
669
+ } & {
670
+ _id: mongoose.Types.ObjectId;
671
+ } & {
672
+ __v: number;
673
+ }, "id" | keyof IMessageRelationshipMethods> & mongoose.HydratedDocumentOverrides<{
674
+ id: string;
675
+ } & IMessageRelationshipMethods>> | undefined;
676
+ fromUser?: mongoose.SchemaDefinitionProperty<UserId | null, MessageArchiveSchemaFields, mongoose.Document<unknown, {}, MessageArchiveSchemaFields, {
677
+ id: string;
678
+ }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
679
+ actionCd: string;
680
+ archivedBy: unknown;
681
+ archivedAt: Date;
682
+ actionAttemptId: string | null;
683
+ actionNotificationState: "none" | "pending" | "sent" | "failed";
684
+ actionNotificationError: string | null;
685
+ actionNotificationAttemptedAt: Date | null;
686
+ } & {
687
+ _id: mongoose.Types.ObjectId;
688
+ } & {
689
+ __v: number;
690
+ }, "id" | keyof IMessageRelationshipMethods> & mongoose.HydratedDocumentOverrides<{
691
+ id: string;
692
+ } & IMessageRelationshipMethods>> | undefined;
693
+ toUser?: mongoose.SchemaDefinitionProperty<UserId | null, MessageArchiveSchemaFields, mongoose.Document<unknown, {}, MessageArchiveSchemaFields, {
694
+ id: string;
695
+ }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
696
+ actionCd: string;
697
+ archivedBy: unknown;
698
+ archivedAt: Date;
699
+ actionAttemptId: string | null;
700
+ actionNotificationState: "none" | "pending" | "sent" | "failed";
701
+ actionNotificationError: string | null;
702
+ actionNotificationAttemptedAt: Date | null;
703
+ } & {
704
+ _id: mongoose.Types.ObjectId;
705
+ } & {
706
+ __v: number;
707
+ }, "id" | keyof IMessageRelationshipMethods> & mongoose.HydratedDocumentOverrides<{
708
+ id: string;
709
+ } & IMessageRelationshipMethods>> | undefined;
710
+ toRoles?: mongoose.SchemaDefinitionProperty<string[], MessageArchiveSchemaFields, mongoose.Document<unknown, {}, MessageArchiveSchemaFields, {
711
+ id: string;
712
+ }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
713
+ actionCd: string;
714
+ archivedBy: unknown;
715
+ archivedAt: Date;
716
+ actionAttemptId: string | null;
717
+ actionNotificationState: "none" | "pending" | "sent" | "failed";
718
+ actionNotificationError: string | null;
719
+ actionNotificationAttemptedAt: Date | null;
720
+ } & {
721
+ _id: mongoose.Types.ObjectId;
722
+ } & {
723
+ __v: number;
724
+ }, "id" | keyof IMessageRelationshipMethods> & mongoose.HydratedDocumentOverrides<{
725
+ id: string;
726
+ } & IMessageRelationshipMethods>> | undefined;
727
+ senderContent?: mongoose.SchemaDefinitionProperty<IMessageContent, MessageArchiveSchemaFields, mongoose.Document<unknown, {}, MessageArchiveSchemaFields, {
728
+ id: string;
729
+ }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
730
+ actionCd: string;
731
+ archivedBy: unknown;
732
+ archivedAt: Date;
733
+ actionAttemptId: string | null;
734
+ actionNotificationState: "none" | "pending" | "sent" | "failed";
735
+ actionNotificationError: string | null;
736
+ actionNotificationAttemptedAt: Date | null;
737
+ } & {
738
+ _id: mongoose.Types.ObjectId;
739
+ } & {
740
+ __v: number;
741
+ }, "id" | keyof IMessageRelationshipMethods> & mongoose.HydratedDocumentOverrides<{
742
+ id: string;
743
+ } & IMessageRelationshipMethods>> | undefined;
744
+ receiverContent?: mongoose.SchemaDefinitionProperty<IMessageContent, MessageArchiveSchemaFields, mongoose.Document<unknown, {}, MessageArchiveSchemaFields, {
745
+ id: string;
746
+ }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
747
+ actionCd: string;
748
+ archivedBy: unknown;
749
+ archivedAt: Date;
750
+ actionAttemptId: string | null;
751
+ actionNotificationState: "none" | "pending" | "sent" | "failed";
752
+ actionNotificationError: string | null;
753
+ actionNotificationAttemptedAt: Date | null;
754
+ } & {
755
+ _id: mongoose.Types.ObjectId;
756
+ } & {
757
+ __v: number;
758
+ }, "id" | keyof IMessageRelationshipMethods> & mongoose.HydratedDocumentOverrides<{
759
+ id: string;
760
+ } & IMessageRelationshipMethods>> | undefined;
761
+ documents?: mongoose.SchemaDefinitionProperty<mongoose.Types.ObjectId[], MessageArchiveSchemaFields, mongoose.Document<unknown, {}, MessageArchiveSchemaFields, {
762
+ id: string;
763
+ }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
764
+ actionCd: string;
765
+ archivedBy: unknown;
766
+ archivedAt: Date;
767
+ actionAttemptId: string | null;
768
+ actionNotificationState: "none" | "pending" | "sent" | "failed";
769
+ actionNotificationError: string | null;
770
+ actionNotificationAttemptedAt: Date | null;
771
+ } & {
772
+ _id: mongoose.Types.ObjectId;
773
+ } & {
774
+ __v: number;
775
+ }, "id" | keyof IMessageRelationshipMethods> & mongoose.HydratedDocumentOverrides<{
776
+ id: string;
777
+ } & IMessageRelationshipMethods>> | undefined;
778
+ paymentSession?: mongoose.SchemaDefinitionProperty<string | null, MessageArchiveSchemaFields, mongoose.Document<unknown, {}, MessageArchiveSchemaFields, {
779
+ id: string;
780
+ }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
781
+ actionCd: string;
782
+ archivedBy: unknown;
783
+ archivedAt: Date;
784
+ actionAttemptId: string | null;
785
+ actionNotificationState: "none" | "pending" | "sent" | "failed";
786
+ actionNotificationError: string | null;
787
+ actionNotificationAttemptedAt: Date | null;
788
+ } & {
789
+ _id: mongoose.Types.ObjectId;
790
+ } & {
791
+ __v: number;
792
+ }, "id" | keyof IMessageRelationshipMethods> & mongoose.HydratedDocumentOverrides<{
793
+ id: string;
794
+ } & IMessageRelationshipMethods>> | undefined;
795
+ paymentCd?: mongoose.SchemaDefinitionProperty<string, MessageArchiveSchemaFields, mongoose.Document<unknown, {}, MessageArchiveSchemaFields, {
796
+ id: string;
797
+ }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
798
+ actionCd: string;
799
+ archivedBy: unknown;
800
+ archivedAt: Date;
801
+ actionAttemptId: string | null;
802
+ actionNotificationState: "none" | "pending" | "sent" | "failed";
803
+ actionNotificationError: string | null;
804
+ actionNotificationAttemptedAt: Date | null;
805
+ } & {
806
+ _id: mongoose.Types.ObjectId;
807
+ } & {
808
+ __v: number;
809
+ }, "id" | keyof IMessageRelationshipMethods> & mongoose.HydratedDocumentOverrides<{
810
+ id: string;
811
+ } & IMessageRelationshipMethods>> | undefined;
812
+ payload?: mongoose.SchemaDefinitionProperty<Record<string, unknown>, MessageArchiveSchemaFields, mongoose.Document<unknown, {}, MessageArchiveSchemaFields, {
813
+ id: string;
814
+ }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
815
+ actionCd: string;
816
+ archivedBy: unknown;
817
+ archivedAt: Date;
818
+ actionAttemptId: string | null;
819
+ actionNotificationState: "none" | "pending" | "sent" | "failed";
820
+ actionNotificationError: string | null;
821
+ actionNotificationAttemptedAt: Date | null;
822
+ } & {
823
+ _id: mongoose.Types.ObjectId;
824
+ } & {
825
+ __v: number;
826
+ }, "id" | keyof IMessageRelationshipMethods> & mongoose.HydratedDocumentOverrides<{
827
+ id: string;
828
+ } & IMessageRelationshipMethods>> | undefined;
829
+ display?: mongoose.SchemaDefinitionProperty<Record<string, unknown>, MessageArchiveSchemaFields, mongoose.Document<unknown, {}, MessageArchiveSchemaFields, {
830
+ id: string;
831
+ }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
832
+ actionCd: string;
833
+ archivedBy: unknown;
834
+ archivedAt: Date;
835
+ actionAttemptId: string | null;
836
+ actionNotificationState: "none" | "pending" | "sent" | "failed";
837
+ actionNotificationError: string | null;
838
+ actionNotificationAttemptedAt: Date | null;
839
+ } & {
840
+ _id: mongoose.Types.ObjectId;
841
+ } & {
842
+ __v: number;
843
+ }, "id" | keyof IMessageRelationshipMethods> & mongoose.HydratedDocumentOverrides<{
844
+ id: string;
845
+ } & IMessageRelationshipMethods>> | undefined;
846
+ clientRequestId?: mongoose.SchemaDefinitionProperty<string | null, MessageArchiveSchemaFields, mongoose.Document<unknown, {}, MessageArchiveSchemaFields, {
847
+ id: string;
848
+ }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
849
+ actionCd: string;
850
+ archivedBy: unknown;
851
+ archivedAt: Date;
852
+ actionAttemptId: string | null;
853
+ actionNotificationState: "none" | "pending" | "sent" | "failed";
854
+ actionNotificationError: string | null;
855
+ actionNotificationAttemptedAt: Date | null;
856
+ } & {
857
+ _id: mongoose.Types.ObjectId;
858
+ } & {
859
+ __v: number;
860
+ }, "id" | keyof IMessageRelationshipMethods> & mongoose.HydratedDocumentOverrides<{
861
+ id: string;
862
+ } & IMessageRelationshipMethods>> | undefined;
863
+ clientRequestOwnerId?: mongoose.SchemaDefinitionProperty<string | null, MessageArchiveSchemaFields, mongoose.Document<unknown, {}, MessageArchiveSchemaFields, {
864
+ id: string;
865
+ }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
866
+ actionCd: string;
867
+ archivedBy: unknown;
868
+ archivedAt: Date;
869
+ actionAttemptId: string | null;
870
+ actionNotificationState: "none" | "pending" | "sent" | "failed";
871
+ actionNotificationError: string | null;
872
+ actionNotificationAttemptedAt: Date | null;
873
+ } & {
874
+ _id: mongoose.Types.ObjectId;
875
+ } & {
876
+ __v: number;
877
+ }, "id" | keyof IMessageRelationshipMethods> & mongoose.HydratedDocumentOverrides<{
878
+ id: string;
879
+ } & IMessageRelationshipMethods>> | undefined;
880
+ clientRequestItemIndex?: mongoose.SchemaDefinitionProperty<number | null, MessageArchiveSchemaFields, mongoose.Document<unknown, {}, MessageArchiveSchemaFields, {
881
+ id: string;
882
+ }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
883
+ actionCd: string;
884
+ archivedBy: unknown;
885
+ archivedAt: Date;
886
+ actionAttemptId: string | null;
887
+ actionNotificationState: "none" | "pending" | "sent" | "failed";
888
+ actionNotificationError: string | null;
889
+ actionNotificationAttemptedAt: Date | null;
890
+ } & {
891
+ _id: mongoose.Types.ObjectId;
892
+ } & {
893
+ __v: number;
894
+ }, "id" | keyof IMessageRelationshipMethods> & mongoose.HydratedDocumentOverrides<{
895
+ id: string;
896
+ } & IMessageRelationshipMethods>> | undefined;
897
+ actionState?: mongoose.SchemaDefinitionProperty<ActionLifecycleState, MessageArchiveSchemaFields, mongoose.Document<unknown, {}, MessageArchiveSchemaFields, {
898
+ id: string;
899
+ }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
900
+ actionCd: string;
901
+ archivedBy: unknown;
902
+ archivedAt: Date;
903
+ actionAttemptId: string | null;
904
+ actionNotificationState: "none" | "pending" | "sent" | "failed";
905
+ actionNotificationError: string | null;
906
+ actionNotificationAttemptedAt: Date | null;
907
+ } & {
908
+ _id: mongoose.Types.ObjectId;
909
+ } & {
910
+ __v: number;
911
+ }, "id" | keyof IMessageRelationshipMethods> & mongoose.HydratedDocumentOverrides<{
912
+ id: string;
913
+ } & IMessageRelationshipMethods>> | undefined;
914
+ actionCd?: mongoose.SchemaDefinitionProperty<string, MessageArchiveSchemaFields, mongoose.Document<unknown, {}, MessageArchiveSchemaFields, {
915
+ id: string;
916
+ }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
917
+ actionCd: string;
918
+ archivedBy: unknown;
919
+ archivedAt: Date;
920
+ actionAttemptId: string | null;
921
+ actionNotificationState: "none" | "pending" | "sent" | "failed";
922
+ actionNotificationError: string | null;
923
+ actionNotificationAttemptedAt: Date | null;
924
+ } & {
925
+ _id: mongoose.Types.ObjectId;
926
+ } & {
927
+ __v: number;
928
+ }, "id" | keyof IMessageRelationshipMethods> & mongoose.HydratedDocumentOverrides<{
929
+ id: string;
930
+ } & IMessageRelationshipMethods>> | undefined;
931
+ actionAttemptId?: mongoose.SchemaDefinitionProperty<string | null, MessageArchiveSchemaFields, mongoose.Document<unknown, {}, MessageArchiveSchemaFields, {
932
+ id: string;
933
+ }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
934
+ actionCd: string;
935
+ archivedBy: unknown;
936
+ archivedAt: Date;
937
+ actionAttemptId: string | null;
938
+ actionNotificationState: "none" | "pending" | "sent" | "failed";
939
+ actionNotificationError: string | null;
940
+ actionNotificationAttemptedAt: Date | null;
941
+ } & {
942
+ _id: mongoose.Types.ObjectId;
943
+ } & {
944
+ __v: number;
945
+ }, "id" | keyof IMessageRelationshipMethods> & mongoose.HydratedDocumentOverrides<{
946
+ id: string;
947
+ } & IMessageRelationshipMethods>> | undefined;
948
+ actionClaimedBy?: mongoose.SchemaDefinitionProperty<string | null, MessageArchiveSchemaFields, mongoose.Document<unknown, {}, MessageArchiveSchemaFields, {
949
+ id: string;
950
+ }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
951
+ actionCd: string;
952
+ archivedBy: unknown;
953
+ archivedAt: Date;
954
+ actionAttemptId: string | null;
955
+ actionNotificationState: "none" | "pending" | "sent" | "failed";
956
+ actionNotificationError: string | null;
957
+ actionNotificationAttemptedAt: Date | null;
958
+ } & {
959
+ _id: mongoose.Types.ObjectId;
960
+ } & {
961
+ __v: number;
962
+ }, "id" | keyof IMessageRelationshipMethods> & mongoose.HydratedDocumentOverrides<{
963
+ id: string;
964
+ } & IMessageRelationshipMethods>> | undefined;
965
+ actionClaimedAt?: mongoose.SchemaDefinitionProperty<Date | null, MessageArchiveSchemaFields, mongoose.Document<unknown, {}, MessageArchiveSchemaFields, {
966
+ id: string;
967
+ }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
968
+ actionCd: string;
969
+ archivedBy: unknown;
970
+ archivedAt: Date;
971
+ actionAttemptId: string | null;
972
+ actionNotificationState: "none" | "pending" | "sent" | "failed";
973
+ actionNotificationError: string | null;
974
+ actionNotificationAttemptedAt: Date | null;
975
+ } & {
976
+ _id: mongoose.Types.ObjectId;
977
+ } & {
978
+ __v: number;
979
+ }, "id" | keyof IMessageRelationshipMethods> & mongoose.HydratedDocumentOverrides<{
980
+ id: string;
981
+ } & IMessageRelationshipMethods>> | undefined;
982
+ actionLeaseExpiresAt?: mongoose.SchemaDefinitionProperty<Date | null, MessageArchiveSchemaFields, mongoose.Document<unknown, {}, MessageArchiveSchemaFields, {
983
+ id: string;
984
+ }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
985
+ actionCd: string;
986
+ archivedBy: unknown;
987
+ archivedAt: Date;
988
+ actionAttemptId: string | null;
989
+ actionNotificationState: "none" | "pending" | "sent" | "failed";
990
+ actionNotificationError: string | null;
991
+ actionNotificationAttemptedAt: Date | null;
992
+ } & {
993
+ _id: mongoose.Types.ObjectId;
994
+ } & {
995
+ __v: number;
996
+ }, "id" | keyof IMessageRelationshipMethods> & mongoose.HydratedDocumentOverrides<{
997
+ id: string;
998
+ } & IMessageRelationshipMethods>> | undefined;
999
+ actionFailureMessage?: mongoose.SchemaDefinitionProperty<string | null, MessageArchiveSchemaFields, mongoose.Document<unknown, {}, MessageArchiveSchemaFields, {
1000
+ id: string;
1001
+ }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
1002
+ actionCd: string;
1003
+ archivedBy: unknown;
1004
+ archivedAt: Date;
1005
+ actionAttemptId: string | null;
1006
+ actionNotificationState: "none" | "pending" | "sent" | "failed";
1007
+ actionNotificationError: string | null;
1008
+ actionNotificationAttemptedAt: Date | null;
1009
+ } & {
1010
+ _id: mongoose.Types.ObjectId;
1011
+ } & {
1012
+ __v: number;
1013
+ }, "id" | keyof IMessageRelationshipMethods> & mongoose.HydratedDocumentOverrides<{
1014
+ id: string;
1015
+ } & IMessageRelationshipMethods>> | undefined;
1016
+ createdAt?: mongoose.SchemaDefinitionProperty<Date, MessageArchiveSchemaFields, mongoose.Document<unknown, {}, MessageArchiveSchemaFields, {
1017
+ id: string;
1018
+ }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
1019
+ actionCd: string;
1020
+ archivedBy: unknown;
1021
+ archivedAt: Date;
1022
+ actionAttemptId: string | null;
1023
+ actionNotificationState: "none" | "pending" | "sent" | "failed";
1024
+ actionNotificationError: string | null;
1025
+ actionNotificationAttemptedAt: Date | null;
1026
+ } & {
1027
+ _id: mongoose.Types.ObjectId;
1028
+ } & {
1029
+ __v: number;
1030
+ }, "id" | keyof IMessageRelationshipMethods> & mongoose.HydratedDocumentOverrides<{
1031
+ id: string;
1032
+ } & IMessageRelationshipMethods>> | undefined;
1033
+ updatedAt?: mongoose.SchemaDefinitionProperty<Date, MessageArchiveSchemaFields, mongoose.Document<unknown, {}, MessageArchiveSchemaFields, {
1034
+ id: string;
1035
+ }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
1036
+ actionCd: string;
1037
+ archivedBy: unknown;
1038
+ archivedAt: Date;
1039
+ actionAttemptId: string | null;
1040
+ actionNotificationState: "none" | "pending" | "sent" | "failed";
1041
+ actionNotificationError: string | null;
1042
+ actionNotificationAttemptedAt: Date | null;
1043
+ } & {
1044
+ _id: mongoose.Types.ObjectId;
1045
+ } & {
1046
+ __v: number;
1047
+ }, "id" | keyof IMessageRelationshipMethods> & mongoose.HydratedDocumentOverrides<{
1048
+ id: string;
1049
+ } & IMessageRelationshipMethods>> | undefined;
1050
+ archivedBy?: mongoose.SchemaDefinitionProperty<unknown, MessageArchiveSchemaFields, mongoose.Document<unknown, {}, MessageArchiveSchemaFields, {
1051
+ id: string;
1052
+ }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
1053
+ actionCd: string;
1054
+ archivedBy: unknown;
1055
+ archivedAt: Date;
1056
+ actionAttemptId: string | null;
1057
+ actionNotificationState: "none" | "pending" | "sent" | "failed";
1058
+ actionNotificationError: string | null;
1059
+ actionNotificationAttemptedAt: Date | null;
1060
+ } & {
1061
+ _id: mongoose.Types.ObjectId;
1062
+ } & {
1063
+ __v: number;
1064
+ }, "id" | keyof IMessageRelationshipMethods> & mongoose.HydratedDocumentOverrides<{
1065
+ id: string;
1066
+ } & IMessageRelationshipMethods>> | undefined;
1067
+ archivedAt?: mongoose.SchemaDefinitionProperty<Date, MessageArchiveSchemaFields, mongoose.Document<unknown, {}, MessageArchiveSchemaFields, {
1068
+ id: string;
1069
+ }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
1070
+ actionCd: string;
1071
+ archivedBy: unknown;
1072
+ archivedAt: Date;
1073
+ actionAttemptId: string | null;
1074
+ actionNotificationState: "none" | "pending" | "sent" | "failed";
1075
+ actionNotificationError: string | null;
1076
+ actionNotificationAttemptedAt: Date | null;
1077
+ } & {
1078
+ _id: mongoose.Types.ObjectId;
1079
+ } & {
1080
+ __v: number;
1081
+ }, "id" | keyof IMessageRelationshipMethods> & mongoose.HydratedDocumentOverrides<{
1082
+ id: string;
1083
+ } & IMessageRelationshipMethods>> | undefined;
1084
+ actionNotificationState?: mongoose.SchemaDefinitionProperty<"none" | "pending" | "sent" | "failed", MessageArchiveSchemaFields, mongoose.Document<unknown, {}, MessageArchiveSchemaFields, {
1085
+ id: string;
1086
+ }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
1087
+ actionCd: string;
1088
+ archivedBy: unknown;
1089
+ archivedAt: Date;
1090
+ actionAttemptId: string | null;
1091
+ actionNotificationState: "none" | "pending" | "sent" | "failed";
1092
+ actionNotificationError: string | null;
1093
+ actionNotificationAttemptedAt: Date | null;
1094
+ } & {
1095
+ _id: mongoose.Types.ObjectId;
1096
+ } & {
1097
+ __v: number;
1098
+ }, "id" | keyof IMessageRelationshipMethods> & mongoose.HydratedDocumentOverrides<{
1099
+ id: string;
1100
+ } & IMessageRelationshipMethods>> | undefined;
1101
+ actionNotificationError?: mongoose.SchemaDefinitionProperty<string | null, MessageArchiveSchemaFields, mongoose.Document<unknown, {}, MessageArchiveSchemaFields, {
1102
+ id: string;
1103
+ }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
1104
+ actionCd: string;
1105
+ archivedBy: unknown;
1106
+ archivedAt: Date;
1107
+ actionAttemptId: string | null;
1108
+ actionNotificationState: "none" | "pending" | "sent" | "failed";
1109
+ actionNotificationError: string | null;
1110
+ actionNotificationAttemptedAt: Date | null;
1111
+ } & {
1112
+ _id: mongoose.Types.ObjectId;
1113
+ } & {
1114
+ __v: number;
1115
+ }, "id" | keyof IMessageRelationshipMethods> & mongoose.HydratedDocumentOverrides<{
1116
+ id: string;
1117
+ } & IMessageRelationshipMethods>> | undefined;
1118
+ actionNotificationAttemptedAt?: mongoose.SchemaDefinitionProperty<Date | null, MessageArchiveSchemaFields, mongoose.Document<unknown, {}, MessageArchiveSchemaFields, {
1119
+ id: string;
1120
+ }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
1121
+ actionCd: string;
1122
+ archivedBy: unknown;
1123
+ archivedAt: Date;
1124
+ actionAttemptId: string | null;
1125
+ actionNotificationState: "none" | "pending" | "sent" | "failed";
1126
+ actionNotificationError: string | null;
1127
+ actionNotificationAttemptedAt: Date | null;
1128
+ } & {
1129
+ _id: mongoose.Types.ObjectId;
1130
+ } & {
1131
+ __v: number;
1132
+ }, "id" | keyof IMessageRelationshipMethods> & mongoose.HydratedDocumentOverrides<{
1133
+ id: string;
1134
+ } & IMessageRelationshipMethods>> | undefined;
1135
+ }, MessageArchiveSchemaFields>;
340
1136
 
341
- declare function buildMessageRequestSchema(): mongoose.Schema;
342
- declare const MessageRequestSchema: mongoose.Schema;
1137
+ interface MessageRequestSchemaFields {
1138
+ clientRequestId: string;
1139
+ clientRequestOwnerId: string;
1140
+ templateCd: string;
1141
+ state: 'pending' | 'completed' | 'failed';
1142
+ itemCount: number | null;
1143
+ leaseOwnerId: string | null;
1144
+ leaseExpiresAt: Date | null;
1145
+ completedAt: Date | null;
1146
+ failedAt: Date | null;
1147
+ failureMessage: string | null;
1148
+ createdAt: Date;
1149
+ updatedAt: Date;
1150
+ }
1151
+ declare function buildMessageRequestSchema(): mongoose.Schema<MessageRequestSchemaFields>;
1152
+ declare const MessageRequestSchema: mongoose.Schema<MessageRequestSchemaFields, mongoose.Model<MessageRequestSchemaFields, any, any, any, any, any, MessageRequestSchemaFields>, {}, {}, {}, {}, mongoose.DefaultSchemaOptions, MessageRequestSchemaFields, mongoose.Document<unknown, {}, MessageRequestSchemaFields, {
1153
+ id: string;
1154
+ }, mongoose.DefaultSchemaOptions> & Omit<MessageRequestSchemaFields & {
1155
+ _id: mongoose.Types.ObjectId;
1156
+ } & {
1157
+ __v: number;
1158
+ }, "id"> & mongoose.HydratedDocumentOverrides<{
1159
+ id: string;
1160
+ }>, {
1161
+ clientRequestId?: mongoose.SchemaDefinitionProperty<string, MessageRequestSchemaFields, mongoose.Document<unknown, {}, MessageRequestSchemaFields, {
1162
+ id: string;
1163
+ }, mongoose.DefaultSchemaOptions> & Omit<MessageRequestSchemaFields & {
1164
+ _id: mongoose.Types.ObjectId;
1165
+ } & {
1166
+ __v: number;
1167
+ }, "id"> & mongoose.HydratedDocumentOverrides<{
1168
+ id: string;
1169
+ }>> | undefined;
1170
+ clientRequestOwnerId?: mongoose.SchemaDefinitionProperty<string, MessageRequestSchemaFields, mongoose.Document<unknown, {}, MessageRequestSchemaFields, {
1171
+ id: string;
1172
+ }, mongoose.DefaultSchemaOptions> & Omit<MessageRequestSchemaFields & {
1173
+ _id: mongoose.Types.ObjectId;
1174
+ } & {
1175
+ __v: number;
1176
+ }, "id"> & mongoose.HydratedDocumentOverrides<{
1177
+ id: string;
1178
+ }>> | undefined;
1179
+ templateCd?: mongoose.SchemaDefinitionProperty<string, MessageRequestSchemaFields, mongoose.Document<unknown, {}, MessageRequestSchemaFields, {
1180
+ id: string;
1181
+ }, mongoose.DefaultSchemaOptions> & Omit<MessageRequestSchemaFields & {
1182
+ _id: mongoose.Types.ObjectId;
1183
+ } & {
1184
+ __v: number;
1185
+ }, "id"> & mongoose.HydratedDocumentOverrides<{
1186
+ id: string;
1187
+ }>> | undefined;
1188
+ state?: mongoose.SchemaDefinitionProperty<"pending" | "failed" | "completed", MessageRequestSchemaFields, mongoose.Document<unknown, {}, MessageRequestSchemaFields, {
1189
+ id: string;
1190
+ }, mongoose.DefaultSchemaOptions> & Omit<MessageRequestSchemaFields & {
1191
+ _id: mongoose.Types.ObjectId;
1192
+ } & {
1193
+ __v: number;
1194
+ }, "id"> & mongoose.HydratedDocumentOverrides<{
1195
+ id: string;
1196
+ }>> | undefined;
1197
+ itemCount?: mongoose.SchemaDefinitionProperty<number | null, MessageRequestSchemaFields, mongoose.Document<unknown, {}, MessageRequestSchemaFields, {
1198
+ id: string;
1199
+ }, mongoose.DefaultSchemaOptions> & Omit<MessageRequestSchemaFields & {
1200
+ _id: mongoose.Types.ObjectId;
1201
+ } & {
1202
+ __v: number;
1203
+ }, "id"> & mongoose.HydratedDocumentOverrides<{
1204
+ id: string;
1205
+ }>> | undefined;
1206
+ leaseOwnerId?: mongoose.SchemaDefinitionProperty<string | null, MessageRequestSchemaFields, mongoose.Document<unknown, {}, MessageRequestSchemaFields, {
1207
+ id: string;
1208
+ }, mongoose.DefaultSchemaOptions> & Omit<MessageRequestSchemaFields & {
1209
+ _id: mongoose.Types.ObjectId;
1210
+ } & {
1211
+ __v: number;
1212
+ }, "id"> & mongoose.HydratedDocumentOverrides<{
1213
+ id: string;
1214
+ }>> | undefined;
1215
+ leaseExpiresAt?: mongoose.SchemaDefinitionProperty<Date | null, MessageRequestSchemaFields, mongoose.Document<unknown, {}, MessageRequestSchemaFields, {
1216
+ id: string;
1217
+ }, mongoose.DefaultSchemaOptions> & Omit<MessageRequestSchemaFields & {
1218
+ _id: mongoose.Types.ObjectId;
1219
+ } & {
1220
+ __v: number;
1221
+ }, "id"> & mongoose.HydratedDocumentOverrides<{
1222
+ id: string;
1223
+ }>> | undefined;
1224
+ completedAt?: mongoose.SchemaDefinitionProperty<Date | null, MessageRequestSchemaFields, mongoose.Document<unknown, {}, MessageRequestSchemaFields, {
1225
+ id: string;
1226
+ }, mongoose.DefaultSchemaOptions> & Omit<MessageRequestSchemaFields & {
1227
+ _id: mongoose.Types.ObjectId;
1228
+ } & {
1229
+ __v: number;
1230
+ }, "id"> & mongoose.HydratedDocumentOverrides<{
1231
+ id: string;
1232
+ }>> | undefined;
1233
+ failedAt?: mongoose.SchemaDefinitionProperty<Date | null, MessageRequestSchemaFields, mongoose.Document<unknown, {}, MessageRequestSchemaFields, {
1234
+ id: string;
1235
+ }, mongoose.DefaultSchemaOptions> & Omit<MessageRequestSchemaFields & {
1236
+ _id: mongoose.Types.ObjectId;
1237
+ } & {
1238
+ __v: number;
1239
+ }, "id"> & mongoose.HydratedDocumentOverrides<{
1240
+ id: string;
1241
+ }>> | undefined;
1242
+ failureMessage?: mongoose.SchemaDefinitionProperty<string | null, MessageRequestSchemaFields, mongoose.Document<unknown, {}, MessageRequestSchemaFields, {
1243
+ id: string;
1244
+ }, mongoose.DefaultSchemaOptions> & Omit<MessageRequestSchemaFields & {
1245
+ _id: mongoose.Types.ObjectId;
1246
+ } & {
1247
+ __v: number;
1248
+ }, "id"> & mongoose.HydratedDocumentOverrides<{
1249
+ id: string;
1250
+ }>> | undefined;
1251
+ createdAt?: mongoose.SchemaDefinitionProperty<Date, MessageRequestSchemaFields, mongoose.Document<unknown, {}, MessageRequestSchemaFields, {
1252
+ id: string;
1253
+ }, mongoose.DefaultSchemaOptions> & Omit<MessageRequestSchemaFields & {
1254
+ _id: mongoose.Types.ObjectId;
1255
+ } & {
1256
+ __v: number;
1257
+ }, "id"> & mongoose.HydratedDocumentOverrides<{
1258
+ id: string;
1259
+ }>> | undefined;
1260
+ updatedAt?: mongoose.SchemaDefinitionProperty<Date, MessageRequestSchemaFields, mongoose.Document<unknown, {}, MessageRequestSchemaFields, {
1261
+ id: string;
1262
+ }, mongoose.DefaultSchemaOptions> & Omit<MessageRequestSchemaFields & {
1263
+ _id: mongoose.Types.ObjectId;
1264
+ } & {
1265
+ __v: number;
1266
+ }, "id"> & mongoose.HydratedDocumentOverrides<{
1267
+ id: string;
1268
+ }>> | undefined;
1269
+ }, MessageRequestSchemaFields>;
343
1270
 
344
1271
  /**
345
1272
  * Apply the standard set of action filters (usertype match, permission, condition).
@@ -392,6 +1319,14 @@ declare class NoopEmailProvider implements EmailProvider {
392
1319
  * Host apps implement this to handle payment sessions for messages
393
1320
  * that require payment (e.g. Stripe, Adyen, Paddle).
394
1321
  *
1322
+ * Message creation may create external sessions before MongoDB commit. If the
1323
+ * message write or idempotent batch transaction fails, `MessageService` calls
1324
+ * `expireSession()` for every newly created uncommitted session. Providers must
1325
+ * make expiration idempotent because callers may retry cleanup after ambiguous
1326
+ * network or provider failures. If expiration itself fails, message creation
1327
+ * fails with `PaymentSessionCompensationError` and the optional service hook is
1328
+ * invoked for observability.
1329
+ *
395
1330
  * `priceArgs` is intentionally a free-form `Record<string, unknown>` so
396
1331
  * providers can accept their own metadata (currency, line items, etc.).
397
1332
  * Templates should document what they pass.
@@ -404,13 +1339,13 @@ interface PaymentProvider {
404
1339
  */
405
1340
  createSession(user: UserId, code: string, priceArgs?: Record<string, unknown>): Promise<string | null>;
406
1341
  /**
407
- * Expire a session that was never completed.
408
- * Should be idempotent.
1342
+ * Expire a session that was never committed to a usable message.
1343
+ * Must be idempotent.
409
1344
  */
410
1345
  expireSession(sessionId: string): Promise<void>;
411
1346
  /**
412
1347
  * Refund a completed payment.
413
- * Should be idempotent.
1348
+ * Must be idempotent.
414
1349
  */
415
1350
  refundPayment(sessionId: string): Promise<void>;
416
1351
  }
@@ -426,8 +1361,15 @@ declare class NoopPaymentProvider implements PaymentProvider {
426
1361
  }
427
1362
 
428
1363
  interface MessageServiceOptions {
429
- getModel: (name: string) => mongoose.Model<unknown>;
1364
+ getModel?: (name: string) => mongoose.Model<unknown>;
1365
+ connection?: mongoose.Connection;
1366
+ modelNames?: Partial<MessageServiceModelNames>;
430
1367
  paymentProvider?: PaymentProvider | null;
1368
+ /**
1369
+ * Called when the service cannot expire an external payment session that was
1370
+ * created for a message batch that did not commit.
1371
+ */
1372
+ onPaymentCompensationFailure?: (event: PaymentCompensationFailureEvent) => void | Promise<void>;
431
1373
  adminRoles?: string[];
432
1374
  registry?: TemplateRegistry;
433
1375
  /**
@@ -439,7 +1381,40 @@ interface MessageServiceOptions {
439
1381
  * Hard upper bound for `listMessages` limit to prevent abuse. Defaults to 100.
440
1382
  */
441
1383
  maxListLimit?: number;
1384
+ /**
1385
+ * How long a pending idempotent create reservation lease remains live before
1386
+ * another caller may atomically take it over. Defaults to 30000 ms.
1387
+ */
1388
+ clientRequestLeaseMs?: number;
1389
+ /**
1390
+ * Maximum time a duplicate idempotent create waits for completion or stale
1391
+ * lease takeover before raising `ClientRequestPendingError`. Defaults to 5000 ms.
1392
+ */
1393
+ clientRequestWaitMs?: number;
1394
+ /** Poll interval while waiting for an idempotent create outcome. Defaults to 200 ms. */
1395
+ clientRequestPollMs?: number;
1396
+ /** Test hook for deterministic waiting; production uses `setTimeout`. */
1397
+ clientRequestDelay?: (ms: number) => Promise<void>;
442
1398
  }
1399
+ interface MessageServiceModelNames {
1400
+ active: string;
1401
+ archive: string;
1402
+ request: string;
1403
+ user: string;
1404
+ }
1405
+ interface PaymentCompensationFailureEvent {
1406
+ operation: 'expire';
1407
+ sessionId: string;
1408
+ error: unknown;
1409
+ originalError: unknown;
1410
+ clientRequestId?: string;
1411
+ clientRequestOwnerId?: string;
1412
+ templateCd?: string;
1413
+ }
1414
+ type HydratedModelSource = {
1415
+ constructor: unknown;
1416
+ };
1417
+ type MessageModelRole = keyof MessageServiceModelNames;
443
1418
  /**
444
1419
  * The `templateCd` used for generic notifications created via
445
1420
  * `createNotification`. These messages have no actions, so
@@ -447,20 +1422,88 @@ interface MessageServiceOptions {
447
1422
  */
448
1423
  declare const GENERIC_NOTIFICATION_TEMPLATE_CD = "__generic-notification__";
449
1424
  declare class MessageNotFoundError extends Error {
1425
+ static [Symbol.hasInstance](value: unknown): boolean;
450
1426
  constructor(messageId: string);
451
1427
  }
452
1428
  declare class MessageArchivedError extends Error {
1429
+ static [Symbol.hasInstance](value: unknown): boolean;
453
1430
  constructor(messageId: string);
454
1431
  }
455
1432
  declare class TemplateNotFoundError extends Error {
1433
+ static [Symbol.hasInstance](value: unknown): boolean;
456
1434
  constructor(templateCd: string);
457
1435
  }
458
1436
  declare class ActionNotFoundError extends Error {
1437
+ static [Symbol.hasInstance](value: unknown): boolean;
459
1438
  constructor(templateCd: string, actionCd: string);
460
1439
  }
461
1440
  declare class ActionNotAllowedError extends Error {
1441
+ static [Symbol.hasInstance](value: unknown): boolean;
462
1442
  constructor();
463
1443
  }
1444
+ declare class InvalidMessageUserError extends Error {
1445
+ static [Symbol.hasInstance](value: unknown): boolean;
1446
+ constructor(message?: string);
1447
+ }
1448
+ declare class ActionTemplateMismatchError extends Error {
1449
+ static [Symbol.hasInstance](value: unknown): boolean;
1450
+ constructor(expectedTemplateCd: string, receivedTemplateCd: string);
1451
+ }
1452
+ declare class ActionConflictError extends Error {
1453
+ static [Symbol.hasInstance](value: unknown): boolean;
1454
+ constructor(messageId: string);
1455
+ }
1456
+ declare class ActionRetryableError extends Error {
1457
+ static [Symbol.hasInstance](value: unknown): boolean;
1458
+ actionAttemptId: string;
1459
+ constructor(messageId: string, actionAttemptId: string, cause?: unknown);
1460
+ }
1461
+ declare class ActionNotificationPendingError extends Error {
1462
+ static [Symbol.hasInstance](value: unknown): boolean;
1463
+ actionAttemptId: string;
1464
+ result: unknown;
1465
+ constructor(messageId: string, actionAttemptId: string, result: unknown, cause?: unknown);
1466
+ }
1467
+ declare class InvalidClientRequestIdError extends Error {
1468
+ static [Symbol.hasInstance](value: unknown): boolean;
1469
+ constructor(message: string);
1470
+ }
1471
+ declare class InvalidPaginationValueError extends Error {
1472
+ static [Symbol.hasInstance](value: unknown): boolean;
1473
+ constructor(message: string);
1474
+ }
1475
+ declare class ClientRequestPendingError extends Error {
1476
+ static [Symbol.hasInstance](value: unknown): boolean;
1477
+ constructor(clientRequestId: string);
1478
+ }
1479
+ declare class ClientRequestFailedError extends Error {
1480
+ static [Symbol.hasInstance](value: unknown): boolean;
1481
+ constructor(clientRequestId: string, reason?: string | null);
1482
+ }
1483
+ declare class ClientRequestInconsistentStateError extends Error {
1484
+ static [Symbol.hasInstance](value: unknown): boolean;
1485
+ constructor(clientRequestId: string, message: string);
1486
+ }
1487
+ declare class MessageTransactionRequiredError extends Error {
1488
+ static [Symbol.hasInstance](value: unknown): boolean;
1489
+ constructor(cause?: unknown);
1490
+ }
1491
+ declare class MessageModelResolutionError extends Error {
1492
+ static [Symbol.hasInstance](value: unknown): boolean;
1493
+ role: MessageModelRole;
1494
+ modelName: string;
1495
+ connectionName: string;
1496
+ constructor(role: MessageModelRole, modelName: string, connectionName: string, cause?: unknown);
1497
+ }
1498
+ declare class PaymentSessionCompensationError extends Error {
1499
+ static [Symbol.hasInstance](value: unknown): boolean;
1500
+ sessionId: string;
1501
+ operation: 'expire';
1502
+ compensationError: unknown;
1503
+ originalError: unknown;
1504
+ hookError?: unknown;
1505
+ constructor(sessionId: string, operation: 'expire', compensationError: unknown, originalError: unknown, hookError?: unknown);
1506
+ }
464
1507
  /**
465
1508
  * Core message service for creating messages, getting actions, and handling actions.
466
1509
  *
@@ -468,14 +1511,22 @@ declare class ActionNotAllowedError extends Error {
468
1511
  * const service = new MessageService({ getModel: mongoose.model.bind(mongoose) });
469
1512
  */
470
1513
  declare class MessageService {
471
- private getModel;
1514
+ private getModel?;
1515
+ private connection?;
1516
+ private modelNames;
472
1517
  private paymentProvider;
473
1518
  private expirePaymentSession?;
474
1519
  private refundPaymentSession?;
1520
+ private onPaymentCompensationFailure?;
475
1521
  private adminRoles;
476
1522
  private registry;
477
1523
  private defaultListLimit;
478
1524
  private maxListLimit;
1525
+ private clientRequestLeaseMs;
1526
+ private clientRequestWaitMs;
1527
+ private clientRequestPollMs;
1528
+ private clientRequestDelay;
1529
+ private actionLeaseMs;
479
1530
  constructor(options: MessageServiceOptions);
480
1531
  /**
481
1532
  * Find a message by id, falling back to the archive. Returns null if
@@ -499,11 +1550,11 @@ declare class MessageService {
499
1550
  payerUser?: MessageUser;
500
1551
  req?: unknown;
501
1552
  /**
502
- * Optional client-supplied request id. If a message with this
503
- * `clientRequestId` already exists, that message is returned instead
504
- * of creating a duplicate. Useful for double-submit protection.
1553
+ * Optional client-supplied request id. The service trims surrounding
1554
+ * whitespace, preserves case, and requires a non-empty value up to 128
1555
+ * characters. Replays are scoped to the requester identity and template.
505
1556
  */
506
- clientRequestId?: string;
1557
+ clientRequestId?: unknown;
507
1558
  }): Promise<IMessage[]>;
508
1559
  private createMessageWithReservation;
509
1560
  private createPreparedMessageBatch;
@@ -522,7 +1573,7 @@ declare class MessageService {
522
1573
  short?: string;
523
1574
  };
524
1575
  documents?: mongoose.Types.ObjectId[];
525
- }): Promise<IMessage>;
1576
+ }, sourceDocument?: HydratedModelSource | null): Promise<IMessage>;
526
1577
  /**
527
1578
  * Build a Mongoose filter for messages visible to the given user.
528
1579
  * Exposed so callers can use the same visibility rules for custom
@@ -561,16 +1612,38 @@ declare class MessageService {
561
1612
  permissions?: Record<string, boolean>;
562
1613
  req?: unknown;
563
1614
  }): Promise<unknown>;
1615
+ private resolveModel;
1616
+ private getTemplateModelResolver;
1617
+ private getDocumentConnection;
1618
+ private getModelConnection;
1619
+ private describeModelSource;
564
1620
  private persistItem;
1621
+ private buildMessageDocument;
1622
+ private persistPreparedBatchTransaction;
1623
+ private compensatePaymentSessions;
1624
+ private compensatePaymentSession;
565
1625
  private buildActionContext;
1626
+ private claimAction;
1627
+ private markActionRetryable;
1628
+ private archiveClaimedMessage;
1629
+ private markActionNotificationState;
566
1630
  private runSenderNotification;
567
- private findByClientRequestId;
568
- private waitForClientRequestOutcome;
1631
+ private normalizeClientRequestId;
1632
+ private validatePositiveIntegerOption;
1633
+ private normalizeListLimit;
1634
+ private normalizeListSkip;
1635
+ private buildClientRequestScope;
1636
+ private requireUserId;
1637
+ private findByClientRequestScope;
1638
+ private findCompletedClientRequestReplay;
1639
+ private acquireClientRequestStart;
1640
+ private tryAcquireClientRequestLease;
569
1641
  private tryCreateClientRequestReservation;
1642
+ private tryTakeOverStaleClientRequestReservation;
570
1643
  private findClientRequestReservation;
571
- private completeClientRequestReservation;
572
- private releaseClientRequestReservation;
1644
+ private failClientRequestReservation;
573
1645
  private isDuplicateKeyError;
1646
+ private isTransactionSupportError;
574
1647
  private delay;
575
1648
  private isArchivedMessage;
576
1649
  private applyPopulate;
@@ -582,6 +1655,8 @@ interface MessageRoutesOptions {
582
1655
  getModel: (name: string) => mongoose.Model<unknown>;
583
1656
  /** Payment provider (optional — enables payment session handling) */
584
1657
  paymentProvider?: PaymentProvider | null;
1658
+ /** Optional hook called when expiring an uncommitted payment session fails. */
1659
+ onPaymentCompensationFailure?: MessageServiceOptions['onPaymentCompensationFailure'];
585
1660
  /** Admin roles that receive messages when no toUser/toRoles specified */
586
1661
  adminRoles?: string[];
587
1662
  /**
@@ -592,7 +1667,11 @@ interface MessageRoutesOptions {
592
1667
  registry?: TemplateRegistry;
593
1668
  /** Custom auth middleware applied to all routes */
594
1669
  authMiddleware?: ((req: Request, res: Response, next: NextFunction) => void)[];
595
- /** Extract user from request (default: req._user || req.user) */
1670
+ /**
1671
+ * Extract user from request (default: req._user || req.user). All routes
1672
+ * require this extractor to return a user with a non-empty `_id` before any
1673
+ * service, template, payment, model, or action side effect runs.
1674
+ */
596
1675
  getUser?: (req: Request) => MessageUser | undefined;
597
1676
  /** Extract permissions from request (default: req._permissions || {}) */
598
1677
  getPermissions?: (req: Request) => Record<string, boolean>;
@@ -611,12 +1690,15 @@ interface MessageRoutesOptions {
611
1690
  * Routes:
612
1691
  * POST /new/:templateCd — create message from template
613
1692
  * GET /:id/actions/:usertype — get available actions for a message
614
- * GET /:id/action/:actionCd — execute an action (GET)
615
1693
  * POST /:id/action/:actionCd — execute an action (POST)
1694
+ *
1695
+ * All routes require a resolved user with a non-empty `_id`. Route parameters
1696
+ * are validated before service/model/template lookup, and mutating actions are
1697
+ * intentionally POST-only.
616
1698
  */
617
1699
  declare function createMessageRoutes(options: MessageRoutesOptions): {
618
1700
  router: JsonRouter;
619
1701
  service: MessageService;
620
1702
  };
621
1703
 
622
- export { type ActionConfirmation, type ActionContext, ActionNotAllowedError, ActionNotFoundError, BaseMessageFields, type EmailNotifier, type EmailProvider, GENERIC_NOTIFICATION_TEMPLATE_CD, type IBaseMessage, type IMessage, type IMessageArchive, type IMessageContent, type IMessageMethods, type InterpolatedAction, type InterpolatedContent, type InterpolationResult, MESSAGE_ARCHIVE_MODEL_NAME, MESSAGE_MODEL_NAME, MESSAGE_REQUEST_MODEL_NAME, type MessageAction, MessageArchiveSchema, MessageArchivedError, MessageContentSchema, MessageNotFoundError, MessageRequestSchema, type MessageRoutesOptions, MessageSchema, type MessageSchemaConfig, MessageService, type MessageServiceOptions, type MessageTemplate, type MessageType, type MessageUser, NoopEmailProvider, NoopPaymentProvider, type PaymentProvider, type PrepareContext, type PrepareResult, type SenderNotificationContent, TemplateNotFoundError, TemplateRegistry, type UiTemplate, type Usertype, buildMessageArchiveSchema, buildMessageRequestSchema, buildMessageSchema, createMessageRoutes, defaultRegistry, filterActions, includesAction, interpolateTemplate, isActionAllowed };
1704
+ export { type ActionConfirmation, ActionConflictError, type ActionContext, type ActionLifecycleState, ActionNotAllowedError, ActionNotFoundError, ActionNotificationPendingError, type ActionNotificationState, ActionRetryableError, ActionTemplateMismatchError, BaseMessageFields, ClientRequestFailedError, ClientRequestInconsistentStateError, ClientRequestPendingError, type EmailDeliveryFailureEvent, type EmailDeliveryFailureStage, type EmailNotifier, type EmailProvider, GENERIC_NOTIFICATION_TEMPLATE_CD, type IBaseMessage, type IMessage, type IMessageArchive, type IMessageContent, type IMessageMethods, type InterpolatedAction, type InterpolatedContent, type InterpolationResult, InvalidClientRequestIdError, InvalidMessageUserError, InvalidPaginationValueError, MESSAGE_ARCHIVE_MODEL_NAME, MESSAGE_MODEL_NAME, MESSAGE_REQUEST_MODEL_NAME, type MessageAction, MessageArchiveSchema, MessageArchivedError, MessageContentSchema, MessageModelResolutionError, MessageNotFoundError, MessageRequestSchema, type MessageRoutesOptions, MessageSchema, type MessageSchemaConfig, MessageService, type MessageServiceModelNames, type MessageServiceOptions, type MessageTemplate, MessageTransactionRequiredError, type MessageType, type MessageUser, NoopEmailProvider, NoopPaymentProvider, type PaymentCompensationFailureEvent, type PaymentProvider, PaymentSessionCompensationError, type PrepareContext, type PrepareResult, type SenderNotificationContent, TemplateNotFoundError, TemplateRegistry, TemplateRegistryValidationError, type UiTemplate, type UserId, type Usertype, buildMessageArchiveSchema, buildMessageRequestSchema, buildMessageSchema, createMessageRoutes, defaultRegistry, filterActions, includesAction, interpolateTemplate, isActionAllowed };