@consilioweb/payload-support 1.1.0 → 2.0.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 (99) hide show
  1. package/README.md +4 -0
  2. package/dist/components/TicketConversation/components/AISummaryPanel.cjs +22 -14
  3. package/dist/components/TicketConversation/components/AISummaryPanel.js +23 -16
  4. package/dist/components/TicketConversation/components/ActionPanels.cjs +5 -5
  5. package/dist/components/TicketConversation/components/ActionPanels.js +5 -5
  6. package/dist/components/TicketConversation/components/ClientBar.cjs +1 -1
  7. package/dist/components/TicketConversation/components/ClientBar.js +1 -1
  8. package/dist/components/TicketConversation/components/QuickActions.cjs +2 -2
  9. package/dist/components/TicketConversation/components/QuickActions.js +2 -2
  10. package/dist/components/TicketConversation/components/TicketHeader.cjs +1 -1
  11. package/dist/components/TicketConversation/components/TicketHeader.js +1 -1
  12. package/dist/components/TicketConversation/index.cjs +10 -10
  13. package/dist/components/TicketConversation/index.js +10 -10
  14. package/dist/index.cjs +710 -174
  15. package/dist/index.d.cts +165 -3
  16. package/dist/index.d.ts +165 -3
  17. package/dist/index.js +703 -176
  18. package/dist/styles/ChatView.module.scss +1 -1
  19. package/dist/styles/TicketDetail.module.scss +3 -3
  20. package/dist/styles/_tokens.scss +1 -1
  21. package/dist/styles/theme.css +6 -6
  22. package/dist/views/TicketingSettingsView/client.cjs +3 -3
  23. package/dist/views/TicketingSettingsView/client.js +3 -3
  24. package/package.json +9 -9
  25. package/src/__tests__/aiSummaryRendering.test.ts +21 -0
  26. package/src/__tests__/authResponses.test.ts +69 -0
  27. package/src/__tests__/capabilities.test.ts +71 -0
  28. package/src/__tests__/generateTrackingToken.test.ts +18 -4
  29. package/src/__tests__/integration/core-behaviors.test.ts +23 -0
  30. package/src/__tests__/rateLimiter.test.ts +60 -66
  31. package/src/__tests__/trackOpenEndpoint.test.ts +54 -0
  32. package/src/__tests__/webhookSecurity.test.ts +58 -0
  33. package/src/collections/PendingEmails.ts +2 -1
  34. package/src/collections/SupportClients.ts +43 -1
  35. package/src/collections/SupportCounters.ts +14 -0
  36. package/src/collections/SupportRateLimits.ts +20 -0
  37. package/src/collections/TicketMessages.ts +76 -0
  38. package/src/collections/Tickets.ts +183 -40
  39. package/src/collections/index.ts +2 -0
  40. package/src/components/TicketConversation/components/AISummaryPanel.tsx +26 -13
  41. package/src/components/TicketConversation/components/ActionPanels.tsx +5 -5
  42. package/src/components/TicketConversation/components/ClientBar.tsx +1 -1
  43. package/src/components/TicketConversation/components/QuickActions.tsx +2 -2
  44. package/src/components/TicketConversation/components/TicketHeader.tsx +1 -1
  45. package/src/components/TicketConversation/index.tsx +10 -10
  46. package/src/endpoints/admin-chat.ts +4 -4
  47. package/src/endpoints/ai-agent.ts +6 -1
  48. package/src/endpoints/ai.ts +10 -5
  49. package/src/endpoints/auth-2fa.ts +6 -7
  50. package/src/endpoints/auto-close.ts +2 -1
  51. package/src/endpoints/capabilities.ts +144 -0
  52. package/src/endpoints/channels.ts +2 -1
  53. package/src/endpoints/chat.ts +6 -6
  54. package/src/endpoints/chatbot.ts +4 -4
  55. package/src/endpoints/client-intelligence.ts +13 -4
  56. package/src/endpoints/import-conversation.ts +6 -5
  57. package/src/endpoints/index.ts +35 -14
  58. package/src/endpoints/invite-collaborator.ts +4 -4
  59. package/src/endpoints/login.ts +4 -5
  60. package/src/endpoints/oauth-google.ts +1 -1
  61. package/src/endpoints/process-digests.ts +2 -1
  62. package/src/endpoints/process-scheduled.ts +2 -1
  63. package/src/endpoints/process-snooze.ts +2 -1
  64. package/src/endpoints/resend-notification.ts +4 -4
  65. package/src/endpoints/send-reminder.ts +4 -4
  66. package/src/endpoints/ticket-synthesis.ts +17 -2
  67. package/src/endpoints/track-open.ts +44 -21
  68. package/src/endpoints/transfer-ticket.ts +4 -4
  69. package/src/index.ts +7 -0
  70. package/src/plugin.ts +16 -1
  71. package/src/portal/LiveChat.tsx +1 -1
  72. package/src/portal/auth/ChatWidget.tsx +4 -4
  73. package/src/portal/auth/ChatbotWidget.tsx +4 -4
  74. package/src/portal/auth/dashboard/DashboardClient.tsx +2 -2
  75. package/src/portal/auth/faq/FAQSearch.tsx +1 -1
  76. package/src/portal/auth/faq/page.tsx +2 -2
  77. package/src/portal/auth/profile/page.tsx +17 -17
  78. package/src/portal/auth/tickets/detail/CloseTicketButton.tsx +1 -1
  79. package/src/portal/auth/tickets/detail/MarkSolutionButton.tsx +1 -1
  80. package/src/portal/auth/tickets/detail/ReopenTicketButton.tsx +1 -1
  81. package/src/portal/auth/tickets/detail/SatisfactionForm.tsx +3 -3
  82. package/src/portal/auth/tickets/detail/TicketReplyForm.tsx +3 -3
  83. package/src/portal/auth/tickets/detail/page.tsx +5 -5
  84. package/src/portal/auth/tickets/new/page.tsx +8 -8
  85. package/src/portal/forgot-password/page.tsx +3 -3
  86. package/src/portal/layout.tsx +5 -2
  87. package/src/portal/login/page.tsx +7 -7
  88. package/src/portal/page.tsx +9 -9
  89. package/src/portal/register/page.tsx +4 -4
  90. package/src/portal/reset-password/page.tsx +3 -3
  91. package/src/styles/ChatView.module.scss +1 -1
  92. package/src/styles/TicketDetail.module.scss +3 -3
  93. package/src/styles/_tokens.scss +1 -1
  94. package/src/styles/theme.css +6 -6
  95. package/src/types.ts +71 -0
  96. package/src/utils/rateLimiter.ts +131 -38
  97. package/src/utils/slugs.ts +4 -0
  98. package/src/utils/webhookSecurity.ts +81 -0
  99. package/src/views/TicketingSettingsView/client.tsx +3 -3
package/dist/index.d.cts CHANGED
@@ -1,4 +1,69 @@
1
- import { Plugin, Payload, BasePayload, CollectionAfterChangeHook, CollectionConfig } from 'payload';
1
+ import { Payload, PayloadRequest, Plugin, Endpoint, BasePayload, CollectionAfterChangeHook, CollectionConfig } from 'payload';
2
+
3
+ interface RateLimitEntry {
4
+ count: number;
5
+ resetAt: number;
6
+ }
7
+ interface RateLimitStore {
8
+ increment(key: string, windowMs: number, context?: unknown): Promise<RateLimitEntry>;
9
+ reset(key: string, context?: unknown): Promise<void>;
10
+ }
11
+ /**
12
+ * Process-local fallback store. Applications running more than one process
13
+ * should provide a persistent RateLimitStore through the plugin options.
14
+ */
15
+ declare class MemoryRateLimitStore implements RateLimitStore {
16
+ private readonly entries;
17
+ increment(key: string, windowMs: number): Promise<RateLimitEntry>;
18
+ reset(key: string): Promise<void>;
19
+ }
20
+ declare class PayloadRateLimitStore implements RateLimitStore {
21
+ private readonly collectionSlug;
22
+ constructor(collectionSlug?: string);
23
+ increment(key: string, windowMs: number, context?: unknown): Promise<RateLimitEntry>;
24
+ reset(key: string, context?: unknown): Promise<void>;
25
+ private resolveContext;
26
+ }
27
+ declare class RateLimiter {
28
+ private readonly windowMs;
29
+ private readonly maxRequests;
30
+ private readonly store;
31
+ constructor(windowMs: number, maxRequests: number, store?: RateLimitStore);
32
+ check(key: string, context?: unknown): Promise<boolean>;
33
+ reset(key: string, context?: unknown): Promise<void>;
34
+ }
35
+
36
+ interface InboundEmailLimits {
37
+ maxRequestBytes: number;
38
+ maxAttachmentBytes: number;
39
+ maxAttachments: number;
40
+ maxSubjectLength: number;
41
+ maxNameLength: number;
42
+ maxEmailLength: number;
43
+ maxBodyLength: number;
44
+ }
45
+ declare const DEFAULT_INBOUND_EMAIL_LIMITS: InboundEmailLimits;
46
+ interface InboundAttachment {
47
+ filename?: string;
48
+ size?: number;
49
+ content?: string;
50
+ }
51
+ interface InboundEmailInput {
52
+ senderEmail?: string;
53
+ senderName?: string;
54
+ recipientEmail?: string;
55
+ cc?: string;
56
+ subject?: string;
57
+ body?: string;
58
+ htmlBody?: string;
59
+ attachments?: InboundAttachment[];
60
+ }
61
+ interface InboundEmailValidationError {
62
+ code: 'request_too_large' | 'too_many_attachments' | 'attachment_too_large' | 'text_field_too_large';
63
+ status: 413;
64
+ }
65
+ declare function verifySecret(provided: string | null | undefined, expected: string | null | undefined): boolean;
66
+ declare function validateInboundEmailPayload(input: InboundEmailInput, contentLength?: number, limits?: InboundEmailLimits): InboundEmailValidationError | null;
2
67
 
3
68
  interface SupportFeatures {
4
69
  /** Time tracking: timer, manual entries, billing */
@@ -69,6 +134,59 @@ interface EmailConfig {
69
134
  fromName?: string;
70
135
  replyTo?: string;
71
136
  }
137
+ interface SmsSendResult {
138
+ sent: boolean;
139
+ skipped?: boolean;
140
+ error?: string;
141
+ }
142
+ interface SmsAdapter {
143
+ isConfigured?: () => boolean;
144
+ send: (input: {
145
+ message: string;
146
+ to: string;
147
+ payload: Payload;
148
+ ticket: Record<string, unknown>;
149
+ client: Record<string, unknown>;
150
+ }) => Promise<SmsSendResult>;
151
+ }
152
+ interface SupportCapabilities {
153
+ /** Optional SMS transport. The module never depends on a concrete provider. */
154
+ sms?: {
155
+ adapter: SmsAdapter;
156
+ buildMessage?: (input: {
157
+ client: Record<string, unknown>;
158
+ ticket: Record<string, unknown>;
159
+ }) => string | Promise<string>;
160
+ };
161
+ /** Native daily/weekly notification queue. */
162
+ digests?: boolean;
163
+ /** Incoming email business adapter, protected and validated by the module. */
164
+ inboundEmail?: {
165
+ handle: (req: PayloadRequest, input: InboundEmailInput) => Promise<Response>;
166
+ secret?: string;
167
+ secretHeader?: string;
168
+ };
169
+ /** Generate a short, editable display title after ticket creation. */
170
+ aiTitles?: {
171
+ generate: (payload: Payload, ticketId: number | string) => Promise<unknown>;
172
+ };
173
+ /** Override the module's default resolved-ticket synthesis generator. */
174
+ aiSummaries?: {
175
+ generate: (payload: Payload, ticketId: number | string) => Promise<unknown>;
176
+ };
177
+ /** Persist billing lines and their invoicing state. */
178
+ detailedBilling?: boolean;
179
+ /** Persist pro-bono work and its estimated value. */
180
+ volunteering?: boolean;
181
+ /** Best-effort cleanup of noisy messages after an inbound client reply. */
182
+ threadCleanup?: {
183
+ clean: (payload: Payload, ticketId: number | string, messageId: number | string) => Promise<unknown>;
184
+ };
185
+ /** Deployment-specific project suggestion adapter. */
186
+ projectSuggestions?: {
187
+ suggest: (req: PayloadRequest) => Promise<Response>;
188
+ };
189
+ }
72
190
  interface SupportPluginConfig {
73
191
  /** Enable/disable individual features (all enabled by default) */
74
192
  features?: SupportFeatures;
@@ -76,6 +194,15 @@ interface SupportPluginConfig {
76
194
  ai?: AIProviderConfig;
77
195
  /** Email configuration for ticket notifications */
78
196
  email?: EmailConfig;
197
+ /** Shared rate-limit storage. Defaults to process-local memory. */
198
+ rateLimitStore?: RateLimitStore | 'payload';
199
+ /** Sequential ticket number formatting. */
200
+ ticketNumber?: {
201
+ prefix?: string;
202
+ padding?: number;
203
+ };
204
+ /** Optional generic capabilities backed by deployment-specific adapters. */
205
+ capabilities?: SupportCapabilities;
79
206
  /** Locale: 'fr' or 'en' (default: 'fr') */
80
207
  locale?: 'fr' | 'en';
81
208
  /** Nav group label in Payload admin sidebar */
@@ -116,6 +243,8 @@ interface SupportPluginConfig {
116
243
  macros?: string;
117
244
  ticketStatuses?: string;
118
245
  ticketFeedback?: string;
246
+ rateLimits?: string;
247
+ counters?: string;
119
248
  };
120
249
  /** Admin notification collection slug (default: 'admin-notifications') */
121
250
  notificationSlug?: string;
@@ -241,6 +370,8 @@ interface CollectionSlugs {
241
370
  automationRules: string;
242
371
  supportTeams: string;
243
372
  pushSubscriptions: string;
373
+ rateLimits: string;
374
+ counters: string;
244
375
  users: string;
245
376
  media: string;
246
377
  }
@@ -285,6 +416,29 @@ declare const DEFAULT_USER_PREFS: UserPrefs;
285
416
  declare function readSupportSettings(payload: Payload): Promise<SupportSettings>;
286
417
  declare function readUserPrefs(payload: Payload, userId: string | number): Promise<UserPrefs>;
287
418
 
419
+ /**
420
+ * POST /api/support/oauth/google
421
+ * Google OAuth — handles both login redirect and callback.
422
+ * Body: { action: 'login' } or { code: string, state: string, cookieState: string }
423
+ */
424
+ interface OAuthGoogleOptions {
425
+ allowedEmailDomains?: string[];
426
+ }
427
+ declare function createOAuthGoogleEndpoint(slugs: CollectionSlugs, options?: OAuthGoogleOptions): Endpoint;
428
+
429
+ /**
430
+ * GET /api/support/track-open?t=<ticketId>&m=<messageId>&sig=<hmac>
431
+ * Tracking pixel for email open detection. No auth required.
432
+ * Validates HMAC signature to prevent enumeration attacks.
433
+ */
434
+ declare function createTrackOpenEndpoint(slugs: CollectionSlugs): Endpoint;
435
+
436
+ /**
437
+ * POST /api/support/login
438
+ * Client login endpoint.
439
+ */
440
+ declare function createLoginEndpoint(slugs: CollectionSlugs, store?: RateLimitStore): Endpoint;
441
+
288
442
  /**
289
443
  * Helper to create an admin notification.
290
444
  * Can be called from any hook or endpoint.
@@ -370,13 +524,21 @@ declare function createTicketsCollection(slugs: CollectionSlugs, options?: {
370
524
  projectCollectionSlug?: string;
371
525
  documentsCollectionSlug?: string;
372
526
  notificationSlug?: string;
527
+ ticketNumber?: {
528
+ prefix?: string;
529
+ padding?: number;
530
+ };
531
+ capabilities?: SupportCapabilities;
373
532
  }): CollectionConfig;
374
533
 
375
534
  declare function createTicketMessagesCollection(slugs: CollectionSlugs, options?: {
376
535
  notificationSlug?: string;
536
+ capabilities?: SupportCapabilities;
377
537
  }): CollectionConfig;
378
538
 
379
- declare function createSupportClientsCollection(slugs: CollectionSlugs): CollectionConfig;
539
+ declare function createSupportClientsCollection(slugs: CollectionSlugs, options?: {
540
+ capabilities?: SupportCapabilities;
541
+ }): CollectionConfig;
380
542
 
381
543
  declare function createTimeEntriesCollection(slugs: CollectionSlugs): CollectionConfig;
382
544
 
@@ -416,4 +578,4 @@ declare function createTicketStatusesCollection(slugs: CollectionSlugs): Collect
416
578
  */
417
579
  declare function createTicketCollaboratorsCollection(slugs: CollectionSlugs): CollectionConfig;
418
580
 
419
- export { type AIProviderConfig, type ActivityEntryData, type CannedResponseData, type ClientData, type CollectionSlugs, DEFAULT_FEATURES, DEFAULT_SETTINGS, DEFAULT_SLUGS, DEFAULT_USER_PREFS, type EmailConfig, type MessageData, type SatisfactionSurveyData, type SupportFeatures, type SupportPluginConfig, type SupportSettings, type TicketData, type TicketSynthesisResult, type TimeEntryData, type UserPrefs, calculateBusinessHoursDeadline, createAdminNotification, createAssignSlaDeadlines, createAuthLogsCollection, createCannedResponsesCollection, createChatMessagesCollection, createCheckSlaOnReply, createCheckSlaOnResolve, createEmailLogsCollection, createKnowledgeBaseCollection, createMacrosCollection, createPendingEmailsCollection, createSatisfactionSurveysCollection, createSlaPoliciesCollection, createSupportClientsCollection, createTicketActivityLogCollection, createTicketCollaboratorsCollection, createTicketMessagesCollection, createTicketStatusEmail, createTicketStatusesCollection, createTicketsCollection, createTimeEntriesCollection, createWebhookEndpointsCollection, dispatchWebhook, generateTicketSynthesis, readSupportSettings, readUserPrefs, resolveSlugs, supportPlugin };
581
+ export { type AIProviderConfig, type ActivityEntryData, type CannedResponseData, type ClientData, type CollectionSlugs, DEFAULT_FEATURES, DEFAULT_INBOUND_EMAIL_LIMITS, DEFAULT_SETTINGS, DEFAULT_SLUGS, DEFAULT_USER_PREFS, type EmailConfig, type InboundEmailInput, type InboundEmailLimits, type InboundEmailValidationError, MemoryRateLimitStore, type MessageData, PayloadRateLimitStore, type RateLimitEntry, type RateLimitStore, RateLimiter, type SatisfactionSurveyData, type SupportFeatures, type SupportPluginConfig, type SupportSettings, type TicketData, type TicketSynthesisResult, type TimeEntryData, type UserPrefs, calculateBusinessHoursDeadline, createAdminNotification, createAssignSlaDeadlines, createAuthLogsCollection, createCannedResponsesCollection, createChatMessagesCollection, createCheckSlaOnReply, createCheckSlaOnResolve, createEmailLogsCollection, createKnowledgeBaseCollection, createLoginEndpoint, createMacrosCollection, createOAuthGoogleEndpoint, createPendingEmailsCollection, createSatisfactionSurveysCollection, createSlaPoliciesCollection, createSupportClientsCollection, createTicketActivityLogCollection, createTicketCollaboratorsCollection, createTicketMessagesCollection, createTicketStatusEmail, createTicketStatusesCollection, createTicketsCollection, createTimeEntriesCollection, createTrackOpenEndpoint, createWebhookEndpointsCollection, dispatchWebhook, generateTicketSynthesis, readSupportSettings, readUserPrefs, resolveSlugs, supportPlugin, validateInboundEmailPayload, verifySecret };
package/dist/index.d.ts CHANGED
@@ -1,4 +1,69 @@
1
- import { Plugin, Payload, BasePayload, CollectionAfterChangeHook, CollectionConfig } from 'payload';
1
+ import { Payload, PayloadRequest, Plugin, Endpoint, BasePayload, CollectionAfterChangeHook, CollectionConfig } from 'payload';
2
+
3
+ interface RateLimitEntry {
4
+ count: number;
5
+ resetAt: number;
6
+ }
7
+ interface RateLimitStore {
8
+ increment(key: string, windowMs: number, context?: unknown): Promise<RateLimitEntry>;
9
+ reset(key: string, context?: unknown): Promise<void>;
10
+ }
11
+ /**
12
+ * Process-local fallback store. Applications running more than one process
13
+ * should provide a persistent RateLimitStore through the plugin options.
14
+ */
15
+ declare class MemoryRateLimitStore implements RateLimitStore {
16
+ private readonly entries;
17
+ increment(key: string, windowMs: number): Promise<RateLimitEntry>;
18
+ reset(key: string): Promise<void>;
19
+ }
20
+ declare class PayloadRateLimitStore implements RateLimitStore {
21
+ private readonly collectionSlug;
22
+ constructor(collectionSlug?: string);
23
+ increment(key: string, windowMs: number, context?: unknown): Promise<RateLimitEntry>;
24
+ reset(key: string, context?: unknown): Promise<void>;
25
+ private resolveContext;
26
+ }
27
+ declare class RateLimiter {
28
+ private readonly windowMs;
29
+ private readonly maxRequests;
30
+ private readonly store;
31
+ constructor(windowMs: number, maxRequests: number, store?: RateLimitStore);
32
+ check(key: string, context?: unknown): Promise<boolean>;
33
+ reset(key: string, context?: unknown): Promise<void>;
34
+ }
35
+
36
+ interface InboundEmailLimits {
37
+ maxRequestBytes: number;
38
+ maxAttachmentBytes: number;
39
+ maxAttachments: number;
40
+ maxSubjectLength: number;
41
+ maxNameLength: number;
42
+ maxEmailLength: number;
43
+ maxBodyLength: number;
44
+ }
45
+ declare const DEFAULT_INBOUND_EMAIL_LIMITS: InboundEmailLimits;
46
+ interface InboundAttachment {
47
+ filename?: string;
48
+ size?: number;
49
+ content?: string;
50
+ }
51
+ interface InboundEmailInput {
52
+ senderEmail?: string;
53
+ senderName?: string;
54
+ recipientEmail?: string;
55
+ cc?: string;
56
+ subject?: string;
57
+ body?: string;
58
+ htmlBody?: string;
59
+ attachments?: InboundAttachment[];
60
+ }
61
+ interface InboundEmailValidationError {
62
+ code: 'request_too_large' | 'too_many_attachments' | 'attachment_too_large' | 'text_field_too_large';
63
+ status: 413;
64
+ }
65
+ declare function verifySecret(provided: string | null | undefined, expected: string | null | undefined): boolean;
66
+ declare function validateInboundEmailPayload(input: InboundEmailInput, contentLength?: number, limits?: InboundEmailLimits): InboundEmailValidationError | null;
2
67
 
3
68
  interface SupportFeatures {
4
69
  /** Time tracking: timer, manual entries, billing */
@@ -69,6 +134,59 @@ interface EmailConfig {
69
134
  fromName?: string;
70
135
  replyTo?: string;
71
136
  }
137
+ interface SmsSendResult {
138
+ sent: boolean;
139
+ skipped?: boolean;
140
+ error?: string;
141
+ }
142
+ interface SmsAdapter {
143
+ isConfigured?: () => boolean;
144
+ send: (input: {
145
+ message: string;
146
+ to: string;
147
+ payload: Payload;
148
+ ticket: Record<string, unknown>;
149
+ client: Record<string, unknown>;
150
+ }) => Promise<SmsSendResult>;
151
+ }
152
+ interface SupportCapabilities {
153
+ /** Optional SMS transport. The module never depends on a concrete provider. */
154
+ sms?: {
155
+ adapter: SmsAdapter;
156
+ buildMessage?: (input: {
157
+ client: Record<string, unknown>;
158
+ ticket: Record<string, unknown>;
159
+ }) => string | Promise<string>;
160
+ };
161
+ /** Native daily/weekly notification queue. */
162
+ digests?: boolean;
163
+ /** Incoming email business adapter, protected and validated by the module. */
164
+ inboundEmail?: {
165
+ handle: (req: PayloadRequest, input: InboundEmailInput) => Promise<Response>;
166
+ secret?: string;
167
+ secretHeader?: string;
168
+ };
169
+ /** Generate a short, editable display title after ticket creation. */
170
+ aiTitles?: {
171
+ generate: (payload: Payload, ticketId: number | string) => Promise<unknown>;
172
+ };
173
+ /** Override the module's default resolved-ticket synthesis generator. */
174
+ aiSummaries?: {
175
+ generate: (payload: Payload, ticketId: number | string) => Promise<unknown>;
176
+ };
177
+ /** Persist billing lines and their invoicing state. */
178
+ detailedBilling?: boolean;
179
+ /** Persist pro-bono work and its estimated value. */
180
+ volunteering?: boolean;
181
+ /** Best-effort cleanup of noisy messages after an inbound client reply. */
182
+ threadCleanup?: {
183
+ clean: (payload: Payload, ticketId: number | string, messageId: number | string) => Promise<unknown>;
184
+ };
185
+ /** Deployment-specific project suggestion adapter. */
186
+ projectSuggestions?: {
187
+ suggest: (req: PayloadRequest) => Promise<Response>;
188
+ };
189
+ }
72
190
  interface SupportPluginConfig {
73
191
  /** Enable/disable individual features (all enabled by default) */
74
192
  features?: SupportFeatures;
@@ -76,6 +194,15 @@ interface SupportPluginConfig {
76
194
  ai?: AIProviderConfig;
77
195
  /** Email configuration for ticket notifications */
78
196
  email?: EmailConfig;
197
+ /** Shared rate-limit storage. Defaults to process-local memory. */
198
+ rateLimitStore?: RateLimitStore | 'payload';
199
+ /** Sequential ticket number formatting. */
200
+ ticketNumber?: {
201
+ prefix?: string;
202
+ padding?: number;
203
+ };
204
+ /** Optional generic capabilities backed by deployment-specific adapters. */
205
+ capabilities?: SupportCapabilities;
79
206
  /** Locale: 'fr' or 'en' (default: 'fr') */
80
207
  locale?: 'fr' | 'en';
81
208
  /** Nav group label in Payload admin sidebar */
@@ -116,6 +243,8 @@ interface SupportPluginConfig {
116
243
  macros?: string;
117
244
  ticketStatuses?: string;
118
245
  ticketFeedback?: string;
246
+ rateLimits?: string;
247
+ counters?: string;
119
248
  };
120
249
  /** Admin notification collection slug (default: 'admin-notifications') */
121
250
  notificationSlug?: string;
@@ -241,6 +370,8 @@ interface CollectionSlugs {
241
370
  automationRules: string;
242
371
  supportTeams: string;
243
372
  pushSubscriptions: string;
373
+ rateLimits: string;
374
+ counters: string;
244
375
  users: string;
245
376
  media: string;
246
377
  }
@@ -285,6 +416,29 @@ declare const DEFAULT_USER_PREFS: UserPrefs;
285
416
  declare function readSupportSettings(payload: Payload): Promise<SupportSettings>;
286
417
  declare function readUserPrefs(payload: Payload, userId: string | number): Promise<UserPrefs>;
287
418
 
419
+ /**
420
+ * POST /api/support/oauth/google
421
+ * Google OAuth — handles both login redirect and callback.
422
+ * Body: { action: 'login' } or { code: string, state: string, cookieState: string }
423
+ */
424
+ interface OAuthGoogleOptions {
425
+ allowedEmailDomains?: string[];
426
+ }
427
+ declare function createOAuthGoogleEndpoint(slugs: CollectionSlugs, options?: OAuthGoogleOptions): Endpoint;
428
+
429
+ /**
430
+ * GET /api/support/track-open?t=<ticketId>&m=<messageId>&sig=<hmac>
431
+ * Tracking pixel for email open detection. No auth required.
432
+ * Validates HMAC signature to prevent enumeration attacks.
433
+ */
434
+ declare function createTrackOpenEndpoint(slugs: CollectionSlugs): Endpoint;
435
+
436
+ /**
437
+ * POST /api/support/login
438
+ * Client login endpoint.
439
+ */
440
+ declare function createLoginEndpoint(slugs: CollectionSlugs, store?: RateLimitStore): Endpoint;
441
+
288
442
  /**
289
443
  * Helper to create an admin notification.
290
444
  * Can be called from any hook or endpoint.
@@ -370,13 +524,21 @@ declare function createTicketsCollection(slugs: CollectionSlugs, options?: {
370
524
  projectCollectionSlug?: string;
371
525
  documentsCollectionSlug?: string;
372
526
  notificationSlug?: string;
527
+ ticketNumber?: {
528
+ prefix?: string;
529
+ padding?: number;
530
+ };
531
+ capabilities?: SupportCapabilities;
373
532
  }): CollectionConfig;
374
533
 
375
534
  declare function createTicketMessagesCollection(slugs: CollectionSlugs, options?: {
376
535
  notificationSlug?: string;
536
+ capabilities?: SupportCapabilities;
377
537
  }): CollectionConfig;
378
538
 
379
- declare function createSupportClientsCollection(slugs: CollectionSlugs): CollectionConfig;
539
+ declare function createSupportClientsCollection(slugs: CollectionSlugs, options?: {
540
+ capabilities?: SupportCapabilities;
541
+ }): CollectionConfig;
380
542
 
381
543
  declare function createTimeEntriesCollection(slugs: CollectionSlugs): CollectionConfig;
382
544
 
@@ -416,4 +578,4 @@ declare function createTicketStatusesCollection(slugs: CollectionSlugs): Collect
416
578
  */
417
579
  declare function createTicketCollaboratorsCollection(slugs: CollectionSlugs): CollectionConfig;
418
580
 
419
- export { type AIProviderConfig, type ActivityEntryData, type CannedResponseData, type ClientData, type CollectionSlugs, DEFAULT_FEATURES, DEFAULT_SETTINGS, DEFAULT_SLUGS, DEFAULT_USER_PREFS, type EmailConfig, type MessageData, type SatisfactionSurveyData, type SupportFeatures, type SupportPluginConfig, type SupportSettings, type TicketData, type TicketSynthesisResult, type TimeEntryData, type UserPrefs, calculateBusinessHoursDeadline, createAdminNotification, createAssignSlaDeadlines, createAuthLogsCollection, createCannedResponsesCollection, createChatMessagesCollection, createCheckSlaOnReply, createCheckSlaOnResolve, createEmailLogsCollection, createKnowledgeBaseCollection, createMacrosCollection, createPendingEmailsCollection, createSatisfactionSurveysCollection, createSlaPoliciesCollection, createSupportClientsCollection, createTicketActivityLogCollection, createTicketCollaboratorsCollection, createTicketMessagesCollection, createTicketStatusEmail, createTicketStatusesCollection, createTicketsCollection, createTimeEntriesCollection, createWebhookEndpointsCollection, dispatchWebhook, generateTicketSynthesis, readSupportSettings, readUserPrefs, resolveSlugs, supportPlugin };
581
+ export { type AIProviderConfig, type ActivityEntryData, type CannedResponseData, type ClientData, type CollectionSlugs, DEFAULT_FEATURES, DEFAULT_INBOUND_EMAIL_LIMITS, DEFAULT_SETTINGS, DEFAULT_SLUGS, DEFAULT_USER_PREFS, type EmailConfig, type InboundEmailInput, type InboundEmailLimits, type InboundEmailValidationError, MemoryRateLimitStore, type MessageData, PayloadRateLimitStore, type RateLimitEntry, type RateLimitStore, RateLimiter, type SatisfactionSurveyData, type SupportFeatures, type SupportPluginConfig, type SupportSettings, type TicketData, type TicketSynthesisResult, type TimeEntryData, type UserPrefs, calculateBusinessHoursDeadline, createAdminNotification, createAssignSlaDeadlines, createAuthLogsCollection, createCannedResponsesCollection, createChatMessagesCollection, createCheckSlaOnReply, createCheckSlaOnResolve, createEmailLogsCollection, createKnowledgeBaseCollection, createLoginEndpoint, createMacrosCollection, createOAuthGoogleEndpoint, createPendingEmailsCollection, createSatisfactionSurveysCollection, createSlaPoliciesCollection, createSupportClientsCollection, createTicketActivityLogCollection, createTicketCollaboratorsCollection, createTicketMessagesCollection, createTicketStatusEmail, createTicketStatusesCollection, createTicketsCollection, createTimeEntriesCollection, createTrackOpenEndpoint, createWebhookEndpointsCollection, dispatchWebhook, generateTicketSynthesis, readSupportSettings, readUserPrefs, resolveSlugs, supportPlugin, validateInboundEmailPayload, verifySecret };