@unchainedshop/plugins 4.0.0-rc.9 → 4.0.0

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 (307) hide show
  1. package/lib/accounts/google-oauth.d.ts +4 -0
  2. package/lib/accounts/google-oauth.d.ts.map +1 -0
  3. package/lib/accounts/google-oauth.js +145 -0
  4. package/lib/accounts/google-oauth.js.map +1 -0
  5. package/lib/accounts/linkedin-oauth.d.ts +4 -0
  6. package/lib/accounts/linkedin-oauth.d.ts.map +1 -0
  7. package/lib/accounts/linkedin-oauth.js +82 -0
  8. package/lib/accounts/linkedin-oauth.js.map +1 -0
  9. package/lib/delivery/send-message.js.map +1 -1
  10. package/lib/enrollments/licensed.js +15 -2
  11. package/lib/enrollments/licensed.js.map +1 -1
  12. package/lib/files/gridfs/adapter.d.ts.map +1 -1
  13. package/lib/files/gridfs/adapter.js +11 -8
  14. package/lib/files/gridfs/adapter.js.map +1 -1
  15. package/lib/files/gridfs/gridfs-adapter.d.ts +3 -0
  16. package/lib/files/gridfs/gridfs-adapter.d.ts.map +1 -0
  17. package/lib/files/gridfs/gridfs-adapter.js +97 -0
  18. package/lib/files/gridfs/gridfs-adapter.js.map +1 -0
  19. package/lib/files/gridfs/gridfs-webhook.d.ts +11 -0
  20. package/lib/files/gridfs/gridfs-webhook.d.ts.map +1 -0
  21. package/lib/files/gridfs/gridfs-webhook.js +84 -0
  22. package/lib/files/gridfs/gridfs-webhook.js.map +1 -0
  23. package/lib/files/gridfs/handler-express.d.ts.map +1 -1
  24. package/lib/files/gridfs/handler-express.js +21 -25
  25. package/lib/files/gridfs/handler-express.js.map +1 -1
  26. package/lib/files/gridfs/handler-fastify.d.ts.map +1 -1
  27. package/lib/files/gridfs/handler-fastify.js +50 -13
  28. package/lib/files/gridfs/handler-fastify.js.map +1 -1
  29. package/lib/files/gridfs/module.d.ts +2 -2
  30. package/lib/files/minio/handler-express.d.ts.map +1 -1
  31. package/lib/files/minio/handler-express.js +4 -7
  32. package/lib/files/minio/handler-express.js.map +1 -1
  33. package/lib/files/minio/handler-fastify.js +2 -2
  34. package/lib/files/minio/handler-fastify.js.map +1 -1
  35. package/lib/files/minio/index.d.ts +1 -1
  36. package/lib/files/minio/index.d.ts.map +1 -1
  37. package/lib/files/minio/index.js +7 -7
  38. package/lib/files/minio/index.js.map +1 -1
  39. package/lib/files/minio/minio-adapter.d.ts +6 -0
  40. package/lib/files/minio/minio-adapter.d.ts.map +1 -0
  41. package/lib/files/minio/minio-adapter.js +181 -0
  42. package/lib/files/minio/minio-adapter.js.map +1 -0
  43. package/lib/files/minio/minio-webhook.d.ts +2 -0
  44. package/lib/files/minio/minio-webhook.d.ts.map +1 -0
  45. package/lib/files/minio/minio-webhook.js +33 -0
  46. package/lib/files/minio/minio-webhook.js.map +1 -0
  47. package/lib/filters/local-search.js +1 -1
  48. package/lib/filters/local-search.js.map +1 -1
  49. package/lib/filters/strict-equal.js +0 -18
  50. package/lib/filters/strict-equal.js.map +1 -1
  51. package/lib/payment/apple-iap/adapter.js +12 -10
  52. package/lib/payment/apple-iap/adapter.js.map +1 -1
  53. package/lib/payment/apple-iap/db/AppleTransactionsCollection.d.ts +1 -1
  54. package/lib/payment/apple-iap/db/AppleTransactionsCollection.d.ts.map +1 -1
  55. package/lib/payment/apple-iap/handler-express.d.ts.map +1 -1
  56. package/lib/payment/apple-iap/handler-express.js +14 -10
  57. package/lib/payment/apple-iap/handler-express.js.map +1 -1
  58. package/lib/payment/apple-iap/handler-fastify.d.ts.map +1 -1
  59. package/lib/payment/apple-iap/handler-fastify.js +15 -8
  60. package/lib/payment/apple-iap/handler-fastify.js.map +1 -1
  61. package/lib/payment/apple-iap/module/configureAppleTransactionsModule.d.ts +9 -0
  62. package/lib/payment/apple-iap/module/configureAppleTransactionsModule.d.ts.map +1 -0
  63. package/lib/payment/apple-iap/module/configureAppleTransactionsModule.js +17 -0
  64. package/lib/payment/apple-iap/module/configureAppleTransactionsModule.js.map +1 -0
  65. package/lib/payment/apple-iap/module.d.ts +4 -4
  66. package/lib/payment/apple-iap/module.d.ts.map +1 -1
  67. package/lib/payment/apple-iap/module.js +4 -2
  68. package/lib/payment/apple-iap/module.js.map +1 -1
  69. package/lib/payment/braintree.js +3 -1
  70. package/lib/payment/braintree.js.map +1 -1
  71. package/lib/payment/cryptopay/db/CryptopayTransactions.d.ts +1 -1
  72. package/lib/payment/cryptopay/db/CryptopayTransactions.d.ts.map +1 -1
  73. package/lib/payment/cryptopay/derive-btc-address.d.ts.map +1 -1
  74. package/lib/payment/cryptopay/derive-btc-address.js +2 -3
  75. package/lib/payment/cryptopay/derive-btc-address.js.map +1 -1
  76. package/lib/payment/cryptopay/derive-eth-address.d.ts.map +1 -1
  77. package/lib/payment/cryptopay/derive-eth-address.js +5 -3
  78. package/lib/payment/cryptopay/derive-eth-address.js.map +1 -1
  79. package/lib/payment/cryptopay/handle-webhook.js +2 -2
  80. package/lib/payment/cryptopay/handle-webhook.js.map +1 -1
  81. package/lib/payment/cryptopay/handler-express.d.ts.map +1 -1
  82. package/lib/payment/cryptopay/handler-express.js +4 -7
  83. package/lib/payment/cryptopay/handler-express.js.map +1 -1
  84. package/lib/payment/cryptopay/handler-fastify.js +1 -1
  85. package/lib/payment/cryptopay/handler-fastify.js.map +1 -1
  86. package/lib/payment/cryptopay/middleware.d.ts +2 -0
  87. package/lib/payment/cryptopay/middleware.d.ts.map +1 -0
  88. package/lib/payment/cryptopay/middleware.js +75 -0
  89. package/lib/payment/cryptopay/middleware.js.map +1 -0
  90. package/lib/payment/cryptopay/module/configureCryptopayModule.d.ts +25 -0
  91. package/lib/payment/cryptopay/module/configureCryptopayModule.d.ts.map +1 -0
  92. package/lib/payment/cryptopay/module/configureCryptopayModule.js +75 -0
  93. package/lib/payment/cryptopay/module/configureCryptopayModule.js.map +1 -0
  94. package/lib/payment/cryptopay/module.d.ts +2 -2
  95. package/lib/payment/cryptopay/module.d.ts.map +1 -1
  96. package/lib/payment/cryptopay/module.js +4 -4
  97. package/lib/payment/cryptopay/module.js.map +1 -1
  98. package/lib/payment/cryptopay/plugin.d.ts.map +1 -1
  99. package/lib/payment/cryptopay/plugin.js +18 -4
  100. package/lib/payment/cryptopay/plugin.js.map +1 -1
  101. package/lib/payment/datatrans-v2/handler-express.d.ts.map +1 -1
  102. package/lib/payment/datatrans-v2/handler-express.js +13 -11
  103. package/lib/payment/datatrans-v2/handler-express.js.map +1 -1
  104. package/lib/payment/datatrans-v2/handler-fastify.d.ts.map +1 -1
  105. package/lib/payment/datatrans-v2/handler-fastify.js +11 -5
  106. package/lib/payment/datatrans-v2/handler-fastify.js.map +1 -1
  107. package/lib/payment/datatrans-v2/index.js +63 -37
  108. package/lib/payment/datatrans-v2/index.js.map +1 -1
  109. package/lib/payment/datatrans-v2/middleware.d.ts +2 -0
  110. package/lib/payment/datatrans-v2/middleware.d.ts.map +1 -0
  111. package/lib/payment/datatrans-v2/middleware.js +68 -0
  112. package/lib/payment/datatrans-v2/middleware.js.map +1 -0
  113. package/lib/payment/datatrans-v2/parseRegistrationData.d.ts +1 -1
  114. package/lib/payment/datatrans-v2/parseRegistrationData.d.ts.map +1 -1
  115. package/lib/payment/paypal-checkout.js +4 -2
  116. package/lib/payment/paypal-checkout.js.map +1 -1
  117. package/lib/payment/payrexx/api/index.d.ts +1 -1
  118. package/lib/payment/payrexx/api/index.d.ts.map +1 -1
  119. package/lib/payment/payrexx/api/makeFetcher.d.ts +1 -1
  120. package/lib/payment/payrexx/api/makeFetcher.d.ts.map +1 -1
  121. package/lib/payment/payrexx/api/makeFetcher.js +1 -1
  122. package/lib/payment/payrexx/api/makeFetcher.js.map +1 -1
  123. package/lib/payment/payrexx/handler-express.d.ts.map +1 -1
  124. package/lib/payment/payrexx/handler-express.js +15 -15
  125. package/lib/payment/payrexx/handler-express.js.map +1 -1
  126. package/lib/payment/payrexx/handler-fastify.js +23 -15
  127. package/lib/payment/payrexx/handler-fastify.js.map +1 -1
  128. package/lib/payment/payrexx/index.js +21 -15
  129. package/lib/payment/payrexx/index.js.map +1 -1
  130. package/lib/payment/payrexx/middleware.d.ts +2 -0
  131. package/lib/payment/payrexx/middleware.d.ts.map +1 -0
  132. package/lib/payment/payrexx/middleware.js +86 -0
  133. package/lib/payment/payrexx/middleware.js.map +1 -0
  134. package/lib/payment/postfinance-checkout/api-client.d.ts.map +1 -1
  135. package/lib/payment/postfinance-checkout/api-client.js +7 -7
  136. package/lib/payment/postfinance-checkout/api-client.js.map +1 -1
  137. package/lib/payment/postfinance-checkout/handler-express.js +7 -8
  138. package/lib/payment/postfinance-checkout/handler-express.js.map +1 -1
  139. package/lib/payment/postfinance-checkout/handler-fastify.d.ts.map +1 -1
  140. package/lib/payment/postfinance-checkout/handler-fastify.js +6 -4
  141. package/lib/payment/postfinance-checkout/handler-fastify.js.map +1 -1
  142. package/lib/payment/postfinance-checkout/index.d.ts.map +1 -1
  143. package/lib/payment/postfinance-checkout/index.js +20 -7
  144. package/lib/payment/postfinance-checkout/index.js.map +1 -1
  145. package/lib/payment/postfinance-checkout/middleware.d.ts +2 -0
  146. package/lib/payment/postfinance-checkout/middleware.d.ts.map +1 -0
  147. package/lib/payment/postfinance-checkout/middleware.js +38 -0
  148. package/lib/payment/postfinance-checkout/middleware.js.map +1 -0
  149. package/lib/payment/saferpay/adapter.d.ts.map +1 -1
  150. package/lib/payment/saferpay/adapter.js +9 -0
  151. package/lib/payment/saferpay/adapter.js.map +1 -1
  152. package/lib/payment/saferpay/handler-express.d.ts.map +1 -1
  153. package/lib/payment/saferpay/handler-express.js +10 -8
  154. package/lib/payment/saferpay/handler-express.js.map +1 -1
  155. package/lib/payment/saferpay/handler-fastify.d.ts.map +1 -1
  156. package/lib/payment/saferpay/handler-fastify.js +11 -5
  157. package/lib/payment/saferpay/handler-fastify.js.map +1 -1
  158. package/lib/payment/saferpay/middleware.d.ts +2 -0
  159. package/lib/payment/saferpay/middleware.d.ts.map +1 -0
  160. package/lib/payment/saferpay/middleware.js +57 -0
  161. package/lib/payment/saferpay/middleware.js.map +1 -0
  162. package/lib/payment/saferpay/module/configureSaferpayTransactionsModule.d.ts +10 -0
  163. package/lib/payment/saferpay/module/configureSaferpayTransactionsModule.d.ts.map +1 -0
  164. package/lib/payment/saferpay/module/configureSaferpayTransactionsModule.js +24 -0
  165. package/lib/payment/saferpay/module/configureSaferpayTransactionsModule.js.map +1 -0
  166. package/lib/payment/saferpay/module.d.ts +2 -2
  167. package/lib/payment/stripe/handler-express.js +25 -17
  168. package/lib/payment/stripe/handler-express.js.map +1 -1
  169. package/lib/payment/stripe/handler-fastify.d.ts.map +1 -1
  170. package/lib/payment/stripe/handler-fastify.js +33 -12
  171. package/lib/payment/stripe/handler-fastify.js.map +1 -1
  172. package/lib/payment/stripe/index.js +21 -15
  173. package/lib/payment/stripe/index.js.map +1 -1
  174. package/lib/payment/stripe/middleware.d.ts +6 -0
  175. package/lib/payment/stripe/middleware.d.ts.map +1 -0
  176. package/lib/payment/stripe/middleware.js +114 -0
  177. package/lib/payment/stripe/middleware.js.map +1 -0
  178. package/lib/payment/stripe/stripe.d.ts +2 -2
  179. package/lib/payment/stripe/stripe.d.ts.map +1 -1
  180. package/lib/payment/stripe/stripe.js +14 -11
  181. package/lib/payment/stripe/stripe.js.map +1 -1
  182. package/lib/plugins-index.d.ts +48 -0
  183. package/lib/plugins-index.d.ts.map +1 -0
  184. package/lib/plugins-index.js +107 -0
  185. package/lib/plugins-index.js.map +1 -0
  186. package/lib/presets/all.d.ts +5 -5
  187. package/lib/presets/all.d.ts.map +1 -1
  188. package/lib/pricing/delivery-swiss-tax.d.ts.map +1 -1
  189. package/lib/pricing/delivery-swiss-tax.js +13 -20
  190. package/lib/pricing/delivery-swiss-tax.js.map +1 -1
  191. package/lib/pricing/order-discount.d.ts.map +1 -1
  192. package/lib/pricing/order-discount.js +5 -3
  193. package/lib/pricing/order-discount.js.map +1 -1
  194. package/lib/pricing/order-round.d.ts.map +1 -1
  195. package/lib/pricing/order-round.js +4 -3
  196. package/lib/pricing/order-round.js.map +1 -1
  197. package/lib/pricing/product-catalog-price-options.d.ts +2 -0
  198. package/lib/pricing/product-catalog-price-options.d.ts.map +1 -0
  199. package/lib/pricing/product-catalog-price-options.js +52 -0
  200. package/lib/pricing/product-catalog-price-options.js.map +1 -0
  201. package/lib/pricing/product-catalog-price.d.ts.map +1 -1
  202. package/lib/pricing/product-catalog-price.js +26 -2
  203. package/lib/pricing/product-catalog-price.js.map +1 -1
  204. package/lib/pricing/product-price-rateconversion.js +3 -3
  205. package/lib/pricing/product-price-rateconversion.js.map +1 -1
  206. package/lib/pricing/product-swiss-tax.d.ts +1 -5
  207. package/lib/pricing/product-swiss-tax.d.ts.map +1 -1
  208. package/lib/pricing/product-swiss-tax.js +26 -22
  209. package/lib/pricing/product-swiss-tax.js.map +1 -1
  210. package/lib/pricing/tax/ch.d.ts +7 -2
  211. package/lib/pricing/tax/ch.d.ts.map +1 -1
  212. package/lib/pricing/tax/ch.js +16 -1
  213. package/lib/pricing/tax/ch.js.map +1 -1
  214. package/lib/pricing/utils/isDeliveryAddressInCountry.d.ts +7 -0
  215. package/lib/pricing/utils/isDeliveryAddressInCountry.d.ts.map +1 -0
  216. package/lib/pricing/utils/isDeliveryAddressInCountry.js +13 -0
  217. package/lib/pricing/utils/isDeliveryAddressInCountry.js.map +1 -0
  218. package/lib/warehousing/eth-minter.js +23 -11
  219. package/lib/warehousing/eth-minter.js.map +1 -1
  220. package/lib/worker/bulk-import.d.ts +1 -1
  221. package/lib/worker/bulk-import.d.ts.map +1 -1
  222. package/lib/worker/bulk-import.js +11 -33
  223. package/lib/worker/bulk-import.js.map +1 -1
  224. package/lib/worker/email.d.ts.map +1 -1
  225. package/lib/worker/email.js +25 -7
  226. package/lib/worker/email.js.map +1 -1
  227. package/lib/worker/enrollment-order-generator.d.ts.map +1 -1
  228. package/lib/worker/enrollment-order-generator.js +7 -49
  229. package/lib/worker/enrollment-order-generator.js.map +1 -1
  230. package/lib/worker/error-notifications.js +1 -1
  231. package/lib/worker/error-notifications.js.map +1 -1
  232. package/lib/worker/export-token.d.ts.map +1 -1
  233. package/lib/worker/export-token.js +0 -1
  234. package/lib/worker/export-token.js.map +1 -1
  235. package/lib/worker/message.d.ts +1 -1
  236. package/lib/worker/message.d.ts.map +1 -1
  237. package/lib/worker/message.js +4 -2
  238. package/lib/worker/message.js.map +1 -1
  239. package/lib/worker/sms.js +17 -17
  240. package/lib/worker/sms.js.map +1 -1
  241. package/lib/worker/twilio.js +4 -0
  242. package/lib/worker/twilio.js.map +1 -1
  243. package/package.json +22 -33
  244. package/src/delivery/send-message.ts +1 -1
  245. package/src/enrollments/licensed.ts +15 -2
  246. package/src/files/gridfs/adapter.ts +12 -7
  247. package/src/files/gridfs/handler-express.ts +23 -25
  248. package/src/files/gridfs/handler-fastify.ts +53 -14
  249. package/src/files/minio/handler-express.ts +4 -7
  250. package/src/files/minio/handler-fastify.ts +2 -2
  251. package/src/files/minio/index.ts +16 -16
  252. package/src/filters/local-search.ts +1 -1
  253. package/src/filters/strict-equal.ts +0 -21
  254. package/src/payment/apple-iap/adapter.ts +12 -14
  255. package/src/payment/apple-iap/db/AppleTransactionsCollection.ts +1 -1
  256. package/src/payment/apple-iap/handler-express.ts +17 -11
  257. package/src/payment/apple-iap/handler-fastify.ts +19 -9
  258. package/src/payment/apple-iap/module.ts +9 -4
  259. package/src/payment/braintree.ts +4 -1
  260. package/src/payment/cryptopay/db/CryptopayTransactions.ts +1 -1
  261. package/src/payment/cryptopay/derive-btc-address.ts +1 -3
  262. package/src/payment/cryptopay/derive-eth-address.ts +5 -3
  263. package/src/payment/cryptopay/handle-webhook.ts +6 -6
  264. package/src/payment/cryptopay/handler-express.ts +4 -7
  265. package/src/payment/cryptopay/handler-fastify.ts +1 -1
  266. package/src/payment/cryptopay/module.ts +8 -5
  267. package/src/payment/cryptopay/plugin.ts +21 -4
  268. package/src/payment/datatrans-v2/handler-express.ts +17 -12
  269. package/src/payment/datatrans-v2/handler-fastify.ts +15 -6
  270. package/src/payment/datatrans-v2/index.ts +82 -50
  271. package/src/payment/paypal-checkout.ts +4 -2
  272. package/src/payment/payrexx/api/index.ts +1 -1
  273. package/src/payment/payrexx/api/makeFetcher.ts +2 -2
  274. package/src/payment/payrexx/handler-express.ts +24 -32
  275. package/src/payment/payrexx/handler-fastify.ts +33 -33
  276. package/src/payment/payrexx/index.ts +26 -16
  277. package/src/payment/postfinance-checkout/api-client.ts +13 -8
  278. package/src/payment/postfinance-checkout/handler-express.ts +8 -8
  279. package/src/payment/postfinance-checkout/handler-fastify.ts +7 -4
  280. package/src/payment/postfinance-checkout/index.ts +20 -8
  281. package/src/payment/saferpay/adapter.ts +14 -2
  282. package/src/payment/saferpay/handler-express.ts +14 -13
  283. package/src/payment/saferpay/handler-fastify.ts +14 -9
  284. package/src/payment/stripe/handler-express.ts +33 -33
  285. package/src/payment/stripe/handler-fastify.ts +40 -27
  286. package/src/payment/stripe/index.ts +18 -16
  287. package/src/payment/stripe/stripe.ts +17 -12
  288. package/src/pricing/delivery-swiss-tax.ts +16 -31
  289. package/src/pricing/order-discount.ts +6 -4
  290. package/src/pricing/order-round.ts +5 -4
  291. package/src/pricing/product-catalog-price-options.ts +67 -0
  292. package/src/pricing/product-catalog-price.ts +25 -2
  293. package/src/pricing/product-price-rateconversion.ts +3 -3
  294. package/src/pricing/product-swiss-tax.ts +39 -40
  295. package/src/pricing/tax/ch.ts +33 -7
  296. package/src/pricing/utils/isDeliveryAddressInCountry.test.ts +106 -0
  297. package/src/pricing/utils/isDeliveryAddressInCountry.ts +26 -0
  298. package/src/warehousing/eth-minter.ts +30 -11
  299. package/src/worker/budgetsms.ts +1 -1
  300. package/src/worker/bulk-import.ts +12 -53
  301. package/src/worker/email.ts +30 -8
  302. package/src/worker/enrollment-order-generator.ts +14 -72
  303. package/src/worker/error-notifications.ts +2 -2
  304. package/src/worker/export-token.ts +0 -1
  305. package/src/worker/message.ts +5 -3
  306. package/src/worker/twilio.ts +10 -3
  307. package/src/pricing/product-swiss-tax.test.ts +0 -139
@@ -1,14 +1,16 @@
1
+ import { DeliveryProvider } from '@unchainedshop/core-delivery';
2
+ import { Product } from '@unchainedshop/core-products';
3
+
1
4
  const startOf2024 = new Date('2024-01-01T00:00:00.000+0100');
2
5
 
3
6
  // https://www.estv.admin.ch/estv/en/home/value-added-tax/vat-rates-switzerland.html
4
7
 
5
- export const SwissTaxCategories: Record<
6
- string,
7
- {
8
- value: string;
9
- rate: (referenceDate?: Date) => number;
10
- }
11
- > = {
8
+ export interface SwissTaxCategoryResolver {
9
+ value: string;
10
+ rate: (referenceDate?: Date) => number;
11
+ }
12
+
13
+ export const SwissTaxCategories: Record<string, SwissTaxCategoryResolver> = {
12
14
  DEFAULT: {
13
15
  value: 'default',
14
16
  rate: (referenceDate = new Date()) => {
@@ -37,3 +39,27 @@ export const SwissTaxCategories: Record<
37
39
  },
38
40
  },
39
41
  };
42
+
43
+ export const resolveTaxCategoryFromDeliveryProvider = (
44
+ provider: DeliveryProvider,
45
+ ): SwissTaxCategoryResolver | null => {
46
+ const taxCategoryFromProvider = provider?.configuration
47
+ ?.find(({ key }) => {
48
+ if (key === 'swiss-tax-category') return true;
49
+ return null;
50
+ })
51
+ ?.value?.toUpperCase();
52
+
53
+ const taxCategory = taxCategoryFromProvider ? SwissTaxCategories[taxCategoryFromProvider] : null;
54
+ return taxCategory;
55
+ };
56
+
57
+ export const resolveTaxCategoryFromProduct = (product: Product): SwissTaxCategoryResolver | null => {
58
+ const productSpecialTaxTag = product.tags?.find((tag) =>
59
+ tag?.trim().toLowerCase().startsWith('swiss-tax-category:'),
60
+ );
61
+ const taxCategory = Object.values(SwissTaxCategories).find(
62
+ (t) => `swiss-tax-category:${t.value}` === productSpecialTaxTag?.trim().toLowerCase(),
63
+ );
64
+ return taxCategory || null;
65
+ };
@@ -0,0 +1,106 @@
1
+ import { describe, it } from 'node:test';
2
+ import assert from 'node:assert';
3
+ import isDeliveryAddressInCountry from './isDeliveryAddressInCountry.js';
4
+
5
+ describe('isDeliveryAddressInCountry', () => {
6
+ const context = {
7
+ modules: {
8
+ orders: {
9
+ deliveries: {
10
+ findDelivery: async ({ orderDeliveryId }: any) => {
11
+ if (orderDeliveryId === 'CH' || orderDeliveryId === 'LI')
12
+ return { context: { address: { countryCode: 'CH' } } };
13
+ if (orderDeliveryId === null) return { context: { address: null } };
14
+ return { context: { address: { countryCode: 'RT' } } };
15
+ },
16
+ },
17
+ },
18
+ },
19
+ order: {
20
+ deliveryId: 'CH',
21
+ billingAddress: { countryCode: 'LI' },
22
+ },
23
+ countryCode: 'CH',
24
+ };
25
+ it('Should return true when passed country code CH', async () => {
26
+ assert.strictEqual(
27
+ await isDeliveryAddressInCountry({ ...context, countryCode: 'ch', order: null } as any, [
28
+ 'CH',
29
+ 'LI',
30
+ ]),
31
+ true,
32
+ );
33
+ });
34
+
35
+ it('Should return true when passed country code LI', async () => {
36
+ assert.strictEqual(
37
+ await isDeliveryAddressInCountry({ ...context, countryCode: 'LI', order: null } as any, [
38
+ 'CH',
39
+ 'LI',
40
+ ]),
41
+ true,
42
+ );
43
+ });
44
+
45
+ it('Should return false when country is neither CH nor LI and order is null', async () => {
46
+ assert.strictEqual(
47
+ await isDeliveryAddressInCountry({ ...context, countryCode: 'ET', order: null } as any, [
48
+ 'CH',
49
+ 'LI',
50
+ ]),
51
+ false,
52
+ );
53
+ });
54
+
55
+ it('Order should take precedence over country parameter', async () => {
56
+ // not CH or LI order so returns false
57
+ assert.strictEqual(
58
+ await isDeliveryAddressInCountry(
59
+ {
60
+ ...context,
61
+ countryCode: 'CH',
62
+ order: {
63
+ deliveryId: 'ET',
64
+ billingAddress: { countryCode: 'ET' },
65
+ },
66
+ } as any,
67
+ ['CH', 'LI'],
68
+ ),
69
+ false,
70
+ );
71
+ });
72
+
73
+ it('If order is not from CH and LI but billingAddress is, it should take precedence over country ', async () => {
74
+ assert.strictEqual(
75
+ await isDeliveryAddressInCountry(
76
+ {
77
+ ...context,
78
+ countryCode: 'IT',
79
+ order: {
80
+ deliveryId: null,
81
+ billingAddress: { countryCode: 'CH' },
82
+ },
83
+ } as any,
84
+ ['CH', 'LI'],
85
+ ),
86
+ true,
87
+ );
88
+ });
89
+
90
+ it('Should return false if billingAddress is neither CH or LI and order does not have address', async () => {
91
+ assert.strictEqual(
92
+ await isDeliveryAddressInCountry(
93
+ {
94
+ ...context,
95
+ country: null,
96
+ order: {
97
+ deliveryId: null,
98
+ billingAddress: { countryCode: 'HH' },
99
+ },
100
+ } as any,
101
+ ['CH', 'LI'],
102
+ ),
103
+ false,
104
+ );
105
+ });
106
+ });
@@ -0,0 +1,26 @@
1
+ import { Order, OrderDelivery } from '@unchainedshop/core-orders';
2
+
3
+ export default function isDeliveryAddressInCountry(
4
+ {
5
+ orderDelivery,
6
+ order,
7
+ countryCode: forceCountryCode = null,
8
+ }: {
9
+ orderDelivery?: OrderDelivery | null;
10
+ order?: Order | null;
11
+ countryCode?: string | null;
12
+ },
13
+ allowedCountryCodes: string[],
14
+ ) {
15
+ let countryCode = forceCountryCode?.toUpperCase().trim() || order?.countryCode;
16
+
17
+ if (orderDelivery || order) {
18
+ const address = orderDelivery?.context?.address || order?.billingAddress;
19
+ if (address?.countryCode > '') {
20
+ countryCode = address.countryCode?.toUpperCase().trim();
21
+ }
22
+ }
23
+
24
+ if (!countryCode) return false;
25
+ return allowedCountryCodes.includes(countryCode);
26
+ }
@@ -11,9 +11,12 @@ import { ProductContractStandard, ProductTypes } from '@unchainedshop/core-produ
11
11
  import { systemLocale } from '@unchainedshop/utils';
12
12
  import { generateDbObjectId } from '@unchainedshop/mongodb';
13
13
  import { getFileAdapter } from '@unchainedshop/core-files';
14
+ import { createLogger } from '@unchainedshop/logger';
14
15
 
15
16
  const { MINTER_TOKEN_OFFSET = '0', ROOT_URL = 'http://localhost:4010' } = process.env;
16
17
 
18
+ const logger = createLogger('unchained:eth-minter');
19
+
17
20
  const ETHMinter: IWarehousingAdapter = {
18
21
  ...WarehousingAdapter,
19
22
 
@@ -40,7 +43,7 @@ const ETHMinter: IWarehousingAdapter = {
40
43
  ? { contractAddress: contractStandard }
41
44
  : {
42
45
  contractAddress: contractStandard,
43
- chainTokenId: tokenId,
46
+ tokenSerialNumber: tokenId,
44
47
  },
45
48
  );
46
49
  const tokensCreated = existingTokens.reduce((acc, curToken) => {
@@ -57,7 +60,13 @@ const ETHMinter: IWarehousingAdapter = {
57
60
  },
58
61
 
59
62
  configurationError() {
60
- return null as any as WarehousingError;
63
+ if (contractStandard === 'ERC1155' && !tokenId) {
64
+ logger.error(
65
+ `Token ID is required for ERC1155 contract standard (productId: ${product!._id})`,
66
+ );
67
+ return WarehousingError.INCOMPLETE_CONFIGURATION;
68
+ }
69
+ return null;
61
70
  },
62
71
 
63
72
  stock: async () => {
@@ -74,11 +83,17 @@ const ETHMinter: IWarehousingAdapter = {
74
83
  const meta = { contractStandard };
75
84
  const tokensCreated = await getTokensCreated();
76
85
 
86
+ if (!orderPosition) {
87
+ throw new Error('Order position not found in context');
88
+ }
89
+
77
90
  if (contractStandard === 'ERC721') {
78
- // ERC721 is non-fungible, thus every chainTokenId unique!
79
- const items = new Array(orderPosition?.quantity).fill(null).map((_, i) => ({
91
+ // ERC721 is non-fungible, thus every tokenSerialNumber unique!
92
+ const items = new Array(orderPosition.quantity).fill(null).map((_, i) => ({
80
93
  _id: generateDbObjectId(),
81
- chainTokenId: Number(parseInt(MINTER_TOKEN_OFFSET, 10) + tokensCreated + (i + 1)).toString(),
94
+ tokenSerialNumber: Number(
95
+ parseInt(MINTER_TOKEN_OFFSET, 10) + tokensCreated + (i + 1),
96
+ ).toString(),
82
97
  contractAddress,
83
98
  quantity: 1,
84
99
  chainId,
@@ -90,20 +105,24 @@ const ETHMinter: IWarehousingAdapter = {
90
105
  return [
91
106
  {
92
107
  _id: generateDbObjectId(),
93
- chainTokenId: tokenId,
108
+ tokenSerialNumber: tokenId!,
94
109
  contractAddress,
95
- quantity: orderPosition?.quantity,
110
+ quantity: orderPosition.quantity,
96
111
  chainId,
97
112
  meta,
98
113
  },
99
114
  ];
100
115
  },
101
116
 
102
- tokenMetadata: async (chainTokenId) => {
117
+ tokenMetadata: async (tokenSerialNumber) => {
103
118
  // Metadata standards supported
104
119
  // https://eips.ethereum.org/EIPS/eip-1155 (backward compatible with 721)
105
120
  // https://eips.ethereum.org/EIPS/eip-721
106
121
 
122
+ if (!product) {
123
+ throw new Error('Product not found in context');
124
+ }
125
+
107
126
  const allLanguages = await modules.languages.findLanguages({
108
127
  includeInactive: false,
109
128
  });
@@ -114,15 +133,15 @@ const ETHMinter: IWarehousingAdapter = {
114
133
  });
115
134
  const file = firstMedia && (await modules.files.findFile({ fileId: firstMedia.mediaId }));
116
135
 
117
- const fileUploadAdapter = getFileAdapter();
118
- const signedUrl = await fileUploadAdapter.createDownloadURL(file);
136
+ const fileAdapter = file && getFileAdapter();
137
+ const signedUrl = await fileAdapter?.createDownloadURL(file!);
119
138
  const url = signedUrl && (await modules.files.normalizeUrl(signedUrl, {}));
120
139
  const text = await modules.products.texts.findLocalizedText({
121
140
  productId: product._id,
122
141
  locale: locale || systemLocale,
123
142
  });
124
143
 
125
- const name = `${text.title} #${chainTokenId}`;
144
+ const name = `${text.title} #${tokenSerialNumber}`;
126
145
 
127
146
  const isDefaultLanguageActive = locale ? locale.language === systemLocale.language : true;
128
147
  const localization = isDefaultLanguageActive
@@ -8,7 +8,7 @@ const { BUDGETSMS_USERNAME, BUDGETSMS_USERID, BUDGETSMS_HANDLE } = process.env;
8
8
  const BudgetSMSWorker: IWorkerAdapter<
9
9
  {
10
10
  from?: string;
11
- to?: string;
11
+ to: string;
12
12
  text?: string;
13
13
  test?: boolean; // If true, uses test endpoint (no credit deducted)
14
14
  customid?: string;
@@ -1,57 +1,9 @@
1
1
  import { WorkerDirector, WorkerAdapter, IWorkerAdapter } from '@unchainedshop/core';
2
2
  import { createLogger } from '@unchainedshop/logger';
3
- import JSONStream from 'JSONStream';
4
- import { EventIterator } from 'event-iterator';
5
- import { UnchainedCore } from '@unchainedshop/core';
6
3
 
7
- const logger = createLogger('unchained:worker:bulk-import');
4
+ const logger = createLogger('unchained:bulk-import');
8
5
 
9
- const streamPayloadToBulkImporter = async (
10
- bulkImporter,
11
- payloadId,
12
- unchainedAPI: Pick<UnchainedCore, 'bulkImporter' | 'modules' | 'services'>,
13
- ) => {
14
- logger.trace(`parseAsync start`);
15
-
16
- const readStream = await unchainedAPI.services.files.createDownloadStream({ fileId: payloadId });
17
-
18
- if (!readStream) {
19
- throw new Error(
20
- 'The current file adapter does not support streams when downloading required for streamed events. Please use a different file adapter.',
21
- );
22
- }
23
-
24
- const eventIterator = new EventIterator(
25
- (queue) => {
26
- const jsonStream = JSONStream.parse('events.*'); // rows, ANYTHING, doc
27
- jsonStream.on('data', queue.push);
28
- jsonStream.on('close', queue.stop);
29
- jsonStream.on('error', queue.fail);
30
-
31
- queue.on('highWater', () => readStream.pause());
32
- queue.on('lowWater', () => readStream.resume());
33
-
34
- readStream.pipe(jsonStream);
35
- readStream.on('error', queue.fail);
36
-
37
- return () => {
38
- jsonStream.removeListener('data', queue.push);
39
- jsonStream.removeListener('close', queue.stop);
40
- jsonStream.removeListener('error', queue.fail);
41
- jsonStream.destroy();
42
- };
43
- },
44
- { highWaterMark: 100, lowWaterMark: 5 },
45
- );
46
-
47
- for await (const event of eventIterator) {
48
- await bulkImporter.prepare(event, unchainedAPI);
49
- }
50
-
51
- logger.trace(`parseAsync done`);
52
- };
53
-
54
- export const BulkImportWorker: IWorkerAdapter<any, Record<string, unknown>> = {
6
+ export const BulkImportWorker: IWorkerAdapter<any, Record<string, any>> = {
55
7
  ...WorkerAdapter,
56
8
 
57
9
  key: 'shop.unchained.worker-plugin.bulk-import',
@@ -76,13 +28,20 @@ export const BulkImportWorker: IWorkerAdapter<any, Record<string, unknown>> = {
76
28
 
77
29
  if (rawPayload.payloadId) {
78
30
  // stream payload from gridfs
79
- await streamPayloadToBulkImporter(bulkImporter, rawPayload.payloadId, unchainedAPI);
31
+ const readStream = await unchainedAPI.services.files.createDownloadStream({
32
+ fileId: rawPayload.payloadId,
33
+ });
34
+ if (!readStream) {
35
+ throw new Error('Could not create download stream from uploaded file');
36
+ }
37
+ await unchainedAPI.bulkImporter.pipeEventStream(readStream, bulkImporter, unchainedAPI);
80
38
  } else {
81
39
  const { events } = rawPayload;
82
40
  if (!events?.length) throw new Error('No events submitted');
83
41
 
84
42
  await events.reduce(async (currentEventPromise, nextEvent) => {
85
43
  await currentEventPromise;
44
+ await bulkImporter.validate(nextEvent);
86
45
  return bulkImporter.prepare(nextEvent, unchainedAPI);
87
46
  }, Promise.resolve());
88
47
  }
@@ -93,13 +52,13 @@ export const BulkImportWorker: IWorkerAdapter<any, Record<string, unknown>> = {
93
52
  if (error) {
94
53
  return {
95
54
  success: false,
96
- result,
55
+ result: result!,
97
56
  error,
98
57
  };
99
58
  }
100
59
  return {
101
60
  success: true,
102
- result,
61
+ result: result!,
103
62
  };
104
63
  } catch (err) {
105
64
  logger.error(err);
@@ -1,5 +1,9 @@
1
1
  import { WorkerDirector, WorkerAdapter, IWorkerAdapter } from '@unchainedshop/core';
2
2
  import nodemailer from 'nodemailer';
3
+ import { spawn } from 'node:child_process';
4
+ import { writeFile, mkdtemp } from 'node:fs/promises';
5
+ import { tmpdir } from 'node:os';
6
+ import { join } from 'node:path';
3
7
 
4
8
  export const checkEmailInterceptionEnabled = () => {
5
9
  return process.env.NODE_ENV !== 'production' && !process.env.UNCHAINED_DISABLE_EMAIL_INTERCEPTION;
@@ -18,10 +22,16 @@ const buildLink = async ({ filename, content, href, contentType, encoding, path
18
22
  return '';
19
23
  };
20
24
 
21
- const openInBrowser = async (options) => {
22
- // eslint-disable-next-line
23
- // @ts-ignore
24
- const { default: open, apps } = await import('open');
25
+ const openInBrowser = async (options): Promise<boolean> => {
26
+ const command = {
27
+ darwin: 'open',
28
+ win32: 'explorer.exe',
29
+ linux: 'xdg-open',
30
+ }[process.platform];
31
+
32
+ if (!command) {
33
+ return false;
34
+ }
25
35
 
26
36
  const messageBody = options.html || options.text.replace(/(\r\n|\n|\r)/gm, '<br/>');
27
37
  const attachmentLinks = await Promise.all((options.attachments || []).map(buildLink));
@@ -46,11 +56,23 @@ const openInBrowser = async (options) => {
46
56
  </body>
47
57
  </html>`;
48
58
 
49
- const base64 = Buffer.from(content).toString('base64');
50
- const dataUri = `data:text/html;base64,${base64}`;
59
+ // Create a temporary directory and file
60
+ const tempDir = await mkdtemp(join(tmpdir(), 'unchained-email-'));
61
+ const tempFile = join(tempDir, 'email-preview.html');
62
+
63
+ await writeFile(tempFile, content, 'utf8');
64
+
65
+ return new Promise((resolve) => {
66
+ const child = spawn(command, [tempFile], {
67
+ detached: true,
68
+ stdio: 'ignore',
69
+ });
70
+
71
+ child.unref();
51
72
 
52
- await open(dataUri, { app: [{ name: apps.chrome }, { name: apps.firefox }, { name: apps.browser }] });
53
- return true;
73
+ // Resolve immediately after spawning since process is detached
74
+ resolve(true);
75
+ });
54
76
  };
55
77
 
56
78
  const EmailWorkerPlugin: IWorkerAdapter<
@@ -1,73 +1,7 @@
1
- import { Enrollment } from '@unchainedshop/core-enrollments';
2
- import { OrderPosition } from '@unchainedshop/core-orders';
3
1
  import { enrollmentsSettings, EnrollmentStatus } from '@unchainedshop/core-enrollments';
4
- import {
5
- EnrollmentDirector,
6
- UnchainedCore,
7
- WorkerDirector,
8
- WorkerAdapter,
9
- IWorkerAdapter,
10
- } from '@unchainedshop/core';
2
+ import { EnrollmentDirector, WorkerDirector, WorkerAdapter, IWorkerAdapter } from '@unchainedshop/core';
11
3
 
12
- const generateOrder = async (
13
- enrollment: Enrollment,
14
- params: {
15
- orderPositions: OrderPosition[];
16
- } & Record<string, any>,
17
- unchainedAPI: Pick<UnchainedCore, 'modules' | 'services'>,
18
- ) => {
19
- if (!enrollment.payment || !enrollment.delivery) return null;
20
-
21
- const { modules, services } = unchainedAPI;
22
- const { orderPositions, ...configuration } = params;
23
- let order = await modules.orders.create({
24
- userId: enrollment.userId,
25
- currencyCode: enrollment.currencyCode,
26
- countryCode: enrollment.countryCode,
27
- contact: enrollment.contact,
28
- billingAddress: enrollment.billingAddress,
29
- originEnrollmentId: enrollment._id,
30
- ...configuration,
31
- });
32
- const orderId = order._id;
33
-
34
- if (orderPositions) {
35
- await Promise.all(
36
- orderPositions.map((orderPosition) => modules.orders.positions.addProductItem(orderPosition)),
37
- );
38
- } else {
39
- const product = await modules.products.findProduct({
40
- productId: enrollment.productId,
41
- });
42
- await modules.orders.positions.addProductItem({
43
- quantity: 1,
44
- productId: product._id,
45
- originalProductId: product._id,
46
- orderId: order._id,
47
- });
48
- }
49
-
50
- const { paymentProviderId, context: paymentContext } = enrollment.payment;
51
- if (paymentProviderId) {
52
- await modules.orders.setPaymentProvider(orderId, paymentProviderId);
53
- }
54
-
55
- const { deliveryProviderId, context: deliveryContext } = enrollment.delivery;
56
- if (deliveryProviderId) {
57
- await modules.orders.setDeliveryProvider(orderId, deliveryProviderId);
58
- }
59
-
60
- await services.orders.updateCalculation(orderId);
61
-
62
- order = await services.orders.checkoutOrder(order._id, {
63
- paymentContext,
64
- deliveryContext,
65
- });
66
-
67
- return order;
68
- };
69
-
70
- const GenerateOrderWorker: IWorkerAdapter<any, any> = {
4
+ const GenerateOrderWorker: IWorkerAdapter<never, any> = {
71
5
  ...WorkerAdapter,
72
6
 
73
7
  key: 'shop.unchained.worker-plugin.generate-enrollment-orders',
@@ -76,7 +10,7 @@ const GenerateOrderWorker: IWorkerAdapter<any, any> = {
76
10
  type: 'ENROLLMENT_ORDER_GENERATOR',
77
11
 
78
12
  doWork: async (input, unchainedAPI) => {
79
- const { modules } = unchainedAPI;
13
+ const { modules, services } = unchainedAPI;
80
14
 
81
15
  const enrollments = await modules.enrollments.findEnrollments({
82
16
  status: [EnrollmentStatus.ACTIVE, EnrollmentStatus.PAUSED],
@@ -86,7 +20,13 @@ const GenerateOrderWorker: IWorkerAdapter<any, any> = {
86
20
  await Promise.all(
87
21
  enrollments.map(async (enrollment) => {
88
22
  try {
89
- const director = await EnrollmentDirector.actions({ enrollment }, unchainedAPI);
23
+ const product = await unchainedAPI.modules.products.findProduct({
24
+ productId: enrollment.productId,
25
+ });
26
+ const director = await EnrollmentDirector.actions(
27
+ { enrollment, product: product! },
28
+ unchainedAPI,
29
+ );
90
30
  const period = await director.nextPeriod();
91
31
  if (period) {
92
32
  if (period.isTrial) {
@@ -96,11 +36,13 @@ const GenerateOrderWorker: IWorkerAdapter<any, any> = {
96
36
  return null;
97
37
  }
98
38
  const configuration = await director.configurationForOrder({
99
- ...input,
100
39
  period,
101
40
  });
102
41
  if (configuration) {
103
- const order = await generateOrder(enrollment, configuration, unchainedAPI);
42
+ const order = await services.enrollments.generateOrderFromEnrollment(
43
+ enrollment,
44
+ configuration,
45
+ );
104
46
  if (order) {
105
47
  await modules.enrollments.addEnrollmentPeriod(enrollment._id, {
106
48
  ...period,
@@ -1,4 +1,4 @@
1
- import { WorkStatus } from '@unchainedshop/core-worker';
1
+ import { Work, WorkStatus } from '@unchainedshop/core-worker';
2
2
  import { IWorkerAdapter, WorkerDirector, WorkerAdapter } from '@unchainedshop/core';
3
3
  import later from '@breejs/later';
4
4
 
@@ -22,7 +22,7 @@ export const ErrorNotifications: IWorkerAdapter<Arg, Result> = {
22
22
  type: 'ERROR_NOTIFICATIONS',
23
23
 
24
24
  doWork: async (args, context, workId) => {
25
- const work = await context.modules.worker.findWork({ workId });
25
+ const work = (await context.modules.worker.findWork({ workId })) as Work;
26
26
  const secondsPassed = args?.secondsPassed || 60;
27
27
  const to = new Date();
28
28
  const from = new Date(new Date(work.scheduled).getTime() - secondsPassed * 1000);
@@ -21,7 +21,6 @@ export const configureExportToken = (unchainedAPI: UnchainedCore) => {
21
21
  if (work.type === 'EXPORT_TOKEN' && work.success) {
22
22
  await unchainedAPI.modules.warehousing.updateTokenOwnership({
23
23
  tokenId: work.input.token._id,
24
- userId: null,
25
24
  walletAddress: work.input.recipientWalletAddress,
26
25
  });
27
26
  }
@@ -2,7 +2,7 @@ import { MessagingDirector, IWorkerAdapter, WorkerAdapter, WorkerDirector } from
2
2
  import { Work } from '@unchainedshop/core-worker';
3
3
 
4
4
  export const MessageWorker: IWorkerAdapter<
5
- { template: string; _id?: string; [x: string]: any },
5
+ { template: string; _id: string; [x: string]: any },
6
6
  { info?: string; forked?: Work[] }
7
7
  > = {
8
8
  ...WorkerAdapter,
@@ -16,6 +16,8 @@ export const MessageWorker: IWorkerAdapter<
16
16
  try {
17
17
  const templateResolver = MessagingDirector.getTemplate(template);
18
18
 
19
+ if (!templateResolver) throw new Error(`No template resolver found for template ${template}`);
20
+
19
21
  const workConfigurations = await templateResolver(
20
22
  {
21
23
  template,
@@ -31,13 +33,13 @@ export const MessageWorker: IWorkerAdapter<
31
33
  ...workConfiguration,
32
34
  originalWorkId: workId,
33
35
  });
34
- delete work.input;
36
+ delete (work as any).input; // Remove input from returned work for privacy
35
37
  return work;
36
38
  }),
37
39
  );
38
40
  return { success: true, result: { forked } };
39
41
  }
40
- return { success: true, result: { info: 'Skipped Message' } };
42
+ return { success: true, result: { forked: [] } };
41
43
  } catch (err) {
42
44
  return {
43
45
  success: false,
@@ -5,8 +5,8 @@ const { TWILIO_ACCOUNT_SID, TWILIO_AUTH_TOKEN, TWILIO_SMS_FROM } = process.env;
5
5
  const SmsWorkerPlugin: IWorkerAdapter<
6
6
  {
7
7
  from?: string;
8
- to?: string;
9
- text?: string;
8
+ to: string;
9
+ text: string;
10
10
  [key: string]: any; // Allow additional parameters
11
11
  },
12
12
  any
@@ -21,6 +21,13 @@ const SmsWorkerPlugin: IWorkerAdapter<
21
21
 
22
22
  doWork: async ({ from, to, text, ...params }) => {
23
23
  try {
24
+ if (!TWILIO_SMS_FROM && !from)
25
+ throw new Error(
26
+ 'Missing Twilio "from" number. Set TWILIO_SMS_FROM env var or provide "from" in input',
27
+ );
28
+
29
+ if (!to) throw new Error('Missing "to" in input');
30
+
24
31
  const url = `https://api.twilio.com/2010-04-01/Accounts/${TWILIO_ACCOUNT_SID}/Messages.json`;
25
32
  const response = await fetch(url, {
26
33
  method: 'POST',
@@ -30,7 +37,7 @@ const SmsWorkerPlugin: IWorkerAdapter<
30
37
  },
31
38
  body: new URLSearchParams({
32
39
  Body: text || '',
33
- From: from || TWILIO_SMS_FROM,
40
+ From: from || TWILIO_SMS_FROM!,
34
41
  To: to,
35
42
  ...params, // Include any additional parameters passed
36
43
  }),