@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.
Files changed (50) hide show
  1. package/dist/admin.cjs +4179 -2665
  2. package/dist/admin.js +2990 -1476
  3. package/dist/api.cjs +41 -37
  4. package/dist/api.js +9 -5
  5. package/dist/{chunk-URN7GS23.js → chunk-6LV36PCL.js} +199 -1059
  6. package/dist/{chunk-O2642WVS.js → chunk-6XAVZE4I.js} +17 -3
  7. package/dist/{chunk-BXYZDMTZ.cjs → chunk-AXMP2U43.cjs} +3 -94
  8. package/dist/{chunk-T3HPSF7K.js → chunk-AYWDQFJZ.js} +3 -0
  9. package/dist/chunk-CTIEAHQL.cjs +96 -0
  10. package/dist/chunk-GWDI752Q.js +83 -0
  11. package/dist/chunk-GZGFNVTK.js +886 -0
  12. package/dist/chunk-H3IVLIPR.cjs +86 -0
  13. package/dist/{chunk-2KUCQVAQ.js → chunk-HMLVPIJR.js} +2 -91
  14. package/dist/{chunk-V25RDUOU.cjs → chunk-LRD4CGOG.cjs} +38 -4
  15. package/dist/{chunk-73WVHINE.cjs → chunk-LVQSG25Y.cjs} +18 -4
  16. package/dist/chunk-NMYGQWHV.js +93 -0
  17. package/dist/chunk-OVTOP42W.js +199 -0
  18. package/dist/{chunk-BSLNXKV2.cjs → chunk-QA5C477U.cjs} +927 -351
  19. package/dist/{chunk-JAEUYYGA.js → chunk-R6Q67HAS.js} +876 -291
  20. package/dist/{chunk-YSYX4GUD.cjs → chunk-TWTISTZB.cjs} +210 -1080
  21. package/dist/{chunk-77I3KS7V.cjs → chunk-UEE4PTTB.cjs} +3 -0
  22. package/dist/chunk-WFMVD567.cjs +209 -0
  23. package/dist/{chunk-L3525VXI.js → chunk-YW7EF7K7.js} +36 -2
  24. package/dist/chunk-ZPAPCGCR.cjs +899 -0
  25. package/dist/{email-queue-OI2HSCGE.js → email-queue-65PQAG4C.js} +3 -2
  26. package/dist/{email-queue-6NJY6HNM.cjs → email-queue-J7DXYNCE.cjs} +7 -6
  27. package/dist/email-service-F7HA4X63.js +3 -0
  28. package/dist/email-service-RDOTY3CO.cjs +28 -0
  29. package/dist/{emit-order-notification-trigger-TNEZOYEE.cjs → emit-order-notification-trigger-K7URAZHJ.cjs} +4 -4
  30. package/dist/{emit-order-notification-trigger-CZU3V2WE.js → emit-order-notification-trigger-MD7EBODC.js} +2 -2
  31. package/dist/{erp-order-invoice-EYYNR526.cjs → erp-order-invoice-C5GZCOBM.cjs} +6 -5
  32. package/dist/{erp-order-invoice-3GXDE443.js → erp-order-invoice-MYFCXOCY.js} +2 -1
  33. package/dist/index.cjs +638 -346
  34. package/dist/index.d.cts +53 -19
  35. package/dist/index.d.ts +53 -19
  36. package/dist/index.js +350 -58
  37. package/dist/migrations/1783000000000-AddOrderPendingProcessingCompletedTriggers.ts +56 -0
  38. package/dist/migrations/1783100000000-AddSmsToOrderNotificationBindingsChannelEnum.ts +17 -0
  39. package/dist/migrations/1783200000000-AddOrderAssigneeColumns.ts +30 -0
  40. package/dist/order-assignees-handlers-LKMAGLG6.js +150 -0
  41. package/dist/order-assignees-handlers-NPKD64P6.cjs +152 -0
  42. package/dist/order-completion-otp-handlers-3NTOGEA5.js +361 -0
  43. package/dist/order-completion-otp-handlers-4EOLYLAP.cjs +363 -0
  44. package/dist/order-notification-dispatcher-IYMOS4VY.js +10 -0
  45. package/dist/order-notification-dispatcher-X2XM5VUY.cjs +35 -0
  46. package/dist/sms-notification-templates-handlers-SJLO7JGZ.js +47 -0
  47. package/dist/sms-notification-templates-handlers-YSB3L2PK.cjs +49 -0
  48. package/package.json +1 -1
  49. package/dist/order-notification-dispatcher-KJVGLK5E.cjs +0 -24
  50. package/dist/order-notification-dispatcher-ZSFKEYMP.js +0 -7
package/dist/index.js CHANGED
@@ -1,18 +1,22 @@
1
- export { emitOrderNotificationTrigger, fireOrderNotificationTrigger } from './chunk-O2642WVS.js';
2
- import { checkMultiVendorEnabled, loadUserVendorContext, getPublicSettingsGroup, BlogGeneratorService } from './chunk-JAEUYYGA.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, 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, daysBeforeEventStart, decrementDiscountUsage, describeEventTierPolicy, ensureMessagingPluginsOnCms, ensureScheduleQueueWorker, ensureVendorCustomerForOrderContact, ensureVendorCustomersForOrder, findActiveRefundPolicyForVendor, findUserByInviteToken, findVendorByInviteToken, formatTierRange, generateNumericOtp, getPublicSettingsGroup, getRequireEventApproval, getRequireProductApproval, getRssArticleSummaryFromItem, getVendorCatalogCreateFlags, hashOtpCode, hydrateVendorSessionUser, invalidateEventsCache, invalidateMultiVendorCache, invalidateRequireEventApprovalCache, invalidateRequireProductApprovalCache, invalidateVendorCatalogCreateFlagsCache, isCustomerTypeContact, isMaxPerUserUsageReached, isMaxTotalUsageReached, isZipMedia, llmAgentToChatAgentOptions, loadSettingsGroupFromDb, loadUserVendorContext, mergeGuardrailsIntoSystemPrompt, messagingPlugins, metaFetchUserManagedPages, metaPostPageFeed, metaPostPagePhoto, metaResolvePageAccessToken, newUserInviteToken, normalizePhoneE164, normalizeRefundTiers, overlayCmsPlugins, parseBlogGeneratorAgentContent, parseBlogGeneratorModelOutput, parseBlogMetadataEnrichmentJson, parseLlmAgentValidationRules, pgBossScheduleNameForId, queueErpCreateContactIfEnabled, queueJobScheduleNow, queuePlugin, queueSms, recordDiscountUsage, registerJobRunnerWorker, registerMessagingQueueProcessors, registerSmsQueueProcessor, relativePathFromMediaParentId, resolveBlogCategoryIdByName, resolveSettingsEncryptionKey, resolveVendorIdForContactCheck, sanitizeMediaFolderPath, sanitizeStorageSegment, sendVendorOnboardEmails, simpleDecrypt, simpleEncrypt, syncJobScheduleToPgBoss, validateRefundTiers, validateScheduleInput, validateUserMessageAgainstAgentRules, validateUserMessageAgainstStructuredRules, verifyAndConsumeOtpChallenge, verifyOtpCodeHash, whatsappPlugin, wrapGetCmsWithMessaging } from './chunk-JAEUYYGA.js';
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-URN7GS23.js';
8
- export { EmailService, buildEventOrderTemplateVariables, emailPlugin, emailTemplates, initWhatsappTriggerDispatcher, joinRecipientsForSend, parseEmailRecipientsFromConfig, queueWhatsApp, registerWhatsAppQueueProcessor, renderEmail, renderLayout, resendOrderNotification, serializeEmailRecipients } from './chunk-URN7GS23.js';
9
- export { KNOWN_NOTIFICATION_TRIGGERS, notificationTriggerEmitter } from './chunk-T3HPSF7K.js';
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
- import { queueOrderPlacedEmails } from './chunk-L3525VXI.js';
12
- export { queueEmail, queueOrderPlacedEmails, queueVendorOnboardEmails, registerEmailQueueProcessor } from './chunk-L3525VXI.js';
13
- import { mergeEmailLayoutCompanyDetails } from './chunk-2KUCQVAQ.js';
14
- export { INVOICE_TEMPLATE_IDS, INVOICE_TEMPLATE_OPTIONS, buildLocalInvoicePdfForOrder, generateLocalInvoicePdf, getCompanyDetailsFromSettings, isOrderEligibleForInvoiceEmail, mergeEmailLayoutCompanyDetails, normalizeInvoiceTemplateId, resolveInvoiceAssetUrl, resolveOrderInvoicePdfBytes, streamOrderInvoicePdf } from './chunk-2KUCQVAQ.js';
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 getSmsSettings?.() ?? {};
1013
+ db = await settingsLoader?.() ?? {};
993
1014
  } catch {
994
1015
  }
995
- const merged = mergeSmsConfigLayers(env, db, staticRest);
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
- return {
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
- return `${config.baseUrl.replace(/\/$/, "")}/${fullKey}`;
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
- return `https://s3.${config.region}.amazonaws.com/${config.bucket}/${fullKey}`;
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
- const base = config.baseUrl ? new URL(config.baseUrl).host : null;
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
- baseUrlHost: base,
1083
- accessKeyIdLast4: config.accessKeyId.slice(-4),
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
- location: head.headers.get("location")
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
- error: err instanceof Error ? err.message : String(err)
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 { S3Client, PutObjectCommand } = await import('@aws-sdk/client-s3');
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
- const started = Date.now();
1155
- console.info(LOG, "upload start", {
1156
- ...describeS3Config(config),
1157
- key: rawKey,
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
- await client.send(new PutObjectCommand({
1165
- Bucket: config.bucket,
1166
- Key: fullKey,
1167
- Body: buffer,
1168
- ContentType: contentType
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
- key: rawKey,
1355
+ incomingKey: key,
1356
+ rawKey,
1357
+ keyPrefix,
1175
1358
  fullKey,
1176
1359
  publicUrl,
1177
1360
  contentType,
1178
1361
  bytes: buffer.length,
1179
- ...errorDump,
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
- key: rawKey,
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: 1
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: 2
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: 3
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: 4
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: 5
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"