From 3c95dc745c9d6102ae2fd0c43c8c804eb6e7d7f1 Mon Sep 17 00:00:00 2001 From: Pascal Kaufmann Date: Thu, 19 Dec 2024 13:28:58 +0100 Subject: [PATCH] Get rid of as many node deps as possible and prefix all with node: to make it more clearly where we use nodejs --- .github/workflows/codeql-analysis.yml | 2 +- examples/kitchensink/load_env.js | 2 +- examples/kitchensink/src/boot.ts | 2 +- packages/api/src/context.ts | 24 +++----------- .../src/express/createBulkImportMiddleware.ts | 3 +- .../express/createERCMetadataMiddleware.ts | 2 +- packages/api/src/express/index.ts | 3 +- packages/api/src/fastify/index.ts | 5 ++- .../src/module/configureOrdersModule.ts | 1 + .../src/module/configureWorkerModule.ts | 2 +- .../file-upload/src/director/FileAdapter.ts | 2 +- packages/mongodb/src/initDb.ts | 4 +-- packages/platform/package.json | 3 +- .../templates/resolveErrorReportTemplate.ts | 4 +-- .../plugins/src/events/node-event-emitter.ts | 2 +- .../src/files/gridfs/gridfs-adapter.ts | 21 ++++++++---- .../src/files/gridfs/gridfs-webhook.ts | 4 +-- packages/plugins/src/files/gridfs/index.ts | 2 ++ .../plugins/src/files/minio/minio-adapter.ts | 33 ++++--------------- .../payment/datatrans-v2/api/makeFetcher.ts | 19 +++++------ .../src/payment/payrexx/api/makeFetcher.ts | 23 ++++++------- packages/plugins/src/worker/email.ts | 33 +++++++++++-------- .../mock/datatrans}/v1/secure-fields.json | 0 .../mock/datatrans}/v1/transactions.json | 0 .../datatrans}/v1/transactions/authorize.json | 0 .../transactions/card_check_authorized.json | 0 .../payment_alias_authorized.json | 0 .../payment_alias_authorized/settle.json | 0 .../v1/transactions/payment_authorized.json | 0 .../payment_authorized/cancel.json | 0 .../payment_authorized/settle.json | 0 .../payment_authorized_low_amount.json | 0 .../payment_authorized_low_amount/cancel.json | 0 .../datatrans}/v1/transactions/validate.json | 0 .../plugins/tests/mock}/payrexx/Gateway.json | 0 .../tests/mock}/payrexx/Gateway/1000001.json | 0 .../mock}/payrexx/transaction_example1.json | 0 .../mock}/payrexx/transaction_example2.json | 0 .../mock}/payrexx/transaction_example3.json | 0 .../src/mobile-tickets/apple-wallet.ts | 2 +- tests/assortment-media.test.js | 6 ++-- tests/jest-global-setup.js | 3 +- tests/media-permissions.test.js | 6 ++-- tests/product-media.test.js | 6 ++-- 44 files changed, 95 insertions(+), 124 deletions(-) rename {tests/mocks/datatrans-v2 => packages/plugins/tests/mock/datatrans}/v1/secure-fields.json (100%) rename {tests/mocks/datatrans-v2 => packages/plugins/tests/mock/datatrans}/v1/transactions.json (100%) rename {tests/mocks/datatrans-v2 => packages/plugins/tests/mock/datatrans}/v1/transactions/authorize.json (100%) rename {tests/mocks/datatrans-v2 => packages/plugins/tests/mock/datatrans}/v1/transactions/card_check_authorized.json (100%) rename {tests/mocks/datatrans-v2 => packages/plugins/tests/mock/datatrans}/v1/transactions/payment_alias_authorized.json (100%) rename {tests/mocks/datatrans-v2 => packages/plugins/tests/mock/datatrans}/v1/transactions/payment_alias_authorized/settle.json (100%) rename {tests/mocks/datatrans-v2 => packages/plugins/tests/mock/datatrans}/v1/transactions/payment_authorized.json (100%) rename {tests/mocks/datatrans-v2 => packages/plugins/tests/mock/datatrans}/v1/transactions/payment_authorized/cancel.json (100%) rename {tests/mocks/datatrans-v2 => packages/plugins/tests/mock/datatrans}/v1/transactions/payment_authorized/settle.json (100%) rename {tests/mocks/datatrans-v2 => packages/plugins/tests/mock/datatrans}/v1/transactions/payment_authorized_low_amount.json (100%) rename {tests/mocks/datatrans-v2 => packages/plugins/tests/mock/datatrans}/v1/transactions/payment_authorized_low_amount/cancel.json (100%) rename {tests/mocks/datatrans-v2 => packages/plugins/tests/mock/datatrans}/v1/transactions/validate.json (100%) rename {tests/mocks => packages/plugins/tests/mock}/payrexx/Gateway.json (100%) rename {tests/mocks => packages/plugins/tests/mock}/payrexx/Gateway/1000001.json (100%) rename {tests/mocks => packages/plugins/tests/mock}/payrexx/transaction_example1.json (100%) rename {tests/mocks => packages/plugins/tests/mock}/payrexx/transaction_example2.json (100%) rename {tests/mocks => packages/plugins/tests/mock}/payrexx/transaction_example3.json (100%) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index db94104d68..7910fe62d8 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -2,7 +2,7 @@ name: "CodeQL" on: push: - branches: ['master', 'v2.x'] + branches: ['master', 'v2.x', 'v3.x'] pull_request: # The branches below must be a subset of the branches above branches: [master] diff --git a/examples/kitchensink/load_env.js b/examples/kitchensink/load_env.js index 1bda1f5a2e..644eb1c93e 100644 --- a/examples/kitchensink/load_env.js +++ b/examples/kitchensink/load_env.js @@ -1,5 +1,5 @@ import dotenv from 'dotenv-extended'; -import fs from 'fs'; +import fs from 'node:fs'; dotenv.load({ silent: Boolean(process.env.SUPPRESS_ENV_ERRORS), diff --git a/examples/kitchensink/src/boot.ts b/examples/kitchensink/src/boot.ts index 4394fd10c6..d6d0b73632 100644 --- a/examples/kitchensink/src/boot.ts +++ b/examples/kitchensink/src/boot.ts @@ -1,5 +1,5 @@ import express from 'express'; -import http from 'http'; +import http from 'node:http'; import { useExecutionCancellation } from 'graphql-yoga'; import { useResponseCache } from '@graphql-yoga/plugin-response-cache'; import { startPlatform, setAccessToken } from '@unchainedshop/platform'; diff --git a/packages/api/src/context.ts b/packages/api/src/context.ts index a9fd4a91c0..96cae353cd 100644 --- a/packages/api/src/context.ts +++ b/packages/api/src/context.ts @@ -1,5 +1,3 @@ -import fs from 'fs'; -import path from 'path'; import { UnchainedCore } from '@unchainedshop/core'; import instantiateLoaders, { UnchainedLoaders } from './loaders/index.js'; import { getLocaleContext, UnchainedLocaleContext } from './locale-context.js'; @@ -58,24 +56,10 @@ export type UnchainedContextResolver = ( }, ) => Promise; -export const loadJSON = (filename) => { - try { - const base = typeof __filename !== 'undefined' && __filename; - if (!base) - return { - version: process.env.npm_package_version, - }; - const absolutePath = path.resolve(path.dirname(base), filename); - const data = JSON.parse(fs.readFileSync(absolutePath, 'utf-8')); - return data; - } catch { - return null; - } -}; - -const packageJson = loadJSON('../package.json'); - -const { UNCHAINED_API_VERSION = packageJson?.version || '2.x' } = process.env; +const { default: packageJson } = await import(`${import.meta.dirname}/../package.json`, { + with: { type: 'json' }, +}); +const { UNCHAINED_API_VERSION = packageJson?.version || '3.x' } = process.env; export const createContextResolver = ( diff --git a/packages/api/src/express/createBulkImportMiddleware.ts b/packages/api/src/express/createBulkImportMiddleware.ts index aecc76bcc0..d515f6d127 100644 --- a/packages/api/src/express/createBulkImportMiddleware.ts +++ b/packages/api/src/express/createBulkImportMiddleware.ts @@ -1,7 +1,6 @@ import { createLogger } from '@unchainedshop/logger'; import { checkAction } from '../acl.js'; import { actions } from '../roles/index.js'; -import { IncomingMessage } from 'http'; import { Context } from '../context.js'; const logger = createLogger('unchained:bulk-import'); @@ -19,7 +18,7 @@ const methodWrongHandler = (res) => () => { }; export default async function bulkImportMiddleware( - req: IncomingMessage & { query?: any; unchainedContext: Context }, + req: Request & { query?: any; unchainedContext: Context }, res, ) { try { diff --git a/packages/api/src/express/createERCMetadataMiddleware.ts b/packages/api/src/express/createERCMetadataMiddleware.ts index c90f1b9b1f..11d61776bd 100644 --- a/packages/api/src/express/createERCMetadataMiddleware.ts +++ b/packages/api/src/express/createERCMetadataMiddleware.ts @@ -1,4 +1,4 @@ -import path from 'path'; +import path from 'node:path'; import { createLogger } from '@unchainedshop/logger'; import { Context } from '../context.js'; import { Request, RequestHandler } from 'express'; diff --git a/packages/api/src/express/index.ts b/packages/api/src/express/index.ts index 1b92c7893d..fcf7d8b508 100644 --- a/packages/api/src/express/index.ts +++ b/packages/api/src/express/index.ts @@ -11,9 +11,8 @@ import { UnchainedCore } from '@unchainedshop/core'; import { emit } from '@unchainedshop/events'; import { API_EVENTS } from '../events.js'; import { User } from '@unchainedshop/core-users'; -import { IncomingMessage } from 'http'; -const resolveUserRemoteAddress = (req: IncomingMessage) => { +const resolveUserRemoteAddress = (req: e.Request) => { const remoteAddress = (req.headers['x-real-ip'] as string) || (req.headers['x-forwarded-for'] as string) || diff --git a/packages/api/src/fastify/index.ts b/packages/api/src/fastify/index.ts index 0c79f75942..68759d3174 100644 --- a/packages/api/src/fastify/index.ts +++ b/packages/api/src/fastify/index.ts @@ -8,12 +8,11 @@ import { UnchainedCore } from '@unchainedshop/core'; import { emit } from '@unchainedshop/events'; import { API_EVENTS } from '../events.js'; import { User } from '@unchainedshop/core-users'; -import { IncomingMessage } from 'http'; import fastifySession from '@fastify/session'; import fastifyCookie from '@fastify/cookie'; -import { FastifyInstance } from 'fastify'; +import { FastifyInstance, FastifyRequest } from 'fastify'; -const resolveUserRemoteAddress = (req: IncomingMessage) => { +const resolveUserRemoteAddress = (req: FastifyRequest) => { const remoteAddress = (req.headers['x-real-ip'] as string) || (req.headers['x-forwarded-for'] as string) || diff --git a/packages/core-orders/src/module/configureOrdersModule.ts b/packages/core-orders/src/module/configureOrdersModule.ts index b0fb310d80..df84afa7f0 100644 --- a/packages/core-orders/src/module/configureOrdersModule.ts +++ b/packages/core-orders/src/module/configureOrdersModule.ts @@ -36,6 +36,7 @@ export type OrdersModule = OrderQueries & setPaymentProvider: (orderId: string, paymentProviderId: string) => Promise; }; +// @kontsedal/locco uses a deprecated way of importing files in ESM (node16 behavior) const require = createRequire(import.meta.url); const { Locker, MongoAdapter } = require('@kontsedal/locco'); diff --git a/packages/core-worker/src/module/configureWorkerModule.ts b/packages/core-worker/src/module/configureWorkerModule.ts index e9da7eaab9..c271beb1a8 100644 --- a/packages/core-worker/src/module/configureWorkerModule.ts +++ b/packages/core-worker/src/module/configureWorkerModule.ts @@ -1,4 +1,4 @@ -import os from 'os'; +import os from 'node:os'; import { createLogger } from '@unchainedshop/logger'; import { generateDbFilterById, diff --git a/packages/file-upload/src/director/FileAdapter.ts b/packages/file-upload/src/director/FileAdapter.ts index a67ed0b54e..f39846d149 100644 --- a/packages/file-upload/src/director/FileAdapter.ts +++ b/packages/file-upload/src/director/FileAdapter.ts @@ -1,4 +1,4 @@ -import { Readable } from 'stream'; +import type { Readable } from 'node:stream'; import { log, LogLevel } from '@unchainedshop/logger'; import { IBaseAdapter } from '@unchainedshop/utils'; import { UploadedFile, UploadFileData } from '../types.js'; diff --git a/packages/mongodb/src/initDb.ts b/packages/mongodb/src/initDb.ts index 678de1ef02..d4ca24759c 100644 --- a/packages/mongodb/src/initDb.ts +++ b/packages/mongodb/src/initDb.ts @@ -1,4 +1,3 @@ -import { mkdirSync } from 'fs'; import { Db, MongoClient } from 'mongodb'; let mongod; @@ -7,9 +6,10 @@ export const startDb = async () => { try { // eslint-disable-next-line // @ts-ignore + const { mkdir } = await import('node:fs/promises'); const { MongoMemoryServer } = await import('mongodb-memory-server'); try { - mkdirSync(`${process.cwd()}/.db`); + await mkdir(`${process.cwd()}/.db`); } catch { // } diff --git a/packages/platform/package.json b/packages/platform/package.json index b48cbdb65e..e92ac80163 100644 --- a/packages/platform/package.json +++ b/packages/platform/package.json @@ -42,7 +42,8 @@ "@unchainedshop/mongodb": "^3.0.0-rc6", "@unchainedshop/plugins": "^3.0.0-rc6", "@unchainedshop/roles": "^3.0.0-rc6", - "@unchainedshop/utils": "^3.0.0-rc6" + "@unchainedshop/utils": "^3.0.0-rc6", + "safe-stable-stringify": "^2.5.0" }, "devDependencies": { "@types/node": "^22.10.2", diff --git a/packages/platform/src/templates/resolveErrorReportTemplate.ts b/packages/platform/src/templates/resolveErrorReportTemplate.ts index bc3c210d41..d6fc51587e 100644 --- a/packages/platform/src/templates/resolveErrorReportTemplate.ts +++ b/packages/platform/src/templates/resolveErrorReportTemplate.ts @@ -1,5 +1,5 @@ import { TemplateResolver } from '@unchainedshop/core'; -import util from 'util'; +import { stringify } from 'safe-stable-stringify'; const { EMAIL_FROM = 'noreply@unchained.local', @@ -11,7 +11,7 @@ const { const formatWorkItems = (workItems) => { return workItems .map(({ _id, type, started, error }) => { - const stringifiedErrors = util.inspect(error, false, 10, false); + const stringifiedErrors = stringify(error, null, 2); return `${new Date(started).toLocaleString()} ${type} (${_id}): ${stringifiedErrors}`; }) .join('\n'); diff --git a/packages/plugins/src/events/node-event-emitter.ts b/packages/plugins/src/events/node-event-emitter.ts index d96fb7f8c9..aa4d79cfd3 100644 --- a/packages/plugins/src/events/node-event-emitter.ts +++ b/packages/plugins/src/events/node-event-emitter.ts @@ -1,4 +1,4 @@ -import { EventEmitter } from 'events'; +import { EventEmitter } from 'node:events'; import { setEmitAdapter, EmitAdapter } from '@unchainedshop/events'; const NodeEventEmitter = (): EmitAdapter => { diff --git a/packages/plugins/src/files/gridfs/gridfs-adapter.ts b/packages/plugins/src/files/gridfs/gridfs-adapter.ts index 9b8efeed6c..2506403c52 100644 --- a/packages/plugins/src/files/gridfs/gridfs-adapter.ts +++ b/packages/plugins/src/files/gridfs/gridfs-adapter.ts @@ -1,6 +1,5 @@ -import { URL } from 'url'; -import { Readable, PassThrough } from 'stream'; -import { pipeline } from 'stream/promises'; +import { Readable, PassThrough } from 'node:stream'; +import { pipeline } from 'node:stream/promises'; import mimeType from 'mime-types'; import { FileAdapter, @@ -12,6 +11,8 @@ import { import { UploadFileData } from '@unchainedshop/file-upload'; import sign from './sign.js'; import { filesSettings } from '@unchainedshop/core-files'; +import { UnchainedCore } from '@unchainedshop/core'; +import { GridFSFileUploadsModule } from './index.js'; const { ROOT_URL } = process.env; @@ -23,7 +24,13 @@ const bufferToStream = (buffer: any) => { return stream; }; -export const GridFSAdapter: IFileAdapter = { +export const GridFSAdapter: IFileAdapter< + UnchainedCore & { + modules: { + gridfsFileUploads: GridFSFileUploadsModule; + }; + } +> = { key: 'shop.unchained.file-upload-plugin.gridfs', label: 'Uploads files to Database using GridFS', version: '1.0.0', @@ -64,8 +71,8 @@ export const GridFSAdapter: IFileAdapter = { } as UploadFileData & { putURL: string }; }, - async uploadFileFromStream(directoryName: string, rawFile: any, { modules }: any) { - let stream; + async uploadFileFromStream(directoryName: string, rawFile: any, { modules }) { + let stream: Readable; let fileName; if (rawFile instanceof Promise) { const { filename: f, createReadStream } = await rawFile; @@ -104,7 +111,7 @@ export const GridFSAdapter: IFileAdapter = { async uploadFileFromURL( directoryName: string, { fileLink, fileName: fname, fileId, headers }: any, - { modules }: any, + { modules }, ) { const { href } = new URL(fileLink); const fileName = decodeURIComponent(fname || href.split('/').pop()); diff --git a/packages/plugins/src/files/gridfs/gridfs-webhook.ts b/packages/plugins/src/files/gridfs/gridfs-webhook.ts index 9d43d58b13..0602a98010 100644 --- a/packages/plugins/src/files/gridfs/gridfs-webhook.ts +++ b/packages/plugins/src/files/gridfs/gridfs-webhook.ts @@ -1,5 +1,5 @@ -import { pipeline, finished } from 'stream/promises'; -import { PassThrough } from 'stream'; +import { pipeline, finished } from 'node:stream/promises'; +import { PassThrough } from 'node:stream'; import { buildHashedFilename } from '@unchainedshop/file-upload'; import express from 'express'; import sign from './sign.js'; diff --git a/packages/plugins/src/files/gridfs/index.ts b/packages/plugins/src/files/gridfs/index.ts index a9b16045b2..12d16dea11 100644 --- a/packages/plugins/src/files/gridfs/index.ts +++ b/packages/plugins/src/files/gridfs/index.ts @@ -27,3 +27,5 @@ export const configureGridFSFileUploadModule = ({ db }) => { }, }; }; + +export type GridFSFileUploadsModule = ReturnType; diff --git a/packages/plugins/src/files/minio/minio-adapter.ts b/packages/plugins/src/files/minio/minio-adapter.ts index ba1550cac2..344554bff2 100644 --- a/packages/plugins/src/files/minio/minio-adapter.ts +++ b/packages/plugins/src/files/minio/minio-adapter.ts @@ -1,7 +1,5 @@ -import https from 'https'; -import http, { OutgoingHttpHeaders } from 'http'; -import { Readable } from 'stream'; -import { URL } from 'url'; +import { Readable } from 'node:stream'; +import type { ReadableStream } from 'node:stream/web'; import { UploadFileData } from '@unchainedshop/file-upload'; import { FileAdapter, @@ -85,24 +83,6 @@ connectToMinio().then(function setClient(c) { client = c; }); -const createHttpDownloadStream = async ( - fileUrl: string, - headers: OutgoingHttpHeaders, -): Promise => { - const { href, protocol } = new URL(fileUrl); - return new Promise((resolve, reject) => { - try { - if (protocol === 'http:') { - http.get(href, { headers }, resolve); - } else { - https.get(href, { headers }, resolve); - } - } catch (e) { - reject(e); - } - }); -}; - const getObjectStats = async (fileName: string) => { if (!client) throw new Error('Minio not connected, check env variables'); @@ -211,9 +191,10 @@ export const MinioAdapter: IFileAdapter = { const fileName = fname || href.split('/').pop(); const hashedFilename = await buildHashedFilename(directoryName, fileName, new Date()); - const stream = await createHttpDownloadStream(fileLink, headers); - const type = mimeType.lookup(fileName) || stream.headers['content-type']; - + const url = new URL(fileLink); + const response = await fetch(url, { headers }); + const type = mimeType.lookup(fileName) || response.headers['content-type']; + const readable = Readable.fromWeb(response.body as ReadableStream>); const metaData = { 'Content-Type': type, }; @@ -221,7 +202,7 @@ export const MinioAdapter: IFileAdapter = { await client.putObject( MINIO_BUCKET_NAME, generateMinioPath(directoryName, hashedFilename), - stream, + readable, undefined, metaData, ); diff --git a/packages/plugins/src/payment/datatrans-v2/api/makeFetcher.ts b/packages/plugins/src/payment/datatrans-v2/api/makeFetcher.ts index 2a59e5937a..762245f445 100644 --- a/packages/plugins/src/payment/datatrans-v2/api/makeFetcher.ts +++ b/packages/plugins/src/payment/datatrans-v2/api/makeFetcher.ts @@ -1,11 +1,5 @@ -import fs from 'fs'; -import util from 'util'; -import { resolve } from 'path'; import { createLogger } from '@unchainedshop/logger'; - -const readFile = util.promisify(fs.readFile); - -const { DATATRANS_API_MOCKS_PATH } = process.env; +const { MOCK_APIS } = process.env; const logger = createLogger('unchained:datatrans'); @@ -14,12 +8,15 @@ export default ( merchantId: string, secret: string, ): ((path: string, body: unknown) => Promise) => { - if (DATATRANS_API_MOCKS_PATH) { + if (MOCK_APIS) { return async (path): Promise => { try { - const filePath = resolve(process.env.PWD, DATATRANS_API_MOCKS_PATH, `.${path}.json`); - const content = await readFile(filePath); - const json = JSON.parse(content.toString()); + const { default: json } = await import( + `${import.meta.dirname}/../../../../tests/mock/datatrans/${path}.json`, + { + with: { type: 'json' }, + } + ); return { json: async () => json, status: json?.error ? 500 : 204, diff --git a/packages/plugins/src/payment/payrexx/api/makeFetcher.ts b/packages/plugins/src/payment/payrexx/api/makeFetcher.ts index 99c665990b..05190fc570 100644 --- a/packages/plugins/src/payment/payrexx/api/makeFetcher.ts +++ b/packages/plugins/src/payment/payrexx/api/makeFetcher.ts @@ -1,11 +1,6 @@ -import fs from 'fs'; -import util from 'util'; -import { resolve } from 'path'; import { createLogger } from '@unchainedshop/logger'; -const readFile = util.promisify(fs.readFile); - -const { PAYREXX_API_MOCKS_PATH } = process.env; +const { MOCK_APIS } = process.env; const logger = createLogger('unchained:payrexx'); @@ -14,17 +9,19 @@ export default ( instance: string = null, secret: string = null, ): ((path: string, method: 'GET' | 'DELETE' | 'PUT' | 'POST', data?: any) => Promise) => { - if (PAYREXX_API_MOCKS_PATH) { + if (MOCK_APIS) { return async (path): Promise => { try { - const filePath = resolve(process.env.PWD, PAYREXX_API_MOCKS_PATH, `${path}.json`); - const content = await readFile(filePath); - const textData = content.toString(); - const jsonData = JSON.parse(textData); + const { default: jsonData } = await import( + `${import.meta.dirname}/../../../../tests/mock/payrexx/${path}.json`, + { + with: { type: 'json' }, + } + ); return { json: async () => jsonData, - text: async () => textData, - ok: !jsonData?.error, + text: async () => JSON.stringify(jsonData?.error), + ok: true, status: jsonData?.error ? 500 : 204, } as any; } catch (error) { diff --git a/packages/plugins/src/worker/email.ts b/packages/plugins/src/worker/email.ts index 0b48355b5e..fae40353e6 100644 --- a/packages/plugins/src/worker/email.ts +++ b/packages/plugins/src/worker/email.ts @@ -1,17 +1,13 @@ -import { mkdtemp, writeFile } from 'fs/promises'; -import { join, isAbsolute } from 'path'; -import { tmpdir } from 'os'; import { WorkerDirector, WorkerAdapter, IWorkerAdapter } from '@unchainedshop/core'; -import open from 'open'; import nodemailer from 'nodemailer'; export const checkEmailInterceptionEnabled = () => { return process.env.NODE_ENV !== 'production' && !process.env.UNCHAINED_DISABLE_EMAIL_INTERCEPTION; }; -const buildLink = ({ filename, content, href, contentType, encoding, path }) => { +const buildLink = async ({ filename, content, href, contentType, encoding, path }) => { if (path) { - return `${filename}`; + return `${filename}`; } if (href) { return `${filename}`; @@ -23,8 +19,12 @@ const buildLink = ({ filename, content, href, contentType, encoding, path }) => }; const openInBrowser = async (options) => { - const filename = `${Date.now()}.html`; + // eslint-disable-next-line + // @ts-ignore + const { default: open, apps } = await import('open'); + const messageBody = options.html || options.text.replace(/(\r\n|\n|\r)/gm, '
'); + const attachmentLinks = await Promise.all((options.attachments || []).map(buildLink)); const content = ` @@ -40,16 +40,17 @@ const openInBrowser = async (options) => { Reply-To: ${options.replyTo}

subject: ${options.subject}
- attachments: ${(options.attachments || []).map(buildLink).join(', ')}
+ attachments: ${attachmentLinks.join(', ')}

${messageBody} `; - const folder = await mkdtemp(join(tmpdir(), 'email-')); - const fileName = `${folder}/${filename}`; - await writeFile(fileName, content); - return open(fileName); + const base64 = Buffer.from(content).toString('base64'); + const dataUri = `data:text/html;base64,${base64}`; + + await open(dataUri, { app: [{ name: apps.chrome }, { name: apps.firefox }, { name: apps.browser }] }); + return true; }; const EmailWorkerPlugin: IWorkerAdapter< @@ -87,8 +88,12 @@ const EmailWorkerPlugin: IWorkerAdapter< ...rest, }; if (checkEmailInterceptionEnabled()) { - await openInBrowser(sendMailOptions); - return { success: true, result: { intercepted: true } }; + const opened = await openInBrowser(sendMailOptions); + return { + success: opened, + result: opened ? { intercepted: true } : undefined, + error: !opened ? { message: "Interception failed due to missing package 'open'" } : undefined, + }; } if (!process.env.MAIL_URL) { return { diff --git a/tests/mocks/datatrans-v2/v1/secure-fields.json b/packages/plugins/tests/mock/datatrans/v1/secure-fields.json similarity index 100% rename from tests/mocks/datatrans-v2/v1/secure-fields.json rename to packages/plugins/tests/mock/datatrans/v1/secure-fields.json diff --git a/tests/mocks/datatrans-v2/v1/transactions.json b/packages/plugins/tests/mock/datatrans/v1/transactions.json similarity index 100% rename from tests/mocks/datatrans-v2/v1/transactions.json rename to packages/plugins/tests/mock/datatrans/v1/transactions.json diff --git a/tests/mocks/datatrans-v2/v1/transactions/authorize.json b/packages/plugins/tests/mock/datatrans/v1/transactions/authorize.json similarity index 100% rename from tests/mocks/datatrans-v2/v1/transactions/authorize.json rename to packages/plugins/tests/mock/datatrans/v1/transactions/authorize.json diff --git a/tests/mocks/datatrans-v2/v1/transactions/card_check_authorized.json b/packages/plugins/tests/mock/datatrans/v1/transactions/card_check_authorized.json similarity index 100% rename from tests/mocks/datatrans-v2/v1/transactions/card_check_authorized.json rename to packages/plugins/tests/mock/datatrans/v1/transactions/card_check_authorized.json diff --git a/tests/mocks/datatrans-v2/v1/transactions/payment_alias_authorized.json b/packages/plugins/tests/mock/datatrans/v1/transactions/payment_alias_authorized.json similarity index 100% rename from tests/mocks/datatrans-v2/v1/transactions/payment_alias_authorized.json rename to packages/plugins/tests/mock/datatrans/v1/transactions/payment_alias_authorized.json diff --git a/tests/mocks/datatrans-v2/v1/transactions/payment_alias_authorized/settle.json b/packages/plugins/tests/mock/datatrans/v1/transactions/payment_alias_authorized/settle.json similarity index 100% rename from tests/mocks/datatrans-v2/v1/transactions/payment_alias_authorized/settle.json rename to packages/plugins/tests/mock/datatrans/v1/transactions/payment_alias_authorized/settle.json diff --git a/tests/mocks/datatrans-v2/v1/transactions/payment_authorized.json b/packages/plugins/tests/mock/datatrans/v1/transactions/payment_authorized.json similarity index 100% rename from tests/mocks/datatrans-v2/v1/transactions/payment_authorized.json rename to packages/plugins/tests/mock/datatrans/v1/transactions/payment_authorized.json diff --git a/tests/mocks/datatrans-v2/v1/transactions/payment_authorized/cancel.json b/packages/plugins/tests/mock/datatrans/v1/transactions/payment_authorized/cancel.json similarity index 100% rename from tests/mocks/datatrans-v2/v1/transactions/payment_authorized/cancel.json rename to packages/plugins/tests/mock/datatrans/v1/transactions/payment_authorized/cancel.json diff --git a/tests/mocks/datatrans-v2/v1/transactions/payment_authorized/settle.json b/packages/plugins/tests/mock/datatrans/v1/transactions/payment_authorized/settle.json similarity index 100% rename from tests/mocks/datatrans-v2/v1/transactions/payment_authorized/settle.json rename to packages/plugins/tests/mock/datatrans/v1/transactions/payment_authorized/settle.json diff --git a/tests/mocks/datatrans-v2/v1/transactions/payment_authorized_low_amount.json b/packages/plugins/tests/mock/datatrans/v1/transactions/payment_authorized_low_amount.json similarity index 100% rename from tests/mocks/datatrans-v2/v1/transactions/payment_authorized_low_amount.json rename to packages/plugins/tests/mock/datatrans/v1/transactions/payment_authorized_low_amount.json diff --git a/tests/mocks/datatrans-v2/v1/transactions/payment_authorized_low_amount/cancel.json b/packages/plugins/tests/mock/datatrans/v1/transactions/payment_authorized_low_amount/cancel.json similarity index 100% rename from tests/mocks/datatrans-v2/v1/transactions/payment_authorized_low_amount/cancel.json rename to packages/plugins/tests/mock/datatrans/v1/transactions/payment_authorized_low_amount/cancel.json diff --git a/tests/mocks/datatrans-v2/v1/transactions/validate.json b/packages/plugins/tests/mock/datatrans/v1/transactions/validate.json similarity index 100% rename from tests/mocks/datatrans-v2/v1/transactions/validate.json rename to packages/plugins/tests/mock/datatrans/v1/transactions/validate.json diff --git a/tests/mocks/payrexx/Gateway.json b/packages/plugins/tests/mock/payrexx/Gateway.json similarity index 100% rename from tests/mocks/payrexx/Gateway.json rename to packages/plugins/tests/mock/payrexx/Gateway.json diff --git a/tests/mocks/payrexx/Gateway/1000001.json b/packages/plugins/tests/mock/payrexx/Gateway/1000001.json similarity index 100% rename from tests/mocks/payrexx/Gateway/1000001.json rename to packages/plugins/tests/mock/payrexx/Gateway/1000001.json diff --git a/tests/mocks/payrexx/transaction_example1.json b/packages/plugins/tests/mock/payrexx/transaction_example1.json similarity index 100% rename from tests/mocks/payrexx/transaction_example1.json rename to packages/plugins/tests/mock/payrexx/transaction_example1.json diff --git a/tests/mocks/payrexx/transaction_example2.json b/packages/plugins/tests/mock/payrexx/transaction_example2.json similarity index 100% rename from tests/mocks/payrexx/transaction_example2.json rename to packages/plugins/tests/mock/payrexx/transaction_example2.json diff --git a/tests/mocks/payrexx/transaction_example3.json b/packages/plugins/tests/mock/payrexx/transaction_example3.json similarity index 100% rename from tests/mocks/payrexx/transaction_example3.json rename to packages/plugins/tests/mock/payrexx/transaction_example3.json diff --git a/packages/ticketing/src/mobile-tickets/apple-wallet.ts b/packages/ticketing/src/mobile-tickets/apple-wallet.ts index 9b4f0cea82..5970be7b81 100644 --- a/packages/ticketing/src/mobile-tickets/apple-wallet.ts +++ b/packages/ticketing/src/mobile-tickets/apple-wallet.ts @@ -1,5 +1,5 @@ import apn from '@hyperlink/node-apn'; -import { Readable } from 'stream'; +import { Readable } from 'node:stream'; export const pushToApplePushNotificationService = async (deviceTokens) => { const apnProvider = new apn.Provider({ diff --git a/tests/assortment-media.test.js b/tests/assortment-media.test.js index a72eb1b0aa..e3bf81e2cd 100644 --- a/tests/assortment-media.test.js +++ b/tests/assortment-media.test.js @@ -6,11 +6,11 @@ import { } from './helpers.js'; import { ADMIN_TOKEN } from './seeds/users.js'; import { PngAssortmentMedia, SimpleAssortment } from './seeds/assortments.js'; -import fs from 'fs'; +import fs from 'node:fs'; import crypto from 'crypto'; -import path from 'path'; +import path from 'node:path'; -import { fileURLToPath } from 'url'; +import { fileURLToPath } from 'node:url'; const dirname = path.dirname(fileURLToPath(import.meta.url)); diff --git a/tests/jest-global-setup.js b/tests/jest-global-setup.js index faf953e01e..7eb476c84e 100644 --- a/tests/jest-global-setup.js +++ b/tests/jest-global-setup.js @@ -27,8 +27,7 @@ const startAndWaitForApp = async () => { EMAIL_FROM: 'noreply@unchained.local', DATATRANS_SECRET: 'secret', DATATRANS_SIGN_KEY: '1337', - DATATRANS_API_MOCKS_PATH: '../../tests/mocks/datatrans-v2', - PAYREXX_API_MOCKS_PATH: '../../tests/mocks/payrexx', + MOCK_APIS: 1, APPLE_IAP_SHARED_SECRET: '71c41914012b4ad7be859f6c26432298', CRYPTOPAY_SECRET: 'secret', CRYPTOPAY_BTC_XPUB: diff --git a/tests/media-permissions.test.js b/tests/media-permissions.test.js index b6c363da4f..7a19ff76be 100644 --- a/tests/media-permissions.test.js +++ b/tests/media-permissions.test.js @@ -13,9 +13,9 @@ import { GUEST_TOKEN, Guest, } from './seeds/users.js'; -import path from 'path'; -import fs from 'fs'; -import { fileURLToPath } from 'url'; +import path from 'node:path'; +import fs from 'node:fs'; +import { fileURLToPath } from 'node:url'; const dirname = path.dirname(fileURLToPath(import.meta.url)); diff --git a/tests/product-media.test.js b/tests/product-media.test.js index 5c3d644435..12e4a37f6d 100644 --- a/tests/product-media.test.js +++ b/tests/product-media.test.js @@ -6,9 +6,9 @@ import { } from './helpers.js'; import { ADMIN_TOKEN } from './seeds/users.js'; import { JpegProductMedia, SimpleProduct } from './seeds/products.js'; -import path from 'path'; -import fs from 'fs'; -import { fileURLToPath } from 'url'; +import path from 'node:path'; +import fs from 'node:fs'; +import { fileURLToPath } from 'node:url'; const dirname = path.dirname(fileURLToPath(import.meta.url));