Compare commits

..

1 Commits

Author SHA1 Message Date
Ali BARIN
ab4abd590a feat(formatter/text): stringify json transformer 2024-08-16 14:08:00 +00:00
56 changed files with 474 additions and 1696 deletions

View File

@@ -11,7 +11,6 @@
"start:worker": "node src/worker.js",
"pretest": "APP_ENV=test node ./test/setup/prepare-test-env.js",
"test": "APP_ENV=test vitest run",
"test:watch": "APP_ENV=test vitest watch",
"lint": "eslint .",
"db:create": "node ./bin/database/create.js",
"db:seed:user": "node ./bin/database/seed-user.js",

View File

@@ -33,7 +33,6 @@ export default defineAction({
type: 'string',
required: true,
variables: true,
valueType: 'parse',
},
],
},

View File

@@ -16,6 +16,7 @@ import trimWhitespace from './transformers/trim-whitespace.js';
import useDefaultValue from './transformers/use-default-value.js';
import parseStringifiedJson from './transformers/parse-stringified-json.js';
import createUuid from './transformers/create-uuid.js';
import stringifyJson from './transformers/stringify-json.js';
const transformers = {
base64ToString,
@@ -34,6 +35,7 @@ const transformers = {
useDefaultValue,
parseStringifiedJson,
createUuid,
stringifyJson,
};
export default defineAction({
@@ -63,6 +65,7 @@ export default defineAction({
{ label: 'Extract Number', value: 'extractNumber' },
{ label: 'Lowercase', value: 'lowercase' },
{ label: 'Parse stringified JSON', value: 'parseStringifiedJson' },
{ label: 'Stringify JSON', value: 'stringifyJson' },
{ label: 'Pluralize', value: 'pluralize' },
{ label: 'Replace', value: 'replace' },
{ label: 'String to Base64', value: 'stringToBase64' },

View File

@@ -0,0 +1,7 @@
const stringifyJson = ($) => {
const input = $.step.parameters.input;
return JSON.stringify(input);
};
export default stringifyJson;

View File

@@ -13,6 +13,7 @@ import encodeUri from './text/encode-uri.js';
import trimWhitespace from './text/trim-whitespace.js';
import useDefaultValue from './text/use-default-value.js';
import parseStringifiedJson from './text/parse-stringified-json.js';
import stringifyJson from './text/stringify-json.js';
import performMathOperation from './numbers/perform-math-operation.js';
import randomNumber from './numbers/random-number.js';
import formatNumber from './numbers/format-number.js';
@@ -40,6 +41,7 @@ const options = {
formatPhoneNumber,
formatDateTime,
parseStringifiedJson,
stringifyJson,
};
export default {

View File

@@ -1,4 +1,4 @@
const useDefaultValue = [
const parseStringifiedJson = [
{
label: 'Input',
key: 'input',
@@ -9,4 +9,4 @@ const useDefaultValue = [
},
];
export default useDefaultValue;
export default parseStringifiedJson;

View File

@@ -0,0 +1,12 @@
const stringifyJson = [
{
label: 'Input',
key: 'input',
type: 'string',
required: true,
description: 'JSON to stringify.',
variables: true,
},
];
export default stringifyJson;

View File

@@ -11,5 +11,5 @@ export default async (request, response) => {
await accessToken.revoke();
response.status(204).end();
response.status(204).send();
};

View File

@@ -1,25 +0,0 @@
import { renderObject } from '../../../../../helpers/renderer.js';
import AppConfig from '../../../../../models/app-config.js';
export default async (request, response) => {
const appConfig = await AppConfig.query()
.findOne({ key: request.params.appKey })
.throwIfNotFound();
const appAuthClient = await appConfig
.$relatedQuery('appAuthClients')
.insert(appAuthClientParams(request));
renderObject(response, appAuthClient, { status: 201 });
};
const appAuthClientParams = (request) => {
const { active, appKey, name, formattedAuthDefaults } = request.body;
return {
active,
appKey,
name,
formattedAuthDefaults,
};
};

View File

@@ -1,94 +0,0 @@
import { vi, describe, it, expect, beforeEach } from 'vitest';
import request from 'supertest';
import app from '../../../../../app.js';
import createAuthTokenByUserId from '../../../../../helpers/create-auth-token-by-user-id.js';
import { createUser } from '../../../../../../test/factories/user.js';
import { createRole } from '../../../../../../test/factories/role.js';
import createAppAuthClientMock from '../../../../../../test/mocks/rest/api/v1/admin/apps/create-auth-client.js';
import { createAppConfig } from '../../../../../../test/factories/app-config.js';
import * as license from '../../../../../helpers/license.ee.js';
describe('POST /api/v1/admin/apps/:appKey/auth-clients', () => {
let currentUser, adminRole, token;
beforeEach(async () => {
vi.spyOn(license, 'hasValidLicense').mockResolvedValue(true);
adminRole = await createRole({ key: 'admin' });
currentUser = await createUser({ roleId: adminRole.id });
token = await createAuthTokenByUserId(currentUser.id);
});
it('should return created response for valid app config', async () => {
await createAppConfig({
key: 'gitlab',
});
const appAuthClient = {
active: true,
appKey: 'gitlab',
name: 'First auth client',
formattedAuthDefaults: {
clientid: 'sample client ID',
clientSecret: 'sample client secret',
instanceUrl: 'https://gitlab.com',
oAuthRedirectUrl: 'http://localhost:3001/app/gitlab/connection/add',
},
};
const response = await request(app)
.post('/api/v1/admin/apps/gitlab/auth-clients')
.set('Authorization', token)
.send(appAuthClient)
.expect(201);
const expectedPayload = createAppAuthClientMock(appAuthClient);
expect(response.body).toMatchObject(expectedPayload);
});
it('should return not found response for not existing app config', async () => {
const appAuthClient = {
active: true,
appKey: 'gitlab',
name: 'First auth client',
formattedAuthDefaults: {
clientid: 'sample client ID',
clientSecret: 'sample client secret',
instanceUrl: 'https://gitlab.com',
oAuthRedirectUrl: 'http://localhost:3001/app/gitlab/connection/add',
},
};
await request(app)
.post('/api/v1/admin/apps/gitlab/auth-clients')
.set('Authorization', token)
.send(appAuthClient)
.expect(404);
});
it('should return bad request response for missing required fields', async () => {
await createAppConfig({
key: 'gitlab',
});
const appAuthClient = {
appKey: 'gitlab',
};
const response = await request(app)
.post('/api/v1/admin/apps/gitlab/auth-clients')
.set('Authorization', token)
.send(appAuthClient)
.expect(422);
expect(response.body.meta.type).toEqual('ModelValidation');
expect(response.body.errors).toMatchObject({
name: ["must have required property 'name'"],
formattedAuthDefaults: [
"must have required property 'formattedAuthDefaults'",
],
});
});
});

View File

@@ -1,21 +0,0 @@
import { renderObject } from '../../../../../helpers/renderer.js';
import AppConfig from '../../../../../models/app-config.js';
export default async (request, response) => {
const createdAppConfig = await AppConfig.query().insertAndFetch(
appConfigParams(request)
);
renderObject(response, createdAppConfig, { status: 201 });
};
const appConfigParams = (request) => {
const { allowCustomConnection, shared, disabled } = request.body;
return {
key: request.params.appKey,
allowCustomConnection,
shared,
disabled,
};
};

View File

@@ -1,67 +0,0 @@
import { vi, describe, it, expect, beforeEach } from 'vitest';
import request from 'supertest';
import app from '../../../../../app.js';
import createAuthTokenByUserId from '../../../../../helpers/create-auth-token-by-user-id.js';
import { createUser } from '../../../../../../test/factories/user.js';
import { createRole } from '../../../../../../test/factories/role.js';
import createAppConfigMock from '../../../../../../test/mocks/rest/api/v1/admin/apps/create-config.js';
import { createAppConfig } from '../../../../../../test/factories/app-config.js';
import * as license from '../../../../../helpers/license.ee.js';
describe('POST /api/v1/admin/apps/:appKey/config', () => {
let currentUser, adminRole, token;
beforeEach(async () => {
vi.spyOn(license, 'hasValidLicense').mockResolvedValue(true);
adminRole = await createRole({ key: 'admin' });
currentUser = await createUser({ roleId: adminRole.id });
token = await createAuthTokenByUserId(currentUser.id);
});
it('should return created app config', async () => {
const appConfig = {
allowCustomConnection: true,
shared: true,
disabled: false,
};
const response = await request(app)
.post('/api/v1/admin/apps/gitlab/config')
.set('Authorization', token)
.send(appConfig)
.expect(201);
const expectedPayload = createAppConfigMock({
...appConfig,
key: 'gitlab',
});
expect(response.body).toMatchObject(expectedPayload);
});
it('should return HTTP 422 for already existing app config', async () => {
const appConfig = {
key: 'gitlab',
allowCustomConnection: true,
shared: true,
disabled: false,
};
await createAppConfig(appConfig);
const response = await request(app)
.post('/api/v1/admin/apps/gitlab/config')
.set('Authorization', token)
.send({
disabled: false,
})
.expect(422);
expect(response.body.meta.type).toEqual('UniqueViolationError');
expect(response.body.errors).toMatchObject({
key: ["'key' must be unique."],
});
});
});

View File

@@ -1,14 +0,0 @@
import { renderObject } from '../../../../helpers/renderer.js';
export default async (request, response) => {
let connection = await request.currentUser
.$relatedQuery('connections')
.findOne({
id: request.params.connectionId,
})
.throwIfNotFound();
connection = await connection.verifyAndUpdateConnection();
renderObject(response, connection);
};

View File

@@ -1,82 +0,0 @@
import { vi, describe, it, expect, beforeEach } from 'vitest';
import request from 'supertest';
import Crypto from 'crypto';
import app from '../../../../app.js';
import App from '../../../../models/app.js';
import createAuthTokenByUserId from '../../../../helpers/create-auth-token-by-user-id.js';
import { createUser } from '../../../../../test/factories/user.js';
import { createConnection } from '../../../../../test/factories/connection.js';
import { createPermission } from '../../../../../test/factories/permission.js';
describe('POST /api/v1/connections/:connectionId/verify', () => {
let currentUser, currentUserRole, token;
beforeEach(async () => {
currentUser = await createUser();
currentUserRole = await currentUser.$relatedQuery('role');
token = await createAuthTokenByUserId(currentUser.id);
});
it('should update the connection as verified for current user', async () => {
const currentUserConnection = await createConnection({
userId: currentUser.id,
key: 'deepl',
verified: true,
});
await createPermission({
action: 'create',
subject: 'Connection',
roleId: currentUserRole.id,
conditions: ['isCreator'],
});
vi.spyOn(App, 'findOneByKey').mockImplementation((key) => {
if (key !== currentUserConnection.key) return;
return {
auth: {
verifyCredentials: vi.fn().mockResolvedValue(),
},
};
});
const response = await request(app)
.post(`/api/v1/connections/${currentUserConnection.id}/verify`)
.set('Authorization', token)
.expect(200);
expect(response.body.data.verified).toEqual(true);
});
it('should return not found response for not existing connection UUID', async () => {
const notExistingConnectionUUID = Crypto.randomUUID();
await createPermission({
action: 'create',
subject: 'Connection',
roleId: currentUserRole.id,
conditions: ['isCreator'],
});
await request(app)
.post(`/api/v1/connections/${notExistingConnectionUUID}/verify`)
.set('Authorization', token)
.expect(404);
});
it('should return bad request response for invalid UUID', async () => {
await createPermission({
action: 'create',
subject: 'Connection',
roleId: currentUserRole.id,
conditions: ['isCreator'],
});
await request(app)
.post('/api/v1/connections/invalidConnectionUUID/verify')
.set('Authorization', token)
.expect(400);
});
});

View File

@@ -1,9 +0,0 @@
export default async (request, response) => {
const step = await request.currentUser.authorizedSteps
.findById(request.params.stepId)
.throwIfNotFound();
await step.delete();
response.status(204).end();
};

View File

@@ -1,134 +0,0 @@
import { describe, it, beforeEach } from 'vitest';
import request from 'supertest';
import Crypto from 'crypto';
import app from '../../../../app.js';
import createAuthTokenByUserId from '../../../../helpers/create-auth-token-by-user-id';
import { createUser } from '../../../../../test/factories/user';
import { createConnection } from '../../../../../test/factories/connection';
import { createFlow } from '../../../../../test/factories/flow';
import { createStep } from '../../../../../test/factories/step';
import { createPermission } from '../../../../../test/factories/permission';
describe('DELETE /api/v1/steps/:stepId', () => {
let currentUser, currentUserRole, token;
beforeEach(async () => {
currentUser = await createUser();
currentUserRole = await currentUser.$relatedQuery('role');
token = await createAuthTokenByUserId(currentUser.id);
});
it('should remove the step of the current user and return no content', async () => {
const currentUserFlow = await createFlow({ userId: currentUser.id });
const currentUserConnection = await createConnection();
await createStep({
flowId: currentUserFlow.id,
connectionId: currentUserConnection.id,
});
const actionStep = await createStep({
flowId: currentUserFlow.id,
connectionId: currentUserConnection.id,
});
await createPermission({
action: 'read',
subject: 'Flow',
roleId: currentUserRole.id,
conditions: ['isCreator'],
});
await createPermission({
action: 'update',
subject: 'Flow',
roleId: currentUserRole.id,
conditions: ['isCreator'],
});
await request(app)
.delete(`/api/v1/steps/${actionStep.id}`)
.set('Authorization', token)
.expect(204);
});
it('should remove the step of the another user and return no content', async () => {
const anotherUser = await createUser();
const anotherUserFlow = await createFlow({ userId: anotherUser.id });
const anotherUserConnection = await createConnection();
await createStep({
flowId: anotherUserFlow.id,
connectionId: anotherUserConnection.id,
});
const actionStep = await createStep({
flowId: anotherUserFlow.id,
connectionId: anotherUserConnection.id,
});
await createPermission({
action: 'read',
subject: 'Flow',
roleId: currentUserRole.id,
conditions: [],
});
await createPermission({
action: 'update',
subject: 'Flow',
roleId: currentUserRole.id,
conditions: [],
});
await request(app)
.delete(`/api/v1/steps/${actionStep.id}`)
.set('Authorization', token)
.expect(204);
});
it('should return not found response for not existing step UUID', async () => {
await createPermission({
action: 'update',
subject: 'Flow',
roleId: currentUserRole.id,
conditions: [],
});
await createPermission({
action: 'read',
subject: 'Flow',
roleId: currentUserRole.id,
conditions: [],
});
const notExistingStepUUID = Crypto.randomUUID();
await request(app)
.delete(`/api/v1/steps/${notExistingStepUUID}`)
.set('Authorization', token)
.expect(404);
});
it('should return bad request response for invalid step UUID', async () => {
await createPermission({
action: 'update',
subject: 'Flow',
roleId: currentUserRole.id,
conditions: [],
});
await createPermission({
action: 'read',
subject: 'Flow',
roleId: currentUserRole.id,
conditions: [],
});
await request(app)
.delete('/api/v1/steps/invalidStepUUID')
.set('Authorization', token)
.expect(400);
});
});

View File

@@ -1,3 +1,5 @@
import createAppAuthClient from './mutations/create-app-auth-client.ee.js';
import createAppConfig from './mutations/create-app-config.ee.js';
import createConnection from './mutations/create-connection.js';
import createFlow from './mutations/create-flow.js';
import createRole from './mutations/create-role.ee.js';
@@ -7,6 +9,7 @@ import deleteConnection from './mutations/delete-connection.js';
import deleteCurrentUser from './mutations/delete-current-user.ee.js';
import deleteFlow from './mutations/delete-flow.js';
import deleteRole from './mutations/delete-role.ee.js';
import deleteStep from './mutations/delete-step.js';
import duplicateFlow from './mutations/duplicate-flow.js';
import executeFlow from './mutations/execute-flow.js';
import generateAuthUrl from './mutations/generate-auth-url.js';
@@ -24,12 +27,11 @@ import updateStep from './mutations/update-step.js';
import updateUser from './mutations/update-user.ee.js';
import upsertSamlAuthProvider from './mutations/upsert-saml-auth-provider.ee.js';
import upsertSamlAuthProvidersRoleMappings from './mutations/upsert-saml-auth-providers-role-mappings.ee.js';
// Converted mutations
import deleteStep from './mutations/delete-step.js';
import verifyConnection from './mutations/verify-connection.js';
const mutationResolvers = {
createAppAuthClient,
createAppConfig,
createConnection,
createFlow,
createRole,

View File

@@ -0,0 +1,17 @@
import AppConfig from '../../models/app-config.js';
const createAppAuthClient = async (_parent, params, context) => {
context.currentUser.can('update', 'App');
const appConfig = await AppConfig.query()
.findById(params.input.appConfigId)
.throwIfNotFound();
const appAuthClient = await appConfig
.$relatedQuery('appAuthClients')
.insert(params.input);
return appAuthClient;
};
export default createAppAuthClient;

View File

@@ -0,0 +1,18 @@
import App from '../../models/app.js';
import AppConfig from '../../models/app-config.js';
const createAppConfig = async (_parent, params, context) => {
context.currentUser.can('update', 'App');
const key = params.input.key;
const app = await App.findOneByKey(key);
if (!app) throw new Error('The app cannot be found!');
const appConfig = await AppConfig.query().insert(params.input);
return appConfig;
};
export default createAppConfig;

View File

@@ -2,6 +2,8 @@ type Query {
placeholderQuery(name: String): Boolean
}
type Mutation {
createAppConfig(input: CreateAppConfigInput): AppConfig
createAppAuthClient(input: CreateAppAuthClientInput): AppAuthClient
createConnection(input: CreateConnectionInput): Connection
createFlow(input: CreateFlowInput): Flow
createRole(input: CreateRoleInput): Role
@@ -548,6 +550,13 @@ type Subject {
key: String
}
input CreateAppConfigInput {
key: String
allowCustomConnection: Boolean
shared: Boolean
disabled: Boolean
}
input UpdateAppConfigInput {
id: String
allowCustomConnection: Boolean
@@ -562,6 +571,13 @@ type AppAuthClient {
active: Boolean
}
input CreateAppAuthClientInput {
appConfigId: String
name: String
formattedAuthDefaults: JSONObject
active: Boolean
}
input UpdateAppAuthClientInput {
id: String
name: String

View File

@@ -43,10 +43,6 @@ const authorizationList = {
action: 'update',
subject: 'Connection',
},
'POST /api/v1/connections/:connectionId/verify': {
action: 'create',
subject: 'Connection',
},
'GET /api/v1/apps/:appKey/flows': {
action: 'read',
subject: 'Flow',
@@ -67,10 +63,6 @@ const authorizationList = {
action: 'read',
subject: 'Execution',
},
'DELETE /api/v1/steps/:stepId': {
action: 'update',
subject: 'Flow',
},
};
export const authorizeUser = async (request, response, next) => {

View File

@@ -2,164 +2,67 @@ import get from 'lodash.get';
const variableRegExp = /({{step\.[\da-zA-Z-]+(?:\.[^.}{]+)+}})/g;
function getParameterEntries(parameters) {
return Object.entries(parameters);
}
export default function computeParameters(parameters, executionSteps) {
const entries = Object.entries(parameters);
return entries.reduce((result, [key, value]) => {
if (typeof value === 'string') {
const parts = value.split(variableRegExp);
function getFieldByKey(key, fields = []) {
return fields.find((field) => field.key === key);
};
const computedValue = parts
.map((part) => {
const isVariable = part.match(variableRegExp);
function getParameterValueType(parameterKey, fields) {
const field = getFieldByKey(parameterKey, fields);
const defaultValueType = 'string';
if (isVariable) {
const stepIdAndKeyPath = part.replace(/{{step.|}}/g, '');
const [stepId, ...keyPaths] = stepIdAndKeyPath.split('.');
const keyPath = keyPaths.join('.');
const executionStep = executionSteps.find((executionStep) => {
return executionStep.stepId === stepId;
});
const data = executionStep?.dataOut;
const dataValue = get(data, keyPath);
return field?.valueType || defaultValueType;
}
// Covers both arrays and objects
if (typeof dataValue === 'object') {
return JSON.stringify(dataValue);
}
function computeParameterEntries(parameterEntries, fields, executionSteps) {
const defaultComputedParameters = {};
return parameterEntries.reduce((result, [key, value]) => {
const parameterComputedValue = computeParameter(key, value, fields, executionSteps);
return dataValue;
}
return part;
}).join('');
// challenge the input to see if it is stringifies object or array
try {
const parsedValue = JSON.parse(computedValue);
if (typeof parsedValue === 'number') {
throw new Error('Use original unparsed value.');
}
return {
...result,
[key]: parsedValue,
};
} catch (error) {
return {
...result,
[key]: computedValue,
};
}
}
if (Array.isArray(value)) {
return {
...result,
[key]: value.map((item) => computeParameters(item, executionSteps)),
};
}
return {
...result,
[key]: parameterComputedValue,
}
}, defaultComputedParameters);
}
function shouldAutoParse(key, fields) {
const parameterValueType = getParameterValueType(key, fields);
const shouldAutoParse = parameterValueType === 'parse';
return shouldAutoParse;
}
function computeParameter(key, value, fields, executionSteps) {
if (typeof value === 'string') {
const computedStringParameter = computeStringParameter(key, value, fields, executionSteps);
return computedStringParameter;
}
if (Array.isArray(value)) {
const computedArrayParameter = computeArrayParameter(key, value, fields, executionSteps);
return computedArrayParameter;
}
return value;
}
function splitByVariable(stringValue) {
const parts = stringValue.split(variableRegExp);
return parts;
}
function isVariable(stringValue) {
return stringValue.match(variableRegExp);
}
function splitVariableByStepIdAndKeyPath(variableValue) {
const stepIdAndKeyPath = variableValue.replace(/{{step.|}}/g, '');
const [stepId, ...keyPaths] = stepIdAndKeyPath.split('.');
const keyPath = keyPaths.join('.');
return {
stepId,
keyPath
}
}
function getVariableStepId(variableValue) {
const { stepId } = splitVariableByStepIdAndKeyPath(variableValue);
return stepId;
}
function getVariableKeyPath(variableValue) {
const { keyPath } = splitVariableByStepIdAndKeyPath(variableValue);
return keyPath
}
function getVariableExecutionStep(variableValue, executionSteps) {
const stepId = getVariableStepId(variableValue);
const executionStep = executionSteps.find((executionStep) => {
return executionStep.stepId === stepId;
});
return executionStep;
}
function computeVariable(variable, executionSteps) {
const keyPath = getVariableKeyPath(variable);
const executionStep = getVariableExecutionStep(variable, executionSteps);
const data = executionStep?.dataOut;
const computedVariable = get(data, keyPath);
/**
* Inline both arrays and objects. Otherwise, variables resolving to
* them would be resolved as `[object Object]` or lose their shape.
*/
if (typeof computedVariable === 'object') {
return JSON.stringify(computedVariable);
}
return computedVariable;
}
function autoParseComputedVariable(computedVariable) {
// challenge the input to see if it is stringified object or array
try {
const parsedValue = JSON.parse(computedVariable);
if (typeof parsedValue === 'number') {
throw new Error('Use original unparsed value.');
}
return parsedValue;
} catch (error) {
return computedVariable;
}
}
function computeStringParameter(key, stringValue, fields, executionSteps) {
const parts = splitByVariable(stringValue);
const computedValue = parts
.map((part) => {
const variable = isVariable(part);
if (variable) {
return computeVariable(part, executionSteps);
}
return part;
})
.join('');
const autoParse = shouldAutoParse(key, fields);
if (autoParse) {
const autoParsedValue = autoParseComputedVariable(computedValue);
return autoParsedValue;
}
return computedValue;
}
function computeArrayParameter(key, arrayValue, fields = [], executionSteps) {
return arrayValue.map((item) => {
const itemFields = fields.find((field) => field.key === key)?.fields;
return computeParameters(item, itemFields, executionSteps);
});
}
export default function computeParameters(parameters, fields, executionSteps) {
const parameterEntries = getParameterEntries(parameters);
return computeParameterEntries(parameterEntries, fields, executionSteps);
[key]: value,
};
}, {});
}

View File

@@ -1,6 +1,5 @@
import { beforeEach, describe, it, expect } from 'vitest';
import { createExecutionStep } from '../../test/factories/execution-step.js';
import { createDropdownArgument, createDynamicArgument, createStringArgument } from '../../test/factories/app.js';
import computeParameters from './compute-parameters.js';
const computeVariable = (stepId, path) => `{{step.${stepId}.${path}}}`;
@@ -69,7 +68,7 @@ describe('Compute parameters helper', () => {
key2: `"${computeVariable('non-existent-step-id', 'non-existent-key')}" is the value for non-existent-key`,
};
const computedParameters = computeParameters(parameters, [], executionSteps);
const computedParameters = computeParameters(parameters, executionSteps);
const expectedParameters = {
key1: '',
key2: '"" is the value for non-existent-key',
@@ -82,29 +81,20 @@ describe('Compute parameters helper', () => {
it('should resolve empty object', () => {
const parameters = {};
const computedParameters = computeParameters(parameters, [], executionSteps);
const computedParameters = computeParameters(parameters, executionSteps);
expect(computedParameters).toStrictEqual(parameters);
});
});
describe('with string parameters', () => {
let stepArguments;
beforeEach(() => {
stepArguments = [
createStringArgument({
key: 'key1',
}),
];
});
it('should resolve as-is without variables', () => {
const parameters = {
key1: 'plain text',
key2: 'plain text',
};
const computedParameters = computeParameters(parameters, stepArguments, executionSteps);
const computedParameters = computeParameters(parameters, executionSteps);
expect(computedParameters).toStrictEqual(parameters);
});
@@ -116,7 +106,7 @@ describe('Compute parameters helper', () => {
key3: ' plain text',
};
const computedParameters = computeParameters(parameters, stepArguments, executionSteps);
const computedParameters = computeParameters(parameters, executionSteps);
expect(computedParameters).toStrictEqual(parameters);
});
@@ -126,291 +116,23 @@ describe('Compute parameters helper', () => {
key1: `static text ${computeVariable(executionStepOne.stepId, 'step1Key1')}`,
};
const computedParameters = computeParameters(parameters, stepArguments, executionSteps);
const computedParameters = computeParameters(parameters, executionSteps);
const expectedParameters = {
key1: `static text plain text value for step1Key1`,
};
expect(computedParameters).toStrictEqual(expectedParameters);
});
describe('with variables containing JSON', () => {
describe('without explicit valueType defined', () => {
let stepArguments;
beforeEach(() => {
stepArguments = [
createStringArgument({
key: 'key1',
}),
];
});
it('should resolve text + JSON value as-is', () => {
const parameters = {
key1: 'prepended text {"key": "value"} ',
};
const computedParameters = computeParameters(parameters, executionSteps);
expect(computedParameters).toStrictEqual(parameters);
});
it('should resolve stringified JSON parsed', () => {
const parameters = {
key1: '{"key1": "plain text", "key2": "119007199254740999"}',
};
const computedParameters = computeParameters(parameters, stepArguments, executionSteps);
const expectedParameters = {
key1: '{"key1": "plain text", "key2": "119007199254740999"}',
};
expect(computedParameters).toStrictEqual(expectedParameters);
});
it('should handle arrays at root level', () => {
const parameters = {
key1: '["value1", "value2"]',
};
const computedParameters = computeParameters(parameters, stepArguments, executionSteps);
const expectedParameters = {
key1: '["value1", "value2"]',
};
expect(computedParameters).toStrictEqual(expectedParameters);
});
it('should handle arrays in nested level', () => {
const parameters = {
key1: '{"items": ["value1", "value2"]}',
};
const computedParameters = computeParameters(parameters, stepArguments, executionSteps);
const expectedParameters = {
key1: '{"items": ["value1", "value2"]}',
};
expect(computedParameters).toStrictEqual(expectedParameters);
});
it('should compute mix variables correctly', () => {
const parameters = {
key1: `another static text ${computeVariable(executionStepThree.stepId, 'step3Key4.step3Key4ChildKey4')}`,
};
const computedParameters = computeParameters(parameters, stepArguments, executionSteps);
const expectedParameters = {
key1: `another static text ["value1","value2"]`,
};
expect(computedParameters).toStrictEqual(expectedParameters);
});
it('should compute variables correctly', () => {
const parameters = {
key1: `${computeVariable(executionStepThree.stepId, 'step3Key4.step3Key4ChildKey4')}`,
};
const computedParameters = computeParameters(parameters, stepArguments, executionSteps);
const expectedParameters = {
key1: '["value1","value2"]',
};
expect(computedParameters).toStrictEqual(expectedParameters);
});
it('should not parse non-primitives in nested arrays', () => {
const stepArguments = [
createDynamicArgument({
key: 'inputs',
})
];
const parameters = {
inputs: [
{
key: 'person',
value: '{ "name": "John Doe", "age": 32 }',
}
],
};
const computedParameters = computeParameters(parameters, stepArguments, executionSteps);
const expectedParameters = {
inputs: [
{
key: 'person',
value: '{ "name": "John Doe", "age": 32 }',
}
],
};
expect(computedParameters).toStrictEqual(expectedParameters);
});
});
describe(`with valueType as 'parse'`, () => {
let stepArguments;
beforeEach(() => {
stepArguments = [
createStringArgument({
key: 'key1',
valueType: 'parse',
}),
];
});
it('should resolve text + JSON value as-is', () => {
const parameters = {
key1: 'prepended text {"key": "value"} ',
};
const computedParameters = computeParameters(parameters, stepArguments, executionSteps);
expect(computedParameters).toStrictEqual(parameters);
});
it('should resolve stringified JSON parsed', () => {
const parameters = {
key1: '{"key1": "plain text", "key2": "119007199254740999"}',
};
const computedParameters = computeParameters(parameters, stepArguments, executionSteps);
const expectedParameters = {
key1: {
key1: 'plain text',
key2: '119007199254740999',
},
};
expect(computedParameters).toStrictEqual(expectedParameters);
});
it('should handle arrays at root level', () => {
const parameters = {
key1: '["value1", "value2"]',
};
const computedParameters = computeParameters(parameters, stepArguments, executionSteps);
const expectedParameters = {
key1: ['value1', 'value2'],
};
expect(computedParameters).toStrictEqual(expectedParameters);
});
it('should handle arrays in nested level', () => {
const parameters = {
key1: '{"items": ["value1", "value2"]}',
};
const computedParameters = computeParameters(parameters, stepArguments, executionSteps);
const expectedParameters = {
key1: {
items: ['value1', 'value2'],
}
};
expect(computedParameters).toStrictEqual(expectedParameters);
});
it('should compute and parse mix variables correctly', () => {
const parameters = {
key1: `another static text ${computeVariable(executionStepThree.stepId, 'step3Key4.step3Key4ChildKey4')}`,
};
const computedParameters = computeParameters(parameters, stepArguments, executionSteps);
const expectedParameters = {
key1: `another static text ["value1","value2"]`,
};
expect(computedParameters).toStrictEqual(expectedParameters);
});
it('should compute and parse variables correctly', () => {
const parameters = {
key1: `${computeVariable(executionStepThree.stepId, 'step3Key4.step3Key4ChildKey4')}`,
};
const computedParameters = computeParameters(parameters, stepArguments, executionSteps);
const expectedParameters = {
key1: ["value1", "value2"],
};
expect(computedParameters).toStrictEqual(expectedParameters);
});
it('should compute and parse variables in nested arrays correctly', () => {
const stepArguments = [
createDynamicArgument({
key: 'inputs',
fields: [
{
label: 'Key',
key: 'key',
required: true,
variables: true,
},
{
label: 'Value',
key: 'value',
required: true,
variables: true,
valueType: 'parse',
}
],
})
];
const parameters = {
inputs: [
{
key: 'person',
value: '{ "name": "John Doe", "age": 32 }',
}
],
};
const computedParameters = computeParameters(parameters, stepArguments, executionSteps);
const expectedParameters = {
inputs: [
{
key: 'person',
value: {
name: 'John Doe',
age: 32,
}
}
],
};
expect(computedParameters).toStrictEqual(expectedParameters);
});
});
});
});
describe('with number parameters', () => {
let stepArguments;
beforeEach(() => {
stepArguments = [
createStringArgument({
key: 'key1',
}),
createStringArgument({
key: 'key2',
}),
];
});
it('should resolve number larger than MAX_SAFE_INTEGER correctly', () => {
const parameters = {
// eslint-disable-next-line no-loss-of-precision
key1: 119007199254740999,
};
const computedParameters = computeParameters(parameters, stepArguments, executionSteps);
const computedParameters = computeParameters(parameters, executionSteps);
expect(computedParameters).toStrictEqual(parameters);
expect(computedParameters.key1 > Number.MAX_SAFE_INTEGER).toBe(true);
@@ -421,9 +143,10 @@ describe('Compute parameters helper', () => {
key1: '119007199254740999',
};
const computedParameters = computeParameters(parameters, stepArguments, executionSteps);
const computedParameters = computeParameters(parameters, executionSteps);
expect(computedParameters).toStrictEqual(parameters);
expect(parseInt(parameters.key1))
});
it('should compute variables with int values correctly', () => {
@@ -432,7 +155,7 @@ describe('Compute parameters helper', () => {
key2: `${computeVariable(executionStepThree.stepId, 'step3Key3')}`
};
const computedParameters = computeParameters(parameters, stepArguments, executionSteps);
const computedParameters = computeParameters(parameters, executionSteps);
const expectedParameters = {
key1: `another static text 123123`,
key2: `123123`
@@ -447,7 +170,7 @@ describe('Compute parameters helper', () => {
key2: `${computeVariable(executionStepTwo.stepId, 'step2Key3')}`
};
const computedParameters = computeParameters(parameters, stepArguments, executionSteps);
const computedParameters = computeParameters(parameters, executionSteps);
const expectedParameters = {
// The expected `key2` is computed wrongly.
key1: `another static text 6502380617126796383`,
@@ -458,30 +181,85 @@ describe('Compute parameters helper', () => {
});
});
describe('with boolean parameters', () => {
let stepArguments;
beforeEach(() => {
stepArguments = [
createDropdownArgument({
key: 'key1',
}),
createDropdownArgument({
key: 'key2',
}),
];
});
it('should resolve boolean as-is', () => {
describe('with JSON parameters', () => {
it('should resolve text + JSON value as-is', () => {
const parameters = {
key1: true,
key2: false,
key1: 'prepended text {"key": "value"} ',
};
const computedParameters = computeParameters(parameters, stepArguments, executionSteps);
const computedParameters = computeParameters(parameters, executionSteps);
expect(computedParameters).toStrictEqual(parameters);
expect(computedParameters.key1).toBe(true);
expect(computedParameters.key2).toBe(false);
});
it('should resolve stringified JSON parsed', () => {
const parameters = {
key1: '{"key1": "plain text", "key2": "119007199254740999"}',
};
const computedParameters = computeParameters(parameters, executionSteps);
const expectedParameters = {
key1: {
key1: 'plain text',
key2: '119007199254740999',
},
};
expect(computedParameters).toStrictEqual(expectedParameters);
});
it('should handle arrays at root level', () => {
const parameters = {
key1: '["value1", "value2"]',
};
const computedParameters = computeParameters(parameters, executionSteps);
const expectedParameters = {
key1: ['value1', 'value2'],
};
expect(computedParameters).toStrictEqual(expectedParameters);
});
it('should handle arrays in nested level', () => {
const parameters = {
key1: '{"items": ["value1", "value2"]}',
};
const computedParameters = computeParameters(parameters, executionSteps);
const expectedParameters = {
key1: {
items: ['value1', 'value2'],
}
};
expect(computedParameters).toStrictEqual(expectedParameters);
});
it('should compute mix variables correctly', () => {
const parameters = {
key1: `another static text ${computeVariable(executionStepThree.stepId, 'step3Key4.step3Key4ChildKey4')}`,
};
const computedParameters = computeParameters(parameters, executionSteps);
const expectedParameters = {
key1: `another static text ["value1","value2"]`,
};
expect(computedParameters).toStrictEqual(expectedParameters);
});
it('should compute variables correctly', () => {
const parameters = {
key1: `${computeVariable(executionStepThree.stepId, 'step3Key4.step3Key4ChildKey4')}`,
};
const computedParameters = computeParameters(parameters, executionSteps);
const expectedParameters = {
key1: ["value1", "value2"],
};
expect(computedParameters).toStrictEqual(expectedParameters);
});
});
});

View File

@@ -1,13 +1,8 @@
import logger from './logger.js';
import objection from 'objection';
import * as Sentry from './sentry.ee.js';
const { NotFoundError, DataError, ValidationError, UniqueViolationError } =
objection;
const { NotFoundError, DataError } = objection;
import HttpError from '../errors/http.js';
import {
renderObjectionError,
renderUniqueViolationError,
} from './renderer.js';
// Do not remove `next` argument as the function signature will not fit for an error handler middleware
// eslint-disable-next-line no-unused-vars
@@ -20,14 +15,6 @@ const errorHandler = (error, request, response, next) => {
response.status(404).end();
}
if (error instanceof ValidationError) {
renderObjectionError(response, error, 422);
}
if (error instanceof UniqueViolationError) {
renderUniqueViolationError(response, error);
}
if (error instanceof DataError) {
response.status(400).end();
}

View File

@@ -41,9 +41,7 @@ const renderObject = (response, object, options) => {
},
};
const status = options?.status || 200;
return response.status(status).json(computedPayload);
return response.json(computedPayload);
};
const renderError = (response, errors, status, type) => {
@@ -64,31 +62,4 @@ const renderError = (response, errors, status, type) => {
return response.status(errorStatus).send(payload);
};
const renderUniqueViolationError = (response, error) => {
const errors = error.columns.map((column) => ({
[column]: [`'${column}' must be unique.`],
}));
return renderError(response, errors, 422, 'UniqueViolationError');
};
const renderObjectionError = (response, error, status) => {
const { statusCode, type, data = {} } = error;
const computedStatusCode = status || statusCode;
const computedErrors = Object.entries(data).map(
([fieldName, fieldErrors]) => ({
[fieldName]: fieldErrors.map(({ message }) => message),
})
);
return renderError(response, computedErrors, computedStatusCode, type);
};
export {
renderObject,
renderError,
renderObjectionError,
renderUniqueViolationError,
};
export { renderObject, renderError };

View File

@@ -15,8 +15,6 @@ class AppConfig extends Base {
allowCustomConnection: { type: 'boolean', default: false },
shared: { type: 'boolean', default: false },
disabled: { type: 'boolean', default: false },
createdAt: { type: 'string' },
updatedAt: { type: 'string' },
},
};

View File

@@ -171,17 +171,6 @@ class Connection extends Base {
});
}
async verifyAndUpdateConnection() {
const app = await this.getApp();
const $ = await globalVariable({ connection: this, app });
await app.auth.verifyCredentials($);
return await this.$query().patchAndFetch({
verified: true,
draft: false,
});
}
async verifyWebhook(request) {
if (!this.key) return true;

View File

@@ -198,32 +198,6 @@ class Step extends Base {
return existingArguments;
}
async getSetupAndDynamicFields() {
const setupFields = await this.getSetupFields();
const setupAndDynamicFields = [];
for (const setupField of setupFields) {
setupAndDynamicFields.push(setupField);
const additionalFields = setupField.additionalFields;
if (additionalFields) {
const keyArgument = additionalFields.arguments.find(
(argument) => argument.name === 'key'
);
const dynamicFieldsKey = keyArgument.value;
const dynamicFields = await this.createDynamicFields(
dynamicFieldsKey,
this.parameters
);
setupAndDynamicFields.push(...dynamicFields);
}
}
return setupAndDynamicFields;
}
async createDynamicFields(dynamicFieldsKey, parameters) {
const connection = await this.$relatedQuery('connection');
const flow = await this.$relatedQuery('flow');
@@ -266,11 +240,8 @@ class Step extends Base {
})
: [];
const setupAndDynamicFields = await this.getSetupAndDynamicFields();
const computedParameters = computeParameters(
$.step.parameters,
setupAndDynamicFields,
priorExecutionSteps
);
@@ -291,25 +262,6 @@ class Step extends Base {
return this;
}
async delete() {
await this.$relatedQuery('executionSteps').delete();
await this.$query().delete();
const flow = await this.$relatedQuery('flow');
const nextSteps = await flow
.$relatedQuery('steps')
.where('position', '>', this.position);
const nextStepQueries = nextSteps.map(async (nextStep) => {
await nextStep.$query().patch({
position: nextStep.position - 1,
});
});
await Promise.all(nextStepQueries);
}
}
export default Step;

View File

@@ -3,22 +3,11 @@ import asyncHandler from 'express-async-handler';
import { authenticateUser } from '../../../../helpers/authentication.js';
import { authorizeAdmin } from '../../../../helpers/authorization.js';
import { checkIsEnterprise } from '../../../../helpers/check-is-enterprise.js';
import createConfigAction from '../../../../controllers/api/v1/admin/apps/create-config.ee.js';
import getAuthClientsAction from '../../../../controllers/api/v1/admin/apps/get-auth-clients.ee.js';
import getAuthClientAction from '../../../../controllers/api/v1/admin/apps/get-auth-client.ee.js';
import createAuthClientAction from '../../../../controllers/api/v1/admin/apps/create-auth-client.ee.js';
const router = Router();
router.post(
'/:appKey/config',
authenticateUser,
authorizeAdmin,
checkIsEnterprise,
asyncHandler(createConfigAction)
);
router.get(
'/:appKey/auth-clients',
authenticateUser,
@@ -27,14 +16,6 @@ router.get(
asyncHandler(getAuthClientsAction)
);
router.post(
'/:appKey/auth-clients',
authenticateUser,
authorizeAdmin,
checkIsEnterprise,
asyncHandler(createAuthClientAction)
);
router.get(
'/:appKey/auth-clients/:appAuthClientId',
authenticateUser,

View File

@@ -3,8 +3,7 @@ import asyncHandler from 'express-async-handler';
import { authenticateUser } from '../../../helpers/authentication.js';
import { authorizeUser } from '../../../helpers/authorization.js';
import getFlowsAction from '../../../controllers/api/v1/connections/get-flows.js';
import testConnectionAction from '../../../controllers/api/v1/connections/test-connection.js';
import verifyConnectionAction from '../../../controllers/api/v1/connections/verify-connection.js';
import createTestAction from '../../../controllers/api/v1/connections/create-test.js';
const router = Router();
@@ -19,14 +18,7 @@ router.post(
'/:connectionId/test',
authenticateUser,
authorizeUser,
asyncHandler(testConnectionAction)
);
router.post(
'/:connectionId/verify',
authenticateUser,
authorizeUser,
asyncHandler(verifyConnectionAction)
asyncHandler(createTestAction)
);
export default router;

View File

@@ -6,7 +6,6 @@ import getConnectionAction from '../../../controllers/api/v1/steps/get-connectio
import getPreviousStepsAction from '../../../controllers/api/v1/steps/get-previous-steps.js';
import createDynamicFieldsAction from '../../../controllers/api/v1/steps/create-dynamic-fields.js';
import createDynamicDataAction from '../../../controllers/api/v1/steps/create-dynamic-data.js';
import deleteStepAction from '../../../controllers/api/v1/steps/delete-step.js';
const router = Router();
@@ -38,11 +37,4 @@ router.post(
asyncHandler(createDynamicDataAction)
);
router.delete(
'/:stepId',
authenticateUser,
authorizeUser,
asyncHandler(deleteStepAction)
);
export default router;

View File

@@ -31,11 +31,8 @@ export const processAction = async (options) => {
execution_id: $.execution.id,
});
const stepSetupAndDynamicFields = await step.getSetupAndDynamicFields();
const computedParameters = computeParameters(
$.step.parameters,
stepSetupAndDynamicFields,
priorExecutionSteps
);

View File

@@ -1,72 +0,0 @@
import { faker } from '@faker-js/faker';
export const createArgument = (params = {}) => {
const labelAndKey = faker.lorem.word();
const argument = {
label: labelAndKey,
key: labelAndKey,
required: false,
variables: true,
...params,
};
return argument;
};
export const createStringArgument = (params = {}) => {
const stringArgument = createArgument({
...params,
type: 'string',
});
return stringArgument;
};
export const createDropdownArgument = (params = {}) => {
const dropdownArgument = createArgument({
options: [
{
label: 'Yes',
value: true,
},
{
label: 'No',
value: false,
},
],
...params,
type: 'dropdown',
});
return dropdownArgument;
};
export const createDynamicArgument = (params = {}) => {
const dynamicArgument = createArgument({
value: [
{
key: '',
value: '',
},
],
fields: [
{
label: 'Key',
key: 'key',
required: true,
variables: true,
},
{
label: 'Value',
key: 'value',
required: true,
variables: true,
}
],
...params,
type: 'dynamic',
});
return dynamicArgument;
};

View File

@@ -1,17 +0,0 @@
const createAppAuthClientMock = (appAuthClient) => {
return {
data: {
name: appAuthClient.name,
active: appAuthClient.active,
},
meta: {
count: 1,
currentPage: null,
isArray: false,
totalPages: null,
type: 'AppAuthClient',
},
};
};
export default createAppAuthClientMock;

View File

@@ -1,19 +0,0 @@
const createAppConfigMock = (appConfig) => {
return {
data: {
key: appConfig.key,
allowCustomConnection: appConfig.allowCustomConnection,
shared: appConfig.shared,
disabled: appConfig.disabled,
},
meta: {
count: 1,
currentPage: null,
isArray: false,
totalPages: null,
type: 'AppConfig',
},
};
};
export default createAppConfigMock;

View File

@@ -8,9 +8,7 @@ global.beforeAll(async () => {
logger.silent = true;
// Remove default roles and permissions before running the test suite
await knex.raw('TRUNCATE TABLE config CASCADE');
await knex.raw('TRUNCATE TABLE roles CASCADE');
await knex.raw('TRUNCATE TABLE permissions CASCADE');
await knex.raw('TRUNCATE TABLE config, roles, permissions CASCADE');
});
global.beforeEach(async () => {

View File

@@ -1,6 +1,4 @@
const { AuthenticatedPage } = require('./authenticated-page');
const { expect } = require('@playwright/test');
const axios = require('axios');
export class FlowEditorPage extends AuthenticatedPage {
screenshotPath = '/flow-editor';
@@ -14,71 +12,14 @@ export class FlowEditorPage extends AuthenticatedPage {
this.appAutocomplete = this.page.getByTestId('choose-app-autocomplete');
this.eventAutocomplete = this.page.getByTestId('choose-event-autocomplete');
this.continueButton = this.page.getByTestId('flow-substep-continue-button');
this.testAndContinueButton = this.page.getByText('Test & Continue');
this.connectionAutocomplete = this.page.getByTestId(
'choose-connection-autocomplete'
);
this.testOutput = this.page.getByTestId('flow-test-substep-output');
this.hasNoOutput = this.page.getByTestId('flow-test-substep-no-output');
this.testOuput = this.page.getByTestId('flow-test-substep-output');
this.unpublishFlowButton = this.page.getByTestId('unpublish-flow-button');
this.publishFlowButton = this.page.getByTestId('publish-flow-button');
this.infoSnackbar = this.page.getByTestId('flow-cannot-edit-info-snackbar');
this.trigger = this.page.getByLabel('Trigger on weekends?');
this.stepCircularLoader = this.page.getByTestId('step-circular-loader');
this.flowName = this.page.getByTestId('editableTypography');
this.flowNameInput = this.page
.getByTestId('editableTypographyInput')
.locator('input');
}
async createWebhookTrigger(workSynchronously) {
await this.appAutocomplete.click();
await this.page.getByRole('option', { name: 'Webhook' }).click();
await expect(this.eventAutocomplete).toBeVisible();
await this.eventAutocomplete.click();
await this.page.getByRole('option', { name: 'Catch raw webhook' }).click();
await this.continueButton.click();
await this.page
.getByTestId('parameters.workSynchronously-autocomplete')
.click();
await this.page
.getByRole('option', { name: workSynchronously ? 'Yes' : 'No' })
.click();
await this.continueButton.click();
const webhookUrl = this.page.locator('input[name="webhookUrl"]');
if (workSynchronously) {
await expect(webhookUrl).toHaveValue(/sync/);
} else {
await expect(webhookUrl).not.toHaveValue(/sync/);
}
const triggerResponse = await axios.get(await webhookUrl.inputValue());
await expect(triggerResponse.status).toBe(204);
await expect(this.testOutput).not.toBeVisible();
await this.testAndContinueButton.click();
await expect(this.testOutput).toBeVisible();
await expect(this.hasNoOutput).not.toBeVisible();
await this.continueButton.click();
return await webhookUrl.inputValue();
}
async chooseAppAndEvent(appName, eventName) {
await this.appAutocomplete.click();
await this.page.getByRole('option', { name: appName }).click();
await expect(this.eventAutocomplete).toBeVisible();
await this.eventAutocomplete.click();
await this.page.getByRole('option', { name: eventName }).click();
await this.continueButton.click();
}
async testAndContinue() {
await expect(this.continueButton).toHaveCount(1);
await this.continueButton.click();
await expect(this.testOutput).toBeVisible();
await this.continueButton.click();
}
}

View File

@@ -1,85 +0,0 @@
const { test, expect } = require('../../fixtures/index');
const axios = require('axios');
test.describe('Webhook flow', () => {
test.beforeEach(async ({ page }) => {
await page.getByTestId('create-flow-button').click();
await page.waitForURL(
/\/editor\/[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}/
);
await expect(page.getByTestId('flow-step')).toHaveCount(2);
});
test('Create a new flow with a sync Webhook step then a Webhook step', async ({
flowEditorPage,
page,
}) => {
await flowEditorPage.flowName.click();
await flowEditorPage.flowNameInput.fill('syncWebhook');
const syncWebhookUrl = await flowEditorPage.createWebhookTrigger(true);
await flowEditorPage.chooseAppAndEvent('Webhook', 'Respond with');
await expect(flowEditorPage.continueButton).toHaveCount(1);
await expect(flowEditorPage.continueButton).not.toBeEnabled();
await page
.getByTestId('parameters.statusCode-power-input')
.locator('[contenteditable]')
.fill('200');
await flowEditorPage.clickAway();
await expect(flowEditorPage.continueButton).toHaveCount(1);
await expect(flowEditorPage.continueButton).not.toBeEnabled();
await page
.getByTestId('parameters.body-power-input')
.locator('[contenteditable]')
.fill('response from webhook');
await flowEditorPage.clickAway();
await expect(flowEditorPage.continueButton).toBeEnabled();
await flowEditorPage.continueButton.click();
await flowEditorPage.testAndContinue();
await flowEditorPage.publishFlowButton.click();
const response = await axios.get(syncWebhookUrl);
await expect(response.status).toBe(200);
await expect(response.data).toBe('response from webhook');
});
test('Create a new flow with an async Webhook step then a Webhook step', async ({
flowEditorPage,
page,
}) => {
await flowEditorPage.flowName.click();
await flowEditorPage.flowNameInput.fill('asyncWebhook');
const asyncWebhookUrl = await flowEditorPage.createWebhookTrigger(false);
await flowEditorPage.chooseAppAndEvent('Webhook', 'Respond with');
await expect(flowEditorPage.continueButton).toHaveCount(1);
await expect(flowEditorPage.continueButton).not.toBeEnabled();
await page
.getByTestId('parameters.statusCode-power-input')
.locator('[contenteditable]')
.fill('200');
await flowEditorPage.clickAway();
await expect(flowEditorPage.continueButton).toHaveCount(1);
await expect(flowEditorPage.continueButton).not.toBeEnabled();
await page
.getByTestId('parameters.body-power-input')
.locator('[contenteditable]')
.fill('response from webhook');
await flowEditorPage.clickAway();
await expect(flowEditorPage.continueButton).toBeEnabled();
await flowEditorPage.continueButton.click();
await flowEditorPage.testAndContinue();
await flowEditorPage.publishFlowButton.click();
const response = await axios.get(asyncWebhookUrl);
await expect(response.status).toBe(204);
await expect(response.data).toBe('');
});
});

View File

@@ -2,6 +2,7 @@ const { test, expect } = require('../../fixtures/index');
test('Ensure creating a new flow works', async ({ page }) => {
await page.getByTestId('create-flow-button').click();
await expect(page).toHaveURL(/\/editor\/create/);
await expect(page).toHaveURL(
/\/editor\/[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}/
);
@@ -68,9 +69,9 @@ test(
await test.step('test trigger', async () => {
await test.step('show sample output', async () => {
await expect(flowEditorPage.testOutput).not.toBeVisible();
await expect(flowEditorPage.testOuput).not.toBeVisible();
await flowEditorPage.continueButton.click();
await expect(flowEditorPage.testOutput).toBeVisible();
await expect(flowEditorPage.testOuput).toBeVisible();
await flowEditorPage.screenshot({
path: 'Scheduler trigger test output.png',
});
@@ -142,12 +143,12 @@ test(
await test.step('test trigger substep', async () => {
await test.step('show sample output', async () => {
await expect(flowEditorPage.testOutput).not.toBeVisible();
await expect(flowEditorPage.testOuput).not.toBeVisible();
await page
.getByTestId('flow-substep-continue-button')
.first()
.click();
await expect(flowEditorPage.testOutput).toBeVisible();
await expect(flowEditorPage.testOuput).toBeVisible();
await flowEditorPage.screenshot({
path: 'Ntfy action test output.png',
});

View File

@@ -1,11 +1,12 @@
import PropTypes from 'prop-types';
import React, { useCallback, useMemo } from 'react';
import { useMutation } from '@apollo/client';
import { AppPropType } from 'propTypes/propTypes';
import useAdminCreateAppConfig from 'hooks/useAdminCreateAppConfig';
import { CREATE_APP_CONFIG } from 'graphql/mutations/create-app-config';
import { CREATE_APP_AUTH_CLIENT } from 'graphql/mutations/create-app-auth-client';
import useAppConfig from 'hooks/useAppConfig.ee';
import useFormatMessage from 'hooks/useFormatMessage';
import useAdminCreateAppAuthClient from 'hooks/useAdminCreateAppAuthClient.ee';
import AdminApplicationAuthClientDialog from 'components/AdminApplicationAuthClientDialog';
import useAppAuth from 'hooks/useAppAuth';
@@ -17,38 +18,51 @@ function AdminApplicationCreateAuthClient(props) {
const { data: appConfig, isLoading: isAppConfigLoading } =
useAppConfig(appKey);
const {
mutateAsync: createAppConfig,
isPending: isCreateAppConfigPending,
error: createAppConfigError
} = useAdminCreateAppConfig(props.appKey);
const [
createAppConfig,
{ loading: loadingCreateAppConfig, error: createAppConfigError },
] = useMutation(CREATE_APP_CONFIG, {
refetchQueries: ['GetAppConfig'],
context: { autoSnackbar: false },
});
const {
mutateAsync: createAppAuthClient,
isPending: isCreateAppAuthClientPending,
error: createAppAuthClientError,
} = useAdminCreateAppAuthClient(appKey);
const [
createAppAuthClient,
{ loading: loadingCreateAppAuthClient, error: createAppAuthClientError },
] = useMutation(CREATE_APP_AUTH_CLIENT, {
refetchQueries: ['GetAppAuthClients'],
context: { autoSnackbar: false },
});
const submitHandler = async (values) => {
let appConfigId = appConfig?.data?.id;
if (!appConfigId) {
const { data: appConfigData } = await createAppConfig({
allowCustomConnection: true,
shared: false,
disabled: false,
variables: {
input: {
key: appKey,
allowCustomConnection: false,
shared: false,
disabled: false,
},
},
});
appConfigId = appConfigData.id;
appConfigId = appConfigData.createAppConfig.id;
}
const { name, active, ...formattedAuthDefaults } = values;
await createAppAuthClient({
appKey,
name,
active,
formattedAuthDefaults,
variables: {
input: {
appConfigId,
name,
active,
formattedAuthDefaults,
},
},
});
onClose();
@@ -89,7 +103,7 @@ function AdminApplicationCreateAuthClient(props) {
loading={isAppConfigLoading}
submitHandler={submitHandler}
authFields={auth?.data?.fields}
submitting={isCreateAppConfigPending || isCreateAppAuthClientPending}
submitting={loadingCreateAppConfig || loadingCreateAppAuthClient}
defaultValues={defaultValues}
/>
);

View File

@@ -8,11 +8,11 @@ import Stack from '@mui/material/Stack';
import LoadingButton from '@mui/lab/LoadingButton';
import { useMutation } from '@apollo/client';
import { CREATE_APP_CONFIG } from 'graphql/mutations/create-app-config';
import { UPDATE_APP_CONFIG } from 'graphql/mutations/update-app-config';
import Form from 'components/Form';
import { Switch } from './style';
import useEnqueueSnackbar from 'hooks/useEnqueueSnackbar';
import useAdminCreateAppConfig from 'hooks/useAdminCreateAppConfig';
function AdminApplicationSettings(props) {
const formatMessage = useFormatMessage();
@@ -20,10 +20,12 @@ function AdminApplicationSettings(props) {
const { data: appConfig, isLoading: loading } = useAppConfig(props.appKey);
const {
mutateAsync: createAppConfig,
isPending: isCreateAppConfigPending,
} = useAdminCreateAppConfig(props.appKey);
const [createAppConfig, { loading: loadingCreateAppConfig }] = useMutation(
CREATE_APP_CONFIG,
{
refetchQueries: ['GetAppConfig'],
},
);
const [updateAppConfig, { loading: loadingUpdateAppConfig }] = useMutation(
UPDATE_APP_CONFIG,
@@ -35,7 +37,11 @@ function AdminApplicationSettings(props) {
const handleSubmit = async (values) => {
try {
if (!appConfig?.data) {
await createAppConfig(values);
await createAppConfig({
variables: {
input: { key: props.appKey, ...values },
},
});
} else {
await updateAppConfig({
variables: {
@@ -102,7 +108,7 @@ function AdminApplicationSettings(props) {
variant="contained"
color="primary"
sx={{ boxShadow: 2, mt: 5 }}
loading={isCreateAppConfigPending || loadingUpdateAppConfig}
loading={loadingCreateAppConfig || loadingUpdateAppConfig}
disabled={!isDirty || loading}
>
{formatMessage('adminAppsSettings.save')}

View File

@@ -16,7 +16,7 @@ function AdminApplicationUpdateAuthClient(props) {
const { clientId } = useParams();
const { data: adminAppAuthClient, isLoading: isAdminAuthClientLoading } =
useAdminAppAuthClient(application.key, clientId);
useAdminAppAuthClient(clientId);
const { data: auth } = useAppAuth(application.key);

View File

@@ -41,7 +41,6 @@ function EditableTypography(props) {
if (editing) {
component = (
<TextField
data-test="editableTypographyInput"
onClick={handleTextFieldClick}
onKeyDown={handleTextFieldKeyDown}
onBlur={handleTextFieldBlur}

View File

@@ -101,7 +101,6 @@ export default function EditorLayout() {
{!isFlowLoading && (
<EditableTypography
data-test="editableTypography"
variant="body1"
onConfirm={onFlowNameUpdate}
noWrap

View File

@@ -13,7 +13,6 @@ import CircularProgress from '@mui/material/CircularProgress';
import CheckCircleIcon from '@mui/icons-material/CheckCircle';
import { yupResolver } from '@hookform/resolvers/yup';
import * as yup from 'yup';
import { isEqual } from 'lodash';
import { EditorContext } from 'contexts/Editor';
import { StepExecutionsProvider } from 'contexts/StepExecutions';
@@ -178,9 +177,7 @@ function FlowStep(props) {
}, []);
const handleSubmit = (val) => {
if (!isEqual(step, val)) {
handleChange({ step: val });
}
handleChange({ step: val });
};
const stepValidationSchema = React.useMemo(

View File

@@ -25,40 +25,25 @@ const process = ({ data, parentKey, index, parentLabel = '' }) => {
sampleValue: JSON.stringify(sampleValue),
};
const arrayItems = sampleValue.flatMap((item, index) => {
const itemItself = {
label: `${label}.${index}`,
value: `${value}.${index}`,
sampleValue: JSON.stringify(item),
};
const itemEntries = process({
const arrayItems = sampleValue.flatMap((item, index) =>
process({
data: item,
parentKey: value,
index,
parentLabel: label,
});
}),
);
return [itemItself].concat(itemEntries);
});
return [arrayItself].concat(arrayItems);
// TODO: remove spreading
return [arrayItself, ...arrayItems];
}
if (typeof sampleValue === 'object' && sampleValue !== null) {
const objectItself = {
label,
value,
sampleValue: JSON.stringify(sampleValue),
};
const objectEntries = process({
return process({
data: sampleValue,
parentKey: value,
parentLabel: label,
});
return [objectItself].concat(objectEntries);
}
return [

View File

@@ -62,11 +62,11 @@ function TestSubstep(props) {
React.useEffect(
function resetTestDataOnSubstepToggle() {
if (!expanded && !loading) {
if (!expanded) {
reset();
}
},
[expanded, reset, loading],
[expanded, reset],
);
const handleSubmit = React.useCallback(async () => {
@@ -118,11 +118,7 @@ function TestSubstep(props) {
)}
{hasNoOutput && (
<Alert
data-test="flow-test-substep-no-output"
severity="warning"
sx={{ mb: 1, width: '100%' }}
>
<Alert severity="warning" sx={{ mb: 1, width: '100%' }}>
<AlertTitle sx={{ fontWeight: 700 }}>
{formatMessage('flowEditor.noTestDataTitle')}
</AlertTitle>

View File

@@ -0,0 +1,11 @@
import { gql } from '@apollo/client';
export const CREATE_APP_AUTH_CLIENT = gql`
mutation CreateAppAuthClient($input: CreateAppAuthClientInput) {
createAppAuthClient(input: $input) {
id
appConfigId
name
active
}
}
`;

View File

@@ -0,0 +1,12 @@
import { gql } from '@apollo/client';
export const CREATE_APP_CONFIG = gql`
mutation CreateAppConfig($input: CreateAppConfigInput) {
createAppConfig(input: $input) {
id
key
allowCustomConnection
shared
disabled
}
}
`;

View File

@@ -2,17 +2,17 @@ import { useQuery } from '@tanstack/react-query';
import api from 'helpers/api';
export default function useAdminAppAuthClient(appKey, id) {
export default function useAdminAppAuthClient(id) {
const query = useQuery({
queryKey: ['admin', 'apps', appKey, 'authClients', id],
queryKey: ['admin', 'appAuthClients', id],
queryFn: async ({ signal }) => {
const { data } = await api.get(`/v1/admin/apps/${appKey}/auth-clients/${id}`, {
const { data } = await api.get(`/v1/admin/app-auth-clients/${id}`, {
signal,
});
return data;
},
enabled: !!appKey && !!id,
enabled: !!id,
});
return query;

View File

@@ -1,9 +1,9 @@
import { useQuery } from '@tanstack/react-query';
import api from 'helpers/api';
export default function useAdminAppAuthClients(appKey) {
export default function useAdminAppAuthClient(appKey) {
const query = useQuery({
queryKey: ['admin', 'apps', appKey, 'authClients'],
queryKey: ['admin', 'apps', appKey, 'auth-clients'],
queryFn: async ({ signal }) => {
const { data } = await api.get(`/v1/admin/apps/${appKey}/auth-clients`, {
signal,

View File

@@ -1,21 +0,0 @@
import { useMutation, useQueryClient } from '@tanstack/react-query';
import api from 'helpers/api';
export default function useAdminCreateAppAuthClient(appKey) {
const queryClient = useQueryClient();
const query = useMutation({
mutationFn: async (payload) => {
const { data } = await api.post(`/v1/admin/apps/${appKey}/auth-clients`, payload);
return data;
},
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: ['admin', 'apps', appKey, 'authClients'],
});
}
});
return query;
}

View File

@@ -1,21 +0,0 @@
import { useMutation, useQueryClient } from '@tanstack/react-query';
import api from 'helpers/api';
export default function useAdminCreateAppConfig(appKey) {
const queryClient = useQueryClient();
const query = useMutation({
mutationFn: async (payload) => {
const { data } = await api.post(`/v1/admin/apps/${appKey}/config`, payload);
return data;
},
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: ['apps', appKey, 'config'],
});
}
});
return query;
}

407
yarn.lock
View File

@@ -2207,15 +2207,6 @@
"@jridgewell/sourcemap-codec" "^1.4.10"
"@jridgewell/trace-mapping" "^0.3.9"
"@jridgewell/gen-mapping@^0.3.5":
version "0.3.5"
resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz#dcce6aff74bdf6dad1a95802b69b04a2fcb1fb36"
integrity sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==
dependencies:
"@jridgewell/set-array" "^1.2.1"
"@jridgewell/sourcemap-codec" "^1.4.10"
"@jridgewell/trace-mapping" "^0.3.24"
"@jridgewell/resolve-uri@^3.1.0":
version "3.1.0"
resolved "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz"
@@ -2226,11 +2217,6 @@
resolved "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz"
integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==
"@jridgewell/set-array@^1.2.1":
version "1.2.1"
resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280"
integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==
"@jridgewell/source-map@^0.3.2":
version "0.3.2"
resolved "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz"
@@ -2239,14 +2225,6 @@
"@jridgewell/gen-mapping" "^0.3.0"
"@jridgewell/trace-mapping" "^0.3.9"
"@jridgewell/source-map@^0.3.3":
version "0.3.6"
resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.6.tgz#9d71ca886e32502eb9362c9a74a46787c36df81a"
integrity sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==
dependencies:
"@jridgewell/gen-mapping" "^0.3.5"
"@jridgewell/trace-mapping" "^0.3.25"
"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14":
version "1.4.14"
resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz"
@@ -2257,14 +2235,6 @@
resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32"
integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==
"@jridgewell/trace-mapping@^0.3.20", "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25":
version "0.3.25"
resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0"
integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==
dependencies:
"@jridgewell/resolve-uri" "^3.1.0"
"@jridgewell/sourcemap-codec" "^1.4.14"
"@jridgewell/trace-mapping@^0.3.9":
version "0.3.19"
resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz"
@@ -4159,6 +4129,22 @@
dependencies:
"@types/ms" "*"
"@types/eslint-scope@^3.7.3":
version "3.7.4"
resolved "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.4.tgz"
integrity sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==
dependencies:
"@types/eslint" "*"
"@types/estree" "*"
"@types/eslint@*":
version "8.2.2"
resolved "https://registry.npmjs.org/@types/eslint/-/eslint-8.2.2.tgz"
integrity sha512-nQxgB8/Sg+QKhnV8e0WzPpxjIGT3tuJDDzybkDi8ItE/IgTlHo07U0shaIjzhcvQxlq9SDRE42lsJ23uvEgJ2A==
dependencies:
"@types/estree" "*"
"@types/json-schema" "*"
"@types/eslint@^7.28.2":
version "7.29.0"
resolved "https://registry.npmjs.org/@types/eslint/-/eslint-7.29.0.tgz"
@@ -4177,11 +4163,16 @@
resolved "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz"
integrity sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==
"@types/estree@1.0.5", "@types/estree@^1.0.0", "@types/estree@^1.0.5":
"@types/estree@1.0.5", "@types/estree@^1.0.0":
version "1.0.5"
resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.5.tgz#a6ce3e556e00fd9895dd872dd172ad0d4bd687f4"
integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==
"@types/estree@^0.0.51":
version "0.0.51"
resolved "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz"
integrity sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==
"@types/express-serve-static-core@*", "@types/express-serve-static-core@^4.17.18":
version "4.17.28"
resolved "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.28.tgz"
@@ -4976,125 +4967,125 @@
dependencies:
vue-demi "*"
"@webassemblyjs/ast@1.12.1", "@webassemblyjs/ast@^1.12.1":
version "1.12.1"
resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.12.1.tgz#bb16a0e8b1914f979f45864c23819cc3e3f0d4bb"
integrity sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==
"@webassemblyjs/ast@1.11.1":
version "1.11.1"
resolved "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz"
integrity sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==
dependencies:
"@webassemblyjs/helper-numbers" "1.11.6"
"@webassemblyjs/helper-wasm-bytecode" "1.11.6"
"@webassemblyjs/helper-numbers" "1.11.1"
"@webassemblyjs/helper-wasm-bytecode" "1.11.1"
"@webassemblyjs/floating-point-hex-parser@1.11.6":
version "1.11.6"
resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz#dacbcb95aff135c8260f77fa3b4c5fea600a6431"
integrity sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==
"@webassemblyjs/floating-point-hex-parser@1.11.1":
version "1.11.1"
resolved "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz"
integrity sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==
"@webassemblyjs/helper-api-error@1.11.6":
version "1.11.6"
resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz#6132f68c4acd59dcd141c44b18cbebbd9f2fa768"
integrity sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==
"@webassemblyjs/helper-api-error@1.11.1":
version "1.11.1"
resolved "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz"
integrity sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==
"@webassemblyjs/helper-buffer@1.12.1":
version "1.12.1"
resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz#6df20d272ea5439bf20ab3492b7fb70e9bfcb3f6"
integrity sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==
"@webassemblyjs/helper-buffer@1.11.1":
version "1.11.1"
resolved "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz"
integrity sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==
"@webassemblyjs/helper-numbers@1.11.6":
version "1.11.6"
resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz#cbce5e7e0c1bd32cf4905ae444ef64cea919f1b5"
integrity sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==
"@webassemblyjs/helper-numbers@1.11.1":
version "1.11.1"
resolved "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz"
integrity sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==
dependencies:
"@webassemblyjs/floating-point-hex-parser" "1.11.6"
"@webassemblyjs/helper-api-error" "1.11.6"
"@webassemblyjs/floating-point-hex-parser" "1.11.1"
"@webassemblyjs/helper-api-error" "1.11.1"
"@xtuc/long" "4.2.2"
"@webassemblyjs/helper-wasm-bytecode@1.11.6":
version "1.11.6"
resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz#bb2ebdb3b83aa26d9baad4c46d4315283acd51e9"
integrity sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==
"@webassemblyjs/helper-wasm-bytecode@1.11.1":
version "1.11.1"
resolved "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz"
integrity sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==
"@webassemblyjs/helper-wasm-section@1.12.1":
version "1.12.1"
resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz#3da623233ae1a60409b509a52ade9bc22a37f7bf"
integrity sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==
"@webassemblyjs/helper-wasm-section@1.11.1":
version "1.11.1"
resolved "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz"
integrity sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==
dependencies:
"@webassemblyjs/ast" "1.12.1"
"@webassemblyjs/helper-buffer" "1.12.1"
"@webassemblyjs/helper-wasm-bytecode" "1.11.6"
"@webassemblyjs/wasm-gen" "1.12.1"
"@webassemblyjs/ast" "1.11.1"
"@webassemblyjs/helper-buffer" "1.11.1"
"@webassemblyjs/helper-wasm-bytecode" "1.11.1"
"@webassemblyjs/wasm-gen" "1.11.1"
"@webassemblyjs/ieee754@1.11.6":
version "1.11.6"
resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz#bb665c91d0b14fffceb0e38298c329af043c6e3a"
integrity sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==
"@webassemblyjs/ieee754@1.11.1":
version "1.11.1"
resolved "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz"
integrity sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==
dependencies:
"@xtuc/ieee754" "^1.2.0"
"@webassemblyjs/leb128@1.11.6":
version "1.11.6"
resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.11.6.tgz#70e60e5e82f9ac81118bc25381a0b283893240d7"
integrity sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==
"@webassemblyjs/leb128@1.11.1":
version "1.11.1"
resolved "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz"
integrity sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==
dependencies:
"@xtuc/long" "4.2.2"
"@webassemblyjs/utf8@1.11.6":
version "1.11.6"
resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.11.6.tgz#90f8bc34c561595fe156603be7253cdbcd0fab5a"
integrity sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==
"@webassemblyjs/utf8@1.11.1":
version "1.11.1"
resolved "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz"
integrity sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==
"@webassemblyjs/wasm-edit@^1.12.1":
version "1.12.1"
resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz#9f9f3ff52a14c980939be0ef9d5df9ebc678ae3b"
integrity sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==
"@webassemblyjs/wasm-edit@1.11.1":
version "1.11.1"
resolved "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz"
integrity sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==
dependencies:
"@webassemblyjs/ast" "1.12.1"
"@webassemblyjs/helper-buffer" "1.12.1"
"@webassemblyjs/helper-wasm-bytecode" "1.11.6"
"@webassemblyjs/helper-wasm-section" "1.12.1"
"@webassemblyjs/wasm-gen" "1.12.1"
"@webassemblyjs/wasm-opt" "1.12.1"
"@webassemblyjs/wasm-parser" "1.12.1"
"@webassemblyjs/wast-printer" "1.12.1"
"@webassemblyjs/ast" "1.11.1"
"@webassemblyjs/helper-buffer" "1.11.1"
"@webassemblyjs/helper-wasm-bytecode" "1.11.1"
"@webassemblyjs/helper-wasm-section" "1.11.1"
"@webassemblyjs/wasm-gen" "1.11.1"
"@webassemblyjs/wasm-opt" "1.11.1"
"@webassemblyjs/wasm-parser" "1.11.1"
"@webassemblyjs/wast-printer" "1.11.1"
"@webassemblyjs/wasm-gen@1.12.1":
version "1.12.1"
resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz#a6520601da1b5700448273666a71ad0a45d78547"
integrity sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==
"@webassemblyjs/wasm-gen@1.11.1":
version "1.11.1"
resolved "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz"
integrity sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==
dependencies:
"@webassemblyjs/ast" "1.12.1"
"@webassemblyjs/helper-wasm-bytecode" "1.11.6"
"@webassemblyjs/ieee754" "1.11.6"
"@webassemblyjs/leb128" "1.11.6"
"@webassemblyjs/utf8" "1.11.6"
"@webassemblyjs/ast" "1.11.1"
"@webassemblyjs/helper-wasm-bytecode" "1.11.1"
"@webassemblyjs/ieee754" "1.11.1"
"@webassemblyjs/leb128" "1.11.1"
"@webassemblyjs/utf8" "1.11.1"
"@webassemblyjs/wasm-opt@1.12.1":
version "1.12.1"
resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz#9e6e81475dfcfb62dab574ac2dda38226c232bc5"
integrity sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==
"@webassemblyjs/wasm-opt@1.11.1":
version "1.11.1"
resolved "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz"
integrity sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==
dependencies:
"@webassemblyjs/ast" "1.12.1"
"@webassemblyjs/helper-buffer" "1.12.1"
"@webassemblyjs/wasm-gen" "1.12.1"
"@webassemblyjs/wasm-parser" "1.12.1"
"@webassemblyjs/ast" "1.11.1"
"@webassemblyjs/helper-buffer" "1.11.1"
"@webassemblyjs/wasm-gen" "1.11.1"
"@webassemblyjs/wasm-parser" "1.11.1"
"@webassemblyjs/wasm-parser@1.12.1", "@webassemblyjs/wasm-parser@^1.12.1":
version "1.12.1"
resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz#c47acb90e6f083391e3fa61d113650eea1e95937"
integrity sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==
"@webassemblyjs/wasm-parser@1.11.1":
version "1.11.1"
resolved "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz"
integrity sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==
dependencies:
"@webassemblyjs/ast" "1.12.1"
"@webassemblyjs/helper-api-error" "1.11.6"
"@webassemblyjs/helper-wasm-bytecode" "1.11.6"
"@webassemblyjs/ieee754" "1.11.6"
"@webassemblyjs/leb128" "1.11.6"
"@webassemblyjs/utf8" "1.11.6"
"@webassemblyjs/ast" "1.11.1"
"@webassemblyjs/helper-api-error" "1.11.1"
"@webassemblyjs/helper-wasm-bytecode" "1.11.1"
"@webassemblyjs/ieee754" "1.11.1"
"@webassemblyjs/leb128" "1.11.1"
"@webassemblyjs/utf8" "1.11.1"
"@webassemblyjs/wast-printer@1.12.1":
version "1.12.1"
resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz#bcecf661d7d1abdaf989d8341a4833e33e2b31ac"
integrity sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==
"@webassemblyjs/wast-printer@1.11.1":
version "1.11.1"
resolved "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz"
integrity sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==
dependencies:
"@webassemblyjs/ast" "1.12.1"
"@webassemblyjs/ast" "1.11.1"
"@xtuc/long" "4.2.2"
"@wry/context@^0.6.0":
@@ -5182,10 +5173,10 @@ acorn-globals@^6.0.0:
acorn "^7.1.1"
acorn-walk "^7.1.1"
acorn-import-attributes@^1.9.5:
version "1.9.5"
resolved "https://registry.yarnpkg.com/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz#7eb1557b1ba05ef18b5ed0ec67591bfab04688ef"
integrity sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==
acorn-import-assertions@^1.7.6:
version "1.8.0"
resolved "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz"
integrity sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==
acorn-jsx@^5.3.1:
version "5.3.2"
@@ -5231,11 +5222,6 @@ acorn@^8.7.1:
resolved "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz"
integrity sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==
acorn@^8.8.2:
version "8.12.1"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.12.1.tgz#71616bdccbe25e27a54439e0046e89ca76df2248"
integrity sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==
add-stream@^1.0.0:
version "1.0.0"
resolved "https://registry.npmjs.org/add-stream/-/add-stream-1.0.0.tgz"
@@ -6012,7 +5998,7 @@ browser-process-hrtime@^1.0.0:
resolved "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz"
integrity sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==
browserslist@^4.0.0, browserslist@^4.16.0, browserslist@^4.16.6, browserslist@^4.17.5, browserslist@^4.18.1, browserslist@^4.19.1:
browserslist@^4.0.0, browserslist@^4.14.5, browserslist@^4.16.0, browserslist@^4.16.6, browserslist@^4.17.5, browserslist@^4.18.1, browserslist@^4.19.1:
version "4.19.1"
resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.19.1.tgz"
integrity sha512-u2tbbG5PdKRTUoctO3NBD8FQ5HdPh1ZXPHzp1rwaa5jTc+RV9/+RlWiAIKmjRPQF+xbGM9Kklj5bZQFa2s/38A==
@@ -6023,16 +6009,6 @@ browserslist@^4.0.0, browserslist@^4.16.0, browserslist@^4.16.6, browserslist@^4
node-releases "^2.0.1"
picocolors "^1.0.0"
browserslist@^4.21.10:
version "4.23.3"
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.23.3.tgz#debb029d3c93ebc97ffbc8d9cbb03403e227c800"
integrity sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA==
dependencies:
caniuse-lite "^1.0.30001646"
electron-to-chromium "^1.5.4"
node-releases "^2.0.18"
update-browserslist-db "^1.1.0"
bser@2.1.1:
version "2.1.1"
resolved "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz"
@@ -6269,11 +6245,6 @@ caniuse-lite@^1.0.30001299:
resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001301.tgz"
integrity sha512-csfD/GpHMqgEL3V3uIgosvh+SVIQvCh43SNu9HRbP1lnxkKm1kjDG4f32PP571JplkLjfS+mg2p1gxR7MYrrIA==
caniuse-lite@^1.0.30001646:
version "1.0.30001653"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001653.tgz#b8af452f8f33b1c77f122780a4aecebea0caca56"
integrity sha512-XGWQVB8wFQ2+9NZwZ10GxTYC5hk0Fa+q8cSkr0tgvMhYhMHP/QC+WTgrePMDBWiWc/pV+1ik82Al20XOK25Gcw==
case-sensitive-paths-webpack-plugin@^2.4.0:
version "2.4.0"
resolved "https://registry.npmjs.org/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.4.0.tgz"
@@ -7805,11 +7776,6 @@ electron-to-chromium@^1.4.17:
resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.48.tgz"
integrity sha512-RT3SEmpv7XUA+tKXrZGudAWLDpa7f8qmhjcLaM6OD/ERxjQ/zAojT8/Vvo0BSzbArkElFZ1WyZ9FuwAYbkdBNA==
electron-to-chromium@^1.5.4:
version "1.5.13"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.13.tgz#1abf0410c5344b2b829b7247e031f02810d442e6"
integrity sha512-lbBcvtIJ4J6sS4tb5TLp1b4LyfCdMkwStzXPyAgVgTRAsep4bvrAGaBOP7ZJtQMNJpSQ9SqG4brWOroNaQtm7Q==
emittery@^0.8.1:
version "0.8.1"
resolved "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz"
@@ -7854,10 +7820,10 @@ end-of-stream@^1.1.0, end-of-stream@^1.4.1:
dependencies:
once "^1.4.0"
enhanced-resolve@^5.17.1:
version "5.17.1"
resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz#67bfbbcc2f81d511be77d686a90267ef7f898a15"
integrity sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==
enhanced-resolve@^5.10.0:
version "5.12.0"
resolved "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.12.0.tgz"
integrity sha512-QHTXI/sZQmko1cbDoNAa3mJ5qhWUUNAq3vR0/YiD379fWQrcfuoX1+HW2S0MTt7XmoPLapdaDKUtelUSPic7hQ==
dependencies:
graceful-fs "^4.2.4"
tapable "^2.2.0"
@@ -7927,10 +7893,10 @@ es-abstract@^1.17.2, es-abstract@^1.19.0, es-abstract@^1.19.1:
string.prototype.trimstart "^1.0.4"
unbox-primitive "^1.0.1"
es-module-lexer@^1.2.1:
version "1.5.4"
resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-1.5.4.tgz#a8efec3a3da991e60efa6b633a7cad6ab8d26b78"
integrity sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==
es-module-lexer@^0.9.0:
version "0.9.3"
resolved "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz"
integrity sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==
es-to-primitive@^1.2.1:
version "1.2.1"
@@ -8103,11 +8069,6 @@ escalade@^3.1.1:
resolved "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz"
integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==
escalade@^3.1.2:
version "3.1.2"
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.2.tgz#54076e9ab29ea5bf3d8f1ed62acffbb88272df27"
integrity sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==
escape-goat@^2.0.0:
version "2.1.1"
resolved "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz"
@@ -9388,16 +9349,11 @@ got@^9.6.0:
to-readable-stream "^1.0.0"
url-parse-lax "^3.0.0"
graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.2, graceful-fs@^4.2.3, graceful-fs@^4.2.4, graceful-fs@^4.2.6:
graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.2, graceful-fs@^4.2.3, graceful-fs@^4.2.4, graceful-fs@^4.2.6, graceful-fs@^4.2.9:
version "4.2.9"
resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz"
integrity sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==
graceful-fs@^4.2.11:
version "4.2.11"
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3"
integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==
graphql-executor@0.0.18:
version "0.0.18"
resolved "https://registry.npmjs.org/graphql-executor/-/graphql-executor-0.0.18.tgz"
@@ -10835,15 +10791,6 @@ jest-worker@^27.0.2, jest-worker@^27.3.1, jest-worker@^27.4.1, jest-worker@^27.4
merge-stream "^2.0.0"
supports-color "^8.0.0"
jest-worker@^27.4.5:
version "27.5.1"
resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.5.1.tgz#8d146f0900e8973b106b6f73cc1e9a8cb86f8db0"
integrity sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==
dependencies:
"@types/node" "*"
merge-stream "^2.0.0"
supports-color "^8.0.0"
jest@^27.4.3:
version "27.4.7"
resolved "https://registry.npmjs.org/jest/-/jest-27.4.7.tgz"
@@ -12227,11 +12174,6 @@ node-releases@^2.0.1:
resolved "https://registry.npmjs.org/node-releases/-/node-releases-2.0.1.tgz"
integrity sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA==
node-releases@^2.0.18:
version "2.0.18"
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.18.tgz#f010e8d35e2fe8d6b2944f03f70213ecedc4ca3f"
integrity sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==
nodemailer@6.7.0:
version "6.7.0"
resolved "https://registry.npmjs.org/nodemailer/-/nodemailer-6.7.0.tgz"
@@ -13131,11 +13073,6 @@ picocolors@^1.0.0:
resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz"
integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==
picocolors@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.1.tgz#a8ad579b571952f0e5d25892de5445bcfe25aaa1"
integrity sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==
picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.2, picomatch@^2.2.3:
version "2.3.1"
resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz"
@@ -14944,7 +14881,7 @@ schema-utils@^2.6.5:
ajv "^6.12.4"
ajv-keywords "^3.5.2"
schema-utils@^3.0.0, schema-utils@^3.1.1:
schema-utils@^3.0.0, schema-utils@^3.1.0, schema-utils@^3.1.1:
version "3.1.1"
resolved "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz"
integrity sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==
@@ -14953,15 +14890,6 @@ schema-utils@^3.0.0, schema-utils@^3.1.1:
ajv "^6.12.5"
ajv-keywords "^3.5.2"
schema-utils@^3.2.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.3.0.tgz#f50a88877c3c01652a15b622ae9e9795df7a60fe"
integrity sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==
dependencies:
"@types/json-schema" "^7.0.8"
ajv "^6.12.5"
ajv-keywords "^3.5.2"
schema-utils@^4.0.0:
version "4.0.0"
resolved "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz"
@@ -15079,13 +15007,6 @@ serialize-javascript@^6.0.0:
dependencies:
randombytes "^2.1.0"
serialize-javascript@^6.0.1:
version "6.0.2"
resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.2.tgz#defa1e055c83bf6d59ea805d8da862254eb6a6c2"
integrity sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==
dependencies:
randombytes "^2.1.0"
serve-index@^1.9.1:
version "1.9.1"
resolved "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz"
@@ -16069,7 +15990,7 @@ terminal-link@^2.0.0:
ansi-escapes "^4.2.1"
supports-hyperlinks "^2.0.0"
terser-webpack-plugin@^5.2.5:
terser-webpack-plugin@^5.1.3, terser-webpack-plugin@^5.2.5:
version "5.3.0"
resolved "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.0.tgz"
integrity sha512-LPIisi3Ol4chwAaPP8toUJ3L4qCM1G0wao7L3qNv57Drezxj6+VEyySpPw4B1HSO2Eg/hDY/MNF5XihCAoqnsQ==
@@ -16080,17 +16001,6 @@ terser-webpack-plugin@^5.2.5:
source-map "^0.6.1"
terser "^5.7.2"
terser-webpack-plugin@^5.3.10:
version "5.3.10"
resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz#904f4c9193c6fd2a03f693a2150c62a92f40d199"
integrity sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==
dependencies:
"@jridgewell/trace-mapping" "^0.3.20"
jest-worker "^27.4.5"
schema-utils "^3.1.1"
serialize-javascript "^6.0.1"
terser "^5.26.0"
terser@^5.0.0, terser@^5.10.0, terser@^5.7.2:
version "5.14.2"
resolved "https://registry.npmjs.org/terser/-/terser-5.14.2.tgz"
@@ -16101,16 +16011,6 @@ terser@^5.0.0, terser@^5.10.0, terser@^5.7.2:
commander "^2.20.0"
source-map-support "~0.5.20"
terser@^5.26.0:
version "5.31.6"
resolved "https://registry.yarnpkg.com/terser/-/terser-5.31.6.tgz#c63858a0f0703988d0266a82fcbf2d7ba76422b1"
integrity sha512-PQ4DAriWzKj+qgehQ7LK5bQqCFNMmlhjR2PFFLuqGCpuCAauxemVBWwWOxo3UIwWQx8+Pr61Df++r76wDmkQBg==
dependencies:
"@jridgewell/source-map" "^0.3.3"
acorn "^8.8.2"
commander "^2.20.0"
source-map-support "~0.5.20"
test-exclude@^6.0.0:
version "6.0.0"
resolved "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz"
@@ -16569,14 +16469,6 @@ upath@^2.0.1:
resolved "https://registry.npmjs.org/upath/-/upath-2.0.1.tgz"
integrity sha512-1uEe95xksV1O0CYKXo8vQvN1JEbtJp7lb7C5U9HMsIp6IVwntkH/oNUzyVNQSd4S1sYk2FpSSW44FqMc8qee5w==
update-browserslist-db@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz#7ca61c0d8650766090728046e416a8cde682859e"
integrity sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==
dependencies:
escalade "^3.1.2"
picocolors "^1.0.1"
update-notifier@^5.1.0:
version "5.1.0"
resolved "https://registry.npmjs.org/update-notifier/-/update-notifier-5.1.0.tgz"
@@ -16850,10 +16742,10 @@ walker@^1.0.7:
dependencies:
makeerror "1.0.12"
watchpack@^2.4.1:
version "2.4.2"
resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.4.2.tgz#2feeaed67412e7c33184e5a79ca738fbd38564da"
integrity sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==
watchpack@^2.4.0:
version "2.4.0"
resolved "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz"
integrity sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==
dependencies:
glob-to-regexp "^0.4.1"
graceful-fs "^4.1.2"
@@ -16973,32 +16865,33 @@ webpack-sources@^3.2.3:
integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==
webpack@^5.64.4:
version "5.94.0"
resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.94.0.tgz#77a6089c716e7ab90c1c67574a28da518a20970f"
integrity sha512-KcsGn50VT+06JH/iunZJedYGUJS5FGjow8wb9c0v5n1Om8O1g4L6LjtfxwlXIATopoQu+vOXXa7gYisWxCoPyg==
version "5.76.1"
resolved "https://registry.npmjs.org/webpack/-/webpack-5.76.1.tgz"
integrity sha512-4+YIK4Abzv8172/SGqObnUjaIHjLEuUasz9EwQj/9xmPPkYJy2Mh03Q/lJfSD3YLzbxy5FeTq5Uw0323Oh6SJQ==
dependencies:
"@types/estree" "^1.0.5"
"@webassemblyjs/ast" "^1.12.1"
"@webassemblyjs/wasm-edit" "^1.12.1"
"@webassemblyjs/wasm-parser" "^1.12.1"
"@types/eslint-scope" "^3.7.3"
"@types/estree" "^0.0.51"
"@webassemblyjs/ast" "1.11.1"
"@webassemblyjs/wasm-edit" "1.11.1"
"@webassemblyjs/wasm-parser" "1.11.1"
acorn "^8.7.1"
acorn-import-attributes "^1.9.5"
browserslist "^4.21.10"
acorn-import-assertions "^1.7.6"
browserslist "^4.14.5"
chrome-trace-event "^1.0.2"
enhanced-resolve "^5.17.1"
es-module-lexer "^1.2.1"
enhanced-resolve "^5.10.0"
es-module-lexer "^0.9.0"
eslint-scope "5.1.1"
events "^3.2.0"
glob-to-regexp "^0.4.1"
graceful-fs "^4.2.11"
graceful-fs "^4.2.9"
json-parse-even-better-errors "^2.3.1"
loader-runner "^4.2.0"
mime-types "^2.1.27"
neo-async "^2.6.2"
schema-utils "^3.2.0"
schema-utils "^3.1.0"
tapable "^2.1.1"
terser-webpack-plugin "^5.3.10"
watchpack "^2.4.1"
terser-webpack-plugin "^5.1.3"
watchpack "^2.4.0"
webpack-sources "^3.2.3"
websocket-driver@>=0.5.1, websocket-driver@^0.7.4: