mirror of
https://github.com/n8n-io/n8n.git
synced 2025-03-05 20:50:17 -08:00
refactor: Move cURL converter to frontend (#11432)
Co-authored-by: कारतोफ्फेलस्क्रिप्ट™ <aditya@netroy.in>
This commit is contained in:
parent
94789e0309
commit
8b28d6ce8e
|
@ -91,6 +91,7 @@
|
||||||
},
|
},
|
||||||
"patchedDependencies": {
|
"patchedDependencies": {
|
||||||
"bull@4.12.1": "patches/bull@4.12.1.patch",
|
"bull@4.12.1": "patches/bull@4.12.1.patch",
|
||||||
|
"curlconverter@4.11.0": "patches/curlconverter@4.11.0.patch",
|
||||||
"pkce-challenge@3.0.0": "patches/pkce-challenge@3.0.0.patch",
|
"pkce-challenge@3.0.0": "patches/pkce-challenge@3.0.0.patch",
|
||||||
"pyodide@0.23.4": "patches/pyodide@0.23.4.patch",
|
"pyodide@0.23.4": "patches/pyodide@0.23.4.patch",
|
||||||
"@types/express-serve-static-core@4.17.43": "patches/@types__express-serve-static-core@4.17.43.patch",
|
"@types/express-serve-static-core@4.17.43": "patches/@types__express-serve-static-core@4.17.43.patch",
|
||||||
|
|
|
@ -112,7 +112,6 @@
|
||||||
"convict": "6.2.4",
|
"convict": "6.2.4",
|
||||||
"cookie-parser": "1.4.7",
|
"cookie-parser": "1.4.7",
|
||||||
"csrf": "3.1.0",
|
"csrf": "3.1.0",
|
||||||
"curlconverter": "3.21.0",
|
|
||||||
"dotenv": "8.6.0",
|
"dotenv": "8.6.0",
|
||||||
"express": "4.21.1",
|
"express": "4.21.1",
|
||||||
"express-async-errors": "3.1.1",
|
"express-async-errors": "3.1.1",
|
||||||
|
|
|
@ -1,52 +0,0 @@
|
||||||
import type { Request } from 'express';
|
|
||||||
import { mock } from 'jest-mock-extended';
|
|
||||||
|
|
||||||
import { CurlController } from '@/controllers/curl.controller';
|
|
||||||
import { BadRequestError } from '@/errors/response-errors/bad-request.error';
|
|
||||||
import type { CurlService } from '@/services/curl.service';
|
|
||||||
|
|
||||||
describe('CurlController', () => {
|
|
||||||
const service = mock<CurlService>();
|
|
||||||
const controller = new CurlController(service);
|
|
||||||
|
|
||||||
beforeEach(() => jest.clearAllMocks());
|
|
||||||
|
|
||||||
describe('toJson', () => {
|
|
||||||
it('should throw BadRequestError when invalid cURL command is provided', () => {
|
|
||||||
const req = mock<Request>();
|
|
||||||
service.toHttpNodeParameters.mockImplementation(() => {
|
|
||||||
throw new Error();
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(() => controller.toJson(req)).toThrow(BadRequestError);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return flattened parameters when valid cURL command is provided', () => {
|
|
||||||
const curlCommand = 'curl -v -X GET https://test.n8n.berlin/users';
|
|
||||||
const req = mock<Request>();
|
|
||||||
req.body = { curlCommand };
|
|
||||||
service.toHttpNodeParameters.mockReturnValue({
|
|
||||||
url: 'https://test.n8n.berlin/users',
|
|
||||||
authentication: 'none',
|
|
||||||
method: 'GET',
|
|
||||||
sendHeaders: false,
|
|
||||||
sendQuery: false,
|
|
||||||
options: {
|
|
||||||
redirect: { redirect: {} },
|
|
||||||
response: { response: {} },
|
|
||||||
},
|
|
||||||
sendBody: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
const result = controller.toJson(req);
|
|
||||||
expect(result).toEqual({
|
|
||||||
'parameters.method': 'GET',
|
|
||||||
'parameters.url': 'https://test.n8n.berlin/users',
|
|
||||||
'parameters.authentication': 'none',
|
|
||||||
'parameters.sendBody': false,
|
|
||||||
'parameters.sendHeaders': false,
|
|
||||||
'parameters.sendQuery': false,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,20 +0,0 @@
|
||||||
import { Request } from 'express';
|
|
||||||
|
|
||||||
import { Post, RestController } from '@/decorators';
|
|
||||||
import { BadRequestError } from '@/errors/response-errors/bad-request.error';
|
|
||||||
import { CurlService, flattenObject } from '@/services/curl.service';
|
|
||||||
|
|
||||||
@RestController('/curl')
|
|
||||||
export class CurlController {
|
|
||||||
constructor(private readonly curlService: CurlService) {}
|
|
||||||
|
|
||||||
@Post('/to-json')
|
|
||||||
toJson(req: Request<{}, {}, { curlCommand: string }>) {
|
|
||||||
try {
|
|
||||||
const parameters = this.curlService.toHttpNodeParameters(req.body.curlCommand);
|
|
||||||
return flattenObject(parameters, 'parameters');
|
|
||||||
} catch (e) {
|
|
||||||
throw new BadRequestError('Invalid cURL command');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
3
packages/cli/src/curlconverter.d.ts
vendored
3
packages/cli/src/curlconverter.d.ts
vendored
|
@ -1,3 +0,0 @@
|
||||||
declare module 'curlconverter' {
|
|
||||||
export function toJsonString(data: string): string;
|
|
||||||
}
|
|
|
@ -37,7 +37,6 @@ import '@/controllers/active-workflows.controller';
|
||||||
import '@/controllers/annotation-tags.controller.ee';
|
import '@/controllers/annotation-tags.controller.ee';
|
||||||
import '@/controllers/auth.controller';
|
import '@/controllers/auth.controller';
|
||||||
import '@/controllers/binary-data.controller';
|
import '@/controllers/binary-data.controller';
|
||||||
import '@/controllers/curl.controller';
|
|
||||||
import '@/controllers/ai.controller';
|
import '@/controllers/ai.controller';
|
||||||
import '@/controllers/dynamic-node-parameters.controller';
|
import '@/controllers/dynamic-node-parameters.controller';
|
||||||
import '@/controllers/invitation.controller';
|
import '@/controllers/invitation.controller';
|
||||||
|
@ -392,6 +391,7 @@ export class Server extends AbstractServer {
|
||||||
method === 'GET' &&
|
method === 'GET' &&
|
||||||
accept &&
|
accept &&
|
||||||
(accept.includes('text/html') || accept.includes('*/*')) &&
|
(accept.includes('text/html') || accept.includes('*/*')) &&
|
||||||
|
!req.path.endsWith('.wasm') &&
|
||||||
!nonUIRoutesRegex.test(req.path)
|
!nonUIRoutesRegex.test(req.path)
|
||||||
) {
|
) {
|
||||||
res.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate');
|
res.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate');
|
||||||
|
|
|
@ -1,297 +0,0 @@
|
||||||
import { CurlService } from '@/services/curl.service';
|
|
||||||
|
|
||||||
describe('CurlService', () => {
|
|
||||||
const service = new CurlService();
|
|
||||||
|
|
||||||
test('Should parse form-urlencoded content type correctly', () => {
|
|
||||||
const curl =
|
|
||||||
'curl -X POST https://reqbin.com/echo/post/form -H "Content-Type: application/x-www-form-urlencoded" -d "param1=value1¶m2=value2"';
|
|
||||||
const parameters = service.toHttpNodeParameters(curl);
|
|
||||||
expect(parameters.url).toBe('https://reqbin.com/echo/post/form');
|
|
||||||
expect(parameters.sendBody).toBe(true);
|
|
||||||
expect(parameters.bodyParameters?.parameters[0].name).toBe('param1');
|
|
||||||
expect(parameters.bodyParameters?.parameters[0].value).toBe('value1');
|
|
||||||
expect(parameters.bodyParameters?.parameters[1].name).toBe('param2');
|
|
||||||
expect(parameters.bodyParameters?.parameters[1].value).toBe('value2');
|
|
||||||
expect(parameters.contentType).toBe('form-urlencoded');
|
|
||||||
expect(parameters.sendHeaders).toBe(false);
|
|
||||||
expect(parameters.sendQuery).toBe(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('Should parse JSON content type correctly', () => {
|
|
||||||
const curl =
|
|
||||||
'curl -X POST https://reqbin.com/echo/post/json -H \'Content-Type: application/json\' -d \'{"login":"my_login","password":"my_password"}\'';
|
|
||||||
const parameters = service.toHttpNodeParameters(curl);
|
|
||||||
expect(parameters.url).toBe('https://reqbin.com/echo/post/json');
|
|
||||||
expect(parameters.sendBody).toBe(true);
|
|
||||||
expect(parameters.bodyParameters?.parameters[0].name).toBe('login');
|
|
||||||
expect(parameters.bodyParameters?.parameters[0].value).toBe('my_login');
|
|
||||||
expect(parameters.bodyParameters?.parameters[1].name).toBe('password');
|
|
||||||
expect(parameters.bodyParameters?.parameters[1].value).toBe('my_password');
|
|
||||||
expect(parameters.contentType).toBe('json');
|
|
||||||
expect(parameters.sendHeaders).toBe(false);
|
|
||||||
expect(parameters.sendQuery).toBe(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('Should parse multipart-form-data content type correctly', () => {
|
|
||||||
const curl =
|
|
||||||
'curl -X POST https://reqbin.com/echo/post/json -v -F key1=value1 -F upload=@localfilename';
|
|
||||||
const parameters = service.toHttpNodeParameters(curl);
|
|
||||||
expect(parameters.url).toBe('https://reqbin.com/echo/post/json');
|
|
||||||
expect(parameters.sendBody).toBe(true);
|
|
||||||
expect(parameters.bodyParameters?.parameters[0].parameterType).toBe('formData');
|
|
||||||
expect(parameters.bodyParameters?.parameters[0].name).toBe('key1');
|
|
||||||
expect(parameters.bodyParameters?.parameters[0].value).toBe('value1');
|
|
||||||
expect(parameters.bodyParameters?.parameters[1].parameterType).toBe('formBinaryData');
|
|
||||||
expect(parameters.bodyParameters?.parameters[1].name).toBe('upload');
|
|
||||||
expect(parameters.contentType).toBe('multipart-form-data');
|
|
||||||
expect(parameters.sendHeaders).toBe(false);
|
|
||||||
expect(parameters.sendQuery).toBe(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('Should parse binary request correctly', () => {
|
|
||||||
const curl =
|
|
||||||
"curl --location --request POST 'https://www.website.com' --header 'Content-Type: image/png' --data-binary '@/Users/image.png";
|
|
||||||
const parameters = service.toHttpNodeParameters(curl);
|
|
||||||
expect(parameters.url).toBe('https://www.website.com');
|
|
||||||
expect(parameters.method).toBe('POST');
|
|
||||||
expect(parameters.sendBody).toBe(true);
|
|
||||||
expect(parameters.contentType).toBe('binaryData');
|
|
||||||
expect(parameters.sendHeaders).toBe(false);
|
|
||||||
expect(parameters.sendQuery).toBe(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('Should parse unknown content type correctly', () => {
|
|
||||||
const curl = `curl -X POST https://reqbin.com/echo/post/xml
|
|
||||||
-H "Content-Type: application/xml"
|
|
||||||
-H "Accept: application/xml"
|
|
||||||
-d "<Request><Login>my_login</Login><Password>my_password</Password></Request>"`;
|
|
||||||
const parameters = service.toHttpNodeParameters(curl);
|
|
||||||
expect(parameters.url).toBe('https://reqbin.com/echo/post/xml');
|
|
||||||
expect(parameters.method).toBe('POST');
|
|
||||||
expect(parameters.sendBody).toBe(true);
|
|
||||||
expect(parameters.contentType).toBe('raw');
|
|
||||||
expect(parameters.rawContentType).toBe('application/xml');
|
|
||||||
expect(parameters.sendHeaders).toBe(true);
|
|
||||||
expect(parameters.headerParameters?.parameters[0].name).toBe('Accept');
|
|
||||||
expect(parameters.headerParameters?.parameters[0].value).toBe('application/xml');
|
|
||||||
expect(parameters.sendQuery).toBe(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('Should parse header properties and keep the original case', () => {
|
|
||||||
const curl =
|
|
||||||
'curl -X POST https://reqbin.com/echo/post/json -v -F key1=value1 -F upload=@localfilename -H "ACCEPT: text/javascript" -H "content-type: multipart/form-data"';
|
|
||||||
const parameters = service.toHttpNodeParameters(curl);
|
|
||||||
expect(parameters.url).toBe('https://reqbin.com/echo/post/json');
|
|
||||||
expect(parameters.sendBody).toBe(true);
|
|
||||||
expect(parameters.bodyParameters?.parameters[0].parameterType).toBe('formData');
|
|
||||||
expect(parameters.bodyParameters?.parameters[0].name).toBe('key1');
|
|
||||||
expect(parameters.bodyParameters?.parameters[0].value).toBe('value1');
|
|
||||||
expect(parameters.bodyParameters?.parameters[1].parameterType).toBe('formBinaryData');
|
|
||||||
expect(parameters.bodyParameters?.parameters[1].name).toBe('upload');
|
|
||||||
expect(parameters.contentType).toBe('multipart-form-data');
|
|
||||||
expect(parameters.sendHeaders).toBe(true);
|
|
||||||
expect(parameters.headerParameters?.parameters[0].name).toBe('ACCEPT');
|
|
||||||
expect(parameters.headerParameters?.parameters[0].value).toBe('text/javascript');
|
|
||||||
expect(parameters.sendQuery).toBe(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('Should parse querystring properties', () => {
|
|
||||||
const curl = "curl -G -d 'q=kitties' -d 'count=20' https://google.com/search";
|
|
||||||
const parameters = service.toHttpNodeParameters(curl);
|
|
||||||
expect(parameters.url).toBe('https://google.com/search');
|
|
||||||
expect(parameters.sendBody).toBe(false);
|
|
||||||
expect(parameters.contentType).toBeUndefined();
|
|
||||||
expect(parameters.sendHeaders).toBe(false);
|
|
||||||
expect(parameters.sendQuery).toBe(true);
|
|
||||||
expect(parameters.queryParameters?.parameters[0].name).toBe('q');
|
|
||||||
expect(parameters.queryParameters?.parameters[0].value).toBe('kitties');
|
|
||||||
expect(parameters.queryParameters?.parameters[1].name).toBe('count');
|
|
||||||
expect(parameters.queryParameters?.parameters[1].value).toBe('20');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('Should parse basic authentication property and keep the original case', () => {
|
|
||||||
const curl = 'curl https://reqbin.com/echo -u "login:password"';
|
|
||||||
const parameters = service.toHttpNodeParameters(curl);
|
|
||||||
expect(parameters.url).toBe('https://reqbin.com/echo');
|
|
||||||
expect(parameters.sendBody).toBe(false);
|
|
||||||
expect(parameters.contentType).toBeUndefined();
|
|
||||||
expect(parameters.sendQuery).toBe(false);
|
|
||||||
expect(parameters.sendHeaders).toBe(true);
|
|
||||||
expect(parameters.headerParameters?.parameters[0].name).toBe('authorization');
|
|
||||||
expect(parameters.headerParameters?.parameters[0].value).toBe(
|
|
||||||
`Basic ${Buffer.from('login:password').toString('base64')}`,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('Should parse location flag with --location', () => {
|
|
||||||
const curl = 'curl https://reqbin.com/echo -u "login:password" --location';
|
|
||||||
const parameters = service.toHttpNodeParameters(curl);
|
|
||||||
expect(parameters.url).toBe('https://reqbin.com/echo');
|
|
||||||
expect(parameters.sendBody).toBe(false);
|
|
||||||
expect(parameters.contentType).toBeUndefined();
|
|
||||||
expect(parameters.sendQuery).toBe(false);
|
|
||||||
expect(parameters.sendHeaders).toBe(true);
|
|
||||||
expect(parameters.headerParameters?.parameters[0].name).toBe('authorization');
|
|
||||||
expect(parameters.headerParameters?.parameters[0].value).toBe(
|
|
||||||
`Basic ${Buffer.from('login:password').toString('base64')}`,
|
|
||||||
);
|
|
||||||
expect(parameters.options.redirect.redirect.followRedirects).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('Should parse location flag with --L', () => {
|
|
||||||
const curl = 'curl https://reqbin.com/echo -u "login:password" -L';
|
|
||||||
const parameters = service.toHttpNodeParameters(curl);
|
|
||||||
expect(parameters.url).toBe('https://reqbin.com/echo');
|
|
||||||
expect(parameters.sendBody).toBe(false);
|
|
||||||
expect(parameters.contentType).toBeUndefined();
|
|
||||||
expect(parameters.sendQuery).toBe(false);
|
|
||||||
expect(parameters.sendHeaders).toBe(true);
|
|
||||||
expect(parameters.headerParameters?.parameters[0].name).toBe('authorization');
|
|
||||||
expect(parameters.headerParameters?.parameters[0].value).toBe(
|
|
||||||
`Basic ${Buffer.from('login:password').toString('base64')}`,
|
|
||||||
);
|
|
||||||
expect(parameters.options.redirect.redirect.followRedirects).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('Should parse location and max redirects flags with --location and --max-redirs 10', () => {
|
|
||||||
const curl = 'curl https://reqbin.com/echo -u "login:password" --location --max-redirs 10';
|
|
||||||
const parameters = service.toHttpNodeParameters(curl);
|
|
||||||
expect(parameters.url).toBe('https://reqbin.com/echo');
|
|
||||||
expect(parameters.sendBody).toBe(false);
|
|
||||||
expect(parameters.contentType).toBeUndefined();
|
|
||||||
expect(parameters.sendQuery).toBe(false);
|
|
||||||
expect(parameters.sendHeaders).toBe(true);
|
|
||||||
expect(parameters.headerParameters?.parameters[0].name).toBe('authorization');
|
|
||||||
expect(parameters.headerParameters?.parameters[0].value).toBe(
|
|
||||||
`Basic ${Buffer.from('login:password').toString('base64')}`,
|
|
||||||
);
|
|
||||||
expect(parameters.options.redirect.redirect.followRedirects).toBe(true);
|
|
||||||
expect(parameters.options.redirect.redirect.maxRedirects).toBe('10');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('Should parse proxy flag -x', () => {
|
|
||||||
const curl = 'curl https://reqbin.com/echo -u "login:password" -x https://google.com';
|
|
||||||
const parameters = service.toHttpNodeParameters(curl);
|
|
||||||
expect(parameters.url).toBe('https://reqbin.com/echo');
|
|
||||||
expect(parameters.sendBody).toBe(false);
|
|
||||||
expect(parameters.contentType).toBeUndefined();
|
|
||||||
expect(parameters.sendQuery).toBe(false);
|
|
||||||
expect(parameters.sendHeaders).toBe(true);
|
|
||||||
expect(parameters.headerParameters?.parameters[0].name).toBe('authorization');
|
|
||||||
expect(parameters.headerParameters?.parameters[0].value).toBe(
|
|
||||||
`Basic ${Buffer.from('login:password').toString('base64')}`,
|
|
||||||
);
|
|
||||||
expect(parameters.options.proxy).toBe('https://google.com');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('Should parse proxy flag --proxy', () => {
|
|
||||||
const curl = 'curl https://reqbin.com/echo -u "login:password" -x https://google.com';
|
|
||||||
const parameters = service.toHttpNodeParameters(curl);
|
|
||||||
expect(parameters.url).toBe('https://reqbin.com/echo');
|
|
||||||
expect(parameters.sendBody).toBe(false);
|
|
||||||
expect(parameters.contentType).toBeUndefined();
|
|
||||||
expect(parameters.sendQuery).toBe(false);
|
|
||||||
expect(parameters.sendHeaders).toBe(true);
|
|
||||||
expect(parameters.headerParameters?.parameters[0].name).toBe('authorization');
|
|
||||||
expect(parameters.headerParameters?.parameters[0].value).toBe(
|
|
||||||
`Basic ${Buffer.from('login:password').toString('base64')}`,
|
|
||||||
);
|
|
||||||
expect(parameters.options.proxy).toBe('https://google.com');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('Should parse include headers on output flag --include', () => {
|
|
||||||
const curl = 'curl https://reqbin.com/echo -u "login:password" --include -x https://google.com';
|
|
||||||
const parameters = service.toHttpNodeParameters(curl);
|
|
||||||
expect(parameters.url).toBe('https://reqbin.com/echo');
|
|
||||||
expect(parameters.sendBody).toBe(false);
|
|
||||||
expect(parameters.contentType).toBeUndefined();
|
|
||||||
expect(parameters.sendQuery).toBe(false);
|
|
||||||
expect(parameters.sendHeaders).toBe(true);
|
|
||||||
expect(parameters.headerParameters?.parameters[0].name).toBe('authorization');
|
|
||||||
expect(parameters.headerParameters?.parameters[0].value).toBe(
|
|
||||||
`Basic ${Buffer.from('login:password').toString('base64')}`,
|
|
||||||
);
|
|
||||||
expect(parameters.options.response.response.fullResponse).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('Should parse include headers on output flag -i', () => {
|
|
||||||
const curl = 'curl https://reqbin.com/echo -u "login:password" -x https://google.com -i';
|
|
||||||
const parameters = service.toHttpNodeParameters(curl);
|
|
||||||
expect(parameters.url).toBe('https://reqbin.com/echo');
|
|
||||||
expect(parameters.sendBody).toBe(false);
|
|
||||||
expect(parameters.contentType).toBeUndefined();
|
|
||||||
expect(parameters.sendQuery).toBe(false);
|
|
||||||
expect(parameters.sendHeaders).toBe(true);
|
|
||||||
expect(parameters.headerParameters?.parameters[0].name).toBe('authorization');
|
|
||||||
expect(parameters.headerParameters?.parameters[0].value).toBe(
|
|
||||||
`Basic ${Buffer.from('login:password').toString('base64')}`,
|
|
||||||
);
|
|
||||||
expect(parameters.options.response.response.fullResponse).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('Should parse include request flag -X', () => {
|
|
||||||
const curl = 'curl -X POST https://reqbin.com/echo -u "login:password" -x https://google.com';
|
|
||||||
const parameters = service.toHttpNodeParameters(curl);
|
|
||||||
expect(parameters.url).toBe('https://reqbin.com/echo');
|
|
||||||
expect(parameters.method).toBe('POST');
|
|
||||||
expect(parameters.sendBody).toBe(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('Should parse include request flag --request', () => {
|
|
||||||
const curl =
|
|
||||||
'curl --request POST https://reqbin.com/echo -u "login:password" -x https://google.com';
|
|
||||||
const parameters = service.toHttpNodeParameters(curl);
|
|
||||||
expect(parameters.url).toBe('https://reqbin.com/echo');
|
|
||||||
expect(parameters.method).toBe('POST');
|
|
||||||
expect(parameters.sendBody).toBe(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('Should parse include timeout flag --connect-timeout', () => {
|
|
||||||
const curl =
|
|
||||||
'curl --request POST https://reqbin.com/echo -u "login:password" --connect-timeout 20';
|
|
||||||
const parameters = service.toHttpNodeParameters(curl);
|
|
||||||
expect(parameters.url).toBe('https://reqbin.com/echo');
|
|
||||||
expect(parameters.method).toBe('POST');
|
|
||||||
expect(parameters.sendBody).toBe(false);
|
|
||||||
expect(parameters.options.timeout).toBe(20000);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('Should parse download file flag -O', () => {
|
|
||||||
const curl = 'curl --request POST https://reqbin.com/echo -u "login:password" -O';
|
|
||||||
const parameters = service.toHttpNodeParameters(curl);
|
|
||||||
expect(parameters.url).toBe('https://reqbin.com/echo');
|
|
||||||
expect(parameters.method).toBe('POST');
|
|
||||||
expect(parameters.sendBody).toBe(false);
|
|
||||||
expect(parameters.options.response.response.responseFormat).toBe('file');
|
|
||||||
expect(parameters.options.response.response.outputPropertyName).toBe('data');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('Should parse download file flag -o', () => {
|
|
||||||
const curl = 'curl --request POST https://reqbin.com/echo -u "login:password" -o';
|
|
||||||
const parameters = service.toHttpNodeParameters(curl);
|
|
||||||
expect(parameters.url).toBe('https://reqbin.com/echo');
|
|
||||||
expect(parameters.method).toBe('POST');
|
|
||||||
expect(parameters.sendBody).toBe(false);
|
|
||||||
expect(parameters.options.response.response.responseFormat).toBe('file');
|
|
||||||
expect(parameters.options.response.response.outputPropertyName).toBe('data');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('Should parse ignore SSL flag -k', () => {
|
|
||||||
const curl = 'curl --request POST https://reqbin.com/echo -u "login:password" -k';
|
|
||||||
const parameters = service.toHttpNodeParameters(curl);
|
|
||||||
expect(parameters.url).toBe('https://reqbin.com/echo');
|
|
||||||
expect(parameters.method).toBe('POST');
|
|
||||||
expect(parameters.sendBody).toBe(false);
|
|
||||||
expect(parameters.options.allowUnauthorizedCerts).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('Should parse ignore SSL flag --insecure', () => {
|
|
||||||
const curl = 'curl --request POST https://reqbin.com/echo -u "login:password" --insecure';
|
|
||||||
const parameters = service.toHttpNodeParameters(curl);
|
|
||||||
expect(parameters.url).toBe('https://reqbin.com/echo');
|
|
||||||
expect(parameters.method).toBe('POST');
|
|
||||||
expect(parameters.sendBody).toBe(false);
|
|
||||||
expect(parameters.options.allowUnauthorizedCerts).toBe(true);
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,479 +0,0 @@
|
||||||
import { Service } from '@n8n/di';
|
|
||||||
import get from 'lodash/get';
|
|
||||||
import type { IDataObject } from 'n8n-workflow';
|
|
||||||
import { jsonParse } from 'n8n-workflow';
|
|
||||||
|
|
||||||
import curlconverter from 'curlconverter';
|
|
||||||
|
|
||||||
interface CurlJson {
|
|
||||||
url: string;
|
|
||||||
raw_url?: string;
|
|
||||||
method: string;
|
|
||||||
contentType?: string;
|
|
||||||
cookies?: {
|
|
||||||
[key: string]: string;
|
|
||||||
};
|
|
||||||
auth?: {
|
|
||||||
user: string;
|
|
||||||
password: string;
|
|
||||||
};
|
|
||||||
headers?: {
|
|
||||||
[key: string]: string;
|
|
||||||
};
|
|
||||||
files?: {
|
|
||||||
[key: string]: string;
|
|
||||||
};
|
|
||||||
queries: {
|
|
||||||
[key: string]: string;
|
|
||||||
};
|
|
||||||
data?: {
|
|
||||||
[key: string]: string;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Parameter {
|
|
||||||
parameterType?: string;
|
|
||||||
name: string;
|
|
||||||
value: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface HttpNodeParameters {
|
|
||||||
url?: string;
|
|
||||||
method: string;
|
|
||||||
sendBody?: boolean;
|
|
||||||
authentication: string;
|
|
||||||
contentType?: 'form-urlencoded' | 'multipart-form-data' | 'json' | 'raw' | 'binaryData';
|
|
||||||
rawContentType?: string;
|
|
||||||
specifyBody?: 'json' | 'keypair';
|
|
||||||
bodyParameters?: {
|
|
||||||
parameters: Parameter[];
|
|
||||||
};
|
|
||||||
jsonBody?: object;
|
|
||||||
options: {
|
|
||||||
allowUnauthorizedCerts?: boolean;
|
|
||||||
proxy?: string;
|
|
||||||
timeout?: number;
|
|
||||||
redirect: {
|
|
||||||
redirect: {
|
|
||||||
followRedirects?: boolean;
|
|
||||||
maxRedirects?: number;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
response: {
|
|
||||||
response: {
|
|
||||||
fullResponse?: boolean;
|
|
||||||
responseFormat?: string;
|
|
||||||
outputPropertyName?: string;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
sendHeaders?: boolean;
|
|
||||||
headerParameters?: {
|
|
||||||
parameters: Parameter[];
|
|
||||||
};
|
|
||||||
sendQuery?: boolean;
|
|
||||||
queryParameters?: {
|
|
||||||
parameters: Parameter[];
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
type HttpNodeHeaders = Pick<HttpNodeParameters, 'sendHeaders' | 'headerParameters'>;
|
|
||||||
|
|
||||||
type HttpNodeQueries = Pick<HttpNodeParameters, 'sendQuery' | 'queryParameters'>;
|
|
||||||
|
|
||||||
const enum ContentTypes {
|
|
||||||
applicationJson = 'application/json',
|
|
||||||
applicationFormUrlEncoded = 'application/x-www-form-urlencoded',
|
|
||||||
applicationMultipart = 'multipart/form-data',
|
|
||||||
}
|
|
||||||
|
|
||||||
const SUPPORTED_CONTENT_TYPES = [
|
|
||||||
ContentTypes.applicationJson,
|
|
||||||
ContentTypes.applicationFormUrlEncoded,
|
|
||||||
ContentTypes.applicationMultipart,
|
|
||||||
];
|
|
||||||
|
|
||||||
const CONTENT_TYPE_KEY = 'content-type';
|
|
||||||
|
|
||||||
const FOLLOW_REDIRECT_FLAGS = ['--location', '-L'];
|
|
||||||
|
|
||||||
const MAX_REDIRECT_FLAG = '--max-redirs';
|
|
||||||
|
|
||||||
const PROXY_FLAGS = ['-x', '--proxy'];
|
|
||||||
|
|
||||||
const INCLUDE_HEADERS_IN_OUTPUT_FLAGS = ['-i', '--include'];
|
|
||||||
|
|
||||||
const REQUEST_FLAGS = ['-X', '--request'];
|
|
||||||
|
|
||||||
const TIMEOUT_FLAGS = ['--connect-timeout'];
|
|
||||||
|
|
||||||
const DOWNLOAD_FILE_FLAGS = ['-O', '-o'];
|
|
||||||
|
|
||||||
const IGNORE_SSL_ISSUES_FLAGS = ['-k', '--insecure'];
|
|
||||||
|
|
||||||
const isContentType = (headers: CurlJson['headers'], contentType: ContentTypes): boolean => {
|
|
||||||
return get(headers, CONTENT_TYPE_KEY) === contentType;
|
|
||||||
};
|
|
||||||
|
|
||||||
const isJsonRequest = (curlJson: CurlJson): boolean => {
|
|
||||||
if (isContentType(curlJson.headers, ContentTypes.applicationJson)) return true;
|
|
||||||
|
|
||||||
if (curlJson.data) {
|
|
||||||
const bodyKey = Object.keys(curlJson.data)[0];
|
|
||||||
try {
|
|
||||||
JSON.parse(bodyKey);
|
|
||||||
return true;
|
|
||||||
} catch {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
const isFormUrlEncodedRequest = (curlJson: CurlJson): boolean => {
|
|
||||||
if (isContentType(curlJson.headers, ContentTypes.applicationFormUrlEncoded)) return true;
|
|
||||||
if (curlJson.data && !curlJson.files) return true;
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
const isMultipartRequest = (curlJson: CurlJson): boolean => {
|
|
||||||
if (isContentType(curlJson.headers, ContentTypes.applicationMultipart)) return true;
|
|
||||||
|
|
||||||
// only multipart/form-data request include files
|
|
||||||
if (curlJson.files) return true;
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
const isBinaryRequest = (curlJson: CurlJson): boolean => {
|
|
||||||
if (curlJson?.headers?.[CONTENT_TYPE_KEY]) {
|
|
||||||
const contentType = curlJson?.headers?.[CONTENT_TYPE_KEY];
|
|
||||||
return ['image', 'video', 'audio'].some((d) => contentType.includes(d));
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
const sanitizeCurlCommand = (curlCommand: string) =>
|
|
||||||
curlCommand
|
|
||||||
.replace(/\r\n/g, ' ')
|
|
||||||
.replace(/\n/g, ' ')
|
|
||||||
.replace(/\\/g, ' ')
|
|
||||||
.replace(/[ ]{2,}/g, ' ');
|
|
||||||
|
|
||||||
const toKeyValueArray = ([key, value]: string[]) => ({ name: key, value });
|
|
||||||
|
|
||||||
const extractHeaders = (headers: CurlJson['headers'] = {}): HttpNodeHeaders => {
|
|
||||||
const emptyHeaders = !Object.keys(headers).length;
|
|
||||||
|
|
||||||
const onlyContentTypeHeaderDefined =
|
|
||||||
Object.keys(headers).length === 1 && headers[CONTENT_TYPE_KEY] !== undefined;
|
|
||||||
|
|
||||||
if (emptyHeaders || onlyContentTypeHeaderDefined) return { sendHeaders: false };
|
|
||||||
|
|
||||||
return {
|
|
||||||
sendHeaders: true,
|
|
||||||
headerParameters: {
|
|
||||||
parameters: Object.entries(headers)
|
|
||||||
.map(toKeyValueArray)
|
|
||||||
.filter((parameter) => parameter.name !== CONTENT_TYPE_KEY),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
const extractQueries = (queries: CurlJson['queries'] = {}): HttpNodeQueries => {
|
|
||||||
const emptyQueries = !Object.keys(queries).length;
|
|
||||||
|
|
||||||
if (emptyQueries) return { sendQuery: false };
|
|
||||||
|
|
||||||
return {
|
|
||||||
sendQuery: true,
|
|
||||||
queryParameters: {
|
|
||||||
parameters: Object.entries(queries).map(toKeyValueArray),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
const extractJson = (body: CurlJson['data']) =>
|
|
||||||
jsonParse<{ [key: string]: string }>(Object.keys(body as IDataObject)[0]);
|
|
||||||
|
|
||||||
const jsonBodyToNodeParameters = (body: CurlJson['data'] = {}): Parameter[] | [] => {
|
|
||||||
const data = extractJson(body);
|
|
||||||
return Object.entries(data).map(toKeyValueArray);
|
|
||||||
};
|
|
||||||
|
|
||||||
const multipartToNodeParameters = (
|
|
||||||
body: CurlJson['data'] = {},
|
|
||||||
files: CurlJson['files'] = {},
|
|
||||||
): Parameter[] | [] => {
|
|
||||||
return [
|
|
||||||
...Object.entries(body)
|
|
||||||
.map(toKeyValueArray)
|
|
||||||
.map((e) => ({ parameterType: 'formData', ...e })),
|
|
||||||
...Object.entries(files)
|
|
||||||
.map(toKeyValueArray)
|
|
||||||
.map((e) => ({ parameterType: 'formBinaryData', ...e })),
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
const keyValueBodyToNodeParameters = (body: CurlJson['data'] = {}): Parameter[] | [] => {
|
|
||||||
return Object.entries(body).map(toKeyValueArray);
|
|
||||||
};
|
|
||||||
|
|
||||||
const lowerCaseContentTypeKey = (obj: { [x: string]: string }): void => {
|
|
||||||
const regex = new RegExp(CONTENT_TYPE_KEY, 'gi');
|
|
||||||
|
|
||||||
const contentTypeKey = Object.keys(obj).find((key) => {
|
|
||||||
const group = Array.from(key.matchAll(regex));
|
|
||||||
if (group.length) return true;
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!contentTypeKey) return;
|
|
||||||
|
|
||||||
const value = obj[contentTypeKey];
|
|
||||||
delete obj[contentTypeKey];
|
|
||||||
obj[CONTENT_TYPE_KEY] = value;
|
|
||||||
};
|
|
||||||
|
|
||||||
const encodeBasicAuthentication = (username: string, password: string) =>
|
|
||||||
Buffer.from(`${username}:${password}`).toString('base64');
|
|
||||||
|
|
||||||
const jsonHasNestedObjects = (json: { [key: string]: string | number | object }) =>
|
|
||||||
Object.values(json).some((e) => typeof e === 'object');
|
|
||||||
|
|
||||||
const extractGroup = (curlCommand: string, regex: RegExp) => curlCommand.matchAll(regex);
|
|
||||||
|
|
||||||
const mapCookies = (cookies: CurlJson['cookies']): { cookie: string } | {} => {
|
|
||||||
if (!cookies) return {};
|
|
||||||
|
|
||||||
const cookiesValues = Object.entries(cookies).reduce(
|
|
||||||
(accumulator: string, entry: [string, string]) => {
|
|
||||||
accumulator += `${entry[0]}=${entry[1]};`;
|
|
||||||
return accumulator;
|
|
||||||
},
|
|
||||||
'',
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!cookiesValues) return {};
|
|
||||||
|
|
||||||
return {
|
|
||||||
cookie: cookiesValues,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export const flattenObject = (obj: { [x: string]: any }, prefix = '') =>
|
|
||||||
Object.keys(obj).reduce((acc, k) => {
|
|
||||||
const pre = prefix.length ? prefix + '.' : '';
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
||||||
if (typeof obj[k] === 'object') Object.assign(acc, flattenObject(obj[k], pre + k));
|
|
||||||
//@ts-ignore
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
||||||
else acc[pre + k] = obj[k];
|
|
||||||
return acc;
|
|
||||||
}, {});
|
|
||||||
|
|
||||||
@Service()
|
|
||||||
export class CurlService {
|
|
||||||
// eslint-disable-next-line complexity
|
|
||||||
toHttpNodeParameters(curlCommand: string): HttpNodeParameters {
|
|
||||||
const curlJson = jsonParse<CurlJson>(curlconverter.toJsonString(curlCommand));
|
|
||||||
|
|
||||||
if (!curlJson.headers) curlJson.headers = {};
|
|
||||||
|
|
||||||
lowerCaseContentTypeKey(curlJson.headers);
|
|
||||||
|
|
||||||
// set basic authentication
|
|
||||||
if (curlJson.auth) {
|
|
||||||
const { user, password: pass } = curlJson.auth;
|
|
||||||
Object.assign(curlJson.headers, {
|
|
||||||
authorization: `Basic ${encodeBasicAuthentication(user, pass)}`,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const httpNodeParameters: HttpNodeParameters = {
|
|
||||||
url: curlJson.url,
|
|
||||||
authentication: 'none',
|
|
||||||
method: curlJson.method.toUpperCase(),
|
|
||||||
...extractHeaders({ ...curlJson.headers, ...mapCookies(curlJson.cookies) }),
|
|
||||||
...extractQueries(curlJson.queries),
|
|
||||||
options: {
|
|
||||||
redirect: {
|
|
||||||
redirect: {},
|
|
||||||
},
|
|
||||||
response: {
|
|
||||||
response: {},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
//attempt to get the curl flags not supported by the library
|
|
||||||
const curl = sanitizeCurlCommand(curlCommand);
|
|
||||||
|
|
||||||
//check for follow redirect flags
|
|
||||||
if (FOLLOW_REDIRECT_FLAGS.some((flag) => curl.includes(` ${flag}`))) {
|
|
||||||
Object.assign(httpNodeParameters.options.redirect?.redirect, { followRedirects: true });
|
|
||||||
|
|
||||||
if (curl.includes(` ${MAX_REDIRECT_FLAG}`)) {
|
|
||||||
const extractedValue = Array.from(
|
|
||||||
extractGroup(curl, new RegExp(` ${MAX_REDIRECT_FLAG} (\\d+)`, 'g')),
|
|
||||||
);
|
|
||||||
if (extractedValue.length) {
|
|
||||||
const [_, maxRedirects] = extractedValue[0];
|
|
||||||
if (maxRedirects) {
|
|
||||||
Object.assign(httpNodeParameters.options.redirect?.redirect, { maxRedirects });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//check for proxy flags
|
|
||||||
if (PROXY_FLAGS.some((flag) => curl.includes(` ${flag}`))) {
|
|
||||||
const foundFlag = PROXY_FLAGS.find((flag) => curl.includes(` ${flag}`));
|
|
||||||
if (foundFlag) {
|
|
||||||
const extractedValue = Array.from(
|
|
||||||
extractGroup(curl, new RegExp(` ${foundFlag} (\\S*)`, 'g')),
|
|
||||||
);
|
|
||||||
if (extractedValue.length) {
|
|
||||||
const [_, proxy] = extractedValue[0];
|
|
||||||
Object.assign(httpNodeParameters.options, { proxy });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// check for "include header in output" flag
|
|
||||||
if (INCLUDE_HEADERS_IN_OUTPUT_FLAGS.some((flag) => curl.includes(` ${flag}`))) {
|
|
||||||
Object.assign(httpNodeParameters.options?.response?.response, {
|
|
||||||
fullResponse: true,
|
|
||||||
responseFormat: 'autodetect',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// check for request flag
|
|
||||||
if (REQUEST_FLAGS.some((flag) => curl.includes(` ${flag}`))) {
|
|
||||||
const foundFlag = REQUEST_FLAGS.find((flag) => curl.includes(` ${flag}`));
|
|
||||||
if (foundFlag) {
|
|
||||||
const extractedValue = Array.from(
|
|
||||||
extractGroup(curl, new RegExp(` ${foundFlag} (\\w+)`, 'g')),
|
|
||||||
);
|
|
||||||
if (extractedValue.length) {
|
|
||||||
const [_, request] = extractedValue[0];
|
|
||||||
httpNodeParameters.method = request.toUpperCase();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// check for timeout flag
|
|
||||||
if (TIMEOUT_FLAGS.some((flag) => curl.includes(` ${flag}`))) {
|
|
||||||
const foundFlag = TIMEOUT_FLAGS.find((flag) => curl.includes(` ${flag}`));
|
|
||||||
if (foundFlag) {
|
|
||||||
const extractedValue = Array.from(
|
|
||||||
extractGroup(curl, new RegExp(` ${foundFlag} (\\d+)`, 'g')),
|
|
||||||
);
|
|
||||||
if (extractedValue.length) {
|
|
||||||
const [_, timeout] = extractedValue[0];
|
|
||||||
Object.assign(httpNodeParameters.options, {
|
|
||||||
timeout: parseInt(timeout, 10) * 1000,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// check for download flag
|
|
||||||
if (DOWNLOAD_FILE_FLAGS.some((flag) => curl.includes(` ${flag}`))) {
|
|
||||||
const foundFlag = DOWNLOAD_FILE_FLAGS.find((flag) => curl.includes(` ${flag}`));
|
|
||||||
if (foundFlag) {
|
|
||||||
Object.assign(httpNodeParameters.options.response.response, {
|
|
||||||
responseFormat: 'file',
|
|
||||||
outputPropertyName: 'data',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IGNORE_SSL_ISSUES_FLAGS.some((flag) => curl.includes(` ${flag}`))) {
|
|
||||||
const foundFlag = IGNORE_SSL_ISSUES_FLAGS.find((flag) => curl.includes(` ${flag}`));
|
|
||||||
if (foundFlag) {
|
|
||||||
Object.assign(httpNodeParameters.options, {
|
|
||||||
allowUnauthorizedCerts: true,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const contentType = curlJson?.headers?.[CONTENT_TYPE_KEY] as ContentTypes;
|
|
||||||
|
|
||||||
if (isBinaryRequest(curlJson)) {
|
|
||||||
return Object.assign(httpNodeParameters, {
|
|
||||||
contentType: 'binaryData',
|
|
||||||
sendBody: true,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (contentType && !SUPPORTED_CONTENT_TYPES.includes(contentType)) {
|
|
||||||
return Object.assign(httpNodeParameters, {
|
|
||||||
sendBody: true,
|
|
||||||
contentType: 'raw',
|
|
||||||
rawContentType: contentType,
|
|
||||||
body: Object.keys(curlJson?.data ?? {})[0],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isJsonRequest(curlJson)) {
|
|
||||||
Object.assign(httpNodeParameters, {
|
|
||||||
contentType: 'json',
|
|
||||||
sendBody: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (curlJson.data) {
|
|
||||||
const json = extractJson(curlJson.data);
|
|
||||||
|
|
||||||
if (jsonHasNestedObjects(json)) {
|
|
||||||
// json body
|
|
||||||
Object.assign(httpNodeParameters, {
|
|
||||||
specifyBody: 'json',
|
|
||||||
jsonBody: JSON.stringify(json, null, 2),
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
// key-value body
|
|
||||||
Object.assign(httpNodeParameters, {
|
|
||||||
specifyBody: 'keypair',
|
|
||||||
bodyParameters: {
|
|
||||||
parameters: jsonBodyToNodeParameters(curlJson.data),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (isFormUrlEncodedRequest(curlJson)) {
|
|
||||||
Object.assign(httpNodeParameters, {
|
|
||||||
contentType: 'form-urlencoded',
|
|
||||||
sendBody: true,
|
|
||||||
specifyBody: 'keypair',
|
|
||||||
bodyParameters: {
|
|
||||||
parameters: keyValueBodyToNodeParameters(curlJson.data),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
} else if (isMultipartRequest(curlJson)) {
|
|
||||||
Object.assign(httpNodeParameters, {
|
|
||||||
contentType: 'multipart-form-data',
|
|
||||||
sendBody: true,
|
|
||||||
bodyParameters: {
|
|
||||||
parameters: multipartToNodeParameters(curlJson.data, curlJson.files),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
// could not figure the content type so do not set the body
|
|
||||||
Object.assign(httpNodeParameters, {
|
|
||||||
sendBody: false,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Object.keys(httpNodeParameters.options?.redirect.redirect).length) {
|
|
||||||
// @ts-ignore
|
|
||||||
delete httpNodeParameters.options.redirect;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Object.keys(httpNodeParameters.options.response.response).length) {
|
|
||||||
// @ts-ignore
|
|
||||||
delete httpNodeParameters.options.response;
|
|
||||||
}
|
|
||||||
|
|
||||||
return httpNodeParameters;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -56,6 +56,7 @@
|
||||||
"change-case": "^5.4.4",
|
"change-case": "^5.4.4",
|
||||||
"chart.js": "^4.4.0",
|
"chart.js": "^4.4.0",
|
||||||
"codemirror-lang-html-n8n": "^1.0.0",
|
"codemirror-lang-html-n8n": "^1.0.0",
|
||||||
|
"curlconverter": "^4.11.0",
|
||||||
"comlink": "^4.4.1",
|
"comlink": "^4.4.1",
|
||||||
"core-js": "^3.40.0",
|
"core-js": "^3.40.0",
|
||||||
"dateformat": "^3.0.3",
|
"dateformat": "^3.0.3",
|
||||||
|
@ -89,6 +90,7 @@
|
||||||
"vue-router": "catalog:frontend",
|
"vue-router": "catalog:frontend",
|
||||||
"vue-virtual-scroller": "2.0.0-beta.8",
|
"vue-virtual-scroller": "2.0.0-beta.8",
|
||||||
"vue3-touch-events": "^4.1.3",
|
"vue3-touch-events": "^4.1.3",
|
||||||
|
"web-tree-sitter": "0.24.3",
|
||||||
"vuedraggable": "4.1.0",
|
"vuedraggable": "4.1.0",
|
||||||
"xss": "catalog:"
|
"xss": "catalog:"
|
||||||
},
|
},
|
||||||
|
@ -115,6 +117,7 @@
|
||||||
"unplugin-icons": "^0.19.0",
|
"unplugin-icons": "^0.19.0",
|
||||||
"unplugin-vue-components": "^0.27.2",
|
"unplugin-vue-components": "^0.27.2",
|
||||||
"vite": "catalog:frontend",
|
"vite": "catalog:frontend",
|
||||||
|
"vite-plugin-static-copy": "2.2.0",
|
||||||
"vite-svg-loader": "5.1.0",
|
"vite-svg-loader": "5.1.0",
|
||||||
"vitest": "catalog:frontend",
|
"vitest": "catalog:frontend",
|
||||||
"vitest-mock-extended": "catalog:frontend",
|
"vitest-mock-extended": "catalog:frontend",
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
import type { CurlToJSONResponse, IRestApiContext } from '@/Interface';
|
|
||||||
import { makeRestApiRequest } from '@/utils/apiUtils';
|
|
||||||
|
|
||||||
export async function getCurlToJson(
|
|
||||||
context: IRestApiContext,
|
|
||||||
curlCommand: string,
|
|
||||||
): Promise<CurlToJSONResponse> {
|
|
||||||
return await makeRestApiRequest(context, 'POST', '/curl/to-json', { curlCommand });
|
|
||||||
}
|
|
|
@ -6,7 +6,6 @@ import { useUIStore } from '@/stores/ui.store';
|
||||||
import { createEventBus } from 'n8n-design-system/utils';
|
import { createEventBus } from 'n8n-design-system/utils';
|
||||||
import { useTelemetry } from '@/composables/useTelemetry';
|
import { useTelemetry } from '@/composables/useTelemetry';
|
||||||
import { useI18n } from '@/composables/useI18n';
|
import { useI18n } from '@/composables/useI18n';
|
||||||
import { useImportCurlCommand } from '@/composables/useImportCurlCommand';
|
|
||||||
|
|
||||||
const telemetry = useTelemetry();
|
const telemetry = useTelemetry();
|
||||||
const i18n = useI18n();
|
const i18n = useI18n();
|
||||||
|
@ -18,12 +17,6 @@ const modalBus = createEventBus();
|
||||||
|
|
||||||
const inputRef = ref<HTMLTextAreaElement | null>(null);
|
const inputRef = ref<HTMLTextAreaElement | null>(null);
|
||||||
|
|
||||||
const { importCurlCommand } = useImportCurlCommand({
|
|
||||||
onImportSuccess,
|
|
||||||
onImportFailure,
|
|
||||||
onAfterImport,
|
|
||||||
});
|
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
curlCommand.value = (uiStore.modalsById[IMPORT_CURL_MODAL_KEY].data?.curlCommand as string) ?? '';
|
curlCommand.value = (uiStore.modalsById[IMPORT_CURL_MODAL_KEY].data?.curlCommand as string) ?? '';
|
||||||
|
|
||||||
|
@ -71,7 +64,13 @@ function sendTelemetry(
|
||||||
}
|
}
|
||||||
|
|
||||||
async function onImport() {
|
async function onImport() {
|
||||||
await importCurlCommand(curlCommand);
|
const { useImportCurlCommand } = await import('@/composables/useImportCurlCommand');
|
||||||
|
const { importCurlCommand } = useImportCurlCommand({
|
||||||
|
onImportSuccess,
|
||||||
|
onImportFailure,
|
||||||
|
onAfterImport,
|
||||||
|
});
|
||||||
|
importCurlCommand(curlCommand);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
296
packages/editor-ui/src/composables/useImportCurlCommand.test.ts
Normal file
296
packages/editor-ui/src/composables/useImportCurlCommand.test.ts
Normal file
|
@ -0,0 +1,296 @@
|
||||||
|
import { toHttpNodeParameters } from '@/composables/useImportCurlCommand';
|
||||||
|
|
||||||
|
describe('useImportCurlCommand', () => {
|
||||||
|
describe('toHttpNodeParameters', () => {
|
||||||
|
test('Should parse form-urlencoded content type correctly', () => {
|
||||||
|
const curl =
|
||||||
|
'curl -X POST https://reqbin.com/echo/post/form -H "Content-Type: application/x-www-form-urlencoded" -d "param1=value1¶m2=value2"';
|
||||||
|
const parameters = toHttpNodeParameters(curl);
|
||||||
|
expect(parameters.url).toBe('https://reqbin.com/echo/post/form');
|
||||||
|
expect(parameters.sendBody).toBe(true);
|
||||||
|
expect(parameters.bodyParameters?.parameters[0].name).toBe('param1');
|
||||||
|
expect(parameters.bodyParameters?.parameters[0].value).toBe('value1');
|
||||||
|
expect(parameters.bodyParameters?.parameters[1].name).toBe('param2');
|
||||||
|
expect(parameters.bodyParameters?.parameters[1].value).toBe('value2');
|
||||||
|
expect(parameters.contentType).toBe('form-urlencoded');
|
||||||
|
expect(parameters.sendHeaders).toBe(false);
|
||||||
|
expect(parameters.sendQuery).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Should parse JSON content type correctly', () => {
|
||||||
|
const curl =
|
||||||
|
'curl -X POST https://reqbin.com/echo/post/json -H \'Content-Type: application/json\' -d \'{"login":"my_login","password":"my_password"}\'';
|
||||||
|
const parameters = toHttpNodeParameters(curl);
|
||||||
|
expect(parameters.url).toBe('https://reqbin.com/echo/post/json');
|
||||||
|
expect(parameters.sendBody).toBe(true);
|
||||||
|
expect(parameters.bodyParameters?.parameters[0].name).toBe('login');
|
||||||
|
expect(parameters.bodyParameters?.parameters[0].value).toBe('my_login');
|
||||||
|
expect(parameters.bodyParameters?.parameters[1].name).toBe('password');
|
||||||
|
expect(parameters.bodyParameters?.parameters[1].value).toBe('my_password');
|
||||||
|
expect(parameters.contentType).toBe('json');
|
||||||
|
expect(parameters.sendHeaders).toBe(false);
|
||||||
|
expect(parameters.sendQuery).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Should parse multipart-form-data content type correctly', () => {
|
||||||
|
const curl =
|
||||||
|
'curl -X POST https://reqbin.com/echo/post/json -v -F key1=value1 -F upload=@localfilename';
|
||||||
|
const parameters = toHttpNodeParameters(curl);
|
||||||
|
expect(parameters.url).toBe('https://reqbin.com/echo/post/json');
|
||||||
|
expect(parameters.sendBody).toBe(true);
|
||||||
|
expect(parameters.bodyParameters?.parameters[0].parameterType).toBe('formData');
|
||||||
|
expect(parameters.bodyParameters?.parameters[0].name).toBe('key1');
|
||||||
|
expect(parameters.bodyParameters?.parameters[0].value).toBe('value1');
|
||||||
|
expect(parameters.bodyParameters?.parameters[1].parameterType).toBe('formBinaryData');
|
||||||
|
expect(parameters.bodyParameters?.parameters[1].name).toBe('upload');
|
||||||
|
expect(parameters.contentType).toBe('multipart-form-data');
|
||||||
|
expect(parameters.sendHeaders).toBe(false);
|
||||||
|
expect(parameters.sendQuery).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Should parse binary request correctly', () => {
|
||||||
|
const curl =
|
||||||
|
"curl --location --request POST 'https://www.website.com' --header 'Content-Type: image/png' --data-binary '@/Users/image.png'";
|
||||||
|
const parameters = toHttpNodeParameters(curl);
|
||||||
|
expect(parameters.url).toBe('https://www.website.com');
|
||||||
|
expect(parameters.method).toBe('POST');
|
||||||
|
expect(parameters.sendBody).toBe(true);
|
||||||
|
expect(parameters.contentType).toBe('binaryData');
|
||||||
|
expect(parameters.sendHeaders).toBe(false);
|
||||||
|
expect(parameters.sendQuery).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Should parse unknown content type correctly', () => {
|
||||||
|
const curl =
|
||||||
|
'curl -X POST https://reqbin.com/echo/post/xml -H "Content-Type: application/xml" -H "Accept: application/xml" -d "<Request><Login>my_login</Login><Password>my_password</Password></Request>"';
|
||||||
|
const parameters = toHttpNodeParameters(curl);
|
||||||
|
expect(parameters.url).toBe('https://reqbin.com/echo/post/xml');
|
||||||
|
expect(parameters.method).toBe('POST');
|
||||||
|
expect(parameters.sendBody).toBe(true);
|
||||||
|
expect(parameters.contentType).toBe('raw');
|
||||||
|
expect(parameters.rawContentType).toBe('application/xml');
|
||||||
|
expect(parameters.sendHeaders).toBe(true);
|
||||||
|
expect(parameters.headerParameters?.parameters[0].name).toBe('Accept');
|
||||||
|
expect(parameters.headerParameters?.parameters[0].value).toBe('application/xml');
|
||||||
|
expect(parameters.sendQuery).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Should parse header properties and keep the original case', () => {
|
||||||
|
const curl =
|
||||||
|
'curl -X POST https://reqbin.com/echo/post/json -v -F key1=value1 -F upload=@localfilename -H "ACCEPT: text/javascript" -H "content-type: multipart/form-data"';
|
||||||
|
const parameters = toHttpNodeParameters(curl);
|
||||||
|
expect(parameters.url).toBe('https://reqbin.com/echo/post/json');
|
||||||
|
expect(parameters.sendBody).toBe(true);
|
||||||
|
expect(parameters.bodyParameters?.parameters[0].parameterType).toBe('formData');
|
||||||
|
expect(parameters.bodyParameters?.parameters[0].name).toBe('key1');
|
||||||
|
expect(parameters.bodyParameters?.parameters[0].value).toBe('value1');
|
||||||
|
expect(parameters.bodyParameters?.parameters[1].parameterType).toBe('formBinaryData');
|
||||||
|
expect(parameters.bodyParameters?.parameters[1].name).toBe('upload');
|
||||||
|
expect(parameters.contentType).toBe('multipart-form-data');
|
||||||
|
expect(parameters.sendHeaders).toBe(true);
|
||||||
|
expect(parameters.headerParameters?.parameters[0].name).toBe('ACCEPT');
|
||||||
|
expect(parameters.headerParameters?.parameters[0].value).toBe('text/javascript');
|
||||||
|
expect(parameters.sendQuery).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Should parse querystring properties', () => {
|
||||||
|
const curl = "curl -G -d 'q=kitties' -d 'count=20' https://google.com/search";
|
||||||
|
const parameters = toHttpNodeParameters(curl);
|
||||||
|
expect(parameters.url).toBe('https://google.com/search');
|
||||||
|
expect(parameters.sendBody).toBe(false);
|
||||||
|
expect(parameters.contentType).toBeUndefined();
|
||||||
|
expect(parameters.sendHeaders).toBe(false);
|
||||||
|
expect(parameters.sendQuery).toBe(true);
|
||||||
|
expect(parameters.queryParameters?.parameters[0].name).toBe('q');
|
||||||
|
expect(parameters.queryParameters?.parameters[0].value).toBe('kitties');
|
||||||
|
expect(parameters.queryParameters?.parameters[1].name).toBe('count');
|
||||||
|
expect(parameters.queryParameters?.parameters[1].value).toBe('20');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Should parse basic authentication property and keep the original case', () => {
|
||||||
|
const curl = 'curl https://reqbin.com/echo -u "login:password"';
|
||||||
|
const parameters = toHttpNodeParameters(curl);
|
||||||
|
expect(parameters.url).toBe('https://reqbin.com/echo');
|
||||||
|
expect(parameters.sendBody).toBe(false);
|
||||||
|
expect(parameters.contentType).toBeUndefined();
|
||||||
|
expect(parameters.sendQuery).toBe(false);
|
||||||
|
expect(parameters.sendHeaders).toBe(true);
|
||||||
|
expect(parameters.headerParameters?.parameters[0].name).toBe('authorization');
|
||||||
|
expect(parameters.headerParameters?.parameters[0].value).toBe(
|
||||||
|
`Basic ${Buffer.from('login:password').toString('base64')}`,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Should parse location flag with --location', () => {
|
||||||
|
const curl = 'curl https://reqbin.com/echo -u "login:password" --location';
|
||||||
|
const parameters = toHttpNodeParameters(curl);
|
||||||
|
expect(parameters.url).toBe('https://reqbin.com/echo');
|
||||||
|
expect(parameters.sendBody).toBe(false);
|
||||||
|
expect(parameters.contentType).toBeUndefined();
|
||||||
|
expect(parameters.sendQuery).toBe(false);
|
||||||
|
expect(parameters.sendHeaders).toBe(true);
|
||||||
|
expect(parameters.headerParameters?.parameters[0].name).toBe('authorization');
|
||||||
|
expect(parameters.headerParameters?.parameters[0].value).toBe(
|
||||||
|
`Basic ${Buffer.from('login:password').toString('base64')}`,
|
||||||
|
);
|
||||||
|
expect(parameters.options.redirect.redirect.followRedirects).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Should parse location flag with --L', () => {
|
||||||
|
const curl = 'curl https://reqbin.com/echo -u "login:password" -L';
|
||||||
|
const parameters = toHttpNodeParameters(curl);
|
||||||
|
expect(parameters.url).toBe('https://reqbin.com/echo');
|
||||||
|
expect(parameters.sendBody).toBe(false);
|
||||||
|
expect(parameters.contentType).toBeUndefined();
|
||||||
|
expect(parameters.sendQuery).toBe(false);
|
||||||
|
expect(parameters.sendHeaders).toBe(true);
|
||||||
|
expect(parameters.headerParameters?.parameters[0].name).toBe('authorization');
|
||||||
|
expect(parameters.headerParameters?.parameters[0].value).toBe(
|
||||||
|
`Basic ${Buffer.from('login:password').toString('base64')}`,
|
||||||
|
);
|
||||||
|
expect(parameters.options.redirect.redirect.followRedirects).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Should parse location and max redirects flags with --location and --max-redirs 10', () => {
|
||||||
|
const curl = 'curl https://reqbin.com/echo -u "login:password" --location --max-redirs 10';
|
||||||
|
const parameters = toHttpNodeParameters(curl);
|
||||||
|
expect(parameters.url).toBe('https://reqbin.com/echo');
|
||||||
|
expect(parameters.sendBody).toBe(false);
|
||||||
|
expect(parameters.contentType).toBeUndefined();
|
||||||
|
expect(parameters.sendQuery).toBe(false);
|
||||||
|
expect(parameters.sendHeaders).toBe(true);
|
||||||
|
expect(parameters.headerParameters?.parameters[0].name).toBe('authorization');
|
||||||
|
expect(parameters.headerParameters?.parameters[0].value).toBe(
|
||||||
|
`Basic ${Buffer.from('login:password').toString('base64')}`,
|
||||||
|
);
|
||||||
|
expect(parameters.options.redirect.redirect.followRedirects).toBe(true);
|
||||||
|
expect(parameters.options.redirect.redirect.maxRedirects).toBe(10);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Should parse proxy flag -x', () => {
|
||||||
|
const curl = 'curl https://reqbin.com/echo -u "login:password" -x https://google.com';
|
||||||
|
const parameters = toHttpNodeParameters(curl);
|
||||||
|
expect(parameters.url).toBe('https://reqbin.com/echo');
|
||||||
|
expect(parameters.sendBody).toBe(false);
|
||||||
|
expect(parameters.contentType).toBeUndefined();
|
||||||
|
expect(parameters.sendQuery).toBe(false);
|
||||||
|
expect(parameters.sendHeaders).toBe(true);
|
||||||
|
expect(parameters.headerParameters?.parameters[0].name).toBe('authorization');
|
||||||
|
expect(parameters.headerParameters?.parameters[0].value).toBe(
|
||||||
|
`Basic ${Buffer.from('login:password').toString('base64')}`,
|
||||||
|
);
|
||||||
|
expect(parameters.options.proxy).toBe('https://google.com');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Should parse proxy flag --proxy', () => {
|
||||||
|
const curl = 'curl https://reqbin.com/echo -u "login:password" -x https://google.com';
|
||||||
|
const parameters = toHttpNodeParameters(curl);
|
||||||
|
expect(parameters.url).toBe('https://reqbin.com/echo');
|
||||||
|
expect(parameters.sendBody).toBe(false);
|
||||||
|
expect(parameters.contentType).toBeUndefined();
|
||||||
|
expect(parameters.sendQuery).toBe(false);
|
||||||
|
expect(parameters.sendHeaders).toBe(true);
|
||||||
|
expect(parameters.headerParameters?.parameters[0].name).toBe('authorization');
|
||||||
|
expect(parameters.headerParameters?.parameters[0].value).toBe(
|
||||||
|
`Basic ${Buffer.from('login:password').toString('base64')}`,
|
||||||
|
);
|
||||||
|
expect(parameters.options.proxy).toBe('https://google.com');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Should parse include headers on output flag --include', () => {
|
||||||
|
const curl =
|
||||||
|
'curl https://reqbin.com/echo -u "login:password" --include -x https://google.com';
|
||||||
|
const parameters = toHttpNodeParameters(curl);
|
||||||
|
expect(parameters.url).toBe('https://reqbin.com/echo');
|
||||||
|
expect(parameters.sendBody).toBe(false);
|
||||||
|
expect(parameters.contentType).toBeUndefined();
|
||||||
|
expect(parameters.sendQuery).toBe(false);
|
||||||
|
expect(parameters.sendHeaders).toBe(true);
|
||||||
|
expect(parameters.headerParameters?.parameters[0].name).toBe('authorization');
|
||||||
|
expect(parameters.headerParameters?.parameters[0].value).toBe(
|
||||||
|
`Basic ${Buffer.from('login:password').toString('base64')}`,
|
||||||
|
);
|
||||||
|
expect(parameters.options.response.response.fullResponse).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Should parse include headers on output flag -i', () => {
|
||||||
|
const curl = 'curl https://reqbin.com/echo -u "login:password" -x https://google.com -i';
|
||||||
|
const parameters = toHttpNodeParameters(curl);
|
||||||
|
expect(parameters.url).toBe('https://reqbin.com/echo');
|
||||||
|
expect(parameters.sendBody).toBe(false);
|
||||||
|
expect(parameters.contentType).toBeUndefined();
|
||||||
|
expect(parameters.sendQuery).toBe(false);
|
||||||
|
expect(parameters.sendHeaders).toBe(true);
|
||||||
|
expect(parameters.headerParameters?.parameters[0].name).toBe('authorization');
|
||||||
|
expect(parameters.headerParameters?.parameters[0].value).toBe(
|
||||||
|
`Basic ${Buffer.from('login:password').toString('base64')}`,
|
||||||
|
);
|
||||||
|
expect(parameters.options.response.response.fullResponse).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Should parse include request flag -X', () => {
|
||||||
|
const curl = 'curl -X POST https://reqbin.com/echo -u "login:password" -x https://google.com';
|
||||||
|
const parameters = toHttpNodeParameters(curl);
|
||||||
|
expect(parameters.url).toBe('https://reqbin.com/echo');
|
||||||
|
expect(parameters.method).toBe('POST');
|
||||||
|
expect(parameters.sendBody).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Should parse include request flag --request', () => {
|
||||||
|
const curl =
|
||||||
|
'curl --request POST https://reqbin.com/echo -u "login:password" -x https://google.com';
|
||||||
|
const parameters = toHttpNodeParameters(curl);
|
||||||
|
expect(parameters.url).toBe('https://reqbin.com/echo');
|
||||||
|
expect(parameters.method).toBe('POST');
|
||||||
|
expect(parameters.sendBody).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Should parse include timeout flag --connect-timeout', () => {
|
||||||
|
const curl =
|
||||||
|
'curl --request POST https://reqbin.com/echo -u "login:password" --connect-timeout 20';
|
||||||
|
const parameters = toHttpNodeParameters(curl);
|
||||||
|
expect(parameters.url).toBe('https://reqbin.com/echo');
|
||||||
|
expect(parameters.method).toBe('POST');
|
||||||
|
expect(parameters.sendBody).toBe(false);
|
||||||
|
expect(parameters.options.timeout).toBe(20000);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Should parse download file flag --output', () => {
|
||||||
|
const curl = 'curl --request POST https://reqbin.com/echo -u "login:password" --output data';
|
||||||
|
const parameters = toHttpNodeParameters(curl);
|
||||||
|
expect(parameters.url).toBe('https://reqbin.com/echo');
|
||||||
|
expect(parameters.method).toBe('POST');
|
||||||
|
expect(parameters.sendBody).toBe(false);
|
||||||
|
expect(parameters.options.response.response.responseFormat).toBe('file');
|
||||||
|
expect(parameters.options.response.response.outputPropertyName).toBe('data');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Should parse download file flag -o', () => {
|
||||||
|
const curl = 'curl --request POST https://reqbin.com/echo -u "login:password" -o data';
|
||||||
|
const parameters = toHttpNodeParameters(curl);
|
||||||
|
expect(parameters.url).toBe('https://reqbin.com/echo');
|
||||||
|
expect(parameters.method).toBe('POST');
|
||||||
|
expect(parameters.sendBody).toBe(false);
|
||||||
|
expect(parameters.options.response.response.responseFormat).toBe('file');
|
||||||
|
expect(parameters.options.response.response.outputPropertyName).toBe('data');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Should parse ignore SSL flag -k', () => {
|
||||||
|
const curl = 'curl --request POST https://reqbin.com/echo -u "login:password" -k';
|
||||||
|
const parameters = toHttpNodeParameters(curl);
|
||||||
|
expect(parameters.url).toBe('https://reqbin.com/echo');
|
||||||
|
expect(parameters.method).toBe('POST');
|
||||||
|
expect(parameters.sendBody).toBe(false);
|
||||||
|
expect(parameters.options.allowUnauthorizedCerts).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Should parse ignore SSL flag --insecure', () => {
|
||||||
|
const curl = 'curl --request POST https://reqbin.com/echo -u "login:password" --insecure';
|
||||||
|
const parameters = toHttpNodeParameters(curl);
|
||||||
|
expect(parameters.url).toBe('https://reqbin.com/echo');
|
||||||
|
expect(parameters.method).toBe('POST');
|
||||||
|
expect(parameters.sendBody).toBe(false);
|
||||||
|
expect(parameters.options.allowUnauthorizedCerts).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -1,11 +1,362 @@
|
||||||
import type { MaybeRef } from 'vue';
|
import type { MaybeRef } from 'vue';
|
||||||
import { unref } from 'vue';
|
import { unref } from 'vue';
|
||||||
|
import get from 'lodash/get';
|
||||||
|
import { toJsonObject as curlToJson, type JSONOutput } from 'curlconverter';
|
||||||
|
|
||||||
import { CURL_IMPORT_NODES_PROTOCOLS, CURL_IMPORT_NOT_SUPPORTED_PROTOCOLS } from '@/constants';
|
import { CURL_IMPORT_NODES_PROTOCOLS, CURL_IMPORT_NOT_SUPPORTED_PROTOCOLS } from '@/constants';
|
||||||
import { useToast } from '@/composables/useToast';
|
import { useToast } from '@/composables/useToast';
|
||||||
import { useUIStore } from '@/stores/ui.store';
|
|
||||||
import { useI18n } from '@/composables/useI18n';
|
import { useI18n } from '@/composables/useI18n';
|
||||||
import { importCurlEventBus } from '@/event-bus';
|
import { importCurlEventBus } from '@/event-bus';
|
||||||
import type { BaseTextKey } from '@/plugins/i18n';
|
import type { BaseTextKey } from '@/plugins/i18n';
|
||||||
|
import { assert } from '@/utils/assert';
|
||||||
|
import type { CurlToJSONResponse } from '@/Interface';
|
||||||
|
|
||||||
|
interface Parameter {
|
||||||
|
parameterType?: string;
|
||||||
|
name: string;
|
||||||
|
value: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface HttpNodeParameters extends Record<string, unknown> {
|
||||||
|
url?: string;
|
||||||
|
method: string;
|
||||||
|
sendBody?: boolean;
|
||||||
|
authentication: string;
|
||||||
|
contentType?: 'form-urlencoded' | 'multipart-form-data' | 'json' | 'raw' | 'binaryData';
|
||||||
|
rawContentType?: string;
|
||||||
|
specifyBody?: 'json' | 'keypair';
|
||||||
|
bodyParameters?: {
|
||||||
|
parameters: Parameter[];
|
||||||
|
};
|
||||||
|
jsonBody?: object;
|
||||||
|
options: {
|
||||||
|
allowUnauthorizedCerts?: boolean;
|
||||||
|
proxy?: string;
|
||||||
|
timeout?: number;
|
||||||
|
redirect: {
|
||||||
|
redirect: {
|
||||||
|
followRedirects?: boolean;
|
||||||
|
maxRedirects?: number;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
response: {
|
||||||
|
response: {
|
||||||
|
fullResponse?: boolean;
|
||||||
|
responseFormat?: string;
|
||||||
|
outputPropertyName?: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
sendHeaders?: boolean;
|
||||||
|
headerParameters?: {
|
||||||
|
parameters: Parameter[];
|
||||||
|
};
|
||||||
|
sendQuery?: boolean;
|
||||||
|
queryParameters?: {
|
||||||
|
parameters: Parameter[];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
type HttpNodeHeaders = Pick<HttpNodeParameters, 'sendHeaders' | 'headerParameters'>;
|
||||||
|
|
||||||
|
type HttpNodeQueries = Pick<HttpNodeParameters, 'sendQuery' | 'queryParameters'>;
|
||||||
|
|
||||||
|
const SUPPORTED_CONTENT_TYPES = [
|
||||||
|
'application/json',
|
||||||
|
'application/x-www-form-urlencoded',
|
||||||
|
'multipart/form-data',
|
||||||
|
] as const;
|
||||||
|
type ContentTypes = (typeof SUPPORTED_CONTENT_TYPES)[number];
|
||||||
|
|
||||||
|
const CONTENT_TYPE_KEY = 'content-type';
|
||||||
|
|
||||||
|
const isContentType = (headers: JSONOutput['headers'], contentType: ContentTypes): boolean => {
|
||||||
|
return get(headers, CONTENT_TYPE_KEY) === contentType;
|
||||||
|
};
|
||||||
|
|
||||||
|
const isJsonRequest = (curlJson: JSONOutput): boolean => {
|
||||||
|
if (isContentType(curlJson.headers, 'application/json')) return true;
|
||||||
|
|
||||||
|
if (curlJson.data) {
|
||||||
|
const bodyKey = Object.keys(curlJson.data)[0];
|
||||||
|
try {
|
||||||
|
JSON.parse(bodyKey);
|
||||||
|
return true;
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
const isFormUrlEncodedRequest = (curlJson: JSONOutput): boolean => {
|
||||||
|
if (isContentType(curlJson.headers, 'application/x-www-form-urlencoded')) return true;
|
||||||
|
if (curlJson.data && !curlJson.files) return true;
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
const isMultipartRequest = (curlJson: JSONOutput): boolean => {
|
||||||
|
if (isContentType(curlJson.headers, 'multipart/form-data')) return true;
|
||||||
|
|
||||||
|
if (curlJson.files)
|
||||||
|
// only multipart/form-data request include files
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
const isBinaryRequest = (curlJson: JSONOutput): boolean => {
|
||||||
|
if (curlJson?.headers?.[CONTENT_TYPE_KEY]) {
|
||||||
|
const contentType = curlJson?.headers?.[CONTENT_TYPE_KEY];
|
||||||
|
return ['image', 'video', 'audio'].some((d) => contentType.includes(d));
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
const toKeyValueArray = ([key, value]: [string, unknown]) => ({
|
||||||
|
name: key,
|
||||||
|
value: value?.toString() ?? '',
|
||||||
|
});
|
||||||
|
|
||||||
|
const extractHeaders = (headers: JSONOutput['headers'] = {}): HttpNodeHeaders => {
|
||||||
|
const emptyHeaders = !Object.keys(headers).length;
|
||||||
|
|
||||||
|
const onlyContentTypeHeaderDefined =
|
||||||
|
Object.keys(headers).length === 1 && headers[CONTENT_TYPE_KEY] !== undefined;
|
||||||
|
|
||||||
|
if (emptyHeaders || onlyContentTypeHeaderDefined) return { sendHeaders: false };
|
||||||
|
|
||||||
|
return {
|
||||||
|
sendHeaders: true,
|
||||||
|
headerParameters: {
|
||||||
|
parameters: Object.entries(headers)
|
||||||
|
.map(toKeyValueArray)
|
||||||
|
.filter((parameter) => parameter.name !== CONTENT_TYPE_KEY),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const extractQueries = (queries: JSONOutput['queries'] = {}): HttpNodeQueries => {
|
||||||
|
const emptyQueries = !Object.keys(queries).length;
|
||||||
|
|
||||||
|
if (emptyQueries) return { sendQuery: false };
|
||||||
|
|
||||||
|
return {
|
||||||
|
sendQuery: true,
|
||||||
|
queryParameters: {
|
||||||
|
parameters: Object.entries(queries).map(toKeyValueArray),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const jsonBodyToNodeParameters = (body: JSONOutput['data'] = {}): Parameter[] | [] => {
|
||||||
|
return Object.entries(body).map(toKeyValueArray);
|
||||||
|
};
|
||||||
|
|
||||||
|
const multipartToNodeParameters = (
|
||||||
|
body: JSONOutput['data'] = {},
|
||||||
|
files: JSONOutput['files'] = {},
|
||||||
|
): Parameter[] | [] => {
|
||||||
|
return [
|
||||||
|
...Object.entries(body)
|
||||||
|
.map(toKeyValueArray)
|
||||||
|
.map((e) => ({ parameterType: 'formData', ...e })),
|
||||||
|
...Object.entries(files)
|
||||||
|
.map(toKeyValueArray)
|
||||||
|
.map((e) => ({ parameterType: 'formBinaryData', ...e })),
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
const keyValueBodyToNodeParameters = (body: JSONOutput['data'] = {}): Parameter[] | [] => {
|
||||||
|
return Object.entries(body).map(toKeyValueArray);
|
||||||
|
};
|
||||||
|
|
||||||
|
const lowerCaseContentTypeKey = (obj: JSONOutput['headers']): void => {
|
||||||
|
if (!obj) return;
|
||||||
|
|
||||||
|
const regex = new RegExp(CONTENT_TYPE_KEY, 'gi');
|
||||||
|
|
||||||
|
const contentTypeKey = Object.keys(obj).find((key) => !!Array.from(key.matchAll(regex)).length);
|
||||||
|
|
||||||
|
if (!contentTypeKey) return;
|
||||||
|
|
||||||
|
const value = obj[contentTypeKey];
|
||||||
|
delete obj[contentTypeKey];
|
||||||
|
obj[CONTENT_TYPE_KEY] = value;
|
||||||
|
};
|
||||||
|
|
||||||
|
const encodeBasicAuthentication = (username: string, password: string) =>
|
||||||
|
btoa(`${username}:${password}`);
|
||||||
|
const jsonHasNestedObjects = (json: { [key: string]: string | number | object }) =>
|
||||||
|
Object.values(json).some((e) => typeof e === 'object');
|
||||||
|
|
||||||
|
const mapCookies = (cookies: JSONOutput['cookies']): { cookie: string } | {} => {
|
||||||
|
if (!cookies) return {};
|
||||||
|
|
||||||
|
const cookiesValues = Object.entries(cookies).reduce(
|
||||||
|
(accumulator: string, entry: [string, string]) => {
|
||||||
|
accumulator += `${entry[0]}=${entry[1]};`;
|
||||||
|
return accumulator;
|
||||||
|
},
|
||||||
|
'',
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!cookiesValues) return {};
|
||||||
|
|
||||||
|
return {
|
||||||
|
cookie: cookiesValues,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const flattenObject = <T extends Record<string, unknown>>(obj: T, prefix = '') =>
|
||||||
|
Object.keys(obj).reduce(
|
||||||
|
(acc, k) => {
|
||||||
|
const pre = prefix.length ? prefix + '.' : '';
|
||||||
|
if (typeof obj[k] === 'object') Object.assign(acc, flattenObject(obj[k] as T, pre + k));
|
||||||
|
else acc[pre + k] = obj[k];
|
||||||
|
return acc;
|
||||||
|
},
|
||||||
|
{} as Record<string, unknown>,
|
||||||
|
);
|
||||||
|
|
||||||
|
export const toHttpNodeParameters = (curlCommand: string): HttpNodeParameters => {
|
||||||
|
const curlJson = curlToJson(curlCommand);
|
||||||
|
|
||||||
|
const headers = curlJson.headers ?? {};
|
||||||
|
|
||||||
|
lowerCaseContentTypeKey(headers);
|
||||||
|
|
||||||
|
// set basic authentication
|
||||||
|
if (curlJson.auth) {
|
||||||
|
const { user, password: pass } = curlJson.auth;
|
||||||
|
headers.authorization = `Basic ${encodeBasicAuthentication(user, pass)}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const httpNodeParameters: HttpNodeParameters = {
|
||||||
|
url: curlJson.url,
|
||||||
|
authentication: 'none',
|
||||||
|
method: curlJson.method.toUpperCase(),
|
||||||
|
...extractHeaders({ ...headers, ...mapCookies(curlJson.cookies) }),
|
||||||
|
...extractQueries(curlJson.queries),
|
||||||
|
options: {
|
||||||
|
redirect: {
|
||||||
|
redirect: {},
|
||||||
|
},
|
||||||
|
response: {
|
||||||
|
response: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
if (curlJson.follow_redirects) {
|
||||||
|
httpNodeParameters.options.redirect.redirect.followRedirects = true;
|
||||||
|
if (curlJson.max_redirects) {
|
||||||
|
httpNodeParameters.options.redirect.redirect.maxRedirects = curlJson.max_redirects;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (curlJson.proxy) {
|
||||||
|
httpNodeParameters.options.proxy = curlJson.proxy;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (curlJson.connect_timeout !== undefined) {
|
||||||
|
httpNodeParameters.options.timeout = Math.floor(curlJson.connect_timeout * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (curlJson.output) {
|
||||||
|
httpNodeParameters.options.response.response = {
|
||||||
|
responseFormat: 'file',
|
||||||
|
outputPropertyName: curlJson.output ?? 'data',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (curlJson.insecure !== undefined) {
|
||||||
|
httpNodeParameters.options.allowUnauthorizedCerts = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (curlJson.include) {
|
||||||
|
httpNodeParameters.options.response.response.fullResponse = true;
|
||||||
|
httpNodeParameters.options.response.response.responseFormat = 'autodetect';
|
||||||
|
}
|
||||||
|
|
||||||
|
const contentType = curlJson?.headers?.[CONTENT_TYPE_KEY] as ContentTypes;
|
||||||
|
|
||||||
|
if (isBinaryRequest(curlJson)) {
|
||||||
|
return Object.assign(httpNodeParameters, {
|
||||||
|
contentType: 'binaryData',
|
||||||
|
sendBody: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (contentType && !SUPPORTED_CONTENT_TYPES.includes(contentType)) {
|
||||||
|
return Object.assign(httpNodeParameters, {
|
||||||
|
sendBody: true,
|
||||||
|
contentType: 'raw',
|
||||||
|
rawContentType: contentType,
|
||||||
|
body: Object.keys(curlJson?.data ?? {})[0],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isJsonRequest(curlJson)) {
|
||||||
|
Object.assign(httpNodeParameters, {
|
||||||
|
contentType: 'json',
|
||||||
|
sendBody: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (curlJson.data) {
|
||||||
|
const json = curlJson.data;
|
||||||
|
|
||||||
|
if (jsonHasNestedObjects(json)) {
|
||||||
|
// json body
|
||||||
|
Object.assign(httpNodeParameters, {
|
||||||
|
specifyBody: 'json',
|
||||||
|
jsonBody: JSON.stringify(json, null, 2),
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// key-value body
|
||||||
|
Object.assign(httpNodeParameters, {
|
||||||
|
specifyBody: 'keypair',
|
||||||
|
bodyParameters: {
|
||||||
|
parameters: jsonBodyToNodeParameters(curlJson.data),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (isFormUrlEncodedRequest(curlJson)) {
|
||||||
|
Object.assign(httpNodeParameters, {
|
||||||
|
contentType: 'form-urlencoded',
|
||||||
|
sendBody: true,
|
||||||
|
specifyBody: 'keypair',
|
||||||
|
bodyParameters: {
|
||||||
|
parameters: keyValueBodyToNodeParameters(curlJson.data),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} else if (isMultipartRequest(curlJson)) {
|
||||||
|
Object.assign(httpNodeParameters, {
|
||||||
|
contentType: 'multipart-form-data',
|
||||||
|
sendBody: true,
|
||||||
|
bodyParameters: {
|
||||||
|
parameters: multipartToNodeParameters(curlJson.data, curlJson.files),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// could not figure the content type so do not set the body
|
||||||
|
Object.assign(httpNodeParameters, {
|
||||||
|
sendBody: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Object.keys(httpNodeParameters.options?.redirect.redirect).length) {
|
||||||
|
// @ts-ignore
|
||||||
|
delete httpNodeParameters.options.redirect;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Object.keys(httpNodeParameters.options.response.response).length) {
|
||||||
|
// @ts-ignore
|
||||||
|
delete httpNodeParameters.options.response;
|
||||||
|
}
|
||||||
|
|
||||||
|
return httpNodeParameters;
|
||||||
|
};
|
||||||
|
|
||||||
export function useImportCurlCommand(options?: {
|
export function useImportCurlCommand(options?: {
|
||||||
onImportSuccess?: () => void;
|
onImportSuccess?: () => void;
|
||||||
|
@ -18,7 +369,6 @@ export function useImportCurlCommand(options?: {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}) {
|
}) {
|
||||||
const uiStore = useUIStore();
|
|
||||||
const toast = useToast();
|
const toast = useToast();
|
||||||
const i18n = useI18n();
|
const i18n = useI18n();
|
||||||
|
|
||||||
|
@ -30,20 +380,28 @@ export function useImportCurlCommand(options?: {
|
||||||
...options?.i18n,
|
...options?.i18n,
|
||||||
};
|
};
|
||||||
|
|
||||||
async function importCurlCommand(curlCommandRef: MaybeRef<string>): Promise<void> {
|
function importCurlCommand(curlCommandRef: MaybeRef<string>): void {
|
||||||
const curlCommand = unref(curlCommandRef);
|
const curlCommand = unref(curlCommandRef);
|
||||||
if (curlCommand === '') return;
|
if (curlCommand === '') return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const parameters = await uiStore.getCurlToJson(curlCommand);
|
const parameters = flattenObject(toHttpNodeParameters(curlCommand), 'parameters');
|
||||||
const url = parameters['parameters.url'];
|
assert(typeof parameters['parameters.url'] === 'string', 'parameters.url has to be string');
|
||||||
|
// Normalize placeholder values
|
||||||
|
const url: string = parameters['parameters.url']
|
||||||
|
.replaceAll('%7B', '{')
|
||||||
|
.replaceAll('%7D', '}');
|
||||||
|
|
||||||
const invalidProtocol = CURL_IMPORT_NOT_SUPPORTED_PROTOCOLS.find((p) =>
|
const invalidProtocol = CURL_IMPORT_NOT_SUPPORTED_PROTOCOLS.find((p) =>
|
||||||
url.includes(`${p}://`),
|
url.includes(`${p}://`),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!invalidProtocol) {
|
if (!invalidProtocol) {
|
||||||
importCurlEventBus.emit('setHttpNodeParameters', parameters);
|
parameters['parameters.url'] = url;
|
||||||
|
importCurlEventBus.emit(
|
||||||
|
'setHttpNodeParameters',
|
||||||
|
parameters as unknown as CurlToJSONResponse,
|
||||||
|
);
|
||||||
|
|
||||||
options?.onImportSuccess?.();
|
options?.onImportSuccess?.();
|
||||||
|
|
||||||
|
|
|
@ -51,7 +51,6 @@ import type {
|
||||||
} from '@/Interface';
|
} from '@/Interface';
|
||||||
import { defineStore } from 'pinia';
|
import { defineStore } from 'pinia';
|
||||||
import { useRootStore } from '@/stores/root.store';
|
import { useRootStore } from '@/stores/root.store';
|
||||||
import * as curlParserApi from '@/api/curlHelper';
|
|
||||||
import { useWorkflowsStore } from '@/stores/workflows.store';
|
import { useWorkflowsStore } from '@/stores/workflows.store';
|
||||||
import { useSettingsStore } from '@/stores/settings.store';
|
import { useSettingsStore } from '@/stores/settings.store';
|
||||||
import { useUsersStore } from '@/stores/users.store';
|
import { useUsersStore } from '@/stores/users.store';
|
||||||
|
@ -524,19 +523,6 @@ export const useUIStore = defineStore(STORES.UI, () => {
|
||||||
sidebarMenuCollapsed.value = newCollapsedState;
|
sidebarMenuCollapsed.value = newCollapsedState;
|
||||||
};
|
};
|
||||||
|
|
||||||
const getCurlToJson = async (curlCommand: string) => {
|
|
||||||
const parameters = await curlParserApi.getCurlToJson(rootStore.restApiContext, curlCommand);
|
|
||||||
|
|
||||||
// Normalize placeholder values
|
|
||||||
if (parameters['parameters.url']) {
|
|
||||||
parameters['parameters.url'] = parameters['parameters.url']
|
|
||||||
.replaceAll('%7B', '{')
|
|
||||||
.replaceAll('%7D', '}');
|
|
||||||
}
|
|
||||||
|
|
||||||
return parameters;
|
|
||||||
};
|
|
||||||
|
|
||||||
const removeBannerFromStack = (name: BannerName) => {
|
const removeBannerFromStack = (name: BannerName) => {
|
||||||
bannerStack.value = bannerStack.value.filter((bannerName) => bannerName !== name);
|
bannerStack.value = bannerStack.value.filter((bannerName) => bannerName !== name);
|
||||||
};
|
};
|
||||||
|
@ -653,7 +639,6 @@ export const useUIStore = defineStore(STORES.UI, () => {
|
||||||
resetSelectedNodes,
|
resetSelectedNodes,
|
||||||
setCurlCommand,
|
setCurlCommand,
|
||||||
toggleSidebarMenuCollapse,
|
toggleSidebarMenuCollapse,
|
||||||
getCurlToJson,
|
|
||||||
removeBannerFromStack,
|
removeBannerFromStack,
|
||||||
dismissBanner,
|
dismissBanner,
|
||||||
updateBannersHeight,
|
updateBannersHeight,
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import vue from '@vitejs/plugin-vue';
|
import vue from '@vitejs/plugin-vue';
|
||||||
import { resolve } from 'path';
|
import { resolve } from 'path';
|
||||||
import { defineConfig, mergeConfig } from 'vite';
|
import { defineConfig, mergeConfig } from 'vite';
|
||||||
|
import { viteStaticCopy } from 'vite-plugin-static-copy';
|
||||||
import svgLoader from 'vite-svg-loader';
|
import svgLoader from 'vite-svg-loader';
|
||||||
|
|
||||||
import { vitestConfig } from '@n8n/frontend-vitest-config';
|
import { vitestConfig } from '@n8n/frontend-vitest-config';
|
||||||
|
@ -63,6 +64,12 @@ const plugins = [
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
|
viteStaticCopy({
|
||||||
|
targets: [
|
||||||
|
{ src: resolve('node_modules/web-tree-sitter/tree-sitter.wasm'), dest: '' },
|
||||||
|
{ src: resolve('node_modules/curlconverter/dist/tree-sitter-bash.wasm'), dest: '' },
|
||||||
|
],
|
||||||
|
}),
|
||||||
vue(),
|
vue(),
|
||||||
svgLoader(),
|
svgLoader(),
|
||||||
legacy({
|
legacy({
|
||||||
|
@ -73,6 +80,7 @@ const plugins = [
|
||||||
];
|
];
|
||||||
|
|
||||||
const { RELEASE: release } = process.env;
|
const { RELEASE: release } = process.env;
|
||||||
|
const target = browserslistToEsbuild(browsers);
|
||||||
|
|
||||||
export default mergeConfig(
|
export default mergeConfig(
|
||||||
defineConfig({
|
defineConfig({
|
||||||
|
@ -100,7 +108,12 @@ export default mergeConfig(
|
||||||
build: {
|
build: {
|
||||||
minify: !!release,
|
minify: !!release,
|
||||||
sourcemap: !!release,
|
sourcemap: !!release,
|
||||||
target: browserslistToEsbuild(browsers),
|
target,
|
||||||
|
},
|
||||||
|
optimizeDeps: {
|
||||||
|
esbuildOptions: {
|
||||||
|
target,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
worker: {
|
worker: {
|
||||||
format: 'es',
|
format: 'es',
|
||||||
|
|
1725
patches/curlconverter@4.11.0.patch
Normal file
1725
patches/curlconverter@4.11.0.patch
Normal file
File diff suppressed because one or more lines are too long
428
pnpm-lock.yaml
428
pnpm-lock.yaml
|
@ -151,6 +151,9 @@ patchedDependencies:
|
||||||
bull@4.12.1:
|
bull@4.12.1:
|
||||||
hash: ep6h4rqtpclldfcdohxlgcb3aq
|
hash: ep6h4rqtpclldfcdohxlgcb3aq
|
||||||
path: patches/bull@4.12.1.patch
|
path: patches/bull@4.12.1.patch
|
||||||
|
curlconverter@4.11.0:
|
||||||
|
hash: ymigioonidbyw7jydnlor7bohu
|
||||||
|
path: patches/curlconverter@4.11.0.patch
|
||||||
pkce-challenge@3.0.0:
|
pkce-challenge@3.0.0:
|
||||||
hash: dypouzb3lve7vncq25i5fuanki
|
hash: dypouzb3lve7vncq25i5fuanki
|
||||||
path: patches/pkce-challenge@3.0.0.patch
|
path: patches/pkce-challenge@3.0.0.patch
|
||||||
|
@ -868,9 +871,6 @@ importers:
|
||||||
csrf:
|
csrf:
|
||||||
specifier: 3.1.0
|
specifier: 3.1.0
|
||||||
version: 3.1.0
|
version: 3.1.0
|
||||||
curlconverter:
|
|
||||||
specifier: 3.21.0
|
|
||||||
version: 3.21.0(chokidar@4.0.1)
|
|
||||||
dotenv:
|
dotenv:
|
||||||
specifier: 8.6.0
|
specifier: 8.6.0
|
||||||
version: 8.6.0
|
version: 8.6.0
|
||||||
|
@ -1516,6 +1516,9 @@ importers:
|
||||||
core-js:
|
core-js:
|
||||||
specifier: ^3.40.0
|
specifier: ^3.40.0
|
||||||
version: 3.40.0
|
version: 3.40.0
|
||||||
|
curlconverter:
|
||||||
|
specifier: ^4.11.0
|
||||||
|
version: 4.11.0(patch_hash=ymigioonidbyw7jydnlor7bohu)
|
||||||
dateformat:
|
dateformat:
|
||||||
specifier: ^3.0.3
|
specifier: ^3.0.3
|
||||||
version: 3.0.3
|
version: 3.0.3
|
||||||
|
@ -1612,6 +1615,9 @@ importers:
|
||||||
vuedraggable:
|
vuedraggable:
|
||||||
specifier: 4.1.0
|
specifier: 4.1.0
|
||||||
version: 4.1.0(vue@3.5.13(typescript@5.7.2))
|
version: 4.1.0(vue@3.5.13(typescript@5.7.2))
|
||||||
|
web-tree-sitter:
|
||||||
|
specifier: 0.24.3
|
||||||
|
version: 0.24.3
|
||||||
xss:
|
xss:
|
||||||
specifier: 'catalog:'
|
specifier: 'catalog:'
|
||||||
version: 1.0.15
|
version: 1.0.15
|
||||||
|
@ -1682,6 +1688,9 @@ importers:
|
||||||
vite:
|
vite:
|
||||||
specifier: catalog:frontend
|
specifier: catalog:frontend
|
||||||
version: 6.0.2(@types/node@18.16.16)(jiti@1.21.0)(sass@1.64.1)(terser@5.16.1)
|
version: 6.0.2(@types/node@18.16.16)(jiti@1.21.0)(sass@1.64.1)(terser@5.16.1)
|
||||||
|
vite-plugin-static-copy:
|
||||||
|
specifier: 2.2.0
|
||||||
|
version: 2.2.0(vite@6.0.2(@types/node@18.16.16)(jiti@1.21.0)(sass@1.64.1)(terser@5.16.1))
|
||||||
vite-svg-loader:
|
vite-svg-loader:
|
||||||
specifier: 5.1.0
|
specifier: 5.1.0
|
||||||
version: 5.1.0(vue@3.5.13(typescript@5.7.2))
|
version: 5.1.0(vue@3.5.13(typescript@5.7.2))
|
||||||
|
@ -3304,14 +3313,6 @@ packages:
|
||||||
resolution: {integrity: sha512-/Z3l6pXthq0JvMYdUFyX9j0MaCltlIn6mfh9jLyQwg5aPKxkyNa0PTHtU1AlFXLNk55ZuAeJRcpvq+tmLfKmaQ==}
|
resolution: {integrity: sha512-/Z3l6pXthq0JvMYdUFyX9j0MaCltlIn6mfh9jLyQwg5aPKxkyNa0PTHtU1AlFXLNk55ZuAeJRcpvq+tmLfKmaQ==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
|
|
||||||
'@curlconverter/yargs-parser@0.0.1':
|
|
||||||
resolution: {integrity: sha512-DbEVRYqrorzwqc63MQ3RODflut1tNla8ZCKo1h83lF7+fbntgubZsDfRDBv5Lxj3vkKuvAolysNM2ekwJev8wA==}
|
|
||||||
engines: {node: '>=10'}
|
|
||||||
|
|
||||||
'@curlconverter/yargs@0.0.2':
|
|
||||||
resolution: {integrity: sha512-Q1YEebpCY61kxme4wvU0/IN/uMBfG5pZOKCo9FU+w20ElPvN+eH2qEVbK1C12t3Tee3qeYLLEU6HkiUeO1gc4A==}
|
|
||||||
engines: {node: '>=12'}
|
|
||||||
|
|
||||||
'@cypress/request@3.0.1':
|
'@cypress/request@3.0.1':
|
||||||
resolution: {integrity: sha512-TWivJlJi8ZDx2wGOw1dbLuHJKUYX7bWySw377nlnGOW3hP9/MUKIsEdXT/YngWxVdgNCHRBmFlBipE+5/2ZZlQ==}
|
resolution: {integrity: sha512-TWivJlJi8ZDx2wGOw1dbLuHJKUYX7bWySw377nlnGOW3hP9/MUKIsEdXT/YngWxVdgNCHRBmFlBipE+5/2ZZlQ==}
|
||||||
engines: {node: '>= 6'}
|
engines: {node: '>= 6'}
|
||||||
|
@ -6492,9 +6493,6 @@ packages:
|
||||||
engines: {node: '>=10.0.0'}
|
engines: {node: '>=10.0.0'}
|
||||||
deprecated: this version has critical issues, please update to the latest version
|
deprecated: this version has critical issues, please update to the latest version
|
||||||
|
|
||||||
a-sync-waterfall@1.0.1:
|
|
||||||
resolution: {integrity: sha512-RYTOHHdWipFUliRFMCS4X2Yn2X8M87V/OpSqWzKKOGhzqyUxzyVmhHDH9sAvG+ZuQf/TAOFsLCpMw09I1ufUnA==}
|
|
||||||
|
|
||||||
abab@2.0.6:
|
abab@2.0.6:
|
||||||
resolution: {integrity: sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==}
|
resolution: {integrity: sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==}
|
||||||
deprecated: Use your platform's native atob() and btoa() methods instead
|
deprecated: Use your platform's native atob() and btoa() methods instead
|
||||||
|
@ -6685,9 +6683,6 @@ packages:
|
||||||
aria-query@5.3.0:
|
aria-query@5.3.0:
|
||||||
resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==}
|
resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==}
|
||||||
|
|
||||||
array-buffer-byte-length@1.0.0:
|
|
||||||
resolution: {integrity: sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==}
|
|
||||||
|
|
||||||
array-buffer-byte-length@1.0.1:
|
array-buffer-byte-length@1.0.1:
|
||||||
resolution: {integrity: sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==}
|
resolution: {integrity: sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
@ -6728,10 +6723,6 @@ packages:
|
||||||
resolution: {integrity: sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==}
|
resolution: {integrity: sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
arraybuffer.prototype.slice@1.0.1:
|
|
||||||
resolution: {integrity: sha512-09x0ZWFEjj4WD8PDbykUwo3t9arLn8NIzmmYEJFpYekOAQjpkGSyrQhNoRTcwwcFRu+ycWF78QZ63oWTqSjBcw==}
|
|
||||||
engines: {node: '>= 0.4'}
|
|
||||||
|
|
||||||
arraybuffer.prototype.slice@1.0.3:
|
arraybuffer.prototype.slice@1.0.3:
|
||||||
resolution: {integrity: sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==}
|
resolution: {integrity: sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
@ -7358,10 +7349,6 @@ packages:
|
||||||
resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==}
|
resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==}
|
||||||
engines: {node: '>= 6'}
|
engines: {node: '>= 6'}
|
||||||
|
|
||||||
commander@5.1.0:
|
|
||||||
resolution: {integrity: sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==}
|
|
||||||
engines: {node: '>= 6'}
|
|
||||||
|
|
||||||
commander@6.2.1:
|
commander@6.2.1:
|
||||||
resolution: {integrity: sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==}
|
resolution: {integrity: sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==}
|
||||||
engines: {node: '>= 6'}
|
engines: {node: '>= 6'}
|
||||||
|
@ -7464,10 +7451,6 @@ packages:
|
||||||
cookie-signature@1.0.6:
|
cookie-signature@1.0.6:
|
||||||
resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==}
|
resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==}
|
||||||
|
|
||||||
cookie@0.4.2:
|
|
||||||
resolution: {integrity: sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==}
|
|
||||||
engines: {node: '>= 0.6'}
|
|
||||||
|
|
||||||
cookie@0.7.1:
|
cookie@0.7.1:
|
||||||
resolution: {integrity: sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==}
|
resolution: {integrity: sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==}
|
||||||
engines: {node: '>= 0.6'}
|
engines: {node: '>= 0.6'}
|
||||||
|
@ -7605,8 +7588,8 @@ packages:
|
||||||
csv-parse@5.5.0:
|
csv-parse@5.5.0:
|
||||||
resolution: {integrity: sha512-RxruSK3M4XgzcD7Trm2wEN+SJ26ChIb903+IWxNOcB5q4jT2Cs+hFr6QP39J05EohshRFEvyzEBoZ/466S2sbw==}
|
resolution: {integrity: sha512-RxruSK3M4XgzcD7Trm2wEN+SJ26ChIb903+IWxNOcB5q4jT2Cs+hFr6QP39J05EohshRFEvyzEBoZ/466S2sbw==}
|
||||||
|
|
||||||
curlconverter@3.21.0:
|
curlconverter@4.11.0:
|
||||||
resolution: {integrity: sha512-DXCnp1A/Xa69FujksUfdvWQFAnIn/C+4Wuv8t+UVdZkF/lY5bzj98GGKOGme7V/ckSHDLxE29Xp76sJ5Cpsp5A==}
|
resolution: {integrity: sha512-jBSvfDN10L6rGWVlkAYgtkIG8lYprDvtBgos7mafxtv15keYeQWsxUgnzns3JmqEcGJMeaGlDNdRUszURPCUaw==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
currency-codes@2.1.0:
|
currency-codes@2.1.0:
|
||||||
|
@ -7780,10 +7763,6 @@ packages:
|
||||||
decko@1.2.0:
|
decko@1.2.0:
|
||||||
resolution: {integrity: sha512-m8FnyHXV1QX+S1cl+KPFDIl6NMkxtKsy6+U/aYyjrOqWMuwAwYWu7ePqrsUHtDR5Y8Yk2pi/KIDSgF+vT4cPOQ==}
|
resolution: {integrity: sha512-m8FnyHXV1QX+S1cl+KPFDIl6NMkxtKsy6+U/aYyjrOqWMuwAwYWu7ePqrsUHtDR5Y8Yk2pi/KIDSgF+vT4cPOQ==}
|
||||||
|
|
||||||
decode-uri-component@0.2.2:
|
|
||||||
resolution: {integrity: sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==}
|
|
||||||
engines: {node: '>=0.10'}
|
|
||||||
|
|
||||||
decompress-response@6.0.0:
|
decompress-response@6.0.0:
|
||||||
resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==}
|
resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
|
@ -8106,10 +8085,6 @@ packages:
|
||||||
error-ex@1.3.2:
|
error-ex@1.3.2:
|
||||||
resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==}
|
resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==}
|
||||||
|
|
||||||
es-abstract@1.22.1:
|
|
||||||
resolution: {integrity: sha512-ioRRcXMO6OFyRpyzV3kE1IIBd4WG5/kltnzdxSCqoP8CMGs/Li+M1uF5o7lOkZVFjDs+NLesthnF66Pg/0q0Lw==}
|
|
||||||
engines: {node: '>= 0.4'}
|
|
||||||
|
|
||||||
es-abstract@1.22.5:
|
es-abstract@1.22.5:
|
||||||
resolution: {integrity: sha512-oW69R+4q2wG+Hc3KZePPZxOiisRIqfKBVo/HLx94QcJeWGU/8sZhCvc829rd1kS366vlJbzBfXf9yWwf0+Ko7w==}
|
resolution: {integrity: sha512-oW69R+4q2wG+Hc3KZePPZxOiisRIqfKBVo/HLx94QcJeWGU/8sZhCvc829rd1kS366vlJbzBfXf9yWwf0+Ko7w==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
@ -8143,10 +8118,6 @@ packages:
|
||||||
resolution: {integrity: sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==}
|
resolution: {integrity: sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
es-set-tostringtag@2.0.1:
|
|
||||||
resolution: {integrity: sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==}
|
|
||||||
engines: {node: '>= 0.4'}
|
|
||||||
|
|
||||||
es-set-tostringtag@2.0.3:
|
es-set-tostringtag@2.0.3:
|
||||||
resolution: {integrity: sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==}
|
resolution: {integrity: sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
@ -8595,10 +8566,6 @@ packages:
|
||||||
resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
|
resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
filter-obj@1.1.0:
|
|
||||||
resolution: {integrity: sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ==}
|
|
||||||
engines: {node: '>=0.10.0'}
|
|
||||||
|
|
||||||
finalhandler@1.3.1:
|
finalhandler@1.3.1:
|
||||||
resolution: {integrity: sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==}
|
resolution: {integrity: sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==}
|
||||||
engines: {node: '>= 0.8'}
|
engines: {node: '>= 0.8'}
|
||||||
|
@ -8707,6 +8674,10 @@ packages:
|
||||||
fs-constants@1.0.0:
|
fs-constants@1.0.0:
|
||||||
resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==}
|
resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==}
|
||||||
|
|
||||||
|
fs-extra@11.3.0:
|
||||||
|
resolution: {integrity: sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew==}
|
||||||
|
engines: {node: '>=14.14'}
|
||||||
|
|
||||||
fs-extra@7.0.1:
|
fs-extra@7.0.1:
|
||||||
resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==}
|
resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==}
|
||||||
engines: {node: '>=6 <7 || >=8'}
|
engines: {node: '>=6 <7 || >=8'}
|
||||||
|
@ -8735,10 +8706,6 @@ packages:
|
||||||
function-bind@1.1.2:
|
function-bind@1.1.2:
|
||||||
resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
|
resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
|
||||||
|
|
||||||
function.prototype.name@1.1.5:
|
|
||||||
resolution: {integrity: sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==}
|
|
||||||
engines: {node: '>= 0.4'}
|
|
||||||
|
|
||||||
function.prototype.name@1.1.6:
|
function.prototype.name@1.1.6:
|
||||||
resolution: {integrity: sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==}
|
resolution: {integrity: sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
@ -8809,10 +8776,6 @@ packages:
|
||||||
resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==}
|
resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
|
|
||||||
get-symbol-description@1.0.0:
|
|
||||||
resolution: {integrity: sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==}
|
|
||||||
engines: {node: '>= 0.4'}
|
|
||||||
|
|
||||||
get-symbol-description@1.0.2:
|
get-symbol-description@1.0.2:
|
||||||
resolution: {integrity: sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==}
|
resolution: {integrity: sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
@ -9197,10 +9160,6 @@ packages:
|
||||||
resolution: {integrity: sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==}
|
resolution: {integrity: sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==}
|
||||||
engines: {node: '>=8.0.0'}
|
engines: {node: '>=8.0.0'}
|
||||||
|
|
||||||
internal-slot@1.0.5:
|
|
||||||
resolution: {integrity: sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==}
|
|
||||||
engines: {node: '>= 0.4'}
|
|
||||||
|
|
||||||
internal-slot@1.0.7:
|
internal-slot@1.0.7:
|
||||||
resolution: {integrity: sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==}
|
resolution: {integrity: sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
@ -9232,9 +9191,6 @@ packages:
|
||||||
resolution: {integrity: sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==}
|
resolution: {integrity: sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
is-array-buffer@3.0.2:
|
|
||||||
resolution: {integrity: sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==}
|
|
||||||
|
|
||||||
is-array-buffer@3.0.4:
|
is-array-buffer@3.0.4:
|
||||||
resolution: {integrity: sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==}
|
resolution: {integrity: sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
@ -9323,10 +9279,6 @@ packages:
|
||||||
resolution: {integrity: sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==}
|
resolution: {integrity: sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
is-negative-zero@2.0.2:
|
|
||||||
resolution: {integrity: sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==}
|
|
||||||
engines: {node: '>= 0.4'}
|
|
||||||
|
|
||||||
is-negative-zero@2.0.3:
|
is-negative-zero@2.0.3:
|
||||||
resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==}
|
resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
@ -9370,9 +9322,6 @@ packages:
|
||||||
is-set@2.0.2:
|
is-set@2.0.2:
|
||||||
resolution: {integrity: sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==}
|
resolution: {integrity: sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==}
|
||||||
|
|
||||||
is-shared-array-buffer@1.0.2:
|
|
||||||
resolution: {integrity: sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==}
|
|
||||||
|
|
||||||
is-shared-array-buffer@1.0.3:
|
is-shared-array-buffer@1.0.3:
|
||||||
resolution: {integrity: sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==}
|
resolution: {integrity: sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
@ -10153,6 +10102,9 @@ packages:
|
||||||
lossless-json@1.0.5:
|
lossless-json@1.0.5:
|
||||||
resolution: {integrity: sha512-RicKUuLwZVNZ6ZdJHgIZnSeA05p8qWc5NW0uR96mpPIjN9WDLUg9+kj1esQU1GkPn9iLZVKatSQK5gyiaFHgJA==}
|
resolution: {integrity: sha512-RicKUuLwZVNZ6ZdJHgIZnSeA05p8qWc5NW0uR96mpPIjN9WDLUg9+kj1esQU1GkPn9iLZVKatSQK5gyiaFHgJA==}
|
||||||
|
|
||||||
|
lossless-json@4.0.2:
|
||||||
|
resolution: {integrity: sha512-+z0EaLi2UcWi8MZRxA5iTb6m4Ys4E80uftGY+yG5KNFJb5EceQXOhdW/pWJZ8m97s26u7yZZAYMcKWNztSZssA==}
|
||||||
|
|
||||||
loupe@3.1.2:
|
loupe@3.1.2:
|
||||||
resolution: {integrity: sha512-23I4pFZHmAemUnz8WZXbYRSKYj801VDaNv9ETuMh7IrMc7VuVVSo+Z9iLE3ni30+U48iDWfi30d3twAXBYmnCg==}
|
resolution: {integrity: sha512-23I4pFZHmAemUnz8WZXbYRSKYj801VDaNv9ETuMh7IrMc7VuVVSo+Z9iLE3ni30+U48iDWfi30d3twAXBYmnCg==}
|
||||||
|
|
||||||
|
@ -10741,6 +10693,10 @@ packages:
|
||||||
resolution: {integrity: sha512-mNcltoe1R8o7STTegSOHdnJNN7s5EUvhoS7ShnTHDyOSd+8H+UdWODq6qSv67PjC8Zc5JRT8+oLAMCr0SIXw7g==}
|
resolution: {integrity: sha512-mNcltoe1R8o7STTegSOHdnJNN7s5EUvhoS7ShnTHDyOSd+8H+UdWODq6qSv67PjC8Zc5JRT8+oLAMCr0SIXw7g==}
|
||||||
engines: {node: ^16 || ^18 || >= 20}
|
engines: {node: ^16 || ^18 || >= 20}
|
||||||
|
|
||||||
|
node-addon-api@8.3.0:
|
||||||
|
resolution: {integrity: sha512-8VOpLHFrOQlAH+qA0ZzuGRlALRA6/LVh8QJldbrC4DY0hXoMP0l4Acq8TzFC018HztWiRqyCEj2aTWY2UvnJUg==}
|
||||||
|
engines: {node: ^18 || ^20 || >= 21}
|
||||||
|
|
||||||
node-cleanup@2.1.2:
|
node-cleanup@2.1.2:
|
||||||
resolution: {integrity: sha512-qN8v/s2PAJwGUtr1/hYTpNKlD6Y9rc4p8KSmJXyGdYGZsDGKXrGThikLFP9OCHFeLeEpQzPwiAtdIvBLqm//Hw==}
|
resolution: {integrity: sha512-qN8v/s2PAJwGUtr1/hYTpNKlD6Y9rc4p8KSmJXyGdYGZsDGKXrGThikLFP9OCHFeLeEpQzPwiAtdIvBLqm//Hw==}
|
||||||
|
|
||||||
|
@ -10781,6 +10737,10 @@ packages:
|
||||||
resolution: {integrity: sha512-YlCCc6Wffkx0kHkmam79GKvDQ6x+QZkMjFGrIMxgFNILFvGSbCp2fCBC55pGTT9gVaz8Na5CLmxt/urtzRv36w==}
|
resolution: {integrity: sha512-YlCCc6Wffkx0kHkmam79GKvDQ6x+QZkMjFGrIMxgFNILFvGSbCp2fCBC55pGTT9gVaz8Na5CLmxt/urtzRv36w==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
node-gyp-build@4.8.4:
|
||||||
|
resolution: {integrity: sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
node-gyp@8.4.1:
|
node-gyp@8.4.1:
|
||||||
resolution: {integrity: sha512-olTJRgUtAb/hOXG0E93wZDs5YiJlgbXxTwQAFHyNlRsXQnYzUaF2aGgujZbw+hR8aF4ZG/rST57bWMWD16jr9w==}
|
resolution: {integrity: sha512-olTJRgUtAb/hOXG0E93wZDs5YiJlgbXxTwQAFHyNlRsXQnYzUaF2aGgujZbw+hR8aF4ZG/rST57bWMWD16jr9w==}
|
||||||
engines: {node: '>= 10.12.0'}
|
engines: {node: '>= 10.12.0'}
|
||||||
|
@ -10879,16 +10839,6 @@ packages:
|
||||||
number-allocator@1.0.14:
|
number-allocator@1.0.14:
|
||||||
resolution: {integrity: sha512-OrL44UTVAvkKdOdRQZIJpLkAdjXGTRda052sN4sO77bKEzYYqWKMBjQvrJFzqygI99gL6Z4u2xctPW1tB8ErvA==}
|
resolution: {integrity: sha512-OrL44UTVAvkKdOdRQZIJpLkAdjXGTRda052sN4sO77bKEzYYqWKMBjQvrJFzqygI99gL6Z4u2xctPW1tB8ErvA==}
|
||||||
|
|
||||||
nunjucks@3.2.4:
|
|
||||||
resolution: {integrity: sha512-26XRV6BhkgK0VOxfbU5cQI+ICFUtMLixv1noZn1tGU38kQH5A5nmmbk/O45xdyBhD1esk47nKrY0mvQpZIhRjQ==}
|
|
||||||
engines: {node: '>= 6.9.0'}
|
|
||||||
hasBin: true
|
|
||||||
peerDependencies:
|
|
||||||
chokidar: ^4.0.1
|
|
||||||
peerDependenciesMeta:
|
|
||||||
chokidar:
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
nwsapi@2.2.7:
|
nwsapi@2.2.7:
|
||||||
resolution: {integrity: sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ==}
|
resolution: {integrity: sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ==}
|
||||||
|
|
||||||
|
@ -11650,10 +11600,6 @@ packages:
|
||||||
resolution: {integrity: sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==}
|
resolution: {integrity: sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==}
|
||||||
engines: {node: '>=0.6'}
|
engines: {node: '>=0.6'}
|
||||||
|
|
||||||
query-string@7.1.3:
|
|
||||||
resolution: {integrity: sha512-hh2WYhq4fi8+b+/2Kg9CEge4fDPvHS534aOOvOZeQ3+Vf2mCFsaFBYj0i+iXcAq6I9Vzp5fjMFBlONvayDC1qg==}
|
|
||||||
engines: {node: '>=6'}
|
|
||||||
|
|
||||||
querystringify@2.2.0:
|
querystringify@2.2.0:
|
||||||
resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==}
|
resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==}
|
||||||
|
|
||||||
|
@ -11846,10 +11792,6 @@ packages:
|
||||||
resolution: {integrity: sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA==}
|
resolution: {integrity: sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
regexp.prototype.flags@1.5.0:
|
|
||||||
resolution: {integrity: sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==}
|
|
||||||
engines: {node: '>= 0.4'}
|
|
||||||
|
|
||||||
regexp.prototype.flags@1.5.2:
|
regexp.prototype.flags@1.5.2:
|
||||||
resolution: {integrity: sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==}
|
resolution: {integrity: sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
@ -12030,10 +11972,6 @@ packages:
|
||||||
rxjs@7.8.1:
|
rxjs@7.8.1:
|
||||||
resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==}
|
resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==}
|
||||||
|
|
||||||
safe-array-concat@1.0.0:
|
|
||||||
resolution: {integrity: sha512-9dVEFruWIsnie89yym+xWTAYASdpw3CJV7Li/6zBewGf9z2i1j31rP6jnY0pHEO4QZh6N0K11bFjWmdR8UGdPQ==}
|
|
||||||
engines: {node: '>=0.4'}
|
|
||||||
|
|
||||||
safe-array-concat@1.1.2:
|
safe-array-concat@1.1.2:
|
||||||
resolution: {integrity: sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==}
|
resolution: {integrity: sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==}
|
||||||
engines: {node: '>=0.4'}
|
engines: {node: '>=0.4'}
|
||||||
|
@ -12044,9 +11982,6 @@ packages:
|
||||||
safe-buffer@5.2.1:
|
safe-buffer@5.2.1:
|
||||||
resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
|
resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
|
||||||
|
|
||||||
safe-regex-test@1.0.0:
|
|
||||||
resolution: {integrity: sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==}
|
|
||||||
|
|
||||||
safe-regex-test@1.0.3:
|
safe-regex-test@1.0.3:
|
||||||
resolution: {integrity: sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==}
|
resolution: {integrity: sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
@ -12315,10 +12250,6 @@ packages:
|
||||||
resolution: {integrity: sha512-VNiXjFp6R4ldPbVRYbpxlD35yRHceecVXlct1J4/X80KuuPnW2AXMq3sGwhnJOhKkUsOxAT6nRGfGE5pocVw5w==}
|
resolution: {integrity: sha512-VNiXjFp6R4ldPbVRYbpxlD35yRHceecVXlct1J4/X80KuuPnW2AXMq3sGwhnJOhKkUsOxAT6nRGfGE5pocVw5w==}
|
||||||
engines: {node: '>=10.0.0'}
|
engines: {node: '>=10.0.0'}
|
||||||
|
|
||||||
split-on-first@1.1.0:
|
|
||||||
resolution: {integrity: sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==}
|
|
||||||
engines: {node: '>=6'}
|
|
||||||
|
|
||||||
split2@4.2.0:
|
split2@4.2.0:
|
||||||
resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==}
|
resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==}
|
||||||
engines: {node: '>= 10.x'}
|
engines: {node: '>= 10.x'}
|
||||||
|
@ -12432,10 +12363,6 @@ packages:
|
||||||
strict-event-emitter@0.5.1:
|
strict-event-emitter@0.5.1:
|
||||||
resolution: {integrity: sha512-vMgjE/GGEPEFnhFub6pa4FmJBRBVOLpIII2hvCZ8Kzb7K0hlHo7mQv6xYrBvCL2LtAIBwFUK8wvuJgTVSQ5MFQ==}
|
resolution: {integrity: sha512-vMgjE/GGEPEFnhFub6pa4FmJBRBVOLpIII2hvCZ8Kzb7K0hlHo7mQv6xYrBvCL2LtAIBwFUK8wvuJgTVSQ5MFQ==}
|
||||||
|
|
||||||
strict-uri-encode@2.0.0:
|
|
||||||
resolution: {integrity: sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==}
|
|
||||||
engines: {node: '>=4'}
|
|
||||||
|
|
||||||
string-argv@0.3.1:
|
string-argv@0.3.1:
|
||||||
resolution: {integrity: sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg==}
|
resolution: {integrity: sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg==}
|
||||||
engines: {node: '>=0.6.19'}
|
engines: {node: '>=0.6.19'}
|
||||||
|
@ -12452,13 +12379,6 @@ packages:
|
||||||
resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==}
|
resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
|
|
||||||
string.prototype.startswith@1.0.0:
|
|
||||||
resolution: {integrity: sha512-VHhsDkuf8gsw4JNRK9cIZjYe6r7PsVUutVohaBhqYAoPaRADoQH+mMgUg7Cs/TgQeDGEvI+PzPEMOdvdsCMvpg==}
|
|
||||||
|
|
||||||
string.prototype.trim@1.2.7:
|
|
||||||
resolution: {integrity: sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==}
|
|
||||||
engines: {node: '>= 0.4'}
|
|
||||||
|
|
||||||
string.prototype.trim@1.2.8:
|
string.prototype.trim@1.2.8:
|
||||||
resolution: {integrity: sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==}
|
resolution: {integrity: sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
@ -12467,18 +12387,12 @@ packages:
|
||||||
resolution: {integrity: sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==}
|
resolution: {integrity: sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
string.prototype.trimend@1.0.6:
|
|
||||||
resolution: {integrity: sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==}
|
|
||||||
|
|
||||||
string.prototype.trimend@1.0.7:
|
string.prototype.trimend@1.0.7:
|
||||||
resolution: {integrity: sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==}
|
resolution: {integrity: sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==}
|
||||||
|
|
||||||
string.prototype.trimend@1.0.8:
|
string.prototype.trimend@1.0.8:
|
||||||
resolution: {integrity: sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==}
|
resolution: {integrity: sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==}
|
||||||
|
|
||||||
string.prototype.trimstart@1.0.6:
|
|
||||||
resolution: {integrity: sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==}
|
|
||||||
|
|
||||||
string.prototype.trimstart@1.0.7:
|
string.prototype.trimstart@1.0.7:
|
||||||
resolution: {integrity: sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==}
|
resolution: {integrity: sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==}
|
||||||
|
|
||||||
|
@ -12794,6 +12708,17 @@ packages:
|
||||||
resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==}
|
resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
tree-sitter-bash@0.23.3:
|
||||||
|
resolution: {integrity: sha512-36cg/GQ2YmIbeiBeqeuh4fBJ6i4kgVouDaqTxqih5ysPag+zHufyIaxMOFeM8CeplwAK/Luj1o5XHqgdAfoCZg==}
|
||||||
|
peerDependencies:
|
||||||
|
tree-sitter: ^0.21.1
|
||||||
|
peerDependenciesMeta:
|
||||||
|
tree-sitter:
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
tree-sitter@0.21.1:
|
||||||
|
resolution: {integrity: sha512-7dxoA6kYvtgWw80265MyqJlkRl4yawIjO7S5MigytjELkX43fV2WsAXzsNfO7sBpPPCF5Gp0+XzHk0DwLCq3xQ==}
|
||||||
|
|
||||||
triple-beam@1.3.0:
|
triple-beam@1.3.0:
|
||||||
resolution: {integrity: sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==}
|
resolution: {integrity: sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==}
|
||||||
|
|
||||||
|
@ -13014,33 +12939,18 @@ packages:
|
||||||
resolution: {integrity: sha512-SOnx8xygcAh8lvDU2exnK2bomASfNjzB3Qz71s2tw9QnX8fkAo7aC+D0H7FV0HjRKj94CKV2Hi71kVkkO6nOxg==}
|
resolution: {integrity: sha512-SOnx8xygcAh8lvDU2exnK2bomASfNjzB3Qz71s2tw9QnX8fkAo7aC+D0H7FV0HjRKj94CKV2Hi71kVkkO6nOxg==}
|
||||||
engines: {node: '>=0.10.5'}
|
engines: {node: '>=0.10.5'}
|
||||||
|
|
||||||
typed-array-buffer@1.0.0:
|
|
||||||
resolution: {integrity: sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==}
|
|
||||||
engines: {node: '>= 0.4'}
|
|
||||||
|
|
||||||
typed-array-buffer@1.0.2:
|
typed-array-buffer@1.0.2:
|
||||||
resolution: {integrity: sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==}
|
resolution: {integrity: sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
typed-array-byte-length@1.0.0:
|
|
||||||
resolution: {integrity: sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==}
|
|
||||||
engines: {node: '>= 0.4'}
|
|
||||||
|
|
||||||
typed-array-byte-length@1.0.1:
|
typed-array-byte-length@1.0.1:
|
||||||
resolution: {integrity: sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==}
|
resolution: {integrity: sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
typed-array-byte-offset@1.0.0:
|
|
||||||
resolution: {integrity: sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==}
|
|
||||||
engines: {node: '>= 0.4'}
|
|
||||||
|
|
||||||
typed-array-byte-offset@1.0.2:
|
typed-array-byte-offset@1.0.2:
|
||||||
resolution: {integrity: sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==}
|
resolution: {integrity: sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
typed-array-length@1.0.4:
|
|
||||||
resolution: {integrity: sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==}
|
|
||||||
|
|
||||||
typed-array-length@1.0.5:
|
typed-array-length@1.0.5:
|
||||||
resolution: {integrity: sha512-yMi0PlwuznKHxKmcpoOdeLwxBoVPkqZxd7q2FgMkmD3bNwvF5VW0+UlUQ1k1vmktTu4Yu13Q0RIxEP8+B+wloA==}
|
resolution: {integrity: sha512-yMi0PlwuznKHxKmcpoOdeLwxBoVPkqZxd7q2FgMkmD3bNwvF5VW0+UlUQ1k1vmktTu4Yu13Q0RIxEP8+B+wloA==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
@ -13300,6 +13210,12 @@ packages:
|
||||||
vite:
|
vite:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
vite-plugin-static-copy@2.2.0:
|
||||||
|
resolution: {integrity: sha512-ytMrKdR9iWEYHbUxs6x53m+MRl4SJsOSoMu1U1+Pfg0DjPeMlsRVx3RR5jvoonineDquIue83Oq69JvNsFSU5w==}
|
||||||
|
engines: {node: ^18.0.0 || >=20.0.0}
|
||||||
|
peerDependencies:
|
||||||
|
vite: ^5.0.0 || ^6.0.0
|
||||||
|
|
||||||
vite-svg-loader@5.1.0:
|
vite-svg-loader@5.1.0:
|
||||||
resolution: {integrity: sha512-M/wqwtOEjgb956/+m5ZrYT/Iq6Hax0OakWbokj8+9PXOnB7b/4AxESHieEtnNEy7ZpjsjYW1/5nK8fATQMmRxw==}
|
resolution: {integrity: sha512-M/wqwtOEjgb956/+m5ZrYT/Iq6Hax0OakWbokj8+9PXOnB7b/4AxESHieEtnNEy7ZpjsjYW1/5nK8fATQMmRxw==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
|
@ -13536,6 +13452,9 @@ packages:
|
||||||
resolution: {integrity: sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==}
|
resolution: {integrity: sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==}
|
||||||
engines: {node: '>= 14'}
|
engines: {node: '>= 14'}
|
||||||
|
|
||||||
|
web-tree-sitter@0.24.3:
|
||||||
|
resolution: {integrity: sha512-uR9YNewr1S2EzPKE+y39nAwaTyobBaZRG/IsfkB/OT4v0lXtNj5WjtHKgn2h7eOYUWIZh5rK9Px7tI6S9CRKdA==}
|
||||||
|
|
||||||
webidl-conversions@3.0.1:
|
webidl-conversions@3.0.1:
|
||||||
resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==}
|
resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==}
|
||||||
|
|
||||||
|
@ -15938,18 +15857,6 @@ snapshots:
|
||||||
|
|
||||||
'@ctrl/tinycolor@3.6.0': {}
|
'@ctrl/tinycolor@3.6.0': {}
|
||||||
|
|
||||||
'@curlconverter/yargs-parser@0.0.1': {}
|
|
||||||
|
|
||||||
'@curlconverter/yargs@0.0.2':
|
|
||||||
dependencies:
|
|
||||||
'@curlconverter/yargs-parser': 0.0.1
|
|
||||||
cliui: 7.0.4
|
|
||||||
escalade: 3.1.1
|
|
||||||
get-caller-file: 2.0.5
|
|
||||||
require-directory: 2.1.1
|
|
||||||
string-width: 4.2.3
|
|
||||||
y18n: 5.0.8
|
|
||||||
|
|
||||||
'@cypress/request@3.0.1':
|
'@cypress/request@3.0.1':
|
||||||
dependencies:
|
dependencies:
|
||||||
aws-sign2: 0.7.0
|
aws-sign2: 0.7.0
|
||||||
|
@ -19664,8 +19571,6 @@ snapshots:
|
||||||
|
|
||||||
'@xmldom/xmldom@0.8.6': {}
|
'@xmldom/xmldom@0.8.6': {}
|
||||||
|
|
||||||
a-sync-waterfall@1.0.1: {}
|
|
||||||
|
|
||||||
abab@2.0.6: {}
|
abab@2.0.6: {}
|
||||||
|
|
||||||
abbrev@1.1.1: {}
|
abbrev@1.1.1: {}
|
||||||
|
@ -19852,11 +19757,6 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
dequal: 2.0.3
|
dequal: 2.0.3
|
||||||
|
|
||||||
array-buffer-byte-length@1.0.0:
|
|
||||||
dependencies:
|
|
||||||
call-bind: 1.0.7
|
|
||||||
is-array-buffer: 3.0.2
|
|
||||||
|
|
||||||
array-buffer-byte-length@1.0.1:
|
array-buffer-byte-length@1.0.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
call-bind: 1.0.7
|
call-bind: 1.0.7
|
||||||
|
@ -19914,15 +19814,6 @@ snapshots:
|
||||||
es-abstract: 1.22.5
|
es-abstract: 1.22.5
|
||||||
es-shim-unscopables: 1.0.0
|
es-shim-unscopables: 1.0.0
|
||||||
|
|
||||||
arraybuffer.prototype.slice@1.0.1:
|
|
||||||
dependencies:
|
|
||||||
array-buffer-byte-length: 1.0.0
|
|
||||||
call-bind: 1.0.7
|
|
||||||
define-properties: 1.2.1
|
|
||||||
get-intrinsic: 1.2.4
|
|
||||||
is-array-buffer: 3.0.2
|
|
||||||
is-shared-array-buffer: 1.0.2
|
|
||||||
|
|
||||||
arraybuffer.prototype.slice@1.0.3:
|
arraybuffer.prototype.slice@1.0.3:
|
||||||
dependencies:
|
dependencies:
|
||||||
array-buffer-byte-length: 1.0.1
|
array-buffer-byte-length: 1.0.1
|
||||||
|
@ -20677,8 +20568,6 @@ snapshots:
|
||||||
|
|
||||||
commander@4.1.1: {}
|
commander@4.1.1: {}
|
||||||
|
|
||||||
commander@5.1.0: {}
|
|
||||||
|
|
||||||
commander@6.2.1: {}
|
commander@6.2.1: {}
|
||||||
|
|
||||||
commander@7.2.0: {}
|
commander@7.2.0: {}
|
||||||
|
@ -20788,8 +20677,6 @@ snapshots:
|
||||||
|
|
||||||
cookie-signature@1.0.6: {}
|
cookie-signature@1.0.6: {}
|
||||||
|
|
||||||
cookie@0.4.2: {}
|
|
||||||
|
|
||||||
cookie@0.7.1: {}
|
cookie@0.7.1: {}
|
||||||
|
|
||||||
cookie@0.7.2: {}
|
cookie@0.7.2: {}
|
||||||
|
@ -20933,17 +20820,14 @@ snapshots:
|
||||||
|
|
||||||
csv-parse@5.5.0: {}
|
csv-parse@5.5.0: {}
|
||||||
|
|
||||||
curlconverter@3.21.0(chokidar@4.0.1):
|
curlconverter@4.11.0(patch_hash=ymigioonidbyw7jydnlor7bohu):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@curlconverter/yargs': 0.0.2
|
|
||||||
cookie: 0.4.2
|
|
||||||
jsesc: 3.0.2
|
jsesc: 3.0.2
|
||||||
nunjucks: 3.2.4(chokidar@4.0.1)
|
lossless-json: 4.0.2
|
||||||
query-string: 7.1.3
|
tree-sitter: 0.21.1
|
||||||
string.prototype.startswith: 1.0.0
|
tree-sitter-bash: 0.23.3(tree-sitter@0.21.1)
|
||||||
|
web-tree-sitter: 0.24.3
|
||||||
yamljs: 0.3.0
|
yamljs: 0.3.0
|
||||||
transitivePeerDependencies:
|
|
||||||
- chokidar
|
|
||||||
|
|
||||||
currency-codes@2.1.0:
|
currency-codes@2.1.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -21136,8 +21020,6 @@ snapshots:
|
||||||
|
|
||||||
decko@1.2.0: {}
|
decko@1.2.0: {}
|
||||||
|
|
||||||
decode-uri-component@0.2.2: {}
|
|
||||||
|
|
||||||
decompress-response@6.0.0:
|
decompress-response@6.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
mimic-response: 3.1.0
|
mimic-response: 3.1.0
|
||||||
|
@ -21486,48 +21368,6 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
is-arrayish: 0.2.1
|
is-arrayish: 0.2.1
|
||||||
|
|
||||||
es-abstract@1.22.1:
|
|
||||||
dependencies:
|
|
||||||
array-buffer-byte-length: 1.0.0
|
|
||||||
arraybuffer.prototype.slice: 1.0.1
|
|
||||||
available-typed-arrays: 1.0.7
|
|
||||||
call-bind: 1.0.7
|
|
||||||
es-set-tostringtag: 2.0.1
|
|
||||||
es-to-primitive: 1.2.1
|
|
||||||
function.prototype.name: 1.1.5
|
|
||||||
get-intrinsic: 1.2.4
|
|
||||||
get-symbol-description: 1.0.0
|
|
||||||
globalthis: 1.0.3
|
|
||||||
gopd: 1.0.1
|
|
||||||
has: 1.0.3
|
|
||||||
has-property-descriptors: 1.0.2
|
|
||||||
has-proto: 1.0.3
|
|
||||||
has-symbols: 1.0.3
|
|
||||||
internal-slot: 1.0.5
|
|
||||||
is-array-buffer: 3.0.2
|
|
||||||
is-callable: 1.2.7
|
|
||||||
is-negative-zero: 2.0.2
|
|
||||||
is-regex: 1.1.4
|
|
||||||
is-shared-array-buffer: 1.0.2
|
|
||||||
is-string: 1.0.7
|
|
||||||
is-typed-array: 1.1.13
|
|
||||||
is-weakref: 1.0.2
|
|
||||||
object-inspect: 1.13.1
|
|
||||||
object-keys: 1.1.1
|
|
||||||
object.assign: 4.1.5
|
|
||||||
regexp.prototype.flags: 1.5.0
|
|
||||||
safe-array-concat: 1.0.0
|
|
||||||
safe-regex-test: 1.0.0
|
|
||||||
string.prototype.trim: 1.2.7
|
|
||||||
string.prototype.trimend: 1.0.6
|
|
||||||
string.prototype.trimstart: 1.0.6
|
|
||||||
typed-array-buffer: 1.0.0
|
|
||||||
typed-array-byte-length: 1.0.0
|
|
||||||
typed-array-byte-offset: 1.0.0
|
|
||||||
typed-array-length: 1.0.4
|
|
||||||
unbox-primitive: 1.0.2
|
|
||||||
which-typed-array: 1.1.15
|
|
||||||
|
|
||||||
es-abstract@1.22.5:
|
es-abstract@1.22.5:
|
||||||
dependencies:
|
dependencies:
|
||||||
array-buffer-byte-length: 1.0.1
|
array-buffer-byte-length: 1.0.1
|
||||||
|
@ -21658,12 +21498,6 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
es-errors: 1.3.0
|
es-errors: 1.3.0
|
||||||
|
|
||||||
es-set-tostringtag@2.0.1:
|
|
||||||
dependencies:
|
|
||||||
get-intrinsic: 1.2.4
|
|
||||||
has: 1.0.3
|
|
||||||
has-tostringtag: 1.0.2
|
|
||||||
|
|
||||||
es-set-tostringtag@2.0.3:
|
es-set-tostringtag@2.0.3:
|
||||||
dependencies:
|
dependencies:
|
||||||
get-intrinsic: 1.2.4
|
get-intrinsic: 1.2.4
|
||||||
|
@ -22265,8 +22099,6 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
to-regex-range: 5.0.1
|
to-regex-range: 5.0.1
|
||||||
|
|
||||||
filter-obj@1.1.0: {}
|
|
||||||
|
|
||||||
finalhandler@1.3.1:
|
finalhandler@1.3.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
debug: 2.6.9
|
debug: 2.6.9
|
||||||
|
@ -22378,6 +22210,12 @@ snapshots:
|
||||||
|
|
||||||
fs-constants@1.0.0: {}
|
fs-constants@1.0.0: {}
|
||||||
|
|
||||||
|
fs-extra@11.3.0:
|
||||||
|
dependencies:
|
||||||
|
graceful-fs: 4.2.11
|
||||||
|
jsonfile: 6.1.0
|
||||||
|
universalify: 2.0.0
|
||||||
|
|
||||||
fs-extra@7.0.1:
|
fs-extra@7.0.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
graceful-fs: 4.2.11
|
graceful-fs: 4.2.11
|
||||||
|
@ -22405,13 +22243,6 @@ snapshots:
|
||||||
|
|
||||||
function-bind@1.1.2: {}
|
function-bind@1.1.2: {}
|
||||||
|
|
||||||
function.prototype.name@1.1.5:
|
|
||||||
dependencies:
|
|
||||||
call-bind: 1.0.7
|
|
||||||
define-properties: 1.2.1
|
|
||||||
es-abstract: 1.22.5
|
|
||||||
functions-have-names: 1.2.3
|
|
||||||
|
|
||||||
function.prototype.name@1.1.6:
|
function.prototype.name@1.1.6:
|
||||||
dependencies:
|
dependencies:
|
||||||
call-bind: 1.0.7
|
call-bind: 1.0.7
|
||||||
|
@ -22505,11 +22336,6 @@ snapshots:
|
||||||
|
|
||||||
get-stream@6.0.1: {}
|
get-stream@6.0.1: {}
|
||||||
|
|
||||||
get-symbol-description@1.0.0:
|
|
||||||
dependencies:
|
|
||||||
call-bind: 1.0.7
|
|
||||||
get-intrinsic: 1.2.4
|
|
||||||
|
|
||||||
get-symbol-description@1.0.2:
|
get-symbol-description@1.0.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
call-bind: 1.0.7
|
call-bind: 1.0.7
|
||||||
|
@ -23020,12 +22846,6 @@ snapshots:
|
||||||
strip-ansi: 6.0.1
|
strip-ansi: 6.0.1
|
||||||
through: 2.3.8
|
through: 2.3.8
|
||||||
|
|
||||||
internal-slot@1.0.5:
|
|
||||||
dependencies:
|
|
||||||
get-intrinsic: 1.2.4
|
|
||||||
has: 1.0.3
|
|
||||||
side-channel: 1.0.6
|
|
||||||
|
|
||||||
internal-slot@1.0.7:
|
internal-slot@1.0.7:
|
||||||
dependencies:
|
dependencies:
|
||||||
es-errors: 1.3.0
|
es-errors: 1.3.0
|
||||||
|
@ -23071,12 +22891,6 @@ snapshots:
|
||||||
call-bind: 1.0.7
|
call-bind: 1.0.7
|
||||||
has-tostringtag: 1.0.2
|
has-tostringtag: 1.0.2
|
||||||
|
|
||||||
is-array-buffer@3.0.2:
|
|
||||||
dependencies:
|
|
||||||
call-bind: 1.0.7
|
|
||||||
get-intrinsic: 1.2.4
|
|
||||||
is-typed-array: 1.1.13
|
|
||||||
|
|
||||||
is-array-buffer@3.0.4:
|
is-array-buffer@3.0.4:
|
||||||
dependencies:
|
dependencies:
|
||||||
call-bind: 1.0.7
|
call-bind: 1.0.7
|
||||||
|
@ -23157,8 +22971,6 @@ snapshots:
|
||||||
call-bind: 1.0.7
|
call-bind: 1.0.7
|
||||||
define-properties: 1.2.1
|
define-properties: 1.2.1
|
||||||
|
|
||||||
is-negative-zero@2.0.2: {}
|
|
||||||
|
|
||||||
is-negative-zero@2.0.3: {}
|
is-negative-zero@2.0.3: {}
|
||||||
|
|
||||||
is-node-process@1.2.0: {}
|
is-node-process@1.2.0: {}
|
||||||
|
@ -23188,10 +23000,6 @@ snapshots:
|
||||||
|
|
||||||
is-set@2.0.2: {}
|
is-set@2.0.2: {}
|
||||||
|
|
||||||
is-shared-array-buffer@1.0.2:
|
|
||||||
dependencies:
|
|
||||||
call-bind: 1.0.7
|
|
||||||
|
|
||||||
is-shared-array-buffer@1.0.3:
|
is-shared-array-buffer@1.0.3:
|
||||||
dependencies:
|
dependencies:
|
||||||
call-bind: 1.0.7
|
call-bind: 1.0.7
|
||||||
|
@ -24195,6 +24003,8 @@ snapshots:
|
||||||
|
|
||||||
lossless-json@1.0.5: {}
|
lossless-json@1.0.5: {}
|
||||||
|
|
||||||
|
lossless-json@4.0.2: {}
|
||||||
|
|
||||||
loupe@3.1.2: {}
|
loupe@3.1.2: {}
|
||||||
|
|
||||||
lower-case@1.1.4: {}
|
lower-case@1.1.4: {}
|
||||||
|
@ -24996,6 +24806,8 @@ snapshots:
|
||||||
|
|
||||||
node-addon-api@7.1.0: {}
|
node-addon-api@7.1.0: {}
|
||||||
|
|
||||||
|
node-addon-api@8.3.0: {}
|
||||||
|
|
||||||
node-cleanup@2.1.2: {}
|
node-cleanup@2.1.2: {}
|
||||||
|
|
||||||
node-domexception@1.0.0: {}
|
node-domexception@1.0.0: {}
|
||||||
|
@ -25023,6 +24835,8 @@ snapshots:
|
||||||
node-gyp-build-optional-packages@5.0.7:
|
node-gyp-build-optional-packages@5.0.7:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
node-gyp-build@4.8.4: {}
|
||||||
|
|
||||||
node-gyp@8.4.1:
|
node-gyp@8.4.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
env-paths: 2.2.1
|
env-paths: 2.2.1
|
||||||
|
@ -25153,14 +24967,6 @@ snapshots:
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
nunjucks@3.2.4(chokidar@4.0.1):
|
|
||||||
dependencies:
|
|
||||||
a-sync-waterfall: 1.0.1
|
|
||||||
asap: 2.0.6
|
|
||||||
commander: 5.1.0
|
|
||||||
optionalDependencies:
|
|
||||||
chokidar: 4.0.1
|
|
||||||
|
|
||||||
nwsapi@2.2.7: {}
|
nwsapi@2.2.7: {}
|
||||||
|
|
||||||
oas-kit-common@1.0.8:
|
oas-kit-common@1.0.8:
|
||||||
|
@ -25959,13 +25765,6 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
side-channel: 1.0.6
|
side-channel: 1.0.6
|
||||||
|
|
||||||
query-string@7.1.3:
|
|
||||||
dependencies:
|
|
||||||
decode-uri-component: 0.2.2
|
|
||||||
filter-obj: 1.1.0
|
|
||||||
split-on-first: 1.1.0
|
|
||||||
strict-uri-encode: 2.0.0
|
|
||||||
|
|
||||||
querystringify@2.2.0: {}
|
querystringify@2.2.0: {}
|
||||||
|
|
||||||
queue-lit@1.5.0: {}
|
queue-lit@1.5.0: {}
|
||||||
|
@ -26227,12 +26026,6 @@ snapshots:
|
||||||
|
|
||||||
regexp-tree@0.1.27: {}
|
regexp-tree@0.1.27: {}
|
||||||
|
|
||||||
regexp.prototype.flags@1.5.0:
|
|
||||||
dependencies:
|
|
||||||
call-bind: 1.0.7
|
|
||||||
define-properties: 1.2.1
|
|
||||||
functions-have-names: 1.2.3
|
|
||||||
|
|
||||||
regexp.prototype.flags@1.5.2:
|
regexp.prototype.flags@1.5.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
call-bind: 1.0.7
|
call-bind: 1.0.7
|
||||||
|
@ -26430,13 +26223,6 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
tslib: 2.6.2
|
tslib: 2.6.2
|
||||||
|
|
||||||
safe-array-concat@1.0.0:
|
|
||||||
dependencies:
|
|
||||||
call-bind: 1.0.7
|
|
||||||
get-intrinsic: 1.2.4
|
|
||||||
has-symbols: 1.0.3
|
|
||||||
isarray: 2.0.5
|
|
||||||
|
|
||||||
safe-array-concat@1.1.2:
|
safe-array-concat@1.1.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
call-bind: 1.0.7
|
call-bind: 1.0.7
|
||||||
|
@ -26448,12 +26234,6 @@ snapshots:
|
||||||
|
|
||||||
safe-buffer@5.2.1: {}
|
safe-buffer@5.2.1: {}
|
||||||
|
|
||||||
safe-regex-test@1.0.0:
|
|
||||||
dependencies:
|
|
||||||
call-bind: 1.0.7
|
|
||||||
get-intrinsic: 1.2.4
|
|
||||||
is-regex: 1.1.4
|
|
||||||
|
|
||||||
safe-regex-test@1.0.3:
|
safe-regex-test@1.0.3:
|
||||||
dependencies:
|
dependencies:
|
||||||
call-bind: 1.0.7
|
call-bind: 1.0.7
|
||||||
|
@ -26844,8 +26624,6 @@ snapshots:
|
||||||
|
|
||||||
spex@3.3.0: {}
|
spex@3.3.0: {}
|
||||||
|
|
||||||
split-on-first@1.1.0: {}
|
|
||||||
|
|
||||||
split2@4.2.0: {}
|
split2@4.2.0: {}
|
||||||
|
|
||||||
split@0.3.3:
|
split@0.3.3:
|
||||||
|
@ -26976,8 +26754,6 @@ snapshots:
|
||||||
|
|
||||||
strict-event-emitter@0.5.1: {}
|
strict-event-emitter@0.5.1: {}
|
||||||
|
|
||||||
strict-uri-encode@2.0.0: {}
|
|
||||||
|
|
||||||
string-argv@0.3.1: {}
|
string-argv@0.3.1: {}
|
||||||
|
|
||||||
string-length@4.0.2:
|
string-length@4.0.2:
|
||||||
|
@ -26997,17 +26773,6 @@ snapshots:
|
||||||
emoji-regex: 9.2.2
|
emoji-regex: 9.2.2
|
||||||
strip-ansi: 7.1.0
|
strip-ansi: 7.1.0
|
||||||
|
|
||||||
string.prototype.startswith@1.0.0:
|
|
||||||
dependencies:
|
|
||||||
define-properties: 1.2.0
|
|
||||||
es-abstract: 1.22.1
|
|
||||||
|
|
||||||
string.prototype.trim@1.2.7:
|
|
||||||
dependencies:
|
|
||||||
call-bind: 1.0.7
|
|
||||||
define-properties: 1.2.1
|
|
||||||
es-abstract: 1.22.5
|
|
||||||
|
|
||||||
string.prototype.trim@1.2.8:
|
string.prototype.trim@1.2.8:
|
||||||
dependencies:
|
dependencies:
|
||||||
call-bind: 1.0.7
|
call-bind: 1.0.7
|
||||||
|
@ -27021,12 +26786,6 @@ snapshots:
|
||||||
es-abstract: 1.23.3
|
es-abstract: 1.23.3
|
||||||
es-object-atoms: 1.0.0
|
es-object-atoms: 1.0.0
|
||||||
|
|
||||||
string.prototype.trimend@1.0.6:
|
|
||||||
dependencies:
|
|
||||||
call-bind: 1.0.7
|
|
||||||
define-properties: 1.2.1
|
|
||||||
es-abstract: 1.22.5
|
|
||||||
|
|
||||||
string.prototype.trimend@1.0.7:
|
string.prototype.trimend@1.0.7:
|
||||||
dependencies:
|
dependencies:
|
||||||
call-bind: 1.0.7
|
call-bind: 1.0.7
|
||||||
|
@ -27039,12 +26798,6 @@ snapshots:
|
||||||
define-properties: 1.2.1
|
define-properties: 1.2.1
|
||||||
es-object-atoms: 1.0.0
|
es-object-atoms: 1.0.0
|
||||||
|
|
||||||
string.prototype.trimstart@1.0.6:
|
|
||||||
dependencies:
|
|
||||||
call-bind: 1.0.7
|
|
||||||
define-properties: 1.2.1
|
|
||||||
es-abstract: 1.22.5
|
|
||||||
|
|
||||||
string.prototype.trimstart@1.0.7:
|
string.prototype.trimstart@1.0.7:
|
||||||
dependencies:
|
dependencies:
|
||||||
call-bind: 1.0.7
|
call-bind: 1.0.7
|
||||||
|
@ -27423,6 +27176,18 @@ snapshots:
|
||||||
|
|
||||||
tree-kill@1.2.2: {}
|
tree-kill@1.2.2: {}
|
||||||
|
|
||||||
|
tree-sitter-bash@0.23.3(tree-sitter@0.21.1):
|
||||||
|
dependencies:
|
||||||
|
node-addon-api: 8.3.0
|
||||||
|
node-gyp-build: 4.8.4
|
||||||
|
optionalDependencies:
|
||||||
|
tree-sitter: 0.21.1
|
||||||
|
|
||||||
|
tree-sitter@0.21.1:
|
||||||
|
dependencies:
|
||||||
|
node-addon-api: 8.3.0
|
||||||
|
node-gyp-build: 4.8.4
|
||||||
|
|
||||||
triple-beam@1.3.0: {}
|
triple-beam@1.3.0: {}
|
||||||
|
|
||||||
ts-api-utils@1.0.1(typescript@5.7.2):
|
ts-api-utils@1.0.1(typescript@5.7.2):
|
||||||
|
@ -27620,25 +27385,12 @@ snapshots:
|
||||||
|
|
||||||
type-of-is@3.5.1: {}
|
type-of-is@3.5.1: {}
|
||||||
|
|
||||||
typed-array-buffer@1.0.0:
|
|
||||||
dependencies:
|
|
||||||
call-bind: 1.0.7
|
|
||||||
get-intrinsic: 1.2.4
|
|
||||||
is-typed-array: 1.1.13
|
|
||||||
|
|
||||||
typed-array-buffer@1.0.2:
|
typed-array-buffer@1.0.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
call-bind: 1.0.7
|
call-bind: 1.0.7
|
||||||
es-errors: 1.3.0
|
es-errors: 1.3.0
|
||||||
is-typed-array: 1.1.13
|
is-typed-array: 1.1.13
|
||||||
|
|
||||||
typed-array-byte-length@1.0.0:
|
|
||||||
dependencies:
|
|
||||||
call-bind: 1.0.7
|
|
||||||
for-each: 0.3.3
|
|
||||||
has-proto: 1.0.3
|
|
||||||
is-typed-array: 1.1.13
|
|
||||||
|
|
||||||
typed-array-byte-length@1.0.1:
|
typed-array-byte-length@1.0.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
call-bind: 1.0.7
|
call-bind: 1.0.7
|
||||||
|
@ -27647,14 +27399,6 @@ snapshots:
|
||||||
has-proto: 1.0.3
|
has-proto: 1.0.3
|
||||||
is-typed-array: 1.1.13
|
is-typed-array: 1.1.13
|
||||||
|
|
||||||
typed-array-byte-offset@1.0.0:
|
|
||||||
dependencies:
|
|
||||||
available-typed-arrays: 1.0.7
|
|
||||||
call-bind: 1.0.7
|
|
||||||
for-each: 0.3.3
|
|
||||||
has-proto: 1.0.3
|
|
||||||
is-typed-array: 1.1.13
|
|
||||||
|
|
||||||
typed-array-byte-offset@1.0.2:
|
typed-array-byte-offset@1.0.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
available-typed-arrays: 1.0.7
|
available-typed-arrays: 1.0.7
|
||||||
|
@ -27664,12 +27408,6 @@ snapshots:
|
||||||
has-proto: 1.0.3
|
has-proto: 1.0.3
|
||||||
is-typed-array: 1.1.13
|
is-typed-array: 1.1.13
|
||||||
|
|
||||||
typed-array-length@1.0.4:
|
|
||||||
dependencies:
|
|
||||||
call-bind: 1.0.7
|
|
||||||
for-each: 0.3.3
|
|
||||||
is-typed-array: 1.1.13
|
|
||||||
|
|
||||||
typed-array-length@1.0.5:
|
typed-array-length@1.0.5:
|
||||||
dependencies:
|
dependencies:
|
||||||
call-bind: 1.0.7
|
call-bind: 1.0.7
|
||||||
|
@ -27935,6 +27673,14 @@ snapshots:
|
||||||
- rollup
|
- rollup
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
|
vite-plugin-static-copy@2.2.0(vite@6.0.2(@types/node@18.16.16)(jiti@1.21.0)(sass@1.64.1)(terser@5.16.1)):
|
||||||
|
dependencies:
|
||||||
|
chokidar: 4.0.1
|
||||||
|
fast-glob: 3.3.2
|
||||||
|
fs-extra: 11.3.0
|
||||||
|
picocolors: 1.1.1
|
||||||
|
vite: 6.0.2(@types/node@18.16.16)(jiti@1.21.0)(sass@1.64.1)(terser@5.16.1)
|
||||||
|
|
||||||
vite-svg-loader@5.1.0(vue@3.5.13(typescript@5.7.2)):
|
vite-svg-loader@5.1.0(vue@3.5.13(typescript@5.7.2)):
|
||||||
dependencies:
|
dependencies:
|
||||||
svgo: 3.3.2
|
svgo: 3.3.2
|
||||||
|
@ -28179,6 +27925,8 @@ snapshots:
|
||||||
|
|
||||||
web-streams-polyfill@4.0.0-beta.3: {}
|
web-streams-polyfill@4.0.0-beta.3: {}
|
||||||
|
|
||||||
|
web-tree-sitter@0.24.3: {}
|
||||||
|
|
||||||
webidl-conversions@3.0.1: {}
|
webidl-conversions@3.0.1: {}
|
||||||
|
|
||||||
webidl-conversions@4.0.2: {}
|
webidl-conversions@4.0.2: {}
|
||||||
|
|
Loading…
Reference in a new issue