From 8f4118a6b8536527a58ad8dda78e5b451ec7cf85 Mon Sep 17 00:00:00 2001 From: Jan Prochazka Date: Wed, 23 Apr 2025 13:17:54 +0200 Subject: [PATCH] SYNC: Merge pull request #3 from dbgate/feature/zip --- app/src/mainMenuDefinition.js | 3 + e2e-tests/cypress/e2e/browse-data.cy.js | 10 +- .../__tests__/data-duplicator.spec.js | 160 -- .../__tests__/data-replicator.spec.js | 305 +++ integration-tests/__tests__/query.spec.js | 2 +- integration-tests/docker-compose.yaml | 34 +- integration-tests/engines.js | 8 +- integration-tests/package.json | 2 +- packages/api/package.json | 4 +- packages/api/src/controllers/archive.js | 105 +- packages/api/src/controllers/config.js | 155 +- packages/api/src/controllers/connections.js | 16 +- packages/api/src/controllers/files.js | 59 + packages/api/src/controllers/jsldata.js | 9 + packages/api/src/controllers/runners.js | 24 +- packages/api/src/controllers/uploads.js | 46 - packages/api/src/shell/archiveReader.js | 4 +- packages/api/src/shell/collectorWriter.js | 4 +- packages/api/src/shell/dataDuplicator.js | 61 - packages/api/src/shell/dataReplicator.js | 96 + packages/api/src/shell/download.js | 28 +- packages/api/src/shell/index.js | 14 +- packages/api/src/shell/jsonLinesWriter.js | 7 +- packages/api/src/shell/unzipDirectory.js | 91 + packages/api/src/shell/unzipJsonLinesData.js | 60 + packages/api/src/shell/unzipJsonLinesFile.js | 59 + packages/api/src/shell/zipDirectory.js | 49 + packages/api/src/shell/zipJsonLinesData.js | 49 + packages/api/src/utility/cloudUpgrade.js | 15 +- packages/api/src/utility/crypting.js | 61 +- .../src/utility/extractSingleFileFromZip.js | 77 + packages/api/src/utility/listZipEntries.js | 41 + packages/datalib/src/ChangeSet.ts | 21 + packages/datalib/src/DataDuplicator.ts | 326 ---- packages/datalib/src/DataReplicator.ts | 509 +++++ packages/datalib/src/index.ts | 2 +- packages/sqltree/src/utility.ts | 42 +- packages/tools/src/ScriptWriter.ts | 27 +- .../tools/src/createBulkInsertStreamBase.ts | 4 +- packages/tools/src/stringTools.ts | 17 + packages/types/test-engines.d.ts | 2 +- packages/web/src/Screen.svelte | 1 + .../src/appobj/ArchiveFileAppObject.svelte | 77 +- .../src/appobj/ArchiveFolderAppObject.svelte | 48 +- .../web/src/appobj/DatabaseAppObject.svelte | 12 +- .../web/src/appobj/SavedFileAppObject.svelte | 70 +- .../buttons/FormStyledButtonLikeLabel.svelte | 1 + .../web/src/buttons/InlineUploadButton.svelte | 61 + packages/web/src/buttons/LargeButton.svelte | 2 +- packages/web/src/commands/stdCommands.ts | 39 + packages/web/src/datagrid/DataGridCell.svelte | 159 +- packages/web/src/datagrid/DataGridCore.svelte | 243 ++- packages/web/src/datagrid/DataGridRow.svelte | 30 +- packages/web/src/datagrid/Grider.ts | 7 +- packages/web/src/datagrid/JslDataGrid.svelte | 2 +- .../web/src/datagrid/OverlayDiffGrider.ts | 110 ++ .../web/src/datagrid/RowHeaderCell.svelte | 14 + .../web/src/datagrid/SqlDataGridCore.svelte | 18 +- .../web/src/datagrid/TableDataGrid.svelte | 6 +- packages/web/src/elements/TableControl.svelte | 282 ++- .../src/forms/FormArchiveFilesSelect.svelte | 11 +- .../src/forms/FormArchiveFolderSelect.svelte | 16 +- .../web/src/forms/FormCheckboxField.svelte | 2 +- .../web/src/forms/FormCheckboxFieldRaw.svelte | 7 +- packages/web/src/icons/FontIcon.svelte | 10 +- .../src/impexp/FormConnectionSelect.svelte | 2 +- .../web/src/impexp/SourceTargetConfig.svelte | 44 +- packages/web/src/impexp/createImpExpScript.ts | 16 +- .../modals/ChooseArchiveFolderModal.svelte | 2 +- .../ExportImportConnectionsModal.svelte | 368 ++++ .../web/src/modals/SaveArchiveModal.svelte | 5 +- .../web/src/query/RunnerOutputFiles.svelte | 111 +- packages/web/src/tabs/ArchiveFileTab.svelte | 12 +- .../web/src/tabs/DataDuplicatorTab.svelte | 469 ----- packages/web/src/tabs/ImportExportTab.svelte | 10 +- packages/web/src/tabs/index.js | 2 - packages/web/src/utility/exportFileTools.ts | 6 +- packages/web/src/utility/formatFileSize.ts | 6 +- .../web/src/widgets/ArchiveFolderList.svelte | 38 + .../widgets/MultiColumnFilterControl.svelte | 75 + .../web/src/widgets/SavedFilesList.svelte | 82 +- yarn.lock | 1711 +++++------------ 82 files changed, 3981 insertions(+), 2814 deletions(-) delete mode 100644 integration-tests/__tests__/data-duplicator.spec.js create mode 100644 integration-tests/__tests__/data-replicator.spec.js delete mode 100644 packages/api/src/shell/dataDuplicator.js create mode 100644 packages/api/src/shell/dataReplicator.js create mode 100644 packages/api/src/shell/unzipDirectory.js create mode 100644 packages/api/src/shell/unzipJsonLinesData.js create mode 100644 packages/api/src/shell/unzipJsonLinesFile.js create mode 100644 packages/api/src/shell/zipDirectory.js create mode 100644 packages/api/src/shell/zipJsonLinesData.js create mode 100644 packages/api/src/utility/extractSingleFileFromZip.js create mode 100644 packages/api/src/utility/listZipEntries.js delete mode 100644 packages/datalib/src/DataDuplicator.ts create mode 100644 packages/datalib/src/DataReplicator.ts create mode 100644 packages/web/src/buttons/InlineUploadButton.svelte create mode 100644 packages/web/src/datagrid/OverlayDiffGrider.ts create mode 100644 packages/web/src/modals/ExportImportConnectionsModal.svelte delete mode 100644 packages/web/src/tabs/DataDuplicatorTab.svelte create mode 100644 packages/web/src/widgets/MultiColumnFilterControl.svelte diff --git a/app/src/mainMenuDefinition.js b/app/src/mainMenuDefinition.js index b74a94136..3bb581434 100644 --- a/app/src/mainMenuDefinition.js +++ b/app/src/mainMenuDefinition.js @@ -87,6 +87,9 @@ module.exports = ({ editMenu, isMac }) => [ { command: 'folder.showData', hideDisabled: true }, { command: 'new.gist', hideDisabled: true }, { command: 'app.resetSettings', hideDisabled: true }, + { divider: true }, + { command: 'app.exportConnections', hideDisabled: true }, + { command: 'app.importConnections', hideDisabled: true }, ], }, ...(isMac diff --git a/e2e-tests/cypress/e2e/browse-data.cy.js b/e2e-tests/cypress/e2e/browse-data.cy.js index 6bcb59f04..30cd9c706 100644 --- a/e2e-tests/cypress/e2e/browse-data.cy.js +++ b/e2e-tests/cypress/e2e/browse-data.cy.js @@ -468,15 +468,15 @@ describe('Data browser data', () => { cy.themeshot('database-model-table-yaml'); }); - it('Data duplicator', () => { + it('Data replicator', () => { cy.contains('MySql-connection').click(); cy.contains('MyChinook').click(); cy.testid('WidgetIconPanel_archive').click(); cy.contains('chinook-archive').rightclick(); - cy.contains('Data duplicator').click(); + cy.contains('Data replicator').click(); cy.contains('Dry run').click(); - cy.testid('DataDuplicatorTab_importIntoDb').click(); - cy.contains('Duplicated Album, inserted 347 rows, mapped 0 rows, missing 0 rows, skipped 0 rows'); - cy.themeshot('data-duplicator'); + cy.testid('DataReplicatorTab_importIntoDb').click(); + cy.contains('Replicated Album, inserted 347 rows, mapped 0 rows, missing 0 rows, skipped 0 rows'); + cy.themeshot('data-replicator'); }); }); diff --git a/integration-tests/__tests__/data-duplicator.spec.js b/integration-tests/__tests__/data-duplicator.spec.js deleted file mode 100644 index 3c7791b80..000000000 --- a/integration-tests/__tests__/data-duplicator.spec.js +++ /dev/null @@ -1,160 +0,0 @@ -const engines = require('../engines'); -const stream = require('stream'); -const { testWrapper } = require('../tools'); -const dataDuplicator = require('dbgate-api/src/shell/dataDuplicator'); -const { runCommandOnDriver, runQueryOnDriver } = require('dbgate-tools'); - -describe('Data duplicator', () => { - test.each(engines.filter(x => !x.skipDataDuplicator).map(engine => [engine.label, engine]))( - 'Insert simple data - %s', - testWrapper(async (conn, driver, engine) => { - runCommandOnDriver(conn, driver, dmp => - dmp.createTable({ - pureName: 't1', - columns: [ - { columnName: 'id', dataType: 'int', autoIncrement: true, notNull: true }, - { columnName: 'val', dataType: 'varchar(50)' }, - ], - primaryKey: { - columns: [{ columnName: 'id' }], - }, - }) - ); - runCommandOnDriver(conn, driver, dmp => - dmp.createTable({ - pureName: 't2', - columns: [ - { columnName: 'id', dataType: 'int', autoIncrement: true, notNull: true }, - { columnName: 'val', dataType: 'varchar(50)' }, - { columnName: 'valfk', dataType: 'int', notNull: true }, - ], - primaryKey: { - columns: [{ columnName: 'id' }], - }, - foreignKeys: [{ refTableName: 't1', columns: [{ columnName: 'valfk', refColumnName: 'id' }] }], - }) - ); - - const gett1 = () => - stream.Readable.from([ - { __isStreamHeader: true, __isDynamicStructure: true }, - { id: 1, val: 'v1' }, - { id: 2, val: 'v2' }, - { id: 3, val: 'v3' }, - ]); - const gett2 = () => - stream.Readable.from([ - { __isStreamHeader: true, __isDynamicStructure: true }, - { id: 1, val: 'v1', valfk: 1 }, - { id: 2, val: 'v2', valfk: 2 }, - { id: 3, val: 'v3', valfk: 3 }, - ]); - - await dataDuplicator({ - systemConnection: conn, - driver, - items: [ - { - name: 't1', - operation: 'copy', - openStream: gett1, - }, - { - name: 't2', - operation: 'copy', - openStream: gett2, - }, - ], - }); - - await dataDuplicator({ - systemConnection: conn, - driver, - items: [ - { - name: 't1', - operation: 'copy', - openStream: gett1, - }, - { - name: 't2', - operation: 'copy', - openStream: gett2, - }, - ], - }); - - const res1 = await runQueryOnDriver(conn, driver, dmp => dmp.put(`select count(*) as ~cnt from ~t1`)); - expect(res1.rows[0].cnt.toString()).toEqual('6'); - - const res2 = await runQueryOnDriver(conn, driver, dmp => dmp.put(`select count(*) as ~cnt from ~t2`)); - expect(res2.rows[0].cnt.toString()).toEqual('6'); - }) - ); - - test.each(engines.filter(x => !x.skipDataDuplicator).map(engine => [engine.label, engine]))( - 'Skip nullable weak refs - %s', - testWrapper(async (conn, driver, engine) => { - runCommandOnDriver(conn, driver, dmp => - dmp.createTable({ - pureName: 't1', - columns: [ - { columnName: 'id', dataType: 'int', notNull: true }, - { columnName: 'val', dataType: 'varchar(50)' }, - ], - primaryKey: { - columns: [{ columnName: 'id' }], - }, - }) - ); - runCommandOnDriver(conn, driver, dmp => - dmp.createTable({ - pureName: 't2', - columns: [ - { columnName: 'id', dataType: 'int', autoIncrement: true, notNull: true }, - { columnName: 'val', dataType: 'varchar(50)' }, - { columnName: 'valfk', dataType: 'int', notNull: false }, - ], - primaryKey: { - columns: [{ columnName: 'id' }], - }, - foreignKeys: [{ refTableName: 't1', columns: [{ columnName: 'valfk', refColumnName: 'id' }] }], - }) - ); - runCommandOnDriver(conn, driver, dmp => dmp.put("insert into ~t1 (~id, ~val) values (1, 'first')")); - - const gett2 = () => - stream.Readable.from([ - { __isStreamHeader: true, __isDynamicStructure: true }, - { id: 1, val: 'v1', valfk: 1 }, - { id: 2, val: 'v2', valfk: 2 }, - ]); - - await dataDuplicator({ - systemConnection: conn, - driver, - items: [ - { - name: 't2', - operation: 'copy', - openStream: gett2, - }, - ], - options: { - setNullForUnresolvedNullableRefs: true, - }, - }); - - const res1 = await runQueryOnDriver(conn, driver, dmp => dmp.put(`select count(*) as ~cnt from ~t1`)); - expect(res1.rows[0].cnt.toString()).toEqual('1'); - - const res2 = await runQueryOnDriver(conn, driver, dmp => dmp.put(`select count(*) as ~cnt from ~t2`)); - expect(res2.rows[0].cnt.toString()).toEqual('2'); - - const res3 = await runQueryOnDriver(conn, driver, dmp => - dmp.put(`select count(*) as ~cnt from ~t2 where ~valfk is not null`) - ); - expect(res3.rows[0].cnt.toString()).toEqual('1'); - }) - ); -}); diff --git a/integration-tests/__tests__/data-replicator.spec.js b/integration-tests/__tests__/data-replicator.spec.js new file mode 100644 index 000000000..8a3a79318 --- /dev/null +++ b/integration-tests/__tests__/data-replicator.spec.js @@ -0,0 +1,305 @@ +const engines = require('../engines'); +const stream = require('stream'); +const { testWrapper } = require('../tools'); +const dataReplicator = require('dbgate-api/src/shell/dataReplicator'); +const deployDb = require('dbgate-api/src/shell/deployDb'); +const storageModel = require('dbgate-api/src/storageModel'); +const { runCommandOnDriver, runQueryOnDriver } = require('dbgate-tools'); + +describe('Data replicator', () => { + test.each(engines.filter(x => !x.skipDataReplicator).map(engine => [engine.label, engine]))( + 'Insert simple data - %s', + testWrapper(async (conn, driver, engine) => { + runCommandOnDriver(conn, driver, dmp => + dmp.createTable({ + pureName: 't1', + columns: [ + { columnName: 'id', dataType: 'int', autoIncrement: true, notNull: true }, + { columnName: 'val', dataType: 'varchar(50)' }, + ], + primaryKey: { + columns: [{ columnName: 'id' }], + }, + }) + ); + runCommandOnDriver(conn, driver, dmp => + dmp.createTable({ + pureName: 't2', + columns: [ + { columnName: 'id', dataType: 'int', autoIncrement: true, notNull: true }, + { columnName: 'val', dataType: 'varchar(50)' }, + { columnName: 'valfk', dataType: 'int', notNull: true }, + ], + primaryKey: { + columns: [{ columnName: 'id' }], + }, + foreignKeys: [{ refTableName: 't1', columns: [{ columnName: 'valfk', refColumnName: 'id' }] }], + }) + ); + + const gett1 = () => + stream.Readable.from([ + { __isStreamHeader: true, __isDynamicStructure: true }, + { id: 1, val: 'v1' }, + { id: 2, val: 'v2' }, + { id: 3, val: 'v3' }, + ]); + const gett2 = () => + stream.Readable.from([ + { __isStreamHeader: true, __isDynamicStructure: true }, + { id: 1, val: 'v1', valfk: 1 }, + { id: 2, val: 'v2', valfk: 2 }, + { id: 3, val: 'v3', valfk: 3 }, + ]); + + await dataReplicator({ + systemConnection: conn, + driver, + items: [ + { + name: 't1', + createNew: true, + openStream: gett1, + }, + { + name: 't2', + createNew: true, + openStream: gett2, + }, + ], + }); + + await dataReplicator({ + systemConnection: conn, + driver, + items: [ + { + name: 't1', + createNew: true, + openStream: gett1, + }, + { + name: 't2', + createNew: true, + openStream: gett2, + }, + ], + }); + + const res1 = await runQueryOnDriver(conn, driver, dmp => dmp.put(`select count(*) as ~cnt from ~t1`)); + expect(res1.rows[0].cnt.toString()).toEqual('6'); + + const res2 = await runQueryOnDriver(conn, driver, dmp => dmp.put(`select count(*) as ~cnt from ~t2`)); + expect(res2.rows[0].cnt.toString()).toEqual('6'); + }) + ); + + test.each(engines.filter(x => !x.skipDataReplicator).map(engine => [engine.label, engine]))( + 'Skip nullable weak refs - %s', + testWrapper(async (conn, driver, engine) => { + runCommandOnDriver(conn, driver, dmp => + dmp.createTable({ + pureName: 't1', + columns: [ + { columnName: 'id', dataType: 'int', notNull: true }, + { columnName: 'val', dataType: 'varchar(50)' }, + ], + primaryKey: { + columns: [{ columnName: 'id' }], + }, + }) + ); + runCommandOnDriver(conn, driver, dmp => + dmp.createTable({ + pureName: 't2', + columns: [ + { columnName: 'id', dataType: 'int', autoIncrement: true, notNull: true }, + { columnName: 'val', dataType: 'varchar(50)' }, + { columnName: 'valfk', dataType: 'int', notNull: false }, + ], + primaryKey: { + columns: [{ columnName: 'id' }], + }, + foreignKeys: [{ refTableName: 't1', columns: [{ columnName: 'valfk', refColumnName: 'id' }] }], + }) + ); + runCommandOnDriver(conn, driver, dmp => dmp.put("insert into ~t1 (~id, ~val) values (1, 'first')")); + + await dataReplicator({ + systemConnection: conn, + driver, + items: [ + { + name: 't2', + createNew: true, + jsonArray: [ + { id: 1, val: 'v1', valfk: 1 }, + { id: 2, val: 'v2', valfk: 2 }, + ], + }, + ], + options: { + setNullForUnresolvedNullableRefs: true, + }, + }); + + const res1 = await runQueryOnDriver(conn, driver, dmp => dmp.put(`select count(*) as ~cnt from ~t1`)); + expect(res1.rows[0].cnt.toString()).toEqual('1'); + + const res2 = await runQueryOnDriver(conn, driver, dmp => dmp.put(`select count(*) as ~cnt from ~t2`)); + expect(res2.rows[0].cnt.toString()).toEqual('2'); + + const res3 = await runQueryOnDriver(conn, driver, dmp => + dmp.put(`select count(*) as ~cnt from ~t2 where ~valfk is not null`) + ); + expect(res3.rows[0].cnt.toString()).toEqual('1'); + }) + ); + + test.each(engines.filter(x => !x.skipDataReplicator).map(engine => [engine.label, engine]))( + 'Import storage DB - %s', + testWrapper(async (conn, driver, engine) => { + await deployDb({ + systemConnection: conn, + driver, + loadedDbModel: storageModel, + targetSchema: driver.defaultSchemaName, + }); + + async function queryValue(sql) { + const res1 = await runQueryOnDriver(conn, driver, dmp => dmp.put(sql)); + return res1.rows[0].val?.toString(); + } + + expect(await queryValue(`select count(*) as ~val from ~auth_methods`)).toEqual('2'); + expect( + await queryValue( + `select ~is_disabled as ~val from ~auth_methods where ~amoid='790ca4d2-7f01-4800-955b-d691b890cc50'` + ) + ).toBeFalsy(); + + const DB1 = { + auth_methods: [ + { id: -1, name: 'Anonymous', amoid: '790ca4d2-7f01-4800-955b-d691b890cc50', is_disabled: 1 }, + { id: 10, name: 'OAuth', amoid: '4269b660-54b6-11ef-a3aa-a9021250bf4b' }, + ], + auth_methods_config: [{ id: 20, auth_method_id: 10, key: 'oauthClient', value: 'dbgate' }], + config: [ + { group: 'admin', key: 'encyptKey', value: '1234' }, + { group: 'admin', key: 'adminPasswordState', value: 'set' }, + { group: 'license', key: 'licenseKey', value: '123467' }, + ], + roles: [ + { id: -3, name: 'superadmin' }, + { id: -2, name: 'logged-user' }, + { id: -1, name: 'anonymous-user' }, + ], + role_permissions: [ + { id: 14, role_id: -1, permission: 'perm1' }, + { id: 29, role_id: -1, permission: 'perm2' }, + { id: 1, role_id: -1, permission: 'perm3' }, + ], + }; + + const DB2 = { + auth_methods: [{ id: 10, name: 'My Auth', amoid: 'myauth1' }], + auth_methods_config: [{ id: 20, auth_method_id: 10, key: 'my authClient', value: 'mydbgate' }], + config: [], + roles: [{ id: 1, name: 'test' }], + role_permissions: [{ id: 14, role_id: 1, permission: 'permxx' }], + }; + + function createDuplConfig(db) { + return { + systemConnection: conn, + driver, + items: [ + { + name: 'auth_methods', + findExisting: true, + updateExisting: true, + createNew: true, + matchColumns: ['amoid'], + jsonArray: db.auth_methods, + }, + { + name: 'auth_methods_config', + findExisting: true, + updateExisting: true, + createNew: true, + matchColumns: ['auth_method_id', 'key'], + jsonArray: db.auth_methods_config, + }, + { + name: 'config', + findExisting: true, + updateExisting: true, + createNew: true, + matchColumns: ['group', 'key'], + jsonArray: db.config, + }, + { + name: 'roles', + findExisting: true, + updateExisting: true, + createNew: true, + matchColumns: ['name'], + jsonArray: db.roles, + }, + { + name: 'role_permissions', + findExisting: true, + updateExisting: true, + createNew: true, + deleteMissing: true, + matchColumns: ['role_id', 'permission'], + deleteRestrictionColumns: ['role_id'], + jsonArray: db.role_permissions, + }, + ], + }; + } + + await dataReplicator(createDuplConfig(DB1)); + + expect( + await queryValue( + `select ~is_disabled as ~val from ~auth_methods where ~amoid='790ca4d2-7f01-4800-955b-d691b890cc50'` + ) + ).toBeTruthy(); + + expect(await queryValue(`select count(*) as ~val from ~auth_methods`)).toEqual('3'); + expect(await queryValue(`select count(*) as ~val from ~auth_methods_config`)).toEqual('1'); + expect(await queryValue(`select count(*) as ~val from ~config`)).toEqual('3'); + expect(await queryValue(`select ~value as ~val from ~auth_methods_config`)).toEqual('dbgate'); + expect( + await queryValue(`select ~value as ~val from ~config where ~group='license' and ~key='licenseKey'`) + ).toEqual('123467'); + expect(await queryValue(`select count(*) as ~val from ~role_permissions`)).toEqual('3'); + + DB1.auth_methods_config[0].value = 'dbgate2'; + DB1.config[2].value = '567'; + DB1.role_permissions.splice(2, 1); + + await dataReplicator(createDuplConfig(DB1)); + expect(await queryValue(`select count(*) as ~val from ~auth_methods_config`)).toEqual('1'); + expect(await queryValue(`select count(*) as ~val from ~config`)).toEqual('3'); + expect(await queryValue(`select ~value as ~val from ~auth_methods_config`)).toEqual('dbgate2'); + expect( + await queryValue(`select ~value as ~val from ~config where ~group='license' and ~key='licenseKey'`) + ).toEqual('567'); + expect(await queryValue(`select count(*) as ~val from ~role_permissions`)).toEqual('2'); + + // now add DB2 + await dataReplicator(createDuplConfig(DB2)); + + expect(await queryValue(`select count(*) as ~val from ~auth_methods`)).toEqual('4'); + expect(await queryValue(`select count(*) as ~val from ~auth_methods_config`)).toEqual('2'); + expect(await queryValue(`select count(*) as ~val from ~role_permissions`)).toEqual('3'); + + DB1.role_permissions.splice(1, 1); + await dataReplicator(createDuplConfig(DB1)); + expect(await queryValue(`select count(*) as ~val from ~role_permissions`)).toEqual('2'); + }) + ); +}); diff --git a/integration-tests/__tests__/query.spec.js b/integration-tests/__tests__/query.spec.js index 4f6896a54..2a2e662b2 100644 --- a/integration-tests/__tests__/query.spec.js +++ b/integration-tests/__tests__/query.spec.js @@ -188,7 +188,7 @@ describe('Query', () => { }) ); - test.each(engines.filter(x => !x.skipDataDuplicator).map(engine => [engine.label, engine]))( + test.each(engines.filter(x => !x.skipDataReplicator).map(engine => [engine.label, engine]))( 'Select scope identity - %s', testWrapper(async (conn, driver, engine) => { await runCommandOnDriver(conn, driver, dmp => diff --git a/integration-tests/docker-compose.yaml b/integration-tests/docker-compose.yaml index 911b78a31..6ea85877c 100644 --- a/integration-tests/docker-compose.yaml +++ b/integration-tests/docker-compose.yaml @@ -8,14 +8,14 @@ services: # ports: # - 15000:5432 # - # mariadb: - # image: mariadb - # command: --default-authentication-plugin=mysql_native_password - # restart: always - # ports: - # - 15004:3306 - # environment: - # - MYSQL_ROOT_PASSWORD=Pwd2020Db + mariadb: + image: mariadb + command: --default-authentication-plugin=mysql_native_password + restart: always + ports: + - 15004:3306 + environment: + - MYSQL_ROOT_PASSWORD=Pwd2020Db # mysql: # image: mysql:8.0.18 @@ -25,7 +25,7 @@ services: # - 15001:3306 # environment: # - MYSQL_ROOT_PASSWORD=Pwd2020Db - # + # cassandradb: # image: cassandra:5.0.2 @@ -81,11 +81,11 @@ services: # ports: # - 15006:1521 - libsql: - image: ghcr.io/tursodatabase/libsql-server:latest - platform: linux/amd64 - ports: - - '8080:8080' - - '5002:5001' - volumes: - - ./data/libsql:/var/lib/sqld + # libsql: + # image: ghcr.io/tursodatabase/libsql-server:latest + # platform: linux/amd64 + # ports: + # - '8080:8080' + # - '5002:5001' + # volumes: + # - ./data/libsql:/var/lib/sqld diff --git a/integration-tests/engines.js b/integration-tests/engines.js index 75ead4348..5b7f1eb02 100644 --- a/integration-tests/engines.js +++ b/integration-tests/engines.js @@ -551,7 +551,7 @@ const clickhouseEngine = { skipUnique: true, skipAutoIncrement: true, skipPkColumnTesting: true, - skipDataDuplicator: true, + skipDataReplicator: true, skipStringLength: true, alterTableAddColumnSyntax: true, dbSnapshotBySeconds: true, @@ -643,7 +643,7 @@ const cassandraEngine = { skipOrderBy: true, skipAutoIncrement: true, skipDataModifications: true, - skipDataDuplicator: true, + skipDataReplicator: true, skipDeploy: true, skipImportModel: true, @@ -673,14 +673,14 @@ const enginesOnLocal = [ // all engines, which would be run on local test // cassandraEngine, // mysqlEngine, - // mariaDbEngine, + mariaDbEngine, // postgreSqlEngine, // sqlServerEngine, // sqliteEngine, // cockroachDbEngine, // clickhouseEngine, // libsqlFileEngine, - libsqlWsEngine, + // libsqlWsEngine, // oracleEngine, ]; diff --git a/integration-tests/package.json b/integration-tests/package.json index 5e8bb394d..84c6f466c 100644 --- a/integration-tests/package.json +++ b/integration-tests/package.json @@ -12,7 +12,7 @@ "wait:local": "cross-env DEVMODE=1 LOCALTEST=1 node wait.js", "wait:ci": "cross-env DEVMODE=1 CITEST=1 node wait.js", "test:local": "cross-env DEVMODE=1 LOCALTEST=1 jest --testTimeout=5000", - "test:local:path": "cross-env DEVMODE=1 LOCALTEST=1 jest --runTestsByPath __tests__/data-duplicator.spec.js", + "test:local:path": "cross-env DEVMODE=1 LOCALTEST=1 jest --runTestsByPath __tests__/data-replicator.spec.js", "test:ci": "cross-env DEVMODE=1 CITEST=1 jest --runInBand --json --outputFile=result.json --testLocationInResults --detectOpenHandles --forceExit --testTimeout=10000", "run:local": "docker-compose down && docker-compose up -d && yarn wait:local && yarn test:local" }, diff --git a/packages/api/package.json b/packages/api/package.json index 0e1399f98..d330e31f2 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -22,6 +22,7 @@ "dependencies": { "@aws-sdk/rds-signer": "^3.665.0", "activedirectory2": "^2.1.0", + "archiver": "^7.0.1", "async-lock": "^1.2.6", "axios": "^0.21.1", "body-parser": "^1.19.0", @@ -62,7 +63,8 @@ "simple-encryptor": "^4.0.0", "ssh2": "^1.16.0", "stream-json": "^1.8.0", - "tar": "^6.0.5" + "tar": "^6.0.5", + "yauzl": "^3.2.0" }, "scripts": { "start": "env-cmd -f .env node src/index.js --listen-api", diff --git a/packages/api/src/controllers/archive.js b/packages/api/src/controllers/archive.js index d8e8e71c6..6491e2750 100644 --- a/packages/api/src/controllers/archive.js +++ b/packages/api/src/controllers/archive.js @@ -2,14 +2,20 @@ const fs = require('fs-extra'); const readline = require('readline'); const crypto = require('crypto'); const path = require('path'); -const { archivedir, clearArchiveLinksCache, resolveArchiveFolder } = require('../utility/directories'); +const { archivedir, clearArchiveLinksCache, resolveArchiveFolder, uploadsdir } = require('../utility/directories'); const socket = require('../utility/socket'); const loadFilesRecursive = require('../utility/loadFilesRecursive'); const getJslFileName = require('../utility/getJslFileName'); -const { getLogger, extractErrorLogData } = require('dbgate-tools'); +const { getLogger, extractErrorLogData, jsonLinesParse } = require('dbgate-tools'); const dbgateApi = require('../shell'); const jsldata = require('./jsldata'); const platformInfo = require('../utility/platformInfo'); +const { isProApp } = require('../utility/checkLicense'); +const listZipEntries = require('../utility/listZipEntries'); +const unzipJsonLinesFile = require('../shell/unzipJsonLinesFile'); +const { zip } = require('lodash'); +const zipDirectory = require('../shell/zipDirectory'); +const unzipDirectory = require('../shell/unzipDirectory'); const logger = getLogger('archive'); @@ -47,9 +53,31 @@ module.exports = { return folder; }, + async getZipFiles({ file }) { + const entries = await listZipEntries(path.join(archivedir(), file)); + const files = entries.map(entry => { + let name = entry.fileName; + if (isProApp() && entry.fileName.endsWith('.jsonl')) { + name = entry.fileName.slice(0, -6); + } + return { + name: name, + label: name, + type: isProApp() && entry.fileName.endsWith('.jsonl') ? 'jsonl' : 'other', + }; + }); + return files; + }, + files_meta: true, async files({ folder }) { try { + if (folder.endsWith('.zip')) { + if (await fs.exists(path.join(archivedir(), folder))) { + return this.getZipFiles({ file: folder }); + } + return []; + } const dir = resolveArchiveFolder(folder); if (!(await fs.exists(dir))) return []; const files = await loadFilesRecursive(dir); // fs.readdir(dir); @@ -91,6 +119,16 @@ module.exports = { return true; }, + createFile_meta: true, + async createFile({ folder, file, fileType, tableInfo }) { + await fs.writeFile( + path.join(resolveArchiveFolder(folder), `${file}.${fileType}`), + tableInfo ? JSON.stringify({ __isStreamHeader: true, tableInfo }) : '' + ); + socket.emitChanged(`archive-files-changed`, { folder }); + return true; + }, + deleteFile_meta: true, async deleteFile({ folder, file, fileType }) { await fs.unlink(path.join(resolveArchiveFolder(folder), `${file}.${fileType}`)); @@ -158,7 +196,7 @@ module.exports = { deleteFolder_meta: true, async deleteFolder({ folder }) { if (!folder) throw new Error('Missing folder parameter'); - if (folder.endsWith('.link')) { + if (folder.endsWith('.link') || folder.endsWith('.zip')) { await fs.unlink(path.join(archivedir(), folder)); } else { await fs.rmdir(path.join(archivedir(), folder), { recursive: true }); @@ -204,9 +242,10 @@ module.exports = { }, async getNewArchiveFolder({ database }) { - const isLink = database.endsWith(database); - const name = isLink ? database.slice(0, -5) : database; - const suffix = isLink ? '.link' : ''; + const isLink = database.endsWith('.link'); + const isZip = database.endsWith('.zip'); + const name = isLink ? database.slice(0, -5) : isZip ? database.slice(0, -4) : database; + const suffix = isLink ? '.link' : isZip ? '.zip' : ''; if (!(await fs.exists(path.join(archivedir(), database)))) return database; let index = 2; while (await fs.exists(path.join(archivedir(), `${name}${index}${suffix}`))) { @@ -214,4 +253,58 @@ module.exports = { } return `${name}${index}${suffix}`; }, + + getArchiveData_meta: true, + async getArchiveData({ folder, file }) { + let rows; + if (folder.endsWith('.zip')) { + rows = await unzipJsonLinesFile(path.join(archivedir(), folder), `${file}.jsonl`); + } else { + rows = jsonLinesParse(await fs.readFile(path.join(archivedir(), folder, `${file}.jsonl`), { encoding: 'utf8' })); + } + return rows.filter(x => !x.__isStreamHeader); + }, + + saveUploadedZip_meta: true, + async saveUploadedZip({ filePath, fileName }) { + if (!fileName?.endsWith('.zip')) { + throw new Error(`${fileName} is not a ZIP file`); + } + + const folder = await this.getNewArchiveFolder({ database: fileName }); + await fs.copyFile(filePath, path.join(archivedir(), folder)); + socket.emitChanged(`archive-folders-changed`); + + return null; + }, + + zip_meta: true, + async zip({ folder }) { + const newFolder = await this.getNewArchiveFolder({ database: folder + '.zip' }); + await zipDirectory(path.join(archivedir(), folder), path.join(archivedir(), newFolder)); + socket.emitChanged(`archive-folders-changed`); + + return null; + }, + + unzip_meta: true, + async unzip({ folder }) { + const newFolder = await this.getNewArchiveFolder({ database: folder.slice(0, -4) }); + await unzipDirectory(path.join(archivedir(), folder), path.join(archivedir(), newFolder)); + socket.emitChanged(`archive-folders-changed`); + + return null; + }, + + getZippedPath_meta: true, + async getZippedPath({ folder }) { + if (folder.endsWith('.zip')) { + return { filePath: path.join(archivedir(), folder) }; + } + + const uploadName = crypto.randomUUID(); + const filePath = path.join(uploadsdir(), uploadName); + await zipDirectory(path.join(archivedir(), folder), filePath); + return { filePath }; + }, }; diff --git a/packages/api/src/controllers/config.js b/packages/api/src/controllers/config.js index 451331c55..d3d777576 100644 --- a/packages/api/src/controllers/config.js +++ b/packages/api/src/controllers/config.js @@ -19,6 +19,14 @@ const storage = require('./storage'); const { getAuthProxyUrl } = require('../utility/authProxy'); const { getPublicHardwareFingerprint } = require('../utility/hardwareFingerprint'); const { extractErrorMessage } = require('dbgate-tools'); +const { + generateTransportEncryptionKey, + createTransportEncryptor, + recryptConnection, + getInternalEncryptor, + recryptUser, + recryptObjectPasswordFieldInPlace, +} = require('../utility/crypting'); const lock = new AsyncLock(); @@ -107,6 +115,7 @@ module.exports = { datadir(), processArgs.runE2eTests ? 'connections-e2etests.jsonl' : 'connections.jsonl' ), + supportCloudAutoUpgrade: !!process.env.CLOUD_UPGRADE_FILE, ...currentVersion, }; @@ -144,7 +153,7 @@ module.exports = { const res = { ...value, }; - if (value['app.useNativeMenu'] !== true && value['app.useNativeMenu'] !== false) { + if (platformInfo.isElectron && value['app.useNativeMenu'] !== true && value['app.useNativeMenu'] !== false) { // res['app.useNativeMenu'] = os.platform() == 'darwin' ? true : false; res['app.useNativeMenu'] = false; } @@ -161,14 +170,19 @@ module.exports = { async loadSettings() { try { - const settingsText = await fs.readFile( - path.join(datadir(), processArgs.runE2eTests ? 'settings-e2etests.json' : 'settings.json'), - { encoding: 'utf-8' } - ); - return { - ...this.fillMissingSettings(JSON.parse(settingsText)), - 'other.licenseKey': platformInfo.isElectron ? await this.loadLicenseKey() : undefined, - }; + if (process.env.STORAGE_DATABASE) { + const settings = await storage.readConfig({ group: 'settings' }); + return this.fillMissingSettings(settings); + } else { + const settingsText = await fs.readFile( + path.join(datadir(), processArgs.runE2eTests ? 'settings-e2etests.json' : 'settings.json'), + { encoding: 'utf-8' } + ); + return { + ...this.fillMissingSettings(JSON.parse(settingsText)), + 'other.licenseKey': platformInfo.isElectron ? await this.loadLicenseKey() : undefined, + }; + } } catch (err) { return this.fillMissingSettings({}); } @@ -246,19 +260,31 @@ module.exports = { const res = await lock.acquire('settings', async () => { const currentValue = await this.loadSettings(); try { - const updated = { - ...currentValue, - ..._.omit(values, ['other.licenseKey']), - }; - await fs.writeFile( - path.join(datadir(), processArgs.runE2eTests ? 'settings-e2etests.json' : 'settings.json'), - JSON.stringify(updated, undefined, 2) - ); - // this.settingsValue = updated; + let updated = currentValue; + if (process.env.STORAGE_DATABASE) { + updated = { + ...currentValue, + ...values, + }; + await storage.writeConfig({ + group: 'settings', + config: updated, + }); + } else { + updated = { + ...currentValue, + ..._.omit(values, ['other.licenseKey']), + }; + await fs.writeFile( + path.join(datadir(), processArgs.runE2eTests ? 'settings-e2etests.json' : 'settings.json'), + JSON.stringify(updated, undefined, 2) + ); + // this.settingsValue = updated; - if (currentValue['other.licenseKey'] != values['other.licenseKey']) { - await this.saveLicenseKey({ licenseKey: values['other.licenseKey'] }); - socket.emitChanged(`config-changed`); + if (currentValue['other.licenseKey'] != values['other.licenseKey']) { + await this.saveLicenseKey({ licenseKey: values['other.licenseKey'] }); + socket.emitChanged(`config-changed`); + } } socket.emitChanged(`settings-changed`); @@ -281,4 +307,91 @@ module.exports = { const resp = await checkLicenseKey(licenseKey); return resp; }, + + recryptDatabaseForExport(db) { + const encryptionKey = generateTransportEncryptionKey(); + const transportEncryptor = createTransportEncryptor(encryptionKey); + + const config = _.cloneDeep([ + ...(db.config?.filter(c => !(c.group == 'admin' && c.key == 'encryptionKey')) || []), + { group: 'admin', key: 'encryptionKey', value: encryptionKey }, + ]); + const adminPassword = config.find(c => c.group == 'admin' && c.key == 'adminPassword'); + recryptObjectPasswordFieldInPlace(adminPassword, 'value', getInternalEncryptor(), transportEncryptor); + + return { + ...db, + connections: db.connections?.map(conn => recryptConnection(conn, getInternalEncryptor(), transportEncryptor)), + users: db.users?.map(conn => recryptUser(conn, getInternalEncryptor(), transportEncryptor)), + config, + }; + }, + + recryptDatabaseFromImport(db) { + const encryptionKey = db.config?.find(c => c.group == 'admin' && c.key == 'encryptionKey')?.value; + if (!encryptionKey) { + throw new Error('Missing encryption key in the database'); + } + const config = _.cloneDeep(db.config || []).filter(c => !(c.group == 'admin' && c.key == 'encryptionKey')); + const transportEncryptor = createTransportEncryptor(encryptionKey); + + const adminPassword = config.find(c => c.group == 'admin' && c.key == 'adminPassword'); + recryptObjectPasswordFieldInPlace(adminPassword, 'value', transportEncryptor, getInternalEncryptor()); + + return { + ...db, + connections: db.connections?.map(conn => recryptConnection(conn, transportEncryptor, getInternalEncryptor())), + users: db.users?.map(conn => recryptUser(conn, transportEncryptor, getInternalEncryptor())), + config, + }; + }, + + exportConnectionsAndSettings_meta: true, + async exportConnectionsAndSettings(_params, req) { + if (!hasPermission(`admin/config`, req)) { + throw new Error('Permission denied: admin/config'); + } + + if (connections.portalConnections) { + throw new Error('Not allowed'); + } + + if (process.env.STORAGE_DATABASE) { + const db = await storage.getExportedDatabase(); + return this.recryptDatabaseForExport(db); + } + + return this.recryptDatabaseForExport({ + connections: (await connections.list(null, req)).map((conn, index) => ({ + ..._.omit(conn, ['_id']), + id: index + 1, + conid: conn._id, + })), + }); + }, + + importConnectionsAndSettings_meta: true, + async importConnectionsAndSettings({ db }, req) { + if (!hasPermission(`admin/config`, req)) { + throw new Error('Permission denied: admin/config'); + } + + if (connections.portalConnections) { + throw new Error('Not allowed'); + } + + const recryptedDb = this.recryptDatabaseFromImport(db); + if (process.env.STORAGE_DATABASE) { + await storage.replicateImportedDatabase(recryptedDb); + } else { + await connections.importFromArray( + recryptedDb.connections.map(conn => ({ + ..._.omit(conn, ['conid', 'id']), + _id: conn.conid, + })) + ); + } + + return true; + }, }; diff --git a/packages/api/src/controllers/connections.js b/packages/api/src/controllers/connections.js index bf6b86544..43690a646 100644 --- a/packages/api/src/controllers/connections.js +++ b/packages/api/src/controllers/connections.js @@ -102,8 +102,8 @@ function getPortalCollections() { trustServerCertificate: process.env[`SSL_TRUST_CERTIFICATE_${id}`], })); - for(const conn of connections) { - for(const prop in process.env) { + for (const conn of connections) { + for (const prop in process.env) { if (prop.startsWith(`CONNECTION_${conn._id}_`)) { const name = prop.substring(`CONNECTION_${conn._id}_`.length); conn[name] = process.env[prop]; @@ -316,6 +316,18 @@ module.exports = { return res; }, + importFromArray(list) { + this.datastore.transformAll(connections => { + const mapped = connections.map(x => { + const found = list.find(y => y._id == x._id); + if (found) return found; + return x; + }); + return [...mapped, ...list.filter(x => !connections.find(y => y._id == x._id))]; + }); + socket.emitChanged('connection-list-changed'); + }, + async checkUnsavedConnectionsLimit() { if (!this.datastore) { return; diff --git a/packages/api/src/controllers/files.js b/packages/api/src/controllers/files.js index d44fb2863..cc7d86264 100644 --- a/packages/api/src/controllers/files.js +++ b/packages/api/src/controllers/files.js @@ -9,6 +9,9 @@ const scheduler = require('./scheduler'); const getDiagramExport = require('../utility/getDiagramExport'); const apps = require('./apps'); const getMapExport = require('../utility/getMapExport'); +const dbgateApi = require('../shell'); +const { getLogger } = require('dbgate-tools'); +const logger = getLogger('files'); function serialize(format, data) { if (format == 'text') return data; @@ -219,4 +222,60 @@ module.exports = { return path.join(dir, file); } }, + + createZipFromJsons_meta: true, + async createZipFromJsons({ db, filePath }) { + logger.info(`Creating zip file from JSONS ${filePath}`); + await dbgateApi.zipJsonLinesData(db, filePath); + return true; + }, + + getJsonsFromZip_meta: true, + async getJsonsFromZip({ filePath }) { + const res = await dbgateApi.unzipJsonLinesData(filePath); + return res; + }, + + downloadText_meta: true, + async downloadText({ uri }, req) { + if (!uri) return null; + const filePath = await dbgateApi.download(uri); + const text = await fs.readFile(filePath, { + encoding: 'utf-8', + }); + return text; + }, + + saveUploadedFile_meta: true, + async saveUploadedFile({ filePath, fileName }) { + const FOLDERS = ['sql', 'sqlite']; + for (const folder of FOLDERS) { + if (fileName.toLowerCase().endsWith('.' + folder)) { + logger.info(`Saving ${folder} file ${fileName}`); + await fs.copyFile(filePath, path.join(filesdir(), folder, fileName)); + + socket.emitChanged(`files-changed`, { folder: folder }); + socket.emitChanged(`all-files-changed`); + return { + name: path.basename(filePath), + folder: folder, + }; + } + } + + throw new Error(`${fileName} doesn't have one of supported extensions: ${FOLDERS.join(', ')}`); + }, + + exportFile_meta: true, + async exportFile({ folder, file, filePath }, req) { + if (!hasPermission(`files/${folder}/read`, req)) return false; + await fs.copyFile(path.join(filesdir(), folder, file), filePath); + return true; + }, + + simpleCopy_meta: true, + async simpleCopy({ sourceFilePath, targetFilePath }, req) { + await fs.copyFile(sourceFilePath, targetFilePath); + return true; + }, }; diff --git a/packages/api/src/controllers/jsldata.js b/packages/api/src/controllers/jsldata.js index 448ba5d3f..be6e1bf84 100644 --- a/packages/api/src/controllers/jsldata.js +++ b/packages/api/src/controllers/jsldata.js @@ -8,6 +8,8 @@ const getJslFileName = require('../utility/getJslFileName'); const JsonLinesDatastore = require('../utility/JsonLinesDatastore'); const requirePluginFunction = require('../utility/requirePluginFunction'); const socket = require('../utility/socket'); +const crypto = require('crypto'); +const dbgateApi = require('../shell'); function readFirstLine(file) { return new Promise((resolve, reject) => { @@ -293,4 +295,11 @@ module.exports = { })), }; }, + + downloadJslData_meta: true, + async downloadJslData({ uri }) { + const jslid = crypto.randomUUID(); + await dbgateApi.download(uri, { targetFile: getJslFileName(jslid) }); + return { jslid }; + }, }; diff --git a/packages/api/src/controllers/runners.js b/packages/api/src/controllers/runners.js index 39e205e82..1a11319a3 100644 --- a/packages/api/src/controllers/runners.js +++ b/packages/api/src/controllers/runners.js @@ -96,9 +96,9 @@ module.exports = { handle_ping() {}, - handle_freeData(runid, { freeData }) { + handle_dataResult(runid, { dataResult }) { const { resolve } = this.requests[runid]; - resolve(freeData); + resolve(dataResult); delete this.requests[runid]; }, @@ -328,4 +328,24 @@ module.exports = { }); return promise; }, + + scriptResult_meta: true, + async scriptResult({ script }) { + if (script.type != 'json') { + return { errorMessage: 'Only JSON scripts are allowed' }; + } + + const promise = new Promise((resolve, reject) => { + const runid = crypto.randomUUID(); + this.requests[runid] = { resolve, reject, exitOnStreamError: true }; + const cloned = _.cloneDeepWith(script, node => { + if (node?.$replace == 'runid') { + return runid; + } + }); + const js = jsonScriptToJavascript(cloned); + this.startCore(runid, scriptTemplate(js, false)); + }); + return promise; + }, }; diff --git a/packages/api/src/controllers/uploads.js b/packages/api/src/controllers/uploads.js index b406a7599..4e0b9bd2a 100644 --- a/packages/api/src/controllers/uploads.js +++ b/packages/api/src/controllers/uploads.js @@ -39,52 +39,6 @@ module.exports = { }); }, - uploadDataFile_meta: { - method: 'post', - raw: true, - }, - uploadDataFile(req, res) { - const { data } = req.files || {}; - - if (!data) { - res.json(null); - return; - } - - if (data.name.toLowerCase().endsWith('.sql')) { - logger.info(`Uploading SQL file ${data.name}, size=${data.size}`); - data.mv(path.join(filesdir(), 'sql', data.name), () => { - res.json({ - name: data.name, - folder: 'sql', - }); - - socket.emitChanged(`files-changed`, { folder: 'sql' }); - socket.emitChanged(`all-files-changed`); - }); - return; - } - - res.json(null); - }, - - saveDataFile_meta: true, - async saveDataFile({ filePath }) { - if (filePath.toLowerCase().endsWith('.sql')) { - logger.info(`Saving SQL file ${filePath}`); - await fs.copyFile(filePath, path.join(filesdir(), 'sql', path.basename(filePath))); - - socket.emitChanged(`files-changed`, { folder: 'sql' }); - socket.emitChanged(`all-files-changed`); - return { - name: path.basename(filePath), - folder: 'sql', - }; - } - - return null; - }, - get_meta: { method: 'get', raw: true, diff --git a/packages/api/src/shell/archiveReader.js b/packages/api/src/shell/archiveReader.js index 3a6005664..87974bf23 100644 --- a/packages/api/src/shell/archiveReader.js +++ b/packages/api/src/shell/archiveReader.js @@ -3,7 +3,9 @@ const { archivedir, resolveArchiveFolder } = require('../utility/directories'); const jsonLinesReader = require('./jsonLinesReader'); function archiveReader({ folderName, fileName, ...other }) { - const jsonlFile = path.join(resolveArchiveFolder(folderName), `${fileName}.jsonl`); + const jsonlFile = folderName.endsWith('.zip') + ? `zip://archive:${folderName}//${fileName}.jsonl` + : path.join(resolveArchiveFolder(folderName), `${fileName}.jsonl`); const res = jsonLinesReader({ fileName: jsonlFile, ...other }); return res; } diff --git a/packages/api/src/shell/collectorWriter.js b/packages/api/src/shell/collectorWriter.js index c896e3d07..c62e5d35f 100644 --- a/packages/api/src/shell/collectorWriter.js +++ b/packages/api/src/shell/collectorWriter.js @@ -15,9 +15,9 @@ class CollectorWriterStream extends stream.Writable { _final(callback) { process.send({ - msgtype: 'freeData', + msgtype: 'dataResult', runid: this.runid, - freeData: { rows: this.rows, structure: this.structure }, + dataResult: { rows: this.rows, structure: this.structure }, }); callback(); } diff --git a/packages/api/src/shell/dataDuplicator.js b/packages/api/src/shell/dataDuplicator.js deleted file mode 100644 index e08ede4cf..000000000 --- a/packages/api/src/shell/dataDuplicator.js +++ /dev/null @@ -1,61 +0,0 @@ -const stream = require('stream'); -const path = require('path'); -const { quoteFullName, fullNameToString, getLogger } = require('dbgate-tools'); -const requireEngineDriver = require('../utility/requireEngineDriver'); -const { connectUtility } = require('../utility/connectUtility'); -const logger = getLogger('dataDuplicator'); -const { DataDuplicator } = require('dbgate-datalib'); -const copyStream = require('./copyStream'); -const jsonLinesReader = require('./jsonLinesReader'); -const { resolveArchiveFolder } = require('../utility/directories'); - -async function dataDuplicator({ - connection, - archive, - folder, - items, - options, - analysedStructure = null, - driver, - systemConnection, -}) { - if (!driver) driver = requireEngineDriver(connection); - - const dbhan = systemConnection || (await connectUtility(driver, connection, 'write')); - - try { - if (!analysedStructure) { - analysedStructure = await driver.analyseFull(dbhan); - } - - const sourceDir = archive - ? resolveArchiveFolder(archive) - : folder?.startsWith('archive:') - ? resolveArchiveFolder(folder.substring('archive:'.length)) - : folder; - - const dupl = new DataDuplicator( - dbhan, - driver, - analysedStructure, - items.map(item => ({ - name: item.name, - operation: item.operation, - matchColumns: item.matchColumns, - openStream: - item.openStream || (() => jsonLinesReader({ fileName: path.join(sourceDir, `${item.name}.jsonl`) })), - })), - stream, - copyStream, - options - ); - - await dupl.run(); - } finally { - if (!systemConnection) { - await driver.close(dbhan); - } - } -} - -module.exports = dataDuplicator; diff --git a/packages/api/src/shell/dataReplicator.js b/packages/api/src/shell/dataReplicator.js new file mode 100644 index 000000000..cc97b1a7e --- /dev/null +++ b/packages/api/src/shell/dataReplicator.js @@ -0,0 +1,96 @@ +const stream = require('stream'); +const path = require('path'); +const { quoteFullName, fullNameToString, getLogger } = require('dbgate-tools'); +const requireEngineDriver = require('../utility/requireEngineDriver'); +const { connectUtility } = require('../utility/connectUtility'); +const logger = getLogger('datareplicator'); +const { DataReplicator } = require('dbgate-datalib'); +const { compileCompoudEvalCondition } = require('dbgate-filterparser'); +const copyStream = require('./copyStream'); +const jsonLinesReader = require('./jsonLinesReader'); +const { resolveArchiveFolder } = require('../utility/directories'); +const { evaluateCondition } = require('dbgate-sqltree'); + +function compileOperationFunction(enabled, condition) { + if (!enabled) return _row => false; + const conditionCompiled = compileCompoudEvalCondition(condition); + if (condition) { + return row => evaluateCondition(conditionCompiled, row); + } + return _row => true; +} + +async function dataReplicator({ + connection, + archive, + folder, + items, + options, + analysedStructure = null, + driver, + systemConnection, +}) { + if (!driver) driver = requireEngineDriver(connection); + + const dbhan = systemConnection || (await connectUtility(driver, connection, 'write')); + + try { + if (!analysedStructure) { + analysedStructure = await driver.analyseFull(dbhan); + } + + let joinPath; + + if (archive?.endsWith('.zip')) { + joinPath = file => `zip://archive:${archive}//${file}`; + } else { + const sourceDir = archive + ? resolveArchiveFolder(archive) + : folder?.startsWith('archive:') + ? resolveArchiveFolder(folder.substring('archive:'.length)) + : folder; + joinPath = file => path.join(sourceDir, file); + } + + const repl = new DataReplicator( + dbhan, + driver, + analysedStructure, + items.map(item => { + return { + name: item.name, + matchColumns: item.matchColumns, + findExisting: compileOperationFunction(item.findExisting, item.findCondition), + createNew: compileOperationFunction(item.createNew, item.createCondition), + updateExisting: compileOperationFunction(item.updateExisting, item.updateCondition), + deleteMissing: !!item.deleteMissing, + deleteRestrictionColumns: item.deleteRestrictionColumns ?? [], + openStream: item.openStream + ? item.openStream + : item.jsonArray + ? () => stream.Readable.from(item.jsonArray) + : () => jsonLinesReader({ fileName: joinPath(`${item.name}.jsonl`) }), + }; + }), + stream, + copyStream, + options + ); + + await repl.run(); + if (options?.runid) { + process.send({ + msgtype: 'dataResult', + runid: options?.runid, + dataResult: repl.result, + }); + } + return repl.result; + } finally { + if (!systemConnection) { + await driver.close(dbhan); + } + } +} + +module.exports = dataReplicator; diff --git a/packages/api/src/shell/download.js b/packages/api/src/shell/download.js index 888b8a601..1a535419c 100644 --- a/packages/api/src/shell/download.js +++ b/packages/api/src/shell/download.js @@ -1,14 +1,30 @@ const crypto = require('crypto'); const path = require('path'); -const { uploadsdir } = require('../utility/directories'); +const { uploadsdir, archivedir } = require('../utility/directories'); const { downloadFile } = require('../utility/downloader'); +const extractSingleFileFromZip = require('../utility/extractSingleFileFromZip'); -async function download(url) { - if (url && url.match(/(^http:\/\/)|(^https:\/\/)/)) { - const tmpFile = path.join(uploadsdir(), crypto.randomUUID()); - await downloadFile(url, tmpFile); - return tmpFile; +async function download(url, options = {}) { + const { targetFile } = options || {}; + if (url) { + if (url.match(/(^http:\/\/)|(^https:\/\/)/)) { + const destFile = targetFile || path.join(uploadsdir(), crypto.randomUUID()); + await downloadFile(url, destFile); + return destFile; + } + const zipMatch = url.match(/^zip\:\/\/(.*)\/\/(.*)$/); + if (zipMatch) { + const destFile = targetFile || path.join(uploadsdir(), crypto.randomUUID()); + let zipFile = zipMatch[1]; + if (zipFile.startsWith('archive:')) { + zipFile = path.join(archivedir(), zipFile.substring('archive:'.length)); + } + + await extractSingleFileFromZip(zipFile, zipMatch[2], destFile); + return destFile; + } } + return url; } diff --git a/packages/api/src/shell/index.js b/packages/api/src/shell/index.js index b1bd1f083..363d3e5ae 100644 --- a/packages/api/src/shell/index.js +++ b/packages/api/src/shell/index.js @@ -25,7 +25,7 @@ const importDatabase = require('./importDatabase'); const loadDatabase = require('./loadDatabase'); const generateModelSql = require('./generateModelSql'); const modifyJsonLinesReader = require('./modifyJsonLinesReader'); -const dataDuplicator = require('./dataDuplicator'); +const dataReplicator = require('./dataReplicator'); const dbModelToJson = require('./dbModelToJson'); const jsonToDbModel = require('./jsonToDbModel'); const jsonReader = require('./jsonReader'); @@ -35,6 +35,11 @@ const autoIndexForeignKeysTransform = require('./autoIndexForeignKeysTransform') const generateDeploySql = require('./generateDeploySql'); const dropAllDbObjects = require('./dropAllDbObjects'); const importDbFromFolder = require('./importDbFromFolder'); +const zipDirectory = require('./zipDirectory'); +const unzipDirectory = require('./unzipDirectory'); +const zipJsonLinesData = require('./zipJsonLinesData'); +const unzipJsonLinesData = require('./unzipJsonLinesData'); +const unzipJsonLinesFile = require('./unzipJsonLinesFile'); const dbgateApi = { queryReader, @@ -64,7 +69,7 @@ const dbgateApi = { loadDatabase, generateModelSql, modifyJsonLinesReader, - dataDuplicator, + dataReplicator, dbModelToJson, jsonToDbModel, dataTypeMapperTransform, @@ -73,6 +78,11 @@ const dbgateApi = { generateDeploySql, dropAllDbObjects, importDbFromFolder, + zipDirectory, + unzipDirectory, + zipJsonLinesData, + unzipJsonLinesData, + unzipJsonLinesFile, }; requirePlugin.initializeDbgateApi(dbgateApi); diff --git a/packages/api/src/shell/jsonLinesWriter.js b/packages/api/src/shell/jsonLinesWriter.js index 0e12de262..3d4cad8c0 100644 --- a/packages/api/src/shell/jsonLinesWriter.js +++ b/packages/api/src/shell/jsonLinesWriter.js @@ -36,9 +36,10 @@ async function jsonLinesWriter({ fileName, encoding = 'utf-8', header = true }) logger.info(`Writing file ${fileName}`); const stringify = new StringifyStream({ header }); const fileStream = fs.createWriteStream(fileName, encoding); - stringify.pipe(fileStream); - stringify['finisher'] = fileStream; - return stringify; + return [stringify, fileStream]; + // stringify.pipe(fileStream); + // stringify['finisher'] = fileStream; + // return stringify; } module.exports = jsonLinesWriter; diff --git a/packages/api/src/shell/unzipDirectory.js b/packages/api/src/shell/unzipDirectory.js new file mode 100644 index 000000000..61133ad02 --- /dev/null +++ b/packages/api/src/shell/unzipDirectory.js @@ -0,0 +1,91 @@ +const yauzl = require('yauzl'); +const fs = require('fs'); +const path = require('path'); +const { getLogger, extractErrorLogData } = require('dbgate-tools'); + +const logger = getLogger('unzipDirectory'); + +/** + * Extracts an entire ZIP file, preserving its internal directory layout. + * + * @param {string} zipPath Path to the ZIP file on disk. + * @param {string} outputDirectory Folder to create / overwrite with the contents. + * @returns {Promise} Resolves `true` on success, rejects on error. + */ +function unzipDirectory(zipPath, outputDirectory) { + return new Promise((resolve, reject) => { + yauzl.open(zipPath, { lazyEntries: true }, (err, zipFile) => { + if (err) return reject(err); + + /** Pending per-file extractions – we resolve the main promise after they’re all done */ + const pending = []; + + // kick things off + zipFile.readEntry(); + + zipFile.on('entry', entry => { + const destPath = path.join(outputDirectory, entry.fileName); + + // Handle directories (their names always end with “/” in ZIPs) + if (/\/$/.test(entry.fileName)) { + // Ensure directory exists, then continue to next entry + fs.promises + .mkdir(destPath, { recursive: true }) + .then(() => zipFile.readEntry()) + .catch(reject); + return; + } + + // Handle files + const filePromise = fs.promises + .mkdir(path.dirname(destPath), { recursive: true }) // make sure parent dirs exist + .then( + () => + new Promise((res, rej) => { + zipFile.openReadStream(entry, (err, readStream) => { + if (err) return rej(err); + + const writeStream = fs.createWriteStream(destPath); + readStream.pipe(writeStream); + + // proceed to next entry once we’ve consumed *this* one + readStream.on('end', () => zipFile.readEntry()); + + writeStream.on('finish', () => { + logger.info(`Extracted "${entry.fileName}" → "${destPath}".`); + res(); + }); + + writeStream.on('error', writeErr => { + logger.error( + extractErrorLogData(writeErr), + `Error extracting "${entry.fileName}" from "${zipPath}".` + ); + rej(writeErr); + }); + }); + }) + ); + + pending.push(filePromise); + }); + + // Entire archive enumerated; wait for all streams to finish + zipFile.on('end', () => { + Promise.all(pending) + .then(() => { + logger.info(`Archive "${zipPath}" fully extracted to "${outputDirectory}".`); + resolve(true); + }) + .catch(reject); + }); + + zipFile.on('error', err => { + logger.error(extractErrorLogData(err), `ZIP file error in ${zipPath}.`); + reject(err); + }); + }); + }); +} + +module.exports = unzipDirectory; diff --git a/packages/api/src/shell/unzipJsonLinesData.js b/packages/api/src/shell/unzipJsonLinesData.js new file mode 100644 index 000000000..87c2a6568 --- /dev/null +++ b/packages/api/src/shell/unzipJsonLinesData.js @@ -0,0 +1,60 @@ +const yauzl = require('yauzl'); +const fs = require('fs'); +const { jsonLinesParse } = require('dbgate-tools'); + +function unzipJsonLinesData(zipPath) { + return new Promise((resolve, reject) => { + // Open the zip file + yauzl.open(zipPath, { lazyEntries: true }, (err, zipfile) => { + if (err) { + return reject(err); + } + + const results = {}; + + // Start reading entries + zipfile.readEntry(); + + zipfile.on('entry', entry => { + // Only process .json files + if (/\.jsonl$/i.test(entry.fileName)) { + zipfile.openReadStream(entry, (err, readStream) => { + if (err) { + return reject(err); + } + + const chunks = []; + readStream.on('data', chunk => chunks.push(chunk)); + readStream.on('end', () => { + try { + const fileContent = Buffer.concat(chunks).toString('utf-8'); + const parsedJson = jsonLinesParse(fileContent); + results[entry.fileName.replace(/\.jsonl$/, '')] = parsedJson; + } catch (parseError) { + return reject(parseError); + } + + // Move to the next entry + zipfile.readEntry(); + }); + }); + } else { + // Not a JSON file, skip + zipfile.readEntry(); + } + }); + + // Resolve when no more entries + zipfile.on('end', () => { + resolve(results); + }); + + // Catch errors from zipfile + zipfile.on('error', zipErr => { + reject(zipErr); + }); + }); + }); +} + +module.exports = unzipJsonLinesData; diff --git a/packages/api/src/shell/unzipJsonLinesFile.js b/packages/api/src/shell/unzipJsonLinesFile.js new file mode 100644 index 000000000..f8df709de --- /dev/null +++ b/packages/api/src/shell/unzipJsonLinesFile.js @@ -0,0 +1,59 @@ +const yauzl = require('yauzl'); +const fs = require('fs'); +const { jsonLinesParse } = require('dbgate-tools'); + +function unzipJsonLinesFile(zipPath, fileInZip) { + return new Promise((resolve, reject) => { + // Open the zip file + yauzl.open(zipPath, { lazyEntries: true }, (err, zipfile) => { + if (err) { + return reject(err); + } + + let result = null; + + // Start reading entries + zipfile.readEntry(); + + zipfile.on('entry', entry => { + if (entry.fileName == fileInZip) { + zipfile.openReadStream(entry, (err, readStream) => { + if (err) { + return reject(err); + } + + const chunks = []; + readStream.on('data', chunk => chunks.push(chunk)); + readStream.on('end', () => { + try { + const fileContent = Buffer.concat(chunks).toString('utf-8'); + const parsedJson = jsonLinesParse(fileContent); + result = parsedJson; + } catch (parseError) { + return reject(parseError); + } + + // Move to the next entry + zipfile.readEntry(); + }); + }); + } else { + // Not a JSON file, skip + zipfile.readEntry(); + } + }); + + // Resolve when no more entries + zipfile.on('end', () => { + resolve(result); + }); + + // Catch errors from zipfile + zipfile.on('error', zipErr => { + reject(zipErr); + }); + }); + }); +} + +module.exports = unzipJsonLinesFile; diff --git a/packages/api/src/shell/zipDirectory.js b/packages/api/src/shell/zipDirectory.js new file mode 100644 index 000000000..863905e39 --- /dev/null +++ b/packages/api/src/shell/zipDirectory.js @@ -0,0 +1,49 @@ +const fs = require('fs'); +const path = require('path'); +const archiver = require('archiver'); +const { getLogger, extractErrorLogData } = require('dbgate-tools'); +const { archivedir } = require('../utility/directories'); +const logger = getLogger('compressDirectory'); + +function zipDirectory(inputDirectory, outputFile) { + if (outputFile.startsWith('archive:')) { + outputFile = path.join(archivedir(), outputFile.substring('archive:'.length)); + } + + return new Promise((resolve, reject) => { + const output = fs.createWriteStream(outputFile); + const archive = archiver('zip', { zlib: { level: 9 } }); // level: 9 => best compression + + // Listen for all archive data to be written + output.on('close', () => { + logger.info(`ZIP file created (${archive.pointer()} total bytes)`); + resolve(); + }); + + archive.on('warning', err => { + logger.warn(extractErrorLogData(err), `Warning while creating ZIP: ${err.message}`); + }); + + archive.on('error', err => { + logger.error(extractErrorLogData(err), `Error while creating ZIP: ${err.message}`); + reject(err); + }); + + // Pipe archive data to the file + archive.pipe(output); + + // Append files from a folder + archive.directory(inputDirectory, false, entryData => { + if (entryData.name.endsWith('.zip')) { + return false; // returning false means "do not include" + } + // otherwise, include it + return entryData; + }); + + // Finalize the archive + archive.finalize(); + }); +} + +module.exports = zipDirectory; diff --git a/packages/api/src/shell/zipJsonLinesData.js b/packages/api/src/shell/zipJsonLinesData.js new file mode 100644 index 000000000..d36f40324 --- /dev/null +++ b/packages/api/src/shell/zipJsonLinesData.js @@ -0,0 +1,49 @@ +const fs = require('fs'); +const _ = require('lodash'); +const path = require('path'); +const archiver = require('archiver'); +const { getLogger, extractErrorLogData, jsonLinesStringify } = require('dbgate-tools'); +const { archivedir } = require('../utility/directories'); +const logger = getLogger('compressDirectory'); + +function zipDirectory(jsonDb, outputFile) { + if (outputFile.startsWith('archive:')) { + outputFile = path.join(archivedir(), outputFile.substring('archive:'.length)); + } + + return new Promise((resolve, reject) => { + const output = fs.createWriteStream(outputFile); + const archive = archiver('zip', { zlib: { level: 9 } }); // level: 9 => best compression + + // Listen for all archive data to be written + output.on('close', () => { + logger.info(`ZIP file created (${archive.pointer()} total bytes)`); + resolve(); + }); + + archive.on('warning', err => { + logger.warn(extractErrorLogData(err), `Warning while creating ZIP: ${err.message}`); + }); + + archive.on('error', err => { + logger.error(extractErrorLogData(err), `Error while creating ZIP: ${err.message}`); + reject(err); + }); + + // Pipe archive data to the file + archive.pipe(output); + + for (const key in jsonDb) { + const data = jsonDb[key]; + if (_.isArray(data)) { + const jsonString = jsonLinesStringify(data); + archive.append(jsonString, { name: `${key}.jsonl` }); + } + } + + // Finalize the archive + archive.finalize(); + }); +} + +module.exports = zipDirectory; diff --git a/packages/api/src/utility/cloudUpgrade.js b/packages/api/src/utility/cloudUpgrade.js index 12d60868e..e9844eca0 100644 --- a/packages/api/src/utility/cloudUpgrade.js +++ b/packages/api/src/utility/cloudUpgrade.js @@ -4,11 +4,20 @@ const fsp = require('fs/promises'); const semver = require('semver'); const currentVersion = require('../currentVersion'); const { getLogger, extractErrorLogData } = require('dbgate-tools'); +const { storageReadConfig } = require('../controllers/storageDb'); const logger = getLogger('cloudUpgrade'); async function checkCloudUpgrade() { try { + if (process.env.STORAGE_DATABASE) { + const settings = await storageReadConfig('settings'); + if (settings['cloud.useAutoUpgrade'] != 1) { + // auto-upgrade not allowed + return; + } + } + const resp = await axios.default.get('https://api.github.com/repos/dbgate/dbgate/releases/latest'); const json = resp.data; const version = json.name.substring(1); @@ -43,7 +52,11 @@ async function checkCloudUpgrade() { logger.info(`Downloaded new version from ${zipUrl}`); } else { - logger.info(`Checked version ${version} is not newer than ${cloudDownloadedVersion ?? currentVersion.version}, upgrade skippped`); + logger.info( + `Checked version ${version} is not newer than ${ + cloudDownloadedVersion ?? currentVersion.version + }, upgrade skippped` + ); } } catch (err) { logger.error(extractErrorLogData(err), 'Error checking cloud upgrade'); diff --git a/packages/api/src/utility/crypting.js b/packages/api/src/utility/crypting.js index 19f310777..171b75904 100644 --- a/packages/api/src/utility/crypting.js +++ b/packages/api/src/utility/crypting.js @@ -59,7 +59,7 @@ async function loadEncryptionKeyFromExternal(storedValue, setStoredValue) { let _encryptor = null; -function getEncryptor() { +function getInternalEncryptor() { if (_encryptor) { return _encryptor; } @@ -69,14 +69,14 @@ function getEncryptor() { function encryptPasswordString(password) { if (password && !password.startsWith('crypt:')) { - return 'crypt:' + getEncryptor().encrypt(password); + return 'crypt:' + getInternalEncryptor().encrypt(password); } return password; } function decryptPasswordString(password) { if (password && password.startsWith('crypt:')) { - return getEncryptor().decrypt(password.substring('crypt:'.length)); + return getInternalEncryptor().decrypt(password.substring('crypt:'.length)); } return password; } @@ -85,7 +85,7 @@ function encryptObjectPasswordField(obj, field) { if (obj && obj[field] && !obj[field].startsWith('crypt:')) { return { ...obj, - [field]: 'crypt:' + getEncryptor().encrypt(obj[field]), + [field]: 'crypt:' + getInternalEncryptor().encrypt(obj[field]), }; } return obj; @@ -95,7 +95,7 @@ function decryptObjectPasswordField(obj, field) { if (obj && obj[field] && obj[field].startsWith('crypt:')) { return { ...obj, - [field]: getEncryptor().decrypt(obj[field].substring('crypt:'.length)), + [field]: getInternalEncryptor().decrypt(obj[field].substring('crypt:'.length)), }; } return obj; @@ -156,6 +156,49 @@ function getEncryptionKey() { return _encryptionKey; } +function generateTransportEncryptionKey() { + const encryptor = simpleEncryptor.createEncryptor(defaultEncryptionKey); + const result = { + encryptionKey: crypto.randomBytes(32).toString('hex'), + }; + return encryptor.encrypt(result); +} + +function createTransportEncryptor(encryptionData) { + const encryptor = simpleEncryptor.createEncryptor(defaultEncryptionKey); + const data = encryptor.decrypt(encryptionData); + const res = simpleEncryptor.createEncryptor(data['encryptionKey']); + return res; +} + +function recryptObjectPasswordField(obj, field, decryptEncryptor, encryptEncryptor) { + if (obj && obj[field] && obj[field].startsWith('crypt:')) { + return { + ...obj, + [field]: 'crypt:' + encryptEncryptor.encrypt(decryptEncryptor.decrypt(obj[field].substring('crypt:'.length))), + }; + } + return obj; +} + +function recryptObjectPasswordFieldInPlace(obj, field, decryptEncryptor, encryptEncryptor) { + if (obj && obj[field] && obj[field].startsWith('crypt:')) { + obj[field] = 'crypt:' + encryptEncryptor.encrypt(decryptEncryptor.decrypt(obj[field].substring('crypt:'.length))); + } +} + +function recryptConnection(connection, decryptEncryptor, encryptEncryptor) { + connection = recryptObjectPasswordField(connection, 'password', decryptEncryptor, encryptEncryptor); + connection = recryptObjectPasswordField(connection, 'sshPassword', decryptEncryptor, encryptEncryptor); + connection = recryptObjectPasswordField(connection, 'sshKeyfilePassword', decryptEncryptor, encryptEncryptor); + return connection; +} + +function recryptUser(user, decryptEncryptor, encryptEncryptor) { + user = recryptObjectPasswordField(user, 'password', decryptEncryptor, encryptEncryptor); + return user; +} + module.exports = { loadEncryptionKey, encryptConnection, @@ -169,4 +212,12 @@ module.exports = { setEncryptionKey, encryptPasswordString, decryptPasswordString, + + getInternalEncryptor, + recryptConnection, + recryptUser, + generateTransportEncryptionKey, + createTransportEncryptor, + recryptObjectPasswordField, + recryptObjectPasswordFieldInPlace, }; diff --git a/packages/api/src/utility/extractSingleFileFromZip.js b/packages/api/src/utility/extractSingleFileFromZip.js new file mode 100644 index 000000000..58f087827 --- /dev/null +++ b/packages/api/src/utility/extractSingleFileFromZip.js @@ -0,0 +1,77 @@ +const yauzl = require('yauzl'); +const fs = require('fs'); +const { getLogger, extractErrorLogData } = require('dbgate-tools'); +const logger = getLogger('extractSingleFileFromZip'); +/** + * Extracts a single file from a ZIP using yauzl. + * Stops reading the rest of the archive once the file is found. + * + * @param {string} zipPath - Path to the ZIP file on disk. + * @param {string} fileInZip - The file path *inside* the ZIP to extract. + * @param {string} outputPath - Where to write the extracted file on disk. + * @returns {Promise} - Resolves with a success message or a "not found" message. + */ +function extractSingleFileFromZip(zipPath, fileInZip, outputPath) { + return new Promise((resolve, reject) => { + yauzl.open(zipPath, { lazyEntries: true }, (err, zipFile) => { + if (err) return reject(err); + + let fileFound = false; + + // Start reading the first entry + zipFile.readEntry(); + + zipFile.on('entry', entry => { + // Compare the entry name to the file we want + if (entry.fileName === fileInZip) { + fileFound = true; + + // Open a read stream for this entry + zipFile.openReadStream(entry, (err, readStream) => { + if (err) return reject(err); + + // Create a write stream to outputPath + const writeStream = fs.createWriteStream(outputPath); + readStream.pipe(writeStream); + + // When the read stream ends, we can close the zipFile + readStream.on('end', () => { + // We won't read further entries + zipFile.close(); + }); + + // When the file is finished writing, resolve + writeStream.on('finish', () => { + logger.info(`File "${fileInZip}" extracted to "${outputPath}".`); + resolve(true); + }); + + // Handle write errors + writeStream.on('error', writeErr => { + logger.error(extractErrorLogData(writeErr), `Error extracting "${fileInZip}" from "${zipPath}".`); + reject(writeErr); + }); + }); + } else { + // Not the file we want; skip to the next entry + zipFile.readEntry(); + } + }); + + // If we reach the end without finding the file + zipFile.on('end', () => { + if (!fileFound) { + resolve(false); + } + }); + + // Handle general errors + zipFile.on('error', err => { + logger.error(extractErrorLogData(err), `ZIP file error in ${zipPath}.`); + reject(err); + }); + }); + }); +} + +module.exports = extractSingleFileFromZip; diff --git a/packages/api/src/utility/listZipEntries.js b/packages/api/src/utility/listZipEntries.js new file mode 100644 index 000000000..17563a9d8 --- /dev/null +++ b/packages/api/src/utility/listZipEntries.js @@ -0,0 +1,41 @@ +const yauzl = require('yauzl'); +const path = require('path'); + +/** + * Lists the files in a ZIP archive using yauzl, + * returning an array of { fileName, uncompressedSize } objects. + * + * @param {string} zipPath - The path to the ZIP file. + * @returns {Promise>} + */ +function listZipEntries(zipPath) { + return new Promise((resolve, reject) => { + yauzl.open(zipPath, { lazyEntries: true }, (err, zipfile) => { + if (err) return reject(err); + + const entries = []; + + // Start reading entries + zipfile.readEntry(); + + // Handle each entry + zipfile.on('entry', entry => { + entries.push({ + fileName: entry.fileName, + uncompressedSize: entry.uncompressedSize, + }); + + // Move on to the next entry (we’re only listing, not reading file data) + zipfile.readEntry(); + }); + + // Finished reading all entries + zipfile.on('end', () => resolve(entries)); + + // Handle errors + zipfile.on('error', err => reject(err)); + }); + }); +} + +module.exports = listZipEntries; diff --git a/packages/datalib/src/ChangeSet.ts b/packages/datalib/src/ChangeSet.ts index 598c847ed..b4b567c18 100644 --- a/packages/datalib/src/ChangeSet.ts +++ b/packages/datalib/src/ChangeSet.ts @@ -572,6 +572,27 @@ export function changeSetInsertDocuments( }; } +export function createMergedRowsChangeSet( + table: TableInfo, + updatedRows: any[], + insertedRows: any[], + mergeKey: string[] +): ChangeSet { + const res = createChangeSet(); + res.updates = updatedRows.map(row => ({ + pureName: table.pureName, + schemaName: table.schemaName, + fields: _.omit(row, mergeKey), + condition: _.pick(row, mergeKey), + })); + res.inserts = insertedRows.map(row => ({ + pureName: table.pureName, + schemaName: table.schemaName, + fields: row, + })); + return res; +} + export function changeSetContainsChanges(changeSet: ChangeSet) { if (!changeSet) return false; return ( diff --git a/packages/datalib/src/DataDuplicator.ts b/packages/datalib/src/DataDuplicator.ts deleted file mode 100644 index 55c56984e..000000000 --- a/packages/datalib/src/DataDuplicator.ts +++ /dev/null @@ -1,326 +0,0 @@ -import { - createAsyncWriteStream, - extractErrorLogData, - getLogger, - runCommandOnDriver, - runQueryOnDriver, -} from 'dbgate-tools'; -import { DatabaseInfo, EngineDriver, ForeignKeyInfo, TableInfo } from 'dbgate-types'; -import _pick from 'lodash/pick'; -import _omit from 'lodash/omit'; - -const logger = getLogger('dataDuplicator'); - -export interface DataDuplicatorItem { - openStream: () => Promise; - name: string; - operation: 'copy' | 'lookup' | 'insertMissing'; - matchColumns: string[]; -} - -export interface DataDuplicatorOptions { - rollbackAfterFinish?: boolean; - skipRowsWithUnresolvedRefs?: boolean; - setNullForUnresolvedNullableRefs?: boolean; -} - -class DuplicatorReference { - constructor( - public base: DuplicatorItemHolder, - public ref: DuplicatorItemHolder, - public isMandatory: boolean, - public foreignKey: ForeignKeyInfo - ) {} - - get columnName() { - return this.foreignKey.columns[0].columnName; - } -} - -class DuplicatorWeakReference { - constructor(public base: DuplicatorItemHolder, public ref: TableInfo, public foreignKey: ForeignKeyInfo) {} - - get columnName() { - return this.foreignKey.columns[0].columnName; - } -} - -class DuplicatorItemHolder { - references: DuplicatorReference[] = []; - backReferences: DuplicatorReference[] = []; - // not mandatory references to entities out of the model - weakReferences: DuplicatorWeakReference[] = []; - table: TableInfo; - isPlanned = false; - idMap = {}; - autoColumn: string; - refByColumn: { [columnName: string]: DuplicatorReference } = {}; - isReferenced: boolean; - - get name() { - return this.item.name; - } - - constructor(public item: DataDuplicatorItem, public duplicator: DataDuplicator) { - this.table = duplicator.db.tables.find(x => x.pureName.toUpperCase() == item.name.toUpperCase()); - this.autoColumn = this.table.columns.find(x => x.autoIncrement)?.columnName; - if ( - this.table.primaryKey?.columns?.length != 1 || - this.table.primaryKey?.columns?.[0]?.columnName != this.autoColumn - ) { - this.autoColumn = null; - } - } - - initializeReferences() { - for (const fk of this.table.foreignKeys) { - if (fk.columns?.length != 1) continue; - const refHolder = this.duplicator.itemHolders.find(y => y.name.toUpperCase() == fk.refTableName.toUpperCase()); - const isMandatory = this.table.columns.find(x => x.columnName == fk.columns[0]?.columnName)?.notNull; - if (refHolder == null) { - if (!isMandatory) { - const weakref = new DuplicatorWeakReference( - this, - this.duplicator.db.tables.find(x => x.pureName == fk.refTableName), - fk - ); - this.weakReferences.push(weakref); - } - } else { - const newref = new DuplicatorReference(this, refHolder, isMandatory, fk); - this.references.push(newref); - this.refByColumn[newref.columnName] = newref; - - refHolder.isReferenced = true; - } - } - } - - createInsertObject(chunk, weakrefcols: string[]) { - const res = _omit( - _pick( - chunk, - this.table.columns.map(x => x.columnName) - ), - [this.autoColumn, ...this.backReferences.map(x => x.columnName), ...weakrefcols] - ); - - for (const key in res) { - const ref = this.refByColumn[key]; - if (ref) { - // remap id - res[key] = ref.ref.idMap[res[key]]; - if (ref.isMandatory && res[key] == null) { - // mandatory refertence not matched - if (this.duplicator.options.skipRowsWithUnresolvedRefs) { - return null; - } - throw new Error(`Unresolved reference, base=${ref.base.name}, ref=${ref.ref.name}, ${key}=${chunk[key]}`); - } - } - } - - return res; - } - - // returns list of columns that are weak references and are not resolved - async getMissingWeakRefsForRow(row): Promise { - if (!this.duplicator.options.setNullForUnresolvedNullableRefs || !this.weakReferences?.length) { - return []; - } - - const qres = await runQueryOnDriver(this.duplicator.pool, this.duplicator.driver, dmp => { - dmp.put('^select '); - dmp.putCollection(',', this.weakReferences, weakref => { - dmp.put( - '(^case ^when ^exists (^select * ^from %f where %i = %v) ^then 1 ^else 0 ^end) as %i', - weakref.ref, - weakref.foreignKey.columns[0].refColumnName, - row[weakref.foreignKey.columns[0].columnName], - weakref.foreignKey.columns[0].columnName - ); - }); - if (this.duplicator.driver.dialect.requireFromDual) { - dmp.put(' ^from ^dual'); - } - }); - const qrow = qres.rows[0]; - return this.weakReferences.filter(x => qrow[x.columnName] == 0).map(x => x.columnName); - } - - async runImport() { - const readStream = await this.item.openStream(); - const driver = this.duplicator.driver; - const pool = this.duplicator.pool; - let inserted = 0; - let mapped = 0; - let missing = 0; - let skipped = 0; - let lastLogged = new Date(); - - const existingWeakRefs = {}; - - const writeStream = createAsyncWriteStream(this.duplicator.stream, { - processItem: async chunk => { - if (chunk.__isStreamHeader) { - return; - } - - const doCopy = async () => { - // console.log('chunk', this.name, JSON.stringify(chunk)); - const weakrefcols = await this.getMissingWeakRefsForRow(chunk); - const insertedObj = this.createInsertObject(chunk, weakrefcols); - // console.log('insertedObj', this.name, JSON.stringify(insertedObj)); - if (insertedObj == null) { - skipped += 1; - return; - } - let res = await runQueryOnDriver(pool, driver, dmp => { - dmp.put( - '^insert ^into %f (%,i) ^values (%,v)', - this.table, - Object.keys(insertedObj), - Object.values(insertedObj) - ); - - if ( - this.autoColumn && - this.isReferenced && - !this.duplicator.driver.dialect.requireStandaloneSelectForScopeIdentity - ) { - dmp.selectScopeIdentity(this.table); - } - }); - inserted += 1; - if (this.autoColumn && this.isReferenced) { - if (this.duplicator.driver.dialect.requireStandaloneSelectForScopeIdentity) { - res = await runQueryOnDriver(pool, driver, dmp => dmp.selectScopeIdentity(this.table)); - } - // console.log('IDRES', JSON.stringify(res)); - // console.log('*********** ENTRIES OF', res?.rows?.[0]); - const resId = Object.entries(res?.rows?.[0])?.[0]?.[1]; - if (resId != null) { - this.idMap[chunk[this.autoColumn]] = resId; - } - } - }; - - switch (this.item.operation) { - case 'copy': { - await doCopy(); - break; - } - case 'insertMissing': - case 'lookup': { - const res = await runQueryOnDriver(pool, driver, dmp => - dmp.put( - '^select %i ^from %f ^where %i = %v', - this.autoColumn, - this.table, - this.item.matchColumns[0], - chunk[this.item.matchColumns[0]] - ) - ); - const resId = Object.entries(res?.rows?.[0])?.[0]?.[1]; - if (resId != null) { - mapped += 1; - this.idMap[chunk[this.autoColumn]] = resId; - } else if (this.item.operation == 'insertMissing') { - await doCopy(); - } else { - missing += 1; - } - break; - } - } - - if (new Date().getTime() - lastLogged.getTime() > 5000) { - logger.info( - `Duplicating ${this.item.name} in progress, inserted ${inserted} rows, mapped ${mapped} rows, missing ${missing} rows, skipped ${skipped} rows` - ); - lastLogged = new Date(); - } - // this.idMap[oldId] = newId; - }, - }); - - await this.duplicator.copyStream(readStream, writeStream); - - // await this.duplicator.driver.writeQueryStream(this.duplicator.pool, { - // mapResultId: (oldId, newId) => { - // this.idMap[oldId] = newId; - // }, - // }); - - return { inserted, mapped, missing, skipped }; - } -} - -export class DataDuplicator { - itemHolders: DuplicatorItemHolder[]; - itemPlan: DuplicatorItemHolder[] = []; - - constructor( - public pool: any, - public driver: EngineDriver, - public db: DatabaseInfo, - public items: DataDuplicatorItem[], - public stream, - public copyStream: (input, output) => Promise, - public options: DataDuplicatorOptions = {} - ) { - this.itemHolders = items.map(x => new DuplicatorItemHolder(x, this)); - this.itemHolders.forEach(x => x.initializeReferences()); - } - - findItemToPlan(): DuplicatorItemHolder { - for (const item of this.itemHolders) { - if (item.isPlanned) continue; - if (item.references.every(x => x.ref.isPlanned)) { - return item; - } - } - for (const item of this.itemHolders) { - if (item.isPlanned) continue; - if (item.references.every(x => x.ref.isPlanned || !x.isMandatory)) { - const backReferences = item.references.filter(x => !x.ref.isPlanned); - item.backReferences = backReferences; - return item; - } - } - throw new Error('Cycle in mandatory references'); - } - - createPlan() { - while (this.itemPlan.length < this.itemHolders.length) { - const item = this.findItemToPlan(); - item.isPlanned = true; - this.itemPlan.push(item); - } - } - - async run() { - this.createPlan(); - - await runCommandOnDriver(this.pool, this.driver, dmp => dmp.beginTransaction()); - try { - for (const item of this.itemPlan) { - const stats = await item.runImport(); - logger.info( - `Duplicated ${item.name}, inserted ${stats.inserted} rows, mapped ${stats.mapped} rows, missing ${stats.missing} rows, skipped ${stats.skipped} rows` - ); - } - } catch (err) { - logger.error(extractErrorLogData(err), `Failed duplicator job, rollbacking. ${err.message}`); - await runCommandOnDriver(this.pool, this.driver, dmp => dmp.rollbackTransaction()); - return; - } - if (this.options.rollbackAfterFinish) { - logger.info('Rollbacking transaction, nothing was changed'); - await runCommandOnDriver(this.pool, this.driver, dmp => dmp.rollbackTransaction()); - } else { - logger.info('Committing duplicator transaction'); - await runCommandOnDriver(this.pool, this.driver, dmp => dmp.commitTransaction()); - } - } -} diff --git a/packages/datalib/src/DataReplicator.ts b/packages/datalib/src/DataReplicator.ts new file mode 100644 index 000000000..0ade8aa17 --- /dev/null +++ b/packages/datalib/src/DataReplicator.ts @@ -0,0 +1,509 @@ +import { + createAsyncWriteStream, + extractErrorLogData, + getLogger, + isTypeNumber, + runCommandOnDriver, + runQueryOnDriver, + SqlDumper, +} from 'dbgate-tools'; +import { DatabaseInfo, EngineDriver, ForeignKeyInfo, NamedObjectInfo, QueryResult, TableInfo } from 'dbgate-types'; +import _pick from 'lodash/pick'; +import _omit from 'lodash/omit'; +import stableStringify from 'json-stable-stringify'; + +const logger = getLogger('dataReplicator'); + +export interface DataReplicatorItem { + openStream: () => Promise; + name: string; + findExisting: (row: any) => boolean; + createNew: (row: any) => boolean; + updateExisting: (row: any) => boolean; + deleteMissing: boolean; + deleteRestrictionColumns: string[]; + matchColumns: string[]; +} + +export interface DataReplicatorOptions { + rollbackAfterFinish?: boolean; + skipRowsWithUnresolvedRefs?: boolean; + setNullForUnresolvedNullableRefs?: boolean; + generateSqlScript?: boolean; + runid?: string; +} + +class ReplicatorReference { + constructor( + public base: ReplicatorItemHolder, + public ref: ReplicatorItemHolder, + public isMandatory: boolean, + public foreignKey: ForeignKeyInfo + ) {} + + get columnName() { + return this.foreignKey.columns[0].columnName; + } +} + +class ReplicatorWeakReference { + constructor(public base: ReplicatorItemHolder, public ref: TableInfo, public foreignKey: ForeignKeyInfo) {} + + get columnName() { + return this.foreignKey.columns[0].columnName; + } +} + +class ReplicatorItemHolder { + references: ReplicatorReference[] = []; + backReferences: ReplicatorReference[] = []; + // not mandatory references to entities out of the model + weakReferences: ReplicatorWeakReference[] = []; + table: TableInfo; + isPlanned = false; + idMap = {}; + autoColumn: string; + isManualAutoColumn: boolean; + refByColumn: { [columnName: string]: ReplicatorReference } = {}; + isReferenced: boolean; + + get name() { + return this.item.name; + } + + constructor(public item: DataReplicatorItem, public replicator: DataReplicator) { + this.table = replicator.db.tables.find(x => x.pureName.toUpperCase() == item.name.toUpperCase()); + this.autoColumn = this.table.columns.find(x => x.autoIncrement)?.columnName; + if ( + this.table.primaryKey?.columns?.length != 1 || + this.table.primaryKey?.columns?.[0]?.columnName != this.autoColumn + ) { + this.autoColumn = null; + } + if (!this.autoColumn && this.table.primaryKey?.columns?.length == 1) { + const name = this.table.primaryKey.columns[0].columnName; + const column = this.table.columns.find(x => x.columnName == name); + if (isTypeNumber(column?.dataType)) { + this.autoColumn = name; + this.isManualAutoColumn = true; + } + } + if (this.autoColumn && this.replicator.options.generateSqlScript) { + this.isManualAutoColumn = true; + } + } + + initializeReferences() { + for (const fk of this.table.foreignKeys) { + if (fk.columns?.length != 1) continue; + const refHolder = this.replicator.itemHolders.find(y => y.name.toUpperCase() == fk.refTableName.toUpperCase()); + const isMandatory = this.table.columns.find(x => x.columnName == fk.columns[0]?.columnName)?.notNull; + if (refHolder == null) { + if (!isMandatory) { + const weakref = new ReplicatorWeakReference( + this, + this.replicator.db.tables.find(x => x.pureName == fk.refTableName), + fk + ); + this.weakReferences.push(weakref); + } + } else { + const newref = new ReplicatorReference(this, refHolder, isMandatory, fk); + this.references.push(newref); + this.refByColumn[newref.columnName] = newref; + + refHolder.isReferenced = true; + } + } + } + + createInsertObject(chunk, weakrefcols?: string[]) { + const res = _omit( + _pick( + chunk, + this.table.columns.map(x => x.columnName) + ), + [this.autoColumn, ...this.backReferences.map(x => x.columnName), ...(weakrefcols ? weakrefcols : [])] + ); + + for (const key in res) { + const ref = this.refByColumn[key]; + if (ref) { + // remap id + res[key] = ref.ref.idMap[res[key]]; + if (ref.isMandatory && res[key] == null) { + // mandatory refertence not matched + if (this.replicator.options.skipRowsWithUnresolvedRefs) { + return null; + } + throw new Error(`Unresolved reference, base=${ref.base.name}, ref=${ref.ref.name}, ${key}=${chunk[key]}`); + } + } + } + + return res; + } + + createUpdateObject(chunk) { + const res = _omit( + _pick( + chunk, + this.table.columns.map(x => x.columnName) + ), + [this.autoColumn, ...this.backReferences.map(x => x.columnName), ...this.references.map(x => x.columnName)] + ); + + return res; + } + + // returns list of columns that are weak references and are not resolved + async getMissingWeakRefsForRow(row): Promise { + if (!this.replicator.options.setNullForUnresolvedNullableRefs || !this.weakReferences?.length) { + return []; + } + + const qres = await runQueryOnDriver(this.replicator.pool, this.replicator.driver, dmp => { + dmp.put('^select '); + dmp.putCollection(',', this.weakReferences, weakref => { + dmp.put( + '(^case ^when ^exists (^select * ^from %f where %i = %v) ^then 1 ^else 0 ^end) as %i', + weakref.ref, + weakref.foreignKey.columns[0].refColumnName, + row[weakref.foreignKey.columns[0].columnName], + weakref.foreignKey.columns[0].columnName + ); + }); + if (this.replicator.driver.dialect.requireFromDual) { + dmp.put(' ^from ^dual'); + } + }); + const qrow = qres.rows[0]; + return this.weakReferences.filter(x => qrow[x.columnName] == 0).map(x => x.columnName); + } + + async runImport() { + const readStream = await this.item.openStream(); + const driver = this.replicator.driver; + const pool = this.replicator.pool; + let inserted = 0; + let mapped = 0; + let updated = 0; + let deleted = 0; + let missing = 0; + let skipped = 0; + let lastLogged = new Date(); + + const { deleteMissing, deleteRestrictionColumns } = this.item; + const deleteRestrictions = {}; + const usedKeyRows = {}; + + const writeStream = createAsyncWriteStream(this.replicator.stream, { + processItem: async chunk => { + if (chunk.__isStreamHeader) { + return; + } + + const doFind = async () => { + let insertedObj = this.createInsertObject(chunk); + + const res = await runQueryOnDriver(pool, driver, dmp => { + dmp.put('^select %i ^from %f ^where ', this.autoColumn, this.table); + dmp.putCollection(' and ', this.item.matchColumns, x => { + dmp.put('%i = %v', x, insertedObj[x]); + }); + }); + const resId = Object.entries(res?.rows?.[0] || {})?.[0]?.[1]; + if (resId != null) { + mapped += 1; + this.idMap[chunk[this.autoColumn]] = resId; + } + return resId; + }; + + const doUpdate = async recordId => { + const updateObj = this.createUpdateObject(chunk); + if (Object.keys(updateObj).length == 0) { + skipped += 1; + return; + } + + await this.replicator.runDumperCommand(dmp => { + dmp.put('^update %f ^ set ', this.table); + dmp.putCollection(',', Object.keys(updateObj), x => { + dmp.put('%i = %v', x, updateObj[x]); + }); + dmp.put(' ^where %i = %v', this.autoColumn, recordId); + dmp.endCommand(); + }); + updated += 1; + }; + + const doInsert = async () => { + // console.log('chunk', this.name, JSON.stringify(chunk)); + const weakrefcols = await this.getMissingWeakRefsForRow(chunk); + let insertedObj = this.createInsertObject(chunk, weakrefcols); + // console.log('insertedObj', this.name, JSON.stringify(insertedObj)); + if (insertedObj == null) { + skipped += 1; + return; + } + + if (this.isManualAutoColumn) { + const maxId = await this.replicator.generateIdentityValue(this.autoColumn, this.table); + insertedObj = { + ...insertedObj, + [this.autoColumn]: maxId, + }; + this.idMap[chunk[this.autoColumn]] = maxId; + } + + let res = await this.replicator.runDumperQuery(dmp => { + dmp.put( + '^insert ^into %f (%,i) ^values (%,v)', + this.table, + Object.keys(insertedObj), + Object.values(insertedObj) + ); + dmp.endCommand(); + + if ( + this.autoColumn && + this.isReferenced && + !this.replicator.driver.dialect.requireStandaloneSelectForScopeIdentity && + !this.isManualAutoColumn + ) { + dmp.selectScopeIdentity(this.table); + } + }); + inserted += 1; + if (this.autoColumn && this.isReferenced && !this.isManualAutoColumn) { + if (this.replicator.driver.dialect.requireStandaloneSelectForScopeIdentity) { + res = await runQueryOnDriver(pool, driver, dmp => dmp.selectScopeIdentity(this.table)); + } + // console.log('IDRES', JSON.stringify(res)); + // console.log('*********** ENTRIES OF', res?.rows?.[0]); + const resId = Object.entries(res?.rows?.[0])?.[0]?.[1]; + if (resId != null) { + this.idMap[chunk[this.autoColumn]] = resId; + } + return resId; + } + }; + + const doMarkDelete = () => { + const insertedObj = this.createInsertObject(chunk); + if (deleteRestrictionColumns?.length > 0) { + const restriction = _pick(insertedObj, deleteRestrictionColumns); + const key = stableStringify(restriction); + deleteRestrictions[key] = restriction; + } + + const usedKey = _pick(insertedObj, this.item.matchColumns); + usedKeyRows[stableStringify(usedKey)] = usedKey; + }; + + const findExisting = this.item.findExisting(chunk); + const updateExisting = this.item.updateExisting(chunk); + const createNew = this.item.createNew(chunk); + + if (deleteMissing) { + doMarkDelete(); + } + + let recordId = null; + if (findExisting) { + recordId = await doFind(); + } + + if (updateExisting && recordId != null) { + await doUpdate(recordId); + } + + if (createNew && recordId == null) { + recordId = await doInsert(); + } + + if (recordId == null && findExisting) { + missing += 1; + } + + if (new Date().getTime() - lastLogged.getTime() > 5000) { + logger.info( + `Replicating ${this.item.name} in progress, inserted ${inserted} rows, mapped ${mapped} rows, missing ${missing} rows, skipped ${skipped} rows, updated ${updated} rows` + ); + lastLogged = new Date(); + } + // this.idMap[oldId] = newId; + }, + }); + + const dumpConditionArray = (dmp: SqlDumper, array: any[], positive: boolean) => { + dmp.putCollection(positive ? ' or ' : ' and ', array, x => { + dmp.put('('); + dmp.putCollection(positive ? ' and ' : ' or ', Object.keys(x), y => { + dmp.put(positive ? '%i = %v' : 'not (%i = %v)', y, x[y]); + }); + dmp.put(')'); + }); + }; + const dumpDeleteCondition = (dmp: SqlDumper) => { + const deleteRestrictionValues = Object.values(deleteRestrictions); + const usedKeyRowsValues = Object.values(usedKeyRows); + + if (deleteRestrictionValues.length == 0 && usedKeyRowsValues.length == 0) { + return; + } + + dmp.put(' ^where '); + if (deleteRestrictionColumns?.length > 0) { + dmp.put('('); + dumpConditionArray(dmp, deleteRestrictionValues, true); + dmp.put(')'); + if (usedKeyRowsValues.length > 0) { + dmp.put(' ^and '); + } + } + dumpConditionArray(dmp, Object.values(usedKeyRows), false); + }; + const doDelete = async () => { + const countRes = await runQueryOnDriver(pool, driver, dmp => { + dmp.put('^select count(*) as ~cnt ^from %f', this.table); + dumpDeleteCondition(dmp); + dmp.endCommand(); + }); + const count = parseInt(countRes.rows[0].cnt); + if (count > 0) { + await this.replicator.runDumperCommand(dmp => { + dmp.put('^delete ^from %f', this.table); + dumpDeleteCondition(dmp); + dmp.endCommand(); + }); + deleted += count; + } + }; + + await this.replicator.copyStream(readStream, writeStream, {}); + + if (deleteMissing) { + await doDelete(); + } + + // await this.replicator.driver.writeQueryStream(this.replicator.pool, { + // mapResultId: (oldId, newId) => { + // this.idMap[oldId] = newId; + // }, + // }); + + return { inserted, mapped, missing, skipped, updated, deleted }; + } +} + +export class DataReplicator { + itemHolders: ReplicatorItemHolder[]; + itemPlan: ReplicatorItemHolder[] = []; + result: string = ''; + dumper: SqlDumper; + identityValues: { [fullTableName: string]: number } = {}; + + constructor( + public pool: any, + public driver: EngineDriver, + public db: DatabaseInfo, + public items: DataReplicatorItem[], + public stream, + public copyStream: (input, output, options) => Promise, + public options: DataReplicatorOptions = {} + ) { + this.itemHolders = items.map(x => new ReplicatorItemHolder(x, this)); + this.itemHolders.forEach(x => x.initializeReferences()); + // @ts-ignore + this.dumper = driver.createDumper(); + } + + findItemToPlan(): ReplicatorItemHolder { + for (const item of this.itemHolders) { + if (item.isPlanned) continue; + if (item.references.every(x => x.ref.isPlanned)) { + return item; + } + } + for (const item of this.itemHolders) { + if (item.isPlanned) continue; + if (item.references.every(x => x.ref.isPlanned || !x.isMandatory)) { + const backReferences = item.references.filter(x => !x.ref.isPlanned); + item.backReferences = backReferences; + return item; + } + } + throw new Error('Cycle in mandatory references'); + } + + createPlan() { + while (this.itemPlan.length < this.itemHolders.length) { + const item = this.findItemToPlan(); + item.isPlanned = true; + this.itemPlan.push(item); + } + } + + async runDumperCommand(cmd: (dmp: SqlDumper) => void | string): Promise { + if (this.options.generateSqlScript) { + cmd(this.dumper); + } else { + await runCommandOnDriver(this.pool, this.driver, cmd); + } + } + + async runDumperQuery(cmd: (dmp: SqlDumper) => void | string): Promise { + if (this.options.generateSqlScript) { + cmd(this.dumper); + return { + rows: [], + }; + } else { + return await runQueryOnDriver(this.pool, this.driver, cmd); + } + } + + async generateIdentityValue(column: string, table: NamedObjectInfo): Promise { + const tableKey = `${table.schemaName}.${table.pureName}`; + if (!(tableKey in this.identityValues)) { + const max = await runQueryOnDriver(this.pool, this.driver, dmp => { + dmp.put('^select max(%i) as ~maxid ^from %f', column, table); + }); + const maxId = Math.max(max.rows[0]['maxid'] ?? 0, 0) + 1; + this.identityValues[tableKey] = maxId; + return maxId; + } + + this.identityValues[tableKey] += 1; + return this.identityValues[tableKey]; + } + + async run() { + this.createPlan(); + + await this.runDumperCommand(dmp => dmp.beginTransaction()); + try { + for (const item of this.itemPlan) { + const stats = await item.runImport(); + logger.info( + `Replicated ${item.name}, inserted ${stats.inserted} rows, mapped ${stats.mapped} rows, missing ${stats.missing} rows, skipped ${stats.skipped} rows, updated ${stats.updated} rows, deleted ${stats.deleted} rows` + ); + } + } catch (err) { + logger.error(extractErrorLogData(err), `Failed replicator job, rollbacking. ${err.message}`); + await this.runDumperCommand(dmp => dmp.rollbackTransaction()); + return; + } + if (this.options.rollbackAfterFinish) { + logger.info('Rollbacking transaction, nothing was changed'); + await this.runDumperCommand(dmp => dmp.rollbackTransaction()); + } else { + logger.info('Committing replicator transaction'); + await this.runDumperCommand(dmp => dmp.commitTransaction()); + } + + this.result = this.dumper.s; + } +} diff --git a/packages/datalib/src/index.ts b/packages/datalib/src/index.ts index ab407eeed..6ef5c50a0 100644 --- a/packages/datalib/src/index.ts +++ b/packages/datalib/src/index.ts @@ -18,7 +18,7 @@ export * from './processPerspectiveDefaultColunns'; export * from './PerspectiveDataPattern'; export * from './PerspectiveDataLoader'; export * from './perspectiveTools'; -export * from './DataDuplicator'; +export * from './DataReplicator'; export * from './FreeTableGridDisplay'; export * from './FreeTableModel'; export * from './CustomGridDisplay'; diff --git a/packages/sqltree/src/utility.ts b/packages/sqltree/src/utility.ts index ccab90e87..e9b3e9829 100644 --- a/packages/sqltree/src/utility.ts +++ b/packages/sqltree/src/utility.ts @@ -1,5 +1,5 @@ import type { EngineDriver, SqlDumper } from 'dbgate-types'; -import { Command, Condition } from './types'; +import { Command, Condition, Select, Source } from './types'; import { dumpSqlCommand } from './dumpSqlCommand'; export function treeToSql(driver: EngineDriver, object: T, func: (dmp: SqlDumper, obj: T) => void) { @@ -43,3 +43,43 @@ export function mergeConditions(condition1: Condition, condition2: Condition): C conditions: [condition1, condition2], }; } + +export function selectKeysFromTable(options: { + pureName: string; + schemaName: string; + keyColumns: []; + loadKeys: any[][]; +}): Select { + const source: Source = { + name: { pureName: options.pureName, schemaName: options.schemaName }, + }; + const res: Select = { + commandType: 'select', + columns: options.keyColumns.map(col => ({ + exprType: 'column', + columnName: col, + source, + })), + from: source, + where: { + conditionType: 'or', + conditions: options.loadKeys.map(key => ({ + conditionType: 'and', + conditions: key.map((keyValue, index) => ({ + conditionType: 'binary', + operator: '=', + left: { + exprType: 'column', + columnName: options.keyColumns[index], + source, + }, + right: { + exprType: 'value', + value: keyValue, + }, + })), + })), + }, + }; + return res; +} diff --git a/packages/tools/src/ScriptWriter.ts b/packages/tools/src/ScriptWriter.ts index 26d622ac6..72c67e664 100644 --- a/packages/tools/src/ScriptWriter.ts +++ b/packages/tools/src/ScriptWriter.ts @@ -54,8 +54,8 @@ export class ScriptWriter { this._put(`await dbgateApi.importDatabase(${JSON.stringify(options)});`); } - dataDuplicator(options) { - this._put(`await dbgateApi.dataDuplicator(${JSON.stringify(options, null, 2)});`); + dataReplicator(options) { + this._put(`await dbgateApi.dataReplicator(${JSON.stringify(options, null, 2)});`); } comment(s) { @@ -72,6 +72,10 @@ export class ScriptWriter { return prefix + this.s; } + + zipDirectory(inputDirectory, outputFile) { + this._put(`await dbgateApi.zipDirectory('${inputDirectory}', '${outputFile}');`); + } } export class ScriptWriterJson { @@ -138,13 +142,21 @@ export class ScriptWriterJson { }); } - dataDuplicator(options) { + dataReplicator(options) { this.commands.push({ - type: 'dataDuplicator', + type: 'dataReplicator', options, }); } + zipDirectory(inputDirectory, outputFile) { + this.commands.push({ + type: 'zipDirectory', + inputDirectory, + outputFile, + }); + } + getScript(schedule = null) { return { type: 'json', @@ -185,8 +197,11 @@ export function jsonScriptToJavascript(json) { case 'importDatabase': script.importDatabase(cmd.options); break; - case 'dataDuplicator': - script.dataDuplicator(cmd.options); + case 'dataReplicator': + script.dataReplicator(cmd.options); + break; + case 'zipDirectory': + script.zipDirectory(cmd.inputDirectory, cmd.outputFile); break; } } diff --git a/packages/tools/src/createBulkInsertStreamBase.ts b/packages/tools/src/createBulkInsertStreamBase.ts index 9dc6842fc..e3f9d4408 100644 --- a/packages/tools/src/createBulkInsertStreamBase.ts +++ b/packages/tools/src/createBulkInsertStreamBase.ts @@ -100,7 +100,9 @@ export function createBulkInsertStreamBase(driver: EngineDriver, stream, dbhan, dmp.putRaw(';'); // require('fs').writeFileSync('/home/jena/test.sql', dmp.s); // console.log(dmp.s); - await driver.query(dbhan, dmp.s, { discardResult: true }); + if (rows.length > 0) { + await driver.query(dbhan, dmp.s, { discardResult: true }); + } writable.rowsReporter.add(rows.length); } else { for (const row of rows) { diff --git a/packages/tools/src/stringTools.ts b/packages/tools/src/stringTools.ts index 6509cd8bd..b52c7444f 100644 --- a/packages/tools/src/stringTools.ts +++ b/packages/tools/src/stringTools.ts @@ -549,3 +549,20 @@ export function pinoLogRecordToMessageRecord(logRecord, defaultSeverity = 'info' severity: levelToSeverity[level] ?? defaultSeverity, }; } + +export function jsonLinesStringify(jsonArray: any[]): string { + return jsonArray.map(json => JSON.stringify(json)).join('\n'); +} +export function jsonLinesParse(jsonLines: string): any[] { + return jsonLines + .split('\n') + .filter(x => x.trim()) + .map(line => { + try { + return JSON.parse(line); + } catch (e) { + return null; + } + }) + .filter(x => x); +} diff --git a/packages/types/test-engines.d.ts b/packages/types/test-engines.d.ts index c08e07f56..7a426349a 100644 --- a/packages/types/test-engines.d.ts +++ b/packages/types/test-engines.d.ts @@ -31,7 +31,7 @@ export type TestEngineInfo = { skipUnique?: boolean; skipAutoIncrement?: boolean; skipPkColumnTesting?: boolean; - skipDataDuplicator?: boolean; + skipDataReplicator?: boolean; skipDeploy?: boolean; skipStringLength?: boolean; skipChangeColumn?: boolean; diff --git a/packages/web/src/Screen.svelte b/packages/web/src/Screen.svelte index b7262d489..2edba26e5 100644 --- a/packages/web/src/Screen.svelte +++ b/packages/web/src/Screen.svelte @@ -157,6 +157,7 @@ } .snackbar-container { + z-index: 1000; position: fixed; right: 0; bottom: var(--dim-statusbar-height); diff --git a/packages/web/src/appobj/ArchiveFileAppObject.svelte b/packages/web/src/appobj/ArchiveFileAppObject.svelte index 84891e0b4..172bd33eb 100644 --- a/packages/web/src/appobj/ArchiveFileAppObject.svelte +++ b/packages/web/src/appobj/ArchiveFileAppObject.svelte @@ -1,5 +1,5 @@ @@ -79,6 +83,7 @@ import { openImportExportTab } from '../utility/importExportTools'; export let data; + $: isZipped = data.folderName?.endsWith('.zip'); const handleRename = () => { showModal(InputTextModal, { @@ -112,6 +117,9 @@ openArchive(data.fileName, data.folderName); }; const handleClick = () => { + if (!data.fileType) { + return; + } if (data.fileType == 'jsonl') { handleOpenArchive(); } @@ -133,11 +141,15 @@ }; function createMenu() { + if (!data.fileType) { + return []; + } + return [ data.fileType == 'jsonl' && { text: 'Open', onClick: handleOpenArchive }, data.fileType == 'jsonl' && { text: 'Open in text editor', onClick: handleOpenJsonLinesText }, - { text: 'Delete', onClick: handleDelete }, - { text: 'Rename', onClick: handleRename }, + !isZipped && { text: 'Delete', onClick: handleDelete }, + !isZipped && { text: 'Rename', onClick: handleRename }, data.fileType == 'jsonl' && createQuickExportMenu( fmt => async () => { @@ -174,29 +186,30 @@ ), data.fileType.endsWith('.sql') && { text: 'Open SQL', onClick: handleOpenSqlFile }, data.fileType.endsWith('.yaml') && { text: 'Open YAML', onClick: handleOpenYamlFile }, - data.fileType == 'jsonl' && { - text: 'Open in profiler', - submenu: getExtensions() - .drivers.filter(eng => eng.profilerFormatterFunction) - .map(eng => ({ - text: eng.title, - onClick: () => { - openNewTab({ - title: 'Profiler', - icon: 'img profiler', - tabComponent: 'ProfilerTab', - props: { - jslidLoad: `archive://${data.folderName}/${data.fileName}`, - engine: eng.engine, - // profilerFormatterFunction: eng.profilerFormatterFunction, - // profilerTimestampFunction: eng.profilerTimestampFunction, - // profilerChartAggregateFunction: eng.profilerChartAggregateFunction, - // profilerChartMeasures: eng.profilerChartMeasures, - }, - }); - }, - })), - }, + !isZipped && + data.fileType == 'jsonl' && { + text: 'Open in profiler', + submenu: getExtensions() + .drivers.filter(eng => eng.profilerFormatterFunction) + .map(eng => ({ + text: eng.title, + onClick: () => { + openNewTab({ + title: 'Profiler', + icon: 'img profiler', + tabComponent: 'ProfilerTab', + props: { + jslidLoad: `archive://${data.folderName}/${data.fileName}`, + engine: eng.engine, + // profilerFormatterFunction: eng.profilerFormatterFunction, + // profilerTimestampFunction: eng.profilerTimestampFunction, + // profilerChartAggregateFunction: eng.profilerChartAggregateFunction, + // profilerChartMeasures: eng.profilerChartMeasures, + }, + }); + }, + })), + }, ]; } diff --git a/packages/web/src/appobj/ArchiveFolderAppObject.svelte b/packages/web/src/appobj/ArchiveFolderAppObject.svelte index dbd0ede98..1e2dcc7f9 100644 --- a/packages/web/src/appobj/ArchiveFolderAppObject.svelte +++ b/packages/web/src/appobj/ArchiveFolderAppObject.svelte @@ -20,6 +20,7 @@ import hasPermission from '../utility/hasPermission'; import { isProApp } from '../utility/proTools'; import { extractShellConnection } from '../impexp/createImpExpScript'; + import { saveFileToDisk } from '../utility/exportFileTools'; export let data; @@ -100,7 +101,7 @@ await dbgateApi.deployDb(${JSON.stringify( props: { conid: $currentDatabase?.connection?._id, database: $currentDatabase?.name, - } + }, }, { editor: { @@ -113,12 +114,12 @@ await dbgateApi.deployDb(${JSON.stringify( ); }; - const handleOpenDuplicatorTab = () => { + const handleOpenDataDeployTab = () => { openNewTab( { title: data.name, - icon: 'img duplicator', - tabComponent: 'DataDuplicatorTab', + icon: 'img data-deploy', + tabComponent: 'DataDeployTab', props: { conid: $currentDatabase?.connection?._id, database: $currentDatabase?.name, @@ -127,21 +128,56 @@ await dbgateApi.deployDb(${JSON.stringify( { editor: { archiveFolder: data.name, + conid: $currentDatabase?.connection?._id, + database: $currentDatabase?.name, }, } ); }; + const handleZipUnzip = async method => { + await apiCall(method, { + folder: data.name, + }); + }; + + const handleDownloadZip = async () => { + saveFileToDisk( + async filePath => { + const zipped = await apiCall('archive/get-zipped-path', { + folder: data.name, + }); + await apiCall('files/simple-copy', { + sourceFilePath: zipped.filePath, + targetFilePath: filePath, + }); + }, + { + formatLabel: 'ZIP files', + formatExtension: 'zip', + defaultFileName: data.name?.endsWith('.zip') ? data.name : data.name + '.zip', + } + ); + }; + function createMenu() { return [ data.name != 'default' && { text: 'Delete', onClick: handleDelete }, data.name != 'default' && { text: 'Rename', onClick: handleRename }, data.name != 'default' && $currentDatabase && [ - { text: 'Data duplicator', onClick: handleOpenDuplicatorTab }, + isProApp() && { text: 'Data deployer', onClick: handleOpenDataDeployTab }, { text: 'Generate deploy DB SQL', onClick: handleGenerateDeploySql }, { text: 'Shell: Deploy DB', onClick: handleGenerateDeployScript }, ], + data.name != 'default' && + isProApp() && + data.name.endsWith('.zip') && { text: 'Unpack ZIP', onClick: () => handleZipUnzip('archive/unzip') }, + data.name != 'default' && + isProApp() && + !data.name.endsWith('.zip') && { text: 'Pack (create ZIP)', onClick: () => handleZipUnzip('archive/zip') }, + + isProApp() && { text: 'Download ZIP', onClick: handleDownloadZip }, data.name != 'default' && hasPermission('dbops/model/compare') && @@ -158,7 +194,7 @@ await dbgateApi.deployDb(${JSON.stringify( {...$$restProps} {data} title={data.name.endsWith('.link') ? data.name.slice(0, -5) : data.name} - icon={data.name.endsWith('.link') ? 'img link' : 'img archive-folder'} + icon={data.name.endsWith('.link') ? 'img link' : data.name.endsWith('.zip') ? 'img zipfile' : 'img archive-folder'} isBold={data.name == $currentArchive} on:click={() => ($currentArchive = data.name)} menu={createMenu} diff --git a/packages/web/src/appobj/DatabaseAppObject.svelte b/packages/web/src/appobj/DatabaseAppObject.svelte index 37820aa95..e316cfd64 100644 --- a/packages/web/src/appobj/DatabaseAppObject.svelte +++ b/packages/web/src/appobj/DatabaseAppObject.svelte @@ -330,15 +330,15 @@ await dbgateApi.dropAllDbObjects(${JSON.stringify( }); }; - const handleImportWithDbDuplicator = () => { + const handleShowDataDeployer = () => { showModal(ChooseArchiveFolderModal, { - message: 'Choose archive folder for import from', + message: 'Choose archive folder for data deployer', onConfirm: archiveFolder => { openNewTab( { title: archiveFolder, - icon: 'img duplicator', - tabComponent: 'DataDuplicatorTab', + icon: 'img replicator', + tabComponent: 'DataDeployerTab', props: { conid: connection?._id, database: name, @@ -439,8 +439,8 @@ await dbgateApi.dropAllDbObjects(${JSON.stringify( driver?.databaseEngineTypes?.includes('sql') && hasPermission(`dbops/import`) && { - onClick: handleImportWithDbDuplicator, - text: 'Import with DB duplicator', + onClick: handleShowDataDeployer, + text: 'Data deployer', }, { divider: true }, diff --git a/packages/web/src/appobj/SavedFileAppObject.svelte b/packages/web/src/appobj/SavedFileAppObject.svelte index 99ccc2c15..da72c8ae8 100644 --- a/packages/web/src/appobj/SavedFileAppObject.svelte +++ b/packages/web/src/appobj/SavedFileAppObject.svelte @@ -7,6 +7,8 @@ tabComponent: string; folder: string; currentConnection: boolean; + extension: string; + label: string; } const sql: FileTypeHandler = { @@ -15,6 +17,8 @@ tabComponent: 'QueryTab', folder: 'sql', currentConnection: true, + extension: 'sql', + label: 'SQL file', }; const shell: FileTypeHandler = { @@ -23,6 +27,8 @@ tabComponent: 'ShellTab', folder: 'shell', currentConnection: false, + extension: 'js', + label: 'JavaScript Shell script', }; const markdown: FileTypeHandler = { @@ -31,6 +37,8 @@ tabComponent: 'MarkdownEditorTab', folder: 'markdown', currentConnection: false, + extension: 'md', + label: 'Markdown file', }; const charts: FileTypeHandler = { @@ -39,6 +47,8 @@ tabComponent: 'ChartTab', folder: 'charts', currentConnection: true, + extension: 'json', + label: 'Chart file', }; const query: FileTypeHandler = { @@ -47,6 +57,8 @@ tabComponent: 'QueryDesignTab', folder: 'query', currentConnection: true, + extension: 'json', + label: 'Query design file', }; const sqlite: FileTypeHandler = { @@ -55,6 +67,8 @@ tabComponent: null, folder: 'sqlite', currentConnection: true, + extension: 'sqlite', + label: 'SQLite database', }; const diagrams: FileTypeHandler = { @@ -63,22 +77,52 @@ tabComponent: 'DiagramTab', folder: 'diagrams', currentConnection: true, + extension: 'json', + label: 'Diagram file', }; - const jobs: FileTypeHandler = { + const impexp: FileTypeHandler = { icon: 'img export', format: 'json', tabComponent: 'ImportExportTab', - folder: 'jobs', + folder: 'impexp', currentConnection: false, + extension: 'json', + label: 'Import/Export file', }; + const datadeploy: FileTypeHandler = isProApp() + ? { + icon: 'img data-deploy', + format: 'json', + tabComponent: 'DataDeployTab', + folder: 'datadeploy', + currentConnection: false, + extension: 'json', + label: 'Data deploy file', + } + : undefined; + + const dbcompare: FileTypeHandler = isProApp() + ? { + icon: 'img compare', + format: 'json', + tabComponent: 'CompareModelTab', + folder: 'dbcompare', + currentConnection: false, + extension: 'json', + label: 'Database compare file', + } + : undefined; + const perspectives: FileTypeHandler = { icon: 'img perspective', format: 'json', tabComponent: 'PerspectiveTab', folder: 'pesrpectives', currentConnection: true, + extension: 'json', + label: 'Perspective file', }; const modtrans: FileTypeHandler = { @@ -87,6 +131,8 @@ tabComponent: 'ModelTransformTab', folder: 'modtrans', currentConnection: false, + extension: 'json', + label: 'Model transform file', }; export const SAVED_FILE_HANDLERS = { @@ -98,8 +144,10 @@ sqlite, diagrams, perspectives, - jobs, + impexp, modtrans, + datadeploy, + dbcompare, }; export const extractKey = data => data.file; @@ -122,6 +170,8 @@ import openNewTab from '../utility/openNewTab'; import AppObjectCore from './AppObjectCore.svelte'; + import { isProApp } from '../utility/proTools'; + import { saveFileToDisk } from '../utility/exportFileTools'; export let data; @@ -148,6 +198,7 @@ hasPermission(`files/${data.folder}/write`) && { text: 'Create copy', onClick: handleCopy }, hasPermission(`files/${data.folder}/write`) && { text: 'Delete', onClick: handleDelete }, folder == 'markdown' && { text: 'Show page', onClick: showMarkdownPage }, + { text: 'Download', onClick: handleDownload }, ]; } @@ -182,6 +233,19 @@ }); }; + const handleDownload = () => { + saveFileToDisk( + async filePath => { + await apiCall('files/export-file', { + folder, + file: data.file, + filePath, + }); + }, + { formatLabel: handler.label, formatExtension: handler.format, defaultFileName: data.file } + ); + }; + async function openTab() { const resp = await apiCall('files/load', { folder, file: data.file, format: handler.format }); diff --git a/packages/web/src/buttons/FormStyledButtonLikeLabel.svelte b/packages/web/src/buttons/FormStyledButtonLikeLabel.svelte index 17a4f4235..83799ac1b 100644 --- a/packages/web/src/buttons/FormStyledButtonLikeLabel.svelte +++ b/packages/web/src/buttons/FormStyledButtonLikeLabel.svelte @@ -17,6 +17,7 @@ border-radius: 2px; position: relative; top: 3px; + font-size: 10pt; } label:hover:not(.disabled) { diff --git a/packages/web/src/buttons/InlineUploadButton.svelte b/packages/web/src/buttons/InlineUploadButton.svelte new file mode 100644 index 000000000..9c6d8bd92 --- /dev/null +++ b/packages/web/src/buttons/InlineUploadButton.svelte @@ -0,0 +1,61 @@ + + +{#if electron} + + + +{:else} + {}} title="Upload file" data-testid={$$props['data-testid']} htmlFor={inputId}> + + +{/if} + + diff --git a/packages/web/src/buttons/LargeButton.svelte b/packages/web/src/buttons/LargeButton.svelte index 69459fd81..1f6d9e3c5 100644 --- a/packages/web/src/buttons/LargeButton.svelte +++ b/packages/web/src/buttons/LargeButton.svelte @@ -13,7 +13,7 @@ } -
+
diff --git a/packages/web/src/commands/stdCommands.ts b/packages/web/src/commands/stdCommands.ts index 8b99b6584..cef4daacd 100644 --- a/packages/web/src/commands/stdCommands.ts +++ b/packages/web/src/commands/stdCommands.ts @@ -46,6 +46,7 @@ import { openImportExportTab } from '../utility/importExportTools'; import newTable from '../tableeditor/newTable'; import { isProApp } from '../utility/proTools'; import { openWebLink } from '../utility/simpleTools'; +import ExportImportConnectionsModal from '../modals/ExportImportConnectionsModal.svelte'; // function themeCommand(theme: ThemeDefinition) { // return { @@ -509,6 +510,44 @@ registerCommand({ }, }); +registerCommand({ + id: 'app.exportConnections', + category: 'Settings', + name: 'Export connections', + testEnabled: () => getElectron() != null, + onClick: () => { + showModal(ExportImportConnectionsModal, { + mode: 'export', + }); + }, +}); + +registerCommand({ + id: 'app.importConnections', + category: 'Settings', + name: 'Import connections', + testEnabled: () => getElectron() != null, + onClick: async () => { + const files = await electron.showOpenDialog({ + properties: ['showHiddenFiles', 'openFile'], + filters: [ + { + name: `All supported files`, + extensions: ['zip'], + }, + { name: `ZIP files`, extensions: ['zip'] }, + ], + }); + + if (files?.length > 0) { + showModal(ExportImportConnectionsModal, { + mode: 'import', + uploadedFilePath: files[0], + }); + } + }, +}); + registerCommand({ id: 'file.import', category: 'File', diff --git a/packages/web/src/datagrid/DataGridCell.svelte b/packages/web/src/datagrid/DataGridCell.svelte index 3ed072aeb..ba618460c 100644 --- a/packages/web/src/datagrid/DataGridCell.svelte +++ b/packages/web/src/datagrid/DataGridCell.svelte @@ -21,6 +21,7 @@ export let isModifiedCell = false; export let isInserted = false; export let isDeleted = false; + export let isMissing = false; export let isAutofillSelected = false; export let isFocusedColumn = false; export let domCell = undefined; @@ -33,6 +34,9 @@ export let onSetValue; export let editorTypes = null; export let isReadonly; + export let hasOverlayValue = false; + export let overlayValue = null; + export let isMissingOverlayField = false; $: value = col.isStructured ? _.get(rowData || {}, col.uniquePath) : (rowData || {})[col.uniqueName]; @@ -68,75 +72,88 @@ class:isModifiedCell class:isInserted class:isDeleted + class:isMissing class:isAutofillSelected class:isFocusedColumn + class:hasOverlayValue + class:isMissingOverlayField class:alignRight={_.isNumber(value) && !showHint} {style} > - - - {#if showHint} - {col.hintColumnNames.map(hintColumnName => rowData[hintColumnName]).join(col.hintColumnDelimiter || ' ')} - {/if} - - {#if editorTypes?.explicitDataType} - {#if value !== undefined} - getConvertValueMenu(value, onSetValue, editorTypes)} - /> + {#if hasOverlayValue} +
+
+ +
+
+ +
+
+ {:else} + + {#if showHint} + {col.hintColumnNames.map(hintColumnName => rowData[hintColumnName]).join(col.hintColumnDelimiter || ' ')} {/if} - {#if _.isPlainObject(value)} - openJsonDocument(value, undefined, true)} /> - {/if} - {#if _.isArray(value)} + + {#if editorTypes?.explicitDataType} + {#if value !== undefined} + getConvertValueMenu(value, onSetValue, editorTypes)} + /> + {/if} + {#if _.isPlainObject(value)} + openJsonDocument(value, undefined, true)} /> + {/if} + {#if _.isArray(value)} + { + if (_.every(value, x => _.isPlainObject(x))) { + openJsonLinesData(value); + } else { + openJsonDocument(value, undefined, true); + } + }} + /> + {/if} + {:else if col.foreignKey && rowData && rowData[col.uniqueName] && !isCurrentCell} + onSetFormView(rowData, col)} /> + {:else if col.foreignKey && isCurrentCell && onDictionaryLookup && !isReadonly} + + {:else if isJson} + openJsonDocument(value, undefined, true)} /> + {:else if jsonParsedValue && _.isPlainObject(jsonParsedValue)} + openJsonDocument(jsonParsedValue, undefined, true)} /> + {:else if _.isArray(jsonParsedValue || value)} { - if (_.every(value, x => _.isPlainObject(x))) { - openJsonLinesData(value); + if (_.every(jsonParsedValue || value, x => _.isPlainObject(x))) { + openJsonLinesData(jsonParsedValue || value); } else { - openJsonDocument(value, undefined, true); + openJsonDocument(jsonParsedValue || value, undefined, true); } }} /> {/if} - {:else if col.foreignKey && rowData && rowData[col.uniqueName] && !isCurrentCell} - onSetFormView(rowData, col)} /> - {:else if col.foreignKey && isCurrentCell && onDictionaryLookup && !isReadonly} - - {:else if isJson} - openJsonDocument(value, undefined, true)} /> - {:else if jsonParsedValue && _.isPlainObject(jsonParsedValue)} - openJsonDocument(jsonParsedValue, undefined, true)} /> - {:else if _.isArray(jsonParsedValue || value)} - { - if (_.every(jsonParsedValue || value, x => _.isPlainObject(x))) { - openJsonLinesData(jsonParsedValue || value); - } else { - openJsonDocument(jsonParsedValue || value, undefined, true); - } - }} - /> - {/if} - {#if isAutoFillMarker} -
- {/if} + {#if isAutoFillMarker} +
+ {/if} - {#if showSlot} - + {#if showSlot} + + {/if} {/if} @@ -181,6 +198,9 @@ td.isDeleted { background: var(--theme-bg-volcano); } + td.isMissing { + background: var(--theme-bg-volcano); + } td.isSelected { background: var(--theme-bg-3); } @@ -188,9 +208,9 @@ background: var(--theme-bg-selected); } td.isDeleted { - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAEElEQVQImWNgIAX8x4KJBAD+agT8INXz9wAAAABJRU5ErkJggg=='); - background-repeat: repeat-x; - background-position: 50% 50%; + background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAEElEQVQImWNgIAX8x4KJBAD+agT8INXz9wAAAABJRU5ErkJggg==') !important; + background-repeat: repeat-x !important; + background-position: 50% 50% !important; } .hint { @@ -213,4 +233,31 @@ color: var(--theme-icon-green); text-align: var(--data-grid-numbers-align); } + + .hasOverlayValue .overlayCell { + width: 50%; + overflow: hidden; + } + + .hasOverlayValue .overlayCell1 { + margin-right: 5px; + } + + .hasOverlayValue .overlayCell2 { + margin-left: 5px; + } + + .replacedValue { + background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAEElEQVQImWNgIAX8x4KJBAD+agT8INXz9wAAAABJRU5ErkJggg=='); + background-repeat: repeat-x; + background-position: 50% 50%; + } + + td.isMissingOverlayField { + background: var(--theme-bg-orange); + + background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAEElEQVQImWNgIAX8x4KJBAD+agT8INXz9wAAAABJRU5ErkJggg=='); + background-repeat: repeat-x; + background-position: 50% 50%; + } diff --git a/packages/web/src/datagrid/DataGridCore.svelte b/packages/web/src/datagrid/DataGridCore.svelte index a24acd674..daa6e3536 100644 --- a/packages/web/src/datagrid/DataGridCore.svelte +++ b/packages/web/src/datagrid/DataGridCore.svelte @@ -282,48 +282,59 @@ testEnabled: () => getCurrentDataGrid()?.editCellValueEnabled(), onClick: () => getCurrentDataGrid().editCellValue(), }); - registerCommand({ - id: 'dataGrid.mergeSelectedCellsIntoMirror', - category: 'Data grid', - name: 'Merge selected cells', - testEnabled: () => getCurrentDataGrid()?.mirrorWriteEnabled(true), - onClick: () => getCurrentDataGrid().mergeSelectionIntoMirror({ mergeMode: 'merge', fullRows: false }), - }); - registerCommand({ - id: 'dataGrid.mergeSelectedRowsIntoMirror', - category: 'Data grid', - name: 'Merge selected rows', - testEnabled: () => getCurrentDataGrid()?.mirrorWriteEnabled(true), - onClick: () => getCurrentDataGrid().mergeSelectionIntoMirror({ mergeMode: 'merge', fullRows: true }), - }); - registerCommand({ - id: 'dataGrid.appendSelectedCellsIntoMirror', - category: 'Data grid', - name: 'Append selected cells', - testEnabled: () => getCurrentDataGrid()?.mirrorWriteEnabled(true), - onClick: () => getCurrentDataGrid().mergeSelectionIntoMirror({ mergeMode: 'append', fullRows: false }), - }); - registerCommand({ - id: 'dataGrid.appendSelectedRowsIntoMirror', - category: 'Data grid', - name: 'Append selected rows', - testEnabled: () => getCurrentDataGrid()?.mirrorWriteEnabled(true), - onClick: () => getCurrentDataGrid().mergeSelectionIntoMirror({ mergeMode: 'append', fullRows: true }), - }); - registerCommand({ - id: 'dataGrid.replaceSelectedCellsIntoMirror', - category: 'Data grid', - name: 'Replace with selected cells', - testEnabled: () => getCurrentDataGrid()?.mirrorWriteEnabled(true), - onClick: () => getCurrentDataGrid().mergeSelectionIntoMirror({ mergeMode: 'replace', fullRows: false }), - }); - registerCommand({ - id: 'dataGrid.replaceSelectedRowsIntoMirror', - category: 'Data grid', - name: 'Replace with selected rows', - testEnabled: () => getCurrentDataGrid()?.mirrorWriteEnabled(true), - onClick: () => getCurrentDataGrid().mergeSelectionIntoMirror({ mergeMode: 'replace', fullRows: true }), - }); + + if (isProApp()) { + registerCommand({ + id: 'dataGrid.sendToDataDeploy', + category: 'Data grid', + name: 'Send to data deployer', + testEnabled: () => getCurrentDataGrid()?.sendToDataDeployEnabled(), + onClick: () => getCurrentDataGrid().sendToDataDeploy(), + }); + } + + // registerCommand({ + // id: 'dataGrid.mergeSelectedCellsIntoMirror', + // category: 'Data grid', + // name: 'Merge selected cells', + // testEnabled: () => getCurrentDataGrid()?.mirrorWriteEnabled(true), + // onClick: () => getCurrentDataGrid().mergeSelectionIntoMirror({ mergeMode: 'merge', fullRows: false }), + // }); + // registerCommand({ + // id: 'dataGrid.mergeSelectedRowsIntoMirror', + // category: 'Data grid', + // name: 'Merge selected rows', + // testEnabled: () => getCurrentDataGrid()?.mirrorWriteEnabled(true), + // onClick: () => getCurrentDataGrid().mergeSelectionIntoMirror({ mergeMode: 'merge', fullRows: true }), + // }); + // registerCommand({ + // id: 'dataGrid.appendSelectedCellsIntoMirror', + // category: 'Data grid', + // name: 'Append selected cells', + // testEnabled: () => getCurrentDataGrid()?.mirrorWriteEnabled(true), + // onClick: () => getCurrentDataGrid().mergeSelectionIntoMirror({ mergeMode: 'append', fullRows: false }), + // }); + // registerCommand({ + // id: 'dataGrid.appendSelectedRowsIntoMirror', + // category: 'Data grid', + // name: 'Append selected rows', + // testEnabled: () => getCurrentDataGrid()?.mirrorWriteEnabled(true), + // onClick: () => getCurrentDataGrid().mergeSelectionIntoMirror({ mergeMode: 'append', fullRows: true }), + // }); + // registerCommand({ + // id: 'dataGrid.replaceSelectedCellsIntoMirror', + // category: 'Data grid', + // name: 'Replace with selected cells', + // testEnabled: () => getCurrentDataGrid()?.mirrorWriteEnabled(true), + // onClick: () => getCurrentDataGrid().mergeSelectionIntoMirror({ mergeMode: 'replace', fullRows: false }), + // }); + // registerCommand({ + // id: 'dataGrid.replaceSelectedRowsIntoMirror', + // category: 'Data grid', + // name: 'Replace with selected rows', + // testEnabled: () => getCurrentDataGrid()?.mirrorWriteEnabled(true), + // onClick: () => getCurrentDataGrid().mergeSelectionIntoMirror({ mergeMode: 'replace', fullRows: true }), + // }); function getSelectedCellsInfo(selectedCells, grider, realColumnUniqueNames, selectedRowData) { if (selectedCells.length > 1 && selectedCells.every(x => _.isNumber(x[0]) && _.isNumber(x[1]))) { @@ -418,6 +429,8 @@ import contextMenuActivator from '../utility/contextMenuActivator'; import InputTextModal from '../modals/InputTextModal.svelte'; import { _t } from '../translations'; + import { isProApp } from '../utility/proTools'; + import SaveArchiveModal from '../modals/SaveArchiveModal.svelte'; export let onLoadNextData = undefined; export let grider = undefined; @@ -454,6 +467,8 @@ export let jslid; // export let generalAllowSave = false; export let hideGridLeftColumn = false; + export let overlayDefinition = null; + export let onGetSelectionMenu = null; export const activator = createActivator('DataGridCore', false); @@ -482,6 +497,7 @@ const domFilterControlsRef = createRef({}); let isGridFocused = false; + let selectionMenu = null; const tabid = getContext('tabid'); @@ -1003,11 +1019,11 @@ }); } - export function mirrorWriteEnabled(requireKey) { - return requireKey ? !!display.baseTable?.primaryKey || !!display.baseCollection : !!display.baseTableOrSimilar; + export function sendToDataDeployEnabled() { + return !!display.baseTable?.primaryKey || !!display.baseCollection; } - export async function mergeSelectionIntoMirror({ fullRows, mergeMode = 'merge' }) { + export async function sendToDataDeploy() { const file = display.baseTableOrSimilar?.pureName; const mergeKey = display.baseCollection ? display.baseCollection?.uniqueKey?.map(x => x.columnName) @@ -1019,20 +1035,77 @@ const rows = rowIndexes.map(rowIndex => grider.getRowData(rowIndex)); // @ts-ignore const columns = colIndexes.map(col => realColumnUniqueNames[col]); - const mergedRows = fullRows ? rows : rows.map(x => _.pick(x, _.uniq([...columns, ...mergeKey]))); - const res = await apiCall('archive/modify-file', { + const mergedRows = rows.map(x => _.pick(x, _.uniq([...columns, ...mergeKey]))); + + showModal(SaveArchiveModal, { folder: $currentArchive, file, - mergedRows, - mergeKey, - mergeMode, + fileIsReadOnly: true, + onSave: async folder => { + const res = await apiCall('archive/modify-file', { + folder, + file, + mergedRows, + mergeKey, + mergeMode: 'merge', + }); + if (res) { + showSnackbarSuccess(`Merged ${mergedRows.length} rows into ${file} in archive ${folder}`); + + openNewTab( + { + title: folder, + icon: 'img data-deploy', + tabComponent: 'DataDeployTab', + props: { + conid, + database, + }, + }, + { + editor: { + archiveFolder: folder, + conid, + database, + }, + } + ); + } + }, }); - if (res) { - showSnackbarSuccess(`Merged ${mergedRows.length} rows into ${file} in archive ${$currentArchive}`); - } } + // export function mirrorWriteEnabled(requireKey) { + // return requireKey ? !!display.baseTable?.primaryKey || !!display.baseCollection : !!display.baseTableOrSimilar; + // } + + // export async function mergeSelectionIntoMirror({ fullRows, mergeMode = 'merge' }) { + // const file = display.baseTableOrSimilar?.pureName; + // const mergeKey = display.baseCollection + // ? display.baseCollection?.uniqueKey?.map(x => x.columnName) + // : display.baseTable?.primaryKey.columns.map(x => x.columnName); + + // const cells = cellsToRegularCells(selectedCells); + // const rowIndexes = _.sortBy(_.uniq(cells.map(x => x[0]))); + // const colIndexes = _.sortBy(_.uniq(cells.map(x => x[1]))); + // const rows = rowIndexes.map(rowIndex => grider.getRowData(rowIndex)); + // // @ts-ignore + // const columns = colIndexes.map(col => realColumnUniqueNames[col]); + // const mergedRows = fullRows ? rows : rows.map(x => _.pick(x, _.uniq([...columns, ...mergeKey]))); + + // const res = await apiCall('archive/modify-file', { + // folder: $currentArchive, + // file, + // mergedRows, + // mergeKey, + // mergeMode, + // }); + // if (res) { + // showSnackbarSuccess(`Merged ${mergedRows.length} rows into ${file} in archive ${$currentArchive}`); + // } + // } + export function canShowLeftPanel() { return !hideGridLeftColumn; } @@ -1152,8 +1225,16 @@ onChangeSelectedColumns(getSelectedColumns().map(x => x.columnName)); } + let publishedCells = null; + if (onPublishedCellsChanged) { - onPublishedCellsChanged(getCellsPublished(selectedCells)); + if (!publishedCells) publishedCells = getCellsPublished(selectedCells); + onPublishedCellsChanged(publishedCells); + } + + if (onGetSelectionMenu) { + if (!publishedCells) publishedCells = getCellsPublished(selectedCells); + selectionMenu = onGetSelectionMenu(publishedCells); } } }); @@ -1192,6 +1273,7 @@ engine: display?.driver, condition: display?.getChangeSetCondition(rowData), insertedRowIndex: grider?.getInsertedRowIndex(row), + rowStatus: grider.getRowStatus(row), }; }) .filter(x => x.column); @@ -1747,14 +1829,14 @@ { placeTag: 'save' }, { command: 'dataGrid.revertRowChanges', hideDisabled: true }, { command: 'dataGrid.revertAllChanges', hideDisabled: true }, - { command: 'dataGrid.deleteSelectedRows' }, - { command: 'dataGrid.insertNewRow' }, - { command: 'dataGrid.cloneRows' }, + { command: 'dataGrid.deleteSelectedRows', hideDisabled: true }, + { command: 'dataGrid.insertNewRow', hideDisabled: true }, + { command: 'dataGrid.cloneRows', hideDisabled: true }, { command: 'dataGrid.setNull', hideDisabled: true }, { command: 'dataGrid.removeField', hideDisabled: true }, { placeTag: 'edit' }, { divider: true }, - { command: 'dataGrid.findColumn' }, + { command: 'dataGrid.findColumn', hideDisabled: true }, { command: 'dataGrid.hideColumn', hideDisabled: true }, { command: 'dataGrid.filterSelected' }, { command: 'dataGrid.clearFilter' }, @@ -1773,17 +1855,18 @@ // { command: 'dataGrid.copyJsonDocument', hideDisabled: true }, { divider: true }, { placeTag: 'export' }, - { - label: 'Save to current archive', - submenu: [ - { command: 'dataGrid.mergeSelectedCellsIntoMirror' }, - { command: 'dataGrid.mergeSelectedRowsIntoMirror' }, - { command: 'dataGrid.appendSelectedCellsIntoMirror' }, - { command: 'dataGrid.appendSelectedRowsIntoMirror' }, - { command: 'dataGrid.replaceSelectedCellsIntoMirror' }, - { command: 'dataGrid.replaceSelectedRowsIntoMirror' }, - ], - }, + // { + // label: 'Save to current archive', + // submenu: [ + // { command: 'dataGrid.mergeSelectedCellsIntoMirror' }, + // { command: 'dataGrid.mergeSelectedRowsIntoMirror' }, + // { command: 'dataGrid.appendSelectedCellsIntoMirror' }, + // { command: 'dataGrid.appendSelectedRowsIntoMirror' }, + // { command: 'dataGrid.replaceSelectedCellsIntoMirror' }, + // { command: 'dataGrid.replaceSelectedRowsIntoMirror' }, + // ], + // }, + isProApp() && { command: 'dataGrid.sendToDataDeploy' }, { command: 'dataGrid.generateSqlFromData' }, { command: 'dataGrid.openFreeTable' }, { command: 'dataGrid.openChartFromSelection' }, @@ -2017,6 +2100,7 @@ onSetFormView={formViewAvailable && display?.baseTable?.primaryKey ? handleSetFormView : null} {dataEditorTypesBehaviourOverride} {gridColoringMode} + {overlayDefinition} /> {/each} @@ -2053,7 +2137,19 @@ on:scroll={e => (firstVisibleRowScrollIndex = e.detail)} bind:this={domVerticalScroll} /> - {#if selectedCellsInfo} + {#if selectionMenu} +
+ {#each selectionMenu as item} + { + item.onClick(); + }} + > + {item.text} + + {/each} +
+ {:else if selectedCellsInfo}
{selectedCellsInfo}
@@ -2118,6 +2214,13 @@ bottom: 20px; } + .selection-menu { + position: absolute; + background-color: var(--theme-bg-2); + right: 40px; + bottom: 20px; + } + .no-rows-info { margin-top: 60px; } diff --git a/packages/web/src/datagrid/DataGridRow.svelte b/packages/web/src/datagrid/DataGridRow.svelte index 66f33fa2b..6110a754f 100644 --- a/packages/web/src/datagrid/DataGridRow.svelte +++ b/packages/web/src/datagrid/DataGridRow.svelte @@ -1,5 +1,19 @@ + + - onSetFormView(rowData, null) : null} /> + onSetFormView(rowData, null) : null} + extraIcon={overlayDefinition ? OVERLAY_STATUS_ICONS[rowStatus.status] : null} + extraIconTooltip={overlayDefinition ? OVERLAY_STATUS_TOOLTIPS[rowStatus.status] : null} + /> {#each visibleRealColumns as col (col.uniqueName)} {#if inplaceEditorState.cell && rowIndex == inplaceEditorState.cell[0] && col.colIndex == inplaceEditorState.cell[1]} ; insertedFields?: Set; deletedFields?: Set; + overlayFields?: { [field: string]: string }; + missingOverlayFields?: Set; } export default abstract class Grider { @@ -61,4 +63,7 @@ export default abstract class Grider { this.setCellValue(index, key, changeObject[key]); } } + getInsertedRowIndex(index) { + return null; + } } diff --git a/packages/web/src/datagrid/JslDataGrid.svelte b/packages/web/src/datagrid/JslDataGrid.svelte index 9081b001d..002751fcd 100644 --- a/packages/web/src/datagrid/JslDataGrid.svelte +++ b/packages/web/src/datagrid/JslDataGrid.svelte @@ -20,7 +20,7 @@ export let allowChangeChangeSetStructure = false; export let infoLoadCounter = 0; - export let driver; + export let driver = null; let loadedRows; let infoCounter = 0; diff --git a/packages/web/src/datagrid/OverlayDiffGrider.ts b/packages/web/src/datagrid/OverlayDiffGrider.ts new file mode 100644 index 000000000..0aae3a998 --- /dev/null +++ b/packages/web/src/datagrid/OverlayDiffGrider.ts @@ -0,0 +1,110 @@ +import { GridDisplay } from 'dbgate-datalib'; +import Grider from './Grider'; +import { GriderRowStatus } from './Grider'; +import _uniq from 'lodash/uniq'; + +export default class OverlayDiffGrider extends Grider { + private prependRows: any[]; + private rowCacheIndexes: Set; + private rowDataCache; + private rowStatusCache; + private overlayRowsByStr: { [key: string]: any }; + + constructor( + public sourceRows: any[], + public display: GridDisplay, + public matchColumns: string[], + public overlayData: any[], + public matchedDbKeys: any[][] + ) { + super(); + const matchedDbKeysByStr = new Set(matchedDbKeys.map(x => x.join('||'))); + this.prependRows = overlayData.filter(row => !matchedDbKeysByStr.has(matchColumns.map(x => row[x]).join('||'))); + this.overlayRowsByStr = {}; + for (const row of overlayData) { + const key = matchColumns.map(x => row[x]).join('||'); + this.overlayRowsByStr[key] = row; + } + + this.rowDataCache = {}; + this.rowStatusCache = {}; + this.rowCacheIndexes = new Set(); + } + + requireRowCache(index: number) { + if (this.rowCacheIndexes.has(index)) return; + + if (index < this.prependRows.length) { + this.rowStatusCache[index] = { + status: 'inserted', + }; + this.rowDataCache[index] = this.prependRows[index]; + this.rowCacheIndexes.add(index); + return; + } + + const row = this.sourceRows[index - this.prependRows.length]; + + if (!row) { + this.rowStatusCache[index] = { + status: 'missing', + }; + this.rowDataCache[index] = row; + this.rowCacheIndexes.add(index); + return; + } + + const overlayKey = this.matchColumns.map(x => row[x]).join('||'); + const overlayRow = this.overlayRowsByStr[overlayKey]; + + if (!overlayRow) { + this.rowStatusCache[index] = { + status: 'missing', + }; + this.rowDataCache[index] = row; + this.rowCacheIndexes.add(index); + return; + } + + const overlayFields = {}; + const missingOverlayFields = new Set(); + + for (const field of this.display.columns.map(x => x.columnName)) { + if (!(field in overlayRow)) { + missingOverlayFields.add(field); + } else if (row[field] != overlayRow[field]) { + overlayFields[field] = overlayRow[field]; + } + } + + if (Object.keys(overlayFields).length > 0 || missingOverlayFields.size > 0) { + this.rowStatusCache[index] = { + status: 'updated', + overlayFields, + missingOverlayFields, + modifiedFields: new Set(Object.keys(overlayFields)), + }; + this.rowDataCache[index] = row; + } else { + this.rowStatusCache[index] = { + status: 'regular', + }; + this.rowDataCache[index] = row; + } + this.rowCacheIndexes.add(index); + } + + getRowData(index: number) { + this.requireRowCache(index); + return this.rowDataCache[index]; + } + + getRowStatus(index): GriderRowStatus { + this.requireRowCache(index); + return this.rowStatusCache[index]; + } + + get rowCount() { + return this.sourceRows.length + this.prependRows.length; + } +} diff --git a/packages/web/src/datagrid/RowHeaderCell.svelte b/packages/web/src/datagrid/RowHeaderCell.svelte index d56fba8e0..c4a3612bb 100644 --- a/packages/web/src/datagrid/RowHeaderCell.svelte +++ b/packages/web/src/datagrid/RowHeaderCell.svelte @@ -1,9 +1,13 @@ @@ -18,6 +22,11 @@ {#if mouseIn && onShowForm} {/if} + {#if extraIcon} +
+ +
+ {/if} diff --git a/packages/web/src/datagrid/SqlDataGridCore.svelte b/packages/web/src/datagrid/SqlDataGridCore.svelte index caa6ec989..3241c92b2 100644 --- a/packages/web/src/datagrid/SqlDataGridCore.svelte +++ b/packages/web/src/datagrid/SqlDataGridCore.svelte @@ -83,6 +83,7 @@ import hasPermission from '../utility/hasPermission'; import { openImportExportTab } from '../utility/importExportTools'; import { getIntSettingsValue } from '../settings/settingsTools'; + import OverlayDiffGrider from './OverlayDiffGrider'; export let conid; export let display; @@ -92,6 +93,7 @@ export let config; export let changeSetState; export let dispatchChangeSet; + export let overlayDefinition = null; export let macroPreview; export let macroValues; @@ -110,7 +112,7 @@ // $: console.log('loadedRows BIND', loadedRows); $: { - if (macroPreview) { + if (!overlayDefinition && macroPreview) { grider = new ChangeSetGrider( loadedRows, changeSetState, @@ -124,13 +126,25 @@ } // prevent recreate grider, if no macro is selected, so there is no need to selectedcells in macro $: { - if (!macroPreview) { + if (!overlayDefinition && !macroPreview) { grider = new ChangeSetGrider(loadedRows, changeSetState, dispatchChangeSet, display); } } // $: console.log('GRIDER', grider); // $: if (onChangeGrider) onChangeGrider(grider); + $: { + if (overlayDefinition) { + grider = new OverlayDiffGrider( + loadedRows, + display, + overlayDefinition.matchColumns, + overlayDefinition.overlayData, + overlayDefinition.matchedDbKeys + ); + } + } + export async function exportGrid() { const coninfo = await getConnectionInfo({ conid }); diff --git a/packages/web/src/datagrid/TableDataGrid.svelte b/packages/web/src/datagrid/TableDataGrid.svelte index 8272ccccc..4573186ad 100644 --- a/packages/web/src/datagrid/TableDataGrid.svelte +++ b/packages/web/src/datagrid/TableDataGrid.svelte @@ -47,6 +47,8 @@ export let isRawMode = false; + export let forceReadOnly = false; + $: connection = useConnectionInfo({ conid }); $: dbinfo = useDatabaseInfo({ conid, database }); $: serverVersion = useDatabaseServerVersion({ conid, database }); @@ -73,7 +75,7 @@ { showHintColumns: getBoolSettingsValue('dataGrid.showHintColumns', true) }, $serverVersion, table => getDictionaryDescription(table, conid, database, $apps, $connections), - $connection?.isReadOnly, + forceReadOnly || $connection?.isReadOnly, isRawMode ) : null; @@ -161,7 +163,7 @@ formViewComponent={SqlFormView} {display} showReferences - showMacros={!$connection?.isReadOnly} + showMacros={!forceReadOnly && !$connection?.isReadOnly} hasMultiColumnFilter onRunMacro={handleRunMacro} macroCondition={macro => macro.type == 'transformValue'} diff --git a/packages/web/src/elements/TableControl.svelte b/packages/web/src/elements/TableControl.svelte index 1259de159..355dce0fc 100644 --- a/packages/web/src/elements/TableControl.svelte +++ b/packages/web/src/elements/TableControl.svelte @@ -7,6 +7,7 @@ props?: any; formatter?: any; slot?: number; + slotKey?: string; isHighlighted?: Function; sortable?: boolean; filterable?: boolean; @@ -25,12 +26,15 @@ import { evalFilterBehaviour } from 'dbgate-tools'; import { evaluateCondition } from 'dbgate-sqltree'; import { compileCompoudEvalCondition } from 'dbgate-filterparser'; + import { chevronExpandIcon } from '../icons/expandIcons'; export let columns: (TableControlColumn | false)[]; - export let rows; + export let rows = null; + export let groupedRows = null; export let focusOnCreate = false; export let selectable = false; export let selectedIndex = 0; + export let selectedKey = null; export let clickable = false; export let disableFocusOutline = false; export let emptyMessage = null; @@ -41,9 +45,12 @@ export let checkedKeys = null; export let onSetCheckedKeys = null; - export let extractCheckedKey = x => x.id; + export let extractTableItemKey = x => x.id; + export let itemSupportsCheckbox = x => true; export let filters = null; + export let selectionMode: 'index' | 'key' = 'index'; + const dispatch = createEventDispatcher(); $: columnList = _.compact(_.flatten(columns)); @@ -53,37 +60,120 @@ }); const handleKeyDown = event => { - if (event.keyCode == keycodes.downArrow) { - selectedIndex = Math.min(selectedIndex + 1, sortedRows.length - 1); + const oldSelectedIndex = + selectionMode == 'index' ? selectedIndex : _.findIndex(flatRowsShown, x => extractTableItemKey(x) == selectedKey); + let newIndex = oldSelectedIndex; + + switch (event.keyCode) { + case keycodes.downArrow: + newIndex = Math.min(newIndex + 1, flatRowsShown.length - 1); + break; + case keycodes.upArrow: + newIndex = Math.max(0, newIndex - 1); + break; + case keycodes.home: + newIndex = 0; + break; + case keycodes.end: + newIndex = rows.length - 1; + break; + case keycodes.pageUp: + newIndex -= 10; + break; + case keycodes.pageDown: + newIndex += 10; + break; } - if (event.keyCode == keycodes.upArrow) { - selectedIndex = Math.max(0, selectedIndex - 1); + if (newIndex < 0) { + newIndex = 0; + } + if (newIndex >= flatRowsShown.length) { + newIndex = flatRowsShown.length - 1; + } + + if (clickable && oldSelectedIndex != newIndex) { + event.preventDefault(); + domRows[newIndex]?.scrollIntoView(); + if (clickable) { + dispatch('clickrow', flatRowsShown[newIndex]); + } + if (selectionMode == 'index') { + selectedIndex = newIndex; + } else { + selectedKey = extractTableItemKey(flatRowsShown[newIndex]); + } } }; - function filterRows(rows, filters) { + function filterRows(grows, filters) { const condition = compileCompoudEvalCondition(filters); - if (!condition) return rows; + if (!condition) return grows; - return rows.filter(row => { - const newrow = { ...row }; - for (const col of columnList) { - if (col.filteredExpression) { - newrow[col.fieldName] = col.filteredExpression(row); - } - } - return evaluateCondition(condition, newrow); - }); + return grows + .map(gitem => { + return { + group: gitem.group, + rows: gitem.rows.filter(row => { + const newrow = { ...row }; + for (const col of columnList) { + if (col.filteredExpression) { + newrow[col.fieldName] = col.filteredExpression(row); + } + } + return evaluateCondition(condition, newrow); + }), + }; + }) + .filter(gitem => gitem.rows.length > 0); } + // function computeGroupedRows(array) { + // if (!extractGroupName) { + // return [{ label: null, rows: array }]; + // } + // const res = []; + // let lastGroupName = null; + // let buildArray = []; + // for (const item of array) { + // const groupName = extractGroupName(item); + // if (lastGroupName != groupName) { + // if (buildArray.length > 0) { + // res.push({ label: lastGroupName, rows: buildArray }); + // } + // lastGroupName = groupName; + // buildArray = []; + // } + // buildArray.push(item); + // } + // if (buildArray.length > 0) { + // res.push({ label: lastGroupName, rows: buildArray }); + // } + // } + let sortedByField = null; let sortOrderIsDesc = false; + let collapsedGroupIndexes = []; + let domRows = {}; - $: filteredRows = filters ? filterRows(rows, $filters) : rows; + $: rowsSource = groupedRows ? groupedRows : [{ group: null, rows }]; - $: sortedRowsTmp = sortedByField ? _.sortBy(filteredRows || [], sortedByField) : filteredRows; - $: sortedRows = sortOrderIsDesc ? [...sortedRowsTmp].reverse() : sortedRowsTmp; + $: filteredRows = filters ? filterRows(rowsSource, $filters) : rowsSource; + + $: sortedRows = sortedByField + ? filteredRows.map(gitem => { + let res = _.sortBy(gitem.rows, sortedByField); + if (sortOrderIsDesc) res = [...res].reverse(); + return { group: gitem.group, rows: res }; + }) + : filteredRows; + + // $: console.log('sortedRows', sortedRows); + + $: flatRowsShown = sortedRows.map(gitem => gitem.rows).flat(); + $: checkableFlatRowsShown = flatRowsShown.filter(x => itemSupportsCheckbox(x)); + + // $: groupedRows = computeGroupedRows(sortedRows); {#if checkedKeys} - + {/if} {#each columnList as col} + {/if} {#each columnList as col} - {#each sortedRows as row, index} - { - if (selectable) { - selectedIndex = index; - domTable.focus(); - } - if (clickable) { - dispatch('clickrow', row); - } - }} - > - {#if checkedKeys} - + - {/if} - {#each columnList as col} - {@const rowProps = { ...col.props, ...(col.getProps ? col.getProps(row) : null) }} - + {/if} + {#if !collapsedGroupIndexes.includes(groupIndex)} + {#each gitem.rows as row} + {@const index = _.indexOf(flatRowsShown, row)} + { + if (selectable) { + if (selectionMode == 'index') { + selectedIndex = index; + } else { + selectedKey = extractTableItemKey(row); + } + domTable.focus(); + } + if (clickable) { + dispatch('clickrow', row); + } + }} + > + {#if checkedKeys} + {/if} - + {#each columnList as col} + {@const rowProps = { ...col.props, ...(col.getProps ? col.getProps(row) : null) }} + + {/each} + {/each} - + {/if} {/each} {#if emptyMessage && sortedRows.length == 0} @@ -223,6 +355,9 @@ background: var(--theme-bg-0); } tbody tr.selected { + background: var(--theme-bg-3); + } + table:focus tbody tr.selected { background: var(--theme-bg-selected); } tbody tr.clickable:hover { @@ -287,4 +422,9 @@ .empty-cell { background-color: var(--theme-bg-1); } + + .groupcell { + background-color: var(--theme-bg-1); + cursor: pointer; + } diff --git a/packages/web/src/forms/FormArchiveFilesSelect.svelte b/packages/web/src/forms/FormArchiveFilesSelect.svelte index 6df97b04b..c2dee45bd 100644 --- a/packages/web/src/forms/FormArchiveFilesSelect.svelte +++ b/packages/web/src/forms/FormArchiveFilesSelect.svelte @@ -10,14 +10,17 @@ export let folderName; export let name; + export let filterExtension = null; const { setFieldValue, values } = getFormContext(); $: files = useArchiveFiles({ folder: folderName }); - $: filesOptions = ($files || []).map(x => ({ - value: x.name, - label: x.name, - })); + $: filesOptions = ($files || []) + .filter(x => (filterExtension ? x.name.endsWith('.' + filterExtension) : true)) + .map(x => ({ + value: x.name, + label: x.name, + }));
diff --git a/packages/web/src/forms/FormArchiveFolderSelect.svelte b/packages/web/src/forms/FormArchiveFolderSelect.svelte index dde3b3514..1ec091ef7 100644 --- a/packages/web/src/forms/FormArchiveFolderSelect.svelte +++ b/packages/web/src/forms/FormArchiveFolderSelect.svelte @@ -11,16 +11,22 @@ export let additionalFolders = []; export let name; + export let allowCreateNew = false; + export let zipFilesOnly = false; + export let skipZipFiles = false; const { setFieldValue } = getFormContext(); const folders = useArchiveFolders(); $: folderOptions = [ - ...($folders || []).map(folder => ({ - value: folder.name, - label: folder.name, - })), + ...($folders || []) + .filter(folder => (zipFilesOnly ? folder.name.endsWith('.zip') : true)) + .filter(folder => (skipZipFiles ? !folder.name.endsWith('.zip') : true)) + .map(folder => ({ + value: folder.name, + label: folder.name, + })), ...additionalFolders .filter(x => x != '@create') .filter(x => !($folders || []).find(y => y.name == x)) @@ -28,7 +34,7 @@ value: folder, label: folder, })), - { + allowCreateNew && { label: '(Create new)', value: '@create', }, diff --git a/packages/web/src/forms/FormCheckboxField.svelte b/packages/web/src/forms/FormCheckboxField.svelte index 48682428b..122b9a010 100644 --- a/packages/web/src/forms/FormCheckboxField.svelte +++ b/packages/web/src/forms/FormCheckboxField.svelte @@ -22,7 +22,7 @@ ? { disabled: true } : { onClick: () => { - setFieldValue(name, !$values[name]); + setFieldValue(name, $values?.[name] == 0 ? true : $values?.[name] == 1 ? false : !$values?.[name]); dispatch('change'); }, }} diff --git a/packages/web/src/forms/FormCheckboxFieldRaw.svelte b/packages/web/src/forms/FormCheckboxFieldRaw.svelte index 4df086de8..c51bc3dee 100644 --- a/packages/web/src/forms/FormCheckboxFieldRaw.svelte +++ b/packages/web/src/forms/FormCheckboxFieldRaw.svelte @@ -11,4 +11,9 @@ } - + diff --git a/packages/web/src/icons/FontIcon.svelte b/packages/web/src/icons/FontIcon.svelte index 0c00fd046..8190919fc 100644 --- a/packages/web/src/icons/FontIcon.svelte +++ b/packages/web/src/icons/FontIcon.svelte @@ -110,6 +110,7 @@ 'icon history': 'mdi mdi-history', 'icon structure': 'mdi mdi-tools', 'icon square': 'mdi mdi-square', + 'icon data-deploy': 'mdi mdi-database-settings', 'icon edit': 'mdi mdi-pencil', 'icon delete': 'mdi mdi-delete', @@ -206,6 +207,8 @@ 'icon type-objectid': 'mdi mdi-alpha-i-box', 'icon type-null': 'mdi mdi-code-equal', 'icon type-unknown': 'mdi mdi-help-box', + 'icon equal': 'mdi mdi-equal', + 'icon not-equal': 'mdi mdi-not-equal-variant', 'icon at': 'mdi mdi-at', 'icon expand-all': 'mdi mdi-expand-all', @@ -218,6 +221,7 @@ 'icon autocommit-off': 'mdi mdi-check-circle-outline', 'icon premium': 'mdi mdi-star', + 'icon upload': 'mdi mdi-upload', 'img ok': 'mdi mdi-check-circle color-icon-green', 'img ok-inv': 'mdi mdi-check-circle color-icon-inv-green', @@ -232,12 +236,14 @@ 'img archive': 'mdi mdi-table color-icon-gold', 'img archive-folder': 'mdi mdi-database-outline color-icon-green', + 'img zipfile': 'mdi mdi-zip-box color-icon-gold', 'img autoincrement': 'mdi mdi-numeric-1-box-multiple-outline', 'img column': 'mdi mdi-table-column', 'img server': 'mdi mdi-server color-icon-blue', 'img primary-key': 'mdi mdi-key-star color-icon-yellow', 'img foreign-key': 'mdi mdi-key-link', 'img sql-file': 'mdi mdi-file', + 'img anyfile': 'mdi mdi-file-question color-icon-red', 'img shell': 'mdi mdi-flash color-icon-blue', 'img chart': 'mdi mdi-chart-bar color-icon-magenta', 'img markdown': 'mdi mdi-application color-icon-red', @@ -301,7 +307,7 @@ 'img type-rejson': 'mdi mdi-color-json color-icon-blue', 'img keydb': 'mdi mdi-key color-icon-blue', - 'img duplicator': 'mdi mdi-content-duplicate color-icon-green', + 'img replicator': 'mdi mdi-content-duplicate color-icon-green', 'img import': 'mdi mdi-database-import color-icon-green', 'img export': 'mdi mdi-database-export color-icon-green', 'img transform': 'mdi mdi-rotate-orbit color-icon-blue', @@ -311,6 +317,8 @@ 'img db-backup': 'mdi mdi-database-export color-icon-yellow', 'img db-restore': 'mdi mdi-database-import color-icon-red', + 'img settings': 'mdi mdi-cog color-icon-blue', + 'img data-deploy': 'mdi mdi-database-settings color-icon-green', }; diff --git a/packages/web/src/impexp/FormConnectionSelect.svelte b/packages/web/src/impexp/FormConnectionSelect.svelte index 49c5f5feb..5789c7162 100644 --- a/packages/web/src/impexp/FormConnectionSelect.svelte +++ b/packages/web/src/impexp/FormConnectionSelect.svelte @@ -5,7 +5,7 @@ import { getConnectionLabel } from 'dbgate-tools'; export let allowChooseModel = false; - export let direction; + export let direction = 'source'; $: connections = useConnectionList(); $: connectionOptions = [ diff --git a/packages/web/src/impexp/SourceTargetConfig.svelte b/packages/web/src/impexp/SourceTargetConfig.svelte index d4e6421f4..8c20688a5 100644 --- a/packages/web/src/impexp/SourceTargetConfig.svelte +++ b/packages/web/src/impexp/SourceTargetConfig.svelte @@ -25,6 +25,9 @@ import { _t } from '../translations'; import { showModal } from '../modals/modalTools'; import InputTextModal from '../modals/InputTextModal.svelte'; + import FormCheckboxField from '../forms/FormCheckboxField.svelte'; + import { isProApp } from '../utility/proTools'; + import FormTextField from '../forms/FormTextField.svelte'; export let direction; export let storageTypeField; @@ -133,6 +136,41 @@ label="Storage type" /> + {#if format && isProApp()} + {#if direction == 'source'} + + {#if $values.importFromZipFile} + + {/if} + {/if} + {#if direction == 'target'} + + {#if $values.exportToZipFile} + + + + {/if} + {/if} + {/if} + {#if storageType == 'database' || storageType == 'query'} @@ -173,18 +211,20 @@ label="Archive folder" name={archiveFolderField} additionalFolders={_.compact([$values[archiveFolderField]])} + allowCreateNew={direction == 'target'} /> {/if} - {#if storageType == 'archive' && direction == 'source'} + {#if direction == 'source' && (storageType == 'archive' || $values.importFromZipFile)} {/if} - {#if format && direction == 'source'} + {#if format && direction == 'source' && !$values.importFromZipFile} {/if} diff --git a/packages/web/src/impexp/createImpExpScript.ts b/packages/web/src/impexp/createImpExpScript.ts index 6218f2ec0..3414a306b 100644 --- a/packages/web/src/impexp/createImpExpScript.ts +++ b/packages/web/src/impexp/createImpExpScript.ts @@ -1,4 +1,5 @@ import _ from 'lodash'; +import moment from 'moment'; import { ScriptWriter, ScriptWriterJson } from 'dbgate-tools'; import getAsArray from '../utility/getAsArray'; import { getConnectionInfo } from '../utility/metadataLoaders'; @@ -93,7 +94,13 @@ function getSourceExpr(extensions, sourceName, values, sourceConnection, sourceD return [ format.readerFunc, { - ..._.omit(sourceFile, ['isDownload']), + ...(sourceFile + ? _.omit(sourceFile, ['isDownload']) + : { + fileName: values.importFromZipFile + ? `zip://archive:${values.sourceArchiveFolder}//${sourceName}` + : sourceName, + }), ...extractFormatApiParameters(values, 'source', format), }, ]; @@ -237,6 +244,13 @@ export default async function createImpExpScript(extensions, values, forceScript script.copyStream(sourceVar, targetVar, colmapVar, sourceName); script.endLine(); } + + if (values.exportToZipFile) { + let zipFileName = values.exportToZipFileName || `zip-archive-${moment().format('YYYY-MM-DD-HH-mm-ss')}.zip`; + if (!zipFileName.endsWith('.zip')) zipFileName += '.zip'; + script.zipDirectory('.', values.createZipFileInArchive ? 'archive:' + zipFileName : zipFileName); + } + return script.getScript(values.schedule); } diff --git a/packages/web/src/modals/ChooseArchiveFolderModal.svelte b/packages/web/src/modals/ChooseArchiveFolderModal.svelte index 8374f10fc..2798b01fd 100644 --- a/packages/web/src/modals/ChooseArchiveFolderModal.svelte +++ b/packages/web/src/modals/ChooseArchiveFolderModal.svelte @@ -17,7 +17,7 @@
{message}
- + + import { onMount } from 'svelte'; + + import FormStyledButton from '../buttons/FormStyledButton.svelte'; + import FormProvider from '../forms/FormProvider.svelte'; + + import ModalBase from './ModalBase.svelte'; + import { closeCurrentModal } from './modalTools'; + import { _t } from '../translations'; + import { apiCall } from '../utility/api'; + import TabControl from '../elements/TabControl.svelte'; + import TableControl from '../elements/TableControl.svelte'; + import { writable } from 'svelte/store'; + import LargeButton from '../buttons/LargeButton.svelte'; + import { downloadFromApi } from '../utility/exportFileTools'; + import getElectron from '../utility/getElectron'; + import { showSnackbarSuccess } from '../utility/snackbar'; + import { format } from 'date-fns'; + import Link from '../elements/Link.svelte'; + import _ from 'lodash'; + + export let mode: 'export' | 'import'; + export let uploadedFilePath = undefined; + + let fullData: any = {}; + + async function loadExportedData() { + fullData = await apiCall('config/export-connections-and-settings'); + initFromFullData(); + } + + async function loadImportedData() { + fullData = await apiCall('files/get-jsons-from-zip', { filePath: uploadedFilePath }); + initFromFullData(); + } + + function initFromFullData() { + connections = fullData.connections || []; + users = fullData.users || []; + roles = fullData.roles || []; + authMethods = fullData.auth_methods || []; + config = fullData.config || []; + + handleCheckAll(true); + } + + function handleCheckAll(checked) { + if (checked) { + checkedConnections = connections.map(x => x.id); + checkedUsers = users.map(x => x.id); + checkedRoles = roles.map(x => x.id); + checkedAuthMethods = authMethods.map(x => x.id); + checkedConfig = config.map(x => x.id); + } else { + checkedConnections = []; + checkedUsers = []; + checkedRoles = []; + checkedAuthMethods = []; + checkedConfig = []; + } + } + + onMount(() => { + if (mode == 'export') { + loadExportedData(); + } + if (mode == 'import') { + loadImportedData(); + } + }); + + function getLimitedData() { + const limitedData: any = { + connections: fullData.connections?.filter(x => checkedConnections.includes(x.id)), + + users: fullData.users?.filter(x => checkedUsers.includes(x.id)), + + user_connections: fullData.user_connections?.filter( + x => checkedUsers.includes(x.user_id) && checkedConnections.includes(x.connection_id) + ), + user_roles: fullData.user_roles?.filter(x => checkedUsers.includes(x.user_id) && checkedRoles.includes(x.role_id)), + user_permissions: fullData.user_permissions?.filter(x => checkedUsers.includes(x.user_id)), + + roles: fullData.roles?.filter(x => checkedRoles.includes(x.id)), + role_connections: fullData.role_connections?.filter( + x => checkedRoles.includes(x.role_id) && checkedConnections.includes(x.connection_id) + ), + role_permissions: fullData.role_permissions?.filter(x => checkedRoles.includes(x.role_id)), + + auth_methods: fullData.auth_methods?.filter(x => checkedAuthMethods.includes(x.id)), + auth_methods_config: fullData.auth_methods_config?.filter(x => checkedAuthMethods.includes(x.auth_method_id)), + + config: fullData.config?.filter( + x => checkedConfig.includes(x.id) || (x.group == 'admin' && x.key == 'encryptionKey') + ), + }; + return limitedData; + } + + async function handleExport() { + const electron = getElectron(); + + let filePath; + let fileName; + + if (electron) { + const electron = getElectron(); + filePath = await electron.showSaveDialog({ + filters: [ + { name: `ZIP files`, extensions: ['zip'] }, + { name: `All files`, extensions: ['*'] }, + ], + defaultPath: `dbgateconfig.zip`, + properties: ['showOverwriteConfirmation'], + }); + } else { + const resp = await apiCall('files/generate-uploads-file', { extension: 'sql' }); + filePath = resp.filePath; + fileName = resp.fileName; + } + + console.log('SELECTED PATH', filePath); + + if (!filePath) { + return; + } + + await apiCall('files/create-zip-from-jsons', { db: getLimitedData(), filePath }); + + if (electron) { + showSnackbarSuccess(`Saved to file ${filePath}`); + } else { + await downloadFromApi(`uploads/get?file=${fileName}`, `dbgateconfig.zip`); + } + } + + async function handleSaveToArchive() { + const filePath = `archive:dbgateconfig-${format(new Date(), 'yyyy-MM-dd-HH-mm-ss')}.zip`; + await apiCall('files/create-zip-from-jsons', { db: getLimitedData(), filePath }); + showSnackbarSuccess(`Saved to ${filePath}`); + } + + async function handleImport() { + await apiCall('config/import-connections-and-settings', { db: getLimitedData() }); + showSnackbarSuccess(`Imported connections and settings`); + } + + let connections = []; + let checkedConnections = []; + + let users = []; + let checkedUsers = []; + + let roles = []; + let checkedRoles = []; + + let authMethods = []; + let checkedAuthMethods = []; + + let config = []; + let checkedConfig = []; + + const connectionFilters = writable({}); + const userFilters = writable({}); + const roleFilters = writable({}); + const authMethodFilters = writable({}); + const configFilters = writable({}); + + + + +
+ {mode == 'export' ? 'Export' : 'Import'} connections & settings + + handleCheckAll(true)}>Check all + | + handleCheckAll(false)}>Uncheck all + +
+ +
+ + +
+ { + checkedConnections = checkedConnections.includes(event.detail.id) + ? checkedConnections.filter(id => id !== event.detail.id) + : [...checkedConnections, event.detail.id]; + }} + checkedKeys={checkedConnections} + onSetCheckedKeys={keys => { + checkedConnections = keys; + }} + > +
+
+ +
+ { + checkedUsers = checkedUsers.includes(event.detail.id) + ? checkedUsers.filter(id => id !== event.detail.id) + : [...checkedUsers, event.detail.id]; + }} + checkedKeys={checkedUsers} + onSetCheckedKeys={keys => { + checkedUsers = keys; + }} + > +
+
+ +
+ { + checkedRoles = checkedRoles.includes(event.detail.id) + ? checkedRoles.filter(id => id !== event.detail.id) + : [...checkedRoles, event.detail.id]; + }} + checkedKeys={checkedRoles} + onSetCheckedKeys={keys => { + checkedRoles = keys; + }} + > +
+
+ +
+ { + checkedAuthMethods = checkedAuthMethods.includes(event.detail.id) + ? checkedAuthMethods.filter(id => id !== event.detail.id) + : [...checkedAuthMethods, event.detail.id]; + }} + checkedKeys={checkedAuthMethods} + onSetCheckedKeys={keys => { + checkedAuthMethods = keys; + }} + > +
+
+ +
+ { + checkedConfig = checkedConfig.includes(event.detail.id) + ? checkedConfig.filter(id => id !== event.detail.id) + : [...checkedConfig, event.detail.id]; + }} + checkedKeys={checkedConfig} + onSetCheckedKeys={keys => { + checkedConfig = keys; + }} + > +
+
+
+
+ +
+
+ {#if mode == 'export'} + {_t('common.export', { defaultMessage: 'Export' })} + {_t('common.saveToArchive', { defaultMessage: 'Save to archive' })} + {/if} + {#if mode == 'import'} + {_t('common.import', { defaultMessage: 'Import' })} + {/if} + Close +
+
+
+
+ + diff --git a/packages/web/src/modals/SaveArchiveModal.svelte b/packages/web/src/modals/SaveArchiveModal.svelte index bc2d0c372..4288a9b6a 100644 --- a/packages/web/src/modals/SaveArchiveModal.svelte +++ b/packages/web/src/modals/SaveArchiveModal.svelte @@ -13,6 +13,7 @@ export let file = 'new-table'; export let folder = $currentArchive; export let onSave; + export let fileIsReadOnly = false; const handleSubmit = async e => { const { file, folder } = e.detail; @@ -25,8 +26,8 @@ Save to archive - - + + diff --git a/packages/web/src/query/RunnerOutputFiles.svelte b/packages/web/src/query/RunnerOutputFiles.svelte index 28a32e9a8..a5979c11b 100644 --- a/packages/web/src/query/RunnerOutputFiles.svelte +++ b/packages/web/src/query/RunnerOutputFiles.svelte @@ -42,60 +42,63 @@ {#if !files || files.length == 0} {:else} - formatFileSize(row.size) }, - !electron && { - fieldName: 'download', - header: 'Download', - slot: 0, - }, - electron && { - fieldName: 'copy', - header: 'Copy', - slot: 1, - }, - electron && { - fieldName: 'show', - header: 'Show', - slot: 2, - }, - ]} - > - - { - downloadFromApi(`runners/data/${runnerId}/${row.name}`, row.name); - }} - > - download - - +
+ formatFileSize(row.size) }, + !electron && { + fieldName: 'download', + header: 'Download', + slot: 0, + }, + electron && { + fieldName: 'copy', + header: 'Copy', + slot: 1, + }, + electron && { + fieldName: 'show', + header: 'Show', + slot: 2, + }, + ]} + > + + { + downloadFromApi(`runners/data/${runnerId}/${row.name}`, row.name); + }} + > + download + + - - { - const file = await electron.showSaveDialog({}); - if (file) { - const fs = window.require('fs'); - fs.copyFile(row.path, file, () => {}); - } - }} - > - save - - + + { + const file = await electron.showSaveDialog({}); + if (file) { + const fs = window.require('fs'); + fs.copyFile(row.path, file, () => {}); + } + }} + > + save + + - - { - electron.showItemInFolder(row.path); - }} - > - show - - - + + { + electron.showItemInFolder(row.path); + }} + > + show + + + +
{/if} diff --git a/packages/web/src/tabs/ArchiveFileTab.svelte b/packages/web/src/tabs/ArchiveFileTab.svelte index 74e6d1579..6f3ab527c 100644 --- a/packages/web/src/tabs/ArchiveFileTab.svelte +++ b/packages/web/src/tabs/ArchiveFileTab.svelte @@ -57,8 +57,10 @@ export let jslid = undefined; export let tabid; + let infoLoadCounter = 0; let jslidChecked = false; + let extractedJslId = null; const quickExportHandlerRef = createQuickExportHandlerRef(); @@ -155,6 +157,14 @@ } } } + + if (archiveFolder?.endsWith('.zip')) { + const resp = await apiCall('jsldata/download-jsl-data', { + uri: `zip://archive:${archiveFolder}//${archiveFile}.jsonl`, + }); + extractedJslId = resp.jslid; + } + jslidChecked = true; } @@ -166,7 +176,7 @@ {#if jslidChecked || !jslid} - const getCurrentEditor = () => getActiveComponent('DataDuplicatorTab'); - - registerCommand({ - id: 'dataDuplicator.run', - category: 'Data duplicator', - name: 'Import into DB', - keyText: 'F5 | CtrlOrCommand+Enter', - toolbar: true, - isRelatedToTab: true, - icon: 'icon run', - testEnabled: () => getCurrentEditor()?.canRun(), - onClick: () => getCurrentEditor().run(), - }); - registerCommand({ - id: 'dataDuplicator.kill', - category: 'Data duplicator', - icon: 'icon close', - name: 'Kill', - toolbar: true, - isRelatedToTab: true, - testEnabled: () => getCurrentEditor()?.canKill(), - onClick: () => getCurrentEditor().kill(), - }); - registerCommand({ - id: 'dataDuplicator.generateScript', - category: 'Data duplicator', - icon: 'img shell', - name: 'Generate Script', - toolbar: true, - isRelatedToTab: true, - testEnabled: () => getCurrentEditor()?.canRun(), - onClick: () => getCurrentEditor().generateScript(), - }); - - - - - - - -
- - - { - setEditorData(old => ({ - ...old, - archiveFolder: e.detail, - })); - }} - options={$archiveFolders?.map(x => ({ - label: x.name, - value: x.name, - })) || []} - /> - - - { - setEditorData(old => ({ - ...old, - rollbackAfterFinish: !$editorState.value?.rollbackAfterFinish, - })); - }, - }} - > - { - setEditorData(old => ({ - ...old, - rollbackAfterFinish: e.target.checked, - })); - }} - /> - - - { - setEditorData(old => ({ - ...old, - skipRowsWithUnresolvedRefs: !$editorState.value?.skipRowsWithUnresolvedRefs, - })); - }, - }} - > - { - setEditorData(old => ({ - ...old, - skipRowsWithUnresolvedRefs: e.target.checked, - })); - }} - /> - - - { - setEditorData(old => ({ - ...old, - setNullForUnresolvedNullableRefs: !$editorState.value?.setNullForUnresolvedNullableRefs, - })); - }, - }} - > - { - setEditorData(old => ({ - ...old, - setNullForUnresolvedNullableRefs: e.target.checked, - })); - }} - /> - - - - -
- Check all - | - Uncheck all -
- - - - { - changeTable({ ...row, isChecked: e.target.checked }); - }} - /> - - - { - changeTable({ ...row, operation: e.detail }); - }} - disabled={!row.isChecked} - options={[ - { label: 'Copy row', value: 'copy' }, - { label: 'Lookup (find matching row)', value: 'lookup' }, - { label: 'Insert if not exists', value: 'insertMissing' }, - ]} - /> - - - {#if row.operation != 'copy'} - { - changeTable({ ...row, matchColumn1: e.detail }); - }} - disabled={!row.isChecked} - options={$dbinfo?.tables - ?.find(x => x.pureName?.toUpperCase() == row.name.toUpperCase()) - ?.columns?.map(col => ({ - label: col.columnName, - value: col.columnName, - })) || []} - /> - {/if} - - - { - openNewTab({ - title: row.file, - icon: 'img archive', - tooltip: `${$editorState.value?.archiveFolder}\n${row.file}`, - tabComponent: 'ArchiveFileTab', - props: { - archiveFile: row.file, - archiveFolder: $editorState.value?.archiveFolder, - }, - }); - }}> {row.file} - - - { - openNewTab({ - title: row.pureName, - icon: 'img table', - tabComponent: 'TableDataTab', - props: { - schemaName: row.schemaName, - pureName: row.pureName, - conid, - database, - objectTypeField: 'tables', - }, - }); - }}> {row.table} - - -
-
-
- - - -
- - - - - - -
- - - - - diff --git a/packages/web/src/tabs/ImportExportTab.svelte b/packages/web/src/tabs/ImportExportTab.svelte index e22588737..04935cd8b 100644 --- a/packages/web/src/tabs/ImportExportTab.svelte +++ b/packages/web/src/tabs/ImportExportTab.svelte @@ -2,12 +2,12 @@ const getCurrentEditor = () => getActiveComponent('ImportExportTab'); registerFileCommands({ - idPrefix: 'job', - category: 'Job', + idPrefix: 'impexp', + category: 'Impoirt & Export', getCurrentEditor, - folder: 'jobs', + folder: 'impexp', format: 'json', - fileExtension: 'job', + fileExtension: 'impexp', // undoRedo: true, }); @@ -319,7 +319,7 @@ Generate script - +
diff --git a/packages/web/src/tabs/index.js b/packages/web/src/tabs/index.js index 4d1707e56..e0baa54b8 100644 --- a/packages/web/src/tabs/index.js +++ b/packages/web/src/tabs/index.js @@ -24,7 +24,6 @@ import * as ConnectionTab from './ConnectionTab.svelte'; import * as MapTab from './MapTab.svelte'; import * as ServerSummaryTab from './ServerSummaryTab.svelte'; import * as ProfilerTab from './ProfilerTab.svelte'; -import * as DataDuplicatorTab from './DataDuplicatorTab.svelte'; import * as ImportExportTab from './ImportExportTab.svelte'; import * as SqlObjectTab from './SqlObjectTab.svelte'; @@ -57,7 +56,6 @@ export default { MapTab, ServerSummaryTab, ProfilerTab, - DataDuplicatorTab, ImportExportTab, SqlObjectTab, ...protabs, diff --git a/packages/web/src/utility/exportFileTools.ts b/packages/web/src/utility/exportFileTools.ts index 07e9e7714..b7d1bb76b 100644 --- a/packages/web/src/utility/exportFileTools.ts +++ b/packages/web/src/utility/exportFileTools.ts @@ -184,7 +184,7 @@ export async function exportQuickExportFile(dataName, reader, format: QuickExpor export async function saveFileToDisk( filePathFunc, - options: any = { formatLabel: 'HTML page', formatExtension: 'html' } + options: any = { formatLabel: 'HTML page', formatExtension: 'html', defaultFileName: null } ) { const { formatLabel, formatExtension } = options; const electron = getElectron(); @@ -193,7 +193,7 @@ export async function saveFileToDisk( const filters = [{ name: formatLabel, extensions: [formatExtension] }]; const filePath = await electron.showSaveDialog({ filters, - defaultPath: `file.${formatExtension}`, + defaultPath: options.defaultFileName ?? `file.${formatExtension}`, properties: ['showOverwriteConfirmation'], }); if (!filePath) return; @@ -202,7 +202,7 @@ export async function saveFileToDisk( } else { const resp = await apiCall('files/generate-uploads-file'); await filePathFunc(resp.filePath); - await downloadFromApi(`uploads/get?file=${resp.fileName}`, `file.${formatExtension}`); + await downloadFromApi(`uploads/get?file=${resp.fileName}`, options.defaultFileName ?? `file.${formatExtension}`); } } diff --git a/packages/web/src/utility/formatFileSize.ts b/packages/web/src/utility/formatFileSize.ts index 059569559..31bf8dcb3 100644 --- a/packages/web/src/utility/formatFileSize.ts +++ b/packages/web/src/utility/formatFileSize.ts @@ -1,6 +1,6 @@ export default function formatFileSize(size) { - if (size > 1000000000) return `${Math.round(size / 10000000000) * 10} GB`; - if (size > 1000000) return `${Math.round(size / 10000000) * 10} MB`; - if (size > 1000) return `${Math.round(size / 10000) * 10} KB`; + if (size > 1000000000) return `${Math.round(size / 100000000) / 10} GB`; + if (size > 1000000) return `${Math.round(size / 100000) / 10} MB`; + if (size > 1000) return `${Math.round(size / 100) / 10} KB`; return `${size} bytes`; } diff --git a/packages/web/src/widgets/ArchiveFolderList.svelte b/packages/web/src/widgets/ArchiveFolderList.svelte index 1b4b11d13..72537d714 100644 --- a/packages/web/src/widgets/ArchiveFolderList.svelte +++ b/packages/web/src/widgets/ArchiveFolderList.svelte @@ -14,6 +14,8 @@ import { apiCall } from '../utility/api'; import { useArchiveFolders } from '../utility/metadataLoaders'; import WidgetsInnerContainer from './WidgetsInnerContainer.svelte'; + import InlineUploadButton from '../buttons/InlineUploadButton.svelte'; + import { isProApp } from '../utility/proTools'; let filter = ''; @@ -22,11 +24,47 @@ const handleRefreshFolders = () => { apiCall('archive/refresh-folders'); }; + + async function handleUploadedFile(filePath, fileName) { + await apiCall('archive/save-uploaded-zip', { filePath, fileName }); + } + + {#if isProApp()} + + {/if} + + + runCommand('new.archiveFolder')} title="Add new archive folder"> diff --git a/packages/web/src/widgets/MultiColumnFilterControl.svelte b/packages/web/src/widgets/MultiColumnFilterControl.svelte new file mode 100644 index 000000000..c64b64a61 --- /dev/null +++ b/packages/web/src/widgets/MultiColumnFilterControl.svelte @@ -0,0 +1,75 @@ + + +{#each columnsUsed as column, index} +
+ { + const keys = Object.keys(compoudFilter || {}); + const values = Object.values(compoudFilter || {}); + keys[index] = e.detail; + const newFilter = _.zipObject(keys, values); + onSetCompoudFilter(newFilter); + }} + options={columnNames.map(col => ({ + label: col, + value: col, + })) || []} + /> + + { + onSetCompoudFilter({ + ...compoudFilter, + [column]: value, + }); + }} + placeholder="Filter" + /> + + {#if index == 0} + { + const newColumn = columnNames.find(x => !columnsUsed.includes(x)); + if (!newColumn) return; + onSetCompoudFilter({ + ...compoudFilter, + [newColumn]: '', + }); + }} + title="Add filter column" + square + > + + + {:else} + { + onSetCompoudFilter(_.omit(compoudFilter, column)); + }} + title="Remove filter column" + square + > + + + {/if} +
+{/each} diff --git a/packages/web/src/widgets/SavedFilesList.svelte b/packages/web/src/widgets/SavedFilesList.svelte index 4a4c402f1..6ac56d0bc 100644 --- a/packages/web/src/widgets/SavedFilesList.svelte +++ b/packages/web/src/widgets/SavedFilesList.svelte @@ -10,9 +10,8 @@ import { apiCall } from '../utility/api'; import { useFiles } from '../utility/metadataLoaders'; import WidgetsInnerContainer from './WidgetsInnerContainer.svelte'; - import getElectron from '../utility/getElectron'; - import InlineButtonLabel from '../buttons/InlineButtonLabel.svelte'; - import resolveApi, { resolveApiHeaders } from '../utility/resolveApi'; + import { isProApp } from '../utility/proTools'; + import InlineUploadButton from '../buttons/InlineUploadButton.svelte'; let filter = ''; @@ -23,12 +22,12 @@ const queryFiles = useFiles({ folder: 'query' }); const sqliteFiles = useFiles({ folder: 'sqlite' }); const diagramFiles = useFiles({ folder: 'diagrams' }); - const jobFiles = useFiles({ folder: 'jobs' }); + const importExportJobFiles = useFiles({ folder: 'impexp' }); + const dataDeployJobFiles = useFiles({ folder: 'datadeploy' }); + const dbCompareJobFiles = useFiles({ folder: 'dbcompare' }); const perspectiveFiles = useFiles({ folder: 'perspectives' }); const modelTransformFiles = useFiles({ folder: 'modtrans' }); - const electron = getElectron(); - $: files = [ ...($sqlFiles || []), ...($shellFiles || []), @@ -38,8 +37,10 @@ ...($sqliteFiles || []), ...($diagramFiles || []), ...($perspectiveFiles || []), - ...($jobFiles || []), + ...($importExportJobFiles || []), ...($modelTransformFiles || []), + ...((isProApp() && $dataDeployJobFiles) || []), + ...((isProApp() && $dbCompareJobFiles) || []), ]; function handleRefreshFiles() { @@ -53,50 +54,23 @@ 'sqlite', 'diagrams', 'perspectives', - 'jobs', + 'impexp', 'modtrans', + 'datadeploy', + 'dbcompare', ], }); } function dataFolderTitle(folder) { if (folder == 'modtrans') return 'Model transforms'; + if (folder == 'datadeploy') return 'Data deploy jobs'; + if (folder == 'dbcompare') return 'Database compare jobs'; return _.startCase(folder); } - async function handleUploadedFile(e) { - const files = [...e.target.files]; - - for (const file of files) { - const formData = new FormData(); - formData.append('name', file.name); - formData.append('data', file); - - const fetchOptions = { - method: 'POST', - body: formData, - headers: resolveApiHeaders(), - }; - - const apiBase = resolveApi(); - const resp = await fetch(`${apiBase}/uploads/upload-data-file`, fetchOptions); - const fileData = await resp.json(); - } - } - - async function handleOpenElectronFile() { - const filePaths = await electron.showOpenDialog({ - filters: [ - { - name: `All supported files`, - extensions: ['sql'], - }, - { name: `SQL files`, extensions: ['sql'] }, - ], - properties: ['showHiddenFiles', 'openFile'], - }); - const filePath = filePaths && filePaths[0]; - await apiCall('uploads/save-data-file', { filePath }); + async function handleUploadedFile(filePath, fileName) { + await apiCall('files/save-uploaded-file', { filePath, fileName }); } @@ -104,26 +78,20 @@ - {#if electron} - - - - {:else} - {}} - title="Add file" - data-testid="SavedFileList_buttonAddFile" - htmlFor="uploadSavedFileButton" - > - - - {/if} + - - dataFolderTitle(data.folder)} {filter} /> diff --git a/yarn.lock b/yarn.lock index ee2f4a95e..9d364603e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -542,7 +542,7 @@ "@azure/core-util" "^1.1.0" tslib "^2.6.2" -"@azure/core-auth@^1.8.0", "@azure/core-auth@^1.9.0": +"@azure/core-auth@^1.7.1", "@azure/core-auth@^1.8.0", "@azure/core-auth@^1.9.0": version "1.9.0" resolved "https://registry.yarnpkg.com/@azure/core-auth/-/core-auth-1.9.0.tgz#ac725b03fabe3c892371065ee9e2041bee0fd1ac" integrity sha512-FPwHpZywuyasDSLMqJ6fhbOK3TqUdviZNF8OqRGA4W5Ewib2lEEZ+pBsYcBa88B2NGO/SEnYPGhyBqNlE8ilSw== @@ -604,6 +604,20 @@ https-proxy-agent "^7.0.0" tslib "^2.6.2" +"@azure/core-rest-pipeline@^1.15.1", "@azure/core-rest-pipeline@^1.8.0": + version "1.19.1" + resolved "https://registry.yarnpkg.com/@azure/core-rest-pipeline/-/core-rest-pipeline-1.19.1.tgz#e740676444777a04dc55656d8660131dfd926924" + integrity sha512-zHeoI3NCs53lLBbWNzQycjnYKsA1CVKlnzSNuSFcUDwBp8HHVObePxrM7HaX+Ha5Ks639H7chNC9HOaIhNS03w== + dependencies: + "@azure/abort-controller" "^2.0.0" + "@azure/core-auth" "^1.8.0" + "@azure/core-tracing" "^1.0.1" + "@azure/core-util" "^1.11.0" + "@azure/logger" "^1.0.0" + http-proxy-agent "^7.0.0" + https-proxy-agent "^7.0.0" + tslib "^2.6.2" + "@azure/core-rest-pipeline@^1.17.0": version "1.18.2" resolved "https://registry.yarnpkg.com/@azure/core-rest-pipeline/-/core-rest-pipeline-1.18.2.tgz#fa3a83b412d4b3e33edca30a71b1d5838306c075" @@ -625,6 +639,13 @@ dependencies: tslib "^2.6.2" +"@azure/core-tracing@^1.1.1": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@azure/core-tracing/-/core-tracing-1.2.0.tgz#7be5d53c3522d639cf19042cbcdb19f71bc35ab2" + integrity sha512-UKTiEJPkWcESPYJz3X5uKRYyOcJD+4nYph+KpfdPRnQJVrZfk0KJgdnaAWKfhsBBtAf/D58Az4AvCJEmWgIBAg== + dependencies: + tslib "^2.6.2" + "@azure/core-util@^1.0.0", "@azure/core-util@^1.1.0", "@azure/core-util@^1.2.0", "@azure/core-util@^1.6.1", "@azure/core-util@^1.9.0": version "1.9.0" resolved "https://registry.yarnpkg.com/@azure/core-util/-/core-util-1.9.0.tgz#469afd7e6452d5388b189f90d33f7756b0b210d1" @@ -633,7 +654,7 @@ "@azure/abort-controller" "^2.0.0" tslib "^2.6.2" -"@azure/core-util@^1.11.0": +"@azure/core-util@^1.10.0", "@azure/core-util@^1.11.0", "@azure/core-util@^1.8.1": version "1.11.0" resolved "https://registry.yarnpkg.com/@azure/core-util/-/core-util-1.11.0.tgz#f530fc67e738aea872fbdd1cc8416e70219fada7" integrity sha512-DxOSLua+NdpWoSqULhjDyAZTXFdP/LKkqtYuxxz1SCN289zk3OG8UOpnCQAz/tygyACBtWp/BoO72ptK7msY8g== @@ -641,6 +662,23 @@ "@azure/abort-controller" "^2.0.0" tslib "^2.6.2" +"@azure/cosmos@^4.1.0": + version "4.3.0" + resolved "https://registry.yarnpkg.com/@azure/cosmos/-/cosmos-4.3.0.tgz#aeb809f2c7837ea0f5613f2376b9b756ab7f348d" + integrity sha512-0Ls3l1uWBBSphx6YRhnM+w7rSvq8qVugBCdO6kSiNuRYXEf6+YWLjbzz4e7L2kkz/6ScFdZIOJYP+XtkiRYOhA== + dependencies: + "@azure/abort-controller" "^2.0.0" + "@azure/core-auth" "^1.7.1" + "@azure/core-rest-pipeline" "^1.15.1" + "@azure/core-tracing" "^1.1.1" + "@azure/core-util" "^1.8.1" + "@azure/keyvault-keys" "^4.8.0" + fast-json-stable-stringify "^2.1.0" + jsbi "^4.3.0" + priorityqueuejs "^2.0.0" + semaphore "^1.1.0" + tslib "^2.6.2" + "@azure/identity@^3.4.1": version "3.4.2" resolved "https://registry.yarnpkg.com/@azure/identity/-/identity-3.4.2.tgz#6b01724c9caac7cadab6b63c76584345bda8e2de" @@ -681,6 +719,20 @@ stoppable "^1.1.0" tslib "^2.2.0" +"@azure/keyvault-common@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@azure/keyvault-common/-/keyvault-common-2.0.0.tgz#91e50df01d9bfa8f55f107bb9cdbc57586b2b2a4" + integrity sha512-wRLVaroQtOqfg60cxkzUkGKrKMsCP6uYXAOomOIysSMyt1/YM0eUn9LqieAWM8DLcU4+07Fio2YGpPeqUbpP9w== + dependencies: + "@azure/abort-controller" "^2.0.0" + "@azure/core-auth" "^1.3.0" + "@azure/core-client" "^1.5.0" + "@azure/core-rest-pipeline" "^1.8.0" + "@azure/core-tracing" "^1.0.0" + "@azure/core-util" "^1.10.0" + "@azure/logger" "^1.1.4" + tslib "^2.2.0" + "@azure/keyvault-keys@^4.4.0": version "4.8.0" resolved "https://registry.yarnpkg.com/@azure/keyvault-keys/-/keyvault-keys-4.8.0.tgz#1513b3a187bb3a9a372b5980c593962fb793b2ad" @@ -698,6 +750,24 @@ "@azure/logger" "^1.0.0" tslib "^2.2.0" +"@azure/keyvault-keys@^4.8.0": + version "4.9.0" + resolved "https://registry.yarnpkg.com/@azure/keyvault-keys/-/keyvault-keys-4.9.0.tgz#83ad2370429d1f576e6c5c59ff165761e2d8feab" + integrity sha512-ZBP07+K4Pj3kS4TF4XdkqFcspWwBHry3vJSOFM5k5ZABvf7JfiMonvaFk2nBF6xjlEbMpz5PE1g45iTMme0raQ== + dependencies: + "@azure/abort-controller" "^2.0.0" + "@azure/core-auth" "^1.3.0" + "@azure/core-client" "^1.5.0" + "@azure/core-http-compat" "^2.0.1" + "@azure/core-lro" "^2.2.0" + "@azure/core-paging" "^1.1.1" + "@azure/core-rest-pipeline" "^1.8.1" + "@azure/core-tracing" "^1.0.0" + "@azure/core-util" "^1.0.0" + "@azure/keyvault-common" "^2.0.0" + "@azure/logger" "^1.0.0" + tslib "^2.2.0" + "@azure/logger@^1.0.0": version "1.1.2" resolved "https://registry.yarnpkg.com/@azure/logger/-/logger-1.1.2.tgz#3f4b876cefad328dc14aff8b850d63b611e249dc" @@ -705,6 +775,13 @@ dependencies: tslib "^2.6.2" +"@azure/logger@^1.1.4": + version "1.1.4" + resolved "https://registry.yarnpkg.com/@azure/logger/-/logger-1.1.4.tgz#223cbf2b424dfa66478ce9a4f575f59c6f379768" + integrity sha512-4IXXzcCdLdlXuCG+8UKEwLA1T1NHqUfanhXYHiQTn+6sfWCZXduqbtXDGceg3Ce5QxTGo7EqmbV6Bi+aqKuClQ== + dependencies: + tslib "^2.6.2" + "@azure/msal-browser@^3.5.0": version "3.14.0" resolved "https://registry.yarnpkg.com/@azure/msal-browser/-/msal-browser-3.14.0.tgz#1cb5cab438a9943212aa50c403d11f775c787b21" @@ -786,7 +863,7 @@ json5 "^2.2.3" semver "^6.3.1" -"@babel/generator@^7.24.5", "@babel/generator@^7.4.0", "@babel/generator@^7.7.2": +"@babel/generator@^7.24.5", "@babel/generator@^7.7.2": version "7.24.5" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.24.5.tgz#e5afc068f932f05616b66713e28d0f04e99daeb3" integrity sha512-x32i4hEXvr+iI0NEoEfDKzlemF8AmtOP8CcrRaEcpzysWuoEb1KknpcvMsHKPONoKZiDuItklgWhB18xEhr9PA== @@ -908,7 +985,7 @@ js-tokens "^4.0.0" picocolors "^1.0.0" -"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.24.0", "@babel/parser@^7.24.5", "@babel/parser@^7.4.3": +"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.24.0", "@babel/parser@^7.24.5": version "7.24.5" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.24.5.tgz#4a4d5ab4315579e5398a82dcf636ca80c3392790" integrity sha512-EOv5IK8arwh3LI47dz1b0tKUb/1uhHAnHJOrjgtQMIpu1uXd9mlFrJg9IUgGUgZ41Ch0K8REPTYpO7B76b4vJg== @@ -976,7 +1053,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-syntax-object-rest-spread@^7.0.0", "@babel/plugin-syntax-object-rest-spread@^7.8.3": +"@babel/plugin-syntax-object-rest-spread@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== @@ -1018,7 +1095,7 @@ dependencies: regenerator-runtime "^0.14.0" -"@babel/template@^7.22.15", "@babel/template@^7.24.0", "@babel/template@^7.3.3", "@babel/template@^7.4.0": +"@babel/template@^7.22.15", "@babel/template@^7.24.0", "@babel/template@^7.3.3": version "7.24.0" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.24.0.tgz#c6a524aa93a4a05d66aaf31654258fae69d87d50" integrity sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA== @@ -1027,7 +1104,7 @@ "@babel/parser" "^7.24.0" "@babel/types" "^7.24.0" -"@babel/traverse@^7.1.0", "@babel/traverse@^7.24.5", "@babel/traverse@^7.4.3", "@babel/traverse@^7.7.2": +"@babel/traverse@^7.24.5", "@babel/traverse@^7.7.2": version "7.24.5" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.24.5.tgz#972aa0bc45f16983bf64aa1f877b2dd0eea7e6f8" integrity sha512-7aaBLeDQ4zYcUFDUD41lJc1fG8+5IU9DaNSJAgal866FGvmD5EbWQgnEC6kO1gGLsX0esNkfnJSndbTXA3r7UA== @@ -1043,7 +1120,7 @@ debug "^4.3.1" globals "^11.1.0" -"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.22.5", "@babel/types@^7.23.0", "@babel/types@^7.24.0", "@babel/types@^7.24.5", "@babel/types@^7.3.3", "@babel/types@^7.4.0": +"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.22.5", "@babel/types@^7.23.0", "@babel/types@^7.24.0", "@babel/types@^7.24.5", "@babel/types@^7.3.3": version "7.24.5" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.24.5.tgz#7661930afc638a5383eb0c4aee59b74f38db84d7" integrity sha512-6mQNsaLeXTw0nxYUYu+NSa4Hx4BlF1x1x8/PMFbiR+GBSr+2DkECc69b8hgy2frEodNcvPffeH8YfWd3LI6jhQ== @@ -1082,14 +1159,6 @@ dependencies: "@clickhouse/client-common" "1.5.0" -"@cnakazawa/watch@^1.0.3": - version "1.0.4" - resolved "https://registry.yarnpkg.com/@cnakazawa/watch/-/watch-1.0.4.tgz#f864ae85004d0fcab6f50be9141c4da368d1656a" - integrity sha512-v9kIhKwjeZThiWrLmj0y17CWoyddASLj9O2yvbZkbvw/N3rWOYy9zkV66ursAoVr0mV15bL8g0c4QZUE6cdDoQ== - dependencies: - exec-sh "^0.3.2" - minimist "^1.2.0" - "@ctrl/tinycolor@^3.3.1": version "3.6.1" resolved "https://registry.yarnpkg.com/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz#b6c75a56a1947cc916ea058772d666a2c8932f31" @@ -1110,6 +1179,18 @@ resolved "https://registry.yarnpkg.com/@ioredis/commands/-/commands-1.2.0.tgz#6d61b3097470af1fdbbe622795b8921d42018e11" integrity sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg== +"@isaacs/cliui@^8.0.2": + version "8.0.2" + resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550" + integrity sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA== + dependencies: + string-width "^5.1.2" + string-width-cjs "npm:string-width@^4.2.0" + strip-ansi "^7.0.1" + strip-ansi-cjs "npm:strip-ansi@^6.0.1" + wrap-ansi "^8.1.0" + wrap-ansi-cjs "npm:wrap-ansi@^7.0.0" + "@istanbuljs/load-nyc-config@^1.0.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" @@ -1126,15 +1207,6 @@ resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== -"@jest/console@^24.7.1", "@jest/console@^24.9.0": - version "24.9.0" - resolved "https://registry.yarnpkg.com/@jest/console/-/console-24.9.0.tgz#79b1bc06fb74a8cfb01cbdedf945584b1b9707f0" - integrity sha512-Zuj6b8TnKXi3q4ymac8EQfc3ea/uhLeCGThFqXeC8H9/raaH8ARPUTdId+XyGd03Z4In0/VjD2OYFcBF09fNLQ== - dependencies: - "@jest/source-map" "^24.9.0" - chalk "^2.0.1" - slash "^2.0.0" - "@jest/console@^27.5.1": version "27.5.1" resolved "https://registry.yarnpkg.com/@jest/console/-/console-27.5.1.tgz#260fe7239602fe5130a94f1aa386eff54b014bba" @@ -1159,40 +1231,6 @@ jest-util "^28.1.3" slash "^3.0.0" -"@jest/core@^24.9.0": - version "24.9.0" - resolved "https://registry.yarnpkg.com/@jest/core/-/core-24.9.0.tgz#2ceccd0b93181f9c4850e74f2a9ad43d351369c4" - integrity sha512-Fogg3s4wlAr1VX7q+rhV9RVnUv5tD7VuWfYy1+whMiWUrvl7U3QJSJyWcDio9Lq2prqYsZaeTv2Rz24pWGkJ2A== - dependencies: - "@jest/console" "^24.7.1" - "@jest/reporters" "^24.9.0" - "@jest/test-result" "^24.9.0" - "@jest/transform" "^24.9.0" - "@jest/types" "^24.9.0" - ansi-escapes "^3.0.0" - chalk "^2.0.1" - exit "^0.1.2" - graceful-fs "^4.1.15" - jest-changed-files "^24.9.0" - jest-config "^24.9.0" - jest-haste-map "^24.9.0" - jest-message-util "^24.9.0" - jest-regex-util "^24.3.0" - jest-resolve "^24.9.0" - jest-resolve-dependencies "^24.9.0" - jest-runner "^24.9.0" - jest-runtime "^24.9.0" - jest-snapshot "^24.9.0" - jest-util "^24.9.0" - jest-validate "^24.9.0" - jest-watcher "^24.9.0" - micromatch "^3.1.10" - p-each-series "^1.0.0" - realpath-native "^1.1.0" - rimraf "^2.5.4" - slash "^2.0.0" - strip-ansi "^5.0.0" - "@jest/core@^27.5.1": version "27.5.1" resolved "https://registry.yarnpkg.com/@jest/core/-/core-27.5.1.tgz#267ac5f704e09dc52de2922cbf3af9edcd64b626" @@ -1262,16 +1300,6 @@ slash "^3.0.0" strip-ansi "^6.0.0" -"@jest/environment@^24.9.0": - version "24.9.0" - resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-24.9.0.tgz#21e3afa2d65c0586cbd6cbefe208bafade44ab18" - integrity sha512-5A1QluTPhvdIPFYnO3sZC3smkNeXPVELz7ikPbhUj0bQjB07EoE9qtLrem14ZUYWdVayYbsjVwIiL4WBIMV4aQ== - dependencies: - "@jest/fake-timers" "^24.9.0" - "@jest/transform" "^24.9.0" - "@jest/types" "^24.9.0" - jest-mock "^24.9.0" - "@jest/environment@^27.5.1": version "27.5.1" resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-27.5.1.tgz#d7425820511fe7158abbecc010140c3fd3be9c74" @@ -1307,15 +1335,6 @@ expect "^28.1.3" jest-snapshot "^28.1.3" -"@jest/fake-timers@^24.9.0": - version "24.9.0" - resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-24.9.0.tgz#ba3e6bf0eecd09a636049896434d306636540c93" - integrity sha512-eWQcNa2YSwzXWIMC5KufBh3oWRIijrQFROsIqt6v/NS9Io/gknw1jsAC9c+ih/RQX4A3O7SeWAhQeN0goKhT9A== - dependencies: - "@jest/types" "^24.9.0" - jest-message-util "^24.9.0" - jest-mock "^24.9.0" - "@jest/fake-timers@^27.5.1": version "27.5.1" resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-27.5.1.tgz#76979745ce0579c8a94a4678af7a748eda8ada74" @@ -1358,33 +1377,6 @@ "@jest/expect" "^28.1.3" "@jest/types" "^28.1.3" -"@jest/reporters@^24.9.0": - version "24.9.0" - resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-24.9.0.tgz#86660eff8e2b9661d042a8e98a028b8d631a5b43" - integrity sha512-mu4X0yjaHrffOsWmVLzitKmmmWSQ3GGuefgNscUSWNiUNcEOSEQk9k3pERKEQVBb0Cnn88+UESIsZEMH3o88Gw== - dependencies: - "@jest/environment" "^24.9.0" - "@jest/test-result" "^24.9.0" - "@jest/transform" "^24.9.0" - "@jest/types" "^24.9.0" - chalk "^2.0.1" - exit "^0.1.2" - glob "^7.1.2" - istanbul-lib-coverage "^2.0.2" - istanbul-lib-instrument "^3.0.1" - istanbul-lib-report "^2.0.4" - istanbul-lib-source-maps "^3.0.1" - istanbul-reports "^2.2.6" - jest-haste-map "^24.9.0" - jest-resolve "^24.9.0" - jest-runtime "^24.9.0" - jest-util "^24.9.0" - jest-worker "^24.6.0" - node-notifier "^5.4.2" - slash "^2.0.0" - source-map "^0.6.0" - string-length "^2.0.0" - "@jest/reporters@^27.5.1": version "27.5.1" resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-27.5.1.tgz#ceda7be96170b03c923c37987b64015812ffec04" @@ -1454,15 +1446,6 @@ dependencies: "@sinclair/typebox" "^0.24.1" -"@jest/source-map@^24.3.0", "@jest/source-map@^24.9.0": - version "24.9.0" - resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-24.9.0.tgz#0e263a94430be4b41da683ccc1e6bffe2a191714" - integrity sha512-/Xw7xGlsZb4MJzNDgB7PW5crou5JqWiBQaz6xyPd3ArOg2nfn/PunV8+olXbbEZzNl591o5rWKE9BRDaFAuIBg== - dependencies: - callsites "^3.0.0" - graceful-fs "^4.1.15" - source-map "^0.6.0" - "@jest/source-map@^27.5.1": version "27.5.1" resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-27.5.1.tgz#6608391e465add4205eae073b55e7f279e04e8cf" @@ -1481,15 +1464,6 @@ callsites "^3.0.0" graceful-fs "^4.2.9" -"@jest/test-result@^24.9.0": - version "24.9.0" - resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-24.9.0.tgz#11796e8aa9dbf88ea025757b3152595ad06ba0ca" - integrity sha512-XEFrHbBonBJ8dGp2JmF8kP/nQI/ImPpygKHwQ/SY+es59Z3L5PI4Qb9TQQMAEeYsThG1xF0k6tmG0tIKATNiiA== - dependencies: - "@jest/console" "^24.9.0" - "@jest/types" "^24.9.0" - "@types/istanbul-lib-coverage" "^2.0.0" - "@jest/test-result@^27.5.1": version "27.5.1" resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-27.5.1.tgz#56a6585fa80f7cdab72b8c5fc2e871d03832f5bb" @@ -1510,16 +1484,6 @@ "@types/istanbul-lib-coverage" "^2.0.0" collect-v8-coverage "^1.0.0" -"@jest/test-sequencer@^24.9.0": - version "24.9.0" - resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-24.9.0.tgz#f8f334f35b625a4f2f355f2fe7e6036dad2e6b31" - integrity sha512-6qqsU4o0kW1dvA95qfNog8v8gkRN9ph6Lz7r96IvZpHdNipP2cBcb07J1Z45mz/VIS01OHJ3pY8T5fUY38tg4A== - dependencies: - "@jest/test-result" "^24.9.0" - jest-haste-map "^24.9.0" - jest-runner "^24.9.0" - jest-runtime "^24.9.0" - "@jest/test-sequencer@^27.5.1": version "27.5.1" resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-27.5.1.tgz#4057e0e9cea4439e544c6353c6affe58d095745b" @@ -1540,28 +1504,6 @@ jest-haste-map "^28.1.3" slash "^3.0.0" -"@jest/transform@^24.9.0": - version "24.9.0" - resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-24.9.0.tgz#4ae2768b296553fadab09e9ec119543c90b16c56" - integrity sha512-TcQUmyNRxV94S0QpMOnZl0++6RMiqpbH/ZMccFB/amku6Uwvyb1cjYX7xkp5nGNkbX4QPH/FcB6q1HBTHynLmQ== - dependencies: - "@babel/core" "^7.1.0" - "@jest/types" "^24.9.0" - babel-plugin-istanbul "^5.1.0" - chalk "^2.0.1" - convert-source-map "^1.4.0" - fast-json-stable-stringify "^2.0.0" - graceful-fs "^4.1.15" - jest-haste-map "^24.9.0" - jest-regex-util "^24.9.0" - jest-util "^24.9.0" - micromatch "^3.1.10" - pirates "^4.0.1" - realpath-native "^1.1.0" - slash "^2.0.0" - source-map "^0.6.1" - write-file-atomic "2.4.1" - "@jest/transform@^27.5.1": version "27.5.1" resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-27.5.1.tgz#6c3501dcc00c4c08915f292a600ece5ecfe1f409" @@ -1604,15 +1546,6 @@ slash "^3.0.0" write-file-atomic "^4.0.1" -"@jest/types@^24.9.0": - version "24.9.0" - resolved "https://registry.yarnpkg.com/@jest/types/-/types-24.9.0.tgz#63cb26cb7500d069e5a389441a7c6ab5e909fc59" - integrity sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw== - dependencies: - "@types/istanbul-lib-coverage" "^2.0.0" - "@types/istanbul-reports" "^1.1.1" - "@types/yargs" "^13.0.0" - "@jest/types@^25.5.0": version "25.5.0" resolved "https://registry.yarnpkg.com/@jest/types/-/types-25.5.0.tgz#4d6a4793f7b9599fc3680877b856a97dbccf2a9d" @@ -1885,6 +1818,11 @@ node-gyp "^7.1.0" read-package-json-fast "^2.0.1" +"@pkgjs/parseargs@^0.11.0": + version "0.11.0" + resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" + integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== + "@polka/url@^1.0.0-next.20": version "1.0.0-next.25" resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.25.tgz#f077fdc0b5d0078d30893396ff4827a13f99e817" @@ -2393,7 +2331,7 @@ resolved "https://registry.yarnpkg.com/@tsconfig/svelte/-/svelte-1.0.13.tgz#2fa34376627192c0d643ce54964915e2bd3a58e4" integrity sha512-5lYJP45Xllo4yE/RUBccBT32eBlRDbqN8r1/MIvQbKxW3aFqaYPCNgm8D5V20X4ShHcwvYWNlKg3liDh1MlBoA== -"@types/babel__core@^7.0.0", "@types/babel__core@^7.1.0", "@types/babel__core@^7.1.14": +"@types/babel__core@^7.0.0", "@types/babel__core@^7.1.14": version "7.20.5" resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.5.tgz#3df15f27ba85319caa07ba08d0721889bb39c017" integrity sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA== @@ -2632,11 +2570,6 @@ dependencies: sass "*" -"@types/stack-utils@^1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-1.0.1.tgz#0a851d3bd96498fa25c33ab7278ed3bd65f06c3e" - integrity sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw== - "@types/stack-utils@^2.0.0": version "2.0.3" resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.3.tgz#6209321eb2c1712a7e7466422b8cb1fc0d9dd5d8" @@ -2659,13 +2592,6 @@ resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.3.tgz#815e30b786d2e8f0dcd85fd5bcf5e1a04d008f15" integrity sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ== -"@types/yargs@^13.0.0": - version "13.0.12" - resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-13.0.12.tgz#d895a88c703b78af0465a9de88aa92c61430b092" - integrity sha512-qCxJE1qgz2y0hA4pIxjBR+PelCH0U5CK1XJXFwCNqfmliatKp47UCXXE9Dyk1OXBDLvsCF57TqQEJaeLfDYEOQ== - dependencies: - "@types/yargs-parser" "*" - "@types/yargs@^15.0.0": version "15.0.19" resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-15.0.19.tgz#328fb89e46109ecbdb70c295d96ff2f46dfd01b9" @@ -2838,7 +2764,7 @@ resolved "https://registry.yarnpkg.com/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz#e77a97fbd345b76d83245edcd17d393b1b41fb31" integrity sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ== -abab@^2.0.0, abab@^2.0.3, abab@^2.0.5: +abab@^2.0.3, abab@^2.0.5: version "2.0.6" resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.6.tgz#41b80f2c871d19686216b82309231cfd3cb3d291" integrity sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA== @@ -2873,14 +2799,6 @@ ace-builds@^1.36.5: resolved "https://registry.yarnpkg.com/ace-builds/-/ace-builds-1.36.5.tgz#ae9cc7a32eccc2f484926131c00545cd6b78a6a6" integrity sha512-mZ5KVanRT6nLRDLqtG/1YQQLX/gZVC/v526cm1Ru/MTSlrbweSmqv2ZT0d2GaHpJq035MwCMIrj+LgDAUnDXrg== -acorn-globals@^4.1.0: - version "4.3.4" - resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-4.3.4.tgz#9fa1926addc11c97308c4e66d7add0d40c3272e7" - integrity sha512-clfQEh21R+D0leSbUdWf3OcfqyaCSAQ8Ryq00bofSekfr9W8u1jyYZo6ir0xu9Gtcf7BjcHJpnbZH7JOCpP60A== - dependencies: - acorn "^6.0.1" - acorn-walk "^6.0.1" - acorn-globals@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-6.0.0.tgz#46cdd39f0f8ff08a876619b55f5ac8a6dc770b45" @@ -2899,26 +2817,11 @@ acorn-jsx@^5.2.0: resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== -acorn-walk@^6.0.1: - version "6.2.0" - resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-6.2.0.tgz#123cb8f3b84c2171f1f7fb252615b1c78a6b1a8c" - integrity sha512-7evsyfH1cLOCdAzZAd43Cic04yKydNx0cF+7tiA19p1XnLLPU4dpCQOqpjqwokFe//vS0QqfqqjCS2JkiIs0cA== - acorn-walk@^7.1.1: version "7.2.0" resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.2.0.tgz#0de889a601203909b0fbe07b8938dc21d2e967bc" integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA== -acorn@^5.5.3: - version "5.7.4" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.4.tgz#3e8d8a9947d0599a1796d10225d7432f4a4acf5e" - integrity sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg== - -acorn@^6.0.1: - version "6.4.2" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.2.tgz#35866fd710528e92de10cf06016498e47e39e1e6" - integrity sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ== - acorn@^7.1.1: version "7.4.1" resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" @@ -3001,11 +2904,6 @@ ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.3, ajv@^6.12.5: json-schema-traverse "^0.4.1" uri-js "^4.2.2" -ansi-escapes@^3.0.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b" - integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ== - ansi-escapes@^4.2.1: version "4.3.2" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" @@ -3018,12 +2916,7 @@ ansi-regex@^2.0.0: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" integrity sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA== -ansi-regex@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.1.tgz#123d6479e92ad45ad897d4054e3c7ca7db4944e1" - integrity sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw== - -ansi-regex@^4.0.0, ansi-regex@^4.1.0: +ansi-regex@^4.1.0: version "4.1.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.1.tgz#164daac87ab2d6f6db3a29875e2d1766582dabed" integrity sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g== @@ -3033,6 +2926,11 @@ ansi-regex@^5.0.0, ansi-regex@^5.0.1: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== +ansi-regex@^6.0.1: + version "6.1.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.1.0.tgz#95ec409c69619d6cb1b8b34f14b660ef28ebd654" + integrity sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA== + ansi-styles@^3.2.0, ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" @@ -3052,13 +2950,10 @@ ansi-styles@^5.0.0: resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== -anymatch@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" - integrity sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw== - dependencies: - micromatch "^3.1.4" - normalize-path "^2.1.1" +ansi-styles@^6.1.0: + version "6.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" + integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== anymatch@^3.0.3, anymatch@~3.1.2: version "3.1.3" @@ -3073,6 +2968,32 @@ aproba@^1.0.3: resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== +archiver-utils@^5.0.0, archiver-utils@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/archiver-utils/-/archiver-utils-5.0.2.tgz#63bc719d951803efc72cf961a56ef810760dd14d" + integrity sha512-wuLJMmIBQYCsGZgYLTy5FIB2pF6Lfb6cXMSF8Qywwk3t20zWnAi7zLcQFdKQmIB8wyZpY5ER38x08GbwtR2cLA== + dependencies: + glob "^10.0.0" + graceful-fs "^4.2.0" + is-stream "^2.0.1" + lazystream "^1.0.0" + lodash "^4.17.15" + normalize-path "^3.0.0" + readable-stream "^4.0.0" + +archiver@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/archiver/-/archiver-7.0.1.tgz#c9d91c350362040b8927379c7aa69c0655122f61" + integrity sha512-ZcbTaIqJOfCc03QwD468Unz/5Ir8ATtvAHsK+FdXbDIbGfihqh9mrvdcYunQzqn4HrvWWaFyaxJhGZagaJJpPQ== + dependencies: + archiver-utils "^5.0.2" + async "^3.2.4" + buffer-crc32 "^1.0.0" + readable-stream "^4.0.0" + readdir-glob "^1.1.2" + tar-stream "^3.0.0" + zip-stream "^6.0.1" + are-we-there-yet@~1.1.2: version "1.1.7" resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz#b15474a932adab4ff8a50d9adfa7e4e926f21146" @@ -3121,11 +3042,6 @@ array-buffer-byte-length@^1.0.1: call-bind "^1.0.5" is-array-buffer "^3.0.4" -array-equal@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/array-equal/-/array-equal-1.0.2.tgz#a8572e64e822358271250b9156d20d96ef5dec04" - integrity sha512-gUHx76KtnhEgB3HOuFYiCm3FIdEs6ocM2asHvNTkfu/Y09qQVrrVVaOKENmS2KkSaGoxgXNqC+ZVtR/n0MOkSA== - array-flatten@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" @@ -3165,19 +3081,6 @@ array-unique@^0.3.2: resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" integrity sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ== -array.prototype.reduce@^1.0.6: - version "1.0.7" - resolved "https://registry.yarnpkg.com/array.prototype.reduce/-/array.prototype.reduce-1.0.7.tgz#6aadc2f995af29cb887eb866d981dc85ab6f7dc7" - integrity sha512-mzmiUCVwtiD4lgxYP8g7IYy8El8p2CSMePvIbTS7gchKir/L1fgJrk0yDKmAX6mnRQFKNADYIk8nNlTris5H1Q== - dependencies: - call-bind "^1.0.7" - define-properties "^1.2.1" - es-abstract "^1.23.2" - es-array-method-boxes-properly "^1.0.0" - es-errors "^1.3.0" - es-object-atoms "^1.0.0" - is-string "^1.0.7" - arraybuffer.prototype.slice@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz#097972f4255e41bc3425e37dc3f6421cf9aefde6" @@ -3219,11 +3122,6 @@ astral-regex@^1.0.0: resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== -async-limiter@~1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" - integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ== - async-lock@^1.2.6: version "1.4.1" resolved "https://registry.yarnpkg.com/async-lock/-/async-lock-1.4.1.tgz#56b8718915a9b68b10fce2f2a9a3dddf765ef53f" @@ -3241,6 +3139,11 @@ async@^3.1.0, async@^3.2.0, async@^3.2.3: resolved "https://registry.yarnpkg.com/async/-/async-3.2.5.tgz#ebd52a8fdaf7a2289a24df399f8d8485c8a46b66" integrity sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg== +async@^3.2.4: + version "3.2.6" + resolved "https://registry.yarnpkg.com/async/-/async-3.2.6.tgz#1b0728e14929d51b85b449b7f06e27c1145e38ce" + integrity sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA== + asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" @@ -3290,18 +3193,10 @@ axios@^0.21.1: dependencies: follow-redirects "^1.14.0" -babel-jest@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-24.9.0.tgz#3fc327cb8467b89d14d7bc70e315104a783ccd54" - integrity sha512-ntuddfyiN+EhMw58PTNL1ph4C9rECiQXjI4nMMBKBaNjXvqLdkXpPRcMSr4iyBrJg/+wz9brFUD6RhOAT6r4Iw== - dependencies: - "@jest/transform" "^24.9.0" - "@jest/types" "^24.9.0" - "@types/babel__core" "^7.1.0" - babel-plugin-istanbul "^5.1.0" - babel-preset-jest "^24.9.0" - chalk "^2.4.2" - slash "^2.0.0" +b4a@^1.6.4: + version "1.6.7" + resolved "https://registry.yarnpkg.com/b4a/-/b4a-1.6.7.tgz#a99587d4ebbfbd5a6e3b21bdb5d5fa385767abe4" + integrity sha512-OnAYlL5b7LEkALw87fUVafQw5rVR9RjwGd4KUwNQ6DrrNmaVaUCgLipfVlzrPQ4tWOR9P0IXGNOx50jYCCdSJg== babel-jest@^27.5.1: version "27.5.1" @@ -3330,16 +3225,6 @@ babel-jest@^28.1.3: graceful-fs "^4.2.9" slash "^3.0.0" -babel-plugin-istanbul@^5.1.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-5.2.0.tgz#df4ade83d897a92df069c4d9a25cf2671293c854" - integrity sha512-5LphC0USA8t4i1zCtjbbNb6jJj/9+X6P37Qfirc/70EQ34xKlMW+a1RHGwxGI+SwWpNwZ27HqvzAobeqaXwiZw== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - find-up "^3.0.0" - istanbul-lib-instrument "^3.3.0" - test-exclude "^5.2.3" - babel-plugin-istanbul@^6.1.1: version "6.1.1" resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz#fa88ec59232fd9b4e36dbbc540a8ec9a9b47da73" @@ -3351,13 +3236,6 @@ babel-plugin-istanbul@^6.1.1: istanbul-lib-instrument "^5.0.4" test-exclude "^6.0.0" -babel-plugin-jest-hoist@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-24.9.0.tgz#4f837091eb407e01447c8843cbec546d0002d756" - integrity sha512-2EMA2P8Vp7lG0RAzr4HXqtYwacfMErOuv1U3wrvxHX6rD1sV6xS3WXG3r8TRQ2r6w8OhvSdWt+z41hQNwNm3Xw== - dependencies: - "@types/babel__traverse" "^7.0.6" - babel-plugin-jest-hoist@^27.5.1: version "27.5.1" resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.5.1.tgz#9be98ecf28c331eb9f5df9c72d6f89deb8181c2e" @@ -3396,14 +3274,6 @@ babel-preset-current-node-syntax@^1.0.0: "@babel/plugin-syntax-optional-chaining" "^7.8.3" "@babel/plugin-syntax-top-level-await" "^7.8.3" -babel-preset-jest@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-24.9.0.tgz#192b521e2217fb1d1f67cf73f70c336650ad3cdc" - integrity sha512-izTUuhE4TMfTRPF92fFwD2QfdXaZW08qvWTFCI51V8rW5x00UuPgc3ajRoWofXOuxjfcOM5zzSYsQS3H8KGCAg== - dependencies: - "@babel/plugin-syntax-object-rest-spread" "^7.0.0" - babel-plugin-jest-hoist "^24.9.0" - babel-preset-jest@^27.5.1: version "27.5.1" resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-27.5.1.tgz#91f10f58034cb7989cb4f962b69fa6eef6a6bc81" @@ -3432,6 +3302,11 @@ balanced-match@^1.0.0: resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== +bare-events@^2.2.0: + version "2.5.4" + resolved "https://registry.yarnpkg.com/bare-events/-/bare-events-2.5.4.tgz#16143d435e1ed9eafd1ab85f12b89b3357a41745" + integrity sha512-+gFfDkR8pj4/TrWCGUGWmJIkBwuxPS5F+a5yWjOHQt2hHvNZd5YLzadjmDUtFmMM4y429bnKLa8bYBMHcYdnQA== + base64-js@^1.3.1: version "1.5.1" resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" @@ -3579,13 +3454,6 @@ browser-process-hrtime@^1.0.0: resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz#3c9b4b7d782c8121e56f10106d84c0d0ffc94626" integrity sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow== -browser-resolve@^1.11.3: - version "1.11.3" - resolved "https://registry.yarnpkg.com/browser-resolve/-/browser-resolve-1.11.3.tgz#9b7cbb3d0f510e4cb86bdbd796124d28b5890af6" - integrity sha512-exDi1BYWB/6raKHmDTCicQfTkqwN5fioMFV4j8BsfMU4R2DK/QfZfK7kOVkmWCNANf0snkBzqGqAJBao9gZMdQ== - dependencies: - resolve "1.1.7" - browserslist@^4.21.10, browserslist@^4.22.2: version "4.23.0" resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.23.0.tgz#8f3acc2bbe73af7213399430890f86c63a5674ab" @@ -3620,17 +3488,22 @@ bson@^6.8.0: resolved "https://registry.yarnpkg.com/bson/-/bson-6.8.0.tgz#5063c41ba2437c2b8ff851b50d9e36cb7aaa7525" integrity sha512-iOJg8pr7wq2tg/zSlCCHMi3hMm5JTOxLTagf3zxhcenHsFp+c6uOs6K7W5UE7A4QIJGtqh/ZovFNMP4mOPJynQ== -buffer-crc32@^0.2.5: +buffer-crc32@^0.2.5, buffer-crc32@~0.2.3: version "0.2.13" resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" integrity sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ== +buffer-crc32@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-1.0.0.tgz#a10993b9055081d55304bd9feb4a072de179f405" + integrity sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w== + buffer-equal-constant-time@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819" integrity sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA== -buffer-from@1.x, buffer-from@^1.0.0: +buffer-from@^1.0.0: version "1.1.2" resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== @@ -3774,13 +3647,6 @@ caniuse-lite@^1.0.30001587: resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001616.tgz#4342712750d35f71ebba9fcac65e2cf8870013c3" integrity sha512-RHVYKov7IcdNjVHJFNY/78RdG4oGVjbayxv8u5IO74Wv7Hlq4PnJE6mo/OjFijjVFNy5ijnCt6H3IIo4t+wfEw== -capture-exit@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/capture-exit/-/capture-exit-2.0.0.tgz#fb953bfaebeb781f62898239dabb426d08a509a4" - integrity sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g== - dependencies: - rsvp "^4.8.4" - caseless@~0.12.0: version "0.12.0" resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" @@ -3818,7 +3684,7 @@ chalk-template@^0.4.0: dependencies: chalk "^4.1.2" -chalk@^2.0.1, chalk@^2.1.0, chalk@^2.4.2: +chalk@^2.1.0, chalk@^2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== @@ -4127,6 +3993,17 @@ component-emitter@^1.2.1: resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.1.tgz#ef1d5796f7d93f135ee6fb684340b26403c97d17" integrity sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ== +compress-commons@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/compress-commons/-/compress-commons-6.0.2.tgz#26d31251a66b9d6ba23a84064ecd3a6a71d2609e" + integrity sha512-6FqVXeETqWPoGcfzrXb37E50NP0LXT8kAMu5ooZayhWWdgEY4lBEEcbQNXtkuKQsGduxiIcI4gOTsxTmuq/bSg== + dependencies: + crc-32 "^1.2.0" + crc32-stream "^6.0.0" + is-stream "^2.0.1" + normalize-path "^3.0.0" + readable-stream "^4.0.0" + concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" @@ -4249,11 +4126,19 @@ cpu-features@~0.0.10: buildcheck "~0.0.6" nan "^2.19.0" -crc-32@~1.2.0: +crc-32@^1.2.0, crc-32@~1.2.0: version "1.2.2" resolved "https://registry.yarnpkg.com/crc-32/-/crc-32-1.2.2.tgz#3cad35a934b8bf71f25ca524b6da51fb7eace2ff" integrity sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ== +crc32-stream@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/crc32-stream/-/crc32-stream-6.0.0.tgz#8529a3868f8b27abb915f6c3617c0fadedbf9430" + integrity sha512-piICUB6ei4IlTv1+653yq5+KoqfBYmj9bw6LqXoOneTMDXk5nM1qt12mFW1caG3LlJXEKW1Bp0WggEmIfQB34g== + dependencies: + crc-32 "^1.2.0" + readable-stream "^4.0.0" + cross-env@^6.0.3: version "6.0.3" resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-6.0.3.tgz#4256b71e49b3a40637a0ce70768a6ef5c72ae941" @@ -4268,7 +4153,7 @@ cross-env@^7.0.3: dependencies: cross-spawn "^7.0.1" -cross-spawn@^6.0.0, cross-spawn@^6.0.5: +cross-spawn@^6.0.5: version "6.0.5" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== @@ -4288,22 +4173,24 @@ cross-spawn@^7.0.0, cross-spawn@^7.0.1, cross-spawn@^7.0.3: shebang-command "^2.0.0" which "^2.0.1" -cssom@0.3.x, "cssom@>= 0.3.2 < 0.4.0", cssom@~0.3.6: - version "0.3.8" - resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.8.tgz#9f1276f5b2b463f2114d3f2c75250af8c1a36f4a" - integrity sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg== +cross-spawn@^7.0.6: + version "7.0.6" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f" + integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" cssom@^0.4.4: version "0.4.4" resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.4.4.tgz#5a66cf93d2d0b661d80bf6a44fb65f5c2e4e0a10" integrity sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw== -cssstyle@^1.0.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-1.4.0.tgz#9d31328229d3c565c61e586b02041a28fccdccf1" - integrity sha512-GBrLZYZ4X4x6/QEoBnIrqb8B/f5l4+8me2dkom/j1Gtbxy0kBv6OGzKuAsGM75bkGwGAFkt56Iwg28S3XTZgSA== - dependencies: - cssom "0.3.x" +cssom@~0.3.6: + version "0.3.8" + resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.8.tgz#9f1276f5b2b463f2114d3f2c75250af8c1a36f4a" + integrity sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg== cssstyle@^2.3.0: version "2.3.0" @@ -4349,15 +4236,6 @@ dashdash@^1.12.0: dependencies: assert-plus "^1.0.0" -data-urls@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-1.1.0.tgz#15ee0582baa5e22bb59c77140da8f9c76963bbfe" - integrity sha512-YTWYI9se1P55u58gL5GkQHW4P6VJBJ5iBT+B5a7i2Tjadhv52paJG0qHX4A0OR6/t52odI64KP2YvFpkDOi3eQ== - dependencies: - abab "^2.0.0" - whatwg-mimetype "^2.2.0" - whatwg-url "^7.0.0" - data-urls@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-2.0.0.tgz#156485a72963a970f5d5821aaf642bef2bf2db9b" @@ -4593,21 +4471,11 @@ detect-libc@^2.0.0: resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.3.tgz#f0cd503b40f9939b894697d19ad50895e30cf700" integrity sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw== -detect-newline@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-2.1.0.tgz#f41f1c10be4b00e87b5f13da680759f2c5bfd3e2" - integrity sha512-CwffZFvlJffUg9zZA0uqrjQayUTC8ob94pnr5sFwaVv3IOmkfUHcWH+jXaQK3askE51Cqe8/9Ql/0uXNwqZ8Zg== - detect-newline@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== -diff-sequences@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-24.9.0.tgz#5715d6244e2aa65f48bba0bc972db0b0b11e95b5" - integrity sha512-Dj6Wk3tWyTE+Fo1rW8v0Xhwk80um6yFYKbuAxc9c3EZxIHFDYwbi34Uk42u1CdnIiVorvt4RmlSDjIPyzGC2ew== - diff-sequences@^25.2.6: version "25.2.6" resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-25.2.6.tgz#5f467c00edd35352b7bca46d7927d60e687a76dd" @@ -4677,13 +4545,6 @@ doctrine@^3.0.0: dependencies: esutils "^2.0.2" -domexception@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/domexception/-/domexception-1.0.1.tgz#937442644ca6a31261ef36e3ec677fe805582c90" - integrity sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug== - dependencies: - webidl-conversions "^4.0.2" - domexception@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/domexception/-/domexception-2.0.1.tgz#fb44aefba793e1574b0af6aed2801d057529f304" @@ -4703,6 +4564,11 @@ duplexer2@~0.0.2: dependencies: readable-stream "~1.1.9" +eastasianwidth@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" + integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== + ecc-jsbn@~0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" @@ -4748,6 +4614,11 @@ emoji-regex@^8.0.0: resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== +emoji-regex@^9.2.2: + version "9.2.2" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" + integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== + emojis-list@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78" @@ -4867,11 +4738,6 @@ es-abstract@^1.22.1, es-abstract@^1.22.3, es-abstract@^1.23.0, es-abstract@^1.23 unbox-primitive "^1.0.2" which-typed-array "^1.1.15" -es-array-method-boxes-properly@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz#873f3e84418de4ee19c5be752990b2e44718d09e" - integrity sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA== - es-define-property@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.0.tgz#c7faefbdff8b2696cf5f46921edfb77cc4ba3845" @@ -4939,18 +4805,6 @@ escape-string-regexp@^2.0.0: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== -escodegen@^1.9.1: - version "1.14.3" - resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.14.3.tgz#4e7b81fba61581dc97582ed78cab7f0e8d63f503" - integrity sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw== - dependencies: - esprima "^4.0.1" - estraverse "^4.2.0" - esutils "^2.0.2" - optionator "^0.8.1" - optionalDependencies: - source-map "~0.6.1" - escodegen@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-2.1.0.tgz#ba93bbb7a43986d29d6041f99f5262da773e2e17" @@ -5053,7 +4907,7 @@ esrecurse@^4.3.0: dependencies: estraverse "^5.2.0" -estraverse@^4.1.1, estraverse@^4.2.0: +estraverse@^4.1.1: version "4.3.0" resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== @@ -5093,24 +4947,6 @@ events@^3.0.0, events@^3.2.0, events@^3.3.0: resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== -exec-sh@^0.3.2: - version "0.3.6" - resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.3.6.tgz#ff264f9e325519a60cb5e273692943483cca63bc" - integrity sha512-nQn+hI3yp+oD0huYhKwvYI32+JFeq+XkNcD1GAo3Y/MjxsfVGmrrzrnzjWiNY6f+pUCP440fThsFh5gZrRAU/w== - -execa@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" - integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA== - dependencies: - cross-spawn "^6.0.0" - get-stream "^4.0.0" - is-stream "^1.1.0" - npm-run-path "^2.0.0" - p-finally "^1.0.0" - signal-exit "^3.0.0" - strip-eof "^1.0.0" - execa@^5.0.0: version "5.1.1" resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" @@ -5154,18 +4990,6 @@ expand-template@^2.0.3: resolved "https://registry.yarnpkg.com/expand-template/-/expand-template-2.0.3.tgz#6e14b3fcee0f3a6340ecb57d2e8918692052a47c" integrity sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg== -expect@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/expect/-/expect-24.9.0.tgz#b75165b4817074fa4a157794f46fe9f1ba15b6ca" - integrity sha512-wvVAx8XIol3Z5m9zvZXiyZOQ+sRJqNTIm6sGjdWlaZIeupQGO3WbYI+15D/AmEwZywL6wtJkbAbJtzkOfBuR0Q== - dependencies: - "@jest/types" "^24.9.0" - ansi-styles "^3.2.0" - jest-get-type "^24.9.0" - jest-matcher-utils "^24.9.0" - jest-message-util "^24.9.0" - jest-regex-util "^24.9.0" - expect@^27.5.1: version "27.5.1" resolved "https://registry.yarnpkg.com/expect/-/expect-27.5.1.tgz#83ce59f1e5bdf5f9d2b94b61d2050db48f3fef74" @@ -5308,6 +5132,11 @@ fast-deep-equal@^3.1.1: resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== +fast-fifo@^1.2.0, fast-fifo@^1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/fast-fifo/-/fast-fifo-1.3.2.tgz#286e31de96eb96d38a97899815740ba2a4f3640c" + integrity sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ== + fast-glob@^2.2.6: version "2.2.7" resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-2.2.7.tgz#6953857c3afa475fff92ee6015d52da70a4cd39d" @@ -5331,7 +5160,7 @@ fast-glob@^3.0.3, fast-glob@^3.3.2: merge2 "^1.3.0" micromatch "^4.0.4" -fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0: +fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== @@ -5509,6 +5338,14 @@ for-in@^1.0.2: resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" integrity sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ== +foreground-child@^3.1.0: + version "3.3.1" + resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.3.1.tgz#32e8e9ed1b68a3497befb9ac2b6adf92a638576f" + integrity sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw== + dependencies: + cross-spawn "^7.0.6" + signal-exit "^4.0.1" + forever-agent@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" @@ -5611,14 +5448,6 @@ fs.realpath@^1.0.0: resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== -fsevents@^1.2.7: - version "1.2.13" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.13.tgz#f325cb0455592428bcf11b383370ef70e3bfcc38" - integrity sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw== - dependencies: - bindings "^1.5.0" - nan "^2.12.1" - fsevents@^2.3.2, fsevents@~2.3.2: version "2.3.3" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" @@ -5711,13 +5540,6 @@ get-port@^5.1.1: resolved "https://registry.yarnpkg.com/get-port/-/get-port-5.1.1.tgz#0469ed07563479de6efb986baf053dcd7d4e3193" integrity sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ== -get-stream@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" - integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== - dependencies: - pump "^3.0.0" - get-stream@^6.0.0: version "6.0.1" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" @@ -5783,6 +5605,18 @@ glob-to-regexp@^0.4.1: resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== +glob@^10.0.0: + version "10.4.5" + resolved "https://registry.yarnpkg.com/glob/-/glob-10.4.5.tgz#f4d9f0b90ffdbab09c9d77f5f29b4262517b0956" + integrity sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg== + dependencies: + foreground-child "^3.1.0" + jackspeak "^3.1.2" + minimatch "^9.0.4" + minipass "^7.1.2" + package-json-from-dist "^1.0.0" + path-scurry "^1.11.1" + glob@^7.0.5, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: version "7.2.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" @@ -5861,16 +5695,11 @@ gopd@^1.0.1: dependencies: get-intrinsic "^1.1.3" -graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.3, graceful-fs@^4.1.6, graceful-fs@^4.1.9, graceful-fs@^4.2.0, graceful-fs@^4.2.11, graceful-fs@^4.2.3, graceful-fs@^4.2.4, graceful-fs@^4.2.9: +graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.3, graceful-fs@^4.1.6, graceful-fs@^4.1.9, graceful-fs@^4.2.0, graceful-fs@^4.2.11, graceful-fs@^4.2.3, graceful-fs@^4.2.4, graceful-fs@^4.2.9: version "4.2.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== -growly@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" - integrity sha512-+xGQY0YyAWCnqy7Cd++hc2JqMYzlm0dG30Jd0beaA64sROr8C4nt8Yc9V5Ro3avlSUDTN0ulqP/VBKi1/lLygw== - hammerjs@^2.0.8: version "2.0.8" resolved "https://registry.yarnpkg.com/hammerjs/-/hammerjs-2.0.8.tgz#04ef77862cff2bb79d30f7692095930222bf60f1" @@ -6031,13 +5860,6 @@ hosted-git-info@^4.0.1: dependencies: lru-cache "^6.0.0" -html-encoding-sniffer@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz#e70d84b94da53aa375e11fe3a351be6642ca46f8" - integrity sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw== - dependencies: - whatwg-encoding "^1.0.1" - html-encoding-sniffer@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz#42a6dc4fd33f00281176e8b23759ca4e4fa185f3" @@ -6184,14 +6006,6 @@ import-fresh@^3.0.0, import-fresh@^3.2.1: parent-module "^1.0.0" resolve-from "^4.0.0" -import-local@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/import-local/-/import-local-2.0.0.tgz#55070be38a5993cf18ef6db7e961f5bee5c5a09d" - integrity sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ== - dependencies: - pkg-dir "^3.0.0" - resolve-cwd "^2.0.0" - import-local@^3.0.2: version "3.1.0" resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.1.0.tgz#b4479df8a5fd44f6cdce24070675676063c95cb4" @@ -6271,13 +6085,6 @@ interval-operations@^1.0.7: resolved "https://registry.yarnpkg.com/interval-operations/-/interval-operations-1.1.0.tgz#375689e86f212ea72d215dd3fd74df4a80719730" integrity sha512-MfHaFhZPhDtsIDJUVxOnDab9kGeYinhApZ8BItNHjB+nGMs08FVQwLLdSY2+2dYtkAQjM2Oqg335Q8wjbVBg0A== -invariant@^2.2.4: - version "2.2.4" - resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" - integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== - dependencies: - loose-envify "^1.0.0" - ioredis@^4.27.0: version "4.28.5" resolved "https://registry.yarnpkg.com/ioredis/-/ioredis-4.28.5.tgz#5c149e6a8d76a7f8fa8a504ffc85b7d5b6797f9f" @@ -6589,12 +6396,7 @@ is-shared-array-buffer@^1.0.2, is-shared-array-buffer@^1.0.3: dependencies: call-bind "^1.0.7" -is-stream@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" - integrity sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ== - -is-stream@^2.0.0: +is-stream@^2.0.0, is-stream@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== @@ -6637,11 +6439,6 @@ is-windows@^1.0.2: resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== -is-wsl@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d" - integrity sha512-gfygJYZ2gLTDlmbWMI0CE2MwnFzSN/2SZfkMlItC4K/JBlsWVDB0bO6XhqcY13YXE7iMcAJnzTCJjPiTeJJ0Mw== - is-wsl@^2.1.1, is-wsl@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" @@ -6686,29 +6483,11 @@ isstream@~0.1.2: resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" integrity sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g== -istanbul-lib-coverage@^2.0.2, istanbul-lib-coverage@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz#675f0ab69503fad4b1d849f736baaca803344f49" - integrity sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA== - istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: version "3.2.2" resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz#2d166c4b0644d43a39f04bf6c2edd1e585f31756" integrity sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg== -istanbul-lib-instrument@^3.0.1, istanbul-lib-instrument@^3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-3.3.0.tgz#a5f63d91f0bbc0c3e479ef4c5de027335ec6d630" - integrity sha512-5nnIN4vo5xQZHdXno/YDXJ0G+I3dAm4XgzfSVTPLQpj/zAV2dV6Juy0yaf10/zrJOJeHoN3fraFe+XRq2bFVZA== - dependencies: - "@babel/generator" "^7.4.0" - "@babel/parser" "^7.4.3" - "@babel/template" "^7.4.0" - "@babel/traverse" "^7.4.3" - "@babel/types" "^7.4.0" - istanbul-lib-coverage "^2.0.5" - semver "^6.0.0" - istanbul-lib-instrument@^5.0.4, istanbul-lib-instrument@^5.1.0: version "5.2.1" resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz#d10c8885c2125574e1c231cacadf955675e1ce3d" @@ -6720,15 +6499,6 @@ istanbul-lib-instrument@^5.0.4, istanbul-lib-instrument@^5.1.0: istanbul-lib-coverage "^3.2.0" semver "^6.3.0" -istanbul-lib-report@^2.0.4: - version "2.0.8" - resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-2.0.8.tgz#5a8113cd746d43c4889eba36ab10e7d50c9b4f33" - integrity sha512-fHBeG573EIihhAblwgxrSenp0Dby6tJMFR/HvlerBsrCTD5bkUuoNtn3gVh29ZCS824cGGBPn7Sg7cNk+2xUsQ== - dependencies: - istanbul-lib-coverage "^2.0.5" - make-dir "^2.1.0" - supports-color "^6.1.0" - istanbul-lib-report@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz#908305bac9a5bd175ac6a74489eafd0fc2445a7d" @@ -6738,17 +6508,6 @@ istanbul-lib-report@^3.0.0: make-dir "^4.0.0" supports-color "^7.1.0" -istanbul-lib-source-maps@^3.0.1: - version "3.0.6" - resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.6.tgz#284997c48211752ec486253da97e3879defba8c8" - integrity sha512-R47KzMtDJH6X4/YW9XTx+jrLnZnscW4VpNN+1PViSYTejLVPWv7oov+Duf8YQSPyVRUvueQqz1TcsC6mooZTXw== - dependencies: - debug "^4.1.1" - istanbul-lib-coverage "^2.0.5" - make-dir "^2.1.0" - rimraf "^2.6.3" - source-map "^0.6.1" - istanbul-lib-source-maps@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz#895f3a709fcfba34c6de5a42939022f3e4358551" @@ -6758,13 +6517,6 @@ istanbul-lib-source-maps@^4.0.0: istanbul-lib-coverage "^3.0.0" source-map "^0.6.1" -istanbul-reports@^2.2.6: - version "2.2.7" - resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-2.2.7.tgz#5d939f6237d7b48393cc0959eab40cd4fd056931" - integrity sha512-uu1F/L1o5Y6LzPVSVZXNOoD/KXpJue9aeLRd0sM9uMXfZvzomB0WxVamWb5ue8kA2vVWEmW7EG+A5n3f1kqHKg== - dependencies: - html-escaper "^2.0.0" - istanbul-reports@^3.1.3: version "3.1.7" resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.7.tgz#daed12b9e1dca518e15c056e1e537e741280fa0b" @@ -6773,14 +6525,14 @@ istanbul-reports@^3.1.3: html-escaper "^2.0.0" istanbul-lib-report "^3.0.0" -jest-changed-files@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-24.9.0.tgz#08d8c15eb79a7fa3fc98269bc14b451ee82f8039" - integrity sha512-6aTWpe2mHF0DhL28WjdkO8LyGjs3zItPET4bMSeXU6T3ub4FPMw+mcOcbdGXQOAfmLcxofD23/5Bl9Z4AkFwqg== +jackspeak@^3.1.2: + version "3.4.3" + resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-3.4.3.tgz#8833a9d89ab4acde6188942bd1c53b6390ed5a8a" + integrity sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw== dependencies: - "@jest/types" "^24.9.0" - execa "^1.0.0" - throat "^4.0.0" + "@isaacs/cliui" "^8.0.2" + optionalDependencies: + "@pkgjs/parseargs" "^0.11.0" jest-changed-files@^27.5.1: version "27.5.1" @@ -6849,25 +6601,6 @@ jest-circus@^28.1.3: slash "^3.0.0" stack-utils "^2.0.3" -jest-cli@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-24.9.0.tgz#ad2de62d07472d419c6abc301fc432b98b10d2af" - integrity sha512-+VLRKyitT3BWoMeSUIHRxV/2g8y9gw91Jh5z2UmXZzkZKpbC08CSehVxgHUwTpy+HwGcns/tqafQDJW7imYvGg== - dependencies: - "@jest/core" "^24.9.0" - "@jest/test-result" "^24.9.0" - "@jest/types" "^24.9.0" - chalk "^2.0.1" - exit "^0.1.2" - import-local "^2.0.0" - is-ci "^2.0.0" - jest-config "^24.9.0" - jest-util "^24.9.0" - jest-validate "^24.9.0" - prompts "^2.0.1" - realpath-native "^1.1.0" - yargs "^13.3.0" - jest-cli@^27.5.1: version "27.5.1" resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-27.5.1.tgz#278794a6e6458ea8029547e6c6cbf673bd30b145" @@ -6904,29 +6637,6 @@ jest-cli@^28.1.3: prompts "^2.0.1" yargs "^17.3.1" -jest-config@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-24.9.0.tgz#fb1bbc60c73a46af03590719efa4825e6e4dd1b5" - integrity sha512-RATtQJtVYQrp7fvWg6f5y3pEFj9I+H8sWw4aKxnDZ96mob5i5SD6ZEGWgMLXQ4LE8UurrjbdlLWdUeo+28QpfQ== - dependencies: - "@babel/core" "^7.1.0" - "@jest/test-sequencer" "^24.9.0" - "@jest/types" "^24.9.0" - babel-jest "^24.9.0" - chalk "^2.0.1" - glob "^7.1.1" - jest-environment-jsdom "^24.9.0" - jest-environment-node "^24.9.0" - jest-get-type "^24.9.0" - jest-jasmine2 "^24.9.0" - jest-regex-util "^24.3.0" - jest-resolve "^24.9.0" - jest-util "^24.9.0" - jest-validate "^24.9.0" - micromatch "^3.1.10" - pretty-format "^24.9.0" - realpath-native "^1.1.0" - jest-config@^27.5.1: version "27.5.1" resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-27.5.1.tgz#5c387de33dca3f99ad6357ddeccd91bf3a0e4a41" @@ -6985,16 +6695,6 @@ jest-config@^28.1.3: slash "^3.0.0" strip-json-comments "^3.1.1" -jest-diff@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-24.9.0.tgz#931b7d0d5778a1baf7452cb816e325e3724055da" - integrity sha512-qMfrTs8AdJE2iqrTp0hzh7kTd2PQWrsFyj9tORoKmu32xjPjeE4NyjVRDz8ybYwqS2ik8N4hsIpiVTyFeo2lBQ== - dependencies: - chalk "^2.0.1" - diff-sequences "^24.9.0" - jest-get-type "^24.9.0" - pretty-format "^24.9.0" - jest-diff@^25.2.1: version "25.5.0" resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-25.5.0.tgz#1dd26ed64f96667c068cef026b677dfa01afcfa9" @@ -7025,13 +6725,6 @@ jest-diff@^28.1.3: jest-get-type "^28.0.2" pretty-format "^28.1.3" -jest-docblock@^24.3.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-24.9.0.tgz#7970201802ba560e1c4092cc25cbedf5af5a8ce2" - integrity sha512-F1DjdpDMJMA1cN6He0FNYNZlo3yYmOtRUnktrT9Q37njYzC5WEaDdmbynIgy0L/IvXvvgsG8OsqhLPXTpfmZAA== - dependencies: - detect-newline "^2.1.0" - jest-docblock@^27.5.1: version "27.5.1" resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-27.5.1.tgz#14092f364a42c6108d42c33c8cf30e058e25f6c0" @@ -7046,17 +6739,6 @@ jest-docblock@^28.1.1: dependencies: detect-newline "^3.0.0" -jest-each@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-24.9.0.tgz#eb2da602e2a610898dbc5f1f6df3ba86b55f8b05" - integrity sha512-ONi0R4BvW45cw8s2Lrx8YgbeXL1oCQ/wIDwmsM3CqM/nlblNCPmnC3IPQlMbRFZu3wKdQ2U8BqM6lh3LJ5Bsog== - dependencies: - "@jest/types" "^24.9.0" - chalk "^2.0.1" - jest-get-type "^24.9.0" - jest-util "^24.9.0" - pretty-format "^24.9.0" - jest-each@^27.5.1: version "27.5.1" resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-27.5.1.tgz#5bc87016f45ed9507fed6e4702a5b468a5b2c44e" @@ -7079,18 +6761,6 @@ jest-each@^28.1.3: jest-util "^28.1.3" pretty-format "^28.1.3" -jest-environment-jsdom@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-24.9.0.tgz#4b0806c7fc94f95edb369a69cc2778eec2b7375b" - integrity sha512-Zv9FV9NBRzLuALXjvRijO2351DRQeLYXtpD4xNvfoVFw21IOKNhZAEUKcbiEtjTkm2GsJ3boMVgkaR7rN8qetA== - dependencies: - "@jest/environment" "^24.9.0" - "@jest/fake-timers" "^24.9.0" - "@jest/types" "^24.9.0" - jest-mock "^24.9.0" - jest-util "^24.9.0" - jsdom "^11.5.1" - jest-environment-jsdom@^27.5.1: version "27.5.1" resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-27.5.1.tgz#ea9ccd1fc610209655a77898f86b2b559516a546" @@ -7104,17 +6774,6 @@ jest-environment-jsdom@^27.5.1: jest-util "^27.5.1" jsdom "^16.6.0" -jest-environment-node@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-24.9.0.tgz#333d2d2796f9687f2aeebf0742b519f33c1cbfd3" - integrity sha512-6d4V2f4nxzIzwendo27Tr0aFm+IXWa0XEUnaH6nU0FMaozxovt+sfRvh4J47wL1OvF83I3SSTu0XK+i4Bqe7uA== - dependencies: - "@jest/environment" "^24.9.0" - "@jest/fake-timers" "^24.9.0" - "@jest/types" "^24.9.0" - jest-mock "^24.9.0" - jest-util "^24.9.0" - jest-environment-node@^27.5.1: version "27.5.1" resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-27.5.1.tgz#dedc2cfe52fab6b8f5714b4808aefa85357a365e" @@ -7139,11 +6798,6 @@ jest-environment-node@^28.1.3: jest-mock "^28.1.3" jest-util "^28.1.3" -jest-get-type@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-24.9.0.tgz#1684a0c8a50f2e4901b6644ae861f579eed2ef0e" - integrity sha512-lUseMzAley4LhIcpSP9Jf+fTrQ4a1yHQwLNeeVa2cEmbCGeoZAtYPOIv8JaxLD/sUpKxetKGP+gsHl8f8TSj8Q== - jest-get-type@^25.2.6: version "25.2.6" resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-25.2.6.tgz#0b0a32fab8908b44d508be81681487dbabb8d877" @@ -7159,25 +6813,6 @@ jest-get-type@^28.0.2: resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-28.0.2.tgz#34622e628e4fdcd793d46db8a242227901fcf203" integrity sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA== -jest-haste-map@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-24.9.0.tgz#b38a5d64274934e21fa417ae9a9fbeb77ceaac7d" - integrity sha512-kfVFmsuWui2Sj1Rp1AJ4D9HqJwE4uwTlS/vO+eRUaMmd54BFpli2XhMQnPC2k4cHFVbB2Q2C+jtI1AGLgEnCjQ== - dependencies: - "@jest/types" "^24.9.0" - anymatch "^2.0.0" - fb-watchman "^2.0.0" - graceful-fs "^4.1.15" - invariant "^2.2.4" - jest-serializer "^24.9.0" - jest-util "^24.9.0" - jest-worker "^24.9.0" - micromatch "^3.1.10" - sane "^4.0.3" - walker "^1.0.7" - optionalDependencies: - fsevents "^1.2.7" - jest-haste-map@^27.5.1: version "27.5.1" resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-27.5.1.tgz#9fd8bd7e7b4fa502d9c6164c5640512b4e811e7f" @@ -7217,28 +6852,6 @@ jest-haste-map@^28.1.3: optionalDependencies: fsevents "^2.3.2" -jest-jasmine2@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-24.9.0.tgz#1f7b1bd3242c1774e62acabb3646d96afc3be6a0" - integrity sha512-Cq7vkAgaYKp+PsX+2/JbTarrk0DmNhsEtqBXNwUHkdlbrTBLtMJINADf2mf5FkowNsq8evbPc07/qFO0AdKTzw== - dependencies: - "@babel/traverse" "^7.1.0" - "@jest/environment" "^24.9.0" - "@jest/test-result" "^24.9.0" - "@jest/types" "^24.9.0" - chalk "^2.0.1" - co "^4.6.0" - expect "^24.9.0" - is-generator-fn "^2.0.0" - jest-each "^24.9.0" - jest-matcher-utils "^24.9.0" - jest-message-util "^24.9.0" - jest-runtime "^24.9.0" - jest-snapshot "^24.9.0" - jest-util "^24.9.0" - pretty-format "^24.9.0" - throat "^4.0.0" - jest-jasmine2@^27.5.1: version "27.5.1" resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-27.5.1.tgz#a037b0034ef49a9f3d71c4375a796f3b230d1ac4" @@ -7262,14 +6875,6 @@ jest-jasmine2@^27.5.1: pretty-format "^27.5.1" throat "^6.0.1" -jest-leak-detector@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-24.9.0.tgz#b665dea7c77100c5c4f7dfcb153b65cf07dcf96a" - integrity sha512-tYkFIDsiKTGwb2FG1w8hX9V0aUb2ot8zY/2nFg087dUageonw1zrLMP4W6zsRO59dPkTSKie+D4rhMuP9nRmrA== - dependencies: - jest-get-type "^24.9.0" - pretty-format "^24.9.0" - jest-leak-detector@^27.5.1: version "27.5.1" resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-27.5.1.tgz#6ec9d54c3579dd6e3e66d70e3498adf80fde3fb8" @@ -7286,16 +6891,6 @@ jest-leak-detector@^28.1.3: jest-get-type "^28.0.2" pretty-format "^28.1.3" -jest-matcher-utils@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-24.9.0.tgz#f5b3661d5e628dffe6dd65251dfdae0e87c3a073" - integrity sha512-OZz2IXsu6eaiMAwe67c1T+5tUAtQyQx27/EMEkbFAGiw52tB9em+uGbzpcgYVpA8wl0hlxKPZxrly4CXU/GjHA== - dependencies: - chalk "^2.0.1" - jest-diff "^24.9.0" - jest-get-type "^24.9.0" - pretty-format "^24.9.0" - jest-matcher-utils@^27.5.1: version "27.5.1" resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz#9c0cdbda8245bc22d2331729d1091308b40cf8ab" @@ -7316,20 +6911,6 @@ jest-matcher-utils@^28.1.3: jest-get-type "^28.0.2" pretty-format "^28.1.3" -jest-message-util@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-24.9.0.tgz#527f54a1e380f5e202a8d1149b0ec872f43119e3" - integrity sha512-oCj8FiZ3U0hTP4aSui87P4L4jC37BtQwUMqk+zk/b11FR19BJDeZsZAvIHutWnmtw7r85UmR3CEWZ0HWU2mAlw== - dependencies: - "@babel/code-frame" "^7.0.0" - "@jest/test-result" "^24.9.0" - "@jest/types" "^24.9.0" - "@types/stack-utils" "^1.0.1" - chalk "^2.0.1" - micromatch "^3.1.10" - slash "^2.0.0" - stack-utils "^1.0.1" - jest-message-util@^27.5.1: version "27.5.1" resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-27.5.1.tgz#bdda72806da10d9ed6425e12afff38cd1458b6cf" @@ -7360,13 +6941,6 @@ jest-message-util@^28.1.3: slash "^3.0.0" stack-utils "^2.0.3" -jest-mock@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-24.9.0.tgz#c22835541ee379b908673ad51087a2185c13f1c6" - integrity sha512-3BEYN5WbSq9wd+SyLDES7AHnjH9A/ROBwmz7l2y+ol+NtSFO8DYiEBzoO1CeFc9a8DYy10EO4dDFVv/wN3zl1w== - dependencies: - "@jest/types" "^24.9.0" - jest-mock@^27.5.1: version "27.5.1" resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-27.5.1.tgz#19948336d49ef4d9c52021d34ac7b5f36ff967d6" @@ -7383,16 +6957,11 @@ jest-mock@^28.1.3: "@jest/types" "^28.1.3" "@types/node" "*" -jest-pnp-resolver@^1.2.1, jest-pnp-resolver@^1.2.2: +jest-pnp-resolver@^1.2.2: version "1.2.3" resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz#930b1546164d4ad5937d5540e711d4d38d4cad2e" integrity sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w== -jest-regex-util@^24.3.0, jest-regex-util@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-24.9.0.tgz#c13fb3380bde22bf6575432c493ea8fe37965636" - integrity sha512-05Cmb6CuxaA+Ys6fjr3PhvV3bGQmO+2p2La4hFbU+W5uOc479f7FdLXUWXw4pYMAhhSZIuKHwSXSu6CsSBAXQA== - jest-regex-util@^27.5.1: version "27.5.1" resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-27.5.1.tgz#4da143f7e9fd1e542d4aa69617b38e4a78365b95" @@ -7403,15 +6972,6 @@ jest-regex-util@^28.0.2: resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-28.0.2.tgz#afdc377a3b25fb6e80825adcf76c854e5bf47ead" integrity sha512-4s0IgyNIy0y9FK+cjoVYoxamT7Zeo7MhzqRGx7YDYmaQn1wucY9rotiGkBzzcMXTtjrCAP/f7f+E0F7+fxPNdw== -jest-resolve-dependencies@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-24.9.0.tgz#ad055198959c4cfba8a4f066c673a3f0786507ab" - integrity sha512-Fm7b6AlWnYhT0BXy4hXpactHIqER7erNgIsIozDXWl5dVm+k8XdGVe1oTg1JyaFnOxarMEbax3wyRJqGP2Pq+g== - dependencies: - "@jest/types" "^24.9.0" - jest-regex-util "^24.3.0" - jest-snapshot "^24.9.0" - jest-resolve-dependencies@^27.5.1: version "27.5.1" resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-27.5.1.tgz#d811ecc8305e731cc86dd79741ee98fed06f1da8" @@ -7429,17 +6989,6 @@ jest-resolve-dependencies@^28.1.3: jest-regex-util "^28.0.2" jest-snapshot "^28.1.3" -jest-resolve@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-24.9.0.tgz#dff04c7687af34c4dd7e524892d9cf77e5d17321" - integrity sha512-TaLeLVL1l08YFZAt3zaPtjiVvyy4oSA6CRe+0AFPPVX3Q/VI0giIWWoAvoS5L96vj9Dqxj4fB5p2qrHCmTU/MQ== - dependencies: - "@jest/types" "^24.9.0" - browser-resolve "^1.11.3" - chalk "^2.0.1" - jest-pnp-resolver "^1.2.1" - realpath-native "^1.1.0" - jest-resolve@^27.5.1: version "27.5.1" resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-27.5.1.tgz#a2f1c5a0796ec18fe9eb1536ac3814c23617b384" @@ -7471,31 +7020,6 @@ jest-resolve@^28.1.3: resolve.exports "^1.1.0" slash "^3.0.0" -jest-runner@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-24.9.0.tgz#574fafdbd54455c2b34b4bdf4365a23857fcdf42" - integrity sha512-KksJQyI3/0mhcfspnxxEOBueGrd5E4vV7ADQLT9ESaCzz02WnbdbKWIf5Mkaucoaj7obQckYPVX6JJhgUcoWWg== - dependencies: - "@jest/console" "^24.7.1" - "@jest/environment" "^24.9.0" - "@jest/test-result" "^24.9.0" - "@jest/types" "^24.9.0" - chalk "^2.4.2" - exit "^0.1.2" - graceful-fs "^4.1.15" - jest-config "^24.9.0" - jest-docblock "^24.3.0" - jest-haste-map "^24.9.0" - jest-jasmine2 "^24.9.0" - jest-leak-detector "^24.9.0" - jest-message-util "^24.9.0" - jest-resolve "^24.9.0" - jest-runtime "^24.9.0" - jest-util "^24.9.0" - jest-worker "^24.6.0" - source-map-support "^0.5.6" - throat "^4.0.0" - jest-runner@^27.5.1: version "27.5.1" resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-27.5.1.tgz#071b27c1fa30d90540805c5645a0ec167c7b62e5" @@ -7550,35 +7074,6 @@ jest-runner@^28.1.3: p-limit "^3.1.0" source-map-support "0.5.13" -jest-runtime@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-24.9.0.tgz#9f14583af6a4f7314a6a9d9f0226e1a781c8e4ac" - integrity sha512-8oNqgnmF3v2J6PVRM2Jfuj8oX3syKmaynlDMMKQ4iyzbQzIG6th5ub/lM2bCMTmoTKM3ykcUYI2Pw9xwNtjMnw== - dependencies: - "@jest/console" "^24.7.1" - "@jest/environment" "^24.9.0" - "@jest/source-map" "^24.3.0" - "@jest/transform" "^24.9.0" - "@jest/types" "^24.9.0" - "@types/yargs" "^13.0.0" - chalk "^2.0.1" - exit "^0.1.2" - glob "^7.1.3" - graceful-fs "^4.1.15" - jest-config "^24.9.0" - jest-haste-map "^24.9.0" - jest-message-util "^24.9.0" - jest-mock "^24.9.0" - jest-regex-util "^24.3.0" - jest-resolve "^24.9.0" - jest-snapshot "^24.9.0" - jest-util "^24.9.0" - jest-validate "^24.9.0" - realpath-native "^1.1.0" - slash "^2.0.0" - strip-bom "^3.0.0" - yargs "^13.3.0" - jest-runtime@^27.5.1: version "27.5.1" resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-27.5.1.tgz#4896003d7a334f7e8e4a53ba93fb9bcd3db0a1af" @@ -7635,11 +7130,6 @@ jest-runtime@^28.1.3: slash "^3.0.0" strip-bom "^4.0.0" -jest-serializer@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-24.9.0.tgz#e6d7d7ef96d31e8b9079a714754c5d5c58288e73" - integrity sha512-DxYipDr8OvfrKH3Kel6NdED3OXxjvxXZ1uIY2I9OFbGg+vUkkg7AGvi65qbhbWNPvDckXmzMPbK3u3HaDO49bQ== - jest-serializer@^27.5.1: version "27.5.1" resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-27.5.1.tgz#81438410a30ea66fd57ff730835123dea1fb1f64" @@ -7648,25 +7138,6 @@ jest-serializer@^27.5.1: "@types/node" "*" graceful-fs "^4.2.9" -jest-snapshot@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-24.9.0.tgz#ec8e9ca4f2ec0c5c87ae8f925cf97497b0e951ba" - integrity sha512-uI/rszGSs73xCM0l+up7O7a40o90cnrk429LOiK3aeTvfC0HHmldbd81/B7Ix81KSFe1lwkbl7GnBGG4UfuDew== - dependencies: - "@babel/types" "^7.0.0" - "@jest/types" "^24.9.0" - chalk "^2.0.1" - expect "^24.9.0" - jest-diff "^24.9.0" - jest-get-type "^24.9.0" - jest-matcher-utils "^24.9.0" - jest-message-util "^24.9.0" - jest-resolve "^24.9.0" - mkdirp "^0.5.1" - natural-compare "^1.4.0" - pretty-format "^24.9.0" - semver "^6.2.0" - jest-snapshot@^27.5.1: version "27.5.1" resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-27.5.1.tgz#b668d50d23d38054a51b42c4039cab59ae6eb6a1" @@ -7724,24 +7195,6 @@ jest-snapshot@^28.1.3: pretty-format "^28.1.3" semver "^7.3.5" -jest-util@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-24.9.0.tgz#7396814e48536d2e85a37de3e4c431d7cb140162" - integrity sha512-x+cZU8VRmOJxbA1K5oDBdxQmdq0OIdADarLxk0Mq+3XS4jgvhG/oKGWcIDCtPG0HgjxOYvF+ilPJQsAyXfbNOg== - dependencies: - "@jest/console" "^24.9.0" - "@jest/fake-timers" "^24.9.0" - "@jest/source-map" "^24.9.0" - "@jest/test-result" "^24.9.0" - "@jest/types" "^24.9.0" - callsites "^3.0.0" - chalk "^2.0.1" - graceful-fs "^4.1.15" - is-ci "^2.0.0" - mkdirp "^0.5.1" - slash "^2.0.0" - source-map "^0.6.0" - jest-util@^27.5.1: version "27.5.1" resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-27.5.1.tgz#3ba9771e8e31a0b85da48fe0b0891fb86c01c2f9" @@ -7766,18 +7219,6 @@ jest-util@^28.0.0, jest-util@^28.1.3: graceful-fs "^4.2.9" picomatch "^2.2.3" -jest-validate@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-24.9.0.tgz#0775c55360d173cd854e40180756d4ff52def8ab" - integrity sha512-HPIt6C5ACwiqSiwi+OfSSHbK8sG7akG8eATl+IPKaeIjtPOeBUd/g3J7DghugzxrGjI93qS/+RPKe1H6PqvhRQ== - dependencies: - "@jest/types" "^24.9.0" - camelcase "^5.3.1" - chalk "^2.0.1" - jest-get-type "^24.9.0" - leven "^3.1.0" - pretty-format "^24.9.0" - jest-validate@^27.5.1: version "27.5.1" resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-27.5.1.tgz#9197d54dc0bdb52260b8db40b46ae668e04df067" @@ -7802,19 +7243,6 @@ jest-validate@^28.1.3: leven "^3.1.0" pretty-format "^28.1.3" -jest-watcher@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-24.9.0.tgz#4b56e5d1ceff005f5b88e528dc9afc8dd4ed2b3b" - integrity sha512-+/fLOfKPXXYJDYlks62/4R4GoT+GU1tYZed99JSCOsmzkkF7727RqKrjNAxtfO4YpGv11wybgRvCjR73lK2GZw== - dependencies: - "@jest/test-result" "^24.9.0" - "@jest/types" "^24.9.0" - "@types/yargs" "^13.0.0" - ansi-escapes "^3.0.0" - chalk "^2.0.1" - jest-util "^24.9.0" - string-length "^2.0.0" - jest-watcher@^27.5.1: version "27.5.1" resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-27.5.1.tgz#71bd85fb9bde3a2c2ec4dc353437971c43c642a2" @@ -7842,14 +7270,6 @@ jest-watcher@^28.1.3: jest-util "^28.1.3" string-length "^4.0.1" -jest-worker@^24.6.0, jest-worker@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-24.9.0.tgz#5dbfdb5b2d322e98567898238a9697bcce67b3e5" - integrity sha512-51PE4haMSXcHohnSMdM42anbvZANYTqMrr52tVKPqqsPJMzoP6FYYDVqahX/HrAoKEKz3uUPzSvKs9A3qR4iVw== - dependencies: - merge-stream "^2.0.0" - supports-color "^6.1.0" - jest-worker@^26.2.1: version "26.6.2" resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-26.6.2.tgz#7f72cbc4d643c365e27b9fd775f9d0eaa9c7a8ed" @@ -7877,14 +7297,6 @@ jest-worker@^28.1.3: merge-stream "^2.0.0" supports-color "^8.0.0" -jest@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest/-/jest-24.9.0.tgz#987d290c05a08b52c56188c1002e368edb007171" - integrity sha512-YvkBL1Zm7d2B1+h5fHEOdyjCG+sGMz4f8D86/0HiqJ6MB4MnDc8FgP5vdWsGnemOQro7lnYo8UakZ3+5A0jxGw== - dependencies: - import-local "^2.0.0" - jest-cli "^24.9.0" - jest@^27.0.1: version "27.5.1" resolved "https://registry.yarnpkg.com/jest/-/jest-27.5.1.tgz#dadf33ba70a779be7a6fc33015843b51494f63fc" @@ -7914,7 +7326,7 @@ js-md4@^0.3.2: resolved "https://registry.yarnpkg.com/js-md4/-/js-md4-0.3.2.tgz#cd3b3dc045b0c404556c81ddb5756c23e59d7cf5" integrity sha512-/GDnfQYsltsjRswQhN9fhv3EMw2sCpUdrdxyWDOUK7eyD++r3gRhzgiQgc/x4MAv2i1iuQ4lxO5mvqM3vj4bwA== -"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: +js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== @@ -7941,6 +7353,11 @@ js2xmlparser@^4.0.2: dependencies: xmlcreate "^2.0.4" +jsbi@^4.3.0: + version "4.3.2" + resolved "https://registry.yarnpkg.com/jsbi/-/jsbi-4.3.2.tgz#8a4d05d4e09907d73042135b6aa55a6d161ee955" + integrity sha512-9fqMSQbhJykSeii05nxKl4m6Eqn2P6rOlYiS+C5Dr/HPIU/7yZxu5qzbs40tgaFORiw2Amd0mirjxatXYMkIew== + jsbn@1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-1.1.0.tgz#b01307cb29b618a1ed26ec79e911f803c4da0040" @@ -8009,38 +7426,6 @@ jsdoc@^4.0.4: strip-json-comments "^3.1.0" underscore "~1.13.2" -jsdom@^11.5.1: - version "11.12.0" - resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-11.12.0.tgz#1a80d40ddd378a1de59656e9e6dc5a3ba8657bc8" - integrity sha512-y8Px43oyiBM13Zc1z780FrfNLJCXTL40EWlty/LXUtcjykRBNgLlCjWXpfSPBl2iv+N7koQN+dvqszHZgT/Fjw== - dependencies: - abab "^2.0.0" - acorn "^5.5.3" - acorn-globals "^4.1.0" - array-equal "^1.0.0" - cssom ">= 0.3.2 < 0.4.0" - cssstyle "^1.0.0" - data-urls "^1.0.0" - domexception "^1.0.1" - escodegen "^1.9.1" - html-encoding-sniffer "^1.0.2" - left-pad "^1.3.0" - nwsapi "^2.0.7" - parse5 "4.0.0" - pn "^1.1.0" - request "^2.87.0" - request-promise-native "^1.0.5" - sax "^1.2.4" - symbol-tree "^3.2.2" - tough-cookie "^2.3.4" - w3c-hr-time "^1.0.1" - webidl-conversions "^4.0.2" - whatwg-encoding "^1.0.3" - whatwg-mimetype "^2.1.0" - whatwg-url "^6.4.1" - ws "^5.2.0" - xml-name-validator "^3.0.0" - jsdom@^16.6.0: version "16.7.0" resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-16.7.0.tgz#918ae71965424b197c819f8183a754e18977b710" @@ -8119,7 +7504,7 @@ json-stringify-safe@~5.0.1: resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" integrity sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA== -json5@2.x, json5@^2.1.2, json5@^2.2.1, json5@^2.2.3: +json5@^2.1.2, json5@^2.2.1, json5@^2.2.3: version "2.2.3" resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== @@ -8264,6 +7649,13 @@ kleur@^3.0.0, kleur@^3.0.3: resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== +lazystream@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/lazystream/-/lazystream-1.0.1.tgz#494c831062f1f9408251ec44db1cba29242a2638" + integrity sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw== + dependencies: + readable-stream "^2.0.5" + ldap-filter@^0.3.3: version "0.3.3" resolved "https://registry.yarnpkg.com/ldap-filter/-/ldap-filter-0.3.3.tgz#2b14c68a2a9d4104dbdbc910a1ca85fd189e9797" @@ -8290,11 +7682,6 @@ leaflet@^1.8.0: resolved "https://registry.yarnpkg.com/leaflet/-/leaflet-1.9.4.tgz#23fae724e282fa25745aff82ca4d394748db7d8d" integrity sha512-nxS1ynzJOmOlHp+iL3FyWqK89GtNL8U8rvlMOsQdTTssxZwCXh8N2NB3GDQOL+YR3XnWyZAxwQixURb+FA74PA== -left-pad@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/left-pad/-/left-pad-1.3.0.tgz#5b8a3a7765dfe001261dde915589e782f8c94d1e" - integrity sha512-XI5MPzVNApjAyhQzphX8BkmKsKUxD4LdyK24iZeQGinBN9yTQT3bFlCBy/aVx2HrNcqQGsdot8ghrjyrvMCoEA== - leven@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" @@ -8363,16 +7750,6 @@ livereload@^0.9.1: opts ">= 1.2.0" ws "^7.4.3" -load-json-file@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b" - integrity sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw== - dependencies: - graceful-fs "^4.1.2" - parse-json "^4.0.0" - pify "^3.0.0" - strip-bom "^3.0.0" - loader-runner@^4.2.0: version "4.3.0" resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.3.0.tgz#c1b4a163b99f614830353b16755e7149ac2314e1" @@ -8479,11 +7856,6 @@ lodash.once@^4.0.0: resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" integrity sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg== -lodash.sortby@^4.7.0: - version "4.7.0" - resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" - integrity sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA== - lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.21, lodash@^4.7.0: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" @@ -8494,12 +7866,10 @@ long@*, long@^5.2.1, long@~5.2.3: resolved "https://registry.yarnpkg.com/long/-/long-5.2.3.tgz#a3ba97f3877cf1d778eccbcb048525ebb77499e1" integrity sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q== -loose-envify@^1.0.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" - integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== - dependencies: - js-tokens "^3.0.0 || ^4.0.0" +lru-cache@^10.2.0: + version "10.4.3" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.4.3.tgz#410fc8a17b70e598013df257c2446b7f3383f119" + integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ== lru-cache@^5.1.1: version "5.1.1" @@ -8532,14 +7902,6 @@ magic-string@^0.25.7: dependencies: sourcemap-codec "^1.4.8" -make-dir@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" - integrity sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA== - dependencies: - pify "^4.0.1" - semver "^5.6.0" - make-dir@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-4.0.0.tgz#c3c2307a771277cd9638305f915c29ae741b614e" @@ -8694,15 +8056,7 @@ methods@~1.1.2: resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== -micromatch@4.x, micromatch@^4.0.2, micromatch@^4.0.4: - version "4.0.5" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" - integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== - dependencies: - braces "^3.0.2" - picomatch "^2.3.1" - -micromatch@^3.1.10, micromatch@^3.1.4: +micromatch@^3.1.10: version "3.1.10" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== @@ -8721,6 +8075,14 @@ micromatch@^3.1.10, micromatch@^3.1.4: snapdragon "^0.8.1" to-regex "^3.0.2" +micromatch@^4.0.2, micromatch@^4.0.4: + version "4.0.5" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" + integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== + dependencies: + braces "^3.0.2" + picomatch "^2.3.1" + mime-db@1.52.0: version "1.52.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" @@ -8760,13 +8122,20 @@ minimatch@^3.0.3, minimatch@^3.0.4, minimatch@^3.1.1, minimatch@^3.1.2: dependencies: brace-expansion "^1.1.7" -minimatch@^5.0.1: +minimatch@^5.0.1, minimatch@^5.1.0: version "5.1.6" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.6.tgz#1cfcb8cf5522ea69952cd2af95ae09477f122a96" integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g== dependencies: brace-expansion "^2.0.1" +minimatch@^9.0.4: + version "9.0.5" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" + integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== + dependencies: + brace-expansion "^2.0.1" + minimist-options@^4.0.2: version "4.1.0" resolved "https://registry.yarnpkg.com/minimist-options/-/minimist-options-4.1.0.tgz#c0655713c53a8a2ebd77ffa247d342c40f010619" @@ -8776,7 +8145,7 @@ minimist-options@^4.0.2: is-plain-obj "^1.1.0" kind-of "^6.0.3" -minimist@^1.1.1, minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.5, minimist@^1.2.6, minimist@~1.2.0: +minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.5, minimist@^1.2.6, minimist@~1.2.0: version "1.2.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== @@ -8840,6 +8209,11 @@ minipass@^5.0.0: resolved "https://registry.yarnpkg.com/minipass/-/minipass-5.0.0.tgz#3e9788ffb90b694a5d0ec94479a45b5d8738133d" integrity sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ== +"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.1.2: + version "7.1.2" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.2.tgz#93a9626ce5e5e66bd4db86849e7515e92340a707" + integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw== + minizlib@^2.0.0, minizlib@^2.1.1: version "2.1.2" resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931" @@ -8866,7 +8240,7 @@ mkdirp@0.3.0: resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.3.0.tgz#1bbf5ab1ba827af23575143490426455f481fe1e" integrity sha512-OHsdUcVAQ6pOtg5JYWpCBo9W/GySVuwvP9hueRMW7UqshC0tbfzLv8wjySTPm3tfUZ/21CE9E1pJagOA91Pxew== -mkdirp@0.x, mkdirp@^0.5.1, mkdirp@^0.5.6: +mkdirp@^0.5.1, mkdirp@^0.5.6: version "0.5.6" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6" integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw== @@ -8974,7 +8348,7 @@ named-placeholders@^1.1.3: dependencies: lru-cache "^7.14.1" -nan@^2.12.1, nan@^2.19.0: +nan@^2.19.0: version "2.19.0" resolved "https://registry.yarnpkg.com/nan/-/nan-2.19.0.tgz#bb58122ad55a6c5bc973303908d5b16cfdd5a8c0" integrity sha512-nO1xXxfh/RWNxfd/XPfbIfFk5vgLsAxUR9y5O0cHMJu/AW9U95JLXqthYHjEp+8gQ5p96K9jUp8nbVOxCdRbtw== @@ -9085,17 +8459,6 @@ node-loader@^1.0.2: loader-utils "^2.0.0" schema-utils "^3.0.0" -node-notifier@^5.4.2: - version "5.4.5" - resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-5.4.5.tgz#0cbc1a2b0f658493b4025775a13ad938e96091ef" - integrity sha512-tVbHs7DyTLtzOiN78izLA85zRqB9NvEXkAf014Vx3jtSvn/xBl6bR8ZYifj+dFcFrKI21huSQgJZ6ZtL3B4HfQ== - dependencies: - growly "^1.3.0" - is-wsl "^1.1.0" - semver "^5.5.0" - shellwords "^0.1.1" - which "^1.3.0" - node-redis-dump2@^0.5.0: version "0.5.0" resolved "https://registry.yarnpkg.com/node-redis-dump2/-/node-redis-dump2-0.5.0.tgz#22cdb8ef37d8d0234e68027136b2d2a7b66af103" @@ -9163,13 +8526,6 @@ normalize-package-data@^2.3.2, normalize-package-data@^2.5.0: semver "2 || 3 || 4 || 5" validate-npm-package-license "^3.0.1" -normalize-path@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" - integrity sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w== - dependencies: - remove-trailing-separator "^1.0.1" - normalize-path@^3.0.0, normalize-path@~3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" @@ -9235,13 +8591,6 @@ npm-registry-fetch@^11.0.0: minizlib "^2.0.0" npm-package-arg "^8.0.0" -npm-run-path@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" - integrity sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw== - dependencies: - path-key "^2.0.0" - npm-run-path@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" @@ -9264,7 +8613,7 @@ number-is-nan@^1.0.0: resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" integrity sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ== -nwsapi@^2.0.7, nwsapi@^2.2.0: +nwsapi@^2.2.0: version "2.2.9" resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.9.tgz#7f3303218372db2e9f27c27766bcfc59ae7e61c6" integrity sha512-2f3F0SEEer8bBu0dsNCFF50N0cTThV1nWFYcEYFZttdW0lDAoybv9cQoK7X7/68Z89S7FoRrVjP1LPX4XRf9vg== @@ -9325,19 +8674,6 @@ object.assign@^4.1.5: has-symbols "^1.0.3" object-keys "^1.1.1" -object.getownpropertydescriptors@^2.1.6: - version "2.1.8" - resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.8.tgz#2f1fe0606ec1a7658154ccd4f728504f69667923" - integrity sha512-qkHIGe4q0lSYMv0XI4SsBTJz3WaURhLvd0lKSgtVuOsJ2krg4SgMw3PIRQFMp07yi++UR3se2mkcLqsBNpBb/A== - dependencies: - array.prototype.reduce "^1.0.6" - call-bind "^1.0.7" - define-properties "^1.2.1" - es-abstract "^1.23.2" - es-object-atoms "^1.0.0" - gopd "^1.0.1" - safe-array-concat "^1.1.2" - object.pick@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" @@ -9398,7 +8734,7 @@ opencollective-postinstall@^2.0.0: resolved "https://registry.yarnpkg.com/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz#7a0fff978f6dbfa4d006238fbac98ed4198c3259" integrity sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q== -optionator@^0.8.1, optionator@^0.8.3: +optionator@^0.8.3: version "0.8.3" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== @@ -9425,18 +8761,6 @@ os-tmpdir@~1.0.2: resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" integrity sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g== -p-each-series@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-each-series/-/p-each-series-1.0.0.tgz#930f3d12dd1f50e7434457a22cd6f04ac6ad7f71" - integrity sha512-J/e9xiZZQNrt+958FFzJ+auItsBGq+UrQ7nE89AUP7UOTtjHnkISANXLdayhVzh538UnLMCSlf13lFfRIAKQOA== - dependencies: - p-reduce "^1.0.0" - -p-finally@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" - integrity sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow== - p-limit@^2.0.0, p-limit@^2.2.0, p-limit@^2.2.1: version "2.3.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" @@ -9477,16 +8801,16 @@ p-map@^4.0.0: dependencies: aggregate-error "^3.0.0" -p-reduce@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-reduce/-/p-reduce-1.0.0.tgz#18c2b0dd936a4690a529f8231f58a0fdb6a47dfa" - integrity sha512-3Tx1T3oM1xO/Y8Gj0sWyE78EIJZ+t+aEmXUdvQgvGmSMri7aPTHoovbXEreWKkL5j21Er60XAWLTzKbAKYOujQ== - p-try@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== +package-json-from-dist@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz#4f1471a010827a86f94cfd9b0727e36d267de505" + integrity sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw== + pacote@^11.1.13: version "11.3.5" resolved "https://registry.yarnpkg.com/pacote/-/pacote-11.3.5.tgz#73cf1fc3772b533f575e39efa96c50be8c3dc9d2" @@ -9537,11 +8861,6 @@ parse-json@^5.0.0, parse-json@^5.2.0: json-parse-even-better-errors "^2.3.0" lines-and-columns "^1.1.6" -parse5@4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/parse5/-/parse5-4.0.0.tgz#6d78656e3da8d78b4ec0b906f7c08ef1dfe3f608" - integrity sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA== - parse5@6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b" @@ -9602,7 +8921,7 @@ path-is-absolute@^1.0.0: resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== -path-key@^2.0.0, path-key@^2.0.1: +path-key@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" integrity sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw== @@ -9617,6 +8936,14 @@ path-parse@^1.0.7: resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== +path-scurry@^1.11.1: + version "1.11.1" + resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.11.1.tgz#7960a668888594a0720b12a911d1a742ab9f11d2" + integrity sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA== + dependencies: + lru-cache "^10.2.0" + minipass "^5.0.0 || ^6.0.2 || ^7.0.0" + path-to-regexp@0.1.7: version "0.1.7" resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" @@ -9634,6 +8961,11 @@ path-type@^4.0.0: resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== +pend@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" + integrity sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg== + performance-now@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" @@ -9785,18 +9117,11 @@ pinomin@^1.0.4: resolved "https://registry.yarnpkg.com/pinomin/-/pinomin-1.0.4.tgz#fcbc5e50745f1769a6b4d9a5a49475927e3ce556" integrity sha512-UJFXLxbgP9t9PDIWiKeVp3/+kudjeq/7IqWUFXqmNFD7810bh3+/3H8jvf+CCvEDkKVY8ckbCNIDWHWymurqHw== -pirates@^4.0.1, pirates@^4.0.4: +pirates@^4.0.4: version "4.0.6" resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.6.tgz#3018ae32ecfcff6c29ba2267cbf21166ac1f36b9" integrity sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg== -pkg-dir@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-3.0.0.tgz#2749020f239ed990881b1f71210d51eb6523bea3" - integrity sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw== - dependencies: - find-up "^3.0.0" - pkg-dir@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" @@ -9804,11 +9129,6 @@ pkg-dir@^4.2.0: dependencies: find-up "^4.0.0" -pn@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/pn/-/pn-1.1.0.tgz#e2f4cef0e219f463c179ab37463e4e1ecdccbafb" - integrity sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA== - portfinder@^1.0.28: version "1.0.32" resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.32.tgz#2fe1b9e58389712429dc2bea5beb2146146c7f81" @@ -9883,16 +9203,6 @@ prettier@^2.2.1: resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da" integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q== -pretty-format@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-24.9.0.tgz#12fac31b37019a4eea3c11aa9a959eb7628aa7c9" - integrity sha512-00ZMZUiHaJrNfk33guavqgvfJS30sLYf0f8+Srklv0AMPodGGHcoHgksZ3OThYnIvOd+8yMCn0YiEOogjlgsnA== - dependencies: - "@jest/types" "^24.9.0" - ansi-regex "^4.0.0" - ansi-styles "^3.2.0" - react-is "^16.8.4" - pretty-format@^25.2.1, pretty-format@^25.5.0: version "25.5.0" resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-25.5.0.tgz#7873c1d774f682c34b8d48b6743a2bf2ac55791a" @@ -9927,6 +9237,11 @@ printj@~1.1.0: resolved "https://registry.yarnpkg.com/printj/-/printj-1.1.2.tgz#d90deb2975a8b9f600fb3a1c94e3f4c53c78a222" integrity sha512-zA2SmoLaxZyArQTOPj5LXecR+RagfPSU5Kw1qP+jkWeNlrq+eJZyY2oS68SU1Z/7/myXM4lo9716laOFAVStCQ== +priorityqueuejs@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/priorityqueuejs/-/priorityqueuejs-2.0.0.tgz#96064040edd847ee9dd3013d8e16297399a6bd4f" + integrity sha512-19BMarhgpq3x4ccvVi8k2QpJZcymo/iFUcrhPd4V96kYGovOdTsWwy7fxChYi4QY+m2EnGBWSX9Buakz+tWNQQ== + process-nextick-args@~1.0.6: version "1.0.7" resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" @@ -10068,7 +9383,7 @@ rc@^1.2.7: minimist "^1.2.0" strip-json-comments "~2.0.1" -react-is@^16.12.0, react-is@^16.8.4: +react-is@^16.12.0: version "16.13.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== @@ -10091,14 +9406,6 @@ read-package-json-fast@^2.0.1: json-parse-even-better-errors "^2.3.0" npm-normalize-package-bin "^1.0.1" -read-pkg-up@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-4.0.0.tgz#1b221c6088ba7799601c808f91161c66e58f8978" - integrity sha512-6etQSH7nJGsK0RbG/2TeDzZFa8shjQ1um+SwQQ5cwKy0dhSXdOncEhb1CPpvQG4h7FyOV6EB6YlV0yJvZQNAkA== - dependencies: - find-up "^3.0.0" - read-pkg "^3.0.0" - read-pkg-up@^7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-7.0.1.tgz#f3a6135758459733ae2b95638056e1854e7ef507" @@ -10108,15 +9415,6 @@ read-pkg-up@^7.0.1: read-pkg "^5.2.0" type-fest "^0.8.1" -read-pkg@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-3.0.0.tgz#9cbc686978fee65d16c00e2b19c237fcf6e38389" - integrity sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA== - dependencies: - load-json-file "^4.0.0" - normalize-package-data "^2.3.2" - path-type "^3.0.0" - read-pkg@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-4.0.1.tgz#963625378f3e1c4d48c85872b5a6ec7d5d093237" @@ -10136,7 +9434,7 @@ read-pkg@^5.2.0: parse-json "^5.0.0" type-fest "^0.6.0" -readable-stream@^2.0.6, readable-stream@~2.3.6: +readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@~2.3.6: version "2.3.8" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b" integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== @@ -10201,6 +9499,13 @@ readable-stream@~2.0.0: string_decoder "~0.10.x" util-deprecate "~1.0.1" +readdir-glob@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/readdir-glob/-/readdir-glob-1.1.3.tgz#c3d831f51f5e7bfa62fa2ffbe4b508c640f09584" + integrity sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA== + dependencies: + minimatch "^5.1.0" + readdirp@~3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" @@ -10208,13 +9513,6 @@ readdirp@~3.6.0: dependencies: picomatch "^2.2.1" -realpath-native@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/realpath-native/-/realpath-native-1.1.0.tgz#2003294fea23fb0672f2476ebe22fcf498a2d65c" - integrity sha512-wlgPA6cCIIg9gKz0fgAPjnzh4yR/LnXovwuo9hvyGvx3h8nX4+/iLZplfUWasXpqD8BdnGnP5njOFjkUwPzvjA== - dependencies: - util.promisify "^1.0.0" - rechoir@^0.8.0: version "0.8.0" resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.8.0.tgz#49f866e0d32146142da3ad8f0eff352b3215ff22" @@ -10275,11 +9573,6 @@ regexpp@^2.0.1: resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f" integrity sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw== -remove-trailing-separator@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" - integrity sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw== - repeat-element@^1.1.2: version "1.1.4" resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.4.tgz#be681520847ab58c7568ac75fbfad28ed42d39e9" @@ -10290,23 +9583,7 @@ repeat-string@^1.6.1: resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" integrity sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w== -request-promise-core@1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/request-promise-core/-/request-promise-core-1.1.4.tgz#3eedd4223208d419867b78ce815167d10593a22f" - integrity sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw== - dependencies: - lodash "^4.17.19" - -request-promise-native@^1.0.5: - version "1.0.9" - resolved "https://registry.yarnpkg.com/request-promise-native/-/request-promise-native-1.0.9.tgz#e407120526a5efdc9a39b28a5679bf47b9d9dc28" - integrity sha512-wcW+sIUiWnKgNY0dqCpOZkUbF/I+YPi+f09JZIDa39Ec+q82CpSYniDp+ISgTTbKmnpJWASeJBPZmoxH84wt3g== - dependencies: - request-promise-core "1.1.4" - stealthy-require "^1.1.1" - tough-cookie "^2.3.3" - -request@^2.87.0, request@^2.88.2: +request@^2.88.2: version "2.88.2" resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw== @@ -10359,13 +9636,6 @@ resize-observer-polyfill@^1.5.1: resolved "https://registry.yarnpkg.com/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz#0e9020dd3d21024458d4ebd27e23e40269810464" integrity sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg== -resolve-cwd@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a" - integrity sha512-ccu8zQTrzVr954472aUVPLEcB3YpKSYR3cg/3lo1okzobPBM+1INXBbBZlDbnI/hbEocnf8j0QVo43hQKrbchg== - dependencies: - resolve-from "^3.0.0" - resolve-cwd@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" @@ -10373,11 +9643,6 @@ resolve-cwd@^3.0.0: dependencies: resolve-from "^5.0.0" -resolve-from@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" - integrity sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw== - resolve-from@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" @@ -10403,11 +9668,6 @@ resolve.exports@^2.0.0: resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-2.0.2.tgz#f8c934b8e6a13f539e38b7098e2e36134f01e800" integrity sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg== -resolve@1.1.7: - version "1.1.7" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" - integrity sha512-9znBF0vBcaSN3W2j7wKvdERPwqTxSpCq+if5C0WoTCyV9n24rua28jeuQ2pL/HOf+yUe/Mef+H/5p60K0Id3bg== - resolve@^1.10.0, resolve@^1.17.0, resolve@^1.19.0, resolve@^1.20.0: version "1.22.8" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" @@ -10447,7 +9707,7 @@ rimraf@2.6.3: dependencies: glob "^7.1.3" -rimraf@^2.5.2, rimraf@^2.5.4, rimraf@^2.6.3: +rimraf@^2.5.2, rimraf@^2.6.3: version "2.7.1" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== @@ -10511,11 +9771,6 @@ rollup@^2.57.0: optionalDependencies: fsevents "~2.3.2" -rsvp@^4.8.4: - version "4.8.5" - resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.5.tgz#c8f155311d167f68f21e168df71ec5b083113734" - integrity sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA== - run-async@^2.4.0: version "2.4.1" resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" @@ -10542,7 +9797,7 @@ sade@^1.6.0, sade@^1.7.4: dependencies: mri "^1.1.0" -safe-array-concat@^1.0.0, safe-array-concat@^1.1.2: +safe-array-concat@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.1.2.tgz#81d77ee0c4e8b863635227c721278dd524c20edb" integrity sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q== @@ -10598,21 +9853,6 @@ sander@^0.5.0: mkdirp "^0.5.1" rimraf "^2.5.2" -sane@^4.0.3: - version "4.1.0" - resolved "https://registry.yarnpkg.com/sane/-/sane-4.1.0.tgz#ed881fd922733a6c461bc189dc2b6c006f3ffded" - integrity sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA== - dependencies: - "@cnakazawa/watch" "^1.0.3" - anymatch "^2.0.0" - capture-exit "^2.0.0" - exec-sh "^0.3.2" - execa "^1.0.0" - fb-watchman "^2.0.0" - micromatch "^3.1.4" - minimist "^1.1.1" - walker "~1.0.5" - sass@*: version "1.77.0" resolved "https://registry.yarnpkg.com/sass/-/sass-1.77.0.tgz#e736c69aff9fae4a4e6dae60a979eee9c942f321" @@ -10622,11 +9862,6 @@ sass@*: immutable "^4.0.0" source-map-js ">=0.6.2 <2.0.0" -sax@^1.2.4: - version "1.3.0" - resolved "https://registry.yarnpkg.com/sax/-/sax-1.3.0.tgz#a5dbe77db3be05c9d1ee7785dbd3ea9de51593d0" - integrity sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA== - saxes@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/saxes/-/saxes-5.0.1.tgz#eebab953fa3b7608dbe94e5dadb15c888fa6696d" @@ -10653,6 +9888,11 @@ secure-json-parse@^2.4.0: resolved "https://registry.yarnpkg.com/secure-json-parse/-/secure-json-parse-2.7.0.tgz#5a5f9cd6ae47df23dba3151edd06855d47e09862" integrity sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw== +semaphore@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/semaphore/-/semaphore-1.1.0.tgz#aaad8b86b20fe8e9b32b16dc2ee682a8cd26a8aa" + integrity sha512-O4OZEaNtkMd/K0i6js9SL+gqy0ZCBMgUvlSqHKi4IBdjhe7wB8pwztUk1BbZ1fmrvpwFrPbHzqd2w5pTcJH6LA== + semiver@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/semiver/-/semiver-1.1.0.tgz#9c97fb02c21c7ce4fcf1b73e2c7a24324bdddd5f" @@ -10663,16 +9903,16 @@ semiver@^1.0.0: resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== -semver@6.x, semver@^6.0.0, semver@^6.1.2, semver@^6.2.0, semver@^6.3.0, semver@^6.3.1: - version "6.3.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" - integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== - semver@7.x, semver@^7.1.1, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.5.3, semver@^7.5.4: version "7.6.1" resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.1.tgz#60bfe090bf907a25aa8119a72b9f90ef7ca281b2" integrity sha512-f/vbBsu+fOiYt+lmwZV0rVwJScl46HppnOA1ZvIuBWKOTlllpyJ3bfVax76/OrhCH38dyxoDIA8K7uB963IYgA== +semver@^6.1.2, semver@^6.3.0, semver@^6.3.1: + version "6.3.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== + semver@^7.6.3: version "7.6.3" resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" @@ -10804,11 +10044,6 @@ shebang-regex@^3.0.0: resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== -shellwords@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b" - integrity sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww== - side-channel@^1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.6.tgz#abd25fb7cd24baf45466406b1096b7831c9215f2" @@ -10824,6 +10059,11 @@ signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== +signal-exit@^4.0.1: + version "4.1.0" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" + integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== + simple-concat@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.1.tgz#f46976082ba35c2263f1c8ab5edfe26c41c9552f" @@ -11159,13 +10399,6 @@ ssri@^8.0.0, ssri@^8.0.1: dependencies: minipass "^3.1.1" -stack-utils@^1.0.1: - version "1.0.5" - resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-1.0.5.tgz#a19b0b01947e0029c8e451d5d61a498f5bb1471b" - integrity sha512-KZiTzuV3CnSnSvgMRrARVCj+Ht7rMbauGDK0LdVFRGyenwdylpajAp4Q0i6SX8rEmbTpMMf6ryq2gb8pPq2WgQ== - dependencies: - escape-string-regexp "^2.0.0" - stack-utils@^2.0.3: version "2.0.6" resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.6.tgz#aaf0748169c02fc33c8232abccf933f54a1cc34f" @@ -11191,11 +10424,6 @@ statuses@2.0.1: resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== -stealthy-require@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b" - integrity sha512-ZnWpYnYugiOVEY5GkcuJK1io5V8QmNYChG62gSit9pQVGErXtrKuPC55ITaVSukmMta5qpMU7vqLt2Lnni4f/g== - stoppable@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/stoppable/-/stoppable-1.1.0.tgz#32da568e83ea488b08e4d7ea2c3bcc9d75015d5b" @@ -11223,13 +10451,15 @@ streamsearch@^1.1.0: resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-1.1.0.tgz#404dd1e2247ca94af554e841a8ef0eaa238da764" integrity sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg== -string-length@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/string-length/-/string-length-2.0.0.tgz#d40dbb686a3ace960c1cffca562bf2c45f8363ed" - integrity sha512-Qka42GGrS8Mm3SZ+7cH8UXiIWI867/b/Z/feQSpQx/rbfB8UGknGEZVaUQMOUVj+soY6NpWAxily63HI1OckVQ== +streamx@^2.15.0: + version "2.22.0" + resolved "https://registry.yarnpkg.com/streamx/-/streamx-2.22.0.tgz#cd7b5e57c95aaef0ff9b2aef7905afa62ec6e4a7" + integrity sha512-sLh1evHOzBy/iWRiR6d1zRcLao4gGZr3C1kzNz4fopCOKJb6xD9ub8Mpi9Mr1R6id5o43S+d93fI48UC5uM9aw== dependencies: - astral-regex "^1.0.0" - strip-ansi "^4.0.0" + fast-fifo "^1.3.2" + text-decoder "^1.1.0" + optionalDependencies: + bare-events "^2.2.0" string-length@^4.0.1: version "4.0.2" @@ -11239,6 +10469,15 @@ string-length@^4.0.1: char-regex "^1.0.2" strip-ansi "^6.0.0" +"string-width-cjs@npm:string-width@^4.2.0", "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + string-width@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" @@ -11248,15 +10487,6 @@ string-width@^1.0.1: is-fullwidth-code-point "^1.0.0" strip-ansi "^3.0.0" -"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: - version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - string-width@^3.0.0, string-width@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" @@ -11266,6 +10496,15 @@ string-width@^3.0.0, string-width@^3.1.0: is-fullwidth-code-point "^2.0.0" strip-ansi "^5.1.0" +string-width@^5.0.1, string-width@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" + integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== + dependencies: + eastasianwidth "^0.2.0" + emoji-regex "^9.2.2" + strip-ansi "^7.0.1" + string.prototype.trim@^1.2.9: version "1.2.9" resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz#b6fa326d72d2c78b6df02f7759c73f8f6274faa4" @@ -11313,6 +10552,13 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" +"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + strip-ansi@^3.0.0, strip-ansi@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" @@ -11320,13 +10566,6 @@ strip-ansi@^3.0.0, strip-ansi@^3.0.1: dependencies: ansi-regex "^2.0.0" -strip-ansi@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" - integrity sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow== - dependencies: - ansi-regex "^3.0.0" - strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" @@ -11334,28 +10573,18 @@ strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: dependencies: ansi-regex "^4.1.0" -strip-ansi@^6.0.0, strip-ansi@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== +strip-ansi@^7.0.1: + version "7.1.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" + integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ== dependencies: - ansi-regex "^5.0.1" - -strip-bom@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" - integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA== + ansi-regex "^6.0.1" strip-bom@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878" integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w== -strip-eof@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" - integrity sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q== - strip-final-newline@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" @@ -11469,7 +10698,7 @@ svelte@^3.46.4: resolved "https://registry.yarnpkg.com/svelte/-/svelte-3.59.2.tgz#a137b28e025a181292b2ae2e3dca90bf8ec73aec" integrity sha512-vzSyuGr3eEoAtT/A6bmajosJZIUWySzY2CzB3w2pgPvnkUjGqlDnsNnA0PMO+mMAhuyMul6C2uuZzY6ELSkzyA== -symbol-tree@^3.2.2, symbol-tree@^3.2.4: +symbol-tree@^3.2.4: version "3.2.4" resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== @@ -11518,6 +10747,15 @@ tar-stream@^2.1.4: inherits "^2.0.3" readable-stream "^3.1.1" +tar-stream@^3.0.0: + version "3.1.7" + resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-3.1.7.tgz#24b3fb5eabada19fe7338ed6d26e5f7c482e792b" + integrity sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ== + dependencies: + b4a "^1.6.4" + fast-fifo "^1.2.0" + streamx "^2.15.0" + tar@^6.0.2, tar@^6.0.5, tar@^6.1.0: version "6.2.1" resolved "https://registry.yarnpkg.com/tar/-/tar-6.2.1.tgz#717549c541bc3c2af15751bea94b1dd068d4b03a" @@ -11581,16 +10819,6 @@ terser@^5.0.0, terser@^5.26.0: commander "^2.20.0" source-map-support "~0.5.20" -test-exclude@^5.2.3: - version "5.2.3" - resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-5.2.3.tgz#c3d3e1e311eb7ee405e092dac10aefd09091eac0" - integrity sha512-M+oxtseCFO3EDtAaGH7iiej3CBkzXqFMbzqYAACdzKui4eZA+pq3tZEwChvOdNfa7xxy8BfbmgJSIr43cC/+2g== - dependencies: - glob "^7.1.3" - minimatch "^3.0.4" - read-pkg-up "^4.0.0" - require-main-filename "^2.0.0" - test-exclude@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" @@ -11600,16 +10828,18 @@ test-exclude@^6.0.0: glob "^7.1.4" minimatch "^3.0.4" +text-decoder@^1.1.0: + version "1.2.3" + resolved "https://registry.yarnpkg.com/text-decoder/-/text-decoder-1.2.3.tgz#b19da364d981b2326d5f43099c310cc80d770c65" + integrity sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA== + dependencies: + b4a "^1.6.4" + text-table@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== -throat@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/throat/-/throat-4.1.0.tgz#89037cbc92c56ab18926e6ba4cbb200e15672a6a" - integrity sha512-wCVxLDcFxw7ujDxaeJC6nfl2XfHJNYs8yUYJnvMgtPEFlttP9tHSfRUv2vBe6C4hkVFPWoP1P6ZccbYjmSEkKA== - throat@^6.0.1: version "6.0.2" resolved "https://registry.yarnpkg.com/throat/-/throat-6.0.2.tgz#51a3fbb5e11ae72e2cf74861ed5c8020f89f29fe" @@ -11725,14 +10955,6 @@ touch@^3.1.0: dependencies: nopt "~1.0.10" -tough-cookie@^2.3.3, tough-cookie@^2.3.4, tough-cookie@~2.5.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" - integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g== - dependencies: - psl "^1.1.28" - punycode "^2.1.1" - tough-cookie@^4.0.0: version "4.1.4" resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.1.4.tgz#945f1461b45b5a8c76821c33ea49c3ac192c1b36" @@ -11743,12 +10965,13 @@ tough-cookie@^4.0.0: universalify "^0.2.0" url-parse "^1.5.3" -tr46@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/tr46/-/tr46-1.0.1.tgz#a8b13fd6bfd2489519674ccde55ba3693b706d09" - integrity sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA== +tough-cookie@~2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" + integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g== dependencies: - punycode "^2.1.0" + psl "^1.1.28" + punycode "^2.1.1" tr46@^2.1.0: version "2.1.0" @@ -11774,22 +10997,6 @@ trim-newlines@^3.0.0: resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-3.0.1.tgz#260a5d962d8b752425b32f3a7db0dcacd176c144" integrity sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw== -ts-jest@^25.2.1: - version "25.5.1" - resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-25.5.1.tgz#2913afd08f28385d54f2f4e828be4d261f4337c7" - integrity sha512-kHEUlZMK8fn8vkxDjwbHlxXRB9dHYpyzqKIGDNxbzs+Rz+ssNDSDNusEK8Fk/sDd4xE6iKoQLfFkFVaskmTJyw== - dependencies: - bs-logger "0.x" - buffer-from "1.x" - fast-json-stable-stringify "2.x" - json5 "2.x" - lodash.memoize "4.x" - make-error "1.x" - micromatch "4.x" - mkdirp "0.x" - semver "6.x" - yargs-parser "18.x" - ts-jest@^28.0.7: version "28.0.8" resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-28.0.8.tgz#cd204b8e7a2f78da32cf6c95c9a6165c5b99cc73" @@ -12082,19 +11289,6 @@ util-deprecate@^1.0.1, util-deprecate@~1.0.1: resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== -util.promisify@^1.0.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.1.2.tgz#02b3dbadbb80071eee4c43aed58747afdfc516db" - integrity sha512-PBdZ03m1kBnQ5cjjO0ZvJMJS+QsbyIcFwi4hY4U76OQsCO9JrOYjbCFgIF76ccFg9xnJo7ZHPkqyj1GqmdS7MA== - dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - for-each "^0.3.3" - has-proto "^1.0.1" - has-symbols "^1.0.3" - object.getownpropertydescriptors "^2.1.6" - safe-array-concat "^1.0.0" - utils-merge@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" @@ -12183,7 +11377,7 @@ verror@^1.8.1: core-util-is "1.0.2" extsprintf "^1.2.0" -w3c-hr-time@^1.0.1, w3c-hr-time@^1.0.2: +w3c-hr-time@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd" integrity sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ== @@ -12207,7 +11401,7 @@ walk-back@^5.1.1: resolved "https://registry.yarnpkg.com/walk-back/-/walk-back-5.1.1.tgz#80045191b3b3a05a8e3cc6fca066a2e495230d93" integrity sha512-e/FRLDVdZQWFrAzU6Hdvpm7D7m2ina833gIKLptQykRK49mmCYHLHq7UqjPDbxbKLZkTkW1rFqbengdE3sLfdw== -walker@^1.0.7, walker@^1.0.8, walker@~1.0.5: +walker@^1.0.7, walker@^1.0.8: version "1.0.8" resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.8.tgz#bd498db477afe573dc04185f011d3ab8a8d7653f" integrity sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ== @@ -12222,11 +11416,6 @@ watchpack@^2.4.1: glob-to-regexp "^0.4.1" graceful-fs "^4.1.2" -webidl-conversions@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad" - integrity sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg== - webidl-conversions@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-5.0.0.tgz#ae59c8a00b121543a2acc65c0434f57b0fc11aff" @@ -12313,14 +11502,14 @@ wellknown@^0.5.0: concat-stream "~1.5.0" minimist "~1.2.0" -whatwg-encoding@^1.0.1, whatwg-encoding@^1.0.3, whatwg-encoding@^1.0.5: +whatwg-encoding@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz#5abacf777c32166a51d085d6b4f3e7d27113ddb0" integrity sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw== dependencies: iconv-lite "0.4.24" -whatwg-mimetype@^2.1.0, whatwg-mimetype@^2.2.0, whatwg-mimetype@^2.3.0: +whatwg-mimetype@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf" integrity sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g== @@ -12333,24 +11522,6 @@ whatwg-url@^13.0.0: tr46 "^4.1.1" webidl-conversions "^7.0.0" -whatwg-url@^6.4.1: - version "6.5.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-6.5.0.tgz#f2df02bff176fd65070df74ad5ccbb5a199965a8" - integrity sha512-rhRZRqx/TLJQWUpQ6bmrt2UV4f0HCQ463yQuONJqC6fO2VoEb1pTYddbe59SkYq87aoM5A3bdhMZiUiVws+fzQ== - dependencies: - lodash.sortby "^4.7.0" - tr46 "^1.0.1" - webidl-conversions "^4.0.2" - -whatwg-url@^7.0.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-7.1.0.tgz#c2c492f1eca612988efd3d2266be1b9fc6170d06" - integrity sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg== - dependencies: - lodash.sortby "^4.7.0" - tr46 "^1.0.1" - webidl-conversions "^4.0.2" - whatwg-url@^8.0.0, whatwg-url@^8.5.0: version "8.7.0" resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-8.7.0.tgz#656a78e510ff8f3937bc0bcbe9f5c0ac35941b77" @@ -12387,7 +11558,7 @@ which-typed-array@^1.1.14, which-typed-array@^1.1.15: gopd "^1.0.1" has-tostringtag "^1.0.2" -which@^1.2.9, which@^1.3.0: +which@^1.2.9: version "1.3.1" resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== @@ -12466,6 +11637,15 @@ workspaces-run@^1.0.1: trim-newlines "^3.0.0" wrapline "^2.0.1" +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + wrap-ansi@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09" @@ -12475,14 +11655,14 @@ wrap-ansi@^5.1.0: string-width "^3.0.0" strip-ansi "^5.0.0" -wrap-ansi@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== +wrap-ansi@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" + integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ== dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" + ansi-styles "^6.1.0" + string-width "^5.0.1" + strip-ansi "^7.0.1" wrapline@^2.0.1: version "2.0.1" @@ -12498,15 +11678,6 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== -write-file-atomic@2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-2.4.1.tgz#d0b05463c188ae804396fd5ab2a370062af87529" - integrity sha512-TGHFeZEZMnv+gBFRfjAcxL5bPHrsGKtnb4qsFAws7/vlh+QfwAaySIw4AXP9ZskTTh5GWu3FLuJhsWVdiJPGvg== - dependencies: - graceful-fs "^4.1.11" - imurmurhash "^0.1.4" - signal-exit "^3.0.2" - write-file-atomic@^3.0.0: version "3.0.3" resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-3.0.3.tgz#56bd5c5a5c70481cd19c571bd39ab965a5de56e8" @@ -12532,13 +11703,6 @@ write@1.0.3: dependencies: mkdirp "^0.5.1" -ws@^5.2.0: - version "5.2.3" - resolved "https://registry.yarnpkg.com/ws/-/ws-5.2.3.tgz#05541053414921bc29c63bee14b8b0dd50b07b3d" - integrity sha512-jZArVERrMsKUatIdnLzqvcfydI85dvd/Fp1u/VOpfdDWQ4c9qWXe+VIeAbQ5FrDwciAkr+lzofXLz3Kuf26AOA== - dependencies: - async-limiter "~1.0.0" - ws@^7.4.3, ws@^7.4.6: version "7.5.9" resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.9.tgz#54fa7db29f4c7cec68b1ddd3a89de099942bb591" @@ -12629,14 +11793,6 @@ yaml@^1.10.2: resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== -yargs-parser@18.x, yargs-parser@^18.1.3: - version "18.1.3" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0" - integrity sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ== - dependencies: - camelcase "^5.0.0" - decamelize "^1.2.0" - yargs-parser@^13.1.2: version "13.1.2" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.2.tgz#130f09702ebaeef2650d54ce6e3e5706f7a4fb38" @@ -12645,6 +11801,14 @@ yargs-parser@^13.1.2: camelcase "^5.0.0" decamelize "^1.2.0" +yargs-parser@^18.1.3: + version "18.1.3" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0" + integrity sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ== + dependencies: + camelcase "^5.0.0" + decamelize "^1.2.0" + yargs-parser@^20.2.2: version "20.2.9" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" @@ -12697,7 +11861,24 @@ yargs@^17.3.1: y18n "^5.0.5" yargs-parser "^21.1.1" +yauzl@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-3.2.0.tgz#7b6cb548f09a48a6177ea0be8ece48deb7da45c0" + integrity sha512-Ow9nuGZE+qp1u4JIPvg+uCiUr7xGQWdff7JQSk5VGYTAZMDe2q8lxJ10ygv10qmSj031Ty/6FNJpLO4o1Sgc+w== + dependencies: + buffer-crc32 "~0.2.3" + pend "~1.2.0" + yocto-queue@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== + +zip-stream@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/zip-stream/-/zip-stream-6.0.1.tgz#e141b930ed60ccaf5d7fa9c8260e0d1748a2bbfb" + integrity sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA== + dependencies: + archiver-utils "^5.0.0" + compress-commons "^6.0.2" + readable-stream "^4.0.0"
+ checkedKeys.includes(extractTableItemKey(r)))} + on:change={e => { + if (e.target['checked']) onSetCheckedKeys(checkableFlatRowsShown.map(r => extractTableItemKey(r))); + else onSetCheckedKeys([]); + }} + /> + {#if checkedKeys} - @@ -147,58 +246,91 @@ {/if}
- { - if (e.target['checked']) onSetCheckedKeys(_.uniq([...checkedKeys, extractCheckedKey(row)])); - else onSetCheckedKeys(checkedKeys.filter(x => x != extractCheckedKey(row))); - }} - /> + {#each sortedRows as gitem, groupIndex} + {#if gitem.group} +
{ + if (collapsedGroupIndexes.includes(groupIndex)) { + collapsedGroupIndexes = collapsedGroupIndexes.filter(x => x != groupIndex); + } else { + collapsedGroupIndexes = [...collapsedGroupIndexes, groupIndex]; + } + }} + > + + {gitem.group} ({gitem.rows.length}) - {#if col.component} - - {:else if col.formatter} - {col.formatter(row)} - {:else if col.slot != null} - {#if col.slot == -1} - {:else if col.slot == 0} - {:else if col.slot == 1} - {:else if col.slot == 2} - {:else if col.slot == 3} - {:else if col.slot == 4} - {:else if col.slot == 5} - {:else if col.slot == 6} - {:else if col.slot == 7} - {:else if col.slot == 8} - {:else if col.slot == 9} - {/if} - {:else} - {row[col.fieldName] || ''} +
+ {#if itemSupportsCheckbox(row)} + { + if (e.target['checked']) onSetCheckedKeys(_.uniq([...checkedKeys, extractTableItemKey(row)])); + else onSetCheckedKeys(checkedKeys.filter(x => x != extractTableItemKey(row))); + }} + /> + {/if} + + {#if col.component} + + {:else if col.formatter} + {col.formatter(row)} + {:else if col.slot != null} + {#key row[col.slotKey] || 'key'} + {#if col.slot == -1} + {:else if col.slot == 0} + {:else if col.slot == 1} + {:else if col.slot == 2} + {:else if col.slot == 3} + {:else if col.slot == 4} + {:else if col.slot == 5} + {:else if col.slot == 6} + {:else if col.slot == 7} + {:else if col.slot == 8} + {:else if col.slot == 9} + {/if} + {/key} + {:else} + {row[col.fieldName] || ''} + {/if} +