diff --git a/.eslintrc.js b/.eslintrc.js
index c0c37e3..24bfade 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -19,9 +19,28 @@ module.exports = {
'**/.prettier*',
'**/.version*',
'**/*.md',
- '**/*.js'
+ '**/*.js',
+ '**/*.js.map',
+ '**/*.d.ts'
+ ],
+ overrides: [
+ {
+ files: ["*"],
+ "rules": {
+ "prefer-rest-params": "off"
+ }
+ }
],
rules: {
- "prettier/prettier": "error"
+ "prettier/prettier": "error",
+ "@typescript-eslint/ban-types": [
+ "error",
+ {
+ "types": {
+ "Function": false
+ },
+ "extendDefaults": true
+ }
+ ]
},
};
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
deleted file mode 100644
index 7ade64b..0000000
--- a/.github/workflows/codeql-analysis.yml
+++ /dev/null
@@ -1,69 +0,0 @@
-# For most projects, this workflow file will not need changing; you simply need
-# to commit it to your repository.
-#
-# You may wish to alter this file to override the set of languages analyzed,
-# or to provide custom queries or build logic.
-#
-# ******** NOTE ********
-# We have attempted to detect the languages in your repository. Please check
-# the `language` matrix defined below to confirm you have the correct set of
-# supported CodeQL languages.
-#
-name: "CodeQL"
-
-on:
- push:
- branches:
- - '*'
- - '!main'
- schedule:
- - cron: '36 15 * * 5'
-
-jobs:
- analyze:
- name: Analyze
- runs-on: ubuntu-latest
- permissions:
- actions: read
- contents: read
- security-events: write
-
- strategy:
- fail-fast: false
- matrix:
- language: [ 'javascript' ]
- # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
- # Learn more about CodeQL language support at https://git.io/codeql-language-support
-
- steps:
- - name: Checkout repository
- uses: actions/checkout@v2
-
- # Initializes the CodeQL tools for scanning.
- - name: Initialize CodeQL
- uses: github/codeql-action/init@v1
- with:
- languages: ${{ matrix.language }}
- # If you wish to specify custom queries, you can do so here or in a config file.
- # By default, queries listed here will override any specified in a config file.
- # Prefix the list here with "+" to use these queries and those in the config file.
- # queries: ./path/to/local/query, your-org/your-repo/queries@main
-
- # Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
- # If this step fails, then you should remove it and run the build manually (see below)
- - name: Autobuild
- uses: github/codeql-action/autobuild@v1
-
- # âšī¸ Command-line programs to run using the OS shell.
- # đ https://git.io/JvXDl
-
- # âī¸ If the Autobuild fails above, remove it and uncomment the following three lines
- # and modify them (or add more) to build your code if your project
- # uses a compiled language
-
- #- run: |
- # make bootstrap
- # make release
-
- - name: Perform CodeQL Analysis
- uses: github/codeql-action/analyze@v1
diff --git a/.github/workflows/payment-paytr.yml b/.github/workflows/payment-paytr.yml
deleted file mode 100644
index 7882e02..0000000
--- a/.github/workflows/payment-paytr.yml
+++ /dev/null
@@ -1,47 +0,0 @@
-name: Payment-paytr tests pipeline
-on: [push]
-
-jobs:
- unit-tests:
- runs-on: ubuntu-latest
- defaults:
- run:
- working-directory: ./packages/medusa/payment-paytr
-
- steps:
- - name: Cancel Previous Runs
- uses: styfle/cancel-workflow-action@0.9.1
- with:
- access_token: ${{ github.token }}
-
- - name: Checkout
- uses: actions/checkout@v2.3.5
- with:
- fetch-depth: 0
-
- - name: Setup Node.js environment
- uses: actions/setup-node@v2.4.1
- with:
- node-version: "14"
- cache: "npm"
-
- - name: create test env file
- run: |
- touch .env.test
- echo MERCHANT_ID=${{ secrets.PAYTR_MERCHANT_ID }} >> .env.test
- echo MERCHANT_KEY=${{ secrets.PAYTR_MERCHANT_KEY }} >> .env.test
- echo MERCHANT_SALT=${{ secrets.PAYTR_MERCHANT_SALT }} >> .env.test
- echo TOKEN_ENDPOINT=${{ secrets.PAYTR_TOKEN_ENDPOINT }} >> .env.test
- echo REFUND_ENDPOINT=${{ secrets.PAYTR_REFUND_ENDPOINT }} >> .env.test
- env:
- MERCHANT_ID: ${{secrets.PAYTR_MERCHANT_ID}}
- MERCHANT_KEY: ${{secrets.PAYTR_MERCHANT_KEY}}
- MERCHANT_SALT: ${{secrets.PAYTR_MERCHANT_SALT}}
- TOKEN_ENDPOINT: ${{secrets.PAYTR_TOKEN_ENDPOINT}}
- REFUND_ENDPOINT: ${{secrets.PAYTR_REFUND_ENDPOINT}}
-
- - name: 'npm install'
- run: npm install
-
- - name: 'run unit tests'
- run: npm run test
diff --git a/README.md b/README.md
index e86d93f..7c644cd 100644
--- a/README.md
+++ b/README.md
@@ -11,7 +11,6 @@
-
@@ -48,9 +47,9 @@ make it easier for you to find them :rocket:
# Plugins
-| Name | Target | Badges |
-|---------------------------|---------------|----------------------------------------------|
-| `payment-paytr` | `medusa` | |
+| Name | Target | Badges |
+|---------------------------------------------------------------------------------------------------------------------|---------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| [`medusa-plugin-sentry (Link)`](https://github.com/adrien2p/medusa-plugins/tree/main/packages/medusa-plugin-sentry) | `medusa` | |
[![-----------------------------------------------------](https://raw.githubusercontent.com/andreasbm/readme/master/assets/lines/cloudy.png)](#discussions)
@@ -71,26 +70,4 @@ If you found the package helpful consider supporting me with a coffee
# Contribute
-Contributions are welcome! You can look at the contribution [guidelines](./CONTRIBUTING.md)
-
-## Test a package locally
-
-Go to the plugin package directory and Build your local plugin
-
-```bash
-npm run build
-npm pack
-```
-
-Then copy the tgz file newly creating by the `pack` command into your project.
-
-## Target project
-
-In your target project past the tgz file previously copied.
-then update your `package.json`
-
-```bash
-"my-package": "file:my-package-1.0.0.tgz"
-```
-
-now run `npm i` and run your project
\ No newline at end of file
+Contributions are welcome! You can look at the contribution [guidelines](./CONTRIBUTING.md)
\ No newline at end of file
diff --git a/package.json b/package.json
index e552835..fe996af 100644
--- a/package.json
+++ b/package.json
@@ -12,7 +12,6 @@
]
},
"scripts": {
- "build": "run-p clean run-s build:api /node_modules/.bin/lerna/tsc -b ./packages/tsconfig.api-base.json",
"bootstrap": "./node_modules/.bin/lerna/lerna bootstrap",
"clean": "./node_modules/.bin/lerna/lerna run --parallel clean",
"release": "./node_modules/.bin/lerna/lerna publish",
@@ -46,6 +45,6 @@
"npm-run-all": "^4.1.5",
"prettier": "^2.5.0",
"tslint": "~6.1.0",
- "typescript": "^3.7.5"
+ "typescript": "^4.5.5"
}
}
diff --git a/packages/medusa-plugin-sentry/.gitignore b/packages/medusa-plugin-sentry/.gitignore
index c712284..d398854 100644
--- a/packages/medusa-plugin-sentry/.gitignore
+++ b/packages/medusa-plugin-sentry/.gitignore
@@ -1,7 +1,11 @@
.idea
-/lib
-/dist
-api/
+
+/api
+/handlers
+/utils
+/types
+/services
+
node_modules
.DS_store
**/.DS_Store
@@ -9,8 +13,8 @@ node_modules
dist
coverage
-/tsconfig.tsbuildinfo
-/package-lock.json
-/yarn.json
+tsconfig.tsbuildinfo
+package-lock.json
+yarn.json
.env.*
\ No newline at end of file
diff --git a/packages/medusa-plugin-sentry/README.md b/packages/medusa-plugin-sentry/README.md
new file mode 100644
index 0000000..3caf592
--- /dev/null
+++ b/packages/medusa-plugin-sentry/README.md
@@ -0,0 +1,219 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# Medusa Sentry plugin
+
+## Getting started
+
+First of all, you need to install the plugin as follow
+`yarn add @medusa-plugins/medusa-plugni-sentry`
+
+Then, go to your `medusa-config.js` file and in the plugins collection property add the following at the beginning to be registered first
+```javascript
+{
+ resolve: `@medusa-plugins/medusa-plugin-sentry`,
+ options: {
+ dsn: "__YOUR_DSN__",
+ apiToken: "__YOUR_API_TOKEN__",
+ integrations: (router, Sentry, Tracing) => {
+ return [
+ new Sentry.Integrations.Http({ tracing: true }),
+ new Tracing.Integrations.Express({ router }),
+ ];
+ },
+ tracesSampleRate: 1.0,
+ shouldHandleError: (code) => code >= 400,
+ webHookOptions: {
+ path: "/sentry/webhook",
+ secret: "__YOUR_SECRET__",
+ emitOnIssue: true,
+ emitOnError: false,
+ emitOnComment: true,
+ emitOnEventOrMetricAlert: true,
+ emitOnInstallOrDeleted: false,
+ }
+ },
+},
+```
+
+> The `webHookOptions.path` is always attached on the `/admin` domain. Which means that if you specify something like `/sentry` the result path will be `/admin/sentry`
+
+## Configuration
+
+You can see above some configuration for the plugin. To be able to know all the options available
+you can have a look at
+- [NodeOptions](https://github.com/getsentry/sentry-javascript/blob/7304215d875decf0bf555cab82aa90fc1341b27e/packages/node/src/types.ts#L30)
+
+And here are the plugin configuration types
+```typescript
+export type SentryWebHookOptions = {
+ path: string;
+ secret: string;
+ emitOnIssue?: boolean | ((req) => Promise);
+ emitOnError?: boolean | ((req) => Promise);
+ emitOnComment?: boolean | ((req) => Promise);
+ emitOnEventOrMetricAlert?: boolean | ((req) => Promise);
+ emitOnInstallOrDeleted?: boolean | ((req) => Promise);
+}
+
+export type SentryOptions = Omit & {
+ integrations: Integration[] | ((router: Router, sentry: typeof Sentry, tracing: typeof Tracing) => Integration[]);
+ shouldHandleError: (code: number) => boolean;
+ requestHandlerOptions?: RequestHandlerOptions;
+ enableRequestHandler?: boolean;
+ enableTracing?: boolean;
+ webHookOptions?: SentryWebHookOptions,
+};
+```
+
+## Web hooks
+
+> Learn more about sentry integration [here](https://docs.sentry.io/product/integrations/integration-platform/)
+
+With this plugin, you can register the path and options to the web hook you want to make available for sentry
+using the `webHookOptions` from the [config](#getting-started).
+
+To activate the web hook you have to provide the appropriate configurations.
+
+Once sentry send an event to the web hook, each type of resource will emit
+his own event that you can subscribe to using the medusa [subscribers](https://docs.medusajs.com/advanced/backend/subscribers/overview/).
+
+Here is the list of the event that can be emitted
+
+```typescript
+export enum SentryWebHookEvent {
+ SENTRY_RECEIVED_ISSUE = 'SentryReceivedIssue',
+ SENTRY_RECEIVED_ERROR = 'SentryReceivedError',
+ SENTRY_RECEIVED_COMMENT = 'SentryReceivedComment',
+ SENTRY_RECEIVED_EVENT_OR_METRIC_ALERT = 'SentryReceivedEventOrMetricAlert',
+ SENTRY_RECEIVED_INSTALL_OR_DELETED = 'SentryReceivedInstallOrDeleted',
+}
+```
+
+It is also possible to specify a function for each of the `emitOn*` options which take the request as the parameter. From that method you can
+resolve any of your services and call it to handle the event. In that case, the even bus will not fire the corresponding event.
+
+## API
+
+The sentry plugins will provide you some authenticated end points if you want to get some data about your transactions and events related to the transactions.
+
+### /admin/sentry-transactions
+
+This end point allow you to retrieve all your transactions for a given period, here are the allowed query parameters
+
+```markdown
+- organisation - The organisation to fetch the transactions from
+- project - The project to fetch the transactions from
+- statsPeriod - The period from when to fetch the transactions (default: 24h)
+- perPage - The number of transaction per page
+- cursor - The cursor to send to fetch the transactions for a given page
+```
+
+The output of that query looks like the following
+
+```json
+{
+ "data": [
+ {
+ "transaction": "POST /admin/customers/:id",
+ "id": "***",
+ "project.name": "node-express"
+ },
+ // ... 19 other items
+ ],
+ "meta": {
+ "fields": {
+ "transaction": "string",
+ "id": "string",
+ "project.name": "string"
+ },
+ "units": {
+ "transaction": null,
+ "id": null,
+ "project.name": null
+ },
+ "isMetricsData": false,
+ "tips": {
+ "query": null,
+ "columns": null
+ }
+ },
+ "next_cursor": "0:20:0",
+ "prev_cursor": "0:0:0"
+}
+```
+
+### /admin/sentry-transaction-events
+
+This end point allow you to retrieve all your transaction events for a given period, here are the allowed query parameters
+
+```markdown
+- transaction - The transaction for which the events must be retrieved (e.g "GET /admin/users")
+- organisation - The organisation to fetch the transactions from
+- project - The project to fetch the transactions from
+- statsPeriod - The period from when to fetch the transactions (default: 24h)
+- perPage - The number of transaction per page
+- cursor - The cursor to send to fetch the transactions for a given page
+```
+
+The output of that query looks like the following
+
+```json
+{
+ "data": [
+ {
+ "spans.db": 46.443939,
+ "timestamp": "2022-10-11T14:00:11+00:00",
+ "id": "***",
+ "transaction.duration": 115,
+ "spans.http": null,
+ "project.name": "node-express"
+ },
+ {
+ "spans.db": 5.561113,
+ "timestamp": "2022-10-11T13:30:43+00:00",
+ "id": "***",
+ "transaction.duration": 18,
+ "spans.http": null,
+ "project.name": "node-express"
+ }
+ ],
+ "meta": {
+ "fields": {
+ "spans.db": "duration",
+ "timestamp": "date",
+ "id": "string",
+ "transaction.duration": "duration",
+ "spans.http": "duration",
+ "project.name": "string"
+ },
+ "units": {
+ "spans.db": "millisecond",
+ "timestamp": null,
+ "id": null,
+ "transaction.duration": "millisecond",
+ "spans.http": "millisecond",
+ "project.name": null
+ },
+ "isMetricsData": false,
+ "tips": {
+ "query": null,
+ "columns": null
+ }
+ },
+ "prev_cursor": "0:0:0",
+ "next_cursor": "0:100:0"
+}
+```
\ No newline at end of file
diff --git a/packages/medusa-plugin-sentry/package.json b/packages/medusa-plugin-sentry/package.json
index 5275333..a1463d0 100644
--- a/packages/medusa-plugin-sentry/package.json
+++ b/packages/medusa-plugin-sentry/package.json
@@ -1,25 +1,47 @@
{
- "name": "@medusa-plugins/medusa-plugin-sentry",
+ "name": "medusa-plugin-sentry",
"version": "1.0.0",
- "main": "index.js",
"author": "Adrien de Peretti",
+ "description": "Sentry plugin for medusajs",
+ "keywords": [
+ "analytics",
+ "sentry",
+ "medusa",
+ "medusajs",
+ "e-commerce",
+ "error-management"
+ ],
"license": "MIT",
+ "files": [
+ "api",
+ "handlers",
+ "utils",
+ "types"
+ ],
"scripts": {
"build": "run-s clean build:tsc",
"build:tsc": "tsc -b",
- "clean": "rimraf lib coverage tsconfig.tsbuildinfo"
+ "clean": "rimraf api handlers utils types coverage tsconfig.tsbuildinfo"
},
"peerDependencies": {
- "@medusajs/medusa": "^1.4.1"
+ "@medusajs/medusa": "^1.4.1",
+ "medusa-interfaces": "^1.3.3",
+ "typeorm": "^0.2.45"
},
"devDependencies": {
+ "@medusajs/medusa": "^1.4.1",
+ "medusa-interfaces": "^1.3.3",
"ts-node": "^8.6.2",
- "@medusajs/medusa": "^1.4.1"
+ "typeorm": "^0.2.45"
},
"dependencies": {
"@sentry/node": "^7.14.1",
"@sentry/tracing": "^7.14.1",
- "@types/express": "types/express",
- "express": "^4.18.1"
+ "@types/express": "^4.17.14",
+ "axios": "^1.0.0",
+ "class-validator": "^0.13.2",
+ "cors": "^2.8.5",
+ "express": "^4.18.1",
+ "medusa-core-utils": "^1.1.31"
}
}
diff --git a/packages/medusa-plugin-sentry/src/api/handlers/sentry-transaction-events.ts b/packages/medusa-plugin-sentry/src/api/handlers/sentry-transaction-events.ts
new file mode 100644
index 0000000..c8dd3ed
--- /dev/null
+++ b/packages/medusa-plugin-sentry/src/api/handlers/sentry-transaction-events.ts
@@ -0,0 +1,31 @@
+import { Request, Response } from 'express';
+import { validator } from '@medusajs/medusa/dist/utils/validator';
+import SentryService from '../../services/sentry';
+import { IsString } from 'class-validator';
+import { GetSentryTransactionsParams } from './sentry-transaction';
+
+export default (token: string) => {
+ return async (req: Request, res: Response) => {
+ const { transaction, organisation, project, statsPeriod, perPage, cursor } = await validator(
+ GetSentryTransactionEventsParams,
+ req.query
+ );
+
+ const sentryService: SentryService = req.scope.resolve(SentryService.RESOLVE_KEY);
+ const result = await sentryService.fetchTransactionEvents({
+ transaction,
+ organisation,
+ project,
+ statsPeriod,
+ perPage,
+ cursor,
+ token,
+ });
+ res.json(result);
+ };
+};
+
+export class GetSentryTransactionEventsParams extends GetSentryTransactionsParams {
+ @IsString()
+ transaction: string;
+}
diff --git a/packages/medusa-plugin-sentry/src/api/handlers/sentry-transaction.ts b/packages/medusa-plugin-sentry/src/api/handlers/sentry-transaction.ts
new file mode 100644
index 0000000..6d4229a
--- /dev/null
+++ b/packages/medusa-plugin-sentry/src/api/handlers/sentry-transaction.ts
@@ -0,0 +1,43 @@
+import { Request, Response } from 'express';
+import { validator } from '@medusajs/medusa/dist/utils/validator';
+import SentryService from '../../services/sentry';
+import { IsOptional, IsString } from 'class-validator';
+
+export default (token: string) => {
+ return async (req: Request, res: Response) => {
+ const { organisation, project, statsPeriod, perPage, cursor } = await validator(
+ GetSentryTransactionsParams,
+ req.query
+ );
+
+ const sentryService: SentryService = req.scope.resolve(SentryService.RESOLVE_KEY);
+ const result = await sentryService.fetchSentryTransactions({
+ organisation,
+ project,
+ statsPeriod,
+ perPage,
+ cursor,
+ token,
+ });
+ res.json(result);
+ };
+};
+
+export class GetSentryTransactionsParams {
+ @IsString()
+ organisation: string;
+
+ @IsString()
+ project: string;
+
+ @IsString()
+ statsPeriod: string;
+
+ @IsOptional()
+ @IsString()
+ perPage?: string;
+
+ @IsOptional()
+ @IsString()
+ cursor?: string;
+}
diff --git a/packages/medusa-plugin-sentry/src/api/handlers/sentry-web-hook.ts b/packages/medusa-plugin-sentry/src/api/handlers/sentry-web-hook.ts
new file mode 100644
index 0000000..1164712
--- /dev/null
+++ b/packages/medusa-plugin-sentry/src/api/handlers/sentry-web-hook.ts
@@ -0,0 +1,66 @@
+import { Request, Response } from 'express';
+import SentryService from '../../services/sentry';
+import { verifySignature } from '../../utils';
+import { SentryWebHookOptions } from '../../types';
+
+export default (webHookOptions: SentryWebHookOptions) => {
+ return async (req: Request, res: Response) => {
+ if (!verifySignature(req, webHookOptions.secret)) {
+ return res.sendStatus(401);
+ }
+
+ res.status(200);
+
+ // Parse the JSON body fields off of the request
+ const { action, data, installation, actor } = req.body;
+ const { uuid } = installation || {};
+
+ // Identify the resource triggering the webhook in Sentry
+ const resource = req.header('sentry-hook-resource');
+ if (!action || !data || !uuid || !resource) {
+ return res.sendStatus(400);
+ }
+
+ const sentryService: SentryService = req.scope.resolve(SentryService.RESOLVE_KEY);
+
+ const dataToEmit = {
+ actor,
+ action,
+ data,
+ installation,
+ };
+
+ // Handle webhooks related to issues
+ if (webHookOptions.emitOnIssue && resource === 'issue') {
+ await sentryService.handleIssues(dataToEmit);
+ res.status(200);
+ }
+
+ // Handle webhooks related to errors
+ if (webHookOptions.emitOnError && resource === 'error') {
+ await sentryService.handleErrors(dataToEmit);
+ res.status(200);
+ }
+
+ // Handle webhooks related to comments
+ if (webHookOptions.emitOnComment && resource === 'comment') {
+ await sentryService.handleComments(dataToEmit);
+
+ res.status(200);
+ }
+
+ // Handle webhooks related to alerts
+ if (webHookOptions.emitOnEventOrMetricAlert && (resource === 'event_alert' || resource === 'metric_alert')) {
+ await sentryService.handleAlerts(dataToEmit);
+ res.status(200);
+ }
+
+ // Handle uninstallation webhook
+ if (webHookOptions.emitOnInstallOrDeleted && resource === 'installation' && action === 'deleted') {
+ await sentryService.handleInstallation(dataToEmit);
+ res.status(200);
+ }
+
+ res.send();
+ };
+};
diff --git a/packages/medusa-plugin-sentry/src/api/index.ts b/packages/medusa-plugin-sentry/src/api/index.ts
index 952a8e8..edfb36f 100644
--- a/packages/medusa-plugin-sentry/src/api/index.ts
+++ b/packages/medusa-plugin-sentry/src/api/index.ts
@@ -1,19 +1,16 @@
-import { Router } from 'express';
+import express, { Router } from 'express';
+import cors from 'cors';
import * as Sentry from '@sentry/node';
import * as Tracing from '@sentry/tracing';
-import { NodeOptions } from '@sentry/node/types/types';
-import { Integration } from '@sentry/types/types/integration';
-import { RequestHandlerOptions } from '@sentry/node/types/handlers';
+import authenticate from '@medusajs/medusa/dist/api/middlewares/authenticate';
+import wrapHandler from '@medusajs/medusa/dist/api/middlewares/await-middleware';
+import { getConfigFile } from 'medusa-core-utils';
-export type SentryOptions = Omit & {
- integrations: Integration[] | ((router: Router, sentry: typeof Sentry, tracing: typeof Tracing) => Integration[]);
- shouldHandleError: (code: number) => boolean;
- requestHandlerOptions?: RequestHandlerOptions;
- enableRequestHandler?: boolean;
- enableTracing?: boolean;
-};
-
-export default function (rootDirectory, pluginOptions: SentryOptions) {
+import { SentryOptions, SentryWebHookOptions } from '../types';
+import sentryTransactionsHandler from './handlers/sentry-transaction';
+import sentryTransactionEventsHandler from './handlers/sentry-transaction-events';
+import sentryWebHookHandler from './handlers/sentry-web-hook';
+export default function (rootDirectory, pluginOptions: SentryOptions): Router {
const router = Router();
const {
@@ -22,6 +19,7 @@ export default function (rootDirectory, pluginOptions: SentryOptions) {
requestHandlerOptions = {},
enableTracing = true,
enableRequestHandler = true,
+ webHookOptions,
...options
} = pluginOptions;
@@ -41,6 +39,23 @@ export default function (rootDirectory, pluginOptions: SentryOptions) {
router.use(Sentry.Handlers.tracingHandler());
}
+ attachSentryErrorHandler(shouldHandleError);
+
+ if (webHookOptions) {
+ attachSentryWebHook(router, webHookOptions);
+ }
+
+ attachAdminEndPoints(router, rootDirectory, pluginOptions);
+
+ return router;
+}
+
+/**
+ * Attach the sentry error handler in the medusa core
+ * @param shouldHandleError
+ */
+function attachSentryErrorHandler(shouldHandleError) {
+ /* eslint-disable @typescript-eslint/no-var-requires */
const medusaErrorHandler = require('@medusajs/medusa/dist/api/middlewares/error-handler');
const originalMedusaErrorHandler = medusaErrorHandler.default;
medusaErrorHandler.default = () => {
@@ -59,6 +74,47 @@ export default function (rootDirectory, pluginOptions: SentryOptions) {
})(err, req, res, () => void 0);
};
};
+}
- return router;
+/**
+ * Attach sentry web hook
+ * @param router
+ * @param webHookOptions
+ */
+function attachSentryWebHook(router: Router, webHookOptions: SentryWebHookOptions): void {
+ router.post(
+ '/admin' + webHookOptions.path,
+ express.json(),
+ express.urlencoded({ extended: true }),
+ sentryWebHookHandler(webHookOptions)
+ );
+}
+
+/**
+ * Attach specific sentry end point to fetch data under the admin domain
+ * @param router
+ * @param rootDirectory
+ * @param pluginOptions
+ */
+function attachAdminEndPoints(router, rootDirectory, pluginOptions) {
+ const { apiToken } = pluginOptions;
+ const { configModule } = getConfigFile(rootDirectory, 'medusa-config') as {
+ configModule: { projectConfig: { admin_cors: string } };
+ };
+ const { projectConfig } = configModule;
+
+ const corsOptions = {
+ origin: projectConfig.admin_cors.split(','),
+ credentials: true,
+ };
+
+ router.options('/admin/sentry-transactions', cors(corsOptions));
+ router.get('/admin/sentry-transactions', authenticate(), wrapHandler(sentryTransactionsHandler(apiToken)));
+
+ router.options('/admin/sentry-transaction-events', cors(corsOptions));
+ router.get(
+ '/admin/sentry-transaction-events',
+ authenticate(),
+ wrapHandler(sentryTransactionEventsHandler(apiToken))
+ );
}
diff --git a/packages/medusa-plugin-sentry/src/services/sentry.ts b/packages/medusa-plugin-sentry/src/services/sentry.ts
new file mode 100644
index 0000000..6beae31
--- /dev/null
+++ b/packages/medusa-plugin-sentry/src/services/sentry.ts
@@ -0,0 +1,226 @@
+import { EventBusService, TransactionBaseService } from '@medusajs/medusa';
+import axios from 'axios';
+import formatRegistrationName from '@medusajs/medusa/dist/utils/format-registration-name';
+import { EntityManager } from 'typeorm';
+
+import { SentryOptions, SentryWebHookData, SentryWebHookEvent } from '../types';
+import { isFunction } from '../utils';
+
+type InjectedDeps = {
+ manager: EntityManager;
+ eventBusService: EventBusService;
+};
+
+type SentryFetchResult = {
+ data: Record[];
+ meta: unknown;
+ prev_cursor: string;
+ next_cursor: string;
+};
+
+export default class SentryService extends TransactionBaseService {
+ static readonly RESOLVE_KEY = formatRegistrationName(`${process.cwd()}/services/sentry.js`);
+ protected readonly sentryApiBaseUrl = 'https://sentry.io/api/0/organizations';
+
+ protected manager_: EntityManager;
+ protected transactionManager_: EntityManager | undefined;
+
+ protected readonly config_: SentryOptions;
+ protected readonly eventBusService_: EventBusService;
+
+ constructor({ manager, eventBusService }: InjectedDeps, config: SentryOptions) {
+ // @ts-ignore
+ super(...arguments);
+
+ this.manager_ = manager;
+ this.config_ = config;
+ this.eventBusService_ = eventBusService;
+ }
+
+ /**
+ * Fetch paginated transactions from an organisation project on sentry
+ * @param organisation The organisation on which to fetch the transactions
+ * @param project The project in the organisation on which to fetch the transactions
+ * @param statsPeriod The period from when to fetch the transactions (default: 24h)
+ * @param perPage The number of transaction per page
+ * @param token The token to use to send request to sentry
+ * @param cursor The cursor to send to fetch the transactions for a given page
+ * @return The result is composed of the data and the next cursor for the pagination purpose
+ */
+ async fetchSentryTransactions({
+ organisation,
+ project,
+ statsPeriod,
+ perPage,
+ token,
+ cursor,
+ }): Promise {
+ perPage = perPage ?? 100;
+
+ const queryParams = {
+ field: 'transaction',
+ per_page: Number(perPage),
+ project,
+ query: `event.type:transaction`,
+ statsPeriod,
+ // The three values from cursor are: cursor identifier (integer, usually 0), row offset, and is_prev (1 or 0).
+ // e.g 0:10:0
+ cursor,
+ };
+
+ return await this.fetchSentry({
+ organisation,
+ token,
+ perPage,
+ queryParams,
+ });
+ }
+
+ /**
+ * Fetch paginated transaction events from an organisation project on sentry
+ * @param transaction The transaction for which to fetch the events (e.g "GET /admin/users")
+ * @param organisation The organisation on which to fetch the transactions
+ * @param project The project in the organisation on which to fetch the transactions
+ * @param statsPeriod The period from when to fetch the transactions (default: 24h)
+ * @param perPage The number of transaction per page
+ * @param token The token to use to send request to sentry
+ * @param cursor The cursor to send to fetch the transactions for a given page
+ * @return The result is composed of the data and the next cursor for the pagination purpose
+ */
+ async fetchTransactionEvents({
+ transaction,
+ organisation,
+ project,
+ statsPeriod,
+ perPage,
+ token,
+ cursor,
+ }): Promise {
+ perPage = perPage ?? 100;
+
+ const queryParams = {
+ field: ['id', 'transaction.duration', 'timestamp', 'spans.db'],
+ per_page: Number(perPage),
+ project,
+ query: `event.type:transaction transaction:"${transaction}"`,
+ statsPeriod,
+ sort: '-timestamp',
+ // The three values from cursor are: cursor identifier (integer, usually 0), row offset, and is_prev (1 or 0).
+ // e.g 0:10:0
+ cursor,
+ };
+
+ return await this.fetchSentry({
+ organisation,
+ token,
+ perPage,
+ queryParams,
+ });
+ }
+
+ async handleIssues(data: SentryWebHookData): Promise {
+ await this.manager_.transaction(async (transactionManager) => {
+ if (isFunction(this.config_.webHookOptions.emitOnIssue)) {
+ return await this.config_.webHookOptions.emitOnIssue(this.__container__);
+ }
+ await this.eventBusService_
+ .withTransaction(transactionManager)
+ .emit(SentryWebHookEvent.SENTRY_RECEIVED_ISSUE, data);
+ });
+ }
+
+ async handleErrors(data: SentryWebHookData): Promise {
+ await this.manager_.transaction(async (transactionManager) => {
+ if (isFunction(this.config_.webHookOptions.emitOnError)) {
+ return await this.config_.webHookOptions.emitOnError(this.__container__);
+ }
+ await this.eventBusService_
+ .withTransaction(transactionManager)
+ .emit(SentryWebHookEvent.SENTRY_RECEIVED_ERROR, data);
+ });
+ }
+
+ async handleComments(data: SentryWebHookData): Promise {
+ await this.manager_.transaction(async (transactionManager) => {
+ if (isFunction(this.config_.webHookOptions.emitOnComment)) {
+ return await this.config_.webHookOptions.emitOnComment(this.__container__);
+ }
+ await this.eventBusService_
+ .withTransaction(transactionManager)
+ .emit(SentryWebHookEvent.SENTRY_RECEIVED_COMMENT, data);
+ });
+ }
+
+ async handleAlerts(data: SentryWebHookData): Promise {
+ await this.manager_.transaction(async (transactionManager) => {
+ if (isFunction(this.config_.webHookOptions.emitOnEventOrMetricAlert)) {
+ return await this.config_.webHookOptions.emitOnEventOrMetricAlert(this.__container__);
+ }
+ await this.eventBusService_
+ .withTransaction(transactionManager)
+ .emit(SentryWebHookEvent.SENTRY_RECEIVED_EVENT_OR_METRIC_ALERT, data);
+ });
+ }
+
+ async handleInstallation(data: SentryWebHookData): Promise {
+ await this.manager_.transaction(async (transactionManager) => {
+ if (isFunction(this.config_.webHookOptions.emitOnInstallOrDeleted)) {
+ return await this.config_.webHookOptions.emitOnInstallOrDeleted(this.__container__);
+ }
+ await this.eventBusService_
+ .withTransaction(transactionManager)
+ .emit(SentryWebHookEvent.SENTRY_RECEIVED_INSTALL_OR_DELETED, data);
+ });
+ }
+
+ protected async fetchSentry({ organisation, token, queryParams, perPage }): Promise {
+ const url = this.sentryApiBaseUrl + `/${organisation}/events/`;
+
+ const searchParams = new URLSearchParams();
+ Object.entries(queryParams).forEach(([key, value]) => {
+ if (Array.isArray(value)) {
+ value.forEach((val) => {
+ searchParams.append(key, val);
+ });
+ } else {
+ value && searchParams.append(key, value?.toString());
+ }
+ });
+
+ const {
+ data: { data, meta },
+ headers,
+ } = await axios.get(url, {
+ headers: {
+ Authorization: `Bearer ${token}`,
+ },
+ params: searchParams,
+ });
+
+ const nextCursor: string = SentryService.buildNextCursor(headers['link']);
+
+ let prevCursor: string;
+ if (nextCursor) {
+ prevCursor = SentryService.buildPrevCursor(nextCursor, perPage);
+ }
+
+ return { data, meta, prev_cursor: prevCursor, next_cursor: nextCursor };
+ }
+
+ protected static buildNextCursor(link: string): string {
+ let result = '';
+
+ const nextCursorMatch = link?.match(/.*cursor="(.*)"$/);
+ if (nextCursorMatch && nextCursorMatch[1]) {
+ result = nextCursorMatch[1]?.split(',')[0];
+ }
+
+ return result;
+ }
+
+ protected static buildPrevCursor(nextCursor: string, perPage: number): string {
+ const parts = nextCursor.split(':');
+ const prevCursorItems = Math.max(0, Number(parts[1]) - perPage * 2);
+ return `${parts[0]}:${prevCursorItems}:${parts[2]}`;
+ }
+}
diff --git a/packages/medusa-plugin-sentry/src/types/index.ts b/packages/medusa-plugin-sentry/src/types/index.ts
new file mode 100644
index 0000000..ccbc13c
--- /dev/null
+++ b/packages/medusa-plugin-sentry/src/types/index.ts
@@ -0,0 +1,41 @@
+import { NodeOptions } from '@sentry/node/types/types';
+import { Integration } from '@sentry/types/types/integration';
+import { Router } from 'express';
+import * as Sentry from '@sentry/node';
+import * as Tracing from '@sentry/tracing';
+import { RequestHandlerOptions } from '@sentry/node/types/handlers';
+
+export type SentryWebHookOptions = {
+ path: string;
+ secret: string;
+ emitOnIssue?: boolean | ((req) => Promise);
+ emitOnError?: boolean | ((req) => Promise);
+ emitOnComment?: boolean | ((req) => Promise);
+ emitOnEventOrMetricAlert?: boolean | ((req) => Promise);
+ emitOnInstallOrDeleted?: boolean | ((req) => Promise);
+};
+
+export type SentryOptions = Omit & {
+ integrations: Integration[] | ((router: Router, sentry: typeof Sentry, tracing: typeof Tracing) => Integration[]);
+ apiToken?: string;
+ shouldHandleError: (code: number) => boolean;
+ requestHandlerOptions?: RequestHandlerOptions;
+ enableRequestHandler?: boolean;
+ enableTracing?: boolean;
+ webHookOptions?: SentryWebHookOptions;
+};
+
+export enum SentryWebHookEvent {
+ SENTRY_RECEIVED_ISSUE = 'SentryReceivedIssue',
+ SENTRY_RECEIVED_ERROR = 'SentryReceivedError',
+ SENTRY_RECEIVED_COMMENT = 'SentryReceivedComment',
+ SENTRY_RECEIVED_EVENT_OR_METRIC_ALERT = 'SentryReceivedEventOrMetricAlert',
+ SENTRY_RECEIVED_INSTALL_OR_DELETED = 'SentryReceivedInstallOrDeleted',
+}
+
+export type SentryWebHookData = {
+ actor: unknown;
+ action: unknown;
+ data: unknown;
+ installation: unknown;
+};
diff --git a/packages/medusa-plugin-sentry/src/utils/index.ts b/packages/medusa-plugin-sentry/src/utils/index.ts
new file mode 100644
index 0000000..4214883
--- /dev/null
+++ b/packages/medusa-plugin-sentry/src/utils/index.ts
@@ -0,0 +1,12 @@
+import crypto from 'crypto';
+
+export function verifySignature(req, secret: string): boolean {
+ const hmac = crypto.createHmac('sha256', secret);
+ hmac.update(JSON.stringify(req.body), 'utf8');
+ const digest = hmac.digest('hex');
+ return digest === req.get('sentry-hook-signature');
+}
+
+export function isFunction(val: unknown): val is Function {
+ return val != null && typeof val === 'function';
+}
diff --git a/packages/medusa-plugin-sentry/tsconfig.json b/packages/medusa-plugin-sentry/tsconfig.json
index 336f115..a7fbb56 100644
--- a/packages/medusa-plugin-sentry/tsconfig.json
+++ b/packages/medusa-plugin-sentry/tsconfig.json
@@ -1,12 +1,17 @@
{
- "extends": "../tsconfig.json",
+ "extends": "../../tsconfig.json",
"compilerOptions": {
+ "declaration": true,
+ "declarationMap": true,
+ "emitDecoratorMetadata": true,
+ "module": "commonjs",
+ "noEmit": false,
"resolveJsonModule": true,
"esModuleInterop": true,
"outDir": ".",
"rootDir": "src",
- "baseUrl": "./",
+ "baseUrl": "./"
},
- "include": ["src/**/*"],
- "exclude": ["node_modules", "**/__tests__/*", "**/__e2e__/*"],
+ "include": ["src"],
+ "exclude": ["**/node_modules", "**/__tests__/*", "**/__e2e__/*"],
}
\ No newline at end of file
diff --git a/packages/tsconfig.json b/packages/tsconfig.json
deleted file mode 100644
index b559349..0000000
--- a/packages/tsconfig.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "extends": "../tsconfig.json",
- "compilerOptions": {
- "declaration": true,
- "declarationMap": true,
- "emitDecoratorMetadata": true,
- "module": "commonjs",
- "noEmit": false,
- "composite": true
- },
- "files": [],
- "references": [{ "path": "./medusa-plugin-sentry" }]
-}
\ No newline at end of file
diff --git a/tsconfig.json b/tsconfig.json
index bf4b486..9628e20 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -9,7 +9,8 @@
"target": "es2017",
"sourceMap": true,
"skipLibCheck": true,
- "esModuleInterop": true
+ "esModuleInterop": true,
+ "incremental": false
},
- "exclude": ["**/node_modules"]
+ "exclude": ["node_modules"]
}
diff --git a/yarn.lock b/yarn.lock
index b5b58a6..8d04730 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1453,17 +1453,49 @@
resolved "https://registry.yarnpkg.com/@sideway/pinpoint/-/pinpoint-2.0.0.tgz#cff8ffadc372ad29fd3f78277aeb29e632cc70df"
integrity sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==
+"@sqltools/formatter@^1.2.2":
+ version "1.2.3"
+ resolved "https://registry.yarnpkg.com/@sqltools/formatter/-/formatter-1.2.3.tgz#1185726610acc37317ddab11c3c7f9066966bd20"
+ integrity sha512-O3uyB/JbkAEMZaP3YqyHH7TMnex7tWyCbCI4EfJdOCoN6HIhqdJBWTM6aCCiWQ/5f5wxjgU735QAIpJbjDvmzg==
+
"@tootallnate/once@1":
version "1.1.2"
resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82"
integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==
-"@types/express@types/express":
- version "4.14.0"
- resolved "https://codeload.github.com/types/express/tar.gz/7670cf1cbce96b3159e3ff04a253926b34111220"
+"@types/body-parser@*":
+ version "1.19.2"
+ resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.2.tgz#aea2059e28b7658639081347ac4fab3de166e6f0"
+ integrity sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==
dependencies:
- "@types/serve-static" "github:types/npm-serve-static#c1f96843c8b96a37f6c534cb1dadb48f5329e4e0"
- path-to-regexp "github:pillarjs/path-to-regexp#ec285ed3500aed455df59e3b8b07f473412918a4"
+ "@types/connect" "*"
+ "@types/node" "*"
+
+"@types/connect@*":
+ version "3.4.35"
+ resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.35.tgz#5fcf6ae445e4021d1fc2219a4873cc73a3bb2ad1"
+ integrity sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==
+ dependencies:
+ "@types/node" "*"
+
+"@types/express-serve-static-core@^4.17.18":
+ version "4.17.31"
+ resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.31.tgz#a1139efeab4e7323834bb0226e62ac019f474b2f"
+ integrity sha512-DxMhY+NAsTwMMFHBTtJFNp5qiHKJ7TeqOo23zVEM9alT1Ml27Q3xcTH0xwxn7Q0BbMcVEJOs/7aQtUWupUQN3Q==
+ dependencies:
+ "@types/node" "*"
+ "@types/qs" "*"
+ "@types/range-parser" "*"
+
+"@types/express@^4.17.14":
+ version "4.17.14"
+ resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.14.tgz#143ea0557249bc1b3b54f15db4c81c3d4eb3569c"
+ integrity sha512-TEbt+vaPFQ+xpxFLFssxUDXj5cWCxZJjIcB7Yg0k0GMHGtgtQgpvx/MUQUeAkNbA9AAGrwkAsoeItdTgS7FMyg==
+ dependencies:
+ "@types/body-parser" "*"
+ "@types/express-serve-static-core" "^4.17.18"
+ "@types/qs" "*"
+ "@types/serve-static" "*"
"@types/ioredis@^4.28.10":
version "4.28.10"
@@ -1482,6 +1514,11 @@
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.186.tgz#862e5514dd7bd66ada6c70ee5fce844b06c8ee97"
integrity sha512-eHcVlLXP0c2FlMPm56ITode2AgLMSa6aJ05JTTbYbI+7EMkCEE5qk2E41d5g2lCVTqRe0GnnRFurmlCsDODrPw==
+"@types/mime@*":
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/@types/mime/-/mime-3.0.1.tgz#5f8f2bca0a5863cb69bc0b0acd88c96cb1d4ae10"
+ integrity sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==
+
"@types/minimatch@^3.0.3":
version "3.0.5"
resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.5.tgz#1001cc5e6a3704b83c236027e77f2f58ea010f40"
@@ -1507,9 +1544,28 @@
resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0"
integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==
-"@types/serve-static@github:types/npm-serve-static#c1f96843c8b96a37f6c534cb1dadb48f5329e4e0":
- version "1.11.1"
- resolved "https://codeload.github.com/types/npm-serve-static/tar.gz/c1f96843c8b96a37f6c534cb1dadb48f5329e4e0"
+"@types/qs@*":
+ version "6.9.7"
+ resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.7.tgz#63bb7d067db107cc1e457c303bc25d511febf6cb"
+ integrity sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==
+
+"@types/range-parser@*":
+ version "1.2.4"
+ resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.4.tgz#cd667bcfdd025213aafb7ca5915a932590acdcdc"
+ integrity sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==
+
+"@types/serve-static@*":
+ version "1.15.0"
+ resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.15.0.tgz#c7930ff61afb334e121a9da780aac0d9b8f34155"
+ integrity sha512-z5xyF6uh8CbjAu9760KDKsH2FcDxZ2tFCsA4HIMWE6IkiYMXfVoa+4f9KX+FN0ZLsaMw1WNG2ETLA6N+/YA+cg==
+ dependencies:
+ "@types/mime" "*"
+ "@types/node" "*"
+
+"@types/zen-observable@0.8.3":
+ version "0.8.3"
+ resolved "https://registry.yarnpkg.com/@types/zen-observable/-/zen-observable-0.8.3.tgz#781d360c282436494b32fe7d9f7f8e64b3118aa3"
+ integrity sha512-fbF6oTd4sGGy0xjHPKAt+eS2CrxJ3+6gQ3FGcBoIJR2TLAyCkCyI8JqZNy+FeON0AhVgNJoUumVoZQjBFUqHkw==
"@typescript-eslint/eslint-plugin@^5.4.0":
version "5.39.0"
@@ -1709,6 +1765,11 @@ ansicolors@~0.3.2:
resolved "https://registry.yarnpkg.com/ansicolors/-/ansicolors-0.3.2.tgz#665597de86a9ffe3aa9bfbe6cae5c6ea426b4979"
integrity sha512-QXu7BPrP29VllRxH8GwB7x5iX5qWKAAMLqKQGWTeLWVlNHNOpVMJ91dsxQAIWXpjuW5wqvxu3Jd/nRjrJ+0pqg==
+any-promise@^1.0.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f"
+ integrity sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==
+
anymatch@~3.1.2:
version "3.1.2"
resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716"
@@ -1717,6 +1778,11 @@ anymatch@~3.1.2:
normalize-path "^3.0.0"
picomatch "^2.0.4"
+app-root-path@^3.0.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/app-root-path/-/app-root-path-3.1.0.tgz#5971a2fc12ba170369a7a1ef018c71e6e47c2e86"
+ integrity sha512-biN3PwB2gUtjaYy/isrU3aNWI5w+fAfvHkSvCKeQGxhmYpwKFUxudR3Yya+KqVRHBmEDYh+/lTozYCFbmzX4nA==
+
append-field@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/append-field/-/append-field-1.0.0.tgz#1e3440e915f0b1203d23748e78edd7b9b5b43e56"
@@ -1879,6 +1945,15 @@ axios@^0.21.1:
dependencies:
follow-redirects "^1.14.0"
+axios@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/axios/-/axios-1.0.0.tgz#16ded6096c1d37650db9f6a8d48a2f7c1bb58622"
+ integrity sha512-SsHsGFN1qNPFT5QhSoSD37SHDfGyLSW5AESmyLk2JeCMHv5g0I9g0Hz/zQHx2KNe0jGXh2q2hAm7OdkXm360CA==
+ dependencies:
+ follow-redirects "^1.15.0"
+ form-data "^4.0.0"
+ proxy-from-env "^1.1.0"
+
balanced-match@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
@@ -2002,6 +2077,14 @@ buffer@^5.5.0:
base64-js "^1.3.1"
ieee754 "^1.1.13"
+buffer@^6.0.3:
+ version "6.0.3"
+ resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6"
+ integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==
+ dependencies:
+ base64-js "^1.3.1"
+ ieee754 "^1.2.1"
+
builtin-modules@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f"
@@ -2195,7 +2278,7 @@ class-transformer@^0.5.1:
resolved "https://registry.yarnpkg.com/class-transformer/-/class-transformer-0.5.1.tgz#24147d5dffd2a6cea930a3250a677addf96ab336"
integrity sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==
-class-validator@^0.13.1:
+class-validator@^0.13.1, class-validator@^0.13.2:
version "0.13.2"
resolved "https://registry.yarnpkg.com/class-validator/-/class-validator-0.13.2.tgz#64b031e9f3f81a1e1dcd04a5d604734608b24143"
integrity sha512-yBUcQy07FPlGzUjoLuUfIOXzgynnQPPruyK1Ge2B74k9ROwnle1E+NxLWnUv5OLU8hA/qL5leAE9XnXq3byaBw==
@@ -2227,6 +2310,18 @@ cli-cursor@^3.1.0:
dependencies:
restore-cursor "^3.1.0"
+cli-highlight@^2.1.11:
+ version "2.1.11"
+ resolved "https://registry.yarnpkg.com/cli-highlight/-/cli-highlight-2.1.11.tgz#49736fa452f0aaf4fae580e30acb26828d2dc1bf"
+ integrity sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg==
+ dependencies:
+ chalk "^4.0.0"
+ highlight.js "^10.7.1"
+ mz "^2.4.0"
+ parse5 "^5.1.1"
+ parse5-htmlparser2-tree-adapter "^6.0.0"
+ yargs "^16.0.0"
+
cli-progress@^3.4.0:
version "3.11.2"
resolved "https://registry.yarnpkg.com/cli-progress/-/cli-progress-3.11.2.tgz#f8c89bd157e74f3f2c43bcfb3505670b4d48fc77"
@@ -2294,6 +2389,15 @@ cliui@^7.0.2:
strip-ansi "^6.0.0"
wrap-ansi "^7.0.0"
+cliui@^8.0.1:
+ version "8.0.1"
+ resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa"
+ integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==
+ dependencies:
+ string-width "^4.2.0"
+ strip-ansi "^6.0.1"
+ wrap-ansi "^7.0.0"
+
clone-deep@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387"
@@ -2386,7 +2490,7 @@ columnify@^1.5.4:
strip-ansi "^6.0.1"
wcwidth "^1.0.0"
-combined-stream@^1.0.6, combined-stream@~1.0.6:
+combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6:
version "1.0.8"
resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==
@@ -3389,7 +3493,7 @@ fn.name@1.x.x:
resolved "https://registry.yarnpkg.com/fn.name/-/fn.name-1.1.0.tgz#26cad8017967aea8731bc42961d04a3d5988accc"
integrity sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==
-follow-redirects@^1.14.0:
+follow-redirects@^1.14.0, follow-redirects@^1.15.0:
version "1.15.2"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13"
integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==
@@ -3406,6 +3510,15 @@ forever-agent@~0.6.1:
resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
integrity sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==
+form-data@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452"
+ integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==
+ dependencies:
+ asynckit "^0.4.0"
+ combined-stream "^1.0.8"
+ mime-types "^2.1.12"
+
form-data@~2.3.2:
version "2.3.3"
resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6"
@@ -3792,6 +3905,11 @@ has@^1.0.3:
dependencies:
function-bind "^1.1.1"
+highlight.js@^10.7.1:
+ version "10.7.3"
+ resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.7.3.tgz#697272e3991356e40c3cac566a74eef681756531"
+ integrity sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==
+
hosted-git-info@^2.1.4:
version "2.8.9"
resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9"
@@ -3882,7 +4000,7 @@ iconv-lite@^0.6.2:
dependencies:
safer-buffer ">= 2.1.2 < 3.0.0"
-ieee754@^1.1.13:
+ieee754@^1.1.13, ieee754@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352"
integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==
@@ -3938,7 +4056,7 @@ inflight@^1.0.4:
once "^1.3.0"
wrappy "1"
-inherits@2, inherits@2.0.4, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3:
+inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3:
version "2.0.4"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
@@ -4378,7 +4496,7 @@ js-yaml@^3.13.1:
argparse "^1.0.7"
esprima "^4.0.0"
-js-yaml@^4.1.0:
+js-yaml@^4.0.0, js-yaml@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602"
integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==
@@ -4838,6 +4956,11 @@ medusa-core-utils@^1.1.31:
joi "^17.3.0"
joi-objectid "^3.0.1"
+medusa-interfaces@^1.3.3:
+ version "1.3.3"
+ resolved "https://registry.yarnpkg.com/medusa-interfaces/-/medusa-interfaces-1.3.3.tgz#85745ea768fcbb093d3d5d3dee987fcdf996cb45"
+ integrity sha512-e2ZkKtBppBVZYu09y479b5JgkNhzzDLuOHPxVXN2CVK9vUCYrzfEPMXd6B21CTchrhD07MCtR17l4OElRvPtSw==
+
medusa-telemetry@0.0.13:
version "0.0.13"
resolved "https://registry.yarnpkg.com/medusa-telemetry/-/medusa-telemetry-0.0.13.tgz#48f40051d6c7dadc8eed2898a5b5f43adaab1d3c"
@@ -5138,6 +5261,15 @@ mute-stream@0.0.8, mute-stream@~0.0.4:
resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d"
integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==
+mz@^2.4.0:
+ version "2.7.0"
+ resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32"
+ integrity sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==
+ dependencies:
+ any-promise "^1.0.0"
+ object-assign "^4.0.1"
+ thenify-all "^1.0.0"
+
natural-compare@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
@@ -5456,7 +5588,7 @@ oauth-sign@~0.9.0:
resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455"
integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==
-object-assign@^4, object-assign@^4.1.0, object-assign@^4.1.1:
+object-assign@^4, object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==
@@ -5776,6 +5908,23 @@ parse-url@^6.0.0:
parse-path "^4.0.0"
protocols "^1.4.0"
+parse5-htmlparser2-tree-adapter@^6.0.0:
+ version "6.0.1"
+ resolved "https://registry.yarnpkg.com/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz#2cdf9ad823321140370d4dbf5d3e92c7c8ddc6e6"
+ integrity sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==
+ dependencies:
+ parse5 "^6.0.1"
+
+parse5@^5.1.1:
+ version "5.1.1"
+ resolved "https://registry.yarnpkg.com/parse5/-/parse5-5.1.1.tgz#f68e4e5ba1852ac2cadc00f4555fff6c2abb6178"
+ integrity sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==
+
+parse5@^6.0.1:
+ version "6.0.1"
+ resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b"
+ integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==
+
parseurl@~1.3.3:
version "1.3.3"
resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4"
@@ -5867,12 +6016,6 @@ path-to-regexp@0.1.7:
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c"
integrity sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==
-"path-to-regexp@github:pillarjs/path-to-regexp#ec285ed3500aed455df59e3b8b07f473412918a4":
- version "1.5.3"
- resolved "https://codeload.github.com/pillarjs/path-to-regexp/tar.gz/ec285ed3500aed455df59e3b8b07f473412918a4"
- dependencies:
- isarray "0.0.1"
-
path-type@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f"
@@ -6109,6 +6252,11 @@ proxy-addr@~2.0.7:
forwarded "0.2.0"
ipaddr.js "1.9.1"
+proxy-from-env@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2"
+ integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==
+
psl@^1.1.28:
version "1.9.0"
resolved "https://registry.yarnpkg.com/psl/-/psl-1.9.0.tgz#d0df2a137f00794565fcaf3b2c00cd09f8d5a5a7"
@@ -6578,6 +6726,11 @@ safe-stable-stringify@^2.3.1:
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
+sax@>=0.6.0:
+ version "1.2.4"
+ resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
+ integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==
+
scrypt-kdf@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/scrypt-kdf/-/scrypt-kdf-2.0.1.tgz#3355224c52d398331b2cbf2b70a7be26b52c53e6"
@@ -6639,6 +6792,14 @@ setprototypeof@1.2.0:
resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424"
integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==
+sha.js@^2.4.11:
+ version "2.4.11"
+ resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7"
+ integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==
+ dependencies:
+ inherits "^2.0.1"
+ safe-buffer "^5.0.1"
+
shallow-clone@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-3.0.1.tgz#8f2981ad92531f55035b01fb230769a40e02efa3"
@@ -7101,6 +7262,20 @@ text-table@^0.2.0:
resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==
+thenify-all@^1.0.0:
+ version "1.6.0"
+ resolved "https://registry.yarnpkg.com/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726"
+ integrity sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==
+ dependencies:
+ thenify ">= 3.1.0 < 4"
+
+"thenify@>= 3.1.0 < 4":
+ version "3.3.1"
+ resolved "https://registry.yarnpkg.com/thenify/-/thenify-3.3.1.tgz#8932e686a4066038a016dd9e2ca46add9838a95f"
+ integrity sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==
+ dependencies:
+ any-promise "^1.0.0"
+
through2@^2.0.0:
version "2.0.5"
resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd"
@@ -7298,10 +7473,33 @@ typedarray@^0.0.6:
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
integrity sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==
-typescript@^3.7.5:
- version "3.9.10"
- resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.10.tgz#70f3910ac7a51ed6bef79da7800690b19bf778b8"
- integrity sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q==
+typeorm@^0.2.45:
+ version "0.2.45"
+ resolved "https://registry.yarnpkg.com/typeorm/-/typeorm-0.2.45.tgz#e5bbb3af822dc4646bad96cfa48cd22fa4687cea"
+ integrity sha512-c0rCO8VMJ3ER7JQ73xfk0zDnVv0WDjpsP6Q1m6CVKul7DB9iVdWLRjPzc8v2eaeBuomsbZ2+gTaYr8k1gm3bYA==
+ dependencies:
+ "@sqltools/formatter" "^1.2.2"
+ app-root-path "^3.0.0"
+ buffer "^6.0.3"
+ chalk "^4.1.0"
+ cli-highlight "^2.1.11"
+ debug "^4.3.1"
+ dotenv "^8.2.0"
+ glob "^7.1.6"
+ js-yaml "^4.0.0"
+ mkdirp "^1.0.4"
+ reflect-metadata "^0.1.13"
+ sha.js "^2.4.11"
+ tslib "^2.1.0"
+ uuid "^8.3.2"
+ xml2js "^0.4.23"
+ yargs "^17.0.1"
+ zen-observable-ts "^1.0.0"
+
+typescript@^4.5.5:
+ version "4.8.4"
+ resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.8.4.tgz#c464abca159669597be5f96b8943500b238e60e6"
+ integrity sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==
uglify-js@^3.1.4:
version "3.17.2"
@@ -7675,6 +7873,19 @@ xdg-basedir@^4.0.0:
resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-4.0.0.tgz#4bc8d9984403696225ef83a1573cbbcb4e79db13"
integrity sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==
+xml2js@^0.4.23:
+ version "0.4.23"
+ resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.23.tgz#a0c69516752421eb2ac758ee4d4ccf58843eac66"
+ integrity sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==
+ dependencies:
+ sax ">=0.6.0"
+ xmlbuilder "~11.0.0"
+
+xmlbuilder@~11.0.0:
+ version "11.0.1"
+ resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-11.0.1.tgz#be9bae1c8a046e76b31127726347d0ad7002beb3"
+ integrity sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==
+
xtend@^4.0.0, xtend@~4.0.1:
version "4.0.2"
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"
@@ -7723,6 +7934,11 @@ yargs-parser@^20.2.2, yargs-parser@^20.2.3:
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee"
integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==
+yargs-parser@^21.0.0:
+ version "21.1.1"
+ resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35"
+ integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==
+
yargs@^15.3.1:
version "15.4.1"
resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.4.1.tgz#0d87a16de01aee9d8bec2bfbf74f67851730f4f8"
@@ -7740,7 +7956,7 @@ yargs@^15.3.1:
y18n "^4.0.0"
yargs-parser "^18.1.2"
-yargs@^16.2.0:
+yargs@^16.0.0, yargs@^16.2.0:
version "16.2.0"
resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66"
integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==
@@ -7753,6 +7969,19 @@ yargs@^16.2.0:
y18n "^5.0.5"
yargs-parser "^20.2.2"
+yargs@^17.0.1:
+ version "17.6.0"
+ resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.6.0.tgz#e134900fc1f218bc230192bdec06a0a5f973e46c"
+ integrity sha512-8H/wTDqlSwoSnScvV2N/JHfLWOKuh5MVla9hqLjK3nsfyy6Y4kDSYSvkU5YCUEPOSnRXfIyx3Sq+B/IWudTo4g==
+ dependencies:
+ cliui "^8.0.1"
+ escalade "^3.1.1"
+ get-caller-file "^2.0.5"
+ require-directory "^2.1.1"
+ string-width "^4.2.3"
+ y18n "^5.0.5"
+ yargs-parser "^21.0.0"
+
yn@3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50"
@@ -7762,3 +7991,16 @@ yocto-queue@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"
integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==
+
+zen-observable-ts@^1.0.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/zen-observable-ts/-/zen-observable-ts-1.1.0.tgz#2d1aa9d79b87058e9b75698b92791c1838551f83"
+ integrity sha512-1h4zlLSqI2cRLPJUHJFL8bCWHhkpuXkF+dbGkRaWjgDIG26DmzyshUMrdV/rL3UnR+mhaX4fRq8LPouq0MYYIA==
+ dependencies:
+ "@types/zen-observable" "0.8.3"
+ zen-observable "0.8.15"
+
+zen-observable@0.8.15:
+ version "0.8.15"
+ resolved "https://registry.yarnpkg.com/zen-observable/-/zen-observable-0.8.15.tgz#96415c512d8e3ffd920afd3889604e30b9eaac15"
+ integrity sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ==