@infuro/cms-core 1.0.35 → 1.0.38
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/admin.cjs +1222 -1024
- package/dist/admin.d.cts +6 -0
- package/dist/admin.d.ts +6 -0
- package/dist/admin.js +1224 -1026
- package/dist/api.cjs +40 -39
- package/dist/api.js +8 -7
- package/dist/auth.cjs +51 -51
- package/dist/auth.d.cts +3 -3
- package/dist/auth.d.ts +3 -3
- package/dist/auth.js +3 -3
- package/dist/chunk-22FFHLTO.cjs +2356 -0
- package/dist/{chunk-CNTSLED2.cjs → chunk-E6WVP7BK.cjs} +75 -14
- package/dist/chunk-HCIRL37O.js +21 -0
- package/dist/chunk-HT5DI3XW.cjs +82 -0
- package/dist/{chunk-EF2JBPDM.js → chunk-KFFB6EMZ.js} +9 -0
- package/dist/chunk-NNQBWDCI.js +2325 -0
- package/dist/{chunk-TIAEXJLI.cjs → chunk-OIGCAGH7.cjs} +7 -7
- package/dist/{chunk-4TRPKBKO.js → chunk-P7QCLE5W.js} +52 -24
- package/dist/{chunk-2XE4X74C.js → chunk-PYUXVU75.js} +7801 -6871
- package/dist/{chunk-EQPITOP6.js → chunk-SBRBR3VO.js} +70 -9
- package/dist/{chunk-N44BJZ4C.cjs → chunk-SPQFNIYJ.cjs} +9 -0
- package/dist/chunk-UCKN4BBY.cjs +24 -0
- package/dist/{chunk-6KPQWRFW.js → chunk-UXMDSNIG.js} +1 -1
- package/dist/{chunk-BGJAV67S.cjs → chunk-VJDUKAJ3.cjs} +8207 -7261
- package/dist/{chunk-3KPNTQBV.cjs → chunk-WMXPKKXU.cjs} +52 -23
- package/dist/chunk-X47PBV4I.js +79 -0
- package/dist/cli.cjs +4 -2
- package/dist/cli.js +4 -2
- package/dist/emit-order-notification-trigger-D2N3KFHL.cjs +16 -0
- package/dist/emit-order-notification-trigger-IVLWKKJL.js +3 -0
- package/dist/{event-order-defaults-DUGDVGJI.cjs → event-order-defaults-EMWBIGL3.cjs} +9 -9
- package/dist/{event-order-defaults-6E543227.js → event-order-defaults-SDRNAZHC.js} +1 -1
- package/dist/index.cjs +805 -1059
- package/dist/index.d.cts +834 -728
- package/dist/index.d.ts +834 -728
- package/dist/index.js +385 -724
- package/dist/migrations/1775500000000-RssFeedsAndArticles.ts +0 -1
- package/dist/migrations/1775700000000-JobSchedules.ts +0 -1
- package/dist/migrations/1781220000000-AddWhatsappTriggerBindings.ts +23 -0
- package/dist/migrations/1781230000000-AddOrderNotificationTriggers.ts +46 -0
- package/dist/migrations/1781240000000-DropEventOrderNotificationColumns.ts +29 -0
- package/dist/migrations/1781250000000-RemoveOrderRefundedTrigger.ts +36 -0
- package/dist/migrations/1781260000000-RenameWhatsappTriggerBindingsToOrderNotificationBindings.ts +92 -0
- package/dist/migrations/1781270000000-ComboVendorId.ts +58 -0
- package/dist/order-notification-dispatcher-RU7BTGGX.cjs +18 -0
- package/dist/order-notification-dispatcher-XWIJYDGA.js +5 -0
- package/dist/{rbac-debug-db-D7ME7QUY.cjs → rbac-debug-db-KHG4FJC3.cjs} +2 -2
- package/dist/{rbac-debug-db-MTCTVNNM.js → rbac-debug-db-QWHOENBR.js} +1 -1
- package/package.json +1 -1
- package/dist/chunk-46GKADYE.cjs +0 -84
- package/dist/chunk-7YIBMQDR.cjs +0 -86
- package/dist/chunk-J7XHLOLO.js +0 -830
- package/dist/chunk-JBRR5UYL.js +0 -87
- package/dist/chunk-JHF4YYRC.cjs +0 -188
- package/dist/chunk-PAMVINEX.cjs +0 -577
- package/dist/chunk-QM733NUK.js +0 -186
- package/dist/chunk-R73BKDRO.cjs +0 -90
- package/dist/chunk-TFUOHI37.cjs +0 -839
- package/dist/chunk-XDSNZUW7.js +0 -564
- package/dist/chunk-ZQ4X6OAU.js +0 -82
- package/dist/chunk-ZSVCP6N3.js +0 -83
- package/dist/email-FKR4FXFI.js +0 -5
- package/dist/email-KVKVPNCL.cjs +0 -58
- package/dist/event-order-notifications-5GSAOYVS.cjs +0 -27
- package/dist/event-order-notifications-IIIF23D5.js +0 -10
- package/dist/layout-36UFTHC5.cjs +0 -11
- package/dist/layout-AOBN26XG.js +0 -2
- package/dist/whatsapp-queue-3DXA4MXU.js +0 -2
- package/dist/whatsapp-queue-KG65MXD5.cjs +0 -15
package/dist/index.d.cts
CHANGED
|
@@ -3,6 +3,7 @@ import * as typeorm from 'typeorm';
|
|
|
3
3
|
import { DataSource, EntityTarget, ObjectLiteral, EntityManager, SelectQueryBuilder } from 'typeorm';
|
|
4
4
|
import { ClassValue } from 'clsx';
|
|
5
5
|
import { Metadata } from 'next';
|
|
6
|
+
import { EventEmitter } from 'events';
|
|
6
7
|
import { NextAuthOptions } from 'next-auth';
|
|
7
8
|
import { getToken } from 'next-auth/jwt';
|
|
8
9
|
|
|
@@ -34,6 +35,8 @@ interface CmsApp {
|
|
|
34
35
|
dataSource: unknown;
|
|
35
36
|
getPlugin<T = unknown>(name: string): T | undefined;
|
|
36
37
|
}
|
|
38
|
+
/** Merge extra plugin instances on top of an existing CMS app (overlay wins). */
|
|
39
|
+
declare function overlayCmsPlugins(base: CmsApp, plugins: Record<string, unknown>): CmsApp;
|
|
37
40
|
declare function createCmsApp(options: CreateCmsAppOptions): Promise<CmsApp>;
|
|
38
41
|
|
|
39
42
|
interface ContactFormData {
|
|
@@ -527,6 +530,7 @@ interface WhatsAppJobPayload {
|
|
|
527
530
|
body?: string;
|
|
528
531
|
templateKey?: string;
|
|
529
532
|
externalTemplateRef?: string;
|
|
533
|
+
templateLanguage?: string;
|
|
530
534
|
variables?: Record<string, string>;
|
|
531
535
|
templateParamOrder?: readonly string[];
|
|
532
536
|
}
|
|
@@ -1487,22 +1491,6 @@ declare function createJobScheduleHandlers(apiConfig: JobScheduleApiConfig): {
|
|
|
1487
1491
|
listRuns(req: Request, id: string): Promise<Response>;
|
|
1488
1492
|
};
|
|
1489
1493
|
|
|
1490
|
-
interface EventNotificationHandlersConfig {
|
|
1491
|
-
dataSource: DataSource;
|
|
1492
|
-
entityMap: EntityMap$2;
|
|
1493
|
-
json: (body: unknown, init?: {
|
|
1494
|
-
status?: number;
|
|
1495
|
-
}) => Response;
|
|
1496
|
-
requireAuth: (req: Request) => Promise<Response | null>;
|
|
1497
|
-
requireEntityPermission?: RequireEntityPermissionFn;
|
|
1498
|
-
getCms?: () => Promise<CmsAppLike$3>;
|
|
1499
|
-
}
|
|
1500
|
-
declare function createEventNotificationHandlers(config: EventNotificationHandlersConfig): {
|
|
1501
|
-
getSettings(req: Request, id: string): Promise<Response>;
|
|
1502
|
-
updateSettings(req: Request, id: string): Promise<Response>;
|
|
1503
|
-
sendTest(req: Request, id: string): Promise<Response>;
|
|
1504
|
-
};
|
|
1505
|
-
|
|
1506
1494
|
interface EventOrderMessageTemplateHandlersConfig {
|
|
1507
1495
|
dataSource: DataSource;
|
|
1508
1496
|
entityMap: EntityMap$2;
|
|
@@ -1517,6 +1505,137 @@ declare function createEventOrderMessageTemplateHandlers(config: EventOrderMessa
|
|
|
1517
1505
|
PUT(req: Request): Promise<Response>;
|
|
1518
1506
|
};
|
|
1519
1507
|
|
|
1508
|
+
declare function cn(...inputs: ClassValue[]): string;
|
|
1509
|
+
declare function generateSlug(title: string): string;
|
|
1510
|
+
declare function validateSlug(slug: string): boolean;
|
|
1511
|
+
declare function formatDate(date: Date | string): string;
|
|
1512
|
+
declare function formatDateTime(date: Date | string): string;
|
|
1513
|
+
declare function formatDateOnly(date: Date | string): string;
|
|
1514
|
+
declare function truncateText(text: string, maxLength: number): string;
|
|
1515
|
+
|
|
1516
|
+
/** Minimal SEO row shape (DB or API). */
|
|
1517
|
+
type SeoLike = {
|
|
1518
|
+
title?: string | null;
|
|
1519
|
+
description?: string | null;
|
|
1520
|
+
keywords?: string | null;
|
|
1521
|
+
ogTitle?: string | null;
|
|
1522
|
+
ogDescription?: string | null;
|
|
1523
|
+
ogImage?: string | null;
|
|
1524
|
+
};
|
|
1525
|
+
type SeoMetadataOverrides = {
|
|
1526
|
+
title?: string;
|
|
1527
|
+
description?: string;
|
|
1528
|
+
keywords?: string;
|
|
1529
|
+
ogTitle?: string;
|
|
1530
|
+
ogDescription?: string;
|
|
1531
|
+
ogImage?: string;
|
|
1532
|
+
};
|
|
1533
|
+
/** Per-field: join row wins over slug row. */
|
|
1534
|
+
declare function mergeSeoBySlug(join: SeoLike | null | undefined, bySlug: SeoLike | null): SeoLike | null;
|
|
1535
|
+
declare function fetchSeoBySlug(dataSource: DataSource, entityMap: EntityMap$2, slug: string): Promise<SeoLike | null>;
|
|
1536
|
+
/**
|
|
1537
|
+
* Build Next.js Metadata from merged SEO + optional layers.
|
|
1538
|
+
* `overrides` win over SEO; `fallbacks` apply when SEO (and overrides) omit a field.
|
|
1539
|
+
* Returns a partial object; omit fields so the root layout defaults apply.
|
|
1540
|
+
*/
|
|
1541
|
+
declare function resolvePublicMetadata(args: {
|
|
1542
|
+
dataSource: DataSource;
|
|
1543
|
+
entityMap: EntityMap$2;
|
|
1544
|
+
slug: string;
|
|
1545
|
+
seoFromJoin?: SeoLike | null;
|
|
1546
|
+
overrides?: SeoMetadataOverrides;
|
|
1547
|
+
fallbacks?: SeoMetadataOverrides;
|
|
1548
|
+
canonicalPath?: string;
|
|
1549
|
+
metadataBase?: URL;
|
|
1550
|
+
}): Promise<Metadata>;
|
|
1551
|
+
|
|
1552
|
+
/** Links an unclaimed contact (same email, no userId) to the new user after signup or invite. */
|
|
1553
|
+
declare function linkUnclaimedContactToUser(dataSource: DataSource, contactsEntity: EntityTarget<ObjectLiteral>, userId: number, email: string): Promise<void>;
|
|
1554
|
+
|
|
1555
|
+
type EnsureCustomerUserInput = {
|
|
1556
|
+
id: number;
|
|
1557
|
+
name: string;
|
|
1558
|
+
email: string;
|
|
1559
|
+
phone?: string | null;
|
|
1560
|
+
};
|
|
1561
|
+
/** Stable unique placeholder when no phone is available (customer.phone is NOT NULL + UNIQUE). */
|
|
1562
|
+
declare function customerPhoneForUser(userId: number, phone?: string | null): string;
|
|
1563
|
+
/**
|
|
1564
|
+
* Ensures a `customer` row exists for the given user (idempotent by userId / email).
|
|
1565
|
+
* Returns null when customer entity is missing or email belongs to another user.
|
|
1566
|
+
*/
|
|
1567
|
+
declare function ensureCustomerForUser(dsOrEm: DataSource | EntityManager, customerEntity: EntityTarget<ObjectLiteral>, user: EnsureCustomerUserInput, overrides?: {
|
|
1568
|
+
phone?: string | null;
|
|
1569
|
+
}): Promise<{
|
|
1570
|
+
id: number;
|
|
1571
|
+
} | null>;
|
|
1572
|
+
|
|
1573
|
+
/** Parse stored config value into a list of emails (JSON array, or comma/semicolon-separated string). */
|
|
1574
|
+
declare function parseEmailRecipientsFromConfig(raw: string | undefined | null): string[];
|
|
1575
|
+
/** Serialize email list for config storage (JSON array in DB). */
|
|
1576
|
+
declare function serializeEmailRecipients(emails: string[]): string;
|
|
1577
|
+
/** Join for SMTP `to` header (multiple recipients). */
|
|
1578
|
+
declare function joinRecipientsForSend(emails: string[]): string | null;
|
|
1579
|
+
|
|
1580
|
+
type OtpPurpose = 'login' | 'verify_email' | 'verify_phone';
|
|
1581
|
+
type OtpChannel = 'email' | 'sms';
|
|
1582
|
+
declare function hashOtpCode(code: string, purpose: string, identifier: string, pepper?: string): string;
|
|
1583
|
+
declare function verifyOtpCodeHash(code: string, storedHash: string, purpose: string, identifier: string, pepper?: string): boolean;
|
|
1584
|
+
declare function generateNumericOtp(length?: number): string;
|
|
1585
|
+
/** Normalize to E.164-like +digits */
|
|
1586
|
+
declare function normalizePhoneE164(raw: string, defaultCountryCode?: string): string | null;
|
|
1587
|
+
type EntityMap$1 = Record<string, EntityTarget<ObjectLiteral>>;
|
|
1588
|
+
declare function countRecentOtpSends(dataSource: DataSource, entityMap: EntityMap$1, purpose: OtpPurpose, identifier: string, since: Date): Promise<number>;
|
|
1589
|
+
declare function createOtpChallenge(dataSource: DataSource, entityMap: EntityMap$1, input: {
|
|
1590
|
+
purpose: OtpPurpose;
|
|
1591
|
+
channel: OtpChannel;
|
|
1592
|
+
identifier: string;
|
|
1593
|
+
code: string;
|
|
1594
|
+
pepper?: string;
|
|
1595
|
+
}): Promise<{
|
|
1596
|
+
ok: true;
|
|
1597
|
+
} | {
|
|
1598
|
+
ok: false;
|
|
1599
|
+
error: string;
|
|
1600
|
+
status: number;
|
|
1601
|
+
}>;
|
|
1602
|
+
declare function verifyAndConsumeOtpChallenge(dataSource: DataSource, entityMap: EntityMap$1, input: {
|
|
1603
|
+
purpose: OtpPurpose;
|
|
1604
|
+
identifier: string;
|
|
1605
|
+
code: string;
|
|
1606
|
+
pepper?: string;
|
|
1607
|
+
}): Promise<{
|
|
1608
|
+
ok: true;
|
|
1609
|
+
} | {
|
|
1610
|
+
ok: false;
|
|
1611
|
+
error: string;
|
|
1612
|
+
status: number;
|
|
1613
|
+
}>;
|
|
1614
|
+
|
|
1615
|
+
/** Returns true if request is allowed; false if rate limited. */
|
|
1616
|
+
declare function allowRateLimit(key: string): Promise<boolean>;
|
|
1617
|
+
type ExtraPublicWriteRule = (method: string, segments: string[]) => boolean;
|
|
1618
|
+
/** Segments are path parts after `/api/` (e.g. `['form-submissions']`). */
|
|
1619
|
+
declare function shouldRateLimitPublicWrite(method: string, segments: string[], extraRule?: ExtraPublicWriteRule): boolean;
|
|
1620
|
+
declare function rateLimitKeyForApiRequest(req: Request, segments: string[]): string;
|
|
1621
|
+
declare function rateLimitPublicApiIfNeeded(req: Request, method: string, segments: string[], options?: {
|
|
1622
|
+
extraRule?: ExtraPublicWriteRule;
|
|
1623
|
+
}): Promise<Response | null>;
|
|
1624
|
+
declare function rateLimitCheckoutPost(req: Request): Promise<Response | null>;
|
|
1625
|
+
|
|
1626
|
+
interface EntityMapLike$1 {
|
|
1627
|
+
configs: unknown;
|
|
1628
|
+
orders: unknown;
|
|
1629
|
+
order_items: unknown;
|
|
1630
|
+
}
|
|
1631
|
+
interface SendOrderPlacedEmailDeps {
|
|
1632
|
+
getDataSource: () => Promise<DataSource>;
|
|
1633
|
+
entityMap: EntityMapLike$1;
|
|
1634
|
+
getCms: () => Promise<CmsApp>;
|
|
1635
|
+
}
|
|
1636
|
+
/** After payment confirmation: email customer + each sales team address from plugin settings. */
|
|
1637
|
+
declare function sendOrderPlacedEmailsAfterConfirmation(orderId: number, deps: SendOrderPlacedEmailDeps): Promise<void>;
|
|
1638
|
+
|
|
1520
1639
|
declare class Permission {
|
|
1521
1640
|
id: number;
|
|
1522
1641
|
groupId: number;
|
|
@@ -2265,13 +2384,6 @@ type EventSocialMediaLinks = {
|
|
|
2265
2384
|
type EventPricingType = 'free' | 'paid';
|
|
2266
2385
|
type EventEntityMode = 'inperson' | 'online' | 'hybrid';
|
|
2267
2386
|
type EventVisibility = 'public' | 'private';
|
|
2268
|
-
type EventOrderNotificationChannel$1 = 'email' | 'whatsapp';
|
|
2269
|
-
type EventOrderTemplateOverride$1 = {
|
|
2270
|
-
subject?: string;
|
|
2271
|
-
body?: string;
|
|
2272
|
-
externalTemplateRef?: string;
|
|
2273
|
-
};
|
|
2274
|
-
type EventOrderNotificationTemplates = Partial<Record<EventOrderNotificationChannel$1, EventOrderTemplateOverride$1>>;
|
|
2275
2387
|
declare class Event {
|
|
2276
2388
|
id: number;
|
|
2277
2389
|
vendorId: number | null;
|
|
@@ -2305,12 +2417,6 @@ declare class Event {
|
|
|
2305
2417
|
supportContact: string | null;
|
|
2306
2418
|
allowGroupOrders: boolean;
|
|
2307
2419
|
sendIndividualTicketPDFToAttendees: boolean;
|
|
2308
|
-
/** Send email/WhatsApp when an order containing this event's products is created. */
|
|
2309
|
-
orderNotificationsEnabled: boolean;
|
|
2310
|
-
/** Enabled channels, e.g. ["email","whatsapp"]. */
|
|
2311
|
-
orderNotificationChannels: EventOrderNotificationChannel$1[] | null;
|
|
2312
|
-
/** Per-event template overrides keyed by channel. */
|
|
2313
|
-
orderNotificationTemplates: EventOrderNotificationTemplates | null;
|
|
2314
2420
|
/** CMS contact/attendee form used for this event's registration checkout. */
|
|
2315
2421
|
contactFormId: number | null;
|
|
2316
2422
|
/** GST / tax applied to event ticket sales. */
|
|
@@ -2371,6 +2477,7 @@ type EventOrderTemplateOverride = {
|
|
|
2371
2477
|
body?: string;
|
|
2372
2478
|
externalTemplateRef?: string;
|
|
2373
2479
|
};
|
|
2480
|
+
type EventOrderNotificationTemplates = Partial<Record<EventOrderNotificationChannel, EventOrderTemplateOverride>>;
|
|
2374
2481
|
type EventOrderMessageTemplateDefault = {
|
|
2375
2482
|
channel: EventOrderNotificationChannel;
|
|
2376
2483
|
templateKey: string;
|
|
@@ -2386,777 +2493,716 @@ type ResolvedEventOrderTemplate = {
|
|
|
2386
2493
|
subject?: string;
|
|
2387
2494
|
body: string;
|
|
2388
2495
|
externalTemplateRef?: string;
|
|
2496
|
+
name?: string;
|
|
2497
|
+
language?: string;
|
|
2498
|
+
paramOrder?: string[];
|
|
2389
2499
|
enabled: boolean;
|
|
2390
2500
|
};
|
|
2391
2501
|
declare function resolveEventOrderTemplate(channel: EventOrderNotificationChannel, getRow: (channel: string, key: string) => Promise<{
|
|
2392
2502
|
subject: string | null;
|
|
2393
2503
|
body: string;
|
|
2394
2504
|
externalTemplateRef: string | null;
|
|
2505
|
+
name?: string | null;
|
|
2506
|
+
language?: string | null;
|
|
2507
|
+
paramOrder?: string[] | null;
|
|
2395
2508
|
enabled: boolean;
|
|
2396
2509
|
} | null>, eventOverride?: EventOrderTemplateOverride | null): Promise<ResolvedEventOrderTemplate | null>;
|
|
2397
2510
|
|
|
2398
|
-
interface
|
|
2511
|
+
interface EmitOrderNotificationTriggerDeps {
|
|
2399
2512
|
dataSource: DataSource;
|
|
2400
2513
|
entityMap: Record<string, unknown>;
|
|
2401
|
-
getCms: () => Promise<CmsAppLike$3>;
|
|
2402
2514
|
}
|
|
2515
|
+
declare function emitOrderNotificationTrigger(triggerKey: string, orderId: number, deps: EmitOrderNotificationTriggerDeps, extra?: {
|
|
2516
|
+
refundAmount?: number | null;
|
|
2517
|
+
}): Promise<void>;
|
|
2518
|
+
/** Fire-and-forget wrapper for API handlers (storefront, CRUD, CMS). */
|
|
2519
|
+
declare function fireOrderNotificationTrigger(triggerKey: string, orderId: number, deps: EmitOrderNotificationTriggerDeps, extra?: {
|
|
2520
|
+
refundAmount?: number | null;
|
|
2521
|
+
}): void;
|
|
2403
2522
|
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
enabled: boolean;
|
|
2409
|
-
activeProvider: CaptchaProviderId | null;
|
|
2410
|
-
siteKey: string | null;
|
|
2411
|
-
availableProviders: Array<{
|
|
2412
|
-
id: CaptchaProviderId;
|
|
2413
|
-
siteKey: string;
|
|
2414
|
-
}>;
|
|
2415
|
-
multipleProviders: boolean;
|
|
2416
|
-
}
|
|
2417
|
-
type CaptchaVerifyResult = {
|
|
2418
|
-
ok: true;
|
|
2419
|
-
} | {
|
|
2420
|
-
ok: false;
|
|
2421
|
-
status: number;
|
|
2422
|
-
message: string;
|
|
2423
|
-
};
|
|
2424
|
-
declare function buildCaptchaPublicConfig(config: Record<string, string>): CaptchaPublicConfig;
|
|
2425
|
-
declare class CaptchaService {
|
|
2426
|
-
private readonly env;
|
|
2427
|
-
constructor(env: Record<string, string>);
|
|
2428
|
-
isEnforced(): boolean;
|
|
2429
|
-
getPublicConfig(): CaptchaPublicConfig;
|
|
2430
|
-
verify(body: Record<string, unknown>, req: Request): Promise<CaptchaVerifyResult>;
|
|
2523
|
+
interface OrderNotificationDispatcherDeps {
|
|
2524
|
+
dataSource: DataSource;
|
|
2525
|
+
entityMap: EntityMap$2;
|
|
2526
|
+
getCms: () => Promise<CmsAppLike$1>;
|
|
2431
2527
|
}
|
|
2528
|
+
declare function initWhatsappTriggerDispatcher(deps: OrderNotificationDispatcherDeps): void;
|
|
2529
|
+
/** Manually re-fire a trigger for an existing order (admin testing / resend). */
|
|
2530
|
+
declare function resendOrderNotification(triggerKey: string, orderId: number, deps: OrderNotificationDispatcherDeps): Promise<{
|
|
2531
|
+
ok: boolean;
|
|
2532
|
+
error?: string;
|
|
2533
|
+
}>;
|
|
2432
2534
|
|
|
2433
|
-
declare
|
|
2535
|
+
declare const KNOWN_NOTIFICATION_TRIGGERS: {
|
|
2536
|
+
readonly ORDER_PLACED: "order_placed";
|
|
2537
|
+
readonly ORDER_CANCELLED: "order_cancelled";
|
|
2538
|
+
};
|
|
2539
|
+
interface OrderTriggerPayload {
|
|
2540
|
+
orderId: number;
|
|
2541
|
+
orderNumber: string;
|
|
2542
|
+
customerName: string;
|
|
2543
|
+
customerPhone: string | null;
|
|
2544
|
+
total: number | string;
|
|
2545
|
+
currency: string;
|
|
2546
|
+
vendorId?: number | null;
|
|
2547
|
+
refundAmount?: number | null;
|
|
2548
|
+
}
|
|
2549
|
+
declare class NotificationTriggerEmitter extends EventEmitter {
|
|
2550
|
+
emitTrigger(triggerKey: string, payload: OrderTriggerPayload): void;
|
|
2551
|
+
onAnyTrigger(listener: (triggerKey: string, payload: OrderTriggerPayload) => void): void;
|
|
2552
|
+
}
|
|
2553
|
+
declare const notificationTriggerEmitter: NotificationTriggerEmitter;
|
|
2554
|
+
|
|
2555
|
+
/** Default order lifecycle triggers — seeded by migration, not tied to the `events` table. */
|
|
2556
|
+
declare const DEFAULT_ORDER_NOTIFICATION_TRIGGER_SEEDS: readonly [{
|
|
2557
|
+
readonly triggerKey: "order_placed";
|
|
2558
|
+
readonly label: "Order placed";
|
|
2559
|
+
readonly description: "Fires when a new order is created (storefront checkout or admin).";
|
|
2560
|
+
readonly category: "order";
|
|
2561
|
+
readonly sortOrder: 1;
|
|
2562
|
+
}, {
|
|
2563
|
+
readonly triggerKey: "order_cancelled";
|
|
2564
|
+
readonly label: "Order cancelled";
|
|
2565
|
+
readonly description: "Fires when an order is cancelled (includes refund amount when applicable).";
|
|
2566
|
+
readonly category: "order";
|
|
2567
|
+
readonly sortOrder: 2;
|
|
2568
|
+
}];
|
|
2569
|
+
|
|
2570
|
+
/** @deprecated Use DB catalog `order_notification_triggers`; kept for type hints. */
|
|
2571
|
+
declare const ORDER_NOTIFICATION_TRIGGERS: readonly [{
|
|
2572
|
+
readonly key: "order_placed";
|
|
2573
|
+
readonly label: "Order placed";
|
|
2574
|
+
}, {
|
|
2575
|
+
readonly key: "order_cancelled";
|
|
2576
|
+
readonly label: "Order cancelled";
|
|
2577
|
+
}];
|
|
2578
|
+
type OrderNotificationTriggerKey = (typeof ORDER_NOTIFICATION_TRIGGERS)[number]['key'];
|
|
2434
2579
|
|
|
2435
|
-
type
|
|
2436
|
-
|
|
2437
|
-
headers?: HeadersInit;
|
|
2438
|
-
}) => Response;
|
|
2439
|
-
declare function assertCaptchaOk(getCms: (() => Promise<{
|
|
2440
|
-
getPlugin: (name: string) => unknown;
|
|
2441
|
-
}>) | undefined, body: Record<string, unknown>, req: Request, json: JsonResponse): Promise<Response | null>;
|
|
2580
|
+
type VendorOnboardedActivation = 'invite' | 'password';
|
|
2581
|
+
type VendorOnboardedKind = 'vendor_onboard' | 'team_invite';
|
|
2442
2582
|
|
|
2443
|
-
interface
|
|
2444
|
-
|
|
2445
|
-
link?: string;
|
|
2446
|
-
/** Short excerpt */
|
|
2447
|
-
summary?: string;
|
|
2448
|
-
/** Full content if available */
|
|
2449
|
-
content?: string;
|
|
2450
|
-
date: Date;
|
|
2451
|
-
creator?: string;
|
|
2452
|
-
categories?: string[];
|
|
2583
|
+
interface EntityMapLike {
|
|
2584
|
+
configs: unknown;
|
|
2453
2585
|
}
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
'content:encoded'?: string;
|
|
2466
|
-
categories?: string[];
|
|
2467
|
-
guid?: string | {
|
|
2468
|
-
_: string;
|
|
2469
|
-
};
|
|
2470
|
-
};
|
|
2471
|
-
declare function getRssArticleSummaryFromItem(item: RssItem): {
|
|
2472
|
-
summary: string;
|
|
2473
|
-
fullContent: string;
|
|
2474
|
-
};
|
|
2475
|
-
type BlogGeneratorDraftParseMode = 'json' | 'plaintext';
|
|
2476
|
-
interface BlogGeneratorSeoDraft {
|
|
2477
|
-
title: string | null;
|
|
2478
|
-
description: string | null;
|
|
2479
|
-
keywords: string | null;
|
|
2480
|
-
ogTitle: string | null;
|
|
2481
|
-
ogDescription: string | null;
|
|
2586
|
+
interface SendVendorOnboardEmailInput {
|
|
2587
|
+
vendorName: string;
|
|
2588
|
+
vendorSlug?: string;
|
|
2589
|
+
ownerName: string;
|
|
2590
|
+
ownerEmail: string;
|
|
2591
|
+
activation: VendorOnboardedActivation;
|
|
2592
|
+
inviteLink?: string;
|
|
2593
|
+
signInLink: string;
|
|
2594
|
+
kind?: VendorOnboardedKind;
|
|
2595
|
+
/** When false, skips owner email but still notifies internal recipients. Default true. */
|
|
2596
|
+
sendToOwner?: boolean;
|
|
2482
2597
|
}
|
|
2483
|
-
interface
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
/** Short plain-text copy for social (e.g. LinkedIn); optional until social LLM step runs. */
|
|
2488
|
-
socialMediaContent?: string | null;
|
|
2489
|
-
categoryName: string | null;
|
|
2490
|
-
seo: BlogGeneratorSeoDraft;
|
|
2491
|
-
/** Suggested tag labels (may not exist in CMS yet). */
|
|
2492
|
-
tags: string[];
|
|
2493
|
-
parseMode: BlogGeneratorDraftParseMode;
|
|
2598
|
+
interface SendVendorOnboardEmailDeps {
|
|
2599
|
+
getDataSource: () => Promise<DataSource>;
|
|
2600
|
+
entityMap: EntityMapLike;
|
|
2601
|
+
getCms: () => Promise<CmsAppLike$3>;
|
|
2494
2602
|
}
|
|
2495
|
-
/**
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
}
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
2603
|
+
/** After vendor onboard / team invite: email owner + platform team from plugin settings. */
|
|
2604
|
+
declare function sendVendorOnboardEmails(input: SendVendorOnboardEmailInput, deps: SendVendorOnboardEmailDeps): Promise<{
|
|
2605
|
+
ownerEmailSent: boolean;
|
|
2606
|
+
}>;
|
|
2607
|
+
|
|
2608
|
+
interface DataSourceManager {
|
|
2609
|
+
getDataSource: () => DataSource;
|
|
2610
|
+
getDataSourceInitialized: () => Promise<DataSource>;
|
|
2611
|
+
resetDataSource: () => void;
|
|
2612
|
+
registerOnReset: (cb: () => void) => void;
|
|
2613
|
+
isConnectionError: (e: unknown) => boolean;
|
|
2614
|
+
}
|
|
2615
|
+
declare function createDataSourceManager(entityMap: Record<string, unknown>, options?: {
|
|
2616
|
+
databaseUrl?: string;
|
|
2617
|
+
idleTimeoutMillis?: number;
|
|
2618
|
+
}): DataSourceManager;
|
|
2619
|
+
|
|
2620
|
+
interface SeedEntityMap {
|
|
2621
|
+
users: unknown;
|
|
2622
|
+
user_groups: unknown;
|
|
2623
|
+
}
|
|
2624
|
+
declare function seedDefaultAdmin(ds: DataSource, entityMap: SeedEntityMap, opts?: {
|
|
2625
|
+
email?: string;
|
|
2626
|
+
password?: string;
|
|
2627
|
+
}): Promise<void>;
|
|
2628
|
+
|
|
2629
|
+
type UserVendorContext = {
|
|
2630
|
+
vendorIds: number[];
|
|
2631
|
+
activeVendorId: number | null;
|
|
2632
|
+
/** @deprecated legacy vendor_users.role */
|
|
2633
|
+
vendorRole: VendorUserRole | null;
|
|
2634
|
+
vendorRoleId: number | null;
|
|
2635
|
+
vendorRoleName: string | null;
|
|
2636
|
+
isVendorRoleOwner: boolean;
|
|
2637
|
+
vendorEntityPerms: Record<string, EntityPermissionFlags>;
|
|
2529
2638
|
};
|
|
2639
|
+
/** Load vendor membership + active vendor role permissions for session. */
|
|
2640
|
+
declare function loadUserVendorContext(dataSource: DataSource, userId: number, preferredVendorId?: number | null): Promise<UserVendorContext>;
|
|
2641
|
+
|
|
2530
2642
|
/**
|
|
2531
|
-
*
|
|
2532
|
-
* If the model still returns legacy JSON with `blogHtml` / `blogMarkdown`, returns a single draft from that object.
|
|
2643
|
+
* Build NextAuth options for credentials auth. App can extend/override via extend().
|
|
2533
2644
|
*/
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
|
|
2645
|
+
|
|
2646
|
+
interface NextAuthUser {
|
|
2647
|
+
id: number;
|
|
2648
|
+
email: string;
|
|
2649
|
+
name: string | null;
|
|
2650
|
+
password: string | null;
|
|
2651
|
+
blocked?: boolean;
|
|
2652
|
+
deleted?: boolean;
|
|
2653
|
+
groupId?: number | null;
|
|
2654
|
+
adminAccess?: boolean;
|
|
2655
|
+
group?: {
|
|
2656
|
+
name?: string;
|
|
2657
|
+
permissions?: Array<{
|
|
2658
|
+
entity: string;
|
|
2659
|
+
canCreate: boolean;
|
|
2660
|
+
canRead: boolean;
|
|
2661
|
+
canUpdate: boolean;
|
|
2662
|
+
canDelete: boolean;
|
|
2663
|
+
}>;
|
|
2543
2664
|
};
|
|
2665
|
+
vendorIds?: number[];
|
|
2666
|
+
activeVendorId?: number | null;
|
|
2667
|
+
vendorRole?: 'owner' | 'staff' | null;
|
|
2668
|
+
vendorRoleId?: number | null;
|
|
2669
|
+
vendorRoleName?: string | null;
|
|
2670
|
+
isVendorRoleOwner?: boolean;
|
|
2671
|
+
vendorEntityPerms?: Record<string, {
|
|
2672
|
+
c: boolean;
|
|
2673
|
+
r: boolean;
|
|
2674
|
+
u: boolean;
|
|
2675
|
+
d: boolean;
|
|
2676
|
+
}>;
|
|
2677
|
+
}
|
|
2678
|
+
interface AuthorizeOtpInput {
|
|
2679
|
+
identifier: string;
|
|
2680
|
+
channel: 'email' | 'sms';
|
|
2681
|
+
code: string;
|
|
2682
|
+
}
|
|
2683
|
+
interface NextAuthOptionsConfig {
|
|
2684
|
+
/** Resolve user by email (e.g. from TypeORM). Return null if not found. */
|
|
2685
|
+
getUserByEmail: (email: string) => Promise<NextAuthUser | null>;
|
|
2686
|
+
comparePassword: (plain: string, hash: string) => Promise<boolean>;
|
|
2687
|
+
signInPage?: string;
|
|
2688
|
+
secret?: string;
|
|
2689
|
+
extend?: (options: NextAuthOptions) => NextAuthOptions;
|
|
2690
|
+
/** When false, password CredentialsProvider is omitted. Default true. */
|
|
2691
|
+
enablePasswordLogin?: boolean;
|
|
2692
|
+
/** When true, registers CredentialsProvider id `otp`. Requires authorizeOtp. Default false. */
|
|
2693
|
+
enableOtpLogin?: boolean;
|
|
2694
|
+
/** Validate OTP and return user (same shape as password flow) or null. */
|
|
2695
|
+
authorizeOtp?: (input: AuthorizeOtpInput) => Promise<NextAuthUser | null>;
|
|
2544
2696
|
/**
|
|
2545
|
-
*
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
* Third LLM call: one draft at a time — short social copy (JSON `{ socialMediaContent }`).
|
|
2550
|
-
*/
|
|
2551
|
-
private enrichBlogDraftWithLlmSocial;
|
|
2552
|
-
/**
|
|
2553
|
-
* Fetches the latest item for each RSS URL, then calls {@link LlmServiceInterface.chatAgent}.
|
|
2554
|
-
* `userPrompt` is only per-feed source material; rules live in the system prompt.
|
|
2555
|
-
* Expects HTML article fragment(s), optionally separated by {@link BLOG_GENERATOR_MARKDOWN_ARTICLE_SEPARATOR}.
|
|
2697
|
+
* Customer group sign-in policy for credentials/OTP on a shared `/api/auth` route:
|
|
2698
|
+
* - `true` — always allow (dedicated storefront auth)
|
|
2699
|
+
* - `false` — always block
|
|
2700
|
+
* - omitted — auto: allow unless `callbackUrl` targets `/admin` (storefront `/signin` works unchanged)
|
|
2556
2701
|
*/
|
|
2557
|
-
|
|
2558
|
-
llm: LlmServiceInterface;
|
|
2559
|
-
/** Single feed (legacy). */
|
|
2560
|
-
rssUrl?: string;
|
|
2561
|
-
/** One or more feeds; latest item per URL is sent together. Prefer this when multiple URLs. */
|
|
2562
|
-
rssUrls?: readonly string[];
|
|
2563
|
-
systemInstruction?: string;
|
|
2564
|
-
validationRules?: string;
|
|
2565
|
-
/** Reserved for future structured output; writer does not inject categories into the user prompt. */
|
|
2566
|
-
categoryNamesHint?: readonly string[];
|
|
2567
|
-
/** Names of non-deleted tags in CMS (hint for reuse). */
|
|
2568
|
-
tagNamesHint?: readonly string[];
|
|
2569
|
-
/** From optional `llm_agents` row (slug `blog-generator`): model / sampling for the writer step. */
|
|
2570
|
-
llmAgentChatOptions?: Pick<LlmAgentOptions, 'model' | 'temperature' | 'max_tokens'>;
|
|
2571
|
-
/** Optional overrides for the metadata step; defaults live in `blog-generator-metadata-defaults.ts`. */
|
|
2572
|
-
metadataSystemInstruction?: string;
|
|
2573
|
-
metadataValidationRules?: string;
|
|
2574
|
-
/** From optional `llm_agents` row (slug `blog-generator-metadata`): model / sampling for metadata only. */
|
|
2575
|
-
metadataLlmAgentChatOptions?: Pick<LlmAgentOptions, 'model' | 'temperature' | 'max_tokens'>;
|
|
2576
|
-
/** Optional overrides for the social-summary step; defaults in `blog-generator-social-defaults.ts`. */
|
|
2577
|
-
socialSystemInstruction?: string;
|
|
2578
|
-
socialValidationRules?: string;
|
|
2579
|
-
/** From optional `llm_agents` row (slug `blog-generator-social`): model / sampling for social copy only. */
|
|
2580
|
-
socialLlmAgentChatOptions?: Pick<LlmAgentOptions, 'model' | 'temperature' | 'max_tokens'>;
|
|
2581
|
-
}): Promise<{
|
|
2582
|
-
agentName: string;
|
|
2583
|
-
feedArticles: Array<{
|
|
2584
|
-
rssUrl: string;
|
|
2585
|
-
article: LatestArticleFromFeed;
|
|
2586
|
-
}>;
|
|
2587
|
-
/** First feed's article (backward compatibility). */
|
|
2588
|
-
article: LatestArticleFromFeed;
|
|
2589
|
-
/** Raw model reply (HTML body per defaults; legacy markdown or JSON still parsed when present). */
|
|
2590
|
-
blogMarkdown: string;
|
|
2591
|
-
blogDrafts: BlogGeneratorBlogDraft[];
|
|
2592
|
-
/** Same as first draft; backward compatibility. */
|
|
2593
|
-
blogDraft: BlogGeneratorBlogDraft;
|
|
2594
|
-
}>;
|
|
2702
|
+
allowCustomerLogin?: boolean;
|
|
2595
2703
|
}
|
|
2704
|
+
declare function getNextAuthOptions(config: NextAuthOptionsConfig): NextAuthOptions;
|
|
2705
|
+
/** Storefront sign-in: allows Customer group; use with signInPage `/signin`. */
|
|
2706
|
+
declare function getStorefrontNextAuthOptions(config: Omit<NextAuthOptionsConfig, 'allowCustomerLogin'>): NextAuthOptions;
|
|
2596
2707
|
|
|
2597
|
-
|
|
2598
|
-
declare const BLOG_GENERATOR_AGENT_NAME = "Blog Generator Agent";
|
|
2599
|
-
/**
|
|
2600
|
-
* Optional `llm_agents` row: when present and enabled, model / temperature / max_tokens
|
|
2601
|
-
* are applied to {@link LlmServiceInterface.chatAgent} (system + user content still come from blog generator defaults / UI).
|
|
2602
|
-
*/
|
|
2603
|
-
declare const BLOG_GENERATOR_LLM_AGENT_SLUG = "blog-generator";
|
|
2604
|
-
/** Line that separates multiple articles in the model reply (HTML or legacy markdown; must match parser and prompts). */
|
|
2605
|
-
declare const BLOG_GENERATOR_MARKDOWN_ARTICLE_SEPARATOR = "---BLOG_GENERATOR_NEXT---";
|
|
2606
|
-
declare const BLOG_GENERATOR_DEFAULT_SYSTEM_INSTRUCTION = "You are a professional financial and business content writer.\n\nYour task is to generate completely original, high-quality blog article(s) from the latest RSS-derived source material in the user message (one block per feed). The user message is factual input only.\n\nIMPORTANT RULES:\n\n1. NEVER copy the RSS article directly.\n2. Rewrite the information into a fresh, human-like article.\n3. Expand the topic with professional insights and explanations.\n4. Maintain a natural editorial tone.\n5. Make the article SEO-friendly.\n6. Use engaging headings and subheadings.\n7. Avoid robotic AI phrasing.\n8. Do not mention that the content came from RSS or feeds.\n9. Preserve factual accuracy from the source material.\n10. The output should feel like a professionally written industry blog.\n\nMULTIPLE FEEDS:\n- If several feeds are provided, compare them: if they largely cover the same story or overlap heavily, produce ONE cohesive article.\n- If they cover clearly different topics or distinct stories, produce MULTIPLE articles (one per distinct story).\n- You may also produce one synthesis plus a short separate angle when that best serves the reader\u2014use your judgment.\n\nWRITING STYLE:\n- Professional\n- Clear\n- Informative\n- Business-focused\n- Human sounding\n- Modern editorial style\n\nARTICLE STRUCTURE (each article \u2014 express in HTML):\n1. Engaging introduction\n2. Industry context\n3. Main developments\n4. Key implications\n5. Expert/business analysis\n6. Conclusion\n\nHTML STRUCTURE (STRICT \u2014 each article must be valid, semantic HTML only):\n- Output HTML only. Do not use Markdown (no # headings, no **bold**, no `code fences`).\n- Wrap each complete article in a single root: <article class=\"blog-post\"> ... </article>\n- Inside <article>, use this outline:\n - <header><h1 class=\"blog-post-title\">\u2026main title\u2026</h1></header> (exactly one h1 per article)\n - <section class=\"blog-post-body\"> for all following content\n - Use <h2> and <h3> for section and subsection titles (never skip levels: h1 \u2192 h2 \u2192 h3).\n - Use <p> for paragraphs; keep paragraphs focused (avoid huge unbroken text).\n - Use <ul>/<ol> with <li> for lists where appropriate.\n - Use <strong> and <em> for emphasis sparingly; use <blockquote> only when quoting or callouts fit.\n- Do not include <html>, <head>, <body>, or document-level wrappers \u2014 only the fragment(s) described above.\n- Do not use <script>, <style>, <iframe>, or inline event handlers. Avoid inline style=\"\" except when essential for accessibility (prefer none).\n- Escape angle brackets in body text if you must mention markup; keep output safe for embedding in a CMS.\n\nCONTENT REQUIREMENTS:\n- Minimum 800 words per article unless source material is very small.\n- Add context around industry trends where appropriate.\n- Explain why the topic matters.\n- Include practical implications for businesses/professionals.\n\nIF RSS CONTENT IS LIMITED:\n- Expand intelligently using general industry knowledge.\n- Keep the article relevant to the original topic.\n- Do not invent fake facts or statistics.\n\nOUTPUT FORMAT (STRICT \u2014 HTML only):\n- Return ONLY the article HTML fragment(s). No JSON, no preamble or postscript (\"Here is your article\u2026\"), no markdown.\n- If you output more than one article, output multiple <article class=\"blog-post\">\u2026</article> blocks in sequence, and between articles put a single line containing exactly this (and nothing else on that line):\n---BLOG_GENERATOR_NEXT---\n- If you output a single article, use one <article> only and do not use that separator line.";
|
|
2607
|
-
/**
|
|
2608
|
-
* JSON so {@link parseLlmAgentValidationRules} can attach guardrails and allow long source payloads.
|
|
2609
|
-
* Edit in the admin UI if needed; defaults match product intent.
|
|
2610
|
-
*/
|
|
2611
|
-
declare const BLOG_GENERATOR_DEFAULT_VALIDATION_RULES: string;
|
|
2708
|
+
declare function enrichUserWithVendorContext(dataSource: DataSource, user: NextAuthUser | null): Promise<NextAuthUser | null>;
|
|
2612
2709
|
|
|
2613
|
-
/**
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
* To change how metadata is produced, edit the constants in this file (system instruction + validation JSON).
|
|
2620
|
-
* No admin UI override is wired yet; add request body fields in `cms-api-handler` if you need runtime overrides later.
|
|
2621
|
-
*/
|
|
2622
|
-
declare const BLOG_METADATA_ENRICHER_AGENT_NAME = "Blog Generator Metadata";
|
|
2623
|
-
/** `llm_agents.slug` for routing model/temperature for the metadata-only chat step. */
|
|
2624
|
-
declare const BLOG_METADATA_ENRICHER_LLM_AGENT_SLUG = "blog-generator-metadata";
|
|
2625
|
-
declare const BLOG_METADATA_ENRICHER_DEFAULT_SYSTEM_INSTRUCTION = "You are a careful CMS metadata assistant for a publishing system.\n\nYou receive ONE complete blog post as HTML (title is usually in <h1 class=\"blog-post-title\"> or the first <h1>). Your job is to propose structured fields so an editor can save the post: category, URL slug, SEO block, and topical tags.\n\nRULES:\n1. Read the whole article and infer the primary topic and audience.\n2. categoryName must be EXACTLY one string from AVAILABLE_BLOG_CATEGORIES in the user message, or \"\" if none fit.\n3. blogSlug: lowercase kebab-case, ASCII letters/digits/hyphens only, no leading/trailing hyphens, max ~80 chars. Derive from the main topic or title.\n4. seo.title: concise meta title (~50\u201360 characters when reasonable).\n5. seo.description: meta description (~150\u2013160 characters when reasonable), plain text.\n6. seo.keywords: comma-separated phrases, no stuffing.\n7. seo.ogTitle / seo.ogDescription: may mirror title/description or be slightly adapted for social.\n8. tags: 4\u201310 short labels (1\u20133 words each). Prefer exact matches from EXISTING_TAG_NAMES when they truly apply; otherwise invent precise new labels (they may be created in the CMS later).\n9. Do not invent statistics, quotes, or URLs not implied by the article.\n10. Output JSON only \u2014 no markdown outside the JSON, no commentary.\n\nOUTPUT FORMAT (STRICT):\nReturn a single JSON object only. Do not wrap it in a markdown code fence.\n\n{\n \"categoryName\": \"string \u2014 exact match from list or empty string\",\n \"blogSlug\": \"string \u2014 url-safe kebab-case\",\n \"seo\": {\n \"title\": \"string or empty\",\n \"description\": \"string or empty\",\n \"keywords\": \"string or empty\",\n \"ogTitle\": \"string or empty\",\n \"ogDescription\": \"string or empty\"\n },\n \"tags\": [\"tag-one\", \"tag-two\"]\n}";
|
|
2626
|
-
declare const BLOG_METADATA_ENRICHER_DEFAULT_VALIDATION_RULES: string;
|
|
2710
|
+
/** Merge DB group + vendor_users into session (JWT often missing these). Server/API only. */
|
|
2711
|
+
declare function hydrateVendorSessionUser(dataSource: DataSource, user: SessionUser | null | undefined): Promise<SessionUser | null | undefined>;
|
|
2712
|
+
declare function invalidateMultiVendorCache(): void;
|
|
2713
|
+
declare function checkMultiVendorEnabled(dataSource: DataSource): Promise<boolean>;
|
|
2714
|
+
declare function invalidateEventsCache(): void;
|
|
2715
|
+
declare function checkEventsEnabled(dataSource: DataSource): Promise<boolean>;
|
|
2627
2716
|
|
|
2628
|
-
interface
|
|
2629
|
-
|
|
2630
|
-
|
|
2717
|
+
interface NavItem {
|
|
2718
|
+
id: string;
|
|
2719
|
+
label: string;
|
|
2720
|
+
url: string;
|
|
2721
|
+
openInNewTab?: boolean;
|
|
2722
|
+
/** When set, url is derived from the linked page slug. */
|
|
2723
|
+
pageId?: number;
|
|
2724
|
+
children?: NavItem[];
|
|
2631
2725
|
}
|
|
2632
|
-
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
|
|
2726
|
+
interface NavbarConfig {
|
|
2727
|
+
logo: string;
|
|
2728
|
+
items: NavItem[];
|
|
2729
|
+
ctaLabel?: string;
|
|
2730
|
+
ctaUrl?: string;
|
|
2731
|
+
/** Optional variant for theme-specific layout (e.g. "page2"). */
|
|
2732
|
+
variant?: string;
|
|
2733
|
+
}
|
|
2734
|
+
interface FooterConfig {
|
|
2735
|
+
copyright: string;
|
|
2736
|
+
columns: {
|
|
2737
|
+
title: string;
|
|
2738
|
+
links: {
|
|
2739
|
+
label: string;
|
|
2740
|
+
url: string;
|
|
2741
|
+
}[];
|
|
2742
|
+
}[];
|
|
2743
|
+
socialLinks: {
|
|
2744
|
+
icon: string;
|
|
2745
|
+
url: string;
|
|
2746
|
+
}[];
|
|
2747
|
+
/** When set, footer shows this logo (e.g. same as navbar). */
|
|
2748
|
+
logo?: string;
|
|
2650
2749
|
}
|
|
2651
|
-
declare function createSocialMediaHandlers(config: SocialMediaApiConfig): {
|
|
2652
|
-
getLinkedInStatus(req: Request): Promise<Response>;
|
|
2653
|
-
fetchLinkedInOrganizations(req: Request): Promise<Response>;
|
|
2654
|
-
syncLinkedInProfile(req: Request): Promise<Response>;
|
|
2655
|
-
publishBlogToLinkedIn(req: Request, blogId: number): Promise<Response>;
|
|
2656
|
-
getFacebookStatus(req: Request): Promise<Response>;
|
|
2657
|
-
publishBlogToFacebook(req: Request, blogId: number): Promise<Response>;
|
|
2658
|
-
/**
|
|
2659
|
-
* POST JSON `{ appId, appSecret, userAccessToken }`. Calls Graph `GET /me/accounts` with the user token.
|
|
2660
|
-
* App ID and secret are validated but not used yet (reserved for future token flows).
|
|
2661
|
-
* Persist credentials via Plugins → Save: `meta_app_id` (public), `meta_app_secret` and `meta_user_access_token` (encrypted).
|
|
2662
|
-
*/
|
|
2663
|
-
fetchFacebookManagedPages(req: Request): Promise<Response>;
|
|
2664
|
-
};
|
|
2665
|
-
|
|
2666
|
-
/**
|
|
2667
|
-
* Meta (Facebook) Graph API helpers (server-side). Uses fetch — no SDK.
|
|
2668
|
-
* @see https://developers.facebook.com/docs/graph-api/reference/user/accounts
|
|
2669
|
-
*/
|
|
2670
|
-
type FacebookPageAccount = {
|
|
2671
|
-
access_token?: string;
|
|
2672
|
-
category?: string;
|
|
2673
|
-
name?: string;
|
|
2674
|
-
id?: string;
|
|
2675
|
-
/** Graph may return additional fields */
|
|
2676
|
-
[key: string]: unknown;
|
|
2677
|
-
};
|
|
2678
|
-
type FacebookMeAccountsResponse = {
|
|
2679
|
-
data?: FacebookPageAccount[];
|
|
2680
|
-
paging?: Record<string, unknown>;
|
|
2681
|
-
error?: {
|
|
2682
|
-
message?: string;
|
|
2683
|
-
type?: string;
|
|
2684
|
-
code?: number;
|
|
2685
|
-
fbtrace_id?: string;
|
|
2686
|
-
};
|
|
2687
|
-
};
|
|
2688
|
-
/**
|
|
2689
|
-
* Lists Facebook Pages the user manages (page access tokens + metadata).
|
|
2690
|
-
* Requires a User access token with `pages_show_list` or equivalent page permissions.
|
|
2691
|
-
*/
|
|
2692
|
-
declare function metaFetchUserManagedPages(userAccessToken: string): Promise<FacebookMeAccountsResponse>;
|
|
2693
|
-
type MetaGraphMutationResponse = {
|
|
2694
|
-
id?: string;
|
|
2695
|
-
post_id?: string;
|
|
2696
|
-
error?: {
|
|
2697
|
-
message?: string;
|
|
2698
|
-
type?: string;
|
|
2699
|
-
code?: number;
|
|
2700
|
-
fbtrace_id?: string;
|
|
2701
|
-
};
|
|
2702
|
-
};
|
|
2703
|
-
/** Resolves the long-lived page access token for a Page ID from `/me/accounts` data. */
|
|
2704
|
-
declare function metaResolvePageAccessToken(accounts: FacebookMeAccountsResponse, pageId: string): string | null;
|
|
2705
|
-
/**
|
|
2706
|
-
* Upload a photo to a Page timeline (multipart).
|
|
2707
|
-
* @see https://developers.facebook.com/docs/graph-api/reference/page/photos#Creating
|
|
2708
|
-
*/
|
|
2709
|
-
declare function metaPostPagePhoto(opts: {
|
|
2710
|
-
pageId: string;
|
|
2711
|
-
pageAccessToken: string;
|
|
2712
|
-
imageBuffer: Buffer;
|
|
2713
|
-
contentType: string;
|
|
2714
|
-
caption: string;
|
|
2715
|
-
}): Promise<MetaGraphMutationResponse>;
|
|
2716
|
-
/**
|
|
2717
|
-
* Publish a text-only post to the Page feed (when no JPEG/PNG image is available).
|
|
2718
|
-
* @see https://developers.facebook.com/docs/graph-api/reference/page/feed#Creating
|
|
2719
|
-
*/
|
|
2720
|
-
declare function metaPostPageFeed(opts: {
|
|
2721
|
-
pageId: string;
|
|
2722
|
-
pageAccessToken: string;
|
|
2723
|
-
message: string;
|
|
2724
|
-
}): Promise<MetaGraphMutationResponse>;
|
|
2725
2750
|
|
|
2726
|
-
interface
|
|
2727
|
-
|
|
2728
|
-
|
|
2751
|
+
interface PublicThemeSettingsPayload {
|
|
2752
|
+
activeThemeId: string;
|
|
2753
|
+
primaryColor: string;
|
|
2754
|
+
secondaryColor: string;
|
|
2755
|
+
navbarConfig: NavbarConfig;
|
|
2756
|
+
footerOverrides: Partial<FooterConfig>;
|
|
2729
2757
|
}
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
|
|
2758
|
+
declare function loadPublicThemeSettings(config: {
|
|
2759
|
+
dataSource: DataSource;
|
|
2760
|
+
entityMap: EntityMap$2;
|
|
2761
|
+
encryptionKey?: string;
|
|
2762
|
+
defaultActiveThemeId?: string;
|
|
2763
|
+
defaultPrimaryColor?: string;
|
|
2764
|
+
defaultSecondaryColor?: string;
|
|
2765
|
+
}): Promise<PublicThemeSettingsPayload>;
|
|
2737
2766
|
|
|
2738
|
-
|
|
2739
|
-
declare function
|
|
2740
|
-
|
|
2741
|
-
declare function
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
|
|
2767
|
+
/** Normalize a logical media folder path: no leading/trailing slashes, no ".." segments, max length. */
|
|
2768
|
+
declare function sanitizeMediaFolderPath(input: unknown): string;
|
|
2769
|
+
/** Single path segment for storage (folder name or legacy path segment). */
|
|
2770
|
+
declare function sanitizeStorageSegment(name: string): string;
|
|
2771
|
+
|
|
2772
|
+
type EntityMap = Record<string, EntityTarget<ObjectLiteral>>;
|
|
2773
|
+
/** Build `a/b/c` path under `uploads/` from the chain of folder rows up to root. */
|
|
2774
|
+
declare function relativePathFromMediaParentId(dataSource: DataSource, entityMap: EntityMap, parentId: number | null): Promise<string>;
|
|
2775
|
+
|
|
2776
|
+
declare const ZIP_MIME_TYPES: Set<string>;
|
|
2777
|
+
declare function isZipMedia(mime: string | null | undefined, filename: string): boolean;
|
|
2745
2778
|
|
|
2746
|
-
/** Minimal SEO row shape (DB or API). */
|
|
2747
|
-
type SeoLike = {
|
|
2748
|
-
title?: string | null;
|
|
2749
|
-
description?: string | null;
|
|
2750
|
-
keywords?: string | null;
|
|
2751
|
-
ogTitle?: string | null;
|
|
2752
|
-
ogDescription?: string | null;
|
|
2753
|
-
ogImage?: string | null;
|
|
2754
|
-
};
|
|
2755
|
-
type SeoMetadataOverrides = {
|
|
2756
|
-
title?: string;
|
|
2757
|
-
description?: string;
|
|
2758
|
-
keywords?: string;
|
|
2759
|
-
ogTitle?: string;
|
|
2760
|
-
ogDescription?: string;
|
|
2761
|
-
ogImage?: string;
|
|
2762
|
-
};
|
|
2763
|
-
/** Per-field: join row wins over slug row. */
|
|
2764
|
-
declare function mergeSeoBySlug(join: SeoLike | null | undefined, bySlug: SeoLike | null): SeoLike | null;
|
|
2765
|
-
declare function fetchSeoBySlug(dataSource: DataSource, entityMap: EntityMap$2, slug: string): Promise<SeoLike | null>;
|
|
2766
2779
|
/**
|
|
2767
|
-
*
|
|
2768
|
-
* `
|
|
2769
|
-
*
|
|
2780
|
+
* Executes `fn` inside a transaction where the PostgreSQL GUC
|
|
2781
|
+
* `app.vendor_id` is set for the duration of that transaction.
|
|
2782
|
+
*
|
|
2783
|
+
* This activates the `vendor_isolation` RLS policy added by the
|
|
2784
|
+
* `VendorRls1775940000000` migration.
|
|
2785
|
+
*
|
|
2786
|
+
* vendorId = 0 → admin / all-access (policy allows everything)
|
|
2787
|
+
* vendorId > 0 → only rows whose `vendorId` column matches
|
|
2788
|
+
*
|
|
2789
|
+
* Example:
|
|
2790
|
+
* const orders = await withVendorRlsContext(dataSource, 4, (ds) =>
|
|
2791
|
+
* ds.getRepository(Order).find({ where: { deleted: false } })
|
|
2792
|
+
* );
|
|
2770
2793
|
*/
|
|
2771
|
-
declare function
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
fallbacks?: SeoMetadataOverrides;
|
|
2778
|
-
canonicalPath?: string;
|
|
2779
|
-
metadataBase?: URL;
|
|
2780
|
-
}): Promise<Metadata>;
|
|
2781
|
-
|
|
2782
|
-
/** Links an unclaimed contact (same email, no userId) to the new user after signup or invite. */
|
|
2783
|
-
declare function linkUnclaimedContactToUser(dataSource: DataSource, contactsEntity: EntityTarget<ObjectLiteral>, userId: number, email: string): Promise<void>;
|
|
2794
|
+
declare function withVendorRlsContext<T>(dataSource: DataSource, vendorId: number, fn: (dataSource: DataSource) => Promise<T>): Promise<T>;
|
|
2795
|
+
/**
|
|
2796
|
+
* Convenience wrapper: sets admin mode (vendor_id = '0') so all rows are
|
|
2797
|
+
* visible regardless of their vendorId. Use for platform-admin queries.
|
|
2798
|
+
*/
|
|
2799
|
+
declare function withAdminRlsContext<T>(dataSource: DataSource, fn: (dataSource: DataSource) => Promise<T>): Promise<T>;
|
|
2784
2800
|
|
|
2785
|
-
type
|
|
2786
|
-
id: number;
|
|
2801
|
+
type EnsureVendorCustomerDetails = {
|
|
2787
2802
|
name: string;
|
|
2788
2803
|
email: string;
|
|
2789
2804
|
phone?: string | null;
|
|
2790
2805
|
};
|
|
2791
|
-
|
|
2792
|
-
|
|
2806
|
+
declare function isCustomerTypeContact(type: unknown): boolean;
|
|
2807
|
+
/** Restrict contact list to rows linked in `vendor_customers` with type customer. */
|
|
2808
|
+
declare function applyVendorCustomersContactFilter(qb: SelectQueryBuilder<typeorm.ObjectLiteral>, contactAlias: string, scope: VendorScope, vendorIdFilter: number | null): void;
|
|
2809
|
+
declare function contactIsVendorCustomer(dataSource: DataSource, entityMap: EntityMap$2, vendorId: number, contactId: number): Promise<boolean>;
|
|
2810
|
+
/** Returns an error message when the contact is not a vendor-linked customer; otherwise null. */
|
|
2811
|
+
declare function assertContactAllowedForVendorOrder(dataSource: DataSource, entityMap: EntityMap$2, vendorId: number, contactId: number): Promise<string | null>;
|
|
2812
|
+
declare function resolveVendorIdForContactCheck(scope: VendorScope, bodyOrRow: Record<string, unknown>): number | null;
|
|
2793
2813
|
/**
|
|
2794
|
-
*
|
|
2795
|
-
*
|
|
2814
|
+
* When an order is placed for a manually entered customer, ensure they appear in
|
|
2815
|
+
* vendor customers: customer row, vendor_customers link, and contact type.
|
|
2796
2816
|
*/
|
|
2797
|
-
declare function
|
|
2798
|
-
phone?: string | null;
|
|
2799
|
-
}): Promise<{
|
|
2800
|
-
id: number;
|
|
2801
|
-
} | null>;
|
|
2802
|
-
|
|
2803
|
-
/** Parse stored config value into a list of emails (JSON array, or comma/semicolon-separated string). */
|
|
2804
|
-
declare function parseEmailRecipientsFromConfig(raw: string | undefined | null): string[];
|
|
2805
|
-
/** Serialize email list for config storage (JSON array in DB). */
|
|
2806
|
-
declare function serializeEmailRecipients(emails: string[]): string;
|
|
2807
|
-
/** Join for SMTP `to` header (multiple recipients). */
|
|
2808
|
-
declare function joinRecipientsForSend(emails: string[]): string | null;
|
|
2817
|
+
declare function ensureVendorCustomerForOrderContact(dataSource: DataSource, entityMap: EntityMap$2, vendorId: number, contactId: number, details: EnsureVendorCustomerDetails): Promise<void>;
|
|
2809
2818
|
|
|
2810
|
-
|
|
2811
|
-
type
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
|
|
2820
|
-
|
|
2821
|
-
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
}
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
}
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2819
|
+
/** One band: refund % when cancellation falls N days before event start. */
|
|
2820
|
+
type RefundPolicyTier = {
|
|
2821
|
+
/** Inclusive lower bound (days before event start; 0 = event day). */
|
|
2822
|
+
fromDaysBefore: number;
|
|
2823
|
+
/** Exclusive upper bound, or null for open-ended (e.g. 20+ days). */
|
|
2824
|
+
toDaysBefore: number | null;
|
|
2825
|
+
percentage: number;
|
|
2826
|
+
};
|
|
2827
|
+
type RefundPolicyType = 'percentage' | 'event_tiers';
|
|
2828
|
+
type RefundPolicyLike = {
|
|
2829
|
+
id?: number;
|
|
2830
|
+
type: RefundPolicyType;
|
|
2831
|
+
value: number;
|
|
2832
|
+
refundWindowDays: number;
|
|
2833
|
+
tiers?: RefundPolicyTier[] | null;
|
|
2834
|
+
};
|
|
2835
|
+
type RefundCalculationResult = {
|
|
2836
|
+
amount: number;
|
|
2837
|
+
percentage: number;
|
|
2838
|
+
daysBeforeEvent: number | null;
|
|
2839
|
+
daysSincePurchase: number | null;
|
|
2840
|
+
policyId: number | null;
|
|
2841
|
+
summary: string;
|
|
2842
|
+
/** Order cancelled without policy-based refund (no policy on event). */
|
|
2843
|
+
directCancellation?: boolean;
|
|
2844
|
+
eventId?: number | null;
|
|
2845
|
+
eventName?: string | null;
|
|
2846
|
+
};
|
|
2847
|
+
declare function normalizeRefundTiers(raw: unknown): RefundPolicyTier[];
|
|
2848
|
+
declare function validateRefundTiers(tiers: RefundPolicyTier[]): string | null;
|
|
2849
|
+
declare function daysBeforeEventStart(eventStart: Date, asOf?: Date): number;
|
|
2850
|
+
declare function formatTierRange(tier: RefundPolicyTier): string;
|
|
2851
|
+
declare function describeEventTierPolicy(tiers: RefundPolicyTier[]): string;
|
|
2852
|
+
declare function calculateRefundFromPolicy(policy: RefundPolicyLike | null | undefined, orderTotal: number, options?: {
|
|
2853
|
+
orderCreatedAt?: Date | null;
|
|
2854
|
+
eventStartDate?: Date | null;
|
|
2855
|
+
asOf?: Date;
|
|
2856
|
+
}): RefundCalculationResult;
|
|
2844
2857
|
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
}): Promise<
|
|
2854
|
-
|
|
2858
|
+
type PolicyRow = RefundPolicyLike & {
|
|
2859
|
+
id: number;
|
|
2860
|
+
};
|
|
2861
|
+
declare function calculateOrderRefundPreview(dataSource: DataSource, entityMap: EntityMap$2, order: {
|
|
2862
|
+
id: number;
|
|
2863
|
+
vendorId?: number | null;
|
|
2864
|
+
total?: number | null;
|
|
2865
|
+
createdAt?: Date | string | null;
|
|
2866
|
+
}, asOf?: Date): Promise<RefundCalculationResult & {
|
|
2867
|
+
eventStartDate: string | null;
|
|
2868
|
+
directCancellation: boolean;
|
|
2869
|
+
eventId: number | null;
|
|
2870
|
+
eventName: string | null;
|
|
2871
|
+
}>;
|
|
2872
|
+
/** @deprecated Use event-attached policy via calculateOrderRefundPreview. */
|
|
2873
|
+
declare function findActiveRefundPolicyForVendor(dataSource: DataSource, entityMap: EntityMap$2, vendorId: number | null | undefined): Promise<PolicyRow | null>;
|
|
2855
2874
|
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
2875
|
+
type CaptchaProviderId = 'turnstile' | 'recaptcha_v3';
|
|
2876
|
+
interface CaptchaPublicConfig {
|
|
2877
|
+
enabled: boolean;
|
|
2878
|
+
activeProvider: CaptchaProviderId | null;
|
|
2879
|
+
siteKey: string | null;
|
|
2880
|
+
availableProviders: Array<{
|
|
2881
|
+
id: CaptchaProviderId;
|
|
2882
|
+
siteKey: string;
|
|
2883
|
+
}>;
|
|
2884
|
+
multipleProviders: boolean;
|
|
2860
2885
|
}
|
|
2861
|
-
|
|
2862
|
-
|
|
2863
|
-
|
|
2864
|
-
|
|
2886
|
+
type CaptchaVerifyResult = {
|
|
2887
|
+
ok: true;
|
|
2888
|
+
} | {
|
|
2889
|
+
ok: false;
|
|
2890
|
+
status: number;
|
|
2891
|
+
message: string;
|
|
2892
|
+
};
|
|
2893
|
+
declare function buildCaptchaPublicConfig(config: Record<string, string>): CaptchaPublicConfig;
|
|
2894
|
+
declare class CaptchaService {
|
|
2895
|
+
private readonly env;
|
|
2896
|
+
constructor(env: Record<string, string>);
|
|
2897
|
+
isEnforced(): boolean;
|
|
2898
|
+
getPublicConfig(): CaptchaPublicConfig;
|
|
2899
|
+
verify(body: Record<string, unknown>, req: Request): Promise<CaptchaVerifyResult>;
|
|
2865
2900
|
}
|
|
2866
|
-
/** After payment confirmation: email customer + each sales team address from plugin settings. */
|
|
2867
|
-
declare function sendOrderPlacedEmailsAfterConfirmation(orderId: number, deps: SendOrderPlacedEmailDeps): Promise<void>;
|
|
2868
|
-
|
|
2869
|
-
type VendorOnboardedActivation = 'invite' | 'password';
|
|
2870
|
-
type VendorOnboardedKind = 'vendor_onboard' | 'team_invite';
|
|
2871
2901
|
|
|
2872
|
-
|
|
2873
|
-
configs: unknown;
|
|
2874
|
-
}
|
|
2875
|
-
interface SendVendorOnboardEmailInput {
|
|
2876
|
-
vendorName: string;
|
|
2877
|
-
vendorSlug?: string;
|
|
2878
|
-
ownerName: string;
|
|
2879
|
-
ownerEmail: string;
|
|
2880
|
-
activation: VendorOnboardedActivation;
|
|
2881
|
-
inviteLink?: string;
|
|
2882
|
-
signInLink: string;
|
|
2883
|
-
kind?: VendorOnboardedKind;
|
|
2884
|
-
/** When false, skips owner email but still notifies internal recipients. Default true. */
|
|
2885
|
-
sendToOwner?: boolean;
|
|
2886
|
-
}
|
|
2887
|
-
interface SendVendorOnboardEmailDeps {
|
|
2888
|
-
getDataSource: () => Promise<DataSource>;
|
|
2889
|
-
entityMap: EntityMapLike;
|
|
2890
|
-
getCms: () => Promise<CmsAppLike$3>;
|
|
2891
|
-
}
|
|
2892
|
-
/** After vendor onboard / team invite: email owner + platform team from plugin settings. */
|
|
2893
|
-
declare function sendVendorOnboardEmails(input: SendVendorOnboardEmailInput, deps: SendVendorOnboardEmailDeps): Promise<{
|
|
2894
|
-
ownerEmailSent: boolean;
|
|
2895
|
-
}>;
|
|
2902
|
+
declare function captchaPlugin(): CmsPlugin<CaptchaService | void>;
|
|
2896
2903
|
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
}
|
|
2904
|
-
declare function createDataSourceManager(entityMap: Record<string, unknown>, options?: {
|
|
2905
|
-
databaseUrl?: string;
|
|
2906
|
-
idleTimeoutMillis?: number;
|
|
2907
|
-
}): DataSourceManager;
|
|
2904
|
+
type JsonResponse = (body: unknown, init?: {
|
|
2905
|
+
status?: number;
|
|
2906
|
+
headers?: HeadersInit;
|
|
2907
|
+
}) => Response;
|
|
2908
|
+
declare function assertCaptchaOk(getCms: (() => Promise<{
|
|
2909
|
+
getPlugin: (name: string) => unknown;
|
|
2910
|
+
}>) | undefined, body: Record<string, unknown>, req: Request, json: JsonResponse): Promise<Response | null>;
|
|
2908
2911
|
|
|
2909
|
-
interface
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
+
interface LatestArticleFromFeed {
|
|
2913
|
+
title?: string;
|
|
2914
|
+
link?: string;
|
|
2915
|
+
/** Short excerpt */
|
|
2916
|
+
summary?: string;
|
|
2917
|
+
/** Full content if available */
|
|
2918
|
+
content?: string;
|
|
2919
|
+
date: Date;
|
|
2920
|
+
creator?: string;
|
|
2921
|
+
categories?: string[];
|
|
2912
2922
|
}
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
|
|
2918
|
-
|
|
2919
|
-
|
|
2920
|
-
|
|
2921
|
-
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
|
|
2923
|
+
type RssItem = {
|
|
2924
|
+
title?: string;
|
|
2925
|
+
link?: string;
|
|
2926
|
+
pubDate?: string;
|
|
2927
|
+
isoDate?: string;
|
|
2928
|
+
contentSnippet?: string;
|
|
2929
|
+
summary?: string;
|
|
2930
|
+
description?: string;
|
|
2931
|
+
content?: string;
|
|
2932
|
+
creator?: string;
|
|
2933
|
+
'dc:creator'?: string;
|
|
2934
|
+
'content:encoded'?: string;
|
|
2935
|
+
categories?: string[];
|
|
2936
|
+
guid?: string | {
|
|
2937
|
+
_: string;
|
|
2938
|
+
};
|
|
2927
2939
|
};
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
|
|
2940
|
+
declare function getRssArticleSummaryFromItem(item: RssItem): {
|
|
2941
|
+
summary: string;
|
|
2942
|
+
fullContent: string;
|
|
2943
|
+
};
|
|
2944
|
+
type BlogGeneratorDraftParseMode = 'json' | 'plaintext';
|
|
2945
|
+
interface BlogGeneratorSeoDraft {
|
|
2946
|
+
title: string | null;
|
|
2947
|
+
description: string | null;
|
|
2948
|
+
keywords: string | null;
|
|
2949
|
+
ogTitle: string | null;
|
|
2950
|
+
ogDescription: string | null;
|
|
2951
|
+
}
|
|
2952
|
+
interface BlogGeneratorBlogDraft {
|
|
2953
|
+
title: string;
|
|
2954
|
+
slug?: string;
|
|
2955
|
+
markdown: string;
|
|
2956
|
+
/** Short plain-text copy for social (e.g. LinkedIn); optional until social LLM step runs. */
|
|
2957
|
+
socialMediaContent?: string | null;
|
|
2958
|
+
categoryName: string | null;
|
|
2959
|
+
seo: BlogGeneratorSeoDraft;
|
|
2960
|
+
/** Suggested tag labels (may not exist in CMS yet). */
|
|
2961
|
+
tags: string[];
|
|
2962
|
+
parseMode: BlogGeneratorDraftParseMode;
|
|
2963
|
+
}
|
|
2931
2964
|
/**
|
|
2932
|
-
*
|
|
2965
|
+
* Parses the LLM reply: prefers a single JSON object with blogTitle, blogHtml/blogMarkdown/content, categoryName, seo, …
|
|
2966
|
+
* Falls back to treating the entire string as HTML (or legacy markdown) if JSON parsing fails.
|
|
2933
2967
|
*/
|
|
2934
|
-
|
|
2935
|
-
|
|
2968
|
+
declare function parseBlogGeneratorAgentContent(raw: string): BlogGeneratorBlogDraft;
|
|
2969
|
+
declare function resolveBlogCategoryIdByName(needle: string | null | undefined, rows: readonly {
|
|
2936
2970
|
id: number;
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
|
|
2944
|
-
|
|
2945
|
-
|
|
2946
|
-
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
2971
|
+
name: string;
|
|
2972
|
+
}[]): {
|
|
2973
|
+
categoryId: number | null;
|
|
2974
|
+
matched: boolean;
|
|
2975
|
+
};
|
|
2976
|
+
/**
|
|
2977
|
+
* Minimal user payload: latest item per feed only (system prompt carries writing rules).
|
|
2978
|
+
*/
|
|
2979
|
+
declare function buildRssUserPromptFromFeeds(feeds: ReadonlyArray<{
|
|
2980
|
+
rssUrl: string;
|
|
2981
|
+
article: LatestArticleFromFeed;
|
|
2982
|
+
}>): string;
|
|
2983
|
+
/**
|
|
2984
|
+
* User message for the metadata-only LLM step (one blog at a time).
|
|
2985
|
+
*/
|
|
2986
|
+
declare function buildBlogMetadataUserPrompt(opts: {
|
|
2987
|
+
title: string;
|
|
2988
|
+
markdown: string;
|
|
2989
|
+
categoryNames: readonly string[];
|
|
2990
|
+
tagNames: readonly string[];
|
|
2991
|
+
}): string;
|
|
2992
|
+
/** Parses JSON from the metadata-enrichment LLM (category, slug, seo, tags). */
|
|
2993
|
+
declare function parseBlogMetadataEnrichmentJson(raw: string): {
|
|
2994
|
+
categoryName: string | null;
|
|
2995
|
+
blogSlug: string | null;
|
|
2996
|
+
seo: BlogGeneratorSeoDraft;
|
|
2997
|
+
tags: string[];
|
|
2998
|
+
};
|
|
2999
|
+
/**
|
|
3000
|
+
* Parses LLM output: prefers HTML + {@link BLOG_GENERATOR_MARKDOWN_ARTICLE_SEPARATOR} for multiple articles.
|
|
3001
|
+
* If the model still returns legacy JSON with `blogHtml` / `blogMarkdown`, returns a single draft from that object.
|
|
3002
|
+
*/
|
|
3003
|
+
declare function parseBlogGeneratorModelOutput(raw: string): BlogGeneratorBlogDraft[];
|
|
3004
|
+
declare class BlogGeneratorService {
|
|
3005
|
+
readonly version: "1.0.0";
|
|
3006
|
+
getLatestArticleFromFeed(rssUrl: string): Promise<LatestArticleFromFeed | null>;
|
|
3007
|
+
/** Defaults for the Blog Generator Agent (admin can override per request). */
|
|
3008
|
+
getAgentDefaults(): {
|
|
3009
|
+
agentName: string;
|
|
3010
|
+
systemInstruction: string;
|
|
3011
|
+
validationRules: string;
|
|
2953
3012
|
};
|
|
2954
|
-
vendorIds?: number[];
|
|
2955
|
-
activeVendorId?: number | null;
|
|
2956
|
-
vendorRole?: 'owner' | 'staff' | null;
|
|
2957
|
-
vendorRoleId?: number | null;
|
|
2958
|
-
vendorRoleName?: string | null;
|
|
2959
|
-
isVendorRoleOwner?: boolean;
|
|
2960
|
-
vendorEntityPerms?: Record<string, {
|
|
2961
|
-
c: boolean;
|
|
2962
|
-
r: boolean;
|
|
2963
|
-
u: boolean;
|
|
2964
|
-
d: boolean;
|
|
2965
|
-
}>;
|
|
2966
|
-
}
|
|
2967
|
-
interface AuthorizeOtpInput {
|
|
2968
|
-
identifier: string;
|
|
2969
|
-
channel: 'email' | 'sms';
|
|
2970
|
-
code: string;
|
|
2971
|
-
}
|
|
2972
|
-
interface NextAuthOptionsConfig {
|
|
2973
|
-
/** Resolve user by email (e.g. from TypeORM). Return null if not found. */
|
|
2974
|
-
getUserByEmail: (email: string) => Promise<NextAuthUser | null>;
|
|
2975
|
-
comparePassword: (plain: string, hash: string) => Promise<boolean>;
|
|
2976
|
-
signInPage?: string;
|
|
2977
|
-
secret?: string;
|
|
2978
|
-
extend?: (options: NextAuthOptions) => NextAuthOptions;
|
|
2979
|
-
/** When false, password CredentialsProvider is omitted. Default true. */
|
|
2980
|
-
enablePasswordLogin?: boolean;
|
|
2981
|
-
/** When true, registers CredentialsProvider id `otp`. Requires authorizeOtp. Default false. */
|
|
2982
|
-
enableOtpLogin?: boolean;
|
|
2983
|
-
/** Validate OTP and return user (same shape as password flow) or null. */
|
|
2984
|
-
authorizeOtp?: (input: AuthorizeOtpInput) => Promise<NextAuthUser | null>;
|
|
2985
3013
|
/**
|
|
2986
|
-
*
|
|
2987
|
-
* - `true` — always allow (dedicated storefront auth)
|
|
2988
|
-
* - `false` — always block
|
|
2989
|
-
* - omitted — auto: allow unless `callbackUrl` targets `/admin` (storefront `/signin` works unchanged)
|
|
3014
|
+
* Second LLM call: one draft at a time — category, URL slug, SEO fields, tags (JSON).
|
|
2990
3015
|
*/
|
|
2991
|
-
|
|
2992
|
-
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
|
|
3002
|
-
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
|
|
3024
|
-
|
|
3025
|
-
|
|
3026
|
-
|
|
3027
|
-
|
|
3028
|
-
|
|
3029
|
-
|
|
3030
|
-
|
|
3031
|
-
|
|
3032
|
-
|
|
3033
|
-
|
|
3034
|
-
|
|
3035
|
-
|
|
3036
|
-
|
|
3037
|
-
|
|
3038
|
-
|
|
3039
|
-
primaryColor: string;
|
|
3040
|
-
secondaryColor: string;
|
|
3041
|
-
navbarConfig: NavbarConfig;
|
|
3042
|
-
footerOverrides: Partial<FooterConfig>;
|
|
3016
|
+
private enrichBlogDraftWithLlmMetadata;
|
|
3017
|
+
/**
|
|
3018
|
+
* Third LLM call: one draft at a time — short social copy (JSON `{ socialMediaContent }`).
|
|
3019
|
+
*/
|
|
3020
|
+
private enrichBlogDraftWithLlmSocial;
|
|
3021
|
+
/**
|
|
3022
|
+
* Fetches the latest item for each RSS URL, then calls {@link LlmServiceInterface.chatAgent}.
|
|
3023
|
+
* `userPrompt` is only per-feed source material; rules live in the system prompt.
|
|
3024
|
+
* Expects HTML article fragment(s), optionally separated by {@link BLOG_GENERATOR_MARKDOWN_ARTICLE_SEPARATOR}.
|
|
3025
|
+
*/
|
|
3026
|
+
generateBlogMarkdownFromRss(params: {
|
|
3027
|
+
llm: LlmServiceInterface;
|
|
3028
|
+
/** Single feed (legacy). */
|
|
3029
|
+
rssUrl?: string;
|
|
3030
|
+
/** One or more feeds; latest item per URL is sent together. Prefer this when multiple URLs. */
|
|
3031
|
+
rssUrls?: readonly string[];
|
|
3032
|
+
systemInstruction?: string;
|
|
3033
|
+
validationRules?: string;
|
|
3034
|
+
/** Reserved for future structured output; writer does not inject categories into the user prompt. */
|
|
3035
|
+
categoryNamesHint?: readonly string[];
|
|
3036
|
+
/** Names of non-deleted tags in CMS (hint for reuse). */
|
|
3037
|
+
tagNamesHint?: readonly string[];
|
|
3038
|
+
/** From optional `llm_agents` row (slug `blog-generator`): model / sampling for the writer step. */
|
|
3039
|
+
llmAgentChatOptions?: Pick<LlmAgentOptions, 'model' | 'temperature' | 'max_tokens'>;
|
|
3040
|
+
/** Optional overrides for the metadata step; defaults live in `blog-generator-metadata-defaults.ts`. */
|
|
3041
|
+
metadataSystemInstruction?: string;
|
|
3042
|
+
metadataValidationRules?: string;
|
|
3043
|
+
/** From optional `llm_agents` row (slug `blog-generator-metadata`): model / sampling for metadata only. */
|
|
3044
|
+
metadataLlmAgentChatOptions?: Pick<LlmAgentOptions, 'model' | 'temperature' | 'max_tokens'>;
|
|
3045
|
+
/** Optional overrides for the social-summary step; defaults in `blog-generator-social-defaults.ts`. */
|
|
3046
|
+
socialSystemInstruction?: string;
|
|
3047
|
+
socialValidationRules?: string;
|
|
3048
|
+
/** From optional `llm_agents` row (slug `blog-generator-social`): model / sampling for social copy only. */
|
|
3049
|
+
socialLlmAgentChatOptions?: Pick<LlmAgentOptions, 'model' | 'temperature' | 'max_tokens'>;
|
|
3050
|
+
}): Promise<{
|
|
3051
|
+
agentName: string;
|
|
3052
|
+
feedArticles: Array<{
|
|
3053
|
+
rssUrl: string;
|
|
3054
|
+
article: LatestArticleFromFeed;
|
|
3055
|
+
}>;
|
|
3056
|
+
/** First feed's article (backward compatibility). */
|
|
3057
|
+
article: LatestArticleFromFeed;
|
|
3058
|
+
/** Raw model reply (HTML body per defaults; legacy markdown or JSON still parsed when present). */
|
|
3059
|
+
blogMarkdown: string;
|
|
3060
|
+
blogDrafts: BlogGeneratorBlogDraft[];
|
|
3061
|
+
/** Same as first draft; backward compatibility. */
|
|
3062
|
+
blogDraft: BlogGeneratorBlogDraft;
|
|
3063
|
+
}>;
|
|
3043
3064
|
}
|
|
3044
|
-
declare function loadPublicThemeSettings(config: {
|
|
3045
|
-
dataSource: DataSource;
|
|
3046
|
-
entityMap: EntityMap$2;
|
|
3047
|
-
encryptionKey?: string;
|
|
3048
|
-
defaultActiveThemeId?: string;
|
|
3049
|
-
defaultPrimaryColor?: string;
|
|
3050
|
-
defaultSecondaryColor?: string;
|
|
3051
|
-
}): Promise<PublicThemeSettingsPayload>;
|
|
3052
|
-
|
|
3053
|
-
/** Normalize a logical media folder path: no leading/trailing slashes, no ".." segments, max length. */
|
|
3054
|
-
declare function sanitizeMediaFolderPath(input: unknown): string;
|
|
3055
|
-
/** Single path segment for storage (folder name or legacy path segment). */
|
|
3056
|
-
declare function sanitizeStorageSegment(name: string): string;
|
|
3057
|
-
|
|
3058
|
-
type EntityMap = Record<string, EntityTarget<ObjectLiteral>>;
|
|
3059
|
-
/** Build `a/b/c` path under `uploads/` from the chain of folder rows up to root. */
|
|
3060
|
-
declare function relativePathFromMediaParentId(dataSource: DataSource, entityMap: EntityMap, parentId: number | null): Promise<string>;
|
|
3061
3065
|
|
|
3062
|
-
|
|
3063
|
-
declare
|
|
3066
|
+
/** Stable display name; not persisted as DB agent row in v1. */
|
|
3067
|
+
declare const BLOG_GENERATOR_AGENT_NAME = "Blog Generator Agent";
|
|
3068
|
+
/**
|
|
3069
|
+
* Optional `llm_agents` row: when present and enabled, model / temperature / max_tokens
|
|
3070
|
+
* are applied to {@link LlmServiceInterface.chatAgent} (system + user content still come from blog generator defaults / UI).
|
|
3071
|
+
*/
|
|
3072
|
+
declare const BLOG_GENERATOR_LLM_AGENT_SLUG = "blog-generator";
|
|
3073
|
+
/** Line that separates multiple articles in the model reply (HTML or legacy markdown; must match parser and prompts). */
|
|
3074
|
+
declare const BLOG_GENERATOR_MARKDOWN_ARTICLE_SEPARATOR = "---BLOG_GENERATOR_NEXT---";
|
|
3075
|
+
declare const BLOG_GENERATOR_DEFAULT_SYSTEM_INSTRUCTION = "You are a professional financial and business content writer.\n\nYour task is to generate completely original, high-quality blog article(s) from the latest RSS-derived source material in the user message (one block per feed). The user message is factual input only.\n\nIMPORTANT RULES:\n\n1. NEVER copy the RSS article directly.\n2. Rewrite the information into a fresh, human-like article.\n3. Expand the topic with professional insights and explanations.\n4. Maintain a natural editorial tone.\n5. Make the article SEO-friendly.\n6. Use engaging headings and subheadings.\n7. Avoid robotic AI phrasing.\n8. Do not mention that the content came from RSS or feeds.\n9. Preserve factual accuracy from the source material.\n10. The output should feel like a professionally written industry blog.\n\nMULTIPLE FEEDS:\n- If several feeds are provided, compare them: if they largely cover the same story or overlap heavily, produce ONE cohesive article.\n- If they cover clearly different topics or distinct stories, produce MULTIPLE articles (one per distinct story).\n- You may also produce one synthesis plus a short separate angle when that best serves the reader\u2014use your judgment.\n\nWRITING STYLE:\n- Professional\n- Clear\n- Informative\n- Business-focused\n- Human sounding\n- Modern editorial style\n\nARTICLE STRUCTURE (each article \u2014 express in HTML):\n1. Engaging introduction\n2. Industry context\n3. Main developments\n4. Key implications\n5. Expert/business analysis\n6. Conclusion\n\nHTML STRUCTURE (STRICT \u2014 each article must be valid, semantic HTML only):\n- Output HTML only. Do not use Markdown (no # headings, no **bold**, no `code fences`).\n- Wrap each complete article in a single root: <article class=\"blog-post\"> ... </article>\n- Inside <article>, use this outline:\n - <header><h1 class=\"blog-post-title\">\u2026main title\u2026</h1></header> (exactly one h1 per article)\n - <section class=\"blog-post-body\"> for all following content\n - Use <h2> and <h3> for section and subsection titles (never skip levels: h1 \u2192 h2 \u2192 h3).\n - Use <p> for paragraphs; keep paragraphs focused (avoid huge unbroken text).\n - Use <ul>/<ol> with <li> for lists where appropriate.\n - Use <strong> and <em> for emphasis sparingly; use <blockquote> only when quoting or callouts fit.\n- Do not include <html>, <head>, <body>, or document-level wrappers \u2014 only the fragment(s) described above.\n- Do not use <script>, <style>, <iframe>, or inline event handlers. Avoid inline style=\"\" except when essential for accessibility (prefer none).\n- Escape angle brackets in body text if you must mention markup; keep output safe for embedding in a CMS.\n\nCONTENT REQUIREMENTS:\n- Minimum 800 words per article unless source material is very small.\n- Add context around industry trends where appropriate.\n- Explain why the topic matters.\n- Include practical implications for businesses/professionals.\n\nIF RSS CONTENT IS LIMITED:\n- Expand intelligently using general industry knowledge.\n- Keep the article relevant to the original topic.\n- Do not invent fake facts or statistics.\n\nOUTPUT FORMAT (STRICT \u2014 HTML only):\n- Return ONLY the article HTML fragment(s). No JSON, no preamble or postscript (\"Here is your article\u2026\"), no markdown.\n- If you output more than one article, output multiple <article class=\"blog-post\">\u2026</article> blocks in sequence, and between articles put a single line containing exactly this (and nothing else on that line):\n---BLOG_GENERATOR_NEXT---\n- If you output a single article, use one <article> only and do not use that separator line.";
|
|
3076
|
+
/**
|
|
3077
|
+
* JSON so {@link parseLlmAgentValidationRules} can attach guardrails and allow long source payloads.
|
|
3078
|
+
* Edit in the admin UI if needed; defaults match product intent.
|
|
3079
|
+
*/
|
|
3080
|
+
declare const BLOG_GENERATOR_DEFAULT_VALIDATION_RULES: string;
|
|
3064
3081
|
|
|
3065
3082
|
/**
|
|
3066
|
-
*
|
|
3067
|
-
* `app.vendor_id` is set for the duration of that transaction.
|
|
3068
|
-
*
|
|
3069
|
-
* This activates the `vendor_isolation` RLS policy added by the
|
|
3070
|
-
* `VendorRls1775940000000` migration.
|
|
3083
|
+
* Second-step LLM: classifies one finished HTML blog body into CMS fields (category, SEO, tags).
|
|
3071
3084
|
*
|
|
3072
|
-
*
|
|
3073
|
-
*
|
|
3085
|
+
* Optional `llm_agents` row: slug {@link BLOG_METADATA_ENRICHER_LLM_AGENT_SLUG} — when present and enabled,
|
|
3086
|
+
* model / temperature / max_tokens apply to this call only (writer step uses `blog-generator`).
|
|
3074
3087
|
*
|
|
3075
|
-
*
|
|
3076
|
-
*
|
|
3077
|
-
* ds.getRepository(Order).find({ where: { deleted: false } })
|
|
3078
|
-
* );
|
|
3079
|
-
*/
|
|
3080
|
-
declare function withVendorRlsContext<T>(dataSource: DataSource, vendorId: number, fn: (dataSource: DataSource) => Promise<T>): Promise<T>;
|
|
3081
|
-
/**
|
|
3082
|
-
* Convenience wrapper: sets admin mode (vendor_id = '0') so all rows are
|
|
3083
|
-
* visible regardless of their vendorId. Use for platform-admin queries.
|
|
3088
|
+
* To change how metadata is produced, edit the constants in this file (system instruction + validation JSON).
|
|
3089
|
+
* No admin UI override is wired yet; add request body fields in `cms-api-handler` if you need runtime overrides later.
|
|
3084
3090
|
*/
|
|
3085
|
-
declare
|
|
3091
|
+
declare const BLOG_METADATA_ENRICHER_AGENT_NAME = "Blog Generator Metadata";
|
|
3092
|
+
/** `llm_agents.slug` for routing model/temperature for the metadata-only chat step. */
|
|
3093
|
+
declare const BLOG_METADATA_ENRICHER_LLM_AGENT_SLUG = "blog-generator-metadata";
|
|
3094
|
+
declare const BLOG_METADATA_ENRICHER_DEFAULT_SYSTEM_INSTRUCTION = "You are a careful CMS metadata assistant for a publishing system.\n\nYou receive ONE complete blog post as HTML (title is usually in <h1 class=\"blog-post-title\"> or the first <h1>). Your job is to propose structured fields so an editor can save the post: category, URL slug, SEO block, and topical tags.\n\nRULES:\n1. Read the whole article and infer the primary topic and audience.\n2. categoryName must be EXACTLY one string from AVAILABLE_BLOG_CATEGORIES in the user message, or \"\" if none fit.\n3. blogSlug: lowercase kebab-case, ASCII letters/digits/hyphens only, no leading/trailing hyphens, max ~80 chars. Derive from the main topic or title.\n4. seo.title: concise meta title (~50\u201360 characters when reasonable).\n5. seo.description: meta description (~150\u2013160 characters when reasonable), plain text.\n6. seo.keywords: comma-separated phrases, no stuffing.\n7. seo.ogTitle / seo.ogDescription: may mirror title/description or be slightly adapted for social.\n8. tags: 4\u201310 short labels (1\u20133 words each). Prefer exact matches from EXISTING_TAG_NAMES when they truly apply; otherwise invent precise new labels (they may be created in the CMS later).\n9. Do not invent statistics, quotes, or URLs not implied by the article.\n10. Output JSON only \u2014 no markdown outside the JSON, no commentary.\n\nOUTPUT FORMAT (STRICT):\nReturn a single JSON object only. Do not wrap it in a markdown code fence.\n\n{\n \"categoryName\": \"string \u2014 exact match from list or empty string\",\n \"blogSlug\": \"string \u2014 url-safe kebab-case\",\n \"seo\": {\n \"title\": \"string or empty\",\n \"description\": \"string or empty\",\n \"keywords\": \"string or empty\",\n \"ogTitle\": \"string or empty\",\n \"ogDescription\": \"string or empty\"\n },\n \"tags\": [\"tag-one\", \"tag-two\"]\n}";
|
|
3095
|
+
declare const BLOG_METADATA_ENRICHER_DEFAULT_VALIDATION_RULES: string;
|
|
3086
3096
|
|
|
3087
|
-
|
|
3088
|
-
|
|
3089
|
-
|
|
3090
|
-
|
|
3097
|
+
interface BlogGeneratorPluginConfig {
|
|
3098
|
+
/** Set to false to skip registering the plugin. */
|
|
3099
|
+
enabled?: boolean;
|
|
3100
|
+
}
|
|
3101
|
+
declare function blogGeneratorPlugin(config?: BlogGeneratorPluginConfig): CmsPlugin<BlogGeneratorService | undefined>;
|
|
3102
|
+
|
|
3103
|
+
interface SocialMediaApiConfig {
|
|
3104
|
+
dataSource: DataSource;
|
|
3105
|
+
entityMap: EntityMap$2;
|
|
3106
|
+
json: (body: unknown, init?: {
|
|
3107
|
+
status?: number;
|
|
3108
|
+
}) => Response;
|
|
3109
|
+
requireAuth: (req: Request) => Promise<Response | null>;
|
|
3110
|
+
requireEntityPermission: (req: Request, entity: string, action: EntityCrudAction) => Promise<Response | null>;
|
|
3111
|
+
encryptionKey?: string;
|
|
3112
|
+
/** Used to resolve relative cover image URLs (e.g. https://mysite.com). */
|
|
3113
|
+
publicSiteUrl?: string;
|
|
3114
|
+
/**
|
|
3115
|
+
* When true (default), `console.info` / `console.warn` lines are emitted for LinkedIn blog publish
|
|
3116
|
+
* (text vs image path, sizes, errors). Set false or `CMS_LINKEDIN_PUBLISH_LOG=0` to silence.
|
|
3117
|
+
*/
|
|
3118
|
+
linkedInPublishLogging?: boolean;
|
|
3119
|
+
}
|
|
3120
|
+
declare function createSocialMediaHandlers(config: SocialMediaApiConfig): {
|
|
3121
|
+
getLinkedInStatus(req: Request): Promise<Response>;
|
|
3122
|
+
fetchLinkedInOrganizations(req: Request): Promise<Response>;
|
|
3123
|
+
syncLinkedInProfile(req: Request): Promise<Response>;
|
|
3124
|
+
publishBlogToLinkedIn(req: Request, blogId: number): Promise<Response>;
|
|
3125
|
+
getFacebookStatus(req: Request): Promise<Response>;
|
|
3126
|
+
publishBlogToFacebook(req: Request, blogId: number): Promise<Response>;
|
|
3127
|
+
/**
|
|
3128
|
+
* POST JSON `{ appId, appSecret, userAccessToken }`. Calls Graph `GET /me/accounts` with the user token.
|
|
3129
|
+
* App ID and secret are validated but not used yet (reserved for future token flows).
|
|
3130
|
+
* Persist credentials via Plugins → Save: `meta_app_id` (public), `meta_app_secret` and `meta_user_access_token` (encrypted).
|
|
3131
|
+
*/
|
|
3132
|
+
fetchFacebookManagedPages(req: Request): Promise<Response>;
|
|
3091
3133
|
};
|
|
3092
|
-
|
|
3093
|
-
/** Restrict contact list to rows linked in `vendor_customers` with type customer. */
|
|
3094
|
-
declare function applyVendorCustomersContactFilter(qb: SelectQueryBuilder<typeorm.ObjectLiteral>, contactAlias: string, scope: VendorScope, vendorIdFilter: number | null): void;
|
|
3095
|
-
declare function contactIsVendorCustomer(dataSource: DataSource, entityMap: EntityMap$2, vendorId: number, contactId: number): Promise<boolean>;
|
|
3096
|
-
/** Returns an error message when the contact is not a vendor-linked customer; otherwise null. */
|
|
3097
|
-
declare function assertContactAllowedForVendorOrder(dataSource: DataSource, entityMap: EntityMap$2, vendorId: number, contactId: number): Promise<string | null>;
|
|
3098
|
-
declare function resolveVendorIdForContactCheck(scope: VendorScope, bodyOrRow: Record<string, unknown>): number | null;
|
|
3134
|
+
|
|
3099
3135
|
/**
|
|
3100
|
-
*
|
|
3101
|
-
*
|
|
3136
|
+
* Meta (Facebook) Graph API helpers (server-side). Uses fetch — no SDK.
|
|
3137
|
+
* @see https://developers.facebook.com/docs/graph-api/reference/user/accounts
|
|
3102
3138
|
*/
|
|
3103
|
-
|
|
3104
|
-
|
|
3105
|
-
|
|
3106
|
-
|
|
3107
|
-
|
|
3108
|
-
|
|
3109
|
-
|
|
3110
|
-
toDaysBefore: number | null;
|
|
3111
|
-
percentage: number;
|
|
3139
|
+
type FacebookPageAccount = {
|
|
3140
|
+
access_token?: string;
|
|
3141
|
+
category?: string;
|
|
3142
|
+
name?: string;
|
|
3143
|
+
id?: string;
|
|
3144
|
+
/** Graph may return additional fields */
|
|
3145
|
+
[key: string]: unknown;
|
|
3112
3146
|
};
|
|
3113
|
-
type
|
|
3114
|
-
|
|
3115
|
-
|
|
3116
|
-
|
|
3117
|
-
|
|
3118
|
-
|
|
3119
|
-
|
|
3147
|
+
type FacebookMeAccountsResponse = {
|
|
3148
|
+
data?: FacebookPageAccount[];
|
|
3149
|
+
paging?: Record<string, unknown>;
|
|
3150
|
+
error?: {
|
|
3151
|
+
message?: string;
|
|
3152
|
+
type?: string;
|
|
3153
|
+
code?: number;
|
|
3154
|
+
fbtrace_id?: string;
|
|
3155
|
+
};
|
|
3120
3156
|
};
|
|
3121
|
-
|
|
3122
|
-
|
|
3123
|
-
|
|
3124
|
-
|
|
3125
|
-
|
|
3126
|
-
|
|
3127
|
-
|
|
3128
|
-
|
|
3129
|
-
|
|
3130
|
-
|
|
3131
|
-
|
|
3157
|
+
/**
|
|
3158
|
+
* Lists Facebook Pages the user manages (page access tokens + metadata).
|
|
3159
|
+
* Requires a User access token with `pages_show_list` or equivalent page permissions.
|
|
3160
|
+
*/
|
|
3161
|
+
declare function metaFetchUserManagedPages(userAccessToken: string): Promise<FacebookMeAccountsResponse>;
|
|
3162
|
+
type MetaGraphMutationResponse = {
|
|
3163
|
+
id?: string;
|
|
3164
|
+
post_id?: string;
|
|
3165
|
+
error?: {
|
|
3166
|
+
message?: string;
|
|
3167
|
+
type?: string;
|
|
3168
|
+
code?: number;
|
|
3169
|
+
fbtrace_id?: string;
|
|
3170
|
+
};
|
|
3132
3171
|
};
|
|
3133
|
-
|
|
3134
|
-
declare function
|
|
3135
|
-
|
|
3136
|
-
|
|
3137
|
-
|
|
3138
|
-
|
|
3139
|
-
|
|
3140
|
-
|
|
3141
|
-
|
|
3142
|
-
|
|
3172
|
+
/** Resolves the long-lived page access token for a Page ID from `/me/accounts` data. */
|
|
3173
|
+
declare function metaResolvePageAccessToken(accounts: FacebookMeAccountsResponse, pageId: string): string | null;
|
|
3174
|
+
/**
|
|
3175
|
+
* Upload a photo to a Page timeline (multipart).
|
|
3176
|
+
* @see https://developers.facebook.com/docs/graph-api/reference/page/photos#Creating
|
|
3177
|
+
*/
|
|
3178
|
+
declare function metaPostPagePhoto(opts: {
|
|
3179
|
+
pageId: string;
|
|
3180
|
+
pageAccessToken: string;
|
|
3181
|
+
imageBuffer: Buffer;
|
|
3182
|
+
contentType: string;
|
|
3183
|
+
caption: string;
|
|
3184
|
+
}): Promise<MetaGraphMutationResponse>;
|
|
3185
|
+
/**
|
|
3186
|
+
* Publish a text-only post to the Page feed (when no JPEG/PNG image is available).
|
|
3187
|
+
* @see https://developers.facebook.com/docs/graph-api/reference/page/feed#Creating
|
|
3188
|
+
*/
|
|
3189
|
+
declare function metaPostPageFeed(opts: {
|
|
3190
|
+
pageId: string;
|
|
3191
|
+
pageAccessToken: string;
|
|
3192
|
+
message: string;
|
|
3193
|
+
}): Promise<MetaGraphMutationResponse>;
|
|
3143
3194
|
|
|
3144
|
-
|
|
3145
|
-
|
|
3146
|
-
|
|
3147
|
-
|
|
3148
|
-
|
|
3149
|
-
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
|
|
3153
|
-
|
|
3154
|
-
|
|
3155
|
-
eventId: number | null;
|
|
3156
|
-
eventName: string | null;
|
|
3157
|
-
}>;
|
|
3158
|
-
/** @deprecated Use event-attached policy via calculateOrderRefundPreview. */
|
|
3159
|
-
declare function findActiveRefundPolicyForVendor(dataSource: DataSource, entityMap: EntityMap$2, vendorId: number | null | undefined): Promise<PolicyRow | null>;
|
|
3195
|
+
interface SocialMediaPluginConfig {
|
|
3196
|
+
/** Set to false to skip registering the plugin instance (API routes still work if wired in the app handler). */
|
|
3197
|
+
enabled?: boolean;
|
|
3198
|
+
}
|
|
3199
|
+
/**
|
|
3200
|
+
* Optional CMS plugin instance for `getPlugin('social_media')`.
|
|
3201
|
+
* LinkedIn publishing is implemented in {@link createSocialMediaHandlers} and mounted from the CMS API handler.
|
|
3202
|
+
*/
|
|
3203
|
+
declare function socialMediaPlugin(config?: SocialMediaPluginConfig): CmsPlugin<{
|
|
3204
|
+
name: string;
|
|
3205
|
+
} | undefined>;
|
|
3160
3206
|
|
|
3161
3207
|
declare class OtpChallenge {
|
|
3162
3208
|
id: number;
|
|
@@ -3507,6 +3553,8 @@ declare enum ComboStatus {
|
|
|
3507
3553
|
}
|
|
3508
3554
|
declare class Combo {
|
|
3509
3555
|
id: number;
|
|
3556
|
+
vendorId: number;
|
|
3557
|
+
vendor: Vendor;
|
|
3510
3558
|
name: string;
|
|
3511
3559
|
desc?: string;
|
|
3512
3560
|
eventId: number;
|
|
@@ -3563,6 +3611,32 @@ declare class Attendee {
|
|
|
3563
3611
|
contact: Contact | null;
|
|
3564
3612
|
}
|
|
3565
3613
|
|
|
3614
|
+
declare enum NotificationChannel {
|
|
3615
|
+
WHATSAPP = "whatsapp",
|
|
3616
|
+
EMAIL = "email"
|
|
3617
|
+
}
|
|
3618
|
+
declare class OrderNotificationBinding {
|
|
3619
|
+
id: number;
|
|
3620
|
+
triggerKey: string;
|
|
3621
|
+
channel: NotificationChannel;
|
|
3622
|
+
messageTemplateId: number | null;
|
|
3623
|
+
enabled: boolean;
|
|
3624
|
+
createdAt: Date;
|
|
3625
|
+
updatedAt: Date;
|
|
3626
|
+
}
|
|
3627
|
+
|
|
3628
|
+
declare class OrderNotificationTrigger {
|
|
3629
|
+
id: number;
|
|
3630
|
+
triggerKey: string;
|
|
3631
|
+
label: string;
|
|
3632
|
+
description: string | null;
|
|
3633
|
+
category: string;
|
|
3634
|
+
enabled: boolean;
|
|
3635
|
+
sortOrder: number;
|
|
3636
|
+
createdAt: Date;
|
|
3637
|
+
updatedAt: Date;
|
|
3638
|
+
}
|
|
3639
|
+
|
|
3566
3640
|
/** Map API resource segment (e.g. "blogs", "form_submissions") to entity. Used by CRUD handler. */
|
|
3567
3641
|
declare const CMS_ENTITY_MAP: Record<string, EntityTarget<typeorm.ObjectLiteral>>;
|
|
3568
3642
|
|
|
@@ -3570,7 +3644,7 @@ declare const CMS_ENTITY_MAP: Record<string, EntityTarget<typeorm.ObjectLiteral>
|
|
|
3570
3644
|
type RbacDebugDataSource = {
|
|
3571
3645
|
query: (sql: string, parameters?: unknown[]) => Promise<unknown>;
|
|
3572
3646
|
};
|
|
3573
|
-
/** Set `CMS_RBAC_DEBUG=true` in `.env` to log permission decisions (server console). */
|
|
3647
|
+
/** Set `CMS_RBAC_DEBUG=true` in `.env` to log permission decisions (server console). Off by default. */
|
|
3574
3648
|
declare function isRbacDebugEnabled(): boolean;
|
|
3575
3649
|
declare function logRbac(message: string, data?: Record<string, unknown>): void;
|
|
3576
3650
|
declare function summarizeEntityPerms(entityPerms: Record<string, EntityPermissionFlags> | undefined): Record<string, {
|
|
@@ -3650,9 +3724,9 @@ declare function createCmsMiddleware(config?: CmsMiddlewareConfig): (request: Cm
|
|
|
3650
3724
|
body: unknown;
|
|
3651
3725
|
}>;
|
|
3652
3726
|
|
|
3653
|
-
/** Set `CMS_AUTH_DEBUG=
|
|
3727
|
+
/** Set `CMS_AUTH_DEBUG=true` to log server auth decisions. Off by default (including in development). */
|
|
3654
3728
|
declare function isAuthDebugEnabled(): boolean;
|
|
3655
|
-
/** Browser console logs; set `NEXT_PUBLIC_CMS_AUTH_DEBUG=
|
|
3729
|
+
/** Browser console logs; set `NEXT_PUBLIC_CMS_AUTH_DEBUG=true` to enable. */
|
|
3656
3730
|
declare function isAuthDebugClientEnabled(): boolean;
|
|
3657
3731
|
declare function logAuth(message: string, data?: Record<string, unknown>): void;
|
|
3658
3732
|
declare function logAuthClient(message: string, data?: Record<string, unknown>): void;
|
|
@@ -3731,4 +3805,36 @@ interface AdminNavItem {
|
|
|
3731
3805
|
}
|
|
3732
3806
|
declare const DEFAULT_ADMIN_NAV: AdminNavItem[];
|
|
3733
3807
|
|
|
3734
|
-
|
|
3808
|
+
interface EnsureMessagingPluginsOptions {
|
|
3809
|
+
dataSource: DataSource;
|
|
3810
|
+
entityMap: EntityMap$2;
|
|
3811
|
+
config?: Record<string, string>;
|
|
3812
|
+
/** Decrypts `configs.encrypted` rows (defaults to SETTINGS_ENCRYPTION_KEY or NEXTAUTH_SECRET). */
|
|
3813
|
+
encryptionKey?: string;
|
|
3814
|
+
logger?: Logger;
|
|
3815
|
+
}
|
|
3816
|
+
/** Minimal CMS handle (matches `CmsGetter` in cms-api-handler). */
|
|
3817
|
+
interface MessagingCmsLike {
|
|
3818
|
+
getPlugin(name: string): unknown;
|
|
3819
|
+
dataSource?: unknown;
|
|
3820
|
+
}
|
|
3821
|
+
/** Same key used by Plugins → settings PUT for encrypted secrets (e.g. WhatsApp access token). */
|
|
3822
|
+
declare function resolveSettingsEncryptionKey(config?: Record<string, string>): string | undefined;
|
|
3823
|
+
declare function loadSettingsGroupFromDb(dataSource: DataSource, entityMap: EntityMap$2, group: string, encryptionKey?: string): Promise<Record<string, string>>;
|
|
3824
|
+
declare function createMessageTemplateRowLoader(dataSource: DataSource, entityMap: EntityMap$2): MessageTemplateRowLoader;
|
|
3825
|
+
/** Register email + WhatsApp queue processors when a queue plugin is present. */
|
|
3826
|
+
declare function registerMessagingQueueProcessors(cms: CmsApp): void;
|
|
3827
|
+
/**
|
|
3828
|
+
* Ensures queue, email, and WhatsApp plugins exist on the CMS app (lazy overlay).
|
|
3829
|
+
* Consumer apps that omit `whatsappPlugin()` / `queuePlugin()` still get order notifications when env/DB is configured.
|
|
3830
|
+
*/
|
|
3831
|
+
declare function ensureMessagingPluginsOnCms(base: MessagingCmsLike, options: EnsureMessagingPluginsOptions): Promise<CmsApp>;
|
|
3832
|
+
/** Cached wrapper so messaging plugins are initialized once per process. */
|
|
3833
|
+
declare function wrapGetCmsWithMessaging(getCms: () => Promise<MessagingCmsLike>, options: EnsureMessagingPluginsOptions): () => Promise<CmsApp>;
|
|
3834
|
+
/** Standard messaging plugins for `createCmsApp({ plugins: [...] })`. */
|
|
3835
|
+
declare function messagingPlugins(options: EnsureMessagingPluginsOptions): CmsPlugin[];
|
|
3836
|
+
type CreateCmsAppWithMessagingOptions = CreateCmsAppOptions & EnsureMessagingPluginsOptions;
|
|
3837
|
+
/** `createCmsApp` + messaging plugins + queue processor registration. */
|
|
3838
|
+
declare function createCmsAppWithMessaging(options: CreateCmsAppWithMessagingOptions): Promise<CmsApp>;
|
|
3839
|
+
|
|
3840
|
+
export { ADMIN_GROUP_NAME, Address, type AdminNavItem, type AnalyticsHandlerConfig, type AnalyticsPluginConfig, Attendee, Attribute, type AuthHandlersConfig, type AuthHelpers, type AuthorizeOtpInput, BLOG_GENERATOR_AGENT_NAME, BLOG_GENERATOR_DEFAULT_SYSTEM_INSTRUCTION, BLOG_GENERATOR_DEFAULT_VALIDATION_RULES, BLOG_GENERATOR_LLM_AGENT_SLUG, BLOG_GENERATOR_MARKDOWN_ARTICLE_SEPARATOR, BLOG_METADATA_ENRICHER_AGENT_NAME, BLOG_METADATA_ENRICHER_DEFAULT_SYSTEM_INSTRUCTION, BLOG_METADATA_ENRICHER_DEFAULT_VALIDATION_RULES, BLOG_METADATA_ENRICHER_LLM_AGENT_SLUG, Blog, type BlogBySlugConfig, type BlogGeneratorBlogDraft, type BlogGeneratorDraftParseMode, type BlogGeneratorPluginConfig, type BlogGeneratorSeoDraft, BlogGeneratorService, Brand, CMS_ENTITY_MAP, type CachePluginConfig, type CacheService, type CaptchaProviderId, type CaptchaPublicConfig, CaptchaService, type CaptchaVerifyResult, Cart, CartItem, Category, type ChangePasswordConfig, ChatConversation, ChatMessage, type ChatPublicConfig, type CmsApiHandlerConfig, type CmsApp, type CmsGetter, type CmsMiddlewareConfig, type CmsMiddlewareRequest, type CmsPlugin, Collection, Combo, ComboItem, Comment, type CompanyDetails, Config, Contact, type CreateCmsAppOptions, type CreateCmsAppWithMessagingOptions, type CrudHandlerOptions, Currency, CurrencyExchange, Customer, Customer_Contacts, DEFAULT_ADMIN_NAV, DEFAULT_ORDER_NOTIFICATION_TRIGGER_SEEDS, type DashboardStatsConfig, type DataSourceManager, Discount, DiscountRules, type ERPPluginConfig, type ERPPluginInstance, ERPSubmissionService, EVENT_ORDER_MESSAGE_TEMPLATE_DEFAULTS, EVENT_ORDER_TEMPLATE_KEY, EVENT_ORDER_TEMPLATE_VARIABLES, type EcommerceAnalyticsConfig, type EmailData, type EmailJobPayload, type EmailPluginConfig, EmailService, type EmailServiceInterface, type EmailTemplateName, type EmailTemplateResult, type EmitOrderNotificationTriggerDeps, type EnsureCustomerUserInput, type EnsureMessagingPluginsOptions, type EnsureVendorCustomerDetails, type EntityCrudAction, type EntityMap$2 as EntityMap, type EntityPermissionFlags, type ErpContactSyncInput, type ErpCreateContactPayload, type ErpJobPayload, type ErpPaidOrderDataSource, type ErpPaidOrderEntityMap, Event, type EventOrderMessageTemplateHandlersConfig, type EventOrderNotificationChannel, type EventOrderNotificationTemplates, type EventOrderTemplateOverride, EventProduct, type ExtraPublicWriteRule, type FacebookMeAccountsResponse, type FacebookPageAccount, type ForgotPasswordConfig, Form, type FormBySlugConfig, FormField, FormSubmission, type GetPublicSettingsGroupConfig, type GetPublicSettingsGroupDataSource, type GetSession, type InviteAcceptConfig, JOB_RUNNER_QUEUE, type CmsAppLike as JobRunnerCmsAppLike, type JobRunnerDeps, type JobRunnerPayload, JobSchedule, type JobScheduleApiConfig, JobScheduleRun, KNOWN_NOTIFICATION_TRIGGERS, KnowledgeBaseChunk, KnowledgeBaseDocument, type LatestArticleFromFeed, LlmAgent, type LlmAgentKnowledgeApiConfig, type LlmAgentOptions, type LlmAgentValidationRulesJson, type LlmChatOptions, type LlmEmbeddingProvider, type LlmMessage, type LlmPluginConfig, LlmService, type LlmServiceEmbedOptions, type LlmServiceInterface, type LocalStoragePluginConfig, type Logger, Media, MessageTemplate, type MetaGraphMutationResponse, type NextAuthOptionsConfig, type NextAuthUser, OPEN_ENDPOINTS, ORDER_NOTIFICATION_TRIGGERS, Order, OrderAddresses, OrderDiscounts, OrderItem, OrderNotificationBinding, OrderNotificationTrigger, type OrderNotificationTriggerKey, type OrderPlacedEmailPayload, type OrderPlacedLineItem, type OrderTriggerPayload, OtpChallenge, type OtpChannel, type OtpPurpose, PERMISSION_REQUIRED_ENDPOINTS, Page, type ParsedLlmAgentValidation, PasswordResetToken, Payment, type PaymentIntent, type PaymentPluginConfig, type PaymentServiceInterface, Permission, type PgBossPluginConfig, PgBossService, type PipelineNames, type PluginContext, Product, ProductAttribute, ProductCategory, ProductConfig, ProductVariant, type PublicThemeSettingsPayload, type QueuePluginConfig, type QueueService, RBAC_ADMIN_ONLY_ENTITIES, type RefundCalculationResult, RefundPolicy, type RefundPolicyLike, type RefundPolicyTier, RefundRequest, type RenderEmailOptions, type RenderedEmail, RssArticle, RssFeed, type S3StoragePluginConfig, SUPER_ADMIN_GROUP_ID, type SendVendorOnboardEmailInput, Seo, type SeoLike, type SeoMetadataOverrides, type SessionUser, type SetPasswordConfig, type SettingsApiConfig, type SmsJobPayload, type SmsPluginConfig, type SmsProviderChoice, type SmsProviderId, type SmsServiceConfig, type SmsServiceInterface, type SocialLinkItem, type SocialMediaPluginConfig, type StorageService, type StorefrontApiConfig, type StorefrontOtpFlags, Tag, Tax, type TemplateContext, type UploadHandlerConfig, User, type UserAuthApiConfig, type UserAvatarConfig, UserGroup, type UserProfileConfig, type UsersApiConfig, VENDOR_ADMIN_GROUP_ID, VENDOR_OWNER_GROUP_NAME, VENDOR_SCOPED_STORE_ENTITIES, VENDOR_STORE_RBAC_ENTITIES, Vendor, VendorCustomer, type VendorDashboardConfig, type VendorOnboardHandlersConfig, type VendorOwnerActivation, VendorRole, VendorRolePermission, VendorUser, type WhatsAppJobPayload, type WhatsAppPluginConfig, type WhatsAppServiceConfig, type WhatsAppServiceInterface, Wishlist, WishlistItem, ZIP_MIME_TYPES, allowRateLimit, analyticsPlugin, applyVendorCustomersContactFilter, assertCaptchaOk, assertContactAllowedForVendorOrder, blogGeneratorPlugin, buildBlogMetadataUserPrompt, buildCaptchaPublicConfig, buildCronFromSchedule, buildEventOrderTemplateVariables, buildRssUserPromptFromFeeds, cachePlugin, calculateOrderRefundPreview, calculateRefundFromPolicy, canManageRoles, canManageVendorRoles, canManageVendorTeam, canOnboardVendors, captchaPlugin, checkEventsEnabled, checkMultiVendorEnabled, cn, contactIsVendorCustomer, countRecentOtpSends, createAnalyticsHandlers, createAuthHelpers, createBlogBySlugHandler, createChangePasswordHandler, createCmsApiHandler, createCmsApp, createCmsAppWithMessaging, createCmsAuthBundle, createCmsMiddleware, createCrudByIdHandler, createCrudHandler, createDashboardStatsHandler, createDataSourceManager, createEcommerceAnalyticsHandler, createEventOrderMessageTemplateHandlers, createForgotPasswordHandler, createFormBySlugHandler, createInviteAcceptHandler, createJobScheduleHandlers, createLlmAgentKnowledgeHandlers, createMediaZipExtractHandler, createMessageTemplateRowLoader, createOtpChallenge, createSetPasswordHandler, createSettingsApiHandlers, createSocialMediaHandlers, createStorefrontApiHandler, createUploadHandler, createUserAuthApiRouter, createUserAvatarHandler, createUserProfileHandler, createUsersApiHandlers, createVendorDashboardHandler, createVendorOnboardHandlers, customerPhoneForUser, daysBeforeEventStart, defaultPublicApiMethods, describeEventTierPolicy, emailPlugin, emailTemplates, emitOrderNotificationTrigger, enrichUserWithVendorContext, ensureCustomerForUser, ensureMessagingPluginsOnCms, ensureScheduleQueueWorker, ensureVendorCustomerForOrderContact, erpPlugin, explainSessionEntityAccess, fetchSeoBySlug, findActiveRefundPolicyForVendor, fireOrderNotificationTrigger, formatDate, formatDateOnly, formatDateTime, formatTierRange, generateNumericOtp, generateSlug, getCompanyDetailsFromSettings, getNextAuthOptions, getPermissionableEntityKeys, getPublicSettingsGroup, getRequiredPermission, getRssArticleSummaryFromItem, getStorefrontNextAuthOptions, hasEntityPermission, hashOtpCode, hydrateVendorSessionUser, initWhatsappTriggerDispatcher, invalidateEventsCache, invalidateMultiVendorCache, isAuthDebugClientEnabled, isAuthDebugEnabled, isCustomerTypeContact, isOpenEndpoint, isPlatformAdministrator, isPublicMethod, isRbacDebugEnabled, isSuperAdmin, isSuperAdminGroupName, isVendorAdmin, isVendorGroupName, isVendorOwner, isVendorPortalUser, isVendorStaff, isZipMedia, joinRecipientsForSend, linkUnclaimedContactToUser, llmAgentToChatAgentOptions, llmPlugin, loadPublicThemeSettings, loadSettingsGroupFromDb, loadUserVendorContext, localStoragePlugin, logAuth, logAuthClient, logEntityAccessDecision, logRbac, mergeEmailLayoutCompanyDetails, mergeGuardrailsIntoSystemPrompt, mergeSeoBySlug, messagingPlugins, metaFetchUserManagedPages, metaPostPageFeed, metaPostPagePhoto, metaResolvePageAccessToken, nextAuthCookieDebugInfo, normalizePhoneE164, normalizeRefundTiers, notificationTriggerEmitter, overlayCmsPlugins, parseBlogGeneratorAgentContent, parseBlogGeneratorModelOutput, parseBlogMetadataEnrichmentJson, parseEmailRecipientsFromConfig, parseHfInferenceEmbeddingBody, parseLlmAgentValidationRules, paymentPlugin, permissionRowsToRecord, pgBossPlugin, pgBossScheduleNameForId, queueEmail, queueErp, queueErpCreateContactIfEnabled, queueErpPaidOrderForOrderId, queueJobScheduleNow, queueOrderPlacedEmails, queuePlugin, queueSms, queueVendorOnboardEmails, queueWhatsApp, rateLimitCheckoutPost, rateLimitKeyForApiRequest, rateLimitPublicApiIfNeeded, registerEmailQueueProcessor, registerErpQueueProcessor, registerJobRunnerWorker, registerMessagingQueueProcessors, registerSmsQueueProcessor, registerWhatsAppQueueProcessor, relativePathFromMediaParentId, renderEmail, renderLayout, resendOrderNotification, resolveBlogCategoryIdByName, resolveEventOrderTemplate, resolvePublicMetadata, resolveSettingsEncryptionKey, resolveVendorIdForContactCheck, resolveVendorScopeFromSessionUser, s3StoragePlugin, sanitizeMediaFolderPath, sanitizeStorageSegment, seedAdministratorPermissions, seedDefaultAdmin, sendOrderPlacedEmailsAfterConfirmation, sendVendorOnboardEmails, serializeEmailRecipients, sessionHasEntityAccess, shouldRateLimitPublicWrite, simpleDecrypt, simpleEncrypt, smsPlugin, socialMediaPlugin, summarizeEntityPerms, summarizeSessionUserForLog, syncJobScheduleToPgBoss, truncateText, validateRefundTiers, validateScheduleInput, validateSlug, validateUserMessageAgainstAgentRules, validateUserMessageAgainstStructuredRules, vendorPortalFlagsFromUser, verifyAndConsumeOtpChallenge, verifyOtpCodeHash, whatsappPlugin, withAdminRlsContext, withVendorRlsContext, wrapGetCmsWithMessaging };
|