@unchainedshop/plugins 4.6.2 → 4.7.2

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 (184) hide show
  1. package/README.md +0 -2
  2. package/lib/events/node-event-emitter.d.ts +3 -1
  3. package/lib/events/node-event-emitter.js +3 -3
  4. package/lib/files/gridfs/adapter.d.ts +2 -2
  5. package/lib/files/gridfs/adapter.js +2 -5
  6. package/lib/files/gridfs/index.d.ts +5 -4
  7. package/lib/files/gridfs/index.js +30 -3
  8. package/lib/files/minio/index.d.ts +4 -5
  9. package/lib/files/minio/index.js +18 -157
  10. package/lib/payment/apple-iap/adapter.d.ts +2 -1
  11. package/lib/payment/apple-iap/adapter.js +2 -3
  12. package/lib/payment/apple-iap/index.d.ts +6 -4
  13. package/lib/payment/apple-iap/index.js +28 -3
  14. package/lib/payment/cryptopay/index.d.ts +5 -4
  15. package/lib/payment/cryptopay/index.js +31 -3
  16. package/lib/payment/datatrans-v2/index.d.ts +4 -1
  17. package/lib/payment/datatrans-v2/index.js +17 -400
  18. package/lib/payment/payrexx/index.d.ts +4 -1
  19. package/lib/payment/payrexx/index.js +19 -158
  20. package/lib/payment/postfinance-checkout/index.d.ts +5 -0
  21. package/lib/payment/postfinance-checkout/index.js +25 -186
  22. package/lib/payment/saferpay/adapter.js +1 -2
  23. package/lib/payment/saferpay/index.d.ts +5 -4
  24. package/lib/payment/saferpay/index.js +29 -3
  25. package/lib/payment/stripe/index.d.ts +4 -1
  26. package/lib/payment/stripe/index.js +22 -116
  27. package/lib/payment/stripe/stripe.js +2 -5
  28. package/lib/presets/all.d.ts +1 -70
  29. package/lib/presets/all.js +41 -27
  30. package/lib/presets/base.d.ts +1 -25
  31. package/lib/presets/base.js +56 -25
  32. package/lib/presets/countries/ch.d.ts +1 -2
  33. package/lib/presets/countries/ch.js +7 -2
  34. package/lib/presets/crypto.d.ts +3 -7
  35. package/lib/presets/crypto.js +18 -7
  36. package/package.json +15 -10
  37. package/lib/delivery/post.d.ts +0 -1
  38. package/lib/delivery/post.js +0 -23
  39. package/lib/delivery/send-message.d.ts +0 -1
  40. package/lib/delivery/send-message.js +0 -40
  41. package/lib/delivery/stores.d.ts +0 -1
  42. package/lib/delivery/stores.js +0 -43
  43. package/lib/enrollments/licensed.d.ts +0 -4
  44. package/lib/enrollments/licensed.js +0 -52
  45. package/lib/files/gridfs/handler-express.d.ts +0 -9
  46. package/lib/files/gridfs/handler-express.js +0 -110
  47. package/lib/files/gridfs/handler-fastify.d.ts +0 -3
  48. package/lib/files/gridfs/handler-fastify.js +0 -138
  49. package/lib/files/minio/handler-express.d.ts +0 -2
  50. package/lib/files/minio/handler-express.js +0 -36
  51. package/lib/files/minio/handler-fastify.d.ts +0 -3
  52. package/lib/files/minio/handler-fastify.js +0 -40
  53. package/lib/filters/local-search.d.ts +0 -3
  54. package/lib/filters/local-search.js +0 -66
  55. package/lib/filters/strict-equal.d.ts +0 -1
  56. package/lib/filters/strict-equal.js +0 -24
  57. package/lib/payment/apple-iap/handler-express.d.ts +0 -2
  58. package/lib/payment/apple-iap/handler-express.js +0 -103
  59. package/lib/payment/apple-iap/handler-fastify.d.ts +0 -3
  60. package/lib/payment/apple-iap/handler-fastify.js +0 -102
  61. package/lib/payment/braintree.d.ts +0 -1
  62. package/lib/payment/braintree.js +0 -138
  63. package/lib/payment/cryptopay/handler-express.d.ts +0 -2
  64. package/lib/payment/cryptopay/handler-express.js +0 -19
  65. package/lib/payment/cryptopay/handler-fastify.d.ts +0 -3
  66. package/lib/payment/cryptopay/handler-fastify.js +0 -17
  67. package/lib/payment/cryptopay/plugin.d.ts +0 -3
  68. package/lib/payment/cryptopay/plugin.js +0 -159
  69. package/lib/payment/datatrans-v2/handler-express.d.ts +0 -1
  70. package/lib/payment/datatrans-v2/handler-express.js +0 -71
  71. package/lib/payment/datatrans-v2/handler-fastify.d.ts +0 -2
  72. package/lib/payment/datatrans-v2/handler-fastify.js +0 -71
  73. package/lib/payment/invoice-prepaid.d.ts +0 -1
  74. package/lib/payment/invoice-prepaid.js +0 -30
  75. package/lib/payment/invoice.d.ts +0 -1
  76. package/lib/payment/invoice.js +0 -27
  77. package/lib/payment/paypal-checkout.d.ts +0 -1
  78. package/lib/payment/paypal-checkout.js +0 -87
  79. package/lib/payment/payrexx/handler-express.d.ts +0 -1
  80. package/lib/payment/payrexx/handler-express.js +0 -85
  81. package/lib/payment/payrexx/handler-fastify.d.ts +0 -2
  82. package/lib/payment/payrexx/handler-fastify.js +0 -91
  83. package/lib/payment/postfinance-checkout/handler-express.d.ts +0 -1
  84. package/lib/payment/postfinance-checkout/handler-express.js +0 -37
  85. package/lib/payment/postfinance-checkout/handler-fastify.d.ts +0 -2
  86. package/lib/payment/postfinance-checkout/handler-fastify.js +0 -40
  87. package/lib/payment/saferpay/handler-express.d.ts +0 -1
  88. package/lib/payment/saferpay/handler-express.js +0 -59
  89. package/lib/payment/saferpay/handler-fastify.d.ts +0 -2
  90. package/lib/payment/saferpay/handler-fastify.js +0 -62
  91. package/lib/payment/stripe/handler-express.d.ts +0 -5
  92. package/lib/payment/stripe/handler-express.js +0 -121
  93. package/lib/payment/stripe/handler-fastify.d.ts +0 -6
  94. package/lib/payment/stripe/handler-fastify.js +0 -131
  95. package/lib/presets/all-express.d.ts +0 -6
  96. package/lib/presets/all-express.js +0 -26
  97. package/lib/presets/all-fastify.d.ts +0 -6
  98. package/lib/presets/all-fastify.js +0 -49
  99. package/lib/presets/base-express.d.ts +0 -2
  100. package/lib/presets/base-express.js +0 -5
  101. package/lib/presets/base-fastify.d.ts +0 -3
  102. package/lib/presets/base-fastify.js +0 -16
  103. package/lib/presets/crypto-express.d.ts +0 -3
  104. package/lib/presets/crypto-express.js +0 -8
  105. package/lib/presets/crypto-fastify.d.ts +0 -3
  106. package/lib/presets/crypto-fastify.js +0 -11
  107. package/lib/pricing/delivery-swiss-tax.d.ts +0 -2
  108. package/lib/pricing/delivery-swiss-tax.js +0 -62
  109. package/lib/pricing/discount-100-off.d.ts +0 -2
  110. package/lib/pricing/discount-100-off.js +0 -30
  111. package/lib/pricing/discount-half-price-manual.d.ts +0 -2
  112. package/lib/pricing/discount-half-price-manual.js +0 -30
  113. package/lib/pricing/discount-half-price.d.ts +0 -2
  114. package/lib/pricing/discount-half-price.js +0 -33
  115. package/lib/pricing/free-delivery.d.ts +0 -2
  116. package/lib/pricing/free-delivery.js +0 -27
  117. package/lib/pricing/free-payment.d.ts +0 -2
  118. package/lib/pricing/free-payment.js +0 -27
  119. package/lib/pricing/order-delivery.d.ts +0 -2
  120. package/lib/pricing/order-delivery.js +0 -33
  121. package/lib/pricing/order-discount.d.ts +0 -2
  122. package/lib/pricing/order-discount.js +0 -74
  123. package/lib/pricing/order-items-discount.d.ts +0 -2
  124. package/lib/pricing/order-items-discount.js +0 -50
  125. package/lib/pricing/order-items.d.ts +0 -2
  126. package/lib/pricing/order-items.js +0 -43
  127. package/lib/pricing/order-payment.d.ts +0 -2
  128. package/lib/pricing/order-payment.js +0 -33
  129. package/lib/pricing/order-round.d.ts +0 -10
  130. package/lib/pricing/order-round.js +0 -135
  131. package/lib/pricing/product-catalog-price-options.d.ts +0 -2
  132. package/lib/pricing/product-catalog-price-options.js +0 -51
  133. package/lib/pricing/product-catalog-price.d.ts +0 -2
  134. package/lib/pricing/product-catalog-price.js +0 -60
  135. package/lib/pricing/product-discount.d.ts +0 -2
  136. package/lib/pricing/product-discount.js +0 -69
  137. package/lib/pricing/product-price-rateconversion.d.ts +0 -2
  138. package/lib/pricing/product-price-rateconversion.js +0 -53
  139. package/lib/pricing/product-round.d.ts +0 -10
  140. package/lib/pricing/product-round.js +0 -44
  141. package/lib/pricing/product-swiss-tax.d.ts +0 -2
  142. package/lib/pricing/product-swiss-tax.js +0 -76
  143. package/lib/quotations/manual.d.ts +0 -1
  144. package/lib/quotations/manual.js +0 -20
  145. package/lib/warehousing/eth-minter.d.ts +0 -1
  146. package/lib/warehousing/eth-minter.js +0 -120
  147. package/lib/warehousing/store.d.ts +0 -1
  148. package/lib/warehousing/store.js +0 -34
  149. package/lib/worker/budgetsms.d.ts +0 -9
  150. package/lib/worker/budgetsms.js +0 -169
  151. package/lib/worker/bulk-export.d.ts +0 -2
  152. package/lib/worker/bulk-export.js +0 -64
  153. package/lib/worker/bulk-import.d.ts +0 -2
  154. package/lib/worker/bulk-import.js +0 -65
  155. package/lib/worker/bulkgate.d.ts +0 -1
  156. package/lib/worker/bulkgate.js +0 -91
  157. package/lib/worker/email.d.ts +0 -1
  158. package/lib/worker/email.js +0 -136
  159. package/lib/worker/enrollment-order-generator.d.ts +0 -1
  160. package/lib/worker/enrollment-order-generator.js +0 -77
  161. package/lib/worker/error-notifications.d.ts +0 -9
  162. package/lib/worker/error-notifications.js +0 -61
  163. package/lib/worker/export-token.d.ts +0 -4
  164. package/lib/worker/export-token.js +0 -26
  165. package/lib/worker/external.d.ts +0 -2
  166. package/lib/worker/external.js +0 -13
  167. package/lib/worker/heartbeat.d.ts +0 -1
  168. package/lib/worker/heartbeat.js +0 -26
  169. package/lib/worker/http-request.d.ts +0 -8
  170. package/lib/worker/http-request.js +0 -56
  171. package/lib/worker/message.d.ts +0 -10
  172. package/lib/worker/message.js +0 -42
  173. package/lib/worker/push-notification.d.ts +0 -1
  174. package/lib/worker/push-notification.js +0 -87
  175. package/lib/worker/twilio.d.ts +0 -1
  176. package/lib/worker/twilio.js +0 -59
  177. package/lib/worker/update-coinbase-rates.d.ts +0 -1
  178. package/lib/worker/update-coinbase-rates.js +0 -59
  179. package/lib/worker/update-ecb-rates.d.ts +0 -1
  180. package/lib/worker/update-ecb-rates.js +0 -92
  181. package/lib/worker/update-token-ownership.d.ts +0 -3
  182. package/lib/worker/update-token-ownership.js +0 -57
  183. package/lib/worker/zombie-killer.d.ts +0 -13
  184. package/lib/worker/zombie-killer.js +0 -91
@@ -1,169 +0,0 @@
1
- import { WorkerAdapter, WorkerDirector } from '@unchainedshop/core';
2
- const { BUDGETSMS_USERNAME, BUDGETSMS_USERID, BUDGETSMS_HANDLE } = process.env;
3
- const BudgetSMSWorker = {
4
- ...WorkerAdapter,
5
- key: 'shop.unchained.worker-plugin.budgetsms',
6
- label: 'Send Messages through BudgetSMS',
7
- version: '1.0.0',
8
- type: 'BUDGETSMS',
9
- doWork: async ({ from, to, text, test = false, customid, price = false, mccmnc = false, credit = false, ...params }) => {
10
- try {
11
- if (!BUDGETSMS_USERNAME || !BUDGETSMS_USERID || !BUDGETSMS_HANDLE) {
12
- throw new Error('Missing BudgetSMS credentials. Please set BUDGETSMS_USERNAME, BUDGETSMS_USERID, and BUDGETSMS_HANDLE');
13
- }
14
- const username = BUDGETSMS_USERNAME.trim();
15
- const userid = BUDGETSMS_USERID.trim();
16
- const handle = BUDGETSMS_HANDLE.trim();
17
- if (!/^\d+$/.test(userid)) {
18
- throw new Error('BUDGETSMS_USERID must be numeric only. Found: ' + userid);
19
- }
20
- const url = test ? 'https://api.budgetsms.net/testsms/' : 'https://api.budgetsms.net/sendsms/';
21
- const formattedTo = to.replace(/^\+|^00/, '').replace(/[\s-]/g, '');
22
- const queryParams = new URLSearchParams({
23
- username: username,
24
- userid: userid,
25
- handle: handle,
26
- msg: text || '',
27
- from: from || '',
28
- to: formattedTo,
29
- ...(customid && { customid }),
30
- ...(!test && price && { price: '1' }),
31
- ...(!test && mccmnc && { mccmnc: '1' }),
32
- ...(!test && credit && { credit: '1' }),
33
- ...params,
34
- });
35
- const fullUrl = `${url}?${queryParams.toString()}`;
36
- const response = await fetch(fullUrl, {
37
- method: 'GET',
38
- headers: {
39
- Accept: 'text/plain',
40
- 'User-Agent': 'Unchained/BudgetSMS-Plugin',
41
- },
42
- });
43
- const responseText = await response.text().then((text) => text.trim());
44
- if (responseText.startsWith('OK')) {
45
- const parts = responseText.split(' ');
46
- const result = {
47
- sms_id: parts[1] || null,
48
- status: test ? 'test_successful' : 'sent',
49
- test_mode: test,
50
- };
51
- if (test) {
52
- result.message = 'Test SMS validated successfully (no credit deducted)';
53
- }
54
- else {
55
- let index = 2;
56
- if (price && parts[index] && parts[index + 1]) {
57
- result.price = parseFloat(parts[index]);
58
- result.parts = parseInt(parts[index + 1]);
59
- index += 2;
60
- }
61
- if (mccmnc && parts[index]) {
62
- result.mccmnc = parts[index];
63
- index += 1;
64
- }
65
- if (credit && parts[index]) {
66
- result.remaining_credit = parseFloat(parts[index]);
67
- }
68
- }
69
- return {
70
- success: true,
71
- result,
72
- error: null,
73
- };
74
- }
75
- if (responseText.startsWith('ERR')) {
76
- const parts = responseText.split(' ');
77
- const errorCode = parts[1] || 'UNKNOWN';
78
- const errorMessages = {
79
- '1001': 'Authentication failed OR insufficient credit (BudgetSMS returns 1001 for both)',
80
- '1002': 'Account not active',
81
- '1003': 'Insufficient credit',
82
- '1004': 'No access to this API',
83
- '1005': 'No handle provided',
84
- '1006': 'No UserID provided',
85
- '1007': 'No Username provided',
86
- '2001': 'SMS message text is empty',
87
- '2002': 'SMS numeric senderid can be max. 16 numbers',
88
- '2003': 'SMS alphanumeric sender can be max. 11 characters',
89
- '2004': 'SMS senderid is empty or invalid',
90
- '2005': 'Destination number is too short',
91
- '2006': 'Destination is not numeric',
92
- '2007': 'Destination is empty',
93
- '2008': 'SMS text is not OK (check encoding?)',
94
- '2009': 'Parameter issue',
95
- '2010': 'Destination number is invalidly formatted',
96
- '2011': 'Destination is invalid',
97
- '2012': 'SMS message text is too long',
98
- '2013': 'SMS message is invalid',
99
- '2014': 'SMS CustomID is used before',
100
- '2015': 'Charset problem',
101
- '2016': 'Invalid UTF-8 encoding',
102
- '3001': 'No route to destination',
103
- '3002': 'No routes are setup',
104
- '3003': 'Invalid destination',
105
- '4001': 'System error, related to customid',
106
- '4002': 'System error, temporary issue',
107
- };
108
- let message = errorMessages[errorCode] || `Unknown error code: ${errorCode}`;
109
- if (errorCode === '1001') {
110
- message += '. Note: Check your account balance - BudgetSMS may return 1001 when credit is 0.';
111
- }
112
- return {
113
- success: false,
114
- error: {
115
- name: 'BUDGETSMS_ERROR',
116
- code: errorCode,
117
- message,
118
- },
119
- };
120
- }
121
- return {
122
- success: false,
123
- error: {
124
- name: 'BUDGETSMS_ERROR',
125
- message: 'Unexpected response format from BudgetSMS API',
126
- response: responseText,
127
- },
128
- };
129
- }
130
- catch (err) {
131
- return {
132
- success: false,
133
- error: {
134
- name: err.name,
135
- message: err.message,
136
- stack: err.stack,
137
- },
138
- };
139
- }
140
- },
141
- };
142
- WorkerDirector.registerAdapter(BudgetSMSWorker);
143
- export async function checkBudgetSmsCredentials() {
144
- const url = 'https://api.budgetsms.net/checkcredit/';
145
- const username = process.env.BUDGETSMS_USERNAME?.trim();
146
- const userid = process.env.BUDGETSMS_USERID?.trim();
147
- const handle = process.env.BUDGETSMS_HANDLE?.trim();
148
- if (!username || !userid || !handle) {
149
- return { error: 'Missing credentials' };
150
- }
151
- if (!/^\d+$/.test(userid)) {
152
- return { error: 'UserID must be numeric only' };
153
- }
154
- const queryParams = new URLSearchParams({ username, userid, handle });
155
- try {
156
- const response = await fetch(`${url}?${queryParams.toString()}`, { method: 'GET' });
157
- const text = await response.text();
158
- if (text.startsWith('OK')) {
159
- const credit = parseFloat(text.split(' ')[1]) || 0;
160
- return { success: true, credit };
161
- }
162
- else {
163
- return { error: text };
164
- }
165
- }
166
- catch (err) {
167
- return { error: err.message };
168
- }
169
- }
@@ -1,2 +0,0 @@
1
- import { type IWorkerAdapter } from '@unchainedshop/core';
2
- export declare const BulkExportWorker: IWorkerAdapter<any, any>;
@@ -1,64 +0,0 @@
1
- import { WorkerDirector, WorkerAdapter } from '@unchainedshop/core';
2
- import { createLogger } from '@unchainedshop/logger';
3
- const isSupportedLocale = (locale) => {
4
- try {
5
- const dtf = new Intl.DateTimeFormat(locale);
6
- const resolved = dtf.resolvedOptions().locale;
7
- return resolved.toLowerCase() === locale.toLowerCase();
8
- }
9
- catch (e) {
10
- console.error(e);
11
- return false;
12
- }
13
- };
14
- const createLanguageDialectList = (languages, countries) => {
15
- const result = new Set();
16
- (languages || []).forEach(({ isoCode: baseIsoCode }) => {
17
- result.add(baseIsoCode);
18
- (countries || []).forEach(({ isoCode: countryIsoCode }) => {
19
- const dialectIsoCode = [baseIsoCode, countryIsoCode.toUpperCase()].join('-');
20
- if (isSupportedLocale(dialectIsoCode))
21
- result.add(dialectIsoCode);
22
- });
23
- });
24
- return Array.from(result);
25
- };
26
- const logger = createLogger('unchained:bulk-export');
27
- export const BulkExportWorker = {
28
- ...WorkerAdapter,
29
- key: 'shop.unchained.worker-plugin.bulk-export',
30
- label: 'Bulk Export',
31
- version: '2.1.0',
32
- type: 'BULK_EXPORT',
33
- maxParallelAllocations: 1,
34
- doWork: async (payload, unchainedAPI) => {
35
- try {
36
- const { modules } = unchainedAPI;
37
- const languages = await modules.languages.findLanguages({ includeInactive: false });
38
- const countries = await modules.countries.findCountries({ includeInactive: false });
39
- const bulkExporter = unchainedAPI.bulkExporter.createBulkExporter({ entity: payload.type });
40
- await bulkExporter.validate(payload);
41
- const locales = createLanguageDialectList(languages, countries);
42
- const [result, error] = await bulkExporter.execute(payload, locales, unchainedAPI);
43
- if (error) {
44
- return {
45
- success: false,
46
- result: result,
47
- error,
48
- };
49
- }
50
- return {
51
- success: true,
52
- result,
53
- };
54
- }
55
- catch (err) {
56
- logger.error(err);
57
- return {
58
- success: false,
59
- error: { name: err.name, message: err.message, stack: err.stack },
60
- };
61
- }
62
- },
63
- };
64
- WorkerDirector.registerAdapter(BulkExportWorker);
@@ -1,2 +0,0 @@
1
- import { type IWorkerAdapter } from '@unchainedshop/core';
2
- export declare const BulkImportWorker: IWorkerAdapter<any, Record<string, any>>;
@@ -1,65 +0,0 @@
1
- import { WorkerDirector, WorkerAdapter } from '@unchainedshop/core';
2
- import { createLogger } from '@unchainedshop/logger';
3
- const logger = createLogger('unchained:bulk-import');
4
- export const BulkImportWorker = {
5
- ...WorkerAdapter,
6
- key: 'shop.unchained.worker-plugin.bulk-import',
7
- label: 'Bulk Import',
8
- version: '1.0.0',
9
- type: 'BULK_IMPORT',
10
- maxParallelAllocations: 1,
11
- doWork: async (rawPayload, unchainedAPI) => {
12
- try {
13
- const { createShouldUpsertIfIDExists = false, skipCacheInvalidation = false, updateShouldUpsertIfIDNotExists = false, } = rawPayload;
14
- const bulkImporter = unchainedAPI.bulkImporter.createBulkImporter({
15
- createShouldUpsertIfIDExists,
16
- updateShouldUpsertIfIDNotExists,
17
- skipCacheInvalidation,
18
- });
19
- if (rawPayload.payloadId) {
20
- const readStream = await unchainedAPI.services.files.createDownloadStream({
21
- fileId: rawPayload.payloadId,
22
- });
23
- if (!readStream) {
24
- throw new Error('Could not create download stream from uploaded file');
25
- }
26
- await unchainedAPI.bulkImporter.pipeEventStream(readStream, bulkImporter, unchainedAPI);
27
- }
28
- else {
29
- const { events } = rawPayload;
30
- if (!events?.length)
31
- throw new Error('No events submitted');
32
- await events.reduce(async (currentEventPromise, nextEvent) => {
33
- await currentEventPromise;
34
- await bulkImporter.validate(nextEvent);
35
- return bulkImporter.prepare(nextEvent, unchainedAPI);
36
- }, Promise.resolve());
37
- }
38
- const [result, error] = await bulkImporter.execute();
39
- await bulkImporter.invalidateCaches(unchainedAPI);
40
- if (error) {
41
- return {
42
- success: false,
43
- result: result,
44
- error,
45
- };
46
- }
47
- return {
48
- success: true,
49
- result: result,
50
- };
51
- }
52
- catch (err) {
53
- logger.error(err);
54
- return {
55
- success: false,
56
- error: {
57
- name: err.name,
58
- message: err.message,
59
- stack: err.stack,
60
- },
61
- };
62
- }
63
- },
64
- };
65
- WorkerDirector.registerAdapter(BulkImportWorker);
@@ -1 +0,0 @@
1
- export {};
@@ -1,91 +0,0 @@
1
- import { WorkerAdapter, WorkerDirector } from '@unchainedshop/core';
2
- const { BULKGATE_APPLICATION_ID, BULKGATE_APPLICATION_TOKEN } = process.env;
3
- const BulkGateWorker = {
4
- ...WorkerAdapter,
5
- key: 'shop.unchained.worker-plugin.bulkgate',
6
- label: 'Send SMS through BulkGate',
7
- version: '1.0.0',
8
- type: 'BULKGATE',
9
- doWork: async ({ from, to, text, unicode = false, country, schedule, promotional = false, ...params }) => {
10
- try {
11
- const url = promotional
12
- ? 'https://portal.bulkgate.com/api/1.0/simple/promotional'
13
- : 'https://portal.bulkgate.com/api/1.0/simple/transactional';
14
- const requestBody = {
15
- application_id: BULKGATE_APPLICATION_ID,
16
- application_token: BULKGATE_APPLICATION_TOKEN,
17
- number: to,
18
- text: text || '',
19
- unicode: unicode,
20
- sender_id: from ? 'gText' : 'gSystem',
21
- sender_id_value: from || '',
22
- ...(country && { country }),
23
- ...(schedule && { schedule }),
24
- ...params,
25
- };
26
- const response = await fetch(url, {
27
- method: 'POST',
28
- headers: {
29
- 'Content-Type': 'application/json',
30
- 'Cache-Control': 'no-cache',
31
- },
32
- body: JSON.stringify(requestBody),
33
- });
34
- const responseData = await response.json();
35
- if (responseData.error || responseData.type) {
36
- return {
37
- success: false,
38
- error: {
39
- name: 'BULKGATE_ERROR',
40
- message: responseData.error ||
41
- `Failed to send ${promotional ? 'promotional' : 'transactional'} SMS`,
42
- type: responseData.type || null,
43
- code: responseData.code || response.status,
44
- detail: responseData.detail || null,
45
- },
46
- };
47
- }
48
- if (responseData.data) {
49
- if (!promotional && responseData.data.status === 'accepted') {
50
- return {
51
- success: true,
52
- result: {
53
- sms_id: responseData.data.sms_id,
54
- price: responseData.data.price,
55
- credit: responseData.data.credit,
56
- number: responseData.data.number,
57
- status: responseData.data.status,
58
- },
59
- error: null,
60
- };
61
- }
62
- if (promotional || responseData.data.status) {
63
- return {
64
- success: true,
65
- result: responseData.data,
66
- error: null,
67
- };
68
- }
69
- }
70
- return {
71
- success: false,
72
- error: {
73
- name: 'BULKGATE_ERROR',
74
- message: 'Unexpected response format from BulkGate API',
75
- response: responseData,
76
- },
77
- };
78
- }
79
- catch (err) {
80
- return {
81
- success: false,
82
- error: {
83
- name: err.name,
84
- message: err.message,
85
- stack: err.stack,
86
- },
87
- };
88
- }
89
- },
90
- };
91
- WorkerDirector.registerAdapter(BulkGateWorker);
@@ -1 +0,0 @@
1
- export declare const checkEmailInterceptionEnabled: () => boolean;
@@ -1,136 +0,0 @@
1
- import { WorkerDirector, WorkerAdapter } from '@unchainedshop/core';
2
- import { spawn } from 'node:child_process';
3
- import { writeFile, mkdtemp } from 'node:fs/promises';
4
- import { tmpdir } from 'node:os';
5
- import { join } from 'node:path';
6
- import { createLogger } from '@unchainedshop/logger';
7
- const logger = createLogger('unchained:worker:email');
8
- export const checkEmailInterceptionEnabled = () => {
9
- return process.env.NODE_ENV !== 'production' && !process.env.UNCHAINED_DISABLE_EMAIL_INTERCEPTION;
10
- };
11
- const buildLink = async ({ filename, content, href, contentType, encoding, path }) => {
12
- if (path) {
13
- return `<a href="file:/${path.startsWith('/') ? path : `${process.cwd()}/${path}`}">${filename}</a>`;
14
- }
15
- if (href) {
16
- return `<a href="${href}">${filename}</a>`;
17
- }
18
- if (content && encoding === 'base64') {
19
- return `<a target="_blank" href="${`data:${contentType};base64,${content}`}">${filename}</a>`;
20
- }
21
- return '';
22
- };
23
- let nodemailer;
24
- try {
25
- const nodemailerModule = await import('nodemailer');
26
- nodemailer = nodemailerModule.default;
27
- }
28
- catch {
29
- logger.warn(`optional peer npm package 'nodemailer' not installed, emails can't be sent`);
30
- }
31
- const openInBrowser = async (options) => {
32
- const command = {
33
- darwin: 'open',
34
- win32: 'explorer.exe',
35
- linux: 'xdg-open',
36
- }[process.platform];
37
- if (!command) {
38
- return false;
39
- }
40
- const messageBody = options.html || options.text.replace(/(\r\n|\n|\r)/gm, '<br/>');
41
- const attachmentLinks = await Promise.all((options.attachments || []).map(buildLink));
42
- const content = `
43
- <!DOCTYPE html>
44
- <html lang="en" xmlns="https://www.w3.org/1999/xhtml" xmlns:o="urn:schemas-microsoft-com:office:office">
45
- <head>
46
- <meta charset="UTF-8"/>
47
- <meta name="viewport" content="width=device-width,initial-scale=1">
48
- </head>
49
- <body>
50
- <b>From:&nbsp</b>${options.from}<br/>
51
- <b>To:&nbsp;</b>${options.to}<br/>
52
- <b>Cc:&nbsp;</b>${options.cc}<br/>
53
- <b>Bcc:&nbsp;</b>${options.bcc}<br/>
54
- <b>Reply-To:&nbsp;</b>${options.replyTo}<br/>
55
- <br/>
56
- <b>subject:&nbsp;</b>${options.subject}<br/>
57
- <b>attachments:&nbsp;</b>${attachmentLinks.join(',&nbsp;')}<br/>
58
- <hr/>
59
- ${messageBody}
60
- </body>
61
- </html>`;
62
- const tempDir = await mkdtemp(join(tmpdir(), 'unchained-email-'));
63
- const tempFile = join(tempDir, 'email-preview.html');
64
- await writeFile(tempFile, content, 'utf8');
65
- return new Promise((resolve) => {
66
- const child = spawn(command, [tempFile], {
67
- detached: true,
68
- stdio: 'ignore',
69
- });
70
- child.unref();
71
- resolve(true);
72
- });
73
- };
74
- const EmailWorkerPlugin = {
75
- ...WorkerAdapter,
76
- key: 'shop.unchained.worker-plugin.email',
77
- label: 'Send a Mail through Nodemailer',
78
- version: '1.0.0',
79
- type: 'EMAIL',
80
- doWork: async ({ from, to, subject, ...rest }) => {
81
- if (!to) {
82
- return {
83
- success: false,
84
- error: {
85
- name: 'RECIPIENT_REQUIRED',
86
- message: 'EMAIL requires a to',
87
- },
88
- };
89
- }
90
- try {
91
- const sendMailOptions = {
92
- from,
93
- to,
94
- subject,
95
- ...rest,
96
- };
97
- if (checkEmailInterceptionEnabled()) {
98
- const opened = await openInBrowser(sendMailOptions);
99
- return {
100
- success: opened,
101
- result: opened ? { intercepted: true } : undefined,
102
- error: !opened ? { message: "Interception failed due to missing package 'open'" } : undefined,
103
- };
104
- }
105
- if (!process.env.MAIL_URL) {
106
- return {
107
- success: false,
108
- error: { name: 'NO_MAIL_URL_SET', message: 'MAIL_URL is not set' },
109
- };
110
- }
111
- if (!nodemailer) {
112
- return {
113
- success: false,
114
- error: {
115
- name: 'NODEMAILER_NOT_INSTALLED',
116
- message: 'npm dependency nodemailer is not installed, please install it to use email features',
117
- },
118
- };
119
- }
120
- const transporter = nodemailer.createTransport(process.env.MAIL_URL);
121
- const result = await transporter.sendMail(sendMailOptions);
122
- return { success: true, result };
123
- }
124
- catch (err) {
125
- return {
126
- success: false,
127
- error: {
128
- name: err.name,
129
- message: err.message,
130
- stack: err.stack,
131
- },
132
- };
133
- }
134
- },
135
- };
136
- WorkerDirector.registerAdapter(EmailWorkerPlugin);
@@ -1 +0,0 @@
1
- export declare const configureGenerateOrderAutoscheduling: () => void;
@@ -1,77 +0,0 @@
1
- import { enrollmentsSettings, EnrollmentStatus } from '@unchainedshop/core-enrollments';
2
- import { EnrollmentDirector, WorkerDirector, WorkerAdapter, } from '@unchainedshop/core';
3
- const GenerateOrderWorker = {
4
- ...WorkerAdapter,
5
- key: 'shop.unchained.worker-plugin.generate-enrollment-orders',
6
- label: 'Generates new Orders from Enrollments',
7
- version: '1.0.0',
8
- type: 'ENROLLMENT_ORDER_GENERATOR',
9
- doWork: async (input, unchainedAPI) => {
10
- const { modules, services } = unchainedAPI;
11
- const enrollments = await modules.enrollments.findEnrollments({
12
- status: [EnrollmentStatus.ACTIVE, EnrollmentStatus.PAUSED],
13
- });
14
- const errors = (await Promise.all(enrollments.map(async (enrollment) => {
15
- try {
16
- const product = await unchainedAPI.modules.products.findProduct({
17
- productId: enrollment.productId,
18
- });
19
- const director = await EnrollmentDirector.actions({ enrollment, product: product }, unchainedAPI);
20
- const period = await director.nextPeriod();
21
- if (period) {
22
- if (period.isTrial) {
23
- await modules.enrollments.addEnrollmentPeriod(enrollment._id, {
24
- ...period,
25
- });
26
- return null;
27
- }
28
- const configuration = await director.configurationForOrder({
29
- period,
30
- });
31
- if (configuration) {
32
- const order = await services.enrollments.generateOrderFromEnrollment(enrollment, configuration);
33
- if (order) {
34
- await modules.enrollments.addEnrollmentPeriod(enrollment._id, {
35
- ...period,
36
- orderId: order._id,
37
- });
38
- }
39
- }
40
- }
41
- }
42
- catch (e) {
43
- return {
44
- name: e.name,
45
- message: e.message,
46
- stack: e.stack,
47
- };
48
- }
49
- return null;
50
- }))).filter(Boolean);
51
- if (errors.length) {
52
- return {
53
- success: false,
54
- error: {
55
- name: 'SOME_ENROLLMENTS_COULD_NOT_PROCESS',
56
- message: 'Some errors have been reported during order generation',
57
- logs: errors,
58
- },
59
- result: {},
60
- };
61
- }
62
- return {
63
- success: true,
64
- result: input,
65
- };
66
- },
67
- };
68
- WorkerDirector.registerAdapter(GenerateOrderWorker);
69
- export const configureGenerateOrderAutoscheduling = () => {
70
- if (enrollmentsSettings.autoSchedulingSchedule) {
71
- WorkerDirector.configureAutoscheduling({
72
- type: GenerateOrderWorker.type,
73
- schedule: enrollmentsSettings.autoSchedulingSchedule,
74
- retries: 5,
75
- });
76
- }
77
- };
@@ -1,9 +0,0 @@
1
- import { type IWorkerAdapter } from '@unchainedshop/core';
2
- interface Arg {
3
- secondsPassed?: number;
4
- }
5
- interface Result {
6
- forked?: string;
7
- }
8
- export declare const ErrorNotifications: IWorkerAdapter<Arg, Result>;
9
- export default ErrorNotifications;