@consilioweb/payload-support 1.1.1 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +74 -3
- package/dist/components/TicketConversation/components/AISummaryPanel.cjs +22 -14
- package/dist/components/TicketConversation/components/AISummaryPanel.js +23 -16
- package/dist/components/TicketConversation/components/ActionPanels.cjs +5 -5
- package/dist/components/TicketConversation/components/ActionPanels.js +5 -5
- package/dist/components/TicketConversation/components/ClientBar.cjs +1 -1
- package/dist/components/TicketConversation/components/ClientBar.js +1 -1
- package/dist/components/TicketConversation/components/QuickActions.cjs +2 -2
- package/dist/components/TicketConversation/components/QuickActions.js +2 -2
- package/dist/components/TicketConversation/components/TicketHeader.cjs +1 -1
- package/dist/components/TicketConversation/components/TicketHeader.js +1 -1
- package/dist/components/TicketConversation/hooks/useTranslation.cjs +25 -2
- package/dist/components/TicketConversation/hooks/useTranslation.js +22 -3
- package/dist/components/TicketConversation/index.cjs +10 -10
- package/dist/components/TicketConversation/index.js +10 -10
- package/dist/index.cjs +709 -173
- package/dist/index.d.cts +165 -3
- package/dist/index.d.ts +165 -3
- package/dist/index.js +702 -175
- package/dist/styles/ChatView.module.scss +1 -1
- package/dist/styles/TicketDetail.module.scss +3 -3
- package/dist/styles/_tokens.scss +1 -1
- package/dist/styles/theme.css +6 -6
- package/dist/views/SupportDashboardView/client.cjs +1 -1
- package/dist/views/SupportDashboardView/client.js +1 -1
- package/dist/views/TicketingSettingsView/client.cjs +4 -4
- package/dist/views/TicketingSettingsView/client.js +4 -4
- package/dist/views/shared/locales/en.json +708 -0
- package/dist/views/shared/locales/fr.json +708 -0
- package/package.json +19 -19
- package/src/__tests__/aiSummaryRendering.test.ts +21 -0
- package/src/__tests__/authResponses.test.ts +69 -0
- package/src/__tests__/capabilities.test.ts +71 -0
- package/src/__tests__/generateTrackingToken.test.ts +18 -4
- package/src/__tests__/integration/core-behaviors.test.ts +23 -0
- package/src/__tests__/rateLimiter.test.ts +60 -66
- package/src/__tests__/trackOpenEndpoint.test.ts +54 -0
- package/src/__tests__/translations.test.ts +67 -0
- package/src/__tests__/webhookSecurity.test.ts +58 -0
- package/src/collections/PendingEmails.ts +2 -1
- package/src/collections/SupportClients.ts +43 -1
- package/src/collections/SupportCounters.ts +14 -0
- package/src/collections/SupportRateLimits.ts +20 -0
- package/src/collections/TicketMessages.ts +76 -0
- package/src/collections/Tickets.ts +179 -39
- package/src/collections/index.ts +2 -0
- package/src/components/TicketConversation/components/AISummaryPanel.tsx +26 -13
- package/src/components/TicketConversation/components/ActionPanels.tsx +5 -5
- package/src/components/TicketConversation/components/ClientBar.tsx +1 -1
- package/src/components/TicketConversation/components/QuickActions.tsx +2 -2
- package/src/components/TicketConversation/components/TicketHeader.tsx +1 -1
- package/src/components/TicketConversation/hooks/useTranslation.ts +38 -4
- package/src/components/TicketConversation/index.tsx +10 -10
- package/src/endpoints/admin-chat.ts +4 -4
- package/src/endpoints/ai-agent.ts +6 -1
- package/src/endpoints/ai.ts +10 -5
- package/src/endpoints/auth-2fa.ts +6 -7
- package/src/endpoints/auto-close.ts +2 -1
- package/src/endpoints/capabilities.ts +144 -0
- package/src/endpoints/channels.ts +2 -1
- package/src/endpoints/chat.ts +6 -6
- package/src/endpoints/chatbot.ts +4 -4
- package/src/endpoints/client-intelligence.ts +13 -4
- package/src/endpoints/import-conversation.ts +6 -5
- package/src/endpoints/index.ts +35 -14
- package/src/endpoints/invite-collaborator.ts +4 -4
- package/src/endpoints/login.ts +4 -5
- package/src/endpoints/oauth-google.ts +1 -1
- package/src/endpoints/process-digests.ts +2 -1
- package/src/endpoints/process-scheduled.ts +2 -1
- package/src/endpoints/process-snooze.ts +2 -1
- package/src/endpoints/resend-notification.ts +4 -4
- package/src/endpoints/send-reminder.ts +4 -4
- package/src/endpoints/ticket-synthesis.ts +17 -2
- package/src/endpoints/track-open.ts +44 -21
- package/src/endpoints/transfer-ticket.ts +4 -4
- package/src/index.ts +7 -0
- package/src/plugin.ts +16 -1
- package/src/portal/LiveChat.tsx +1 -1
- package/src/portal/auth/ChatWidget.tsx +4 -4
- package/src/portal/auth/ChatbotWidget.tsx +4 -4
- package/src/portal/auth/dashboard/DashboardClient.tsx +2 -2
- package/src/portal/auth/faq/FAQSearch.tsx +1 -1
- package/src/portal/auth/faq/page.tsx +2 -2
- package/src/portal/auth/profile/page.tsx +17 -17
- package/src/portal/auth/tickets/detail/CloseTicketButton.tsx +1 -1
- package/src/portal/auth/tickets/detail/MarkSolutionButton.tsx +1 -1
- package/src/portal/auth/tickets/detail/ReopenTicketButton.tsx +1 -1
- package/src/portal/auth/tickets/detail/SatisfactionForm.tsx +3 -3
- package/src/portal/auth/tickets/detail/TicketReplyForm.tsx +3 -3
- package/src/portal/auth/tickets/detail/page.tsx +5 -5
- package/src/portal/auth/tickets/new/page.tsx +8 -8
- package/src/portal/forgot-password/page.tsx +3 -3
- package/src/portal/layout.tsx +5 -2
- package/src/portal/login/page.tsx +7 -7
- package/src/portal/page.tsx +9 -9
- package/src/portal/register/page.tsx +4 -4
- package/src/portal/reset-password/page.tsx +3 -3
- package/src/styles/ChatView.module.scss +1 -1
- package/src/styles/TicketDetail.module.scss +3 -3
- package/src/styles/_tokens.scss +1 -1
- package/src/styles/theme.css +6 -6
- package/src/types.ts +71 -0
- package/src/utils/rateLimiter.ts +131 -38
- package/src/utils/slugs.ts +4 -0
- package/src/utils/webhookSecurity.ts +81 -0
- package/src/views/SupportDashboardView/client.tsx +1 -1
- package/src/views/TicketingSettingsView/client.tsx +4 -4
- package/src/views/shared/locales/en.json +2 -2
- package/src/views/shared/locales/fr.json +2 -2
package/dist/index.d.cts
CHANGED
|
@@ -1,4 +1,69 @@
|
|
|
1
|
-
import { Plugin,
|
|
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
|
|
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,
|
|
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
|
|
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 };
|