@web-ts-toolkit/message-service 0.52.0 → 0.53.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 +833 -11
  2. package/index.d.mts +270 -943
  3. package/index.d.ts +270 -943
  4. package/index.js +174 -43
  5. package/index.mjs +172 -43
  6. package/package.json +3 -3
package/index.d.mts CHANGED
@@ -38,13 +38,30 @@ interface PrepareResult {
38
38
  fromUser?: UserId;
39
39
  toUser?: UserId;
40
40
  toRoles?: string[];
41
+ /**
42
+ * Per-item attachment ObjectIds; `[]` intentionally clears attachments.
43
+ * Omitted/undefined uses the original `PrepareContext.payload.documents`
44
+ * (or `[]` when absent), not this result's `payload.documents`.
45
+ * The selected array is copied per item without mutating either input.
46
+ */
47
+ documents?: mongoose.Types.ObjectId[];
41
48
  payload?: Record<string, unknown>;
42
49
  display?: Record<string, unknown>;
50
+ /**
51
+ * Nonempty code overrides the template and requires a payment session even
52
+ * without recipients. `''`/omission inherits `MessageTemplate.paymentCd`;
53
+ * codes are not trimmed. Absent/null providers throw `PaymentProviderRequiredError`.
54
+ */
43
55
  paymentCd?: string;
44
56
  priceArgs?: Record<string, unknown>;
45
57
  }
46
58
  interface ActionContext {
47
59
  message: IMessage | IMessageArchive;
60
+ /**
61
+ * Validated snapshot of `_id`, `id`, `roles`, and `displayName`, including
62
+ * getter-backed values. `_id` is the normalized string identity; roles are
63
+ * copied. Extra authentication-document fields are excluded; `req` is original.
64
+ */
48
65
  user: MessageUser;
49
66
  /**
50
67
  * Stable, persisted idempotency key for this action attempt. Handlers that
@@ -53,6 +70,14 @@ interface ActionContext {
53
70
  * exactly-once.
54
71
  */
55
72
  actionAttemptId?: string;
73
+ /**
74
+ * Submitted command, or the current action's synchronous `parseInput` output.
75
+ * HTTP supplies `req.body`; direct calls supply `data.input` explicitly (never
76
+ * inferred from `req`). Separate from action metadata and `message.payload`.
77
+ * Unvalidated/pass-through when no parser is configured. Hosts own durable
78
+ * command/result binding and deduplication by `actionAttemptId`.
79
+ */
80
+ input?: unknown;
56
81
  getModel: (name: string) => mongoose.Model<unknown>;
57
82
  expireSession?: (sessionId: string) => Promise<void>;
58
83
  refundPayment?: (sessionId: string) => Promise<void>;
@@ -81,7 +106,22 @@ interface MessageAction {
81
106
  permission?: string;
82
107
  condition?: (message: IMessage) => boolean;
83
108
  confirmation?: ActionConfirmation;
109
+ /** Presentation metadata, not submitted input or an enforced command schema. */
84
110
  payload?: Record<string, unknown>;
111
+ /**
112
+ * Optional synchronous, deterministic, effect-free command parser. Runs once
113
+ * per acquisition after authoritative claimed authorization, before the handler.
114
+ * Treat raw input as read-only; return a normalized allowlisted command for
115
+ * `ActionContext.input`, or throw `ActionInputValidationError` (HTTP 400).
116
+ * Async parsers/thenables are unsupported server errors (HTTP 500); unexpected
117
+ * failures retain their cause and are sanitized over HTTP. No parser runs for
118
+ * unauthorized callers, listings, or archived outcomes.
119
+ *
120
+ * Pre-handler failure releases a fresh claim to active; retries/takeovers retain
121
+ * their stable attempt/action as retryable. Release is owner-fenced. This hook
122
+ * must not reserve commands or perform business effects; do that in the handler.
123
+ */
124
+ parseInput?: (input: unknown) => unknown;
85
125
  senderNotification?: string | ((ctx: ActionContext) => Promise<string | SenderNotificationContent>);
86
126
  runHandler: (ctx: ActionContext) => Promise<unknown>;
87
127
  }
@@ -104,6 +144,12 @@ interface MessageTemplate {
104
144
  short: string;
105
145
  };
106
146
  uiTemplate: UiTemplate;
147
+ /**
148
+ * Default code for fresh prepared items: `item.paymentCd || template.paymentCd || ''`.
149
+ * A nonempty effective code requires a payment session regardless of recipients;
150
+ * absent/null providers throw `PaymentProviderRequiredError`. Empty item codes
151
+ * cannot clear this default. Completed replays never re-evaluate payment.
152
+ */
107
153
  paymentCd?: string;
108
154
  prepareMessage: (ctx: PrepareContext) => Promise<PrepareResult | PrepareResult[] | null>;
109
155
  actions: MessageAction[];
@@ -119,7 +165,7 @@ type RegisteredUiTemplate = string | Readonly<{
119
165
  /**
120
166
  * Readonly action view matching the registry freeze depth: the action object,
121
167
  * its `confirmation`, and its `payload` are each shallow-frozen. Function
122
- * fields (`condition`, `runHandler`, `senderNotification`) keep their original
168
+ * fields (`condition`, `parseInput`, `runHandler`, `senderNotification`) keep their original
123
169
  * identity and remain callable.
124
170
  */
125
171
  type RegisteredMessageAction = Readonly<Omit<MessageAction, 'confirmation' | 'payload'>> & {
@@ -254,24 +300,39 @@ interface IMessageContent {
254
300
  * still allowing arbitrary strings.
255
301
  */
256
302
  type MessageType = 'notification' | 'request' | 'reminder' | 'approval' | (string & {});
303
+ /**
304
+ * Native ObjectId or case-sensitive opaque string. User-facing IDs are trimmed;
305
+ * template party storage and archive ownership trim strings without stringifying
306
+ * native ObjectIds. Bundled party/archivedBy paths default to ObjectId: arbitrary
307
+ * strings require the README's active AND archive String-schema overrides.
308
+ * Stored ObjectIds match 24-hex principals in either case; stored strings compare
309
+ * exactly after trimming (even hex-looking strings). Request scopes always retain
310
+ * the existing trimmed, case-sensitive string keys; ObjectIds use lowercase hex.
311
+ */
257
312
  type UserId = mongoose.Types.ObjectId | string;
258
313
  type ActionLifecycleState = 'active' | 'processing' | 'retryable';
259
314
  type ActionNotificationState = 'none' | 'pending' | 'sent' | 'failed';
260
315
  /**
261
316
  * Minimal user shape accepted by MessageService methods.
317
+ * Plain objects, prototype getters, and hydrated Mongoose documents are
318
+ * supported. User-facing operations reject malformed `roles` with
319
+ * `InvalidMessageUserError`; omitted/undefined roles and `[]` are valid.
320
+ * Action handlers receive only these fields (with a copied roles array),
321
+ * not arbitrary authentication-document properties. The caller is not mutated.
262
322
  * `displayName` is optional but templates that interpolate `{{displayName}}`
263
323
  * will fall back to an empty string if it is absent.
264
324
  */
265
325
  interface MessageUser {
266
326
  _id: UserId;
267
327
  id?: string;
328
+ /** Exact, case-sensitive string roles; no coercion or substring matching. */
268
329
  roles?: string[];
269
330
  displayName?: string;
270
331
  }
271
332
  interface IMessageRelationshipMethods {
272
- /** Match a string/ObjectId or populated party's `_id`; missing references never match. */
333
+ /** Stored ObjectIds accept either hex case; String parties match exact trimmed IDs, including populated `_id`s. Invalid roles/references never match. */
273
334
  isSender(user: MessageUser): boolean;
274
- /** Match the recipient identity (including populated `_id`) or an explicit recipient role. */
335
+ /** Same stored-type ID policy as isSender, or an exact role; malformed user roles fail closed. */
275
336
  isReceiver(user: MessageUser): boolean;
276
337
  }
277
338
  interface IMessageMethods extends IMessageRelationshipMethods {
@@ -288,6 +349,8 @@ interface IMessageMethods extends IMessageRelationshipMethods {
288
349
  * `MessageArchivedError` (archive copy exists) or `MessageNotFoundError`.
289
350
  * Deployments without transaction support throw
290
351
  * `MessageTransactionRequiredError` before writing anything.
352
+ * String `archivedBy` is trimmed; native ObjectIds are preserved for schema
353
+ * casting. Opaque IDs require a String archive `archivedBy` path (see README).
291
354
  * Confirmed commit resolves even if session cleanup rejects; configure
292
355
  * `buildMessageSchema({ onTransactionCleanupFailure })` for diagnostics.
293
356
  * Observer failures cannot change the outcome. An attached `$session()` is
@@ -332,9 +395,11 @@ interface IBaseMessage {
332
395
  }
333
396
  type MongooseQueryHelpers = Record<string, unknown>;
334
397
  type IMessage = mongoose.Document<unknown, MongooseQueryHelpers, IMessageMethods> & IBaseMessage & IMessageMethods & {
398
+ _id: mongoose.Types.ObjectId;
335
399
  __v?: number;
336
400
  };
337
401
  type IMessageArchive = mongoose.Document<unknown, MongooseQueryHelpers, IMessageRelationshipMethods> & IBaseMessage & {
402
+ _id: mongoose.Types.ObjectId;
338
403
  actionCd: string;
339
404
  archivedBy: UserId;
340
405
  archivedAt: Date;
@@ -350,39 +415,7 @@ type IMessageArchive = mongoose.Document<unknown, MongooseQueryHelpers, IMessage
350
415
  declare const MESSAGE_MODEL_NAME = "Message";
351
416
  declare const MESSAGE_ARCHIVE_MODEL_NAME = "MessageArchive";
352
417
  declare const MESSAGE_REQUEST_MODEL_NAME = "MessageRequest";
353
- declare const MessageContentSchema: mongoose.Schema<any, mongoose.Model<any, any, any, any, any, any, any>, {}, {}, {}, {}, {
354
- _id: false;
355
- }, {
356
- title: string;
357
- long: string;
358
- short: string;
359
- }, mongoose.Document<unknown, {}, {
360
- title: string;
361
- long: string;
362
- short: string;
363
- }, {
364
- id: string;
365
- }, Omit<mongoose.DefaultSchemaOptions, "_id"> & {
366
- _id: false;
367
- }> & Omit<{
368
- title: string;
369
- long: string;
370
- short: string;
371
- } & {
372
- _id: mongoose.Types.ObjectId;
373
- } & {
374
- __v: number;
375
- }, "id"> & mongoose.HydratedDocumentOverrides<{
376
- id: string;
377
- }>, unknown, {
378
- title: string;
379
- long: string;
380
- short: string;
381
- } & {
382
- _id: mongoose.Types.ObjectId;
383
- } & {
384
- __v: number;
385
- }>;
418
+ declare const MessageContentSchema: mongoose.Schema<IMessageContent>;
386
419
  /**
387
420
  * Base message fields shared between Message and MessageArchive.
388
421
  *
@@ -394,7 +427,40 @@ declare const MessageContentSchema: mongoose.Schema<any, mongoose.Model<any, any
394
427
  */
395
428
  declare const BaseMessageFields: Record<string, mongoose.SchemaTypeOptions<unknown>>;
396
429
 
430
+ /**
431
+ * Best-effort delivery callback: receives the resolved address unchanged, the
432
+ * trimmed receiver title, and the longer receiver body (short wins ties).
433
+ * Throws/rejections report stage `notifier` without rejecting the saved message.
434
+ * Bind provider methods when they depend on `this`.
435
+ */
397
436
  type EmailNotifier = (email: string, title: string, message: string) => Promise<void> | void;
437
+ /** Host context for address/preference lookup after a new, session-free message save. */
438
+ interface EmailRecipientResolverContext {
439
+ /** Direct recipient ID after schema casting: ObjectId by default, or an opaque string with String party paths. */
440
+ readonly recipientId: UserId;
441
+ /** The hydrated document's owning connection, not the schema's eager-check connection or global Mongoose. */
442
+ readonly connection: mongoose.Connection;
443
+ /**
444
+ * Saved message fields, including templateCd, payload and display. A shallow
445
+ * read-only view of the hydrated document, not a cloned/frozen snapshot; do not
446
+ * mutate it or its nested values. No document methods are exposed by this type.
447
+ */
448
+ readonly message: Readonly<IBaseMessage> & {
449
+ readonly _id: mongoose.Types.ObjectId;
450
+ };
451
+ }
452
+ /**
453
+ * Resolve one recipient address, synchronously or asynchronously. Return null,
454
+ * undefined or an empty string to skip delivery without a failure event; no
455
+ * default lookup is attempted. Addresses are forwarded unchanged to the notifier;
456
+ * the host owns address validation, normalization and notification preferences.
457
+ * Throws/rejections report stage `recipientLookup` without rejecting the saved
458
+ * message. Awaited as part of the save hook; keep external lookups bounded.
459
+ * Not called for updates, session-bound saves, disabled email, missing direct
460
+ * recipients, or blank/excluded rendered titles. It does not enable role fan-out.
461
+ * Bind methods to their host instance when they depend on `this`.
462
+ */
463
+ type EmailRecipientResolver = (context: EmailRecipientResolverContext) => string | null | undefined | Promise<string | null | undefined>;
398
464
  type EmailDeliveryFailureStage = 'recipientLookup' | 'notifier';
399
465
  interface EmailDeliveryFailureEvent {
400
466
  stage: EmailDeliveryFailureStage;
@@ -409,13 +475,24 @@ interface MessageSchemaConfig {
409
475
  * send a best-effort email notification to the recipient. Pass `null` (the
410
476
  * default) to disable.
411
477
  *
412
- * When `null`, no save hooks are registered at all. When set, the schema
478
+ * When `null`, no email save hooks are registered. When set, the schema
413
479
  * registers a pre-save state capture plus a connection-local post-save
414
- * hook: the post-save hook resolves user/archive models on the hydrated
415
- * document's owning connection and skips session-bound writes (Mongoose
416
- * save hooks run before the surrounding transaction commits).
480
+ * hook: recipient lookup uses the hydrated document's owning connection and
481
+ * skips session-bound writes (Mongoose save hooks run before the surrounding
482
+ * transaction commits). Bind provider methods to their instance when needed.
417
483
  */
418
484
  emailNotifier?: EmailNotifier | null;
485
+ /**
486
+ * Optional address/preference lookup for nested fields or external directories.
487
+ * Replaces the default connection-local `User.findById(toUser).select('email').lean()`
488
+ * adapter; no local user model or eager user-model check is needed when set.
489
+ * Called only with email enabled, for new session-free saves with a direct
490
+ * recipient and nonempty, nonexcluded rendered receiver title. Updates never
491
+ * resend. Return null/undefined/'' to skip without default fallback; failures use
492
+ * `onEmailDeliveryFailure`. Addresses are passed through unchanged. Bind host
493
+ * methods that depend on `this`; keep awaited external lookup work bounded.
494
+ */
495
+ emailRecipientResolver?: EmailRecipientResolver;
419
496
  /**
420
497
  * Called when recipient lookup or notifier delivery fails. The message save
421
498
  * has already succeeded and is not rolled back. If this hook throws, that
@@ -430,16 +507,16 @@ interface MessageSchemaConfig {
430
507
  */
431
508
  emailNotificationExclusions?: string[];
432
509
  /**
433
- * Name of the Mongoose model that holds the recipient user records.
510
+ * Name of the Mongoose model used by the default recipient-address adapter.
434
511
  * Defaults to `'User'`. The post-save email hook resolves it on the
435
512
  * message document's owning connection
436
513
  * (`document.constructor.db.model(name)`) to look up the recipient's email
437
514
  * address, so connection-local apps must register the user model on the
438
515
  * same connection as the message models.
439
516
  *
440
- * The model MUST be registered before the first save when `emailNotifier`
441
- * is set — `buildMessageSchema` checks this eagerly to fail fast (pass
442
- * `connection` when configuring connection-local schemas).
517
+ * The model MUST be registered before `buildMessageSchema()` when `emailNotifier`
518
+ * is set without `emailRecipientResolver` — checked eagerly to fail fast (pass
519
+ * `connection` for connection-local schemas). Ignored by custom resolvers.
443
520
  */
444
521
  userModelName?: string;
445
522
  /**
@@ -466,11 +543,15 @@ type MessageModel = mongoose.Model<IBaseMessage, object, IMessageMethods>;
466
543
  /**
467
544
  * Build a fresh Message schema with the given configuration.
468
545
  * Prefer this over the default `MessageSchema` export when you need
469
- * an email notifier, exclusions, cleanup diagnostics, or custom model names.
546
+ * an email notifier/recipient resolver, exclusions, cleanup diagnostics, or custom model names.
547
+ * For opaque string user IDs, use `schema.add()` before compiling the model to
548
+ * replace `fromUser`/`toUser` with trimmed String paths on both active and archive
549
+ * schemas; also replace archive `archivedBy`. Message `_id` stays ObjectId.
550
+ * The README contains the complete root-import recipe and migration policy.
470
551
  *
471
- * Note: when `emailNotifier` is set, the configured `userModelName` MUST
472
- * be registered with Mongoose before calling this function. The schema
473
- * factory checks this eagerly to fail fast.
552
+ * With `emailNotifier` and no `emailRecipientResolver`, the configured `userModelName`
553
+ * MUST be registered on `connection` (global Mongoose by default) before calling
554
+ * this function. Custom resolvers replace that adapter and need no User model.
474
555
  */
475
556
  declare function buildMessageSchema(config?: MessageSchemaConfig): mongoose.Schema<IBaseMessage, MessageModel, IMessageMethods>;
476
557
  /**
@@ -478,241 +559,7 @@ declare function buildMessageSchema(config?: MessageSchemaConfig): mongoose.Sche
478
559
  * Provided for backwards compatibility and simple use cases.
479
560
  * Use `buildMessageSchema(config)` when you need custom behavior.
480
561
  */
481
- declare const MessageSchema: mongoose.Schema<IBaseMessage, MessageModel, IMessageMethods, {}, {}, {}, mongoose.DefaultSchemaOptions, IBaseMessage, mongoose.Document<unknown, {}, IBaseMessage, {
482
- id: string;
483
- }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
484
- _id: mongoose.Types.ObjectId;
485
- } & {
486
- __v: number;
487
- }, "id" | keyof IMessageMethods> & mongoose.HydratedDocumentOverrides<{
488
- id: string;
489
- } & IMessageMethods>, {
490
- templateCd?: mongoose.SchemaDefinitionProperty<string, IBaseMessage, mongoose.Document<unknown, {}, IBaseMessage, {
491
- id: string;
492
- }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
493
- _id: mongoose.Types.ObjectId;
494
- } & {
495
- __v: number;
496
- }, "id" | keyof IMessageMethods> & mongoose.HydratedDocumentOverrides<{
497
- id: string;
498
- } & IMessageMethods>> | undefined;
499
- type?: mongoose.SchemaDefinitionProperty<MessageType, IBaseMessage, mongoose.Document<unknown, {}, IBaseMessage, {
500
- id: string;
501
- }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
502
- _id: mongoose.Types.ObjectId;
503
- } & {
504
- __v: number;
505
- }, "id" | keyof IMessageMethods> & mongoose.HydratedDocumentOverrides<{
506
- id: string;
507
- } & IMessageMethods>> | undefined;
508
- fromUser?: mongoose.SchemaDefinitionProperty<UserId | null, IBaseMessage, mongoose.Document<unknown, {}, IBaseMessage, {
509
- id: string;
510
- }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
511
- _id: mongoose.Types.ObjectId;
512
- } & {
513
- __v: number;
514
- }, "id" | keyof IMessageMethods> & mongoose.HydratedDocumentOverrides<{
515
- id: string;
516
- } & IMessageMethods>> | undefined;
517
- toUser?: mongoose.SchemaDefinitionProperty<UserId | null, IBaseMessage, mongoose.Document<unknown, {}, IBaseMessage, {
518
- id: string;
519
- }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
520
- _id: mongoose.Types.ObjectId;
521
- } & {
522
- __v: number;
523
- }, "id" | keyof IMessageMethods> & mongoose.HydratedDocumentOverrides<{
524
- id: string;
525
- } & IMessageMethods>> | undefined;
526
- toRoles?: mongoose.SchemaDefinitionProperty<string[], IBaseMessage, mongoose.Document<unknown, {}, IBaseMessage, {
527
- id: string;
528
- }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
529
- _id: mongoose.Types.ObjectId;
530
- } & {
531
- __v: number;
532
- }, "id" | keyof IMessageMethods> & mongoose.HydratedDocumentOverrides<{
533
- id: string;
534
- } & IMessageMethods>> | undefined;
535
- senderContent?: mongoose.SchemaDefinitionProperty<IMessageContent, IBaseMessage, mongoose.Document<unknown, {}, IBaseMessage, {
536
- id: string;
537
- }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
538
- _id: mongoose.Types.ObjectId;
539
- } & {
540
- __v: number;
541
- }, "id" | keyof IMessageMethods> & mongoose.HydratedDocumentOverrides<{
542
- id: string;
543
- } & IMessageMethods>> | undefined;
544
- receiverContent?: mongoose.SchemaDefinitionProperty<IMessageContent, IBaseMessage, mongoose.Document<unknown, {}, IBaseMessage, {
545
- id: string;
546
- }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
547
- _id: mongoose.Types.ObjectId;
548
- } & {
549
- __v: number;
550
- }, "id" | keyof IMessageMethods> & mongoose.HydratedDocumentOverrides<{
551
- id: string;
552
- } & IMessageMethods>> | undefined;
553
- documents?: mongoose.SchemaDefinitionProperty<mongoose.Types.ObjectId[], IBaseMessage, mongoose.Document<unknown, {}, IBaseMessage, {
554
- id: string;
555
- }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
556
- _id: mongoose.Types.ObjectId;
557
- } & {
558
- __v: number;
559
- }, "id" | keyof IMessageMethods> & mongoose.HydratedDocumentOverrides<{
560
- id: string;
561
- } & IMessageMethods>> | undefined;
562
- paymentSession?: mongoose.SchemaDefinitionProperty<string | null, IBaseMessage, mongoose.Document<unknown, {}, IBaseMessage, {
563
- id: string;
564
- }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
565
- _id: mongoose.Types.ObjectId;
566
- } & {
567
- __v: number;
568
- }, "id" | keyof IMessageMethods> & mongoose.HydratedDocumentOverrides<{
569
- id: string;
570
- } & IMessageMethods>> | undefined;
571
- paymentCd?: mongoose.SchemaDefinitionProperty<string, IBaseMessage, mongoose.Document<unknown, {}, IBaseMessage, {
572
- id: string;
573
- }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
574
- _id: mongoose.Types.ObjectId;
575
- } & {
576
- __v: number;
577
- }, "id" | keyof IMessageMethods> & mongoose.HydratedDocumentOverrides<{
578
- id: string;
579
- } & IMessageMethods>> | undefined;
580
- payload?: mongoose.SchemaDefinitionProperty<Record<string, unknown>, IBaseMessage, mongoose.Document<unknown, {}, IBaseMessage, {
581
- id: string;
582
- }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
583
- _id: mongoose.Types.ObjectId;
584
- } & {
585
- __v: number;
586
- }, "id" | keyof IMessageMethods> & mongoose.HydratedDocumentOverrides<{
587
- id: string;
588
- } & IMessageMethods>> | undefined;
589
- display?: mongoose.SchemaDefinitionProperty<Record<string, unknown>, IBaseMessage, mongoose.Document<unknown, {}, IBaseMessage, {
590
- id: string;
591
- }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
592
- _id: mongoose.Types.ObjectId;
593
- } & {
594
- __v: number;
595
- }, "id" | keyof IMessageMethods> & mongoose.HydratedDocumentOverrides<{
596
- id: string;
597
- } & IMessageMethods>> | undefined;
598
- clientRequestId?: mongoose.SchemaDefinitionProperty<string | null, IBaseMessage, mongoose.Document<unknown, {}, IBaseMessage, {
599
- id: string;
600
- }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
601
- _id: mongoose.Types.ObjectId;
602
- } & {
603
- __v: number;
604
- }, "id" | keyof IMessageMethods> & mongoose.HydratedDocumentOverrides<{
605
- id: string;
606
- } & IMessageMethods>> | undefined;
607
- clientRequestOwnerId?: mongoose.SchemaDefinitionProperty<string | null, IBaseMessage, mongoose.Document<unknown, {}, IBaseMessage, {
608
- id: string;
609
- }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
610
- _id: mongoose.Types.ObjectId;
611
- } & {
612
- __v: number;
613
- }, "id" | keyof IMessageMethods> & mongoose.HydratedDocumentOverrides<{
614
- id: string;
615
- } & IMessageMethods>> | undefined;
616
- clientRequestItemIndex?: mongoose.SchemaDefinitionProperty<number | null, IBaseMessage, mongoose.Document<unknown, {}, IBaseMessage, {
617
- id: string;
618
- }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
619
- _id: mongoose.Types.ObjectId;
620
- } & {
621
- __v: number;
622
- }, "id" | keyof IMessageMethods> & mongoose.HydratedDocumentOverrides<{
623
- id: string;
624
- } & IMessageMethods>> | undefined;
625
- actionState?: mongoose.SchemaDefinitionProperty<ActionLifecycleState, IBaseMessage, mongoose.Document<unknown, {}, IBaseMessage, {
626
- id: string;
627
- }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
628
- _id: mongoose.Types.ObjectId;
629
- } & {
630
- __v: number;
631
- }, "id" | keyof IMessageMethods> & mongoose.HydratedDocumentOverrides<{
632
- id: string;
633
- } & IMessageMethods>> | undefined;
634
- actionCd?: mongoose.SchemaDefinitionProperty<string | null, IBaseMessage, mongoose.Document<unknown, {}, IBaseMessage, {
635
- id: string;
636
- }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
637
- _id: mongoose.Types.ObjectId;
638
- } & {
639
- __v: number;
640
- }, "id" | keyof IMessageMethods> & mongoose.HydratedDocumentOverrides<{
641
- id: string;
642
- } & IMessageMethods>> | undefined;
643
- actionAttemptId?: mongoose.SchemaDefinitionProperty<string | null, IBaseMessage, mongoose.Document<unknown, {}, IBaseMessage, {
644
- id: string;
645
- }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
646
- _id: mongoose.Types.ObjectId;
647
- } & {
648
- __v: number;
649
- }, "id" | keyof IMessageMethods> & mongoose.HydratedDocumentOverrides<{
650
- id: string;
651
- } & IMessageMethods>> | undefined;
652
- actionOwnerToken?: mongoose.SchemaDefinitionProperty<string | null, IBaseMessage, mongoose.Document<unknown, {}, IBaseMessage, {
653
- id: string;
654
- }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
655
- _id: mongoose.Types.ObjectId;
656
- } & {
657
- __v: number;
658
- }, "id" | keyof IMessageMethods> & mongoose.HydratedDocumentOverrides<{
659
- id: string;
660
- } & IMessageMethods>> | undefined;
661
- actionClaimedBy?: mongoose.SchemaDefinitionProperty<string | null, IBaseMessage, mongoose.Document<unknown, {}, IBaseMessage, {
662
- id: string;
663
- }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
664
- _id: mongoose.Types.ObjectId;
665
- } & {
666
- __v: number;
667
- }, "id" | keyof IMessageMethods> & mongoose.HydratedDocumentOverrides<{
668
- id: string;
669
- } & IMessageMethods>> | undefined;
670
- actionClaimedAt?: mongoose.SchemaDefinitionProperty<Date | null, IBaseMessage, mongoose.Document<unknown, {}, IBaseMessage, {
671
- id: string;
672
- }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
673
- _id: mongoose.Types.ObjectId;
674
- } & {
675
- __v: number;
676
- }, "id" | keyof IMessageMethods> & mongoose.HydratedDocumentOverrides<{
677
- id: string;
678
- } & IMessageMethods>> | undefined;
679
- actionLeaseExpiresAt?: mongoose.SchemaDefinitionProperty<Date | null, IBaseMessage, mongoose.Document<unknown, {}, IBaseMessage, {
680
- id: string;
681
- }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
682
- _id: mongoose.Types.ObjectId;
683
- } & {
684
- __v: number;
685
- }, "id" | keyof IMessageMethods> & mongoose.HydratedDocumentOverrides<{
686
- id: string;
687
- } & IMessageMethods>> | undefined;
688
- actionFailureMessage?: mongoose.SchemaDefinitionProperty<string | null, IBaseMessage, mongoose.Document<unknown, {}, IBaseMessage, {
689
- id: string;
690
- }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
691
- _id: mongoose.Types.ObjectId;
692
- } & {
693
- __v: number;
694
- }, "id" | keyof IMessageMethods> & mongoose.HydratedDocumentOverrides<{
695
- id: string;
696
- } & IMessageMethods>> | undefined;
697
- createdAt?: mongoose.SchemaDefinitionProperty<Date, IBaseMessage, mongoose.Document<unknown, {}, IBaseMessage, {
698
- id: string;
699
- }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
700
- _id: mongoose.Types.ObjectId;
701
- } & {
702
- __v: number;
703
- }, "id" | keyof IMessageMethods> & mongoose.HydratedDocumentOverrides<{
704
- id: string;
705
- } & IMessageMethods>> | undefined;
706
- updatedAt?: mongoose.SchemaDefinitionProperty<Date, IBaseMessage, mongoose.Document<unknown, {}, IBaseMessage, {
707
- id: string;
708
- }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
709
- _id: mongoose.Types.ObjectId;
710
- } & {
711
- __v: number;
712
- }, "id" | keyof IMessageMethods> & mongoose.HydratedDocumentOverrides<{
713
- id: string;
714
- } & IMessageMethods>> | undefined;
715
- }, IBaseMessage>;
562
+ declare const MessageSchema: ReturnType<typeof buildMessageSchema>;
716
563
 
717
564
  type MessageArchiveSchemaFields = IBaseMessage & {
718
565
  actionCd: string;
@@ -728,540 +575,16 @@ type MessageArchiveModel = mongoose.Model<MessageArchiveSchemaFields, object, IM
728
575
  * Build a fresh MessageArchive schema.
729
576
  * Mirrors the default Message schema but adds archive-specific fields
730
577
  * (actionCd, archivedBy, archivedAt) and no pre-save email hook.
578
+ * Opaque string user IDs require String overrides for `fromUser`, `toUser`, AND
579
+ * `archivedBy` before model compilation (and matching active-party overrides).
580
+ * See the README recipe; message `_id` remains ObjectId.
731
581
  */
732
582
  declare function buildMessageArchiveSchema(): mongoose.Schema<MessageArchiveSchemaFields, MessageArchiveModel, IMessageRelationshipMethods>;
733
583
  /**
734
584
  * Default MessageArchive schema. Provided for backwards compatibility.
735
585
  * Use `buildMessageArchiveSchema()` if you need a fresh instance.
736
586
  */
737
- declare const MessageArchiveSchema: mongoose.Schema<MessageArchiveSchemaFields, MessageArchiveModel, IMessageRelationshipMethods, {}, {}, {}, mongoose.DefaultSchemaOptions, MessageArchiveSchemaFields, mongoose.Document<unknown, {}, MessageArchiveSchemaFields, {
738
- id: string;
739
- }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
740
- actionCd: string;
741
- archivedBy: unknown;
742
- archivedAt: Date;
743
- actionAttemptId: string | null;
744
- actionNotificationState: "none" | "pending" | "sent" | "failed";
745
- actionNotificationError: string | null;
746
- actionNotificationAttemptedAt: Date | null;
747
- } & {
748
- _id: mongoose.Types.ObjectId;
749
- } & {
750
- __v: number;
751
- }, "id" | keyof IMessageRelationshipMethods> & mongoose.HydratedDocumentOverrides<{
752
- id: string;
753
- } & IMessageRelationshipMethods>, {
754
- templateCd?: mongoose.SchemaDefinitionProperty<string, MessageArchiveSchemaFields, mongoose.Document<unknown, {}, MessageArchiveSchemaFields, {
755
- id: string;
756
- }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
757
- actionCd: string;
758
- archivedBy: unknown;
759
- archivedAt: Date;
760
- actionAttemptId: string | null;
761
- actionNotificationState: "none" | "pending" | "sent" | "failed";
762
- actionNotificationError: string | null;
763
- actionNotificationAttemptedAt: Date | null;
764
- } & {
765
- _id: mongoose.Types.ObjectId;
766
- } & {
767
- __v: number;
768
- }, "id" | keyof IMessageRelationshipMethods> & mongoose.HydratedDocumentOverrides<{
769
- id: string;
770
- } & IMessageRelationshipMethods>> | undefined;
771
- type?: mongoose.SchemaDefinitionProperty<MessageType, MessageArchiveSchemaFields, mongoose.Document<unknown, {}, MessageArchiveSchemaFields, {
772
- id: string;
773
- }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
774
- actionCd: string;
775
- archivedBy: unknown;
776
- archivedAt: Date;
777
- actionAttemptId: string | null;
778
- actionNotificationState: "none" | "pending" | "sent" | "failed";
779
- actionNotificationError: string | null;
780
- actionNotificationAttemptedAt: Date | null;
781
- } & {
782
- _id: mongoose.Types.ObjectId;
783
- } & {
784
- __v: number;
785
- }, "id" | keyof IMessageRelationshipMethods> & mongoose.HydratedDocumentOverrides<{
786
- id: string;
787
- } & IMessageRelationshipMethods>> | undefined;
788
- fromUser?: mongoose.SchemaDefinitionProperty<UserId | null, MessageArchiveSchemaFields, mongoose.Document<unknown, {}, MessageArchiveSchemaFields, {
789
- id: string;
790
- }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
791
- actionCd: string;
792
- archivedBy: unknown;
793
- archivedAt: Date;
794
- actionAttemptId: string | null;
795
- actionNotificationState: "none" | "pending" | "sent" | "failed";
796
- actionNotificationError: string | null;
797
- actionNotificationAttemptedAt: Date | null;
798
- } & {
799
- _id: mongoose.Types.ObjectId;
800
- } & {
801
- __v: number;
802
- }, "id" | keyof IMessageRelationshipMethods> & mongoose.HydratedDocumentOverrides<{
803
- id: string;
804
- } & IMessageRelationshipMethods>> | undefined;
805
- toUser?: mongoose.SchemaDefinitionProperty<UserId | null, MessageArchiveSchemaFields, mongoose.Document<unknown, {}, MessageArchiveSchemaFields, {
806
- id: string;
807
- }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
808
- actionCd: string;
809
- archivedBy: unknown;
810
- archivedAt: Date;
811
- actionAttemptId: string | null;
812
- actionNotificationState: "none" | "pending" | "sent" | "failed";
813
- actionNotificationError: string | null;
814
- actionNotificationAttemptedAt: Date | null;
815
- } & {
816
- _id: mongoose.Types.ObjectId;
817
- } & {
818
- __v: number;
819
- }, "id" | keyof IMessageRelationshipMethods> & mongoose.HydratedDocumentOverrides<{
820
- id: string;
821
- } & IMessageRelationshipMethods>> | undefined;
822
- toRoles?: mongoose.SchemaDefinitionProperty<string[], MessageArchiveSchemaFields, mongoose.Document<unknown, {}, MessageArchiveSchemaFields, {
823
- id: string;
824
- }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
825
- actionCd: string;
826
- archivedBy: unknown;
827
- archivedAt: Date;
828
- actionAttemptId: string | null;
829
- actionNotificationState: "none" | "pending" | "sent" | "failed";
830
- actionNotificationError: string | null;
831
- actionNotificationAttemptedAt: Date | null;
832
- } & {
833
- _id: mongoose.Types.ObjectId;
834
- } & {
835
- __v: number;
836
- }, "id" | keyof IMessageRelationshipMethods> & mongoose.HydratedDocumentOverrides<{
837
- id: string;
838
- } & IMessageRelationshipMethods>> | undefined;
839
- senderContent?: mongoose.SchemaDefinitionProperty<IMessageContent, MessageArchiveSchemaFields, mongoose.Document<unknown, {}, MessageArchiveSchemaFields, {
840
- id: string;
841
- }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
842
- actionCd: string;
843
- archivedBy: unknown;
844
- archivedAt: Date;
845
- actionAttemptId: string | null;
846
- actionNotificationState: "none" | "pending" | "sent" | "failed";
847
- actionNotificationError: string | null;
848
- actionNotificationAttemptedAt: Date | null;
849
- } & {
850
- _id: mongoose.Types.ObjectId;
851
- } & {
852
- __v: number;
853
- }, "id" | keyof IMessageRelationshipMethods> & mongoose.HydratedDocumentOverrides<{
854
- id: string;
855
- } & IMessageRelationshipMethods>> | undefined;
856
- receiverContent?: mongoose.SchemaDefinitionProperty<IMessageContent, MessageArchiveSchemaFields, mongoose.Document<unknown, {}, MessageArchiveSchemaFields, {
857
- id: string;
858
- }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
859
- actionCd: string;
860
- archivedBy: unknown;
861
- archivedAt: Date;
862
- actionAttemptId: string | null;
863
- actionNotificationState: "none" | "pending" | "sent" | "failed";
864
- actionNotificationError: string | null;
865
- actionNotificationAttemptedAt: Date | null;
866
- } & {
867
- _id: mongoose.Types.ObjectId;
868
- } & {
869
- __v: number;
870
- }, "id" | keyof IMessageRelationshipMethods> & mongoose.HydratedDocumentOverrides<{
871
- id: string;
872
- } & IMessageRelationshipMethods>> | undefined;
873
- documents?: mongoose.SchemaDefinitionProperty<mongoose.Types.ObjectId[], MessageArchiveSchemaFields, mongoose.Document<unknown, {}, MessageArchiveSchemaFields, {
874
- id: string;
875
- }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
876
- actionCd: string;
877
- archivedBy: unknown;
878
- archivedAt: Date;
879
- actionAttemptId: string | null;
880
- actionNotificationState: "none" | "pending" | "sent" | "failed";
881
- actionNotificationError: string | null;
882
- actionNotificationAttemptedAt: Date | null;
883
- } & {
884
- _id: mongoose.Types.ObjectId;
885
- } & {
886
- __v: number;
887
- }, "id" | keyof IMessageRelationshipMethods> & mongoose.HydratedDocumentOverrides<{
888
- id: string;
889
- } & IMessageRelationshipMethods>> | undefined;
890
- paymentSession?: mongoose.SchemaDefinitionProperty<string | null, MessageArchiveSchemaFields, mongoose.Document<unknown, {}, MessageArchiveSchemaFields, {
891
- id: string;
892
- }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
893
- actionCd: string;
894
- archivedBy: unknown;
895
- archivedAt: Date;
896
- actionAttemptId: string | null;
897
- actionNotificationState: "none" | "pending" | "sent" | "failed";
898
- actionNotificationError: string | null;
899
- actionNotificationAttemptedAt: Date | null;
900
- } & {
901
- _id: mongoose.Types.ObjectId;
902
- } & {
903
- __v: number;
904
- }, "id" | keyof IMessageRelationshipMethods> & mongoose.HydratedDocumentOverrides<{
905
- id: string;
906
- } & IMessageRelationshipMethods>> | undefined;
907
- paymentCd?: mongoose.SchemaDefinitionProperty<string, MessageArchiveSchemaFields, mongoose.Document<unknown, {}, MessageArchiveSchemaFields, {
908
- id: string;
909
- }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
910
- actionCd: string;
911
- archivedBy: unknown;
912
- archivedAt: Date;
913
- actionAttemptId: string | null;
914
- actionNotificationState: "none" | "pending" | "sent" | "failed";
915
- actionNotificationError: string | null;
916
- actionNotificationAttemptedAt: Date | null;
917
- } & {
918
- _id: mongoose.Types.ObjectId;
919
- } & {
920
- __v: number;
921
- }, "id" | keyof IMessageRelationshipMethods> & mongoose.HydratedDocumentOverrides<{
922
- id: string;
923
- } & IMessageRelationshipMethods>> | undefined;
924
- payload?: mongoose.SchemaDefinitionProperty<Record<string, unknown>, MessageArchiveSchemaFields, mongoose.Document<unknown, {}, MessageArchiveSchemaFields, {
925
- id: string;
926
- }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
927
- actionCd: string;
928
- archivedBy: unknown;
929
- archivedAt: Date;
930
- actionAttemptId: string | null;
931
- actionNotificationState: "none" | "pending" | "sent" | "failed";
932
- actionNotificationError: string | null;
933
- actionNotificationAttemptedAt: Date | null;
934
- } & {
935
- _id: mongoose.Types.ObjectId;
936
- } & {
937
- __v: number;
938
- }, "id" | keyof IMessageRelationshipMethods> & mongoose.HydratedDocumentOverrides<{
939
- id: string;
940
- } & IMessageRelationshipMethods>> | undefined;
941
- display?: mongoose.SchemaDefinitionProperty<Record<string, unknown>, MessageArchiveSchemaFields, mongoose.Document<unknown, {}, MessageArchiveSchemaFields, {
942
- id: string;
943
- }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
944
- actionCd: string;
945
- archivedBy: unknown;
946
- archivedAt: Date;
947
- actionAttemptId: string | null;
948
- actionNotificationState: "none" | "pending" | "sent" | "failed";
949
- actionNotificationError: string | null;
950
- actionNotificationAttemptedAt: Date | null;
951
- } & {
952
- _id: mongoose.Types.ObjectId;
953
- } & {
954
- __v: number;
955
- }, "id" | keyof IMessageRelationshipMethods> & mongoose.HydratedDocumentOverrides<{
956
- id: string;
957
- } & IMessageRelationshipMethods>> | undefined;
958
- clientRequestId?: mongoose.SchemaDefinitionProperty<string | null, MessageArchiveSchemaFields, mongoose.Document<unknown, {}, MessageArchiveSchemaFields, {
959
- id: string;
960
- }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
961
- actionCd: string;
962
- archivedBy: unknown;
963
- archivedAt: Date;
964
- actionAttemptId: string | null;
965
- actionNotificationState: "none" | "pending" | "sent" | "failed";
966
- actionNotificationError: string | null;
967
- actionNotificationAttemptedAt: Date | null;
968
- } & {
969
- _id: mongoose.Types.ObjectId;
970
- } & {
971
- __v: number;
972
- }, "id" | keyof IMessageRelationshipMethods> & mongoose.HydratedDocumentOverrides<{
973
- id: string;
974
- } & IMessageRelationshipMethods>> | undefined;
975
- clientRequestOwnerId?: mongoose.SchemaDefinitionProperty<string | null, MessageArchiveSchemaFields, mongoose.Document<unknown, {}, MessageArchiveSchemaFields, {
976
- id: string;
977
- }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
978
- actionCd: string;
979
- archivedBy: unknown;
980
- archivedAt: Date;
981
- actionAttemptId: string | null;
982
- actionNotificationState: "none" | "pending" | "sent" | "failed";
983
- actionNotificationError: string | null;
984
- actionNotificationAttemptedAt: Date | null;
985
- } & {
986
- _id: mongoose.Types.ObjectId;
987
- } & {
988
- __v: number;
989
- }, "id" | keyof IMessageRelationshipMethods> & mongoose.HydratedDocumentOverrides<{
990
- id: string;
991
- } & IMessageRelationshipMethods>> | undefined;
992
- clientRequestItemIndex?: mongoose.SchemaDefinitionProperty<number | null, MessageArchiveSchemaFields, mongoose.Document<unknown, {}, MessageArchiveSchemaFields, {
993
- id: string;
994
- }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
995
- actionCd: string;
996
- archivedBy: unknown;
997
- archivedAt: Date;
998
- actionAttemptId: string | null;
999
- actionNotificationState: "none" | "pending" | "sent" | "failed";
1000
- actionNotificationError: string | null;
1001
- actionNotificationAttemptedAt: Date | null;
1002
- } & {
1003
- _id: mongoose.Types.ObjectId;
1004
- } & {
1005
- __v: number;
1006
- }, "id" | keyof IMessageRelationshipMethods> & mongoose.HydratedDocumentOverrides<{
1007
- id: string;
1008
- } & IMessageRelationshipMethods>> | undefined;
1009
- actionState?: mongoose.SchemaDefinitionProperty<ActionLifecycleState, MessageArchiveSchemaFields, mongoose.Document<unknown, {}, MessageArchiveSchemaFields, {
1010
- id: string;
1011
- }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
1012
- actionCd: string;
1013
- archivedBy: unknown;
1014
- archivedAt: Date;
1015
- actionAttemptId: string | null;
1016
- actionNotificationState: "none" | "pending" | "sent" | "failed";
1017
- actionNotificationError: string | null;
1018
- actionNotificationAttemptedAt: Date | null;
1019
- } & {
1020
- _id: mongoose.Types.ObjectId;
1021
- } & {
1022
- __v: number;
1023
- }, "id" | keyof IMessageRelationshipMethods> & mongoose.HydratedDocumentOverrides<{
1024
- id: string;
1025
- } & IMessageRelationshipMethods>> | undefined;
1026
- actionCd?: mongoose.SchemaDefinitionProperty<string, MessageArchiveSchemaFields, mongoose.Document<unknown, {}, MessageArchiveSchemaFields, {
1027
- id: string;
1028
- }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
1029
- actionCd: string;
1030
- archivedBy: unknown;
1031
- archivedAt: Date;
1032
- actionAttemptId: string | null;
1033
- actionNotificationState: "none" | "pending" | "sent" | "failed";
1034
- actionNotificationError: string | null;
1035
- actionNotificationAttemptedAt: Date | null;
1036
- } & {
1037
- _id: mongoose.Types.ObjectId;
1038
- } & {
1039
- __v: number;
1040
- }, "id" | keyof IMessageRelationshipMethods> & mongoose.HydratedDocumentOverrides<{
1041
- id: string;
1042
- } & IMessageRelationshipMethods>> | undefined;
1043
- actionAttemptId?: mongoose.SchemaDefinitionProperty<string | null, MessageArchiveSchemaFields, mongoose.Document<unknown, {}, MessageArchiveSchemaFields, {
1044
- id: string;
1045
- }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
1046
- actionCd: string;
1047
- archivedBy: unknown;
1048
- archivedAt: Date;
1049
- actionAttemptId: string | null;
1050
- actionNotificationState: "none" | "pending" | "sent" | "failed";
1051
- actionNotificationError: string | null;
1052
- actionNotificationAttemptedAt: Date | null;
1053
- } & {
1054
- _id: mongoose.Types.ObjectId;
1055
- } & {
1056
- __v: number;
1057
- }, "id" | keyof IMessageRelationshipMethods> & mongoose.HydratedDocumentOverrides<{
1058
- id: string;
1059
- } & IMessageRelationshipMethods>> | undefined;
1060
- actionOwnerToken?: mongoose.SchemaDefinitionProperty<string | null, MessageArchiveSchemaFields, mongoose.Document<unknown, {}, MessageArchiveSchemaFields, {
1061
- id: string;
1062
- }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
1063
- actionCd: string;
1064
- archivedBy: unknown;
1065
- archivedAt: Date;
1066
- actionAttemptId: string | null;
1067
- actionNotificationState: "none" | "pending" | "sent" | "failed";
1068
- actionNotificationError: string | null;
1069
- actionNotificationAttemptedAt: Date | null;
1070
- } & {
1071
- _id: mongoose.Types.ObjectId;
1072
- } & {
1073
- __v: number;
1074
- }, "id" | keyof IMessageRelationshipMethods> & mongoose.HydratedDocumentOverrides<{
1075
- id: string;
1076
- } & IMessageRelationshipMethods>> | undefined;
1077
- actionClaimedBy?: mongoose.SchemaDefinitionProperty<string | null, MessageArchiveSchemaFields, mongoose.Document<unknown, {}, MessageArchiveSchemaFields, {
1078
- id: string;
1079
- }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
1080
- actionCd: string;
1081
- archivedBy: unknown;
1082
- archivedAt: Date;
1083
- actionAttemptId: string | null;
1084
- actionNotificationState: "none" | "pending" | "sent" | "failed";
1085
- actionNotificationError: string | null;
1086
- actionNotificationAttemptedAt: Date | null;
1087
- } & {
1088
- _id: mongoose.Types.ObjectId;
1089
- } & {
1090
- __v: number;
1091
- }, "id" | keyof IMessageRelationshipMethods> & mongoose.HydratedDocumentOverrides<{
1092
- id: string;
1093
- } & IMessageRelationshipMethods>> | undefined;
1094
- actionClaimedAt?: mongoose.SchemaDefinitionProperty<Date | null, MessageArchiveSchemaFields, mongoose.Document<unknown, {}, MessageArchiveSchemaFields, {
1095
- id: string;
1096
- }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
1097
- actionCd: string;
1098
- archivedBy: unknown;
1099
- archivedAt: Date;
1100
- actionAttemptId: string | null;
1101
- actionNotificationState: "none" | "pending" | "sent" | "failed";
1102
- actionNotificationError: string | null;
1103
- actionNotificationAttemptedAt: Date | null;
1104
- } & {
1105
- _id: mongoose.Types.ObjectId;
1106
- } & {
1107
- __v: number;
1108
- }, "id" | keyof IMessageRelationshipMethods> & mongoose.HydratedDocumentOverrides<{
1109
- id: string;
1110
- } & IMessageRelationshipMethods>> | undefined;
1111
- actionLeaseExpiresAt?: mongoose.SchemaDefinitionProperty<Date | null, MessageArchiveSchemaFields, mongoose.Document<unknown, {}, MessageArchiveSchemaFields, {
1112
- id: string;
1113
- }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
1114
- actionCd: string;
1115
- archivedBy: unknown;
1116
- archivedAt: Date;
1117
- actionAttemptId: string | null;
1118
- actionNotificationState: "none" | "pending" | "sent" | "failed";
1119
- actionNotificationError: string | null;
1120
- actionNotificationAttemptedAt: Date | null;
1121
- } & {
1122
- _id: mongoose.Types.ObjectId;
1123
- } & {
1124
- __v: number;
1125
- }, "id" | keyof IMessageRelationshipMethods> & mongoose.HydratedDocumentOverrides<{
1126
- id: string;
1127
- } & IMessageRelationshipMethods>> | undefined;
1128
- actionFailureMessage?: mongoose.SchemaDefinitionProperty<string | null, MessageArchiveSchemaFields, mongoose.Document<unknown, {}, MessageArchiveSchemaFields, {
1129
- id: string;
1130
- }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
1131
- actionCd: string;
1132
- archivedBy: unknown;
1133
- archivedAt: Date;
1134
- actionAttemptId: string | null;
1135
- actionNotificationState: "none" | "pending" | "sent" | "failed";
1136
- actionNotificationError: string | null;
1137
- actionNotificationAttemptedAt: Date | null;
1138
- } & {
1139
- _id: mongoose.Types.ObjectId;
1140
- } & {
1141
- __v: number;
1142
- }, "id" | keyof IMessageRelationshipMethods> & mongoose.HydratedDocumentOverrides<{
1143
- id: string;
1144
- } & IMessageRelationshipMethods>> | undefined;
1145
- createdAt?: mongoose.SchemaDefinitionProperty<Date, MessageArchiveSchemaFields, mongoose.Document<unknown, {}, MessageArchiveSchemaFields, {
1146
- id: string;
1147
- }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
1148
- actionCd: string;
1149
- archivedBy: unknown;
1150
- archivedAt: Date;
1151
- actionAttemptId: string | null;
1152
- actionNotificationState: "none" | "pending" | "sent" | "failed";
1153
- actionNotificationError: string | null;
1154
- actionNotificationAttemptedAt: Date | null;
1155
- } & {
1156
- _id: mongoose.Types.ObjectId;
1157
- } & {
1158
- __v: number;
1159
- }, "id" | keyof IMessageRelationshipMethods> & mongoose.HydratedDocumentOverrides<{
1160
- id: string;
1161
- } & IMessageRelationshipMethods>> | undefined;
1162
- updatedAt?: mongoose.SchemaDefinitionProperty<Date, MessageArchiveSchemaFields, mongoose.Document<unknown, {}, MessageArchiveSchemaFields, {
1163
- id: string;
1164
- }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
1165
- actionCd: string;
1166
- archivedBy: unknown;
1167
- archivedAt: Date;
1168
- actionAttemptId: string | null;
1169
- actionNotificationState: "none" | "pending" | "sent" | "failed";
1170
- actionNotificationError: string | null;
1171
- actionNotificationAttemptedAt: Date | null;
1172
- } & {
1173
- _id: mongoose.Types.ObjectId;
1174
- } & {
1175
- __v: number;
1176
- }, "id" | keyof IMessageRelationshipMethods> & mongoose.HydratedDocumentOverrides<{
1177
- id: string;
1178
- } & IMessageRelationshipMethods>> | undefined;
1179
- archivedBy?: mongoose.SchemaDefinitionProperty<unknown, MessageArchiveSchemaFields, mongoose.Document<unknown, {}, MessageArchiveSchemaFields, {
1180
- id: string;
1181
- }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
1182
- actionCd: string;
1183
- archivedBy: unknown;
1184
- archivedAt: Date;
1185
- actionAttemptId: string | null;
1186
- actionNotificationState: "none" | "pending" | "sent" | "failed";
1187
- actionNotificationError: string | null;
1188
- actionNotificationAttemptedAt: Date | null;
1189
- } & {
1190
- _id: mongoose.Types.ObjectId;
1191
- } & {
1192
- __v: number;
1193
- }, "id" | keyof IMessageRelationshipMethods> & mongoose.HydratedDocumentOverrides<{
1194
- id: string;
1195
- } & IMessageRelationshipMethods>> | undefined;
1196
- archivedAt?: mongoose.SchemaDefinitionProperty<Date, MessageArchiveSchemaFields, mongoose.Document<unknown, {}, MessageArchiveSchemaFields, {
1197
- id: string;
1198
- }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
1199
- actionCd: string;
1200
- archivedBy: unknown;
1201
- archivedAt: Date;
1202
- actionAttemptId: string | null;
1203
- actionNotificationState: "none" | "pending" | "sent" | "failed";
1204
- actionNotificationError: string | null;
1205
- actionNotificationAttemptedAt: Date | null;
1206
- } & {
1207
- _id: mongoose.Types.ObjectId;
1208
- } & {
1209
- __v: number;
1210
- }, "id" | keyof IMessageRelationshipMethods> & mongoose.HydratedDocumentOverrides<{
1211
- id: string;
1212
- } & IMessageRelationshipMethods>> | undefined;
1213
- actionNotificationState?: mongoose.SchemaDefinitionProperty<"failed" | "none" | "pending" | "sent", MessageArchiveSchemaFields, mongoose.Document<unknown, {}, MessageArchiveSchemaFields, {
1214
- id: string;
1215
- }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
1216
- actionCd: string;
1217
- archivedBy: unknown;
1218
- archivedAt: Date;
1219
- actionAttemptId: string | null;
1220
- actionNotificationState: "none" | "pending" | "sent" | "failed";
1221
- actionNotificationError: string | null;
1222
- actionNotificationAttemptedAt: Date | null;
1223
- } & {
1224
- _id: mongoose.Types.ObjectId;
1225
- } & {
1226
- __v: number;
1227
- }, "id" | keyof IMessageRelationshipMethods> & mongoose.HydratedDocumentOverrides<{
1228
- id: string;
1229
- } & IMessageRelationshipMethods>> | undefined;
1230
- actionNotificationError?: mongoose.SchemaDefinitionProperty<string | null, MessageArchiveSchemaFields, mongoose.Document<unknown, {}, MessageArchiveSchemaFields, {
1231
- id: string;
1232
- }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
1233
- actionCd: string;
1234
- archivedBy: unknown;
1235
- archivedAt: Date;
1236
- actionAttemptId: string | null;
1237
- actionNotificationState: "none" | "pending" | "sent" | "failed";
1238
- actionNotificationError: string | null;
1239
- actionNotificationAttemptedAt: Date | null;
1240
- } & {
1241
- _id: mongoose.Types.ObjectId;
1242
- } & {
1243
- __v: number;
1244
- }, "id" | keyof IMessageRelationshipMethods> & mongoose.HydratedDocumentOverrides<{
1245
- id: string;
1246
- } & IMessageRelationshipMethods>> | undefined;
1247
- actionNotificationAttemptedAt?: mongoose.SchemaDefinitionProperty<Date | null, MessageArchiveSchemaFields, mongoose.Document<unknown, {}, MessageArchiveSchemaFields, {
1248
- id: string;
1249
- }, mongoose.DefaultSchemaOptions> & Omit<IBaseMessage & {
1250
- actionCd: string;
1251
- archivedBy: unknown;
1252
- archivedAt: Date;
1253
- actionAttemptId: string | null;
1254
- actionNotificationState: "none" | "pending" | "sent" | "failed";
1255
- actionNotificationError: string | null;
1256
- actionNotificationAttemptedAt: Date | null;
1257
- } & {
1258
- _id: mongoose.Types.ObjectId;
1259
- } & {
1260
- __v: number;
1261
- }, "id" | keyof IMessageRelationshipMethods> & mongoose.HydratedDocumentOverrides<{
1262
- id: string;
1263
- } & IMessageRelationshipMethods>> | undefined;
1264
- }, MessageArchiveSchemaFields>;
587
+ declare const MessageArchiveSchema: ReturnType<typeof buildMessageArchiveSchema>;
1265
588
 
1266
589
  interface MessageRequestSchemaFields {
1267
590
  clientRequestId: string;
@@ -1278,124 +601,7 @@ interface MessageRequestSchemaFields {
1278
601
  updatedAt: Date;
1279
602
  }
1280
603
  declare function buildMessageRequestSchema(): mongoose.Schema<MessageRequestSchemaFields>;
1281
- declare const MessageRequestSchema: mongoose.Schema<MessageRequestSchemaFields, mongoose.Model<MessageRequestSchemaFields, any, any, any, any, any, MessageRequestSchemaFields>, {}, {}, {}, {}, mongoose.DefaultSchemaOptions, MessageRequestSchemaFields, mongoose.Document<unknown, {}, MessageRequestSchemaFields, {
1282
- id: string;
1283
- }, mongoose.DefaultSchemaOptions> & Omit<MessageRequestSchemaFields & {
1284
- _id: mongoose.Types.ObjectId;
1285
- } & {
1286
- __v: number;
1287
- }, "id"> & mongoose.HydratedDocumentOverrides<{
1288
- id: string;
1289
- }>, {
1290
- clientRequestId?: mongoose.SchemaDefinitionProperty<string, MessageRequestSchemaFields, mongoose.Document<unknown, {}, MessageRequestSchemaFields, {
1291
- id: string;
1292
- }, mongoose.DefaultSchemaOptions> & Omit<MessageRequestSchemaFields & {
1293
- _id: mongoose.Types.ObjectId;
1294
- } & {
1295
- __v: number;
1296
- }, "id"> & mongoose.HydratedDocumentOverrides<{
1297
- id: string;
1298
- }>> | undefined;
1299
- clientRequestOwnerId?: mongoose.SchemaDefinitionProperty<string, MessageRequestSchemaFields, mongoose.Document<unknown, {}, MessageRequestSchemaFields, {
1300
- id: string;
1301
- }, mongoose.DefaultSchemaOptions> & Omit<MessageRequestSchemaFields & {
1302
- _id: mongoose.Types.ObjectId;
1303
- } & {
1304
- __v: number;
1305
- }, "id"> & mongoose.HydratedDocumentOverrides<{
1306
- id: string;
1307
- }>> | undefined;
1308
- templateCd?: mongoose.SchemaDefinitionProperty<string, MessageRequestSchemaFields, mongoose.Document<unknown, {}, MessageRequestSchemaFields, {
1309
- id: string;
1310
- }, mongoose.DefaultSchemaOptions> & Omit<MessageRequestSchemaFields & {
1311
- _id: mongoose.Types.ObjectId;
1312
- } & {
1313
- __v: number;
1314
- }, "id"> & mongoose.HydratedDocumentOverrides<{
1315
- id: string;
1316
- }>> | undefined;
1317
- state?: mongoose.SchemaDefinitionProperty<"failed" | "pending" | "completed", MessageRequestSchemaFields, mongoose.Document<unknown, {}, MessageRequestSchemaFields, {
1318
- id: string;
1319
- }, mongoose.DefaultSchemaOptions> & Omit<MessageRequestSchemaFields & {
1320
- _id: mongoose.Types.ObjectId;
1321
- } & {
1322
- __v: number;
1323
- }, "id"> & mongoose.HydratedDocumentOverrides<{
1324
- id: string;
1325
- }>> | undefined;
1326
- itemCount?: mongoose.SchemaDefinitionProperty<number | null, MessageRequestSchemaFields, mongoose.Document<unknown, {}, MessageRequestSchemaFields, {
1327
- id: string;
1328
- }, mongoose.DefaultSchemaOptions> & Omit<MessageRequestSchemaFields & {
1329
- _id: mongoose.Types.ObjectId;
1330
- } & {
1331
- __v: number;
1332
- }, "id"> & mongoose.HydratedDocumentOverrides<{
1333
- id: string;
1334
- }>> | undefined;
1335
- leaseOwnerId?: mongoose.SchemaDefinitionProperty<string | null, MessageRequestSchemaFields, mongoose.Document<unknown, {}, MessageRequestSchemaFields, {
1336
- id: string;
1337
- }, mongoose.DefaultSchemaOptions> & Omit<MessageRequestSchemaFields & {
1338
- _id: mongoose.Types.ObjectId;
1339
- } & {
1340
- __v: number;
1341
- }, "id"> & mongoose.HydratedDocumentOverrides<{
1342
- id: string;
1343
- }>> | undefined;
1344
- leaseExpiresAt?: mongoose.SchemaDefinitionProperty<Date | null, MessageRequestSchemaFields, mongoose.Document<unknown, {}, MessageRequestSchemaFields, {
1345
- id: string;
1346
- }, mongoose.DefaultSchemaOptions> & Omit<MessageRequestSchemaFields & {
1347
- _id: mongoose.Types.ObjectId;
1348
- } & {
1349
- __v: number;
1350
- }, "id"> & mongoose.HydratedDocumentOverrides<{
1351
- id: string;
1352
- }>> | undefined;
1353
- completedAt?: mongoose.SchemaDefinitionProperty<Date | null, MessageRequestSchemaFields, mongoose.Document<unknown, {}, MessageRequestSchemaFields, {
1354
- id: string;
1355
- }, mongoose.DefaultSchemaOptions> & Omit<MessageRequestSchemaFields & {
1356
- _id: mongoose.Types.ObjectId;
1357
- } & {
1358
- __v: number;
1359
- }, "id"> & mongoose.HydratedDocumentOverrides<{
1360
- id: string;
1361
- }>> | undefined;
1362
- failedAt?: mongoose.SchemaDefinitionProperty<Date | null, MessageRequestSchemaFields, mongoose.Document<unknown, {}, MessageRequestSchemaFields, {
1363
- id: string;
1364
- }, mongoose.DefaultSchemaOptions> & Omit<MessageRequestSchemaFields & {
1365
- _id: mongoose.Types.ObjectId;
1366
- } & {
1367
- __v: number;
1368
- }, "id"> & mongoose.HydratedDocumentOverrides<{
1369
- id: string;
1370
- }>> | undefined;
1371
- failureMessage?: mongoose.SchemaDefinitionProperty<string | null, MessageRequestSchemaFields, mongoose.Document<unknown, {}, MessageRequestSchemaFields, {
1372
- id: string;
1373
- }, mongoose.DefaultSchemaOptions> & Omit<MessageRequestSchemaFields & {
1374
- _id: mongoose.Types.ObjectId;
1375
- } & {
1376
- __v: number;
1377
- }, "id"> & mongoose.HydratedDocumentOverrides<{
1378
- id: string;
1379
- }>> | undefined;
1380
- createdAt?: mongoose.SchemaDefinitionProperty<Date, MessageRequestSchemaFields, mongoose.Document<unknown, {}, MessageRequestSchemaFields, {
1381
- id: string;
1382
- }, mongoose.DefaultSchemaOptions> & Omit<MessageRequestSchemaFields & {
1383
- _id: mongoose.Types.ObjectId;
1384
- } & {
1385
- __v: number;
1386
- }, "id"> & mongoose.HydratedDocumentOverrides<{
1387
- id: string;
1388
- }>> | undefined;
1389
- updatedAt?: mongoose.SchemaDefinitionProperty<Date, MessageRequestSchemaFields, mongoose.Document<unknown, {}, MessageRequestSchemaFields, {
1390
- id: string;
1391
- }, mongoose.DefaultSchemaOptions> & Omit<MessageRequestSchemaFields & {
1392
- _id: mongoose.Types.ObjectId;
1393
- } & {
1394
- __v: number;
1395
- }, "id"> & mongoose.HydratedDocumentOverrides<{
1396
- id: string;
1397
- }>> | undefined;
1398
- }, MessageRequestSchemaFields>;
604
+ declare const MessageRequestSchema: ReturnType<typeof buildMessageRequestSchema>;
1399
605
 
1400
606
  /**
1401
607
  * Single explicit permission predicate shared by every permission boundary:
@@ -1494,6 +700,11 @@ declare function interpolateTemplate(template: MessageTemplate | RegisteredMessa
1494
700
  /**
1495
701
  * Email provider interface.
1496
702
  * Host app implements this to send email notifications.
703
+ * Pass `provider.sendNotification.bind(provider)` as `buildMessageSchema`'s
704
+ * `emailNotifier`; methods are not automatically bound. Recipient lookup is
705
+ * configured separately with `emailRecipientResolver` (local User.email by
706
+ * default). Delivery is best-effort for new session-free saves, not a durable
707
+ * outbox; failures are observed through `onEmailDeliveryFailure`.
1497
708
  */
1498
709
  interface EmailProvider {
1499
710
  sendNotification(to: string, title: string, body: string): Promise<void>;
@@ -1512,6 +723,14 @@ declare class NoopEmailProvider implements EmailProvider {
1512
723
  * Host apps implement this to handle payment sessions for messages
1513
724
  * that require payment (e.g. Stripe, Adyen, Paddle).
1514
725
  *
726
+ * Every fresh item's nonempty `item.paymentCd || template.paymentCd || ''`
727
+ * requires a session, even with no recipients. Empty item codes inherit the
728
+ * template code; codes are passed through without trimming. Absent/null
729
+ * providers raise `PaymentProviderRequiredError`; code-free creation and
730
+ * completed replay (including legacy sessionless records) need no provider.
731
+ * Session creation is not proof of payment: completion, capture, webhooks, and
732
+ * payment-based business authorization remain host/provider responsibilities.
733
+ *
1515
734
  * Message creation may create external sessions before MongoDB commit. If any
1516
735
  * prepared item, model/session setup step, or idempotent batch transaction
1517
736
  * fails before commit, `MessageService` calls `expireSession()` for every
@@ -1543,9 +762,12 @@ declare class NoopEmailProvider implements EmailProvider {
1543
762
  */
1544
763
  interface PaymentProvider {
1545
764
  /**
1546
- * Create a checkout/session for the given user and pricing code.
1547
- * Return the session id, or `null` to indicate the session could not
1548
- * be created (the message creation flow will throw in that case).
765
+ * Create one checkout/session per payment-bearing prepared item, independently
766
+ * of recipients, outside retryable transaction callbacks. `user` is
767
+ * `(payerUser || user)._id`, not the prepared sender or recipient; only the
768
+ * item's `priceArgs` is forwarded. Return a nonempty session id. A null/empty
769
+ * result throws `Error('payment session creation failed')`; provider rejections
770
+ * propagate unchanged (unless known-session compensation itself fails).
1549
771
  */
1550
772
  createSession(user: UserId, code: string, priceArgs?: Record<string, unknown>): Promise<string | null>;
1551
773
  /**
@@ -1560,9 +782,11 @@ interface PaymentProvider {
1560
782
  refundPayment(sessionId: string): Promise<void>;
1561
783
  }
1562
784
  /**
1563
- * No-op payment provider that returns null for session creation
1564
- * and does nothing for expire/refund. Useful for apps that don't use payments
1565
- * or for tests.
785
+ * No-op payment provider that returns null for session creation and does nothing
786
+ * for expire/refund. It cannot satisfy a nonempty payment code: fresh paid items
787
+ * fail with `Error('payment session creation failed')`, even without recipients.
788
+ * Code-free applications may omit the provider entirely; tests may use this
789
+ * implementation to exercise the configured-provider null-return contract.
1566
790
  */
1567
791
  declare class NoopPaymentProvider implements PaymentProvider {
1568
792
  createSession(_user: UserId, _code: string, _priceArgs?: Record<string, unknown>): Promise<string | null>;
@@ -1592,6 +816,18 @@ declare class ActionNotAllowedError extends Error {
1592
816
  static [Symbol.hasInstance](value: unknown): boolean;
1593
817
  constructor();
1594
818
  }
819
+ /**
820
+ * Invalid submitted command rejected by a pure `MessageAction.parseInput` hook.
821
+ * Root-exported with mixed ESM/CommonJS `instanceof` support. HTTP returns only
822
+ * the fixed `invalid action input` message (400), never this diagnostic/cause or
823
+ * an attempt ID. Fresh pre-handler claims are released; retry attempts are kept.
824
+ * Throwing this inside a handler retains the ordinary `ActionRetryableError`
825
+ * contract because business effects may already have occurred.
826
+ */
827
+ declare class ActionInputValidationError extends Error {
828
+ static [Symbol.hasInstance](value: unknown): boolean;
829
+ constructor(message?: string);
830
+ }
1595
831
  declare class InvalidMessageUserError extends Error {
1596
832
  static [Symbol.hasInstance](value: unknown): boolean;
1597
833
  constructor(message?: string);
@@ -1662,6 +898,20 @@ declare class MessageModelResolutionError extends Error {
1662
898
  connectionName: string;
1663
899
  constructor(role: MessageModelRole, modelName: string, connectionName: string, cause?: unknown);
1664
900
  }
901
+ /**
902
+ * Fresh template creation requires a payment provider for every nonempty
903
+ * effective `paymentCd`, regardless of recipients. Absent/null providers throw
904
+ * this server-configuration error before the item's write. Code-free items and
905
+ * completed replays (including legacy sessionless records) need no provider.
906
+ *
907
+ * Root-exported with mixed ESM/CommonJS `instanceof` support. Routes use the
908
+ * sanitized HTTP 500 path; no template, code, payer, or session details are carried.
909
+ * Configured-provider rejections and null-return errors retain their own contracts.
910
+ */
911
+ declare class PaymentProviderRequiredError extends Error {
912
+ static [Symbol.hasInstance](value: unknown): boolean;
913
+ constructor();
914
+ }
1665
915
  declare class PaymentSessionCompensationError extends Error {
1666
916
  static [Symbol.hasInstance](value: unknown): boolean;
1667
917
  sessionId: string;
@@ -1700,6 +950,11 @@ interface MessageServiceOptions {
1700
950
  getModel?: (name: string) => mongoose.Model<unknown>;
1701
951
  connection?: mongoose.Connection;
1702
952
  modelNames?: Partial<MessageServiceModelNames>;
953
+ /**
954
+ * Required for fresh items with a nonempty effective `paymentCd`, even without
955
+ * recipients; absent/null throws `PaymentProviderRequiredError`. Optional for
956
+ * code-free items and completed replays, including legacy sessionless records.
957
+ */
1703
958
  paymentProvider?: PaymentProvider | null;
1704
959
  /**
1705
960
  * Called when the service cannot expire an external payment session that was
@@ -1713,6 +968,11 @@ interface MessageServiceOptions {
1713
968
  * Configure `buildMessageSchema` separately for direct document `archive()`.
1714
969
  */
1715
970
  onTransactionCleanupFailure?: MessageTransactionCleanupFailureObserver;
971
+ /**
972
+ * Fallback roles for `createMessage` when prepared `toUser` is absent and
973
+ * `toRoles` is omitted or empty (`[]` does not suppress fallback).
974
+ * Explicit roles are preserved even alongside `toUser`. Defaults to `[]`.
975
+ */
1716
976
  adminRoles?: string[];
1717
977
  registry?: TemplateRegistry;
1718
978
  /**
@@ -1724,6 +984,22 @@ interface MessageServiceOptions {
1724
984
  * Hard upper bound for `listMessages` limit to prevent abuse. Defaults to 100.
1725
985
  */
1726
986
  maxListLimit?: number;
987
+ /**
988
+ * Processing lease for each action acquisition. Defaults to 30000 ms.
989
+ * Only omission or `undefined` selects the default; `null` is invalid.
990
+ * Must be a finite safe integer in `[1, MAX_MESSAGE_SERVICE_TIMEOUT_MS]` ms
991
+ * (`2147483647` maximum); invalid values throw `InvalidMessageServiceOptionError`
992
+ * at construction. Route construction forwards this option; injected routes
993
+ * require configuring it on the supplied service instead.
994
+ *
995
+ * Expiry permits same-action takeover; it does not cancel the handler or
996
+ * automatically reject the still-current owner's completion/failure. Takeover
997
+ * retains `actionAttemptId` and rotates the owner token to fence stale writes.
998
+ * No heartbeat or renewal is performed. Applies to new acquisitions only;
999
+ * existing persisted deadlines are unchanged. Deduplicate external effects by
1000
+ * `actionAttemptId`, including when handlers overlap after expiry.
1001
+ */
1002
+ actionLeaseMs?: number;
1727
1003
  /**
1728
1004
  * How long a pending idempotent create reservation lease remains live before
1729
1005
  * another caller may atomically take it over. Defaults to 30000 ms.
@@ -1808,6 +1084,9 @@ declare const GENERIC_NOTIFICATION_TEMPLATE_CD = "__generic-notification__";
1808
1084
  * ObjectId by callers and normalized to their hex string only where a string
1809
1085
  * scope/query key is required.
1810
1086
  *
1087
+ * This predicate checks only the id. `requireMessageUserId` also validates
1088
+ * optional principal roles: omitted/undefined or an array of strings.
1089
+ *
1811
1090
  * `findMessage`/`findMessageOrThrow` and `createNotification` are trusted
1812
1091
  * host-level operations and intentionally do not take a principal; they are
1813
1092
  * not part of this contract.
@@ -1816,8 +1095,15 @@ declare function isValidMessageUserId(id: unknown): id is string | mongoose.Type
1816
1095
  /**
1817
1096
  * Assert a user-facing principal and return its normalized string identity.
1818
1097
  * Throws `InvalidMessageUserError` for missing/null/empty/numeric/array/
1819
- * plain-object ids. String ids are trimmed; ObjectId ids become their hex
1820
- * string. The caller's original `MessageUser` object (and its `_id` type) is
1098
+ * plain-object ids, or malformed `roles` (anything except undefined or an
1099
+ * array containing only strings). Role strings retain their exact values;
1100
+ * no coercion, trimming, or substring matching is applied. String ids are
1101
+ * trimmed; ObjectId ids become their hex string.
1102
+ * Case is preserved even for hex-looking strings: request scopes are textual,
1103
+ * so uppercase hex and lowercase hex remain separate legacy-compatible scopes.
1104
+ * Relationship matching against a stored native ObjectId accepts either case;
1105
+ * stored String parties use exact trimmed equality. See the README user-ID recipe.
1106
+ * The caller's original `MessageUser` object (and its `_id` type) is
1821
1107
  * left untouched so ObjectId-backed schemas keep their native type.
1822
1108
  */
1823
1109
  declare function requireMessageUserId(user: unknown): string;
@@ -1875,10 +1161,25 @@ declare class MessageService {
1875
1161
  *
1876
1162
  * User-facing entry point: `user` (and `payerUser` when provided) must
1877
1163
  * carry a valid principal id (non-empty string or ObjectId; numbers,
1878
- * arrays, and plain objects are rejected with `InvalidMessageUserError`)
1164
+ * arrays, and plain objects are rejected with `InvalidMessageUserError`),
1165
+ * and optional `roles` must be undefined or an array of strings,
1879
1166
  * before any template, provider, or model effect runs. Both the
1880
1167
  * idempotent (`clientRequestId`) and direct branches enforce this.
1881
1168
  *
1169
+ * Each `PrepareResult.documents` selects that item's attachments; `[]` clears
1170
+ * them. Omission/undefined retains the original caller `payload.documents`
1171
+ * fallback, independently of the prepared business payload. Selected arrays
1172
+ * are copied per item without mutating caller/preparation arrays.
1173
+ *
1174
+ * Each fresh item's `item.paymentCd || template.paymentCd || ''` requests a
1175
+ * session when nonempty, independently of recipients. An empty item override
1176
+ * inherits the template code. Absent/null providers throw
1177
+ * `PaymentProviderRequiredError`; configured-provider rejections propagate and
1178
+ * null/empty session returns throw `Error('payment session creation failed')`.
1179
+ * The payer remains `(payerUser || user)._id`, not the prepared sender/recipient.
1180
+ * Direct batches retain committed prefixes; idempotent batches commit atomically
1181
+ * and compensate all known uncommitted sessions on failure.
1182
+ *
1882
1183
  * Idempotent replay contract (MSGF-06): a completed same-scope replay
1883
1184
  * returns the current active/archive records merged from both collections
1884
1185
  * (`Array<IMessage | IMessageArchive>`), sorted by exact
@@ -1944,7 +1245,8 @@ declare class MessageService {
1944
1245
  * or matches one of the recipient's roles.
1945
1246
  *
1946
1247
  * User-facing operation: validates `user` via the shared principal
1947
- * contract. Returns `IMessage[]` ordered by `{ createdAt: -1, _id: -1 }`.
1248
+ * contract before model resolution. Returns `IMessage[]` ordered by
1249
+ * `{ createdAt: -1, _id: -1 }`.
1948
1250
  */
1949
1251
  listMessages(params: {
1950
1252
  user: MessageUser;
@@ -1956,7 +1258,8 @@ declare class MessageService {
1956
1258
  * Count active (non-archived) messages visible to a user.
1957
1259
  * Useful for badge indicators ("3 new messages").
1958
1260
  *
1959
- * User-facing operation: validates `user` via the shared principal contract.
1261
+ * User-facing operation: validates `user` via the shared principal contract
1262
+ * before model resolution.
1960
1263
  */
1961
1264
  countMessages(user: MessageUser): Promise<number>;
1962
1265
  /**
@@ -1997,12 +1300,28 @@ declare class MessageService {
1997
1300
  * Execute an action with a durable claim, stable handler attempt key,
1998
1301
  * transactional archive, and post-commit sender notification status.
1999
1302
  *
1303
+ * `actionLeaseMs` controls when a same-action retry may take over. Expiry alone
1304
+ * does not cancel the handler or reject a still-current owner; takeover fences
1305
+ * stale completion/failure writes with `ActionConflictError`. There is no
1306
+ * heartbeat or renewal; external effects must deduplicate by `actionAttemptId`.
1307
+ *
2000
1308
  * User-facing operation: `data.user` is validated before any template or
2001
- * model effect. Authorization and handler selection bind to the persisted
1309
+ * model effect. Handler users contain only the documented `MessageUser`
1310
+ * fields, read explicitly (including getters), with a copied roles array;
1311
+ * the caller's user and original `req` are not modified.
1312
+ * Authorization and handler selection bind to the persisted
2002
1313
  * claim, not the caller-supplied `data.message` copy. Archived messages
2003
1314
  * are re-read by id on their owning connection and apply a stored
2004
1315
  * sender/receiver relationship gate before disclosing current attempt IDs
2005
1316
  * or notification state. A missing archive throws `MessageNotFoundError`.
1317
+ * `data.input` is explicit submitted data, never inferred from `req`. The
1318
+ * current claimed action's optional synchronous pure `parseInput` supplies
1319
+ * `ctx.input` after authorization. Invalid input throws
1320
+ * `ActionInputValidationError`; unexpected parser failures preserve their
1321
+ * cause as server errors. Both use fenced pre-handler release: fresh claims
1322
+ * return to active, retries retain their stable attempt/action as retryable.
1323
+ * Hosts own input bounds, runtime validation, and durable command/result
1324
+ * binding at first host reservation (not at package claim).
2006
1325
  * Returns the handler's value (`unknown`; templates
2007
1326
  * document their own shape).
2008
1327
  */
@@ -2010,6 +1329,8 @@ declare class MessageService {
2010
1329
  message: IMessage | IMessageArchive;
2011
1330
  user: MessageUser;
2012
1331
  permissions?: Record<string, boolean>;
1332
+ /** Submitted command; HTTP supplies its body. Separate from stored/action payloads. */
1333
+ input?: unknown;
2013
1334
  req?: unknown;
2014
1335
  }): Promise<unknown>;
2015
1336
  private resolveModel;
@@ -2023,6 +1344,7 @@ declare class MessageService {
2023
1344
  private compensatePaymentSessions;
2024
1345
  private compensatePaymentSession;
2025
1346
  private buildActionContext;
1347
+ private parseActionInput;
2026
1348
  private claimAction;
2027
1349
  /**
2028
1350
  * Relationship/permission policy for archived outcomes.
@@ -2064,6 +1386,7 @@ declare class MessageService {
2064
1386
  private normalizeListSkip;
2065
1387
  private buildClientRequestScope;
2066
1388
  private requireUserId;
1389
+ private buildAuthorizedUser;
2067
1390
  private findByClientRequestScope;
2068
1391
  private findArchivedByClientRequestScope;
2069
1392
  /**
@@ -2169,6 +1492,9 @@ interface MessageRoutesBehaviorOptions {
2169
1492
  * require this extractor to return a user with a valid `_id` (non-empty
2170
1493
  * string or ObjectId; numbers, arrays, and plain objects are rejected)
2171
1494
  * before any service, template, payment, model, or action side effect runs.
1495
+ * Optional `roles` must be undefined or an array containing only strings;
1496
+ * malformed roles also produce 401 before service/model lookup.
1497
+ * The original request and extracted user are passed through unchanged.
2172
1498
  * Shares the service's principal-validation contract.
2173
1499
  */
2174
1500
  getUser?: (req: Request) => MessageUser | undefined;
@@ -2195,7 +1521,7 @@ interface MessageRoutesBehaviorOptions {
2195
1521
  * Convenience-construction path: routes build and own a `MessageService`
2196
1522
  * from the full service option set. `service` must be absent; every other
2197
1523
  * service knob (`getModel`, `connection`, `modelNames`, payment, `registry`,
2198
- * list limits, and `clientRequest*` timing/test hooks) is forwarded verbatim
1524
+ * list limits, `actionLeaseMs`, and `clientRequest*` timing/test hooks) is forwarded verbatim
2199
1525
  * to `new MessageService(...)` so the route service never drifts behind the
2200
1526
  * direct-service configuration surface.
2201
1527
  */
@@ -2230,6 +1556,7 @@ interface MessageRoutesInjectionOptions extends MessageRoutesBehaviorOptions {
2230
1556
  registry?: never;
2231
1557
  defaultListLimit?: never;
2232
1558
  maxListLimit?: never;
1559
+ actionLeaseMs?: never;
2233
1560
  clientRequestLeaseMs?: never;
2234
1561
  clientRequestWaitMs?: never;
2235
1562
  clientRequestPollMs?: never;
@@ -2286,4 +1613,4 @@ declare function createMessageRoutes(options: MessageRoutesOptions): {
2286
1613
  service: MessageService;
2287
1614
  };
2288
1615
 
2289
- 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, InvalidMessageServiceOptionError, InvalidMessageUserError, InvalidPaginationValueError, MAX_MESSAGE_SERVICE_TIMEOUT_MS, MESSAGE_ARCHIVE_MODEL_NAME, MESSAGE_MODEL_NAME, MESSAGE_REQUEST_MODEL_NAME, type MessageAction, MessageArchiveSchema, MessageArchivedError, MessageContentSchema, MessageModelResolutionError, MessageNotFoundError, MessageRequestSchema, type MessageRoutesBehaviorOptions, type MessageRoutesConstructionOptions, type MessageRoutesInjectionOptions, type MessageRoutesOptions, MessageSchema, type MessageSchemaConfig, MessageService, type MessageServiceModelNames, type MessageServiceOptions, type MessageTemplate, type MessageTransactionCleanupFailureEvent, type MessageTransactionCleanupFailureObserver, MessageTransactionRequiredError, type MessageType, type MessageUser, NoopEmailProvider, NoopPaymentProvider, type PaymentCompensationFailureEvent, type PaymentProvider, PaymentSessionCompensationAggregateError, PaymentSessionCompensationError, type PaymentSessionCompensationFailure, type PrepareContext, type PrepareResult, type PublicMessageDto, type PublicMessageParty, type PublicMessageSource, type RegisteredMessageAction, type RegisteredMessageTemplate, type RegisteredUiTemplate, type SenderNotificationContent, TemplateNotFoundError, TemplateRegistry, TemplateRegistryValidationError, type UiTemplate, type UserId, type Usertype, buildMessageArchiveSchema, buildMessageRequestSchema, buildMessageSchema, createMessageRoutes, defaultRegistry, filterActions, hasExplicitPermissionGrant, includesAction, interpolateMessageContent, interpolateTemplate, isActionAllowed, isValidMessageUserId, requireMessageUserId, resolveUiTemplate, serializePublicMessage };
1616
+ export { type ActionConfirmation, ActionConflictError, type ActionContext, ActionInputValidationError, type ActionLifecycleState, ActionNotAllowedError, ActionNotFoundError, ActionNotificationPendingError, type ActionNotificationState, ActionRetryableError, ActionTemplateMismatchError, BaseMessageFields, ClientRequestFailedError, ClientRequestInconsistentStateError, ClientRequestPendingError, type EmailDeliveryFailureEvent, type EmailDeliveryFailureStage, type EmailNotifier, type EmailProvider, type EmailRecipientResolver, type EmailRecipientResolverContext, GENERIC_NOTIFICATION_TEMPLATE_CD, type IBaseMessage, type IMessage, type IMessageArchive, type IMessageContent, type IMessageMethods, type InterpolatedAction, type InterpolatedContent, type InterpolationResult, InvalidClientRequestIdError, InvalidMessageServiceOptionError, InvalidMessageUserError, InvalidPaginationValueError, MAX_MESSAGE_SERVICE_TIMEOUT_MS, MESSAGE_ARCHIVE_MODEL_NAME, MESSAGE_MODEL_NAME, MESSAGE_REQUEST_MODEL_NAME, type MessageAction, MessageArchiveSchema, MessageArchivedError, MessageContentSchema, MessageModelResolutionError, MessageNotFoundError, MessageRequestSchema, type MessageRoutesBehaviorOptions, type MessageRoutesConstructionOptions, type MessageRoutesInjectionOptions, type MessageRoutesOptions, MessageSchema, type MessageSchemaConfig, MessageService, type MessageServiceModelNames, type MessageServiceOptions, type MessageTemplate, type MessageTransactionCleanupFailureEvent, type MessageTransactionCleanupFailureObserver, MessageTransactionRequiredError, type MessageType, type MessageUser, NoopEmailProvider, NoopPaymentProvider, type PaymentCompensationFailureEvent, type PaymentProvider, PaymentProviderRequiredError, PaymentSessionCompensationAggregateError, PaymentSessionCompensationError, type PaymentSessionCompensationFailure, type PrepareContext, type PrepareResult, type PublicMessageDto, type PublicMessageParty, type PublicMessageSource, type RegisteredMessageAction, type RegisteredMessageTemplate, type RegisteredUiTemplate, type SenderNotificationContent, TemplateNotFoundError, TemplateRegistry, TemplateRegistryValidationError, type UiTemplate, type UserId, type Usertype, buildMessageArchiveSchema, buildMessageRequestSchema, buildMessageSchema, createMessageRoutes, defaultRegistry, filterActions, hasExplicitPermissionGrant, includesAction, interpolateMessageContent, interpolateTemplate, isActionAllowed, isValidMessageUserId, requireMessageUserId, resolveUiTemplate, serializePublicMessage };