@infuro/cms-core 1.0.11 → 1.0.14

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/dist/index.d.ts CHANGED
@@ -1,10 +1,11 @@
1
- import { C as CompanyDetails, T as TemplateContext, E as EmailTemplateResult, a as EmailTemplateName, O as OrderPlacedLineItem, S as StorageService } from './index-DeO4AnAj.js';
2
- export { A as AnalyticsHandlerConfig, b as AuthHandlersConfig, B as BlogBySlugConfig, c as ChangePasswordConfig, d as CmsApiHandlerConfig, e as CmsGetter, f as CrudHandlerOptions, D as DashboardStatsConfig, g as EntityMap, F as ForgotPasswordConfig, h as FormBySlugConfig, I as InviteAcceptConfig, i as SetPasswordConfig, j as SettingsApiConfig, k as SocialLinkItem, l as StorefrontApiConfig, U as UploadHandlerConfig, m as UserAuthApiConfig, n as UserAvatarConfig, o as UserProfileConfig, p as UsersApiConfig, q as createAnalyticsHandlers, r as createBlogBySlugHandler, s as createChangePasswordHandler, t as createCmsApiHandler, u as createCrudByIdHandler, v as createCrudHandler, w as createDashboardStatsHandler, x as createForgotPasswordHandler, y as createFormBySlugHandler, z as createInviteAcceptHandler, G as createSetPasswordHandler, H as createSettingsApiHandlers, J as createStorefrontApiHandler, K as createUploadHandler, L as createUserAuthApiRouter, M as createUserAvatarHandler, N as createUserProfileHandler, P as createUsersApiHandlers, Q as getCompanyDetailsFromSettings, R as mergeEmailLayoutCompanyDetails } from './index-DeO4AnAj.js';
1
+ import { C as CompanyDetails, T as TemplateContext, E as EmailTemplateResult, a as EmailTemplateName, O as OrderPlacedLineItem, S as StorageService, b as EntityMap$1 } from './index-CjBf9dAb.js';
2
+ export { A as AnalyticsHandlerConfig, c as AuthHandlersConfig, B as BlogBySlugConfig, d as ChangePasswordConfig, e as CmsApiHandlerConfig, f as CmsGetter, g as CrudHandlerOptions, D as DashboardStatsConfig, F as ForgotPasswordConfig, h as FormBySlugConfig, G as GetPublicSettingsGroupConfig, i as GetPublicSettingsGroupDataSource, I as InviteAcceptConfig, j as SetPasswordConfig, k as SettingsApiConfig, l as SocialLinkItem, m as StorefrontApiConfig, n as StorefrontOtpFlags, U as UploadHandlerConfig, o as UserAuthApiConfig, p as UserAvatarConfig, q as UserProfileConfig, r as UsersApiConfig, s as createAnalyticsHandlers, t as createBlogBySlugHandler, u as createChangePasswordHandler, v as createCmsApiHandler, w as createCrudByIdHandler, x as createCrudHandler, y as createDashboardStatsHandler, z as createForgotPasswordHandler, H as createFormBySlugHandler, J as createInviteAcceptHandler, K as createSetPasswordHandler, L as createSettingsApiHandlers, M as createStorefrontApiHandler, N as createUploadHandler, P as createUserAuthApiRouter, Q as createUserAvatarHandler, R as createUserProfileHandler, V as createUsersApiHandlers, W as getCompanyDetailsFromSettings, X as getPublicSettingsGroup, Y as mergeEmailLayoutCompanyDetails } from './index-CjBf9dAb.js';
3
3
  import { ClassValue } from 'clsx';
4
4
  import * as typeorm from 'typeorm';
5
5
  import { DataSource, EntityTarget, ObjectLiteral } from 'typeorm';
6
+ import { Metadata } from 'next';
6
7
  export { A as ADMIN_GROUP_NAME, a as AuthHelpers, E as EntityCrudAction, b as EntityPermissionFlags, G as GetSession, O as OPEN_ENDPOINTS, P as PERMISSION_REQUIRED_ENDPOINTS, R as RBAC_ADMIN_ONLY_ENTITIES, S as SessionUser, c as canManageRoles, d as createAuthHelpers, g as getPermissionableEntityKeys, e as getRequiredPermission, h as hasEntityPermission, i as isOpenEndpoint, f as isPublicMethod, j as isSuperAdminGroupName, p as permissionRowsToRecord, s as sessionHasEntityAccess } from './helpers-dlrF_49e.js';
7
- export { CmsMiddlewareConfig, NextAuthOptionsConfig, NextAuthUser, createCmsMiddleware, defaultPublicApiMethods, getNextAuthOptions, seedAdministratorPermissions } from './auth.js';
8
+ export { AuthorizeOtpInput, CmsMiddlewareConfig, NextAuthOptionsConfig, NextAuthUser, createCmsMiddleware, defaultPublicApiMethods, getNextAuthOptions, seedAdministratorPermissions } from './auth.js';
8
9
  export { A as AdminNavItem, D as DEFAULT_ADMIN_NAV } from './config-DJ5CmQvS.js';
9
10
  import 'next-auth';
10
11
 
@@ -38,27 +39,6 @@ interface CmsApp {
38
39
  }
39
40
  declare function createCmsApp(options: CreateCmsAppOptions): Promise<CmsApp>;
40
41
 
41
- interface ERPAuthToken {
42
- access_token: string;
43
- token_type: string;
44
- expires_in: number;
45
- expires_at?: number;
46
- }
47
- declare class ERPAuthService {
48
- private baseUrl;
49
- private credentials;
50
- private token;
51
- constructor(config: {
52
- baseUrl?: string;
53
- clientId: string;
54
- clientSecret: string;
55
- tenantId: string;
56
- });
57
- authenticate(): Promise<ERPAuthToken>;
58
- getValidToken(): Promise<string>;
59
- makeAuthenticatedRequest(url: string, options?: RequestInit): Promise<Response>;
60
- }
61
-
62
42
  interface ContactFormData {
63
43
  firstName: string;
64
44
  lastName: string;
@@ -69,22 +49,70 @@ interface ContactFormData {
69
49
  }
70
50
  interface ERPSubmissionResult {
71
51
  success: boolean;
72
- contactId: string;
73
- opportunityId?: string;
74
52
  error?: string;
53
+ status?: number;
54
+ }
55
+ type PipelineNames = {
56
+ pipelineName: string;
57
+ pipelineStageName: string;
58
+ };
59
+ /** Payload for ERP `create-contact` (§7c) — CRM contact upsert, no lead/opportunity row. */
60
+ interface ErpCreateContactPayload {
61
+ email: string;
62
+ firstName: string;
63
+ lastName: string;
64
+ phone?: string;
65
+ companyName?: string;
66
+ type?: string;
67
+ notes?: string;
68
+ tags?: string[];
75
69
  }
76
70
  declare class ERPSubmissionService {
77
- private baseUrl;
78
- private pipelineId;
79
- private pipelineStageId;
80
- private auth;
71
+ private webhookUrl;
72
+ private webhookJwt;
73
+ private getPipelineNames?;
81
74
  constructor(config: {
82
- baseUrl?: string;
83
- pipelineId: string;
84
- pipelineStageId: string;
85
- auth: ERPAuthService;
75
+ webhookUrl: string;
76
+ webhookJwt: string;
77
+ getPipelineNames?: () => Promise<PipelineNames>;
86
78
  });
79
+ /** Replace trailing path segment of webhook URL with `action` (e.g. `get-order-status`, `invoice-pdf`). */
80
+ resolveErpActionUrl(action: string): string;
81
+ /**
82
+ * Synchronous ERP read (§7d): POST JSON to `.../generic-webhook/<action>`.
83
+ * Body is sent as-is (or wrap with envelope if ERP expects `event_type` — caller may pass envelope).
84
+ */
85
+ postErpReadAction(action: string, body: Record<string, unknown>): Promise<{
86
+ ok: boolean;
87
+ status?: number;
88
+ json?: unknown;
89
+ error?: string;
90
+ }>;
91
+ /** GET PDF bytes for `invoice-pdf` action (§7d). */
92
+ fetchInvoicePdf(invoiceId: string): Promise<{
93
+ ok: boolean;
94
+ buffer?: ArrayBuffer;
95
+ contentType?: string;
96
+ error?: string;
97
+ }>;
98
+ /** `product.updated` envelope → `update-product` (§7e). */
99
+ submitProductUpsert(productData: Record<string, unknown>): Promise<ERPSubmissionResult>;
100
+ private postWebhookJson;
101
+ private resolvePipelineNames;
102
+ /** Generic webhook POST (e.g. order.created envelope). */
103
+ postWebhook(body: unknown): Promise<ERPSubmissionResult>;
104
+ /** Shared CRM inbound fields (§7a/b in ERP-plugin.md). */
105
+ private buildCrmInboundData;
106
+ /** `lead.created` → ERP create-lead (CRM leads table). */
87
107
  submitContact(formData: ContactFormData): Promise<ERPSubmissionResult>;
108
+ /** `create-contact` → ERP ContactService upsert (§7c). */
109
+ submitCreateContact(payload: ErpCreateContactPayload): Promise<ERPSubmissionResult>;
110
+ /** `form.submitted` → ERP create-opportunity (pipeline). */
111
+ submitFormOpportunity(formData: ContactFormData): Promise<ERPSubmissionResult>;
112
+ /**
113
+ * Order payload aligned with ERP generic webhook create-order (§6).
114
+ */
115
+ submitOrder(orderDto: Record<string, unknown>): Promise<ERPSubmissionResult>;
88
116
  extractContactData(formData: Record<string, unknown>, formFields: {
89
117
  id: string | number;
90
118
  type: string;
@@ -92,16 +120,71 @@ declare class ERPSubmissionService {
92
120
  }[]): ContactFormData | null;
93
121
  }
94
122
 
123
+ interface CmsAppLike$2 {
124
+ getPlugin(name: string): unknown;
125
+ }
126
+ type ErpJobPayload = {
127
+ kind: 'lead';
128
+ contact: ContactFormData;
129
+ } | {
130
+ kind: 'formOpportunity';
131
+ contact: ContactFormData;
132
+ } | {
133
+ kind: 'createContact';
134
+ contact: ErpCreateContactPayload;
135
+ } | {
136
+ kind: 'order';
137
+ order: Record<string, unknown>;
138
+ } | {
139
+ kind: 'productUpsert';
140
+ product: Record<string, unknown>;
141
+ };
142
+ declare function queueErp(cms: CmsAppLike$2, payload: ErpJobPayload): Promise<void>;
143
+ declare function registerErpQueueProcessor(cms: CmsAppLike$2): void;
144
+
145
+ /**
146
+ * Duck-typed DataSource so host apps (e.g. Next) can pass their own TypeORM instance
147
+ * without duplicate-package type errors vs core’s node_modules/typeorm.
148
+ */
149
+ type ErpPaidOrderDataSource = {
150
+ getRepository(entity: unknown): {
151
+ find(options?: object): Promise<unknown[]>;
152
+ findOne(options?: object): Promise<unknown | null>;
153
+ };
154
+ };
155
+ /**
156
+ * Entity map with `configs` and `orders` entries (e.g. ENTITY_MAP).
157
+ * Typed as `Record<string, unknown>` so apps that cast their map to `Record<string, EntityTarget<…>>` still pass.
158
+ */
159
+ type ErpPaidOrderEntityMap = Record<string, unknown>;
160
+ /**
161
+ * Enqueues ERP `order.created` only when the order has at least one **completed** payment.
162
+ * Include `payments` in the payload per §6 (minor units for typical 2-decimal currencies).
163
+ */
164
+ declare function queueErpPaidOrderForOrderId(cms: CmsAppLike$2, dataSource: ErpPaidOrderDataSource, entityMap: ErpPaidOrderEntityMap, orderId: number): Promise<void>;
165
+
166
+ interface ErpContactSyncInput {
167
+ name: string;
168
+ email: string;
169
+ phone?: string | null;
170
+ type?: string | null;
171
+ company?: string | null;
172
+ notes?: string | null;
173
+ /** Passed to ERP as `tags` when non-empty (§7c). */
174
+ tags?: string[];
175
+ }
176
+ /**
177
+ * When ERP is enabled and plugin loaded, enqueue `create-contact` (non-fatal on failure).
178
+ * Used for admin CRUD and storefront contact paths — not form submissions (those use lead/opportunity).
179
+ */
180
+ declare function queueErpCreateContactIfEnabled(cms: CmsAppLike$2, dataSource: ErpPaidOrderDataSource, entityMap: ErpPaidOrderEntityMap, input: ErpContactSyncInput): Promise<void>;
181
+
95
182
  interface ERPPluginConfig {
96
- baseUrl?: string;
97
- clientId: string;
98
- clientSecret: string;
99
- tenantId: string;
100
- pipelineId?: string;
101
- pipelineStageId?: string;
183
+ webhookUrl: string;
184
+ webhookJwt: string;
185
+ getPipelineNames?: () => Promise<PipelineNames>;
102
186
  }
103
187
  interface ERPPluginInstance {
104
- auth: ERPAuthService;
105
188
  submission: ERPSubmissionService;
106
189
  }
107
190
  declare function erpPlugin(config: ERPPluginConfig): CmsPlugin<ERPPluginInstance>;
@@ -194,7 +277,7 @@ declare function renderLayout(options: {
194
277
  companyDetails: CompanyDetails;
195
278
  }): string;
196
279
 
197
- interface CmsAppLike {
280
+ interface CmsAppLike$1 {
198
281
  getPlugin(name: string): unknown;
199
282
  }
200
283
  /** Context for template rendering: at least companyDetails; template-specific fields (formName, etc.) are allowed. */
@@ -208,8 +291,8 @@ interface EmailJobPayload {
208
291
  html?: string;
209
292
  text?: string;
210
293
  }
211
- declare function registerEmailQueueProcessor(cms: CmsAppLike): void;
212
- declare function queueEmail(cms: CmsAppLike, payload: EmailJobPayload): Promise<void>;
294
+ declare function registerEmailQueueProcessor(cms: CmsAppLike$1): void;
295
+ declare function queueEmail(cms: CmsAppLike$1, payload: EmailJobPayload): Promise<void>;
213
296
  interface OrderPlacedEmailPayload {
214
297
  orderNumber: string;
215
298
  total?: string | number;
@@ -223,7 +306,7 @@ interface OrderPlacedEmailPayload {
223
306
  lineItems: OrderPlacedLineItem[];
224
307
  }
225
308
  /** Queues one `orderPlaced` email per recipient (customer + each unique sales address; skips sales if same as customer). */
226
- declare function queueOrderPlacedEmails(cms: CmsAppLike, payload: OrderPlacedEmailPayload): Promise<void>;
309
+ declare function queueOrderPlacedEmails(cms: CmsAppLike$1, payload: OrderPlacedEmailPayload): Promise<void>;
227
310
 
228
311
  interface EmailPluginConfig {
229
312
  type: 'AWS' | 'SMTP' | 'GMAIL' | 'SENDGRID';
@@ -291,16 +374,76 @@ interface AnalyticsPluginConfig {
291
374
  }
292
375
  declare function analyticsPlugin(config?: AnalyticsPluginConfig): CmsPlugin<AnalyticsService>;
293
376
 
294
- /** Provider-agnostic SMS interface. Implementations (Twilio, AWS SNS, etc.) can be added later. */
295
- interface SmsServiceInterface {
296
- send(to: string, message: string): Promise<boolean>;
377
+ type MessageTemplateRowLoader = (channel: string, templateKey: string) => Promise<{
378
+ body: string;
379
+ externalTemplateRef: string | null;
380
+ providerMeta: Record<string, unknown> | null;
381
+ enabled: boolean;
382
+ } | null>;
383
+ /** Which transport to use for outbound SMS. */
384
+ type SmsProviderId = 'msg91' | 'twilio' | 'webhook';
385
+ /** Stored in admin `smsProvider` or env `SMS_PROVIDER`. `auto` picks first with credentials: msg91 → twilio → webhook. */
386
+ type SmsProviderChoice = SmsProviderId | 'auto';
387
+ /** MSG91: use DLT Flow API vs legacy sendhttp (non‑India / legacy only). */
388
+ type Msg91ApiMode = 'flow' | 'sendhttp' | 'auto';
389
+ interface SmsServiceConfig {
390
+ provider?: SmsProviderChoice;
391
+ /** Admin settings key `smsProvider` (msg91 | twilio | webhook | auto). */
392
+ smsProvider?: string;
393
+ /** MSG91: auth key */
394
+ msg91AuthKey?: string;
395
+ /** DLT-approved sender ID (required for sendhttp; Flow uses template/header mapped in MSG91 panel). */
396
+ msg91SenderId?: string;
397
+ /** Transactional route; default 4 (sendhttp only). */
398
+ msg91Route?: string;
399
+ /**
400
+ * MSG91 Flow ID / template_id shown in panel after mapping DLT template (India).
401
+ * Required for `flow` mode.
402
+ */
403
+ msg91TemplateId?: string;
404
+ /** `flow` = POST control.msg91.com/api/v5/flow/ (DLT). `sendhttp` = legacy GET API. `auto` = flow if template id set, else sendhttp. */
405
+ msg91ApiMode?: Msg91ApiMode;
406
+ /** Recipient JSON key for OTP value in Flow API (must match MSG91 template variables). Default var1. */
407
+ msg91OtpVarKey?: string;
408
+ /** Flow API short_url flag; default 0. */
409
+ msg91FlowShortUrl?: string;
410
+ accountSid?: string;
411
+ authToken?: string;
412
+ from?: string;
413
+ webhookUrl?: string;
414
+ webhookSecret?: string;
297
415
  }
298
- interface SmsPluginConfig {
299
- provider?: string;
300
- [key: string]: string | undefined;
416
+
417
+ interface CmsAppLike {
418
+ getPlugin(name: string): unknown;
301
419
  }
302
- /** Stub SMS plugin - no implementation yet. Register and implement in app or extend core later. */
303
- declare function smsPlugin(_config?: SmsPluginConfig): CmsPlugin<SmsServiceInterface | null>;
420
+ interface SmsJobPayload {
421
+ to: string;
422
+ /** Legacy / Twilio / sendhttp plain text. */
423
+ body?: string;
424
+ templateKey?: string;
425
+ variables?: Record<string, string>;
426
+ otpCode?: string;
427
+ }
428
+ declare function registerSmsQueueProcessor(cms: CmsAppLike): void;
429
+ declare function queueSms(cms: CmsAppLike, payload: SmsJobPayload): Promise<void>;
430
+
431
+ interface SmsPluginConfig extends Partial<SmsServiceConfig> {
432
+ /** Load admin settings group `sms` (enabled, smsProvider). Secrets typically stay in env. */
433
+ getSmsSettings?: () => Promise<Record<string, string>>;
434
+ /** Resolve `message_templates` rows for SMS (required for `templateKey` sends). */
435
+ getMessageTemplateRow?: MessageTemplateRowLoader;
436
+ }
437
+ interface SmsServiceInterface {
438
+ send(opts: {
439
+ to: string;
440
+ body?: string;
441
+ templateKey?: string;
442
+ otpCode?: string;
443
+ variables?: Record<string, string>;
444
+ }): Promise<boolean>;
445
+ }
446
+ declare function smsPlugin(config?: SmsPluginConfig): CmsPlugin<SmsServiceInterface | null>;
304
447
 
305
448
  interface PaymentIntent {
306
449
  id: string;
@@ -419,6 +562,43 @@ interface QueuePluginConfig {
419
562
  }
420
563
  declare function queuePlugin(config?: QueuePluginConfig): CmsPlugin<QueueService>;
421
564
 
565
+ type CaptchaProviderId = 'turnstile' | 'recaptcha_v3';
566
+ interface CaptchaPublicConfig {
567
+ enabled: boolean;
568
+ activeProvider: CaptchaProviderId | null;
569
+ siteKey: string | null;
570
+ availableProviders: Array<{
571
+ id: CaptchaProviderId;
572
+ siteKey: string;
573
+ }>;
574
+ multipleProviders: boolean;
575
+ }
576
+ type CaptchaVerifyResult = {
577
+ ok: true;
578
+ } | {
579
+ ok: false;
580
+ status: number;
581
+ message: string;
582
+ };
583
+ declare function buildCaptchaPublicConfig(config: Record<string, string>): CaptchaPublicConfig;
584
+ declare class CaptchaService {
585
+ private readonly env;
586
+ constructor(env: Record<string, string>);
587
+ isEnforced(): boolean;
588
+ getPublicConfig(): CaptchaPublicConfig;
589
+ verify(body: Record<string, unknown>, req: Request): Promise<CaptchaVerifyResult>;
590
+ }
591
+
592
+ declare function captchaPlugin(): CmsPlugin<CaptchaService | void>;
593
+
594
+ type JsonResponse = (body: unknown, init?: {
595
+ status?: number;
596
+ headers?: HeadersInit;
597
+ }) => Response;
598
+ declare function assertCaptchaOk(getCms: (() => Promise<{
599
+ getPlugin: (name: string) => unknown;
600
+ }>) | undefined, body: Record<string, unknown>, req: Request, json: JsonResponse): Promise<Response | null>;
601
+
422
602
  declare function cn(...inputs: ClassValue[]): string;
423
603
  declare function generateSlug(title: string): string;
424
604
  declare function validateSlug(slug: string): boolean;
@@ -427,6 +607,42 @@ declare function formatDateTime(date: Date | string): string;
427
607
  declare function formatDateOnly(date: Date | string): string;
428
608
  declare function truncateText(text: string, maxLength: number): string;
429
609
 
610
+ /** Minimal SEO row shape (DB or API). */
611
+ type SeoLike = {
612
+ title?: string | null;
613
+ description?: string | null;
614
+ keywords?: string | null;
615
+ ogTitle?: string | null;
616
+ ogDescription?: string | null;
617
+ ogImage?: string | null;
618
+ };
619
+ type SeoMetadataOverrides = {
620
+ title?: string;
621
+ description?: string;
622
+ keywords?: string;
623
+ ogTitle?: string;
624
+ ogDescription?: string;
625
+ ogImage?: string;
626
+ };
627
+ /** Per-field: join row wins over slug row. */
628
+ declare function mergeSeoBySlug(join: SeoLike | null | undefined, bySlug: SeoLike | null): SeoLike | null;
629
+ declare function fetchSeoBySlug(dataSource: DataSource, entityMap: EntityMap$1, slug: string): Promise<SeoLike | null>;
630
+ /**
631
+ * Build Next.js Metadata from merged SEO + optional layers.
632
+ * `overrides` win over SEO; `fallbacks` apply when SEO (and overrides) omit a field.
633
+ * Returns a partial object; omit fields so the root layout defaults apply.
634
+ */
635
+ declare function resolvePublicMetadata(args: {
636
+ dataSource: DataSource;
637
+ entityMap: EntityMap$1;
638
+ slug: string;
639
+ seoFromJoin?: SeoLike | null;
640
+ overrides?: SeoMetadataOverrides;
641
+ fallbacks?: SeoMetadataOverrides;
642
+ canonicalPath?: string;
643
+ metadataBase?: URL;
644
+ }): Promise<Metadata>;
645
+
430
646
  /** Links an unclaimed contact (same email, no userId) to the new user after signup or invite. */
431
647
  declare function linkUnclaimedContactToUser(dataSource: DataSource, contactsEntity: EntityTarget<ObjectLiteral>, userId: number, email: string): Promise<void>;
432
648
 
@@ -437,6 +653,41 @@ declare function serializeEmailRecipients(emails: string[]): string;
437
653
  /** Join for SMTP `to` header (multiple recipients). */
438
654
  declare function joinRecipientsForSend(emails: string[]): string | null;
439
655
 
656
+ type OtpPurpose = 'login' | 'verify_email' | 'verify_phone';
657
+ type OtpChannel = 'email' | 'sms';
658
+ declare function hashOtpCode(code: string, purpose: string, identifier: string, pepper?: string): string;
659
+ declare function verifyOtpCodeHash(code: string, storedHash: string, purpose: string, identifier: string, pepper?: string): boolean;
660
+ declare function generateNumericOtp(length?: number): string;
661
+ /** Normalize to E.164-like +digits */
662
+ declare function normalizePhoneE164(raw: string, defaultCountryCode?: string): string | null;
663
+ type EntityMap = Record<string, EntityTarget<ObjectLiteral>>;
664
+ declare function countRecentOtpSends(dataSource: DataSource, entityMap: EntityMap, purpose: OtpPurpose, identifier: string, since: Date): Promise<number>;
665
+ declare function createOtpChallenge(dataSource: DataSource, entityMap: EntityMap, input: {
666
+ purpose: OtpPurpose;
667
+ channel: OtpChannel;
668
+ identifier: string;
669
+ code: string;
670
+ pepper?: string;
671
+ }): Promise<{
672
+ ok: true;
673
+ } | {
674
+ ok: false;
675
+ error: string;
676
+ status: number;
677
+ }>;
678
+ declare function verifyAndConsumeOtpChallenge(dataSource: DataSource, entityMap: EntityMap, input: {
679
+ purpose: OtpPurpose;
680
+ identifier: string;
681
+ code: string;
682
+ pepper?: string;
683
+ }): Promise<{
684
+ ok: true;
685
+ } | {
686
+ ok: false;
687
+ error: string;
688
+ status: number;
689
+ }>;
690
+
440
691
  declare class Permission {
441
692
  id: number;
442
693
  groupId: number;
@@ -473,6 +724,10 @@ declare class User {
473
724
  id: number;
474
725
  name: string;
475
726
  email: string;
727
+ /** E.164 when set; unique among non-null values (partial index in DB). */
728
+ phone: string | null;
729
+ phoneVerifiedAt: Date | null;
730
+ emailVerifiedAt: Date | null;
476
731
  password: string | null;
477
732
  blocked: boolean;
478
733
  adminAccess: boolean;
@@ -487,6 +742,18 @@ declare class User {
487
742
  group: UserGroup | null;
488
743
  }
489
744
 
745
+ declare class OtpChallenge {
746
+ id: number;
747
+ purpose: string;
748
+ channel: string;
749
+ identifier: string;
750
+ codeHash: string;
751
+ expiresAt: Date;
752
+ attempts: number;
753
+ consumedAt: Date | null;
754
+ createdAt: Date;
755
+ }
756
+
490
757
  declare class PasswordResetToken {
491
758
  id: number;
492
759
  email: string;
@@ -846,9 +1113,12 @@ declare class Payment {
846
1113
  contact: Contact | null;
847
1114
  }
848
1115
 
1116
+ type OrderKind = 'sale' | 'return' | 'replacement';
849
1117
  declare class Order {
850
1118
  id: number;
851
1119
  orderNumber: string;
1120
+ orderKind: OrderKind;
1121
+ parentOrderId: number | null;
852
1122
  contactId: number;
853
1123
  billingAddressId: number | null;
854
1124
  shippingAddressId: number | null;
@@ -866,6 +1136,8 @@ declare class Order {
866
1136
  createdBy: number | null;
867
1137
  updatedBy: number | null;
868
1138
  deletedBy: number | null;
1139
+ parentOrder: Order | null;
1140
+ children: Order[];
869
1141
  contact: Contact;
870
1142
  billingAddress: Address | null;
871
1143
  shippingAddress: Address | null;
@@ -932,6 +1204,25 @@ declare class Config {
932
1204
  deletedBy: number | null;
933
1205
  }
934
1206
 
1207
+ declare class MessageTemplate {
1208
+ id: number;
1209
+ channel: string;
1210
+ templateKey: string;
1211
+ name: string | null;
1212
+ subject: string | null;
1213
+ body: string;
1214
+ externalTemplateRef: string | null;
1215
+ providerMeta: Record<string, unknown> | null;
1216
+ enabled: boolean;
1217
+ createdAt: Date;
1218
+ updatedAt: Date;
1219
+ deletedAt: Date | null;
1220
+ deleted: boolean;
1221
+ createdBy: number | null;
1222
+ updatedBy: number | null;
1223
+ deletedBy: number | null;
1224
+ }
1225
+
935
1226
  declare class Media {
936
1227
  id: number;
937
1228
  filename: string;
@@ -1034,4 +1325,4 @@ declare class Wishlist {
1034
1325
  /** Map API resource segment (e.g. "blogs", "form_submissions") to entity. Used by CRUD handler. */
1035
1326
  declare const CMS_ENTITY_MAP: Record<string, EntityTarget<typeorm.ObjectLiteral>>;
1036
1327
 
1037
- export { type AnalyticsPluginConfig, Attribute, Blog, Brand, CMS_ENTITY_MAP, type CachePluginConfig, type CacheService, Cart, CartItem, Category, ChatConversation, ChatMessage, type CmsApp, type CmsPlugin, Collection, Comment, CompanyDetails, Config, Contact, type CreateCmsAppOptions, type ERPPluginConfig, type ERPPluginInstance, type EmailData, type EmailJobPayload, type EmailPluginConfig, EmailService, type EmailServiceInterface, EmailTemplateName, EmailTemplateResult, Form, FormField, FormSubmission, KnowledgeBaseChunk, KnowledgeBaseDocument, type LlmChatOptions, type LlmMessage, type LlmPluginConfig, LlmService, type LlmServiceInterface, type LocalStoragePluginConfig, type Logger, Media, Order, OrderItem, type OrderPlacedEmailPayload, OrderPlacedLineItem, Page, PasswordResetToken, Payment, type PaymentIntent, type PaymentPluginConfig, type PaymentServiceInterface, Permission, type PluginContext, Product, ProductAttribute, ProductCategory, ProductTax, type QueuePluginConfig, type QueueService, type RenderEmailOptions, type RenderedEmail, type S3StoragePluginConfig, Seo, StorageService, Tag, Tax, TemplateContext, User, UserGroup, Wishlist, WishlistItem, analyticsPlugin, cachePlugin, cn, createCmsApp, emailPlugin, emailTemplates, erpPlugin, formatDate, formatDateOnly, formatDateTime, generateSlug, joinRecipientsForSend, linkUnclaimedContactToUser, llmPlugin, localStoragePlugin, parseEmailRecipientsFromConfig, paymentPlugin, queueEmail, queueOrderPlacedEmails, queuePlugin, registerEmailQueueProcessor, renderEmail, renderLayout, s3StoragePlugin, serializeEmailRecipients, smsPlugin, truncateText, validateSlug };
1328
+ export { type AnalyticsPluginConfig, Attribute, Blog, Brand, CMS_ENTITY_MAP, type CachePluginConfig, type CacheService, type CaptchaProviderId, type CaptchaPublicConfig, CaptchaService, type CaptchaVerifyResult, Cart, CartItem, Category, ChatConversation, ChatMessage, type CmsApp, type CmsPlugin, Collection, Comment, CompanyDetails, Config, Contact, type CreateCmsAppOptions, type ERPPluginConfig, type ERPPluginInstance, ERPSubmissionService, type EmailData, type EmailJobPayload, type EmailPluginConfig, EmailService, type EmailServiceInterface, EmailTemplateName, EmailTemplateResult, EntityMap$1 as EntityMap, type ErpContactSyncInput, type ErpCreateContactPayload, type ErpJobPayload, type ErpPaidOrderDataSource, type ErpPaidOrderEntityMap, Form, FormField, FormSubmission, KnowledgeBaseChunk, KnowledgeBaseDocument, type LlmChatOptions, type LlmMessage, type LlmPluginConfig, LlmService, type LlmServiceInterface, type LocalStoragePluginConfig, type Logger, Media, MessageTemplate, Order, OrderItem, type OrderPlacedEmailPayload, OrderPlacedLineItem, OtpChallenge, type OtpChannel, type OtpPurpose, Page, PasswordResetToken, Payment, type PaymentIntent, type PaymentPluginConfig, type PaymentServiceInterface, Permission, type PipelineNames, type PluginContext, Product, ProductAttribute, ProductCategory, ProductTax, type QueuePluginConfig, type QueueService, type RenderEmailOptions, type RenderedEmail, type S3StoragePluginConfig, Seo, type SeoLike, type SeoMetadataOverrides, type SmsJobPayload, type SmsPluginConfig, type SmsProviderChoice, type SmsProviderId, type SmsServiceConfig, type SmsServiceInterface, StorageService, Tag, Tax, TemplateContext, User, UserGroup, Wishlist, WishlistItem, analyticsPlugin, assertCaptchaOk, buildCaptchaPublicConfig, cachePlugin, captchaPlugin, cn, countRecentOtpSends, createCmsApp, createOtpChallenge, emailPlugin, emailTemplates, erpPlugin, fetchSeoBySlug, formatDate, formatDateOnly, formatDateTime, generateNumericOtp, generateSlug, hashOtpCode, joinRecipientsForSend, linkUnclaimedContactToUser, llmPlugin, localStoragePlugin, mergeSeoBySlug, normalizePhoneE164, parseEmailRecipientsFromConfig, paymentPlugin, queueEmail, queueErp, queueErpCreateContactIfEnabled, queueErpPaidOrderForOrderId, queueOrderPlacedEmails, queuePlugin, queueSms, registerEmailQueueProcessor, registerErpQueueProcessor, registerSmsQueueProcessor, renderEmail, renderLayout, resolvePublicMetadata, s3StoragePlugin, serializeEmailRecipients, smsPlugin, truncateText, validateSlug, verifyAndConsumeOtpChallenge, verifyOtpCodeHash };