@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.js
CHANGED
|
@@ -1,24 +1,22 @@
|
|
|
1
|
-
export {
|
|
2
|
-
|
|
3
|
-
export {
|
|
4
|
-
import './chunk-
|
|
5
|
-
export { queueWhatsApp, registerWhatsAppQueueProcessor } from './chunk-
|
|
6
|
-
|
|
7
|
-
export { Address, Attendee, Attribute, 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, BlogGeneratorService, Brand, CMS_ENTITY_MAP, Cart, CartItem, Category, ChatConversation, ChatMessage, Collection, Combo, ComboItem, Comment, Config, Contact, Currency, CurrencyExchange, Customer, Customer_Contacts, Discount, DiscountRules, Event, EventProduct, Form, FormField, FormSubmission, JobSchedule, JobScheduleRun, KnowledgeBaseChunk, KnowledgeBaseDocument, LlmAgent, Media, MessageTemplate, Order, OrderAddresses, OrderDiscounts, OrderItem, OtpChallenge, Page, PasswordResetToken, Payment, Permission, Product, ProductAttribute, ProductCategory, ProductConfig, ProductVariant, RefundPolicy, RefundRequest, RssArticle, RssFeed, Seo, Tag, Tax, User, UserGroup, Vendor, VendorCustomer, VendorRole, VendorRolePermission, VendorUser, Wishlist, WishlistItem, ZIP_MIME_TYPES, applyVendorCustomersContactFilter, assertCaptchaOk, assertContactAllowedForVendorOrder, buildBlogMetadataUserPrompt, buildCronFromSchedule, buildRssUserPromptFromFeeds, calculateOrderRefundPreview, calculateRefundFromPolicy, contactIsVendorCustomer, countRecentOtpSends, createAnalyticsHandlers, createBlogBySlugHandler, createChangePasswordHandler, createCmsApiHandler, createCrudByIdHandler, createCrudHandler, createDashboardStatsHandler, createEcommerceAnalyticsHandler, createEventNotificationHandlers, createEventOrderMessageTemplateHandlers, createForgotPasswordHandler, createFormBySlugHandler, createInviteAcceptHandler, createJobScheduleHandlers, createLlmAgentKnowledgeHandlers, createMediaZipExtractHandler, createOtpChallenge, createSetPasswordHandler, createSettingsApiHandlers, createSocialMediaHandlers, createStorefrontApiHandler, createUploadHandler, createUserAuthApiRouter, createUserAvatarHandler, createUserProfileHandler, createUsersApiHandlers, createVendorDashboardHandler, createVendorOnboardHandlers, customerPhoneForUser, daysBeforeEventStart, describeEventTierPolicy, ensureCustomerForUser, ensureScheduleQueueWorker, ensureVendorCustomerForOrderContact, findActiveRefundPolicyForVendor, formatTierRange, generateNumericOtp, getPublicSettingsGroup, getRssArticleSummaryFromItem, hashOtpCode, hydrateVendorSessionUser, isCustomerTypeContact, isZipMedia, linkUnclaimedContactToUser, llmAgentToChatAgentOptions, loadUserVendorContext, mergeGuardrailsIntoSystemPrompt, metaFetchUserManagedPages, metaPostPageFeed, metaPostPagePhoto, metaResolvePageAccessToken, normalizePhoneE164, normalizeRefundTiers, parseBlogGeneratorAgentContent, parseBlogGeneratorModelOutput, parseBlogMetadataEnrichmentJson, parseLlmAgentValidationRules, pgBossScheduleNameForId, queueErpCreateContactIfEnabled, queueJobScheduleNow, queueSms, registerJobRunnerWorker, registerSmsQueueProcessor, relativePathFromMediaParentId, resolveBlogCategoryIdByName, resolveVendorIdForContactCheck, sanitizeMediaFolderPath, sanitizeStorageSegment, sendVendorOnboardEmails, simpleDecrypt, simpleEncrypt, syncJobScheduleToPgBoss, validateRefundTiers, validateScheduleInput, validateUserMessageAgainstAgentRules, validateUserMessageAgainstStructuredRules, verifyAndConsumeOtpChallenge, verifyOtpCodeHash } from './chunk-2XE4X74C.js';
|
|
8
|
-
import { PgBossService } from './chunk-GO7PPYNU.js';
|
|
9
|
-
export { JOB_RUNNER_QUEUE, PgBossService } from './chunk-GO7PPYNU.js';
|
|
10
|
-
export { buildEventOrderTemplateVariables } from './chunk-JBRR5UYL.js';
|
|
1
|
+
export { emitOrderNotificationTrigger, fireOrderNotificationTrigger } from './chunk-X47PBV4I.js';
|
|
2
|
+
import { checkMultiVendorEnabled, loadUserVendorContext, getPublicSettingsGroup, BlogGeneratorService } from './chunk-PYUXVU75.js';
|
|
3
|
+
export { Address, Attendee, Attribute, 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, BlogGeneratorService, Brand, CMS_ENTITY_MAP, Cart, CartItem, Category, ChatConversation, ChatMessage, Collection, Combo, ComboItem, Comment, Config, Contact, Currency, CurrencyExchange, Customer, Customer_Contacts, Discount, DiscountRules, Event, EventProduct, Form, FormField, FormSubmission, JobSchedule, JobScheduleRun, KnowledgeBaseChunk, KnowledgeBaseDocument, LlmAgent, Media, MessageTemplate, Order, OrderAddresses, OrderDiscounts, OrderItem, OrderNotificationBinding, OrderNotificationTrigger, OtpChallenge, Page, PasswordResetToken, Payment, Permission, Product, ProductAttribute, ProductCategory, ProductConfig, ProductVariant, RefundPolicy, RefundRequest, RssArticle, RssFeed, Seo, Tag, Tax, User, UserGroup, Vendor, VendorCustomer, VendorRole, VendorRolePermission, VendorUser, Wishlist, WishlistItem, ZIP_MIME_TYPES, applyVendorCustomersContactFilter, assertCaptchaOk, assertContactAllowedForVendorOrder, buildBlogMetadataUserPrompt, buildCronFromSchedule, buildRssUserPromptFromFeeds, calculateOrderRefundPreview, calculateRefundFromPolicy, checkEventsEnabled, checkMultiVendorEnabled, contactIsVendorCustomer, countRecentOtpSends, createAnalyticsHandlers, createBlogBySlugHandler, createChangePasswordHandler, createCmsApiHandler, createCmsApp, createCmsAppWithMessaging, createCrudByIdHandler, createCrudHandler, createDashboardStatsHandler, createEcommerceAnalyticsHandler, createEventOrderMessageTemplateHandlers, createForgotPasswordHandler, createFormBySlugHandler, createInviteAcceptHandler, createJobScheduleHandlers, createLlmAgentKnowledgeHandlers, createMediaZipExtractHandler, createMessageTemplateRowLoader, createOtpChallenge, createSetPasswordHandler, createSettingsApiHandlers, createSocialMediaHandlers, createStorefrontApiHandler, createUploadHandler, createUserAuthApiRouter, createUserAvatarHandler, createUserProfileHandler, createUsersApiHandlers, createVendorDashboardHandler, createVendorOnboardHandlers, customerPhoneForUser, daysBeforeEventStart, describeEventTierPolicy, ensureCustomerForUser, ensureMessagingPluginsOnCms, ensureScheduleQueueWorker, ensureVendorCustomerForOrderContact, findActiveRefundPolicyForVendor, formatTierRange, generateNumericOtp, getPublicSettingsGroup, getRssArticleSummaryFromItem, hashOtpCode, hydrateVendorSessionUser, invalidateEventsCache, invalidateMultiVendorCache, isCustomerTypeContact, isZipMedia, linkUnclaimedContactToUser, llmAgentToChatAgentOptions, loadSettingsGroupFromDb, loadUserVendorContext, mergeGuardrailsIntoSystemPrompt, messagingPlugins, metaFetchUserManagedPages, metaPostPageFeed, metaPostPagePhoto, metaResolvePageAccessToken, normalizePhoneE164, normalizeRefundTiers, overlayCmsPlugins, parseBlogGeneratorAgentContent, parseBlogGeneratorModelOutput, parseBlogMetadataEnrichmentJson, parseLlmAgentValidationRules, pgBossScheduleNameForId, queueErpCreateContactIfEnabled, queueJobScheduleNow, queuePlugin, queueSms, registerJobRunnerWorker, registerMessagingQueueProcessors, registerSmsQueueProcessor, relativePathFromMediaParentId, resolveBlogCategoryIdByName, resolveSettingsEncryptionKey, resolveVendorIdForContactCheck, sanitizeMediaFolderPath, sanitizeStorageSegment, sendVendorOnboardEmails, simpleDecrypt, simpleEncrypt, syncJobScheduleToPgBoss, validateRefundTiers, validateScheduleInput, validateUserMessageAgainstAgentRules, validateUserMessageAgainstStructuredRules, verifyAndConsumeOtpChallenge, verifyOtpCodeHash, whatsappPlugin, wrapGetCmsWithMessaging } from './chunk-PYUXVU75.js';
|
|
4
|
+
import { mergeEmailLayoutCompanyDetails, parseEmailRecipientsFromConfig } from './chunk-NNQBWDCI.js';
|
|
5
|
+
export { EmailService, buildEventOrderTemplateVariables, emailPlugin, emailTemplates, getCompanyDetailsFromSettings, initWhatsappTriggerDispatcher, joinRecipientsForSend, mergeEmailLayoutCompanyDetails, parseEmailRecipientsFromConfig, queueWhatsApp, registerWhatsAppQueueProcessor, renderEmail, renderLayout, resendOrderNotification, serializeEmailRecipients } from './chunk-NNQBWDCI.js';
|
|
6
|
+
export { KNOWN_NOTIFICATION_TRIGGERS, notificationTriggerEmitter } from './chunk-HCIRL37O.js';
|
|
11
7
|
import './chunk-JXF23MPG.js';
|
|
12
8
|
import './chunk-WEMDMVHQ.js';
|
|
13
|
-
import { mergeEmailLayoutCompanyDetails, parseEmailRecipientsFromConfig } from './chunk-XDSNZUW7.js';
|
|
14
|
-
export { getCompanyDetailsFromSettings, joinRecipientsForSend, mergeEmailLayoutCompanyDetails, parseEmailRecipientsFromConfig, serializeEmailRecipients } from './chunk-XDSNZUW7.js';
|
|
15
9
|
import { queueOrderPlacedEmails } from './chunk-5ELSW2UP.js';
|
|
16
10
|
export { queueEmail, queueOrderPlacedEmails, queueVendorOnboardEmails, registerEmailQueueProcessor } from './chunk-5ELSW2UP.js';
|
|
17
11
|
import './chunk-MQBT33IV.js';
|
|
18
|
-
|
|
19
|
-
export {
|
|
20
|
-
|
|
21
|
-
export {
|
|
12
|
+
import './chunk-CRFV5WJK.js';
|
|
13
|
+
export { EVENT_ORDER_MESSAGE_TEMPLATE_DEFAULTS, EVENT_ORDER_TEMPLATE_KEY, EVENT_ORDER_TEMPLATE_VARIABLES, resolveEventOrderTemplate } from './chunk-KFFB6EMZ.js';
|
|
14
|
+
import { PgBossService } from './chunk-GO7PPYNU.js';
|
|
15
|
+
export { JOB_RUNNER_QUEUE, PgBossService } from './chunk-GO7PPYNU.js';
|
|
16
|
+
export { createCmsMiddleware, defaultPublicApiMethods, getNextAuthOptions, getStorefrontNextAuthOptions, isAuthDebugClientEnabled, isAuthDebugEnabled, logAuth, logAuthClient, nextAuthCookieDebugInfo, seedAdministratorPermissions, summarizeSessionUserForLog } from './chunk-SBRBR3VO.js';
|
|
17
|
+
export { OPEN_ENDPOINTS, PERMISSION_REQUIRED_ENDPOINTS, RBAC_ADMIN_ONLY_ENTITIES, canManageRoles, createAuthHelpers, createCmsAuthBundle, getRequiredPermission, isOpenEndpoint, isPublicMethod, sessionHasEntityAccess } from './chunk-UXMDSNIG.js';
|
|
18
|
+
import { isSuperAdmin, isVendorGroupName } from './chunk-P7QCLE5W.js';
|
|
19
|
+
export { ADMIN_GROUP_NAME, SUPER_ADMIN_GROUP_ID, VENDOR_ADMIN_GROUP_ID, VENDOR_OWNER_GROUP_NAME, VENDOR_SCOPED_STORE_ENTITIES, VENDOR_STORE_RBAC_ENTITIES, canManageVendorRoles, canManageVendorTeam, canOnboardVendors, explainSessionEntityAccess, getPermissionableEntityKeys, hasEntityPermission, isPlatformAdministrator, isRbacDebugEnabled, isSuperAdmin, isSuperAdminGroupName, isVendorAdmin, isVendorGroupName, isVendorOwner, isVendorPortalUser, isVendorStaff, logEntityAccessDecision, logRbac, permissionRowsToRecord, resolveVendorScopeFromSessionUser, summarizeEntityPerms, vendorPortalFlagsFromUser } from './chunk-P7QCLE5W.js';
|
|
22
20
|
export { queueErpPaidOrderForOrderId } from './chunk-TDV6EJHV.js';
|
|
23
21
|
import { erpSafeWebhookUrl, logErp, warnErp, errorErp } from './chunk-SYBOCAWB.js';
|
|
24
22
|
export { queueErp, registerErpQueueProcessor } from './chunk-SYBOCAWB.js';
|
|
@@ -27,8 +25,6 @@ import { __name } from './chunk-SHUYVCID.js';
|
|
|
27
25
|
import { google } from 'googleapis';
|
|
28
26
|
import Redis from 'ioredis';
|
|
29
27
|
import { LRUCache } from 'lru-cache';
|
|
30
|
-
import { Worker, Queue } from 'bullmq';
|
|
31
|
-
import fastq from 'fastq';
|
|
32
28
|
import { clsx } from 'clsx';
|
|
33
29
|
import { twMerge } from 'tailwind-merge';
|
|
34
30
|
import { NextResponse } from 'next/server';
|
|
@@ -36,40 +32,6 @@ import 'reflect-metadata';
|
|
|
36
32
|
import { DataSource } from 'typeorm';
|
|
37
33
|
import bcrypt from 'bcryptjs';
|
|
38
34
|
|
|
39
|
-
// src/plugins/registry.ts
|
|
40
|
-
var noopLogger = {
|
|
41
|
-
info: /* @__PURE__ */ __name(() => {
|
|
42
|
-
}, "info"),
|
|
43
|
-
warn: /* @__PURE__ */ __name(() => {
|
|
44
|
-
}, "warn"),
|
|
45
|
-
error: /* @__PURE__ */ __name(() => {
|
|
46
|
-
}, "error")
|
|
47
|
-
};
|
|
48
|
-
async function createCmsApp(options) {
|
|
49
|
-
const { dataSource, config = {}, plugins = [], logger = noopLogger } = options;
|
|
50
|
-
const context = {
|
|
51
|
-
dataSource,
|
|
52
|
-
config,
|
|
53
|
-
logger
|
|
54
|
-
};
|
|
55
|
-
const registry = /* @__PURE__ */ new Map();
|
|
56
|
-
for (const plugin of plugins) {
|
|
57
|
-
try {
|
|
58
|
-
const instance = await plugin.init(context);
|
|
59
|
-
registry.set(plugin.name, instance !== void 0 ? instance : plugin);
|
|
60
|
-
} catch (err) {
|
|
61
|
-
logger.warn(`Plugin "${plugin.name}" failed to init: ${err instanceof Error ? err.message : err}`);
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
return {
|
|
65
|
-
dataSource,
|
|
66
|
-
getPlugin(name) {
|
|
67
|
-
return registry.get(name);
|
|
68
|
-
}
|
|
69
|
-
};
|
|
70
|
-
}
|
|
71
|
-
__name(createCmsApp, "createCmsApp");
|
|
72
|
-
|
|
73
35
|
// src/plugins/erp/erp-submission.ts
|
|
74
36
|
var ERPSubmissionService = class {
|
|
75
37
|
static {
|
|
@@ -1039,268 +1001,6 @@ function smsPlugin(config = {}) {
|
|
|
1039
1001
|
}
|
|
1040
1002
|
__name(smsPlugin, "smsPlugin");
|
|
1041
1003
|
|
|
1042
|
-
// src/plugins/whatsapp/whatsapp-service.ts
|
|
1043
|
-
function norm2(v) {
|
|
1044
|
-
const t = v?.trim();
|
|
1045
|
-
return t || void 0;
|
|
1046
|
-
}
|
|
1047
|
-
__name(norm2, "norm");
|
|
1048
|
-
function pick2(plugin, db, env, ...keys) {
|
|
1049
|
-
for (const key of keys) {
|
|
1050
|
-
const pk = key;
|
|
1051
|
-
if (pk in plugin && plugin[pk] !== void 0 && String(plugin[pk]).trim() !== "") {
|
|
1052
|
-
const v = norm2(String(plugin[pk]));
|
|
1053
|
-
if (v) return v;
|
|
1054
|
-
}
|
|
1055
|
-
if (norm2(db[key])) return norm2(db[key]);
|
|
1056
|
-
if (norm2(env[key])) return norm2(env[key]);
|
|
1057
|
-
}
|
|
1058
|
-
return void 0;
|
|
1059
|
-
}
|
|
1060
|
-
__name(pick2, "pick");
|
|
1061
|
-
function mergeWhatsAppConfigLayers(env, db, plugin) {
|
|
1062
|
-
return {
|
|
1063
|
-
accessToken: pick2(plugin, db, env, "accessToken", "WHATSAPP_ACCESS_TOKEN"),
|
|
1064
|
-
phoneNumberId: pick2(plugin, db, env, "phoneNumberId", "WHATSAPP_PHONE_NUMBER_ID"),
|
|
1065
|
-
apiVersion: pick2(plugin, db, env, "apiVersion", "WHATSAPP_API_VERSION") ?? "v21.0"
|
|
1066
|
-
};
|
|
1067
|
-
}
|
|
1068
|
-
__name(mergeWhatsAppConfigLayers, "mergeWhatsAppConfigLayers");
|
|
1069
|
-
function isWhatsAppPluginEnabled(db) {
|
|
1070
|
-
const v = (db.enabled ?? "true").toLowerCase();
|
|
1071
|
-
return v !== "false" && v !== "0";
|
|
1072
|
-
}
|
|
1073
|
-
__name(isWhatsAppPluginEnabled, "isWhatsAppPluginEnabled");
|
|
1074
|
-
function whatsAppConfigured(config) {
|
|
1075
|
-
return Boolean(config.accessToken?.trim() && config.phoneNumberId?.trim());
|
|
1076
|
-
}
|
|
1077
|
-
__name(whatsAppConfigured, "whatsAppConfigured");
|
|
1078
|
-
function normalizeWhatsAppRecipient(to) {
|
|
1079
|
-
const digits = to.replace(/\D/g, "");
|
|
1080
|
-
return digits;
|
|
1081
|
-
}
|
|
1082
|
-
__name(normalizeWhatsAppRecipient, "normalizeWhatsAppRecipient");
|
|
1083
|
-
function maskPhone(digits) {
|
|
1084
|
-
if (digits.length <= 4) return "****";
|
|
1085
|
-
return `${"*".repeat(Math.max(0, digits.length - 4))}${digits.slice(-4)}`;
|
|
1086
|
-
}
|
|
1087
|
-
__name(maskPhone, "maskPhone");
|
|
1088
|
-
function logWhatsApp(level, message, extra) {
|
|
1089
|
-
const line = extra ? `${message} ${JSON.stringify(extra)}` : message;
|
|
1090
|
-
if (level === "info") console.log(`[whatsapp] ${line}`);
|
|
1091
|
-
else if (level === "warn") console.warn(`[whatsapp] ${line}`);
|
|
1092
|
-
else console.error(`[whatsapp] ${line}`);
|
|
1093
|
-
}
|
|
1094
|
-
__name(logWhatsApp, "logWhatsApp");
|
|
1095
|
-
var WhatsAppService = class {
|
|
1096
|
-
static {
|
|
1097
|
-
__name(this, "WhatsAppService");
|
|
1098
|
-
}
|
|
1099
|
-
getWhatsAppSettings;
|
|
1100
|
-
config;
|
|
1101
|
-
getMessageTemplateRow;
|
|
1102
|
-
constructor(env, plugin = {}, getWhatsAppSettings, getMessageTemplateRow) {
|
|
1103
|
-
this.getWhatsAppSettings = getWhatsAppSettings;
|
|
1104
|
-
this.getMessageTemplateRow = getMessageTemplateRow;
|
|
1105
|
-
this.config = mergeWhatsAppConfigLayers(env, {}, plugin);
|
|
1106
|
-
}
|
|
1107
|
-
async mergedConfig() {
|
|
1108
|
-
let db = {};
|
|
1109
|
-
try {
|
|
1110
|
-
db = await this.getWhatsAppSettings?.() ?? {};
|
|
1111
|
-
} catch {
|
|
1112
|
-
}
|
|
1113
|
-
return mergeWhatsAppConfigLayers((typeof process !== "undefined" ? process.env : {}) ?? {}, db, this.config);
|
|
1114
|
-
}
|
|
1115
|
-
async send(opts) {
|
|
1116
|
-
const cfg = await this.mergedConfig();
|
|
1117
|
-
if (!whatsAppConfigured(cfg)) {
|
|
1118
|
-
logWhatsApp("warn", "send skipped: not configured (WHATSAPP_ACCESS_TOKEN + WHATSAPP_PHONE_NUMBER_ID)");
|
|
1119
|
-
return false;
|
|
1120
|
-
}
|
|
1121
|
-
const to = normalizeWhatsAppRecipient(opts.to);
|
|
1122
|
-
if (!to) {
|
|
1123
|
-
logWhatsApp("warn", "send skipped: invalid recipient", {
|
|
1124
|
-
rawTo: opts.to
|
|
1125
|
-
});
|
|
1126
|
-
return false;
|
|
1127
|
-
}
|
|
1128
|
-
logWhatsApp("info", "send started", {
|
|
1129
|
-
to: maskPhone(to),
|
|
1130
|
-
templateKey: opts.templateKey ?? null,
|
|
1131
|
-
externalTemplateRef: opts.externalTemplateRef ?? null,
|
|
1132
|
-
phoneNumberId: cfg.phoneNumberId
|
|
1133
|
-
});
|
|
1134
|
-
let templateName = opts.externalTemplateRef?.trim();
|
|
1135
|
-
let body = opts.body?.trim() ?? "";
|
|
1136
|
-
const variables = opts.variables ?? {};
|
|
1137
|
-
if (opts.templateKey?.trim() && this.getMessageTemplateRow) {
|
|
1138
|
-
const { resolveEventOrderTemplate: resolveEventOrderTemplate2 } = await import('./event-order-defaults-6E543227.js');
|
|
1139
|
-
const resolved = await resolveEventOrderTemplate2("whatsapp", async (ch, key) => {
|
|
1140
|
-
const row = await this.getMessageTemplateRow(ch, key);
|
|
1141
|
-
if (!row) return null;
|
|
1142
|
-
return {
|
|
1143
|
-
subject: null,
|
|
1144
|
-
body: row.body,
|
|
1145
|
-
externalTemplateRef: row.externalTemplateRef,
|
|
1146
|
-
enabled: row.enabled
|
|
1147
|
-
};
|
|
1148
|
-
});
|
|
1149
|
-
if (resolved && !resolved.enabled) {
|
|
1150
|
-
logWhatsApp("warn", "send skipped: template disabled in message_templates", {
|
|
1151
|
-
templateKey: opts.templateKey
|
|
1152
|
-
});
|
|
1153
|
-
return false;
|
|
1154
|
-
}
|
|
1155
|
-
if (resolved) {
|
|
1156
|
-
body = resolved.body;
|
|
1157
|
-
if (resolved.externalTemplateRef) templateName = resolved.externalTemplateRef;
|
|
1158
|
-
}
|
|
1159
|
-
}
|
|
1160
|
-
const { applyTemplateVars } = await import('./interpolate-WDUWDF3I.js');
|
|
1161
|
-
if (body) body = applyTemplateVars(body, variables);
|
|
1162
|
-
if (templateName) {
|
|
1163
|
-
const paramValues = opts.templateParamOrder?.length ? opts.templateParamOrder.map((key) => String(variables[key] ?? "").slice(0, 1024)) : Object.keys(variables).length ? Object.values(variables) : body ? [
|
|
1164
|
-
body
|
|
1165
|
-
] : [];
|
|
1166
|
-
logWhatsApp("info", "sending template message", {
|
|
1167
|
-
to: maskPhone(to),
|
|
1168
|
-
templateName,
|
|
1169
|
-
paramCount: paramValues.length,
|
|
1170
|
-
paramOrder: opts.templateParamOrder ?? null
|
|
1171
|
-
});
|
|
1172
|
-
return this.sendTemplateMessage(cfg, to, templateName, paramValues);
|
|
1173
|
-
}
|
|
1174
|
-
if (!body) {
|
|
1175
|
-
logWhatsApp("warn", "send skipped: no template name and empty body", {
|
|
1176
|
-
to: maskPhone(to)
|
|
1177
|
-
});
|
|
1178
|
-
return false;
|
|
1179
|
-
}
|
|
1180
|
-
logWhatsApp("info", "sending text message", {
|
|
1181
|
-
to: maskPhone(to),
|
|
1182
|
-
bodyLength: body.length
|
|
1183
|
-
});
|
|
1184
|
-
return this.sendTextMessage(cfg, to, body);
|
|
1185
|
-
}
|
|
1186
|
-
async sendTextMessage(cfg, to, body) {
|
|
1187
|
-
const url = `https://graph.facebook.com/${cfg.apiVersion}/${cfg.phoneNumberId}/messages`;
|
|
1188
|
-
const res = await fetch(url, {
|
|
1189
|
-
method: "POST",
|
|
1190
|
-
headers: {
|
|
1191
|
-
Authorization: `Bearer ${cfg.accessToken}`,
|
|
1192
|
-
"Content-Type": "application/json"
|
|
1193
|
-
},
|
|
1194
|
-
body: JSON.stringify({
|
|
1195
|
-
messaging_product: "whatsapp",
|
|
1196
|
-
to,
|
|
1197
|
-
type: "text",
|
|
1198
|
-
text: {
|
|
1199
|
-
body
|
|
1200
|
-
}
|
|
1201
|
-
})
|
|
1202
|
-
});
|
|
1203
|
-
if (!res.ok) {
|
|
1204
|
-
const errText = await res.text().catch(() => "");
|
|
1205
|
-
logWhatsApp("error", "text send failed", {
|
|
1206
|
-
status: res.status,
|
|
1207
|
-
to: maskPhone(to),
|
|
1208
|
-
error: errText
|
|
1209
|
-
});
|
|
1210
|
-
return false;
|
|
1211
|
-
}
|
|
1212
|
-
const data = await res.json().catch(() => ({}));
|
|
1213
|
-
logWhatsApp("info", "text send succeeded", {
|
|
1214
|
-
to: maskPhone(to),
|
|
1215
|
-
messageId: data.messages?.[0]?.id ?? null
|
|
1216
|
-
});
|
|
1217
|
-
return true;
|
|
1218
|
-
}
|
|
1219
|
-
async sendTemplateMessage(cfg, to, templateName, paramValues) {
|
|
1220
|
-
const components = paramValues.length > 0 ? [
|
|
1221
|
-
{
|
|
1222
|
-
type: "body",
|
|
1223
|
-
parameters: paramValues.map((text) => ({
|
|
1224
|
-
type: "text",
|
|
1225
|
-
text: String(text).slice(0, 1024)
|
|
1226
|
-
}))
|
|
1227
|
-
}
|
|
1228
|
-
] : void 0;
|
|
1229
|
-
const url = `https://graph.facebook.com/${cfg.apiVersion}/${cfg.phoneNumberId}/messages`;
|
|
1230
|
-
const payload = {
|
|
1231
|
-
messaging_product: "whatsapp",
|
|
1232
|
-
to,
|
|
1233
|
-
type: "template",
|
|
1234
|
-
template: {
|
|
1235
|
-
name: templateName,
|
|
1236
|
-
language: {
|
|
1237
|
-
code: "en"
|
|
1238
|
-
},
|
|
1239
|
-
...components ? {
|
|
1240
|
-
components
|
|
1241
|
-
} : {}
|
|
1242
|
-
}
|
|
1243
|
-
};
|
|
1244
|
-
const res = await fetch(url, {
|
|
1245
|
-
method: "POST",
|
|
1246
|
-
headers: {
|
|
1247
|
-
Authorization: `Bearer ${cfg.accessToken}`,
|
|
1248
|
-
"Content-Type": "application/json"
|
|
1249
|
-
},
|
|
1250
|
-
body: JSON.stringify(payload)
|
|
1251
|
-
});
|
|
1252
|
-
if (!res.ok) {
|
|
1253
|
-
const errText = await res.text().catch(() => "");
|
|
1254
|
-
logWhatsApp("error", "template send failed", {
|
|
1255
|
-
status: res.status,
|
|
1256
|
-
to: maskPhone(to),
|
|
1257
|
-
templateName,
|
|
1258
|
-
paramCount: paramValues.length,
|
|
1259
|
-
error: errText
|
|
1260
|
-
});
|
|
1261
|
-
return false;
|
|
1262
|
-
}
|
|
1263
|
-
const data = await res.json().catch(() => ({}));
|
|
1264
|
-
logWhatsApp("info", "template send succeeded", {
|
|
1265
|
-
to: maskPhone(to),
|
|
1266
|
-
templateName,
|
|
1267
|
-
messageId: data.messages?.[0]?.id ?? null
|
|
1268
|
-
});
|
|
1269
|
-
return true;
|
|
1270
|
-
}
|
|
1271
|
-
};
|
|
1272
|
-
|
|
1273
|
-
// src/plugins/whatsapp/index.ts
|
|
1274
|
-
function whatsappPlugin(config = {}) {
|
|
1275
|
-
return {
|
|
1276
|
-
name: "whatsapp",
|
|
1277
|
-
version: "1.0.0",
|
|
1278
|
-
async init(context) {
|
|
1279
|
-
const env = context.config;
|
|
1280
|
-
const { getWhatsAppSettings, getMessageTemplateRow, ...staticRest } = config;
|
|
1281
|
-
let db = {};
|
|
1282
|
-
try {
|
|
1283
|
-
db = await getWhatsAppSettings?.() ?? {};
|
|
1284
|
-
} catch {
|
|
1285
|
-
}
|
|
1286
|
-
const merged = mergeWhatsAppConfigLayers(env, db, staticRest);
|
|
1287
|
-
if (!isWhatsAppPluginEnabled(db)) {
|
|
1288
|
-
context.logger.warn("WhatsApp plugin skipped: disabled in settings");
|
|
1289
|
-
return null;
|
|
1290
|
-
}
|
|
1291
|
-
if (!whatsAppConfigured(merged)) {
|
|
1292
|
-
context.logger.warn("WhatsApp plugin skipped: set WHATSAPP_ACCESS_TOKEN and WHATSAPP_PHONE_NUMBER_ID (Meta Cloud API)");
|
|
1293
|
-
return null;
|
|
1294
|
-
}
|
|
1295
|
-
const svc = new WhatsAppService(env, staticRest, getWhatsAppSettings, getMessageTemplateRow);
|
|
1296
|
-
return {
|
|
1297
|
-
send: /* @__PURE__ */ __name((opts) => svc.send(opts), "send")
|
|
1298
|
-
};
|
|
1299
|
-
}
|
|
1300
|
-
};
|
|
1301
|
-
}
|
|
1302
|
-
__name(whatsappPlugin, "whatsappPlugin");
|
|
1303
|
-
|
|
1304
1004
|
// src/plugins/payment/index.ts
|
|
1305
1005
|
function paymentPlugin(config) {
|
|
1306
1006
|
return {
|
|
@@ -2148,103 +1848,6 @@ function cachePlugin(config) {
|
|
|
2148
1848
|
};
|
|
2149
1849
|
}
|
|
2150
1850
|
__name(cachePlugin, "cachePlugin");
|
|
2151
|
-
function connectionFromUrl(redisUrl) {
|
|
2152
|
-
const u = new URL(redisUrl);
|
|
2153
|
-
return {
|
|
2154
|
-
host: u.hostname,
|
|
2155
|
-
port: u.port ? parseInt(u.port, 10) : 6379,
|
|
2156
|
-
...u.username && {
|
|
2157
|
-
username: u.username
|
|
2158
|
-
},
|
|
2159
|
-
...u.password && {
|
|
2160
|
-
password: u.password
|
|
2161
|
-
},
|
|
2162
|
-
maxRetriesPerRequest: null
|
|
2163
|
-
};
|
|
2164
|
-
}
|
|
2165
|
-
__name(connectionFromUrl, "connectionFromUrl");
|
|
2166
|
-
var BullMQQueue = class {
|
|
2167
|
-
static {
|
|
2168
|
-
__name(this, "BullMQQueue");
|
|
2169
|
-
}
|
|
2170
|
-
connectionOptions;
|
|
2171
|
-
queues = /* @__PURE__ */ new Map();
|
|
2172
|
-
workers = /* @__PURE__ */ new Map();
|
|
2173
|
-
constructor(redisUrl) {
|
|
2174
|
-
this.connectionOptions = connectionFromUrl(redisUrl);
|
|
2175
|
-
}
|
|
2176
|
-
async add(queueName, data) {
|
|
2177
|
-
const queue = this.getOrCreateQueue(queueName);
|
|
2178
|
-
await queue.add(queueName, data);
|
|
2179
|
-
}
|
|
2180
|
-
registerProcessor(queueName, processor) {
|
|
2181
|
-
if (this.workers.has(queueName)) return;
|
|
2182
|
-
const worker = new Worker(queueName, async (job) => {
|
|
2183
|
-
await processor(job.data);
|
|
2184
|
-
}, {
|
|
2185
|
-
connection: this.connectionOptions
|
|
2186
|
-
});
|
|
2187
|
-
this.workers.set(queueName, worker);
|
|
2188
|
-
}
|
|
2189
|
-
getOrCreateQueue(queueName) {
|
|
2190
|
-
let queue = this.queues.get(queueName);
|
|
2191
|
-
if (!queue) {
|
|
2192
|
-
queue = new Queue(queueName, {
|
|
2193
|
-
connection: this.connectionOptions
|
|
2194
|
-
});
|
|
2195
|
-
this.queues.set(queueName, queue);
|
|
2196
|
-
}
|
|
2197
|
-
return queue;
|
|
2198
|
-
}
|
|
2199
|
-
async destroy() {
|
|
2200
|
-
for (const w of this.workers.values()) await w.close();
|
|
2201
|
-
this.workers.clear();
|
|
2202
|
-
for (const q of this.queues.values()) await q.close();
|
|
2203
|
-
this.queues.clear();
|
|
2204
|
-
}
|
|
2205
|
-
};
|
|
2206
|
-
var MemoryQueue = class {
|
|
2207
|
-
static {
|
|
2208
|
-
__name(this, "MemoryQueue");
|
|
2209
|
-
}
|
|
2210
|
-
queues = /* @__PURE__ */ new Map();
|
|
2211
|
-
async add(queueName, data) {
|
|
2212
|
-
const q = this.queues.get(queueName);
|
|
2213
|
-
if (!q) throw new Error(`No processor registered for queue: ${queueName}`);
|
|
2214
|
-
void Promise.resolve(q.push(data)).catch(() => void 0);
|
|
2215
|
-
}
|
|
2216
|
-
registerProcessor(queueName, processor) {
|
|
2217
|
-
if (this.queues.has(queueName)) return;
|
|
2218
|
-
const worker = /* @__PURE__ */ __name(async (task) => processor(task), "worker");
|
|
2219
|
-
const q = fastq.promise(worker, 1);
|
|
2220
|
-
this.queues.set(queueName, q);
|
|
2221
|
-
}
|
|
2222
|
-
};
|
|
2223
|
-
|
|
2224
|
-
// src/plugins/queue/index.ts
|
|
2225
|
-
function queuePlugin(config) {
|
|
2226
|
-
let instance;
|
|
2227
|
-
return {
|
|
2228
|
-
name: "queue",
|
|
2229
|
-
version: "1.0.0",
|
|
2230
|
-
async init(context) {
|
|
2231
|
-
const redisUrl = config?.redisUrl ?? context.config.REDIS_URL ?? "";
|
|
2232
|
-
const url = typeof redisUrl === "string" ? redisUrl.trim() : "";
|
|
2233
|
-
if (url) {
|
|
2234
|
-
instance = new BullMQQueue(url);
|
|
2235
|
-
return instance;
|
|
2236
|
-
}
|
|
2237
|
-
instance = new MemoryQueue();
|
|
2238
|
-
return instance;
|
|
2239
|
-
},
|
|
2240
|
-
async destroy() {
|
|
2241
|
-
if (instance && "destroy" in instance && typeof instance.destroy === "function") {
|
|
2242
|
-
await instance.destroy();
|
|
2243
|
-
}
|
|
2244
|
-
}
|
|
2245
|
-
};
|
|
2246
|
-
}
|
|
2247
|
-
__name(queuePlugin, "queuePlugin");
|
|
2248
1851
|
|
|
2249
1852
|
// src/plugins/pg-boss/index.ts
|
|
2250
1853
|
function pgBossPlugin(config = {}) {
|
|
@@ -2271,310 +1874,46 @@ function pgBossPlugin(config = {}) {
|
|
|
2271
1874
|
};
|
|
2272
1875
|
}
|
|
2273
1876
|
__name(pgBossPlugin, "pgBossPlugin");
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
function resolveKeys(config) {
|
|
2277
|
-
const turnstile = config.TURNSTILE_SITE_KEY?.trim() && config.TURNSTILE_SECRET_KEY?.trim() ? {
|
|
2278
|
-
site: config.TURNSTILE_SITE_KEY.trim(),
|
|
2279
|
-
secret: config.TURNSTILE_SECRET_KEY.trim()
|
|
2280
|
-
} : null;
|
|
2281
|
-
const recaptcha = config.RECAPTCHA_SITE_KEY?.trim() && config.RECAPTCHA_SECRET_KEY?.trim() ? {
|
|
2282
|
-
site: config.RECAPTCHA_SITE_KEY.trim(),
|
|
2283
|
-
secret: config.RECAPTCHA_SECRET_KEY.trim()
|
|
2284
|
-
} : null;
|
|
2285
|
-
const raw = config.CAPTCHA_PROVIDER?.trim().toLowerCase();
|
|
2286
|
-
let envDefaultProvider = null;
|
|
2287
|
-
if (raw === "turnstile") envDefaultProvider = "turnstile";
|
|
2288
|
-
else if (raw === "recaptcha_v3" || raw === "recaptcha") envDefaultProvider = "recaptcha_v3";
|
|
2289
|
-
const minScore = parseFloat(config.RECAPTCHA_MIN_SCORE ?? "0.5");
|
|
2290
|
-
return {
|
|
2291
|
-
turnstile,
|
|
2292
|
-
recaptcha,
|
|
2293
|
-
envDefaultProvider,
|
|
2294
|
-
minScore: Number.isFinite(minScore) ? minScore : 0.5
|
|
2295
|
-
};
|
|
1877
|
+
function cn(...inputs) {
|
|
1878
|
+
return twMerge(clsx(inputs));
|
|
2296
1879
|
}
|
|
2297
|
-
__name(
|
|
2298
|
-
function
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
1880
|
+
__name(cn, "cn");
|
|
1881
|
+
function generateSlug(title) {
|
|
1882
|
+
return title.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/(^-|-$)/g, "");
|
|
1883
|
+
}
|
|
1884
|
+
__name(generateSlug, "generateSlug");
|
|
1885
|
+
function validateSlug(slug) {
|
|
1886
|
+
const slugRegex = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
1887
|
+
return slugRegex.test(slug) && slug.length >= 3 && slug.length <= 50;
|
|
1888
|
+
}
|
|
1889
|
+
__name(validateSlug, "validateSlug");
|
|
1890
|
+
function formatDate(date) {
|
|
1891
|
+
const d = new Date(date);
|
|
1892
|
+
return d.toLocaleDateString("en-US", {
|
|
1893
|
+
year: "numeric",
|
|
1894
|
+
month: "long",
|
|
1895
|
+
day: "numeric"
|
|
2308
1896
|
});
|
|
2309
|
-
const enabled = available.length > 0;
|
|
2310
|
-
const multipleProviders = available.length > 1;
|
|
2311
|
-
let activeProvider = null;
|
|
2312
|
-
if (r.turnstile && !r.recaptcha) activeProvider = "turnstile";
|
|
2313
|
-
else if (r.recaptcha && !r.turnstile) activeProvider = "recaptcha_v3";
|
|
2314
|
-
else if (multipleProviders) {
|
|
2315
|
-
activeProvider = r.envDefaultProvider ?? available[0].id;
|
|
2316
|
-
}
|
|
2317
|
-
let siteKey = null;
|
|
2318
|
-
if (activeProvider === "turnstile" && r.turnstile) siteKey = r.turnstile.site;
|
|
2319
|
-
else if (activeProvider === "recaptcha_v3" && r.recaptcha) siteKey = r.recaptcha.site;
|
|
2320
|
-
if (!siteKey && available.length === 1) siteKey = available[0].siteKey;
|
|
2321
|
-
return {
|
|
2322
|
-
enabled,
|
|
2323
|
-
activeProvider,
|
|
2324
|
-
siteKey,
|
|
2325
|
-
availableProviders: available,
|
|
2326
|
-
multipleProviders
|
|
2327
|
-
};
|
|
2328
1897
|
}
|
|
2329
|
-
__name(
|
|
2330
|
-
function
|
|
2331
|
-
const
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
1898
|
+
__name(formatDate, "formatDate");
|
|
1899
|
+
function formatDateTime(date) {
|
|
1900
|
+
const d = new Date(date);
|
|
1901
|
+
return d.toLocaleDateString("en-US", {
|
|
1902
|
+
year: "numeric",
|
|
1903
|
+
month: "short",
|
|
1904
|
+
day: "numeric",
|
|
1905
|
+
hour: "2-digit",
|
|
1906
|
+
minute: "2-digit"
|
|
1907
|
+
});
|
|
2338
1908
|
}
|
|
2339
|
-
__name(
|
|
2340
|
-
function
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
const bodyP = normalizeBodyProvider(body.captchaProvider);
|
|
2348
|
-
const hasT = !!r.turnstile;
|
|
2349
|
-
const hasR = !!r.recaptcha;
|
|
2350
|
-
if (hasT && !hasR) {
|
|
2351
|
-
if (bodyP && bodyP !== "turnstile") return {
|
|
2352
|
-
error: "Invalid captchaProvider"
|
|
2353
|
-
};
|
|
2354
|
-
return {
|
|
2355
|
-
provider: "turnstile",
|
|
2356
|
-
secret: r.turnstile.secret
|
|
2357
|
-
};
|
|
2358
|
-
}
|
|
2359
|
-
if (hasR && !hasT) {
|
|
2360
|
-
if (bodyP && bodyP !== "recaptcha_v3") return {
|
|
2361
|
-
error: "Invalid captchaProvider"
|
|
2362
|
-
};
|
|
2363
|
-
return {
|
|
2364
|
-
provider: "recaptcha_v3",
|
|
2365
|
-
secret: r.recaptcha.secret
|
|
2366
|
-
};
|
|
2367
|
-
}
|
|
2368
|
-
if (!hasT && !hasR) return {
|
|
2369
|
-
error: "Captcha not configured"
|
|
2370
|
-
};
|
|
2371
|
-
if (bodyP === "turnstile" && hasT) return {
|
|
2372
|
-
provider: "turnstile",
|
|
2373
|
-
secret: r.turnstile.secret
|
|
2374
|
-
};
|
|
2375
|
-
if (bodyP === "recaptcha_v3" && hasR) return {
|
|
2376
|
-
provider: "recaptcha_v3",
|
|
2377
|
-
secret: r.recaptcha.secret
|
|
2378
|
-
};
|
|
2379
|
-
if (r.envDefaultProvider === "turnstile" && hasT) return {
|
|
2380
|
-
provider: "turnstile",
|
|
2381
|
-
secret: r.turnstile.secret
|
|
2382
|
-
};
|
|
2383
|
-
if (r.envDefaultProvider === "recaptcha_v3" && hasR) return {
|
|
2384
|
-
provider: "recaptcha_v3",
|
|
2385
|
-
secret: r.recaptcha.secret
|
|
2386
|
-
};
|
|
2387
|
-
return {
|
|
2388
|
-
error: "captchaProvider required (turnstile or recaptcha_v3)"
|
|
2389
|
-
};
|
|
2390
|
-
}
|
|
2391
|
-
__name(pickVerifyProvider, "pickVerifyProvider");
|
|
2392
|
-
async function verifyTurnstile(secret, token, remoteip) {
|
|
2393
|
-
const body = new URLSearchParams({
|
|
2394
|
-
secret,
|
|
2395
|
-
response: token
|
|
2396
|
-
});
|
|
2397
|
-
if (remoteip) body.set("remoteip", remoteip);
|
|
2398
|
-
const res = await fetch("https://challenges.cloudflare.com/turnstile/v0/siteverify", {
|
|
2399
|
-
method: "POST",
|
|
2400
|
-
headers: {
|
|
2401
|
-
"Content-Type": "application/x-www-form-urlencoded"
|
|
2402
|
-
},
|
|
2403
|
-
body: body.toString()
|
|
2404
|
-
});
|
|
2405
|
-
if (!res.ok) return false;
|
|
2406
|
-
const data = await res.json();
|
|
2407
|
-
return data.success === true;
|
|
2408
|
-
}
|
|
2409
|
-
__name(verifyTurnstile, "verifyTurnstile");
|
|
2410
|
-
async function verifyRecaptcha(secret, token, remoteip, minScore) {
|
|
2411
|
-
const body = new URLSearchParams({
|
|
2412
|
-
secret,
|
|
2413
|
-
response: token
|
|
2414
|
-
});
|
|
2415
|
-
if (remoteip) body.set("remoteip", remoteip);
|
|
2416
|
-
const res = await fetch("https://www.google.com/recaptcha/api/siteverify", {
|
|
2417
|
-
method: "POST",
|
|
2418
|
-
headers: {
|
|
2419
|
-
"Content-Type": "application/x-www-form-urlencoded"
|
|
2420
|
-
},
|
|
2421
|
-
body: body.toString()
|
|
2422
|
-
});
|
|
2423
|
-
if (!res.ok) return {
|
|
2424
|
-
ok: false
|
|
2425
|
-
};
|
|
2426
|
-
const data = await res.json();
|
|
2427
|
-
if (data.success !== true) return {
|
|
2428
|
-
ok: false
|
|
2429
|
-
};
|
|
2430
|
-
const score = typeof data.score === "number" ? data.score : 0;
|
|
2431
|
-
return {
|
|
2432
|
-
ok: score >= minScore,
|
|
2433
|
-
score
|
|
2434
|
-
};
|
|
2435
|
-
}
|
|
2436
|
-
__name(verifyRecaptcha, "verifyRecaptcha");
|
|
2437
|
-
var CaptchaService = class {
|
|
2438
|
-
static {
|
|
2439
|
-
__name(this, "CaptchaService");
|
|
2440
|
-
}
|
|
2441
|
-
env;
|
|
2442
|
-
constructor(env) {
|
|
2443
|
-
this.env = env;
|
|
2444
|
-
}
|
|
2445
|
-
isEnforced() {
|
|
2446
|
-
return buildCaptchaPublicConfig(this.env).enabled;
|
|
2447
|
-
}
|
|
2448
|
-
getPublicConfig() {
|
|
2449
|
-
return buildCaptchaPublicConfig(this.env);
|
|
2450
|
-
}
|
|
2451
|
-
async verify(body, req) {
|
|
2452
|
-
if (!this.isEnforced()) return {
|
|
2453
|
-
ok: true
|
|
2454
|
-
};
|
|
2455
|
-
const token = typeof body.captchaToken === "string" ? body.captchaToken.trim() : "";
|
|
2456
|
-
if (!token) return {
|
|
2457
|
-
ok: false,
|
|
2458
|
-
status: 400,
|
|
2459
|
-
message: "captchaToken required"
|
|
2460
|
-
};
|
|
2461
|
-
const r = resolveKeys(this.env);
|
|
2462
|
-
const picked = pickVerifyProvider(body, r);
|
|
2463
|
-
if ("error" in picked) return {
|
|
2464
|
-
ok: false,
|
|
2465
|
-
status: 400,
|
|
2466
|
-
message: picked.error
|
|
2467
|
-
};
|
|
2468
|
-
const ip = clientIp(req);
|
|
2469
|
-
if (picked.provider === "turnstile") {
|
|
2470
|
-
const ok = await verifyTurnstile(picked.secret, token, ip);
|
|
2471
|
-
if (!ok) return {
|
|
2472
|
-
ok: false,
|
|
2473
|
-
status: 400,
|
|
2474
|
-
message: "Captcha verification failed"
|
|
2475
|
-
};
|
|
2476
|
-
return {
|
|
2477
|
-
ok: true
|
|
2478
|
-
};
|
|
2479
|
-
}
|
|
2480
|
-
const vr = await verifyRecaptcha(picked.secret, token, ip, r.minScore);
|
|
2481
|
-
if (!vr.ok) return {
|
|
2482
|
-
ok: false,
|
|
2483
|
-
status: 400,
|
|
2484
|
-
message: "Captcha verification failed or score too low"
|
|
2485
|
-
};
|
|
2486
|
-
return {
|
|
2487
|
-
ok: true
|
|
2488
|
-
};
|
|
2489
|
-
}
|
|
2490
|
-
};
|
|
2491
|
-
|
|
2492
|
-
// src/plugins/captcha/captcha-plugin.ts
|
|
2493
|
-
function captchaPlugin() {
|
|
2494
|
-
return {
|
|
2495
|
-
name: "captcha",
|
|
2496
|
-
version: "1.0.0",
|
|
2497
|
-
async init(ctx) {
|
|
2498
|
-
const s = new CaptchaService(ctx.config);
|
|
2499
|
-
return s.isEnforced() ? s : void 0;
|
|
2500
|
-
}
|
|
2501
|
-
};
|
|
2502
|
-
}
|
|
2503
|
-
__name(captchaPlugin, "captchaPlugin");
|
|
2504
|
-
|
|
2505
|
-
// src/plugins/blog-generator/index.ts
|
|
2506
|
-
function blogGeneratorPlugin(config = {}) {
|
|
2507
|
-
return {
|
|
2508
|
-
name: "blog_generator",
|
|
2509
|
-
version: "1.0.0",
|
|
2510
|
-
async init(context) {
|
|
2511
|
-
if (config.enabled === false) {
|
|
2512
|
-
context.logger.warn("Blog Generator plugin skipped: disabled in config");
|
|
2513
|
-
return void 0;
|
|
2514
|
-
}
|
|
2515
|
-
return new BlogGeneratorService();
|
|
2516
|
-
}
|
|
2517
|
-
};
|
|
2518
|
-
}
|
|
2519
|
-
__name(blogGeneratorPlugin, "blogGeneratorPlugin");
|
|
2520
|
-
|
|
2521
|
-
// src/plugins/social-media/index.ts
|
|
2522
|
-
function socialMediaPlugin(config = {}) {
|
|
2523
|
-
return {
|
|
2524
|
-
name: "social_media",
|
|
2525
|
-
version: "1.0.0",
|
|
2526
|
-
async init(context) {
|
|
2527
|
-
if (config.enabled === false) {
|
|
2528
|
-
context.logger.warn("Social media plugin skipped: disabled in config");
|
|
2529
|
-
return void 0;
|
|
2530
|
-
}
|
|
2531
|
-
return {
|
|
2532
|
-
name: "social_media"
|
|
2533
|
-
};
|
|
2534
|
-
}
|
|
2535
|
-
};
|
|
2536
|
-
}
|
|
2537
|
-
__name(socialMediaPlugin, "socialMediaPlugin");
|
|
2538
|
-
function cn(...inputs) {
|
|
2539
|
-
return twMerge(clsx(inputs));
|
|
2540
|
-
}
|
|
2541
|
-
__name(cn, "cn");
|
|
2542
|
-
function generateSlug(title) {
|
|
2543
|
-
return title.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/(^-|-$)/g, "");
|
|
2544
|
-
}
|
|
2545
|
-
__name(generateSlug, "generateSlug");
|
|
2546
|
-
function validateSlug(slug) {
|
|
2547
|
-
const slugRegex = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
2548
|
-
return slugRegex.test(slug) && slug.length >= 3 && slug.length <= 50;
|
|
2549
|
-
}
|
|
2550
|
-
__name(validateSlug, "validateSlug");
|
|
2551
|
-
function formatDate(date) {
|
|
2552
|
-
const d = new Date(date);
|
|
2553
|
-
return d.toLocaleDateString("en-US", {
|
|
2554
|
-
year: "numeric",
|
|
2555
|
-
month: "long",
|
|
2556
|
-
day: "numeric"
|
|
2557
|
-
});
|
|
2558
|
-
}
|
|
2559
|
-
__name(formatDate, "formatDate");
|
|
2560
|
-
function formatDateTime(date) {
|
|
2561
|
-
const d = new Date(date);
|
|
2562
|
-
return d.toLocaleDateString("en-US", {
|
|
2563
|
-
year: "numeric",
|
|
2564
|
-
month: "short",
|
|
2565
|
-
day: "numeric",
|
|
2566
|
-
hour: "2-digit",
|
|
2567
|
-
minute: "2-digit"
|
|
2568
|
-
});
|
|
2569
|
-
}
|
|
2570
|
-
__name(formatDateTime, "formatDateTime");
|
|
2571
|
-
function formatDateOnly(date) {
|
|
2572
|
-
const d = new Date(date);
|
|
2573
|
-
return d.toLocaleDateString("en-US", {
|
|
2574
|
-
year: "numeric",
|
|
2575
|
-
month: "long",
|
|
2576
|
-
day: "numeric"
|
|
2577
|
-
});
|
|
1909
|
+
__name(formatDateTime, "formatDateTime");
|
|
1910
|
+
function formatDateOnly(date) {
|
|
1911
|
+
const d = new Date(date);
|
|
1912
|
+
return d.toLocaleDateString("en-US", {
|
|
1913
|
+
year: "numeric",
|
|
1914
|
+
month: "long",
|
|
1915
|
+
day: "numeric"
|
|
1916
|
+
});
|
|
2578
1917
|
}
|
|
2579
1918
|
__name(formatDateOnly, "formatDateOnly");
|
|
2580
1919
|
function truncateText(text, maxLength) {
|
|
@@ -2713,14 +2052,14 @@ async function resolvePublicMetadata(args) {
|
|
|
2713
2052
|
return out;
|
|
2714
2053
|
}
|
|
2715
2054
|
__name(resolvePublicMetadata, "resolvePublicMetadata");
|
|
2716
|
-
function
|
|
2055
|
+
function clientIp(req) {
|
|
2717
2056
|
const cf = req.headers.get("cf-connecting-ip")?.trim();
|
|
2718
2057
|
if (cf) return cf;
|
|
2719
2058
|
const xff = req.headers.get("x-forwarded-for")?.trim();
|
|
2720
2059
|
if (xff) return xff.split(",")[0].trim();
|
|
2721
2060
|
return req.headers.get("x-real-ip")?.trim() || "unknown";
|
|
2722
2061
|
}
|
|
2723
|
-
__name(
|
|
2062
|
+
__name(clientIp, "clientIp");
|
|
2724
2063
|
var WINDOW_MS = Math.max(1e3, parseInt(process.env.RATE_LIMIT_WINDOW_MS ?? "60000", 10) || 6e4);
|
|
2725
2064
|
var MAX_REQ = Math.max(1, parseInt(process.env.RATE_LIMIT_MAX ?? "120", 10) || 120);
|
|
2726
2065
|
var redisClient;
|
|
@@ -2808,7 +2147,7 @@ function shouldRateLimitPublicWrite(method, segments, extraRule) {
|
|
|
2808
2147
|
}
|
|
2809
2148
|
__name(shouldRateLimitPublicWrite, "shouldRateLimitPublicWrite");
|
|
2810
2149
|
function rateLimitKeyForApiRequest(req, segments) {
|
|
2811
|
-
return `${
|
|
2150
|
+
return `${clientIp(req)}:${segments.join("/")}`;
|
|
2812
2151
|
}
|
|
2813
2152
|
__name(rateLimitKeyForApiRequest, "rateLimitKeyForApiRequest");
|
|
2814
2153
|
async function rateLimitPublicApiIfNeeded(req, method, segments, options) {
|
|
@@ -2825,7 +2164,7 @@ async function rateLimitPublicApiIfNeeded(req, method, segments, options) {
|
|
|
2825
2164
|
__name(rateLimitPublicApiIfNeeded, "rateLimitPublicApiIfNeeded");
|
|
2826
2165
|
var CHECKOUT_PREFIX = "checkout:";
|
|
2827
2166
|
async function rateLimitCheckoutPost(req) {
|
|
2828
|
-
const key = `${CHECKOUT_PREFIX}${
|
|
2167
|
+
const key = `${CHECKOUT_PREFIX}${clientIp(req)}`;
|
|
2829
2168
|
const ok = await allowRateLimit(key);
|
|
2830
2169
|
if (ok) return null;
|
|
2831
2170
|
return NextResponse.json({
|
|
@@ -2935,6 +2274,36 @@ async function sendOrderPlacedEmailsAfterConfirmation(orderId, deps) {
|
|
|
2935
2274
|
}
|
|
2936
2275
|
}
|
|
2937
2276
|
__name(sendOrderPlacedEmailsAfterConfirmation, "sendOrderPlacedEmailsAfterConfirmation");
|
|
2277
|
+
|
|
2278
|
+
// src/lib/order-notification-trigger-seeds.ts
|
|
2279
|
+
var DEFAULT_ORDER_NOTIFICATION_TRIGGER_SEEDS = [
|
|
2280
|
+
{
|
|
2281
|
+
triggerKey: "order_placed",
|
|
2282
|
+
label: "Order placed",
|
|
2283
|
+
description: "Fires when a new order is created (storefront checkout or admin).",
|
|
2284
|
+
category: "order",
|
|
2285
|
+
sortOrder: 1
|
|
2286
|
+
},
|
|
2287
|
+
{
|
|
2288
|
+
triggerKey: "order_cancelled",
|
|
2289
|
+
label: "Order cancelled",
|
|
2290
|
+
description: "Fires when an order is cancelled (includes refund amount when applicable).",
|
|
2291
|
+
category: "order",
|
|
2292
|
+
sortOrder: 2
|
|
2293
|
+
}
|
|
2294
|
+
];
|
|
2295
|
+
|
|
2296
|
+
// src/lib/order-notification-triggers.ts
|
|
2297
|
+
var ORDER_NOTIFICATION_TRIGGERS = [
|
|
2298
|
+
{
|
|
2299
|
+
key: "order_placed",
|
|
2300
|
+
label: "Order placed"
|
|
2301
|
+
},
|
|
2302
|
+
{
|
|
2303
|
+
key: "order_cancelled",
|
|
2304
|
+
label: "Order cancelled"
|
|
2305
|
+
}
|
|
2306
|
+
];
|
|
2938
2307
|
function createDataSourceManager(entityMap, options) {
|
|
2939
2308
|
const entities = Object.values(entityMap);
|
|
2940
2309
|
const databaseUrl = options?.databaseUrl ?? process.env.DATABASE_URL;
|
|
@@ -3043,16 +2412,44 @@ __name(seedDefaultAdmin, "seedDefaultAdmin");
|
|
|
3043
2412
|
// src/lib/enrich-user-vendor-context.ts
|
|
3044
2413
|
async function enrichUserWithVendorContext(dataSource, user) {
|
|
3045
2414
|
if (!user) return null;
|
|
2415
|
+
const multiVendorEnabled = await checkMultiVendorEnabled(dataSource);
|
|
3046
2416
|
const ctx = await loadUserVendorContext(dataSource, user.id);
|
|
2417
|
+
const isRBACAdmin = isSuperAdmin({
|
|
2418
|
+
groupId: user.groupId ?? void 0,
|
|
2419
|
+
groupName: user.group?.name,
|
|
2420
|
+
isRBACAdmin: false
|
|
2421
|
+
});
|
|
2422
|
+
const isVendorOnlyUser = !isRBACAdmin && (ctx.vendorIds.length > 0 || isVendorGroupName(user.group?.name));
|
|
2423
|
+
if (!multiVendorEnabled && isVendorOnlyUser) {
|
|
2424
|
+
console.log("[enrich-vendor]", {
|
|
2425
|
+
email: user.email,
|
|
2426
|
+
multiVendorEnabled,
|
|
2427
|
+
vendorIdsFromCtx: ctx.vendorIds,
|
|
2428
|
+
groupName: user.group?.name,
|
|
2429
|
+
isRBACAdmin,
|
|
2430
|
+
adminAccess: user.adminAccess,
|
|
2431
|
+
isVendorOnlyUser
|
|
2432
|
+
});
|
|
2433
|
+
return null;
|
|
2434
|
+
}
|
|
2435
|
+
const effectiveCtx = multiVendorEnabled ? ctx : {
|
|
2436
|
+
vendorIds: [],
|
|
2437
|
+
activeVendorId: null,
|
|
2438
|
+
vendorRole: null,
|
|
2439
|
+
vendorRoleId: null,
|
|
2440
|
+
vendorRoleName: null,
|
|
2441
|
+
isVendorRoleOwner: false,
|
|
2442
|
+
vendorEntityPerms: {}
|
|
2443
|
+
};
|
|
3047
2444
|
return {
|
|
3048
2445
|
...user,
|
|
3049
|
-
vendorIds:
|
|
3050
|
-
activeVendorId:
|
|
3051
|
-
vendorRole:
|
|
3052
|
-
vendorRoleId:
|
|
3053
|
-
vendorRoleName:
|
|
3054
|
-
isVendorRoleOwner:
|
|
3055
|
-
vendorEntityPerms:
|
|
2446
|
+
vendorIds: effectiveCtx.vendorIds,
|
|
2447
|
+
activeVendorId: effectiveCtx.activeVendorId,
|
|
2448
|
+
vendorRole: effectiveCtx.vendorRole,
|
|
2449
|
+
vendorRoleId: effectiveCtx.vendorRoleId,
|
|
2450
|
+
vendorRoleName: effectiveCtx.vendorRoleName,
|
|
2451
|
+
isVendorRoleOwner: effectiveCtx.isVendorRoleOwner,
|
|
2452
|
+
vendorEntityPerms: effectiveCtx.vendorEntityPerms
|
|
3056
2453
|
};
|
|
3057
2454
|
}
|
|
3058
2455
|
__name(enrichUserWithVendorContext, "enrichUserWithVendorContext");
|
|
@@ -3131,6 +2528,270 @@ async function withAdminRlsContext(dataSource, fn) {
|
|
|
3131
2528
|
}
|
|
3132
2529
|
__name(withAdminRlsContext, "withAdminRlsContext");
|
|
3133
2530
|
|
|
2531
|
+
// src/plugins/captcha/captcha-service.ts
|
|
2532
|
+
function resolveKeys(config) {
|
|
2533
|
+
const turnstile = config.TURNSTILE_SITE_KEY?.trim() && config.TURNSTILE_SECRET_KEY?.trim() ? {
|
|
2534
|
+
site: config.TURNSTILE_SITE_KEY.trim(),
|
|
2535
|
+
secret: config.TURNSTILE_SECRET_KEY.trim()
|
|
2536
|
+
} : null;
|
|
2537
|
+
const recaptcha = config.RECAPTCHA_SITE_KEY?.trim() && config.RECAPTCHA_SECRET_KEY?.trim() ? {
|
|
2538
|
+
site: config.RECAPTCHA_SITE_KEY.trim(),
|
|
2539
|
+
secret: config.RECAPTCHA_SECRET_KEY.trim()
|
|
2540
|
+
} : null;
|
|
2541
|
+
const raw = config.CAPTCHA_PROVIDER?.trim().toLowerCase();
|
|
2542
|
+
let envDefaultProvider = null;
|
|
2543
|
+
if (raw === "turnstile") envDefaultProvider = "turnstile";
|
|
2544
|
+
else if (raw === "recaptcha_v3" || raw === "recaptcha") envDefaultProvider = "recaptcha_v3";
|
|
2545
|
+
const minScore = parseFloat(config.RECAPTCHA_MIN_SCORE ?? "0.5");
|
|
2546
|
+
return {
|
|
2547
|
+
turnstile,
|
|
2548
|
+
recaptcha,
|
|
2549
|
+
envDefaultProvider,
|
|
2550
|
+
minScore: Number.isFinite(minScore) ? minScore : 0.5
|
|
2551
|
+
};
|
|
2552
|
+
}
|
|
2553
|
+
__name(resolveKeys, "resolveKeys");
|
|
2554
|
+
function buildCaptchaPublicConfig(config) {
|
|
2555
|
+
const r = resolveKeys(config);
|
|
2556
|
+
const available = [];
|
|
2557
|
+
if (r.turnstile) available.push({
|
|
2558
|
+
id: "turnstile",
|
|
2559
|
+
siteKey: r.turnstile.site
|
|
2560
|
+
});
|
|
2561
|
+
if (r.recaptcha) available.push({
|
|
2562
|
+
id: "recaptcha_v3",
|
|
2563
|
+
siteKey: r.recaptcha.site
|
|
2564
|
+
});
|
|
2565
|
+
const enabled = available.length > 0;
|
|
2566
|
+
const multipleProviders = available.length > 1;
|
|
2567
|
+
let activeProvider = null;
|
|
2568
|
+
if (r.turnstile && !r.recaptcha) activeProvider = "turnstile";
|
|
2569
|
+
else if (r.recaptcha && !r.turnstile) activeProvider = "recaptcha_v3";
|
|
2570
|
+
else if (multipleProviders) {
|
|
2571
|
+
activeProvider = r.envDefaultProvider ?? available[0].id;
|
|
2572
|
+
}
|
|
2573
|
+
let siteKey = null;
|
|
2574
|
+
if (activeProvider === "turnstile" && r.turnstile) siteKey = r.turnstile.site;
|
|
2575
|
+
else if (activeProvider === "recaptcha_v3" && r.recaptcha) siteKey = r.recaptcha.site;
|
|
2576
|
+
if (!siteKey && available.length === 1) siteKey = available[0].siteKey;
|
|
2577
|
+
return {
|
|
2578
|
+
enabled,
|
|
2579
|
+
activeProvider,
|
|
2580
|
+
siteKey,
|
|
2581
|
+
availableProviders: available,
|
|
2582
|
+
multipleProviders
|
|
2583
|
+
};
|
|
2584
|
+
}
|
|
2585
|
+
__name(buildCaptchaPublicConfig, "buildCaptchaPublicConfig");
|
|
2586
|
+
function clientIp2(req) {
|
|
2587
|
+
const cf = req.headers.get("cf-connecting-ip")?.trim();
|
|
2588
|
+
if (cf) return cf;
|
|
2589
|
+
const xff = req.headers.get("x-forwarded-for")?.trim();
|
|
2590
|
+
if (xff) return xff.split(",")[0].trim();
|
|
2591
|
+
const real = req.headers.get("x-real-ip")?.trim();
|
|
2592
|
+
if (real) return real;
|
|
2593
|
+
return void 0;
|
|
2594
|
+
}
|
|
2595
|
+
__name(clientIp2, "clientIp");
|
|
2596
|
+
function normalizeBodyProvider(v) {
|
|
2597
|
+
if (v === "turnstile") return "turnstile";
|
|
2598
|
+
if (v === "recaptcha_v3" || v === "recaptcha") return "recaptcha_v3";
|
|
2599
|
+
return null;
|
|
2600
|
+
}
|
|
2601
|
+
__name(normalizeBodyProvider, "normalizeBodyProvider");
|
|
2602
|
+
function pickVerifyProvider(body, r) {
|
|
2603
|
+
const bodyP = normalizeBodyProvider(body.captchaProvider);
|
|
2604
|
+
const hasT = !!r.turnstile;
|
|
2605
|
+
const hasR = !!r.recaptcha;
|
|
2606
|
+
if (hasT && !hasR) {
|
|
2607
|
+
if (bodyP && bodyP !== "turnstile") return {
|
|
2608
|
+
error: "Invalid captchaProvider"
|
|
2609
|
+
};
|
|
2610
|
+
return {
|
|
2611
|
+
provider: "turnstile",
|
|
2612
|
+
secret: r.turnstile.secret
|
|
2613
|
+
};
|
|
2614
|
+
}
|
|
2615
|
+
if (hasR && !hasT) {
|
|
2616
|
+
if (bodyP && bodyP !== "recaptcha_v3") return {
|
|
2617
|
+
error: "Invalid captchaProvider"
|
|
2618
|
+
};
|
|
2619
|
+
return {
|
|
2620
|
+
provider: "recaptcha_v3",
|
|
2621
|
+
secret: r.recaptcha.secret
|
|
2622
|
+
};
|
|
2623
|
+
}
|
|
2624
|
+
if (!hasT && !hasR) return {
|
|
2625
|
+
error: "Captcha not configured"
|
|
2626
|
+
};
|
|
2627
|
+
if (bodyP === "turnstile" && hasT) return {
|
|
2628
|
+
provider: "turnstile",
|
|
2629
|
+
secret: r.turnstile.secret
|
|
2630
|
+
};
|
|
2631
|
+
if (bodyP === "recaptcha_v3" && hasR) return {
|
|
2632
|
+
provider: "recaptcha_v3",
|
|
2633
|
+
secret: r.recaptcha.secret
|
|
2634
|
+
};
|
|
2635
|
+
if (r.envDefaultProvider === "turnstile" && hasT) return {
|
|
2636
|
+
provider: "turnstile",
|
|
2637
|
+
secret: r.turnstile.secret
|
|
2638
|
+
};
|
|
2639
|
+
if (r.envDefaultProvider === "recaptcha_v3" && hasR) return {
|
|
2640
|
+
provider: "recaptcha_v3",
|
|
2641
|
+
secret: r.recaptcha.secret
|
|
2642
|
+
};
|
|
2643
|
+
return {
|
|
2644
|
+
error: "captchaProvider required (turnstile or recaptcha_v3)"
|
|
2645
|
+
};
|
|
2646
|
+
}
|
|
2647
|
+
__name(pickVerifyProvider, "pickVerifyProvider");
|
|
2648
|
+
async function verifyTurnstile(secret, token, remoteip) {
|
|
2649
|
+
const body = new URLSearchParams({
|
|
2650
|
+
secret,
|
|
2651
|
+
response: token
|
|
2652
|
+
});
|
|
2653
|
+
if (remoteip) body.set("remoteip", remoteip);
|
|
2654
|
+
const res = await fetch("https://challenges.cloudflare.com/turnstile/v0/siteverify", {
|
|
2655
|
+
method: "POST",
|
|
2656
|
+
headers: {
|
|
2657
|
+
"Content-Type": "application/x-www-form-urlencoded"
|
|
2658
|
+
},
|
|
2659
|
+
body: body.toString()
|
|
2660
|
+
});
|
|
2661
|
+
if (!res.ok) return false;
|
|
2662
|
+
const data = await res.json();
|
|
2663
|
+
return data.success === true;
|
|
2664
|
+
}
|
|
2665
|
+
__name(verifyTurnstile, "verifyTurnstile");
|
|
2666
|
+
async function verifyRecaptcha(secret, token, remoteip, minScore) {
|
|
2667
|
+
const body = new URLSearchParams({
|
|
2668
|
+
secret,
|
|
2669
|
+
response: token
|
|
2670
|
+
});
|
|
2671
|
+
if (remoteip) body.set("remoteip", remoteip);
|
|
2672
|
+
const res = await fetch("https://www.google.com/recaptcha/api/siteverify", {
|
|
2673
|
+
method: "POST",
|
|
2674
|
+
headers: {
|
|
2675
|
+
"Content-Type": "application/x-www-form-urlencoded"
|
|
2676
|
+
},
|
|
2677
|
+
body: body.toString()
|
|
2678
|
+
});
|
|
2679
|
+
if (!res.ok) return {
|
|
2680
|
+
ok: false
|
|
2681
|
+
};
|
|
2682
|
+
const data = await res.json();
|
|
2683
|
+
if (data.success !== true) return {
|
|
2684
|
+
ok: false
|
|
2685
|
+
};
|
|
2686
|
+
const score = typeof data.score === "number" ? data.score : 0;
|
|
2687
|
+
return {
|
|
2688
|
+
ok: score >= minScore,
|
|
2689
|
+
score
|
|
2690
|
+
};
|
|
2691
|
+
}
|
|
2692
|
+
__name(verifyRecaptcha, "verifyRecaptcha");
|
|
2693
|
+
var CaptchaService = class {
|
|
2694
|
+
static {
|
|
2695
|
+
__name(this, "CaptchaService");
|
|
2696
|
+
}
|
|
2697
|
+
env;
|
|
2698
|
+
constructor(env) {
|
|
2699
|
+
this.env = env;
|
|
2700
|
+
}
|
|
2701
|
+
isEnforced() {
|
|
2702
|
+
return buildCaptchaPublicConfig(this.env).enabled;
|
|
2703
|
+
}
|
|
2704
|
+
getPublicConfig() {
|
|
2705
|
+
return buildCaptchaPublicConfig(this.env);
|
|
2706
|
+
}
|
|
2707
|
+
async verify(body, req) {
|
|
2708
|
+
if (!this.isEnforced()) return {
|
|
2709
|
+
ok: true
|
|
2710
|
+
};
|
|
2711
|
+
const token = typeof body.captchaToken === "string" ? body.captchaToken.trim() : "";
|
|
2712
|
+
if (!token) return {
|
|
2713
|
+
ok: false,
|
|
2714
|
+
status: 400,
|
|
2715
|
+
message: "captchaToken required"
|
|
2716
|
+
};
|
|
2717
|
+
const r = resolveKeys(this.env);
|
|
2718
|
+
const picked = pickVerifyProvider(body, r);
|
|
2719
|
+
if ("error" in picked) return {
|
|
2720
|
+
ok: false,
|
|
2721
|
+
status: 400,
|
|
2722
|
+
message: picked.error
|
|
2723
|
+
};
|
|
2724
|
+
const ip = clientIp2(req);
|
|
2725
|
+
if (picked.provider === "turnstile") {
|
|
2726
|
+
const ok = await verifyTurnstile(picked.secret, token, ip);
|
|
2727
|
+
if (!ok) return {
|
|
2728
|
+
ok: false,
|
|
2729
|
+
status: 400,
|
|
2730
|
+
message: "Captcha verification failed"
|
|
2731
|
+
};
|
|
2732
|
+
return {
|
|
2733
|
+
ok: true
|
|
2734
|
+
};
|
|
2735
|
+
}
|
|
2736
|
+
const vr = await verifyRecaptcha(picked.secret, token, ip, r.minScore);
|
|
2737
|
+
if (!vr.ok) return {
|
|
2738
|
+
ok: false,
|
|
2739
|
+
status: 400,
|
|
2740
|
+
message: "Captcha verification failed or score too low"
|
|
2741
|
+
};
|
|
2742
|
+
return {
|
|
2743
|
+
ok: true
|
|
2744
|
+
};
|
|
2745
|
+
}
|
|
2746
|
+
};
|
|
2747
|
+
|
|
2748
|
+
// src/plugins/captcha/captcha-plugin.ts
|
|
2749
|
+
function captchaPlugin() {
|
|
2750
|
+
return {
|
|
2751
|
+
name: "captcha",
|
|
2752
|
+
version: "1.0.0",
|
|
2753
|
+
async init(ctx) {
|
|
2754
|
+
const s = new CaptchaService(ctx.config);
|
|
2755
|
+
return s.isEnforced() ? s : void 0;
|
|
2756
|
+
}
|
|
2757
|
+
};
|
|
2758
|
+
}
|
|
2759
|
+
__name(captchaPlugin, "captchaPlugin");
|
|
2760
|
+
|
|
2761
|
+
// src/plugins/blog-generator/index.ts
|
|
2762
|
+
function blogGeneratorPlugin(config = {}) {
|
|
2763
|
+
return {
|
|
2764
|
+
name: "blog_generator",
|
|
2765
|
+
version: "1.0.0",
|
|
2766
|
+
async init(context) {
|
|
2767
|
+
if (config.enabled === false) {
|
|
2768
|
+
context.logger.warn("Blog Generator plugin skipped: disabled in config");
|
|
2769
|
+
return void 0;
|
|
2770
|
+
}
|
|
2771
|
+
return new BlogGeneratorService();
|
|
2772
|
+
}
|
|
2773
|
+
};
|
|
2774
|
+
}
|
|
2775
|
+
__name(blogGeneratorPlugin, "blogGeneratorPlugin");
|
|
2776
|
+
|
|
2777
|
+
// src/plugins/social-media/index.ts
|
|
2778
|
+
function socialMediaPlugin(config = {}) {
|
|
2779
|
+
return {
|
|
2780
|
+
name: "social_media",
|
|
2781
|
+
version: "1.0.0",
|
|
2782
|
+
async init(context) {
|
|
2783
|
+
if (config.enabled === false) {
|
|
2784
|
+
context.logger.warn("Social media plugin skipped: disabled in config");
|
|
2785
|
+
return void 0;
|
|
2786
|
+
}
|
|
2787
|
+
return {
|
|
2788
|
+
name: "social_media"
|
|
2789
|
+
};
|
|
2790
|
+
}
|
|
2791
|
+
};
|
|
2792
|
+
}
|
|
2793
|
+
__name(socialMediaPlugin, "socialMediaPlugin");
|
|
2794
|
+
|
|
3134
2795
|
// src/admin/config.ts
|
|
3135
2796
|
var DEFAULT_ADMIN_NAV = [
|
|
3136
2797
|
{
|
|
@@ -3172,6 +2833,6 @@ var DEFAULT_ADMIN_NAV = [
|
|
|
3172
2833
|
];
|
|
3173
2834
|
|
|
3174
2835
|
// src/index.ts
|
|
3175
|
-
console.log("\u{1F525}
|
|
2836
|
+
console.log("\u{1F525}USING LOCAL CMS CORE \u{1F525}");
|
|
3176
2837
|
|
|
3177
|
-
export { CaptchaService, DEFAULT_ADMIN_NAV, ERPSubmissionService, LlmService, allowRateLimit, analyticsPlugin, blogGeneratorPlugin, buildCaptchaPublicConfig, cachePlugin, captchaPlugin, cn,
|
|
2838
|
+
export { CaptchaService, DEFAULT_ADMIN_NAV, DEFAULT_ORDER_NOTIFICATION_TRIGGER_SEEDS, ERPSubmissionService, LlmService, ORDER_NOTIFICATION_TRIGGERS, allowRateLimit, analyticsPlugin, blogGeneratorPlugin, buildCaptchaPublicConfig, cachePlugin, captchaPlugin, cn, createDataSourceManager, enrichUserWithVendorContext, erpPlugin, fetchSeoBySlug, formatDate, formatDateOnly, formatDateTime, generateSlug, llmPlugin, loadPublicThemeSettings, localStoragePlugin, mergeSeoBySlug, parseHfInferenceEmbeddingBody, paymentPlugin, pgBossPlugin, rateLimitCheckoutPost, rateLimitKeyForApiRequest, rateLimitPublicApiIfNeeded, resolvePublicMetadata, s3StoragePlugin, seedDefaultAdmin, sendOrderPlacedEmailsAfterConfirmation, shouldRateLimitPublicWrite, smsPlugin, socialMediaPlugin, truncateText, validateSlug, withAdminRlsContext, withVendorRlsContext };
|