@unchainedshop/plugins 3.0.0-rc1 → 3.0.0-rc10

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 (74) hide show
  1. package/lib/events/node-event-emitter.js +1 -1
  2. package/lib/events/node-event-emitter.js.map +1 -1
  3. package/lib/files/gridfs/gridfs-adapter.d.ts +7 -1
  4. package/lib/files/gridfs/gridfs-adapter.d.ts.map +1 -1
  5. package/lib/files/gridfs/gridfs-adapter.js +2 -3
  6. package/lib/files/gridfs/gridfs-adapter.js.map +1 -1
  7. package/lib/files/gridfs/gridfs-webhook.js +2 -2
  8. package/lib/files/gridfs/gridfs-webhook.js.map +1 -1
  9. package/lib/files/gridfs/index.d.ts +1 -0
  10. package/lib/files/gridfs/index.d.ts.map +1 -1
  11. package/lib/files/minio/minio-adapter.d.ts.map +1 -1
  12. package/lib/files/minio/minio-adapter.js +6 -23
  13. package/lib/files/minio/minio-adapter.js.map +1 -1
  14. package/lib/payment/apple-iap/adapter.js +1 -1
  15. package/lib/payment/apple-iap/adapter.js.map +1 -1
  16. package/lib/payment/datatrans-v2/api/makeFetcher.d.ts.map +1 -1
  17. package/lib/payment/datatrans-v2/api/makeFetcher.js +5 -9
  18. package/lib/payment/datatrans-v2/api/makeFetcher.js.map +1 -1
  19. package/lib/payment/paypal-checkout.js +2 -0
  20. package/lib/payment/paypal-checkout.js.map +1 -1
  21. package/lib/payment/payrexx/api/makeFetcher.d.ts.map +1 -1
  22. package/lib/payment/payrexx/api/makeFetcher.js +7 -12
  23. package/lib/payment/payrexx/api/makeFetcher.js.map +1 -1
  24. package/lib/payment/stripe/stripe.d.ts.map +1 -1
  25. package/lib/payment/stripe/stripe.js +3 -1
  26. package/lib/payment/stripe/stripe.js.map +1 -1
  27. package/lib/pricing/discount-100-off.d.ts +2 -2
  28. package/lib/pricing/discount-100-off.d.ts.map +1 -1
  29. package/lib/pricing/discount-100-off.js.map +1 -1
  30. package/lib/pricing/discount-half-price-manual.d.ts +2 -2
  31. package/lib/pricing/discount-half-price-manual.d.ts.map +1 -1
  32. package/lib/pricing/discount-half-price-manual.js.map +1 -1
  33. package/lib/pricing/discount-half-price.d.ts +2 -2
  34. package/lib/pricing/discount-half-price.d.ts.map +1 -1
  35. package/lib/pricing/discount-half-price.js.map +1 -1
  36. package/lib/worker/email.d.ts.map +1 -1
  37. package/lib/worker/email.js +17 -14
  38. package/lib/worker/email.js.map +1 -1
  39. package/package.json +110 -27
  40. package/src/events/node-event-emitter.ts +1 -1
  41. package/src/files/gridfs/gridfs-adapter.ts +14 -7
  42. package/src/files/gridfs/gridfs-webhook.ts +2 -2
  43. package/src/files/gridfs/index.ts +2 -0
  44. package/src/files/minio/minio-adapter.ts +7 -26
  45. package/src/payment/apple-iap/adapter.ts +1 -1
  46. package/src/payment/datatrans-v2/api/makeFetcher.ts +8 -11
  47. package/src/payment/paypal-checkout.ts +2 -0
  48. package/src/payment/payrexx/api/makeFetcher.ts +10 -13
  49. package/src/payment/stripe/stripe.ts +3 -1
  50. package/src/pricing/discount-100-off.ts +1 -2
  51. package/src/pricing/discount-half-price-manual.ts +1 -2
  52. package/src/pricing/discount-half-price.ts +1 -2
  53. package/src/worker/email.ts +19 -14
  54. package/tests/mock/datatrans/v1/secure-fields.json +4 -0
  55. package/tests/mock/datatrans/v1/transactions/authorize.json +48 -0
  56. package/tests/mock/datatrans/v1/transactions/card_check_authorized.json +47 -0
  57. package/tests/mock/datatrans/v1/transactions/payment_alias_authorized/settle.json +1 -0
  58. package/tests/mock/datatrans/v1/transactions/payment_alias_authorized.json +48 -0
  59. package/tests/mock/datatrans/v1/transactions/payment_authorized/cancel.json +1 -0
  60. package/tests/mock/datatrans/v1/transactions/payment_authorized/settle.json +1 -0
  61. package/tests/mock/datatrans/v1/transactions/payment_authorized.json +48 -0
  62. package/tests/mock/datatrans/v1/transactions/payment_authorized_low_amount/cancel.json +1 -0
  63. package/tests/mock/datatrans/v1/transactions/payment_authorized_low_amount.json +48 -0
  64. package/tests/mock/datatrans/v1/transactions/validate.json +1 -0
  65. package/tests/mock/datatrans/v1/transactions.json +4 -0
  66. package/tests/mock/payrexx/Gateway/1000001.json +106 -0
  67. package/tests/mock/payrexx/Gateway.json +24 -0
  68. package/tests/mock/payrexx/transaction_example1.json +65 -0
  69. package/tests/mock/payrexx/transaction_example2.json +65 -0
  70. package/tests/mock/payrexx/transaction_example3.json +94 -0
  71. package/lib/payment/datatrans-v2/generateSignature copy.d.ts +0 -11
  72. package/lib/payment/datatrans-v2/generateSignature copy.d.ts.map +0 -1
  73. package/lib/payment/datatrans-v2/generateSignature copy.js +0 -19
  74. package/lib/payment/datatrans-v2/generateSignature copy.js.map +0 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unchainedshop/plugins",
3
- "version": "3.0.0-rc1",
3
+ "version": "3.0.0-rc10",
4
4
  "main": "lib/plugins-index.js",
5
5
  "types": "lib/plugins-index.d.ts",
6
6
  "exports": {
@@ -25,54 +25,137 @@
25
25
  "ecommerce",
26
26
  "core"
27
27
  ],
28
- "author": "Joël Meiller",
28
+ "authors": [
29
+ "Joël Meiller",
30
+ "Pascal Kaufmann"
31
+ ],
29
32
  "license": "EUPL-1.2",
30
33
  "bugs": {
31
34
  "url": "https://github.com/unchainedshop/unchained/issues"
32
35
  },
33
36
  "homepage": "https://github.com/unchainedshop/unchained#readme",
34
37
  "dependencies": {
35
- "@unchainedshop/api": "^3.0.0-rc1",
36
- "@unchainedshop/core-delivery": "^3.0.0-rc1",
37
- "@unchainedshop/core-enrollments": "^3.0.0-rc1",
38
- "@unchainedshop/core-orders": "^3.0.0-rc1",
39
- "@unchainedshop/core-payment": "^3.0.0-rc1",
40
- "@unchainedshop/core-products": "^3.0.0-rc1",
41
- "@unchainedshop/core-warehousing": "^3.0.0-rc1",
42
- "@unchainedshop/core-worker": "^3.0.0-rc1",
43
- "@unchainedshop/events": "^3.0.0-rc1",
44
- "@unchainedshop/file-upload": "^3.0.0-rc1",
45
- "@unchainedshop/logger": "^3.0.0-rc1",
46
- "@unchainedshop/utils": "^3.0.0-rc1"
38
+ "@breejs/later": "^4.2.0",
39
+ "@unchainedshop/api": "^3.0.0-rc10",
40
+ "@unchainedshop/core-delivery": "^3.0.0-rc10",
41
+ "@unchainedshop/core-enrollments": "^3.0.0-rc10",
42
+ "@unchainedshop/core-orders": "^3.0.0-rc10",
43
+ "@unchainedshop/core-payment": "^3.0.0-rc10",
44
+ "@unchainedshop/core-products": "^3.0.0-rc10",
45
+ "@unchainedshop/core-warehousing": "^3.0.0-rc10",
46
+ "@unchainedshop/core-worker": "^3.0.0-rc10",
47
+ "@unchainedshop/events": "^3.0.0-rc10",
48
+ "@unchainedshop/file-upload": "^3.0.0-rc10",
49
+ "@unchainedshop/logger": "^3.0.0-rc10",
50
+ "@unchainedshop/utils": "^3.0.0-rc10",
51
+ "event-iterator": "^2.0.0",
52
+ "JSONStream": "^1.3.5"
53
+ },
54
+ "peerDependencies": {
55
+ "@aws-sdk/client-eventbridge": ">= 3.714 < 4",
56
+ "@paypal/checkout-server-sdk": "1.x",
57
+ "@redis/client": "1.x",
58
+ "bip32": "4.x",
59
+ "bitcoinjs-lib": ">= 6.1 <7",
60
+ "ethers": ">= 6.13 < 7",
61
+ "expiry-map": "2.x",
62
+ "express": "5.x",
63
+ "mime-types": "2.x",
64
+ "minio": "8.x",
65
+ "nodemailer": ">= 6.9 < 7",
66
+ "open": "10.x",
67
+ "p-memoize": "7.x",
68
+ "postfinancecheckout": ">= 4.5.0",
69
+ "stripe": "^17.4.0",
70
+ "tiny-secp256k1": "2.x",
71
+ "twilio": "5.x",
72
+ "web-push": ">= 3.6 <4",
73
+ "xml-js": ">= 1.6 < 2"
47
74
  },
48
- "optionalDependencies": {
49
- "@aws-sdk/client-eventbridge": "^3.713.0",
75
+ "peerDependenciesMeta": {
76
+ "@aws-sdk/client-eventbridge": {
77
+ "optional": true
78
+ },
79
+ "@paypal/checkout-server-sdk": {
80
+ "optional": true
81
+ },
82
+ "@redis/client": {
83
+ "optional": true
84
+ },
85
+ "bip32": {
86
+ "optional": true
87
+ },
88
+ "bitcoinjs-lib": {
89
+ "optional": true
90
+ },
91
+ "ethers": {
92
+ "optional": true
93
+ },
94
+ "expiry-map": {
95
+ "optional": true
96
+ },
97
+ "express": {
98
+ "optional": true
99
+ },
100
+ "mime-types": {
101
+ "optional": true
102
+ },
103
+ "minio": {
104
+ "optional": true
105
+ },
106
+ "nodemailer": {
107
+ "optional": true
108
+ },
109
+ "open": {
110
+ "optional": true
111
+ },
112
+ "p-memoize": {
113
+ "optional": true
114
+ },
115
+ "postfinancecheckout": {
116
+ "optional": true
117
+ },
118
+ "stripe": {
119
+ "optional": true
120
+ },
121
+ "tiny-secp256k1": {
122
+ "optional": true
123
+ },
124
+ "twilio": {
125
+ "optional": true
126
+ },
127
+ "web-push": {
128
+ "optional": true
129
+ },
130
+ "xml-js": {
131
+ "optional": true
132
+ }
133
+ },
134
+ "devDependencies": {
135
+ "@aws-sdk/client-eventbridge": "^3.716.0",
50
136
  "@breejs/later": "^4.2.0",
51
137
  "@paypal/checkout-server-sdk": "^1.0.3",
52
138
  "@redis/client": "^1.6.0",
139
+ "@types/express": "^5.0.0",
140
+ "@types/node": "^22.10.2",
53
141
  "bip32": "^4.0.0",
54
142
  "bitcoinjs-lib": "^6.1.7",
55
143
  "ethers": "^6.13.4",
56
- "event-iterator": "^2.0.0",
57
144
  "expiry-map": "^2.0.0",
58
- "express": "^4.21.2",
59
- "JSONStream": "^1.3.5",
145
+ "express": "^5.0.1",
146
+ "jest": "^29.7.0",
60
147
  "mime-types": "^2.1.35",
61
- "minio": "^8.0.2",
148
+ "minio": "^8.0.3",
62
149
  "nodemailer": "^6.9.16",
63
150
  "open": "^10.1.0",
64
151
  "p-memoize": "^7.1.1",
65
152
  "postfinancecheckout": "^4.5.0",
66
- "stripe": "^17.4.0",
153
+ "stripe": "^17.5.0",
67
154
  "tiny-secp256k1": "^2.2.3",
155
+ "ts-jest": "^29.2.5",
68
156
  "twilio": "^5.4.0",
157
+ "typescript": "^5.7.2",
69
158
  "web-push": "^3.6.7",
70
159
  "xml-js": "^1.6.11"
71
- },
72
- "devDependencies": {
73
- "@types/node": "^22.10.2",
74
- "jest": "^29.7.0",
75
- "ts-jest": "^29.2.5",
76
- "typescript": "^5.7.2"
77
160
  }
78
161
  }
@@ -1,4 +1,4 @@
1
- import { EventEmitter } from 'events';
1
+ import { EventEmitter } from 'node:events';
2
2
  import { setEmitAdapter, EmitAdapter } from '@unchainedshop/events';
3
3
 
4
4
  const NodeEventEmitter = (): EmitAdapter => {
@@ -1,6 +1,5 @@
1
- import { URL } from 'url';
2
- import { Readable, PassThrough } from 'stream';
3
- import { pipeline } from 'stream/promises';
1
+ import { Readable, PassThrough } from 'node:stream';
2
+ import { pipeline } from 'node:stream/promises';
4
3
  import mimeType from 'mime-types';
5
4
  import {
6
5
  FileAdapter,
@@ -12,6 +11,8 @@ import {
12
11
  import { UploadFileData } from '@unchainedshop/file-upload';
13
12
  import sign from './sign.js';
14
13
  import { filesSettings } from '@unchainedshop/core-files';
14
+ import { UnchainedCore } from '@unchainedshop/core';
15
+ import { GridFSFileUploadsModule } from './index.js';
15
16
 
16
17
  const { ROOT_URL } = process.env;
17
18
 
@@ -23,7 +24,13 @@ const bufferToStream = (buffer: any) => {
23
24
  return stream;
24
25
  };
25
26
 
26
- export const GridFSAdapter: IFileAdapter = {
27
+ export const GridFSAdapter: IFileAdapter<
28
+ UnchainedCore & {
29
+ modules: {
30
+ gridfsFileUploads: GridFSFileUploadsModule;
31
+ };
32
+ }
33
+ > = {
27
34
  key: 'shop.unchained.file-upload-plugin.gridfs',
28
35
  label: 'Uploads files to Database using GridFS',
29
36
  version: '1.0.0',
@@ -64,8 +71,8 @@ export const GridFSAdapter: IFileAdapter = {
64
71
  } as UploadFileData & { putURL: string };
65
72
  },
66
73
 
67
- async uploadFileFromStream(directoryName: string, rawFile: any, { modules }: any) {
68
- let stream;
74
+ async uploadFileFromStream(directoryName: string, rawFile: any, { modules }) {
75
+ let stream: Readable;
69
76
  let fileName;
70
77
  if (rawFile instanceof Promise) {
71
78
  const { filename: f, createReadStream } = await rawFile;
@@ -104,7 +111,7 @@ export const GridFSAdapter: IFileAdapter = {
104
111
  async uploadFileFromURL(
105
112
  directoryName: string,
106
113
  { fileLink, fileName: fname, fileId, headers }: any,
107
- { modules }: any,
114
+ { modules },
108
115
  ) {
109
116
  const { href } = new URL(fileLink);
110
117
  const fileName = decodeURIComponent(fname || href.split('/').pop());
@@ -1,5 +1,5 @@
1
- import { pipeline, finished } from 'stream/promises';
2
- import { PassThrough } from 'stream';
1
+ import { pipeline, finished } from 'node:stream/promises';
2
+ import { PassThrough } from 'node:stream';
3
3
  import { buildHashedFilename } from '@unchainedshop/file-upload';
4
4
  import express from 'express';
5
5
  import sign from './sign.js';
@@ -27,3 +27,5 @@ export const configureGridFSFileUploadModule = ({ db }) => {
27
27
  },
28
28
  };
29
29
  };
30
+
31
+ export type GridFSFileUploadsModule = ReturnType<typeof configureGridFSFileUploadModule>;
@@ -1,7 +1,5 @@
1
- import https from 'https';
2
- import http, { OutgoingHttpHeaders } from 'http';
3
- import { Readable } from 'stream';
4
- import { URL } from 'url';
1
+ import { Readable } from 'node:stream';
2
+ import type { ReadableStream } from 'node:stream/web';
5
3
  import { UploadFileData } from '@unchainedshop/file-upload';
6
4
  import {
7
5
  FileAdapter,
@@ -85,24 +83,6 @@ connectToMinio().then(function setClient(c) {
85
83
  client = c;
86
84
  });
87
85
 
88
- const createHttpDownloadStream = async (
89
- fileUrl: string,
90
- headers: OutgoingHttpHeaders,
91
- ): Promise<http.IncomingMessage> => {
92
- const { href, protocol } = new URL(fileUrl);
93
- return new Promise((resolve, reject) => {
94
- try {
95
- if (protocol === 'http:') {
96
- http.get(href, { headers }, resolve);
97
- } else {
98
- https.get(href, { headers }, resolve);
99
- }
100
- } catch (e) {
101
- reject(e);
102
- }
103
- });
104
- };
105
-
106
86
  const getObjectStats = async (fileName: string) => {
107
87
  if (!client) throw new Error('Minio not connected, check env variables');
108
88
 
@@ -211,9 +191,10 @@ export const MinioAdapter: IFileAdapter = {
211
191
  const fileName = fname || href.split('/').pop();
212
192
  const hashedFilename = await buildHashedFilename(directoryName, fileName, new Date());
213
193
 
214
- const stream = await createHttpDownloadStream(fileLink, headers);
215
- const type = mimeType.lookup(fileName) || stream.headers['content-type'];
216
-
194
+ const url = new URL(fileLink);
195
+ const response = await fetch(url, { headers });
196
+ const type = mimeType.lookup(fileName) || response.headers['content-type'];
197
+ const readable = Readable.fromWeb(response.body as ReadableStream<Uint8Array<ArrayBufferLike>>);
217
198
  const metaData = {
218
199
  'Content-Type': type,
219
200
  };
@@ -221,7 +202,7 @@ export const MinioAdapter: IFileAdapter = {
221
202
  await client.putObject(
222
203
  MINIO_BUCKET_NAME,
223
204
  generateMinioPath(directoryName, hashedFilename),
224
- stream,
205
+ readable,
225
206
  undefined,
226
207
  metaData,
227
208
  );
@@ -63,7 +63,7 @@ const fixPeriods = async (
63
63
  orderId: transaction.transaction_id === transactionId ? orderId : null,
64
64
  };
65
65
  })
66
- .sort((left, right) => {
66
+ .toSorted((left, right) => {
67
67
  return left.end.getTime() - right.end.getTime();
68
68
  });
69
69
 
@@ -1,11 +1,5 @@
1
- import fs from 'fs';
2
- import util from 'util';
3
- import { resolve } from 'path';
4
1
  import { createLogger } from '@unchainedshop/logger';
5
-
6
- const readFile = util.promisify(fs.readFile);
7
-
8
- const { DATATRANS_API_MOCKS_PATH } = process.env;
2
+ const { MOCK_APIS } = process.env;
9
3
 
10
4
  const logger = createLogger('unchained:datatrans');
11
5
 
@@ -14,12 +8,15 @@ export default (
14
8
  merchantId: string,
15
9
  secret: string,
16
10
  ): ((path: string, body: unknown) => Promise<Response>) => {
17
- if (DATATRANS_API_MOCKS_PATH) {
11
+ if (MOCK_APIS) {
18
12
  return async (path): Promise<Response> => {
19
13
  try {
20
- const filePath = resolve(process.env.PWD, DATATRANS_API_MOCKS_PATH, `.${path}.json`);
21
- const content = await readFile(filePath);
22
- const json = JSON.parse(content.toString());
14
+ const { default: json } = await import(
15
+ `${import.meta.dirname}/../../../../tests/mock/datatrans/${path}.json`,
16
+ {
17
+ with: { type: 'json' },
18
+ }
19
+ );
23
20
  return {
24
21
  json: async () => json,
25
22
  status: json?.error ? 500 : 204,
@@ -9,6 +9,8 @@ import { createLogger } from '@unchainedshop/logger';
9
9
 
10
10
  let checkoutNodeJssdk;
11
11
  try {
12
+ // eslint-disable-next-line
13
+ // @ts-ignore
12
14
  checkoutNodeJssdk = await import('@paypal/checkout-server-sdk');
13
15
  } catch {
14
16
  /* */
@@ -1,11 +1,6 @@
1
- import fs from 'fs';
2
- import util from 'util';
3
- import { resolve } from 'path';
4
1
  import { createLogger } from '@unchainedshop/logger';
5
2
 
6
- const readFile = util.promisify(fs.readFile);
7
-
8
- const { PAYREXX_API_MOCKS_PATH } = process.env;
3
+ const { MOCK_APIS } = process.env;
9
4
 
10
5
  const logger = createLogger('unchained:payrexx');
11
6
 
@@ -14,17 +9,19 @@ export default (
14
9
  instance: string = null,
15
10
  secret: string = null,
16
11
  ): ((path: string, method: 'GET' | 'DELETE' | 'PUT' | 'POST', data?: any) => Promise<Response>) => {
17
- if (PAYREXX_API_MOCKS_PATH) {
12
+ if (MOCK_APIS) {
18
13
  return async (path): Promise<Response> => {
19
14
  try {
20
- const filePath = resolve(process.env.PWD, PAYREXX_API_MOCKS_PATH, `${path}.json`);
21
- const content = await readFile(filePath);
22
- const textData = content.toString();
23
- const jsonData = JSON.parse(textData);
15
+ const { default: jsonData } = await import(
16
+ `${import.meta.dirname}/../../../../tests/mock/payrexx/${path}.json`,
17
+ {
18
+ with: { type: 'json' },
19
+ }
20
+ );
24
21
  return {
25
22
  json: async () => jsonData,
26
- text: async () => textData,
27
- ok: !jsonData?.error,
23
+ text: async () => JSON.stringify(jsonData?.error),
24
+ ok: true,
28
25
  status: jsonData?.error ? 500 : 204,
29
26
  } as any;
30
27
  } catch (error) {
@@ -14,9 +14,11 @@ export const initStripeClient = async (): Promise<StripeType> => {
14
14
  logger.warn('STRIPE_SECRET is not set, skipping initialization');
15
15
  return null;
16
16
  }
17
+ // eslint-disable-next-line
18
+ // @ts-ignore
17
19
  const { default: Stripe } = await import('stripe');
18
20
  stripe = new Stripe(STRIPE_SECRET, {
19
- apiVersion: '2024-11-20.acacia',
21
+ apiVersion: '2024-12-18.acacia',
20
22
  });
21
23
  return stripe;
22
24
  };
@@ -2,11 +2,10 @@ import {
2
2
  OrderDiscountDirector,
3
3
  OrderDiscountAdapter,
4
4
  OrderDiscountConfiguration,
5
- UnchainedCore,
6
5
  IDiscountAdapter,
7
6
  } from '@unchainedshop/core';
8
7
 
9
- export const HundredOff: IDiscountAdapter<OrderDiscountConfiguration, UnchainedCore> = {
8
+ export const HundredOff: IDiscountAdapter<OrderDiscountConfiguration> = {
10
9
  ...OrderDiscountAdapter,
11
10
 
12
11
  key: 'shop.unchained.discount.100-off',
@@ -2,11 +2,10 @@ import {
2
2
  OrderDiscountDirector,
3
3
  OrderDiscountAdapter,
4
4
  ProductDiscountConfiguration,
5
- UnchainedCore,
6
5
  IDiscountAdapter,
7
6
  } from '@unchainedshop/core';
8
7
 
9
- export const HalfPriceManual: IDiscountAdapter<ProductDiscountConfiguration, UnchainedCore> = {
8
+ export const HalfPriceManual: IDiscountAdapter<ProductDiscountConfiguration> = {
10
9
  ...OrderDiscountAdapter,
11
10
 
12
11
  key: 'shop.unchained.discount.half-price-manual',
@@ -3,10 +3,9 @@ import {
3
3
  OrderDiscountAdapter,
4
4
  ProductDiscountConfiguration,
5
5
  IDiscountAdapter,
6
- UnchainedCore,
7
6
  } from '@unchainedshop/core';
8
7
 
9
- export const HalfPrice: IDiscountAdapter<ProductDiscountConfiguration, UnchainedCore> = {
8
+ export const HalfPrice: IDiscountAdapter<ProductDiscountConfiguration> = {
10
9
  ...OrderDiscountAdapter,
11
10
 
12
11
  key: 'shop.unchained.discount.half-price',
@@ -1,17 +1,13 @@
1
- import { mkdtemp, writeFile } from 'fs/promises';
2
- import { join, isAbsolute } from 'path';
3
- import { tmpdir } from 'os';
4
1
  import { WorkerDirector, WorkerAdapter, IWorkerAdapter } from '@unchainedshop/core';
5
- import open from 'open';
6
2
  import nodemailer from 'nodemailer';
7
3
 
8
4
  export const checkEmailInterceptionEnabled = () => {
9
5
  return process.env.NODE_ENV !== 'production' && !process.env.UNCHAINED_DISABLE_EMAIL_INTERCEPTION;
10
6
  };
11
7
 
12
- const buildLink = ({ filename, content, href, contentType, encoding, path }) => {
8
+ const buildLink = async ({ filename, content, href, contentType, encoding, path }) => {
13
9
  if (path) {
14
- return `<a href="${isAbsolute(path) ? path : join(process.cwd(), path)}">${filename}</a>`;
10
+ return `<a href="file:/${path.startsWith('/') ? path : `${process.cwd()}/${path}`}">${filename}</a>`;
15
11
  }
16
12
  if (href) {
17
13
  return `<a href="${href}">${filename}</a>`;
@@ -23,8 +19,12 @@ const buildLink = ({ filename, content, href, contentType, encoding, path }) =>
23
19
  };
24
20
 
25
21
  const openInBrowser = async (options) => {
26
- const filename = `${Date.now()}.html`;
22
+ // eslint-disable-next-line
23
+ // @ts-ignore
24
+ const { default: open, apps } = await import('open');
25
+
27
26
  const messageBody = options.html || options.text.replace(/(\r\n|\n|\r)/gm, '<br/>');
27
+ const attachmentLinks = await Promise.all((options.attachments || []).map(buildLink));
28
28
  const content = `
29
29
  <!DOCTYPE html>
30
30
  <html lang="en" xmlns="https://www.w3.org/1999/xhtml" xmlns:o="urn:schemas-microsoft-com:office:office">
@@ -40,16 +40,17 @@ const openInBrowser = async (options) => {
40
40
  <b>Reply-To:&nbsp;</b>${options.replyTo}<br/>
41
41
  <br/>
42
42
  <b>subject:&nbsp;</b>${options.subject}<br/>
43
- <b>attachments:&nbsp;</b>${(options.attachments || []).map(buildLink).join(',&nbsp;')}<br/>
43
+ <b>attachments:&nbsp;</b>${attachmentLinks.join(',&nbsp;')}<br/>
44
44
  <hr/>
45
45
  ${messageBody}
46
46
  </body>
47
47
  </html>`;
48
48
 
49
- const folder = await mkdtemp(join(tmpdir(), 'email-'));
50
- const fileName = `${folder}/${filename}`;
51
- await writeFile(fileName, content);
52
- return open(fileName);
49
+ const base64 = Buffer.from(content).toString('base64');
50
+ const dataUri = `data:text/html;base64,${base64}`;
51
+
52
+ await open(dataUri, { app: [{ name: apps.chrome }, { name: apps.firefox }, { name: apps.browser }] });
53
+ return true;
53
54
  };
54
55
 
55
56
  const EmailWorkerPlugin: IWorkerAdapter<
@@ -87,8 +88,12 @@ const EmailWorkerPlugin: IWorkerAdapter<
87
88
  ...rest,
88
89
  };
89
90
  if (checkEmailInterceptionEnabled()) {
90
- await openInBrowser(sendMailOptions);
91
- return { success: true, result: { intercepted: true } };
91
+ const opened = await openInBrowser(sendMailOptions);
92
+ return {
93
+ success: opened,
94
+ result: opened ? { intercepted: true } : undefined,
95
+ error: !opened ? { message: "Interception failed due to missing package 'open'" } : undefined,
96
+ };
92
97
  }
93
98
  if (!process.env.MAIL_URL) {
94
99
  return {
@@ -0,0 +1,4 @@
1
+ {
2
+ "location": "https://pay.sandbox.datatrans.com/v1/start/new-transaction-secure-fields",
3
+ "transactionId": "new-transaction-secure-fields"
4
+ }
@@ -0,0 +1,48 @@
1
+ {
2
+ "transactionId": "payment_alias_authorized",
3
+ "type": "payment",
4
+ "status": "authorized",
5
+ "currency": "CHF",
6
+ "refno": "MTExMTExMjIyMjI=",
7
+ "refno2": "user",
8
+ "paymentMethod": "VIS",
9
+ "detail": {
10
+ "authorize": {
11
+ "amount": 30000,
12
+ "acquirerAuthorizationCode": "131704"
13
+ }
14
+ },
15
+ "language": "de",
16
+ "card": {
17
+ "alias": "70119122433810042",
18
+ "masked": "424242xxxxxx4242",
19
+ "expiryMonth": "12",
20
+ "expiryYear": "21",
21
+ "info": {
22
+ "brand": "VISA CREDIT",
23
+ "type": "credit",
24
+ "usage": "consumer",
25
+ "country": "GB",
26
+ "issuer": "DATATRANS"
27
+ },
28
+ "3D": {
29
+ "authenticationResponse": "D"
30
+ }
31
+ },
32
+ "history": [
33
+ {
34
+ "action": "init",
35
+ "source": "api",
36
+ "date": "2021-09-03T11:16:50Z",
37
+ "success": true,
38
+ "ip": "212.232.234.26"
39
+ },
40
+ {
41
+ "action": "authorize",
42
+ "source": "redirect",
43
+ "date": "2021-09-03T11:17:04Z",
44
+ "success": true,
45
+ "ip": "212.232.234.26"
46
+ }
47
+ ]
48
+ }
@@ -0,0 +1,47 @@
1
+ {
2
+ "transactionId": "card_check_authorized",
3
+ "type": "card_check",
4
+ "status": "authorized",
5
+ "currency": "CHF",
6
+ "refno": "ZDRkNGQ0ZDRkNA==",
7
+ "refno2": "user",
8
+ "paymentMethod": "VIS",
9
+ "detail": {
10
+ "authorize": {
11
+ "acquirerAuthorizationCode": "131704"
12
+ }
13
+ },
14
+ "language": "de",
15
+ "card": {
16
+ "alias": "70119122433810042",
17
+ "masked": "424242xxxxxx4242",
18
+ "expiryMonth": "12",
19
+ "expiryYear": "21",
20
+ "info": {
21
+ "brand": "VISA CREDIT",
22
+ "type": "credit",
23
+ "usage": "consumer",
24
+ "country": "GB",
25
+ "issuer": "DATATRANS"
26
+ },
27
+ "3D": {
28
+ "authenticationResponse": "D"
29
+ }
30
+ },
31
+ "history": [
32
+ {
33
+ "action": "init",
34
+ "source": "api",
35
+ "date": "2021-09-03T11:16:50Z",
36
+ "success": true,
37
+ "ip": "212.232.234.26"
38
+ },
39
+ {
40
+ "action": "authorize",
41
+ "source": "redirect",
42
+ "date": "2021-09-03T11:17:04Z",
43
+ "success": true,
44
+ "ip": "212.232.234.26"
45
+ }
46
+ ]
47
+ }