@infuro/cms-core 1.0.60 → 1.0.62
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 +4179 -2665
- package/dist/admin.js +2990 -1476
- package/dist/api.cjs +41 -37
- package/dist/api.js +9 -5
- package/dist/{chunk-URN7GS23.js → chunk-6LV36PCL.js} +199 -1059
- package/dist/{chunk-O2642WVS.js → chunk-6XAVZE4I.js} +17 -3
- package/dist/{chunk-BXYZDMTZ.cjs → chunk-AXMP2U43.cjs} +3 -94
- package/dist/{chunk-T3HPSF7K.js → chunk-AYWDQFJZ.js} +3 -0
- package/dist/chunk-CTIEAHQL.cjs +96 -0
- package/dist/chunk-GWDI752Q.js +83 -0
- package/dist/chunk-GZGFNVTK.js +886 -0
- package/dist/chunk-H3IVLIPR.cjs +86 -0
- package/dist/{chunk-2KUCQVAQ.js → chunk-HMLVPIJR.js} +2 -91
- package/dist/{chunk-V25RDUOU.cjs → chunk-LRD4CGOG.cjs} +38 -4
- package/dist/{chunk-73WVHINE.cjs → chunk-LVQSG25Y.cjs} +18 -4
- package/dist/chunk-NMYGQWHV.js +93 -0
- package/dist/chunk-OVTOP42W.js +199 -0
- package/dist/{chunk-BSLNXKV2.cjs → chunk-QA5C477U.cjs} +927 -351
- package/dist/{chunk-JAEUYYGA.js → chunk-R6Q67HAS.js} +876 -291
- package/dist/{chunk-YSYX4GUD.cjs → chunk-TWTISTZB.cjs} +210 -1080
- package/dist/{chunk-77I3KS7V.cjs → chunk-UEE4PTTB.cjs} +3 -0
- package/dist/chunk-WFMVD567.cjs +209 -0
- package/dist/{chunk-L3525VXI.js → chunk-YW7EF7K7.js} +36 -2
- package/dist/chunk-ZPAPCGCR.cjs +899 -0
- package/dist/{email-queue-OI2HSCGE.js → email-queue-65PQAG4C.js} +3 -2
- package/dist/{email-queue-6NJY6HNM.cjs → email-queue-J7DXYNCE.cjs} +7 -6
- package/dist/email-service-F7HA4X63.js +3 -0
- package/dist/email-service-RDOTY3CO.cjs +28 -0
- package/dist/{emit-order-notification-trigger-TNEZOYEE.cjs → emit-order-notification-trigger-K7URAZHJ.cjs} +4 -4
- package/dist/{emit-order-notification-trigger-CZU3V2WE.js → emit-order-notification-trigger-MD7EBODC.js} +2 -2
- package/dist/{erp-order-invoice-EYYNR526.cjs → erp-order-invoice-C5GZCOBM.cjs} +6 -5
- package/dist/{erp-order-invoice-3GXDE443.js → erp-order-invoice-MYFCXOCY.js} +2 -1
- package/dist/index.cjs +638 -346
- package/dist/index.d.cts +53 -19
- package/dist/index.d.ts +53 -19
- package/dist/index.js +350 -58
- package/dist/migrations/1783000000000-AddOrderPendingProcessingCompletedTriggers.ts +56 -0
- package/dist/migrations/1783100000000-AddSmsToOrderNotificationBindingsChannelEnum.ts +17 -0
- package/dist/migrations/1783200000000-AddOrderAssigneeColumns.ts +30 -0
- package/dist/order-assignees-handlers-LKMAGLG6.js +150 -0
- package/dist/order-assignees-handlers-NPKD64P6.cjs +152 -0
- package/dist/order-completion-otp-handlers-3NTOGEA5.js +361 -0
- package/dist/order-completion-otp-handlers-4EOLYLAP.cjs +363 -0
- package/dist/order-notification-dispatcher-IYMOS4VY.js +10 -0
- package/dist/order-notification-dispatcher-X2XM5VUY.cjs +35 -0
- package/dist/sms-notification-templates-handlers-SJLO7JGZ.js +47 -0
- package/dist/sms-notification-templates-handlers-YSB3L2PK.cjs +49 -0
- package/package.json +1 -1
- package/dist/order-notification-dispatcher-KJVGLK5E.cjs +0 -24
- package/dist/order-notification-dispatcher-ZSFKEYMP.js +0 -7
package/dist/index.js
CHANGED
|
@@ -1,18 +1,22 @@
|
|
|
1
|
-
export { emitOrderNotificationTrigger, fireOrderNotificationTrigger } from './chunk-
|
|
2
|
-
import { checkMultiVendorEnabled, loadUserVendorContext, getPublicSettingsGroup, BlogGeneratorService } from './chunk-
|
|
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, LlmAgentKnowledgeDocument, 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, UserDeviceToken, UserGroup, Vendor, VendorCustomer, VendorRole, VendorRolePermission, VendorUser, VendorUserProfile, Wishlist, WishlistItem, ZIP_MIME_TYPES, applyApprovalStatusSideEffects, applyEventApprovalStatusSideEffects, applyRotatingVendorInvite, applyVendorCustomersContactFilter, applyVendorEventCreateApproval, applyVendorProductCreateApproval, assertCaptchaOk, assertContactAllowedForVendorOrder, assertEventApprovalUpdate, assertProductApprovalUpdate, autoExpireOrderIfPaymentTimeExceeded, buildBlogMetadataUserPrompt, buildCronFromSchedule, buildRssUserPromptFromFeeds, buildUserInviteLink, buildVendorInviteLink, calculateOrderRefundPreview, calculateRefundFromPolicy, checkAndIncrementDiscountUsage, checkEventsEnabled, checkMultiVendorEnabled, completeUserInviteAccept, consumeAppliedDiscountUsages, contactIsVendorCustomer, countDiscountOrdersForContact,
|
|
1
|
+
export { emitOrderNotificationTrigger, fireOrderNotificationTrigger } from './chunk-6XAVZE4I.js';
|
|
2
|
+
import { checkMultiVendorEnabled, loadUserVendorContext, getPublicSettingsGroup, BlogGeneratorService } from './chunk-R6Q67HAS.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, LlmAgentKnowledgeDocument, 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, UserDeviceToken, UserGroup, Vendor, VendorCustomer, VendorRole, VendorRolePermission, VendorUser, VendorUserProfile, Wishlist, WishlistItem, ZIP_MIME_TYPES, applyApprovalStatusSideEffects, applyEventApprovalStatusSideEffects, applyRotatingVendorInvite, applyVendorCustomersContactFilter, applyVendorEventCreateApproval, applyVendorProductCreateApproval, assertCaptchaOk, assertContactAllowedForVendorOrder, assertEventApprovalUpdate, assertProductApprovalUpdate, autoExpireOrderIfPaymentTimeExceeded, buildBlogMetadataUserPrompt, buildCronFromSchedule, buildRssUserPromptFromFeeds, buildUserInviteLink, buildVendorInviteLink, calculateOrderRefundPreview, calculateRefundFromPolicy, checkAndIncrementDiscountUsage, checkEventsEnabled, checkMultiVendorEnabled, completeUserInviteAccept, consumeAppliedDiscountUsages, contactIsVendorCustomer, countDiscountOrdersForContact, createAnalyticsHandlers, createBlogBySlugHandler, createChangePasswordHandler, createCmsApiHandler, createCmsApp, createCmsAppWithMessaging, createCrudByIdHandler, createCrudHandler, createDashboardStatsHandler, createEcommerceAnalyticsHandler, createEventOrderMessageTemplateHandlers, createForgotPasswordHandler, createFormBySlugHandler, createInviteAcceptHandler, createJobScheduleHandlers, createLlmAgentKnowledgeHandlers, createMediaZipExtractHandler, createMessageTemplateRowLoader, createSetPasswordHandler, createSettingsApiHandlers, createSocialMediaHandlers, createStorefrontApiHandler, createUploadHandler, createUserAuthApiRouter, createUserAvatarHandler, createUserProfileHandler, createUsersApiHandlers, createVendorDashboardHandler, createVendorOnboardHandlers, daysBeforeEventStart, decrementDiscountUsage, describeEventTierPolicy, ensureMessagingPluginsOnCms, ensureScheduleQueueWorker, ensureVendorCustomerForOrderContact, ensureVendorCustomersForOrder, findActiveRefundPolicyForVendor, findUserByInviteToken, findVendorByInviteToken, formatTierRange, getPublicSettingsGroup, getRequireEventApproval, getRequireProductApproval, getRssArticleSummaryFromItem, getVendorCatalogCreateFlags, hydrateVendorSessionUser, invalidateEventsCache, invalidateMultiVendorCache, invalidateRequireEventApprovalCache, invalidateRequireProductApprovalCache, invalidateVendorCatalogCreateFlagsCache, isCustomerTypeContact, isMaxPerUserUsageReached, isMaxTotalUsageReached, isZipMedia, llmAgentToChatAgentOptions, loadSettingsGroupFromDb, loadUserVendorContext, mergeGuardrailsIntoSystemPrompt, messagingPlugins, metaFetchUserManagedPages, metaPostPageFeed, metaPostPagePhoto, metaResolvePageAccessToken, newUserInviteToken, normalizeRefundTiers, overlayCmsPlugins, parseBlogGeneratorAgentContent, parseBlogGeneratorModelOutput, parseBlogMetadataEnrichmentJson, parseLlmAgentValidationRules, pgBossScheduleNameForId, queueErpCreateContactIfEnabled, queueJobScheduleNow, queuePlugin, recordDiscountUsage, registerJobRunnerWorker, registerMessagingQueueProcessors, relativePathFromMediaParentId, resolveBlogCategoryIdByName, resolveSettingsEncryptionKey, resolveVendorIdForContactCheck, sanitizeMediaFolderPath, sanitizeStorageSegment, sendVendorOnboardEmails, simpleDecrypt, simpleEncrypt, syncJobScheduleToPgBoss, validateRefundTiers, validateScheduleInput, validateUserMessageAgainstAgentRules, validateUserMessageAgainstStructuredRules, whatsappPlugin, wrapGetCmsWithMessaging } from './chunk-R6Q67HAS.js';
|
|
4
|
+
export { countRecentOtpSends, createOtpChallenge, generateNumericOtp, hashOtpCode, normalizePhoneE164, queueSms, registerSmsQueueProcessor, verifyAndConsumeOtpChallenge, verifyOtpCodeHash } from './chunk-OVTOP42W.js';
|
|
4
5
|
import { PgBossService } from './chunk-GO7PPYNU.js';
|
|
5
6
|
export { JOB_RUNNER_QUEUE, PgBossService } from './chunk-GO7PPYNU.js';
|
|
6
7
|
export { deductInventoryForConfirmedOrder, mergeInventoryLines, orderInventorySnapshotFromRow, orderStatusHoldsStock, reconcileOrderInventoryBetweenSnapshots, restoreInventoryForCancelledOrder, validateInventoryForConfirmedOrderLines, validateInventoryForOrderBecomingConfirmed } from './chunk-3K5AIEIZ.js';
|
|
7
|
-
import { parseEmailRecipientsFromConfig } from './chunk-
|
|
8
|
-
export {
|
|
9
|
-
export {
|
|
8
|
+
import { parseEmailRecipientsFromConfig } from './chunk-6LV36PCL.js';
|
|
9
|
+
export { buildEventOrderTemplateVariables, emailPlugin, initWhatsappTriggerDispatcher, joinRecipientsForSend, parseEmailRecipientsFromConfig, resendOrderNotification, serializeEmailRecipients } from './chunk-6LV36PCL.js';
|
|
10
|
+
export { queueWhatsApp, registerWhatsAppQueueProcessor } from './chunk-GWDI752Q.js';
|
|
11
|
+
export { KNOWN_NOTIFICATION_TRIGGERS, notificationTriggerEmitter } from './chunk-AYWDQFJZ.js';
|
|
10
12
|
import './chunk-JXF23MPG.js';
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
export { INVOICE_TEMPLATE_IDS, INVOICE_TEMPLATE_OPTIONS, buildLocalInvoicePdfForOrder, generateLocalInvoicePdf,
|
|
13
|
+
export { EmailService, emailTemplates, renderEmail, renderLayout } from './chunk-GZGFNVTK.js';
|
|
14
|
+
import { queueOrderPlacedEmails } from './chunk-YW7EF7K7.js';
|
|
15
|
+
export { queueEmail, queueOrderPlacedEmails, queueVendorOnboardEmails, registerEmailQueueProcessor } from './chunk-YW7EF7K7.js';
|
|
16
|
+
export { INVOICE_TEMPLATE_IDS, INVOICE_TEMPLATE_OPTIONS, buildLocalInvoicePdfForOrder, generateLocalInvoicePdf, isOrderEligibleForInvoiceEmail, normalizeInvoiceTemplateId, resolveInvoiceAssetUrl, resolveOrderInvoicePdfBytes, streamOrderInvoicePdf } from './chunk-HMLVPIJR.js';
|
|
15
17
|
import './chunk-JC6DLWTE.js';
|
|
18
|
+
import { mergeEmailLayoutCompanyDetails } from './chunk-NMYGQWHV.js';
|
|
19
|
+
export { getCompanyDetailsFromSettings, mergeEmailLayoutCompanyDetails } from './chunk-NMYGQWHV.js';
|
|
16
20
|
import './chunk-MQBT33IV.js';
|
|
17
21
|
import './chunk-CRFV5WJK.js';
|
|
18
22
|
export { EVENT_ORDER_MESSAGE_TEMPLATE_DEFAULTS, EVENT_ORDER_TEMPLATE_KEY, EVENT_ORDER_TEMPLATE_VARIABLES, resolveEventOrderTemplate } from './chunk-AYERBA7I.js';
|
|
@@ -774,10 +778,6 @@ function resolveSmsProvider(cfg) {
|
|
|
774
778
|
return null;
|
|
775
779
|
}
|
|
776
780
|
__name(resolveSmsProvider, "resolveSmsProvider");
|
|
777
|
-
function anySmsProviderConfigured(cfg) {
|
|
778
|
-
return resolveSmsProvider(cfg) !== null;
|
|
779
|
-
}
|
|
780
|
-
__name(anySmsProviderConfigured, "anySmsProviderConfigured");
|
|
781
781
|
var MSG91_FLOW_URL = "https://control.msg91.com/api/v5/flow/";
|
|
782
782
|
async function sendViaMsg91Flow(cfg, to, body, opts, overrides) {
|
|
783
783
|
const authkey = cfg.msg91AuthKey;
|
|
@@ -987,17 +987,33 @@ function smsPlugin(config = {}) {
|
|
|
987
987
|
async init(context) {
|
|
988
988
|
const env = context.config;
|
|
989
989
|
const { getSmsSettings, getMessageTemplateRow, ...staticRest } = config;
|
|
990
|
+
let settingsLoader = getSmsSettings;
|
|
991
|
+
if (!settingsLoader && context.dataSource) {
|
|
992
|
+
settingsLoader = /* @__PURE__ */ __name(async () => {
|
|
993
|
+
try {
|
|
994
|
+
const ds = context.dataSource;
|
|
995
|
+
const repo = ds.getRepository("configs");
|
|
996
|
+
const rows = await repo.find({
|
|
997
|
+
where: {
|
|
998
|
+
settings: "sms",
|
|
999
|
+
deleted: false
|
|
1000
|
+
}
|
|
1001
|
+
});
|
|
1002
|
+
return Object.fromEntries(rows.map((r) => [
|
|
1003
|
+
r.key,
|
|
1004
|
+
r.value
|
|
1005
|
+
]));
|
|
1006
|
+
} catch {
|
|
1007
|
+
return {};
|
|
1008
|
+
}
|
|
1009
|
+
}, "settingsLoader");
|
|
1010
|
+
}
|
|
990
1011
|
let db = {};
|
|
991
1012
|
try {
|
|
992
|
-
db = await
|
|
1013
|
+
db = await settingsLoader?.() ?? {};
|
|
993
1014
|
} catch {
|
|
994
1015
|
}
|
|
995
|
-
const
|
|
996
|
-
if (!anySmsProviderConfigured(merged)) {
|
|
997
|
-
context.logger.warn("SMS plugin skipped: set MSG91_AUTH_KEY (Flow template id per Plugins \u2192 SMS templates or MSG91_TEMPLATE_ID; or sendhttp: MSG91_SENDER_ID), or TWILIO_*, or SMS_WEBHOOK_URL");
|
|
998
|
-
return null;
|
|
999
|
-
}
|
|
1000
|
-
const svc = new SmsService(env, staticRest, getSmsSettings, getMessageTemplateRow);
|
|
1016
|
+
const svc = new SmsService(env, staticRest, settingsLoader, getMessageTemplateRow);
|
|
1001
1017
|
return {
|
|
1002
1018
|
send: /* @__PURE__ */ __name((opts) => svc.send(opts), "send")
|
|
1003
1019
|
};
|
|
@@ -1050,37 +1066,91 @@ var LOG = "[s3]";
|
|
|
1050
1066
|
function serializeS3Error(err) {
|
|
1051
1067
|
if (!err || typeof err !== "object") {
|
|
1052
1068
|
return {
|
|
1053
|
-
error: String(err)
|
|
1069
|
+
error: String(err),
|
|
1070
|
+
errorType: typeof err
|
|
1054
1071
|
};
|
|
1055
1072
|
}
|
|
1056
1073
|
const e = err;
|
|
1057
|
-
|
|
1074
|
+
const out = {
|
|
1058
1075
|
name: e.name,
|
|
1059
1076
|
message: e.message,
|
|
1060
1077
|
code: e.Code ?? e.code,
|
|
1078
|
+
fault: e.$fault,
|
|
1061
1079
|
httpStatus: e.$metadata?.httpStatusCode,
|
|
1062
1080
|
requestId: e.$metadata?.requestId,
|
|
1063
1081
|
extendedRequestId: e.$metadata?.extendedRequestId,
|
|
1064
|
-
cfId: e.$metadata?.cfId
|
|
1082
|
+
cfId: e.$metadata?.cfId,
|
|
1083
|
+
attempts: e.$metadata?.attempts,
|
|
1084
|
+
totalRetryDelay: e.$metadata?.totalRetryDelay,
|
|
1085
|
+
stack: e.stack
|
|
1065
1086
|
};
|
|
1087
|
+
if (e.cause != null) {
|
|
1088
|
+
out.cause = serializeS3Error(e.cause);
|
|
1089
|
+
}
|
|
1090
|
+
try {
|
|
1091
|
+
const extras = {};
|
|
1092
|
+
for (const k of Object.keys(e)) {
|
|
1093
|
+
if (k === "name" || k === "message" || k === "Code" || k === "code" || k === "$fault" || k === "$metadata" || k === "stack" || k === "cause") {
|
|
1094
|
+
continue;
|
|
1095
|
+
}
|
|
1096
|
+
const v = e[k];
|
|
1097
|
+
if (typeof v === "string" || typeof v === "number" || typeof v === "boolean" || v == null) {
|
|
1098
|
+
extras[k] = v;
|
|
1099
|
+
} else {
|
|
1100
|
+
extras[k] = String(v);
|
|
1101
|
+
}
|
|
1102
|
+
}
|
|
1103
|
+
if (Object.keys(extras).length > 0) out.extras = extras;
|
|
1104
|
+
} catch {
|
|
1105
|
+
}
|
|
1106
|
+
return out;
|
|
1066
1107
|
}
|
|
1067
1108
|
__name(serializeS3Error, "serializeS3Error");
|
|
1068
1109
|
function publicObjectUrl(config, fullKey) {
|
|
1110
|
+
console.info(LOG, "build public URL", {
|
|
1111
|
+
fullKey,
|
|
1112
|
+
hasBaseUrl: Boolean(config.baseUrl),
|
|
1113
|
+
baseUrl: config.baseUrl ?? null,
|
|
1114
|
+
bucket: config.bucket,
|
|
1115
|
+
region: config.region
|
|
1116
|
+
});
|
|
1069
1117
|
if (config.baseUrl) {
|
|
1070
|
-
|
|
1118
|
+
const url2 = `${config.baseUrl.replace(/\/$/, "")}/${fullKey}`;
|
|
1119
|
+
console.info(LOG, "public URL from baseUrl", {
|
|
1120
|
+
fullKey,
|
|
1121
|
+
url: url2
|
|
1122
|
+
});
|
|
1123
|
+
return url2;
|
|
1071
1124
|
}
|
|
1072
|
-
|
|
1125
|
+
const url = `https://s3.${config.region}.amazonaws.com/${config.bucket}/${fullKey}`;
|
|
1126
|
+
console.info(LOG, "public URL from default S3 endpoint", {
|
|
1127
|
+
fullKey,
|
|
1128
|
+
url
|
|
1129
|
+
});
|
|
1130
|
+
return url;
|
|
1073
1131
|
}
|
|
1074
1132
|
__name(publicObjectUrl, "publicObjectUrl");
|
|
1075
1133
|
function describeS3Config(config) {
|
|
1076
|
-
|
|
1134
|
+
let baseUrlHost = null;
|
|
1135
|
+
try {
|
|
1136
|
+
baseUrlHost = config.baseUrl ? new URL(config.baseUrl).host : null;
|
|
1137
|
+
} catch (err) {
|
|
1138
|
+
console.error(LOG, "invalid baseUrl while describing config", {
|
|
1139
|
+
baseUrl: config.baseUrl,
|
|
1140
|
+
...serializeS3Error(err)
|
|
1141
|
+
});
|
|
1142
|
+
baseUrlHost = config.baseUrl ?? null;
|
|
1143
|
+
}
|
|
1077
1144
|
return {
|
|
1078
1145
|
bucket: config.bucket,
|
|
1079
1146
|
region: config.region,
|
|
1080
1147
|
prefix: config.prefix ?? "uploads",
|
|
1081
1148
|
hasBaseUrl: Boolean(config.baseUrl),
|
|
1082
|
-
|
|
1083
|
-
|
|
1149
|
+
baseUrl: config.baseUrl ?? null,
|
|
1150
|
+
baseUrlHost,
|
|
1151
|
+
accessKeyIdLast4: config.accessKeyId ? config.accessKeyId.slice(-4) : null,
|
|
1152
|
+
accessKeyIdLength: config.accessKeyId?.length ?? 0,
|
|
1153
|
+
secretAccessKeyLength: config.secretAccessKey?.length ?? 0,
|
|
1084
1154
|
envSummary: {
|
|
1085
1155
|
AWS_BUCKET_NAME: Boolean(config.bucket),
|
|
1086
1156
|
AWS_REGION: Boolean(config.region),
|
|
@@ -1091,7 +1161,11 @@ function describeS3Config(config) {
|
|
|
1091
1161
|
};
|
|
1092
1162
|
}
|
|
1093
1163
|
__name(describeS3Config, "describeS3Config");
|
|
1094
|
-
async function probePublicUrl(url) {
|
|
1164
|
+
async function probePublicUrl(url, fullKey) {
|
|
1165
|
+
console.info(LOG, "probe public URL start", {
|
|
1166
|
+
url,
|
|
1167
|
+
fullKey
|
|
1168
|
+
});
|
|
1095
1169
|
try {
|
|
1096
1170
|
const head = await fetch(url, {
|
|
1097
1171
|
method: "HEAD",
|
|
@@ -1099,15 +1173,25 @@ async function probePublicUrl(url) {
|
|
|
1099
1173
|
});
|
|
1100
1174
|
const headInfo = {
|
|
1101
1175
|
url,
|
|
1176
|
+
fullKey,
|
|
1102
1177
|
status: head.status,
|
|
1103
1178
|
ok: head.ok,
|
|
1104
1179
|
contentType: head.headers.get("content-type"),
|
|
1105
|
-
|
|
1180
|
+
contentLength: head.headers.get("content-length"),
|
|
1181
|
+
location: head.headers.get("location"),
|
|
1182
|
+
cacheControl: head.headers.get("cache-control"),
|
|
1183
|
+
etag: head.headers.get("etag")
|
|
1106
1184
|
};
|
|
1185
|
+
console.info(LOG, "probe HEAD result", headInfo);
|
|
1107
1186
|
if (head.ok) {
|
|
1108
1187
|
console.info(LOG, "public URL reachable (HEAD)", headInfo);
|
|
1109
1188
|
return;
|
|
1110
1189
|
}
|
|
1190
|
+
console.warn(LOG, "probe HEAD not ok \u2014 trying ranged GET", {
|
|
1191
|
+
url,
|
|
1192
|
+
fullKey,
|
|
1193
|
+
status: head.status
|
|
1194
|
+
});
|
|
1111
1195
|
const getRes = await fetch(url, {
|
|
1112
1196
|
method: "GET",
|
|
1113
1197
|
headers: {
|
|
@@ -1118,19 +1202,26 @@ async function probePublicUrl(url) {
|
|
|
1118
1202
|
let bodySnippet = "";
|
|
1119
1203
|
try {
|
|
1120
1204
|
bodySnippet = (await getRes.text()).slice(0, 400);
|
|
1121
|
-
} catch {
|
|
1205
|
+
} catch (bodyErr) {
|
|
1206
|
+
console.error(LOG, "probe GET body read failed", {
|
|
1207
|
+
url,
|
|
1208
|
+
fullKey,
|
|
1209
|
+
...serializeS3Error(bodyErr)
|
|
1210
|
+
});
|
|
1122
1211
|
}
|
|
1123
1212
|
console.error(LOG, "public URL not readable \u2014 admin images will not display", {
|
|
1124
1213
|
...headInfo,
|
|
1125
1214
|
getStatus: getRes.status,
|
|
1126
1215
|
getOk: getRes.ok,
|
|
1127
1216
|
getContentType: getRes.headers.get("content-type"),
|
|
1217
|
+
getContentLength: getRes.headers.get("content-length"),
|
|
1128
1218
|
bodySnippet
|
|
1129
1219
|
});
|
|
1130
1220
|
} catch (err) {
|
|
1131
1221
|
console.error(LOG, "public URL probe failed", {
|
|
1132
1222
|
url,
|
|
1133
|
-
|
|
1223
|
+
fullKey,
|
|
1224
|
+
...serializeS3Error(err)
|
|
1134
1225
|
});
|
|
1135
1226
|
}
|
|
1136
1227
|
}
|
|
@@ -1138,9 +1229,69 @@ __name(probePublicUrl, "probePublicUrl");
|
|
|
1138
1229
|
function getS3Storage(config) {
|
|
1139
1230
|
const prefix = (config.prefix ?? "uploads").replace(/\/$/, "");
|
|
1140
1231
|
const keyPrefix = prefix ? `${prefix}/` : "";
|
|
1232
|
+
console.info(LOG, "storage service created", {
|
|
1233
|
+
...describeS3Config(config),
|
|
1234
|
+
keyPrefix,
|
|
1235
|
+
resolvedPrefix: prefix
|
|
1236
|
+
});
|
|
1141
1237
|
return {
|
|
1142
1238
|
async upload(buffer, key, contentType) {
|
|
1143
|
-
const
|
|
1239
|
+
const uploadId = `upl-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
1240
|
+
const started = Date.now();
|
|
1241
|
+
console.info(LOG, "upload() called", {
|
|
1242
|
+
uploadId,
|
|
1243
|
+
incomingKey: key,
|
|
1244
|
+
contentType,
|
|
1245
|
+
bytes: buffer?.length ?? null,
|
|
1246
|
+
isBuffer: Buffer.isBuffer(buffer),
|
|
1247
|
+
...describeS3Config(config)
|
|
1248
|
+
});
|
|
1249
|
+
if (!buffer || !Buffer.isBuffer(buffer)) {
|
|
1250
|
+
console.error(LOG, "upload aborted \u2014 invalid buffer", {
|
|
1251
|
+
uploadId,
|
|
1252
|
+
incomingKey: key,
|
|
1253
|
+
bufferType: typeof buffer,
|
|
1254
|
+
isBuffer: Buffer.isBuffer(buffer)
|
|
1255
|
+
});
|
|
1256
|
+
throw new Error("S3 upload: invalid buffer");
|
|
1257
|
+
}
|
|
1258
|
+
if (!key || typeof key !== "string") {
|
|
1259
|
+
console.error(LOG, "upload aborted \u2014 invalid key", {
|
|
1260
|
+
uploadId,
|
|
1261
|
+
key,
|
|
1262
|
+
keyType: typeof key
|
|
1263
|
+
});
|
|
1264
|
+
throw new Error("S3 upload: invalid key");
|
|
1265
|
+
}
|
|
1266
|
+
console.info(LOG, "importing @aws-sdk/client-s3", {
|
|
1267
|
+
uploadId,
|
|
1268
|
+
key
|
|
1269
|
+
});
|
|
1270
|
+
let S3Client;
|
|
1271
|
+
let PutObjectCommand;
|
|
1272
|
+
let HeadObjectCommand;
|
|
1273
|
+
try {
|
|
1274
|
+
const sdk = await import('@aws-sdk/client-s3');
|
|
1275
|
+
S3Client = sdk.S3Client;
|
|
1276
|
+
PutObjectCommand = sdk.PutObjectCommand;
|
|
1277
|
+
HeadObjectCommand = sdk.HeadObjectCommand;
|
|
1278
|
+
console.info(LOG, "AWS SDK import ok", {
|
|
1279
|
+
uploadId,
|
|
1280
|
+
key
|
|
1281
|
+
});
|
|
1282
|
+
} catch (err) {
|
|
1283
|
+
console.error(LOG, "AWS SDK import failed", {
|
|
1284
|
+
uploadId,
|
|
1285
|
+
key,
|
|
1286
|
+
...serializeS3Error(err)
|
|
1287
|
+
});
|
|
1288
|
+
throw err;
|
|
1289
|
+
}
|
|
1290
|
+
console.info(LOG, "creating S3Client", {
|
|
1291
|
+
uploadId,
|
|
1292
|
+
region: config.region,
|
|
1293
|
+
accessKeyIdLast4: config.accessKeyId.slice(-4)
|
|
1294
|
+
});
|
|
1144
1295
|
const client = new S3Client({
|
|
1145
1296
|
region: config.region,
|
|
1146
1297
|
credentials: {
|
|
@@ -1151,47 +1302,114 @@ function getS3Storage(config) {
|
|
|
1151
1302
|
const rawKey = key.replace(/^\/+/, "");
|
|
1152
1303
|
const fullKey = keyPrefix + rawKey;
|
|
1153
1304
|
const publicUrl = publicObjectUrl(config, fullKey);
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1305
|
+
console.info(LOG, "resolved S3 object key", {
|
|
1306
|
+
uploadId,
|
|
1307
|
+
incomingKey: key,
|
|
1308
|
+
rawKey,
|
|
1309
|
+
keyPrefix,
|
|
1158
1310
|
fullKey,
|
|
1311
|
+
bucket: config.bucket,
|
|
1312
|
+
region: config.region,
|
|
1159
1313
|
publicUrl,
|
|
1160
1314
|
contentType,
|
|
1161
|
-
bytes: buffer.length
|
|
1315
|
+
bytes: buffer.length,
|
|
1316
|
+
note: "PutObject will use Bucket + Key (= fullKey)"
|
|
1162
1317
|
});
|
|
1318
|
+
const putInput = {
|
|
1319
|
+
Bucket: config.bucket,
|
|
1320
|
+
Key: fullKey,
|
|
1321
|
+
Body: buffer,
|
|
1322
|
+
ContentType: contentType
|
|
1323
|
+
};
|
|
1324
|
+
console.info(LOG, "PutObjectCommand prepared", {
|
|
1325
|
+
uploadId,
|
|
1326
|
+
Bucket: putInput.Bucket,
|
|
1327
|
+
Key: putInput.Key,
|
|
1328
|
+
ContentType: putInput.ContentType,
|
|
1329
|
+
BodyBytes: buffer.length,
|
|
1330
|
+
BodyIsBuffer: Buffer.isBuffer(putInput.Body)
|
|
1331
|
+
});
|
|
1332
|
+
let putResult;
|
|
1163
1333
|
try {
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
})
|
|
1334
|
+
console.info(LOG, "PutObject send start", {
|
|
1335
|
+
uploadId,
|
|
1336
|
+
bucket: config.bucket,
|
|
1337
|
+
fullKey,
|
|
1338
|
+
msElapsed: Date.now() - started
|
|
1339
|
+
});
|
|
1340
|
+
putResult = await client.send(new PutObjectCommand(putInput));
|
|
1341
|
+
console.info(LOG, "PutObject send returned", {
|
|
1342
|
+
uploadId,
|
|
1343
|
+
bucket: config.bucket,
|
|
1344
|
+
fullKey,
|
|
1345
|
+
ETag: putResult?.ETag,
|
|
1346
|
+
VersionId: putResult?.VersionId,
|
|
1347
|
+
httpStatus: putResult?.$metadata?.httpStatusCode,
|
|
1348
|
+
requestId: putResult?.$metadata?.requestId,
|
|
1349
|
+
ms: Date.now() - started
|
|
1350
|
+
});
|
|
1170
1351
|
} catch (err) {
|
|
1171
|
-
const errorDump = serializeS3Error(err);
|
|
1172
1352
|
console.error(LOG, "PutObject failed", {
|
|
1353
|
+
uploadId,
|
|
1173
1354
|
...describeS3Config(config),
|
|
1174
|
-
|
|
1355
|
+
incomingKey: key,
|
|
1356
|
+
rawKey,
|
|
1357
|
+
keyPrefix,
|
|
1175
1358
|
fullKey,
|
|
1176
1359
|
publicUrl,
|
|
1177
1360
|
contentType,
|
|
1178
1361
|
bytes: buffer.length,
|
|
1179
|
-
|
|
1362
|
+
ms: Date.now() - started,
|
|
1363
|
+
...serializeS3Error(err),
|
|
1180
1364
|
rawError: err instanceof Error ? err.message : String(err)
|
|
1181
1365
|
});
|
|
1182
1366
|
throw err;
|
|
1183
1367
|
}
|
|
1184
|
-
console.info(LOG, "PutObject ok", {
|
|
1368
|
+
console.info(LOG, "PutObject ok \u2014 verifying with HeadObject", {
|
|
1369
|
+
uploadId,
|
|
1370
|
+
bucket: config.bucket,
|
|
1371
|
+
fullKey,
|
|
1372
|
+
publicUrl
|
|
1373
|
+
});
|
|
1374
|
+
try {
|
|
1375
|
+
const head = await client.send(new HeadObjectCommand({
|
|
1376
|
+
Bucket: config.bucket,
|
|
1377
|
+
Key: fullKey
|
|
1378
|
+
}));
|
|
1379
|
+
console.info(LOG, "HeadObject ok \u2014 object exists in bucket", {
|
|
1380
|
+
uploadId,
|
|
1381
|
+
bucket: config.bucket,
|
|
1382
|
+
fullKey,
|
|
1383
|
+
contentType: head.ContentType,
|
|
1384
|
+
contentLength: head.ContentLength,
|
|
1385
|
+
etag: head.ETag,
|
|
1386
|
+
lastModified: head.LastModified?.toISOString?.() ?? head.LastModified,
|
|
1387
|
+
httpStatus: head.$metadata?.httpStatusCode,
|
|
1388
|
+
requestId: head.$metadata?.requestId
|
|
1389
|
+
});
|
|
1390
|
+
} catch (headErr) {
|
|
1391
|
+
console.error(LOG, "HeadObject failed after PutObject \u2014 key may be wrong or ACL/permission issue", {
|
|
1392
|
+
uploadId,
|
|
1393
|
+
bucket: config.bucket,
|
|
1394
|
+
fullKey,
|
|
1395
|
+
publicUrl,
|
|
1396
|
+
...serializeS3Error(headErr)
|
|
1397
|
+
});
|
|
1398
|
+
}
|
|
1399
|
+
console.info(LOG, "upload complete", {
|
|
1400
|
+
uploadId,
|
|
1185
1401
|
...describeS3Config(config),
|
|
1186
|
-
|
|
1402
|
+
incomingKey: key,
|
|
1403
|
+
rawKey,
|
|
1187
1404
|
fullKey,
|
|
1188
1405
|
publicUrl,
|
|
1189
1406
|
contentType,
|
|
1190
1407
|
bytes: buffer.length,
|
|
1191
1408
|
ms: Date.now() - started,
|
|
1409
|
+
ETag: putResult?.ETag,
|
|
1192
1410
|
hasCustomBaseUrl: Boolean(config.baseUrl)
|
|
1193
1411
|
});
|
|
1194
|
-
void probePublicUrl(publicUrl);
|
|
1412
|
+
void probePublicUrl(publicUrl, fullKey);
|
|
1195
1413
|
return publicUrl;
|
|
1196
1414
|
}
|
|
1197
1415
|
};
|
|
@@ -1202,26 +1420,66 @@ function s3StoragePlugin(config) {
|
|
|
1202
1420
|
name: "storage",
|
|
1203
1421
|
version: "1.0.0",
|
|
1204
1422
|
async init(context) {
|
|
1423
|
+
console.info(LOG, "plugin init start", {
|
|
1424
|
+
configKeys: Object.keys(config ?? {}),
|
|
1425
|
+
hasContextConfig: Boolean(context?.config),
|
|
1426
|
+
contextConfigKeys: context?.config ? Object.keys(context.config) : []
|
|
1427
|
+
});
|
|
1205
1428
|
const region = config.region ?? context.config.AWS_REGION ?? "";
|
|
1206
1429
|
const accessKeyId = config.accessKeyId ?? context.config.AWS_ACCESS_KEY_ID ?? "";
|
|
1207
1430
|
const secretAccessKey = config.secretAccessKey ?? context.config.AWS_SECRET_ACCESS_KEY ?? "";
|
|
1208
1431
|
const bucket = config.bucket ?? context.config.AWS_BUCKET_NAME ?? "";
|
|
1209
1432
|
const baseUrl = config.baseUrl ?? context.config.S3_MEDIA_URL ?? context.config.S3_CUSTOM_DOMAIN;
|
|
1433
|
+
console.info(LOG, "plugin init resolved raw values", {
|
|
1434
|
+
region: region || "(empty)",
|
|
1435
|
+
bucket: bucket || "(empty)",
|
|
1436
|
+
prefix: config.prefix ?? "uploads",
|
|
1437
|
+
hasAccessKeyId: Boolean(accessKeyId),
|
|
1438
|
+
accessKeyIdLast4: accessKeyId ? accessKeyId.slice(-4) : null,
|
|
1439
|
+
hasSecretAccessKey: Boolean(secretAccessKey),
|
|
1440
|
+
secretAccessKeyLength: secretAccessKey?.length ?? 0,
|
|
1441
|
+
baseUrlRaw: baseUrl ?? null,
|
|
1442
|
+
fromPluginConfig: {
|
|
1443
|
+
region: Boolean(config.region),
|
|
1444
|
+
accessKeyId: Boolean(config.accessKeyId),
|
|
1445
|
+
secretAccessKey: Boolean(config.secretAccessKey),
|
|
1446
|
+
bucket: Boolean(config.bucket),
|
|
1447
|
+
baseUrl: Boolean(config.baseUrl)
|
|
1448
|
+
},
|
|
1449
|
+
fromContext: {
|
|
1450
|
+
AWS_REGION: Boolean(context.config.AWS_REGION),
|
|
1451
|
+
AWS_ACCESS_KEY_ID: Boolean(context.config.AWS_ACCESS_KEY_ID),
|
|
1452
|
+
AWS_SECRET_ACCESS_KEY: Boolean(context.config.AWS_SECRET_ACCESS_KEY),
|
|
1453
|
+
AWS_BUCKET_NAME: Boolean(context.config.AWS_BUCKET_NAME),
|
|
1454
|
+
S3_MEDIA_URL: Boolean(context.config.S3_MEDIA_URL),
|
|
1455
|
+
S3_CUSTOM_DOMAIN: Boolean(context.config.S3_CUSTOM_DOMAIN)
|
|
1456
|
+
}
|
|
1457
|
+
});
|
|
1210
1458
|
const resolvedBaseUrl = typeof baseUrl === "string" && baseUrl ? baseUrl.startsWith("http") ? baseUrl : `https://${baseUrl}` : void 0;
|
|
1459
|
+
console.info(LOG, "plugin init baseUrl resolution", {
|
|
1460
|
+
baseUrlRaw: baseUrl ?? null,
|
|
1461
|
+
resolvedBaseUrl: resolvedBaseUrl ?? null
|
|
1462
|
+
});
|
|
1211
1463
|
if (!region || !accessKeyId || !secretAccessKey || !bucket) {
|
|
1212
1464
|
console.error(LOG, "plugin init missing config", {
|
|
1213
1465
|
hasRegion: Boolean(region),
|
|
1214
1466
|
hasAccessKeyId: Boolean(accessKeyId),
|
|
1215
1467
|
hasSecretAccessKey: Boolean(secretAccessKey),
|
|
1216
1468
|
hasBucket: Boolean(bucket),
|
|
1217
|
-
hasBaseUrl: Boolean(resolvedBaseUrl)
|
|
1469
|
+
hasBaseUrl: Boolean(resolvedBaseUrl),
|
|
1470
|
+
regionValue: region || null,
|
|
1471
|
+
bucketValue: bucket || null
|
|
1218
1472
|
});
|
|
1219
1473
|
throw new Error("S3 storage plugin: missing region, accessKeyId, secretAccessKey or bucket");
|
|
1220
1474
|
}
|
|
1221
1475
|
let baseUrlHost = null;
|
|
1222
1476
|
try {
|
|
1223
1477
|
baseUrlHost = resolvedBaseUrl ? new URL(resolvedBaseUrl).host : null;
|
|
1224
|
-
} catch {
|
|
1478
|
+
} catch (err) {
|
|
1479
|
+
console.error(LOG, "plugin init invalid resolvedBaseUrl", {
|
|
1480
|
+
resolvedBaseUrl,
|
|
1481
|
+
...serializeS3Error(err)
|
|
1482
|
+
});
|
|
1225
1483
|
baseUrlHost = resolvedBaseUrl ?? null;
|
|
1226
1484
|
}
|
|
1227
1485
|
console.info(LOG, "plugin ready", {
|
|
@@ -1229,6 +1487,7 @@ function s3StoragePlugin(config) {
|
|
|
1229
1487
|
bucket,
|
|
1230
1488
|
prefix: config.prefix ?? "uploads",
|
|
1231
1489
|
hasBaseUrl: Boolean(resolvedBaseUrl),
|
|
1490
|
+
baseUrl: resolvedBaseUrl ?? null,
|
|
1232
1491
|
baseUrlHost,
|
|
1233
1492
|
accessKeyIdLast4: accessKeyId.slice(-4),
|
|
1234
1493
|
envSummary: {
|
|
@@ -2478,45 +2737,78 @@ __name(sendOrderPlacedEmailsAfterConfirmation, "sendOrderPlacedEmailsAfterConfir
|
|
|
2478
2737
|
|
|
2479
2738
|
// src/lib/order-notification-trigger-seeds.ts
|
|
2480
2739
|
var DEFAULT_ORDER_NOTIFICATION_TRIGGER_SEEDS = [
|
|
2740
|
+
{
|
|
2741
|
+
triggerKey: "order_pending",
|
|
2742
|
+
label: "Order pending",
|
|
2743
|
+
description: "Fires when an order is created and pending confirmation or payment.",
|
|
2744
|
+
category: "order",
|
|
2745
|
+
sortOrder: 1
|
|
2746
|
+
},
|
|
2747
|
+
{
|
|
2748
|
+
triggerKey: "order_processing",
|
|
2749
|
+
label: "Order processing",
|
|
2750
|
+
description: "Fires when an order moves to processing after being assigned.",
|
|
2751
|
+
category: "order",
|
|
2752
|
+
sortOrder: 2
|
|
2753
|
+
},
|
|
2754
|
+
{
|
|
2755
|
+
triggerKey: "order_completed",
|
|
2756
|
+
label: "Order completed",
|
|
2757
|
+
description: "Fires when an order is completed after customer OTP validation.",
|
|
2758
|
+
category: "order",
|
|
2759
|
+
sortOrder: 3
|
|
2760
|
+
},
|
|
2481
2761
|
{
|
|
2482
2762
|
triggerKey: "order_placed",
|
|
2483
2763
|
label: "Order placed",
|
|
2484
2764
|
description: "Fires when a new order is created (storefront checkout or admin).",
|
|
2485
2765
|
category: "order",
|
|
2486
|
-
sortOrder:
|
|
2766
|
+
sortOrder: 4
|
|
2487
2767
|
},
|
|
2488
2768
|
{
|
|
2489
2769
|
triggerKey: "order_cancelled",
|
|
2490
2770
|
label: "Order cancelled",
|
|
2491
2771
|
description: "Fires when an order is cancelled (includes refund amount when applicable).",
|
|
2492
2772
|
category: "order",
|
|
2493
|
-
sortOrder:
|
|
2773
|
+
sortOrder: 5
|
|
2494
2774
|
},
|
|
2495
2775
|
{
|
|
2496
2776
|
triggerKey: "payment_success",
|
|
2497
2777
|
label: "Payment success",
|
|
2498
2778
|
description: "Fires when order is placed and payment status is paid.",
|
|
2499
2779
|
category: "order",
|
|
2500
|
-
sortOrder:
|
|
2780
|
+
sortOrder: 6
|
|
2501
2781
|
},
|
|
2502
2782
|
{
|
|
2503
2783
|
triggerKey: "payment_failed",
|
|
2504
2784
|
label: "Payment failed",
|
|
2505
2785
|
description: "Fires when payment status is pending, unpaid, or failed, or when order is cancelled without payment.",
|
|
2506
2786
|
category: "order",
|
|
2507
|
-
sortOrder:
|
|
2787
|
+
sortOrder: 7
|
|
2508
2788
|
},
|
|
2509
2789
|
{
|
|
2510
2790
|
triggerKey: "payment_refund_initiated",
|
|
2511
2791
|
label: "Payment refund initiated",
|
|
2512
2792
|
description: "Fires when order is cancelled and its payment status is paid (refund initiated).",
|
|
2513
2793
|
category: "order",
|
|
2514
|
-
sortOrder:
|
|
2794
|
+
sortOrder: 8
|
|
2515
2795
|
}
|
|
2516
2796
|
];
|
|
2517
2797
|
|
|
2518
2798
|
// src/lib/order-notification-triggers.ts
|
|
2519
2799
|
var ORDER_NOTIFICATION_TRIGGERS = [
|
|
2800
|
+
{
|
|
2801
|
+
key: "order_pending",
|
|
2802
|
+
label: "Order pending"
|
|
2803
|
+
},
|
|
2804
|
+
{
|
|
2805
|
+
key: "order_processing",
|
|
2806
|
+
label: "Order processing"
|
|
2807
|
+
},
|
|
2808
|
+
{
|
|
2809
|
+
key: "order_completed",
|
|
2810
|
+
label: "Order completed"
|
|
2811
|
+
},
|
|
2520
2812
|
{
|
|
2521
2813
|
key: "order_placed",
|
|
2522
2814
|
label: "Order placed"
|