mirror of
				https://github.com/gristlabs/grist-core.git
				synced 2025-06-13 20:53:59 +00:00 
			
		
		
		
	* Shutdown Doc worker when it is not considered as available in Redis * Use isAffirmative for GRIST_MANAGED_WORKERS * Upgrade Sinon for the tests * Run Smoke test with pages in English * Add logic in /status endpoint
This commit is contained in:
		
							parent
							
								
									dd83b7f678
								
							
						
					
					
						commit
						4a9b6fea9d
					
				| @ -24,6 +24,9 @@ const CHECKSUM_TTL_MSEC = 24 * 60 * 60 * 1000;  // 24 hours | |||||||
| // How long do permits stored in redis last, in milliseconds.
 | // How long do permits stored in redis last, in milliseconds.
 | ||||||
| const PERMIT_TTL_MSEC = 1 * 60 * 1000;  // 1 minute
 | const PERMIT_TTL_MSEC = 1 * 60 * 1000;  // 1 minute
 | ||||||
| 
 | 
 | ||||||
|  | // Default doc worker group.
 | ||||||
|  | const DEFAULT_GROUP = 'default'; | ||||||
|  | 
 | ||||||
| class DummyDocWorkerMap implements IDocWorkerMap { | class DummyDocWorkerMap implements IDocWorkerMap { | ||||||
|   private _worker?: DocWorkerInfo; |   private _worker?: DocWorkerInfo; | ||||||
|   private _available: boolean = false; |   private _available: boolean = false; | ||||||
| @ -62,6 +65,10 @@ class DummyDocWorkerMap implements IDocWorkerMap { | |||||||
|     this._available = available; |     this._available = available; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   public async isWorkerRegistered(workerInfo: DocWorkerInfo): Promise<boolean> { | ||||||
|  |     return Promise.resolve(true); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   public async releaseAssignment(workerId: string, docId: string): Promise<void> { |   public async releaseAssignment(workerId: string, docId: string): Promise<void> { | ||||||
|     // nothing to do
 |     // nothing to do
 | ||||||
|   } |   } | ||||||
| @ -241,7 +248,7 @@ export class DocWorkerMap implements IDocWorkerMap { | |||||||
|     try { |     try { | ||||||
|       // Drop out of available set first.
 |       // Drop out of available set first.
 | ||||||
|       await this._client.sremAsync('workers-available', workerId); |       await this._client.sremAsync('workers-available', workerId); | ||||||
|       const group = await this._client.getAsync(`worker-${workerId}-group`) || 'default'; |       const group = await this._client.getAsync(`worker-${workerId}-group`) || DEFAULT_GROUP; | ||||||
|       await this._client.sremAsync(`workers-available-${group}`, workerId); |       await this._client.sremAsync(`workers-available-${group}`, workerId); | ||||||
|       // At this point, this worker should no longer be receiving new doc assignments, though
 |       // At this point, this worker should no longer be receiving new doc assignments, though
 | ||||||
|       // clients may still be directed to the worker.
 |       // clients may still be directed to the worker.
 | ||||||
| @ -290,7 +297,7 @@ export class DocWorkerMap implements IDocWorkerMap { | |||||||
| 
 | 
 | ||||||
|   public async setWorkerAvailability(workerId: string, available: boolean): Promise<void> { |   public async setWorkerAvailability(workerId: string, available: boolean): Promise<void> { | ||||||
|     log.info(`DocWorkerMap.setWorkerAvailability ${workerId} ${available}`); |     log.info(`DocWorkerMap.setWorkerAvailability ${workerId} ${available}`); | ||||||
|     const group = await this._client.getAsync(`worker-${workerId}-group`) || 'default'; |     const group = await this._client.getAsync(`worker-${workerId}-group`) || DEFAULT_GROUP; | ||||||
|     if (available) { |     if (available) { | ||||||
|       const docWorker = await this._client.hgetallAsync(`worker-${workerId}`) as DocWorkerInfo|null; |       const docWorker = await this._client.hgetallAsync(`worker-${workerId}`) as DocWorkerInfo|null; | ||||||
|       if (!docWorker) { throw new Error('no doc worker contact info available'); } |       if (!docWorker) { throw new Error('no doc worker contact info available'); } | ||||||
| @ -306,6 +313,11 @@ export class DocWorkerMap implements IDocWorkerMap { | |||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   public async isWorkerRegistered(workerInfo: DocWorkerInfo): Promise<boolean> { | ||||||
|  |     const group = workerInfo.group || DEFAULT_GROUP; | ||||||
|  |     return Boolean(await this._client.sismemberAsync(`workers-available-${group}`, workerInfo.id)); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   public async releaseAssignment(workerId: string, docId: string): Promise<void> { |   public async releaseAssignment(workerId: string, docId: string): Promise<void> { | ||||||
|     const op = this._client.multi(); |     const op = this._client.multi(); | ||||||
|     op.del(`doc-${docId}`); |     op.del(`doc-${docId}`); | ||||||
| @ -352,7 +364,7 @@ export class DocWorkerMap implements IDocWorkerMap { | |||||||
|     if (docId === 'import') { |     if (docId === 'import') { | ||||||
|       const lock = await this._redlock.lock(`workers-lock`, LOCK_TIMEOUT); |       const lock = await this._redlock.lock(`workers-lock`, LOCK_TIMEOUT); | ||||||
|       try { |       try { | ||||||
|         const _workerId = await this._client.srandmemberAsync(`workers-available-default`); |         const _workerId = await this._client.srandmemberAsync(`workers-available-${DEFAULT_GROUP}`); | ||||||
|         if (!_workerId) { throw new Error('no doc worker available'); } |         if (!_workerId) { throw new Error('no doc worker available'); } | ||||||
|         const docWorker = await this._client.hgetallAsync(`worker-${_workerId}`) as DocWorkerInfo|null; |         const docWorker = await this._client.hgetallAsync(`worker-${_workerId}`) as DocWorkerInfo|null; | ||||||
|         if (!docWorker) { throw new Error('no doc worker contact info available'); } |         if (!docWorker) { throw new Error('no doc worker contact info available'); } | ||||||
| @ -383,7 +395,7 @@ export class DocWorkerMap implements IDocWorkerMap { | |||||||
| 
 | 
 | ||||||
|       if (!workerId) { |       if (!workerId) { | ||||||
|         // Check if document has a preferred worker group set.
 |         // Check if document has a preferred worker group set.
 | ||||||
|         const group = await this._client.getAsync(`doc-${docId}-group`) || 'default'; |         const group = await this._client.getAsync(`doc-${docId}-group`) || DEFAULT_GROUP; | ||||||
| 
 | 
 | ||||||
|         // Let's start off by assigning documents to available workers randomly.
 |         // Let's start off by assigning documents to available workers randomly.
 | ||||||
|         // TODO: use a smarter algorithm.
 |         // TODO: use a smarter algorithm.
 | ||||||
|  | |||||||
| @ -6,7 +6,7 @@ | |||||||
| import { IChecksumStore } from 'app/server/lib/IChecksumStore'; | import { IChecksumStore } from 'app/server/lib/IChecksumStore'; | ||||||
| import { IElectionStore } from 'app/server/lib/IElectionStore'; | import { IElectionStore } from 'app/server/lib/IElectionStore'; | ||||||
| import { IPermitStores } from 'app/server/lib/Permit'; | import { IPermitStores } from 'app/server/lib/Permit'; | ||||||
| import {RedisClient} from 'redis'; | import { RedisClient } from 'redis'; | ||||||
| 
 | 
 | ||||||
| export interface DocWorkerInfo { | export interface DocWorkerInfo { | ||||||
|   id: string; |   id: string; | ||||||
| @ -57,6 +57,8 @@ export interface IDocWorkerMap extends IPermitStores, IElectionStore, IChecksumS | |||||||
|   // release existing assignments.
 |   // release existing assignments.
 | ||||||
|   setWorkerAvailability(workerId: string, available: boolean): Promise<void>; |   setWorkerAvailability(workerId: string, available: boolean): Promise<void>; | ||||||
| 
 | 
 | ||||||
|  |   isWorkerRegistered(workerInfo: DocWorkerInfo): Promise<boolean>; | ||||||
|  | 
 | ||||||
|   // Releases doc from worker, freeing it to be assigned elsewhere.
 |   // Releases doc from worker, freeing it to be assigned elsewhere.
 | ||||||
|   // Assignments should only be released for workers that are now unavailable.
 |   // Assignments should only be released for workers that are now unavailable.
 | ||||||
|   releaseAssignment(workerId: string, docId: string): Promise<void>; |   releaseAssignment(workerId: string, docId: string): Promise<void>; | ||||||
|  | |||||||
| @ -445,7 +445,8 @@ export class FlexServer implements GristServer { | |||||||
|     // /status/hooks allows the tests to wait for them to be ready.
 |     // /status/hooks allows the tests to wait for them to be ready.
 | ||||||
|     // If db=1 query parameter is included, status will include the status of DB connection.
 |     // If db=1 query parameter is included, status will include the status of DB connection.
 | ||||||
|     // If redis=1 query parameter is included, status will include the status of the Redis connection.
 |     // If redis=1 query parameter is included, status will include the status of the Redis connection.
 | ||||||
|     // If ready=1 query parameter is included, status will include whether the server is fully ready.
 |     // If docWorkerRegistered=1 query parameter is included, status will include the status of the
 | ||||||
|  |     // doc worker registration in Redis.
 | ||||||
|     this.app.get('/status(/hooks)?', async (req, res) => { |     this.app.get('/status(/hooks)?', async (req, res) => { | ||||||
|       const checks = new Map<string, Promise<boolean>|boolean>(); |       const checks = new Map<string, Promise<boolean>|boolean>(); | ||||||
|       const timeout = optIntegerParam(req.query.timeout, 'timeout') || 10_000; |       const timeout = optIntegerParam(req.query.timeout, 'timeout') || 10_000; | ||||||
| @ -467,6 +468,15 @@ export class FlexServer implements GristServer { | |||||||
|       if (isParameterOn(req.query.redis)) { |       if (isParameterOn(req.query.redis)) { | ||||||
|         checks.set('redis', asyncCheck(this._docWorkerMap.getRedisClient()?.pingAsync())); |         checks.set('redis', asyncCheck(this._docWorkerMap.getRedisClient()?.pingAsync())); | ||||||
|       } |       } | ||||||
|  |       if (isParameterOn(req.query.docWorkerRegistered) && this.worker) { | ||||||
|  |         // Only check whether the doc worker is registered if we have a worker.
 | ||||||
|  |         // The Redis client may not be connected, but in this case this has to
 | ||||||
|  |         // be checked with the 'redis' parameter (the user may want to avoid
 | ||||||
|  |         // removing workers when connection is unstable).
 | ||||||
|  |         if (this._docWorkerMap.getRedisClient()?.connected) { | ||||||
|  |           checks.set('docWorkerRegistered', asyncCheck(this._docWorkerMap.isWorkerRegistered(this.worker))); | ||||||
|  |         } | ||||||
|  |       } | ||||||
|       if (isParameterOn(req.query.ready)) { |       if (isParameterOn(req.query.ready)) { | ||||||
|         checks.set('ready', this._isReady); |         checks.set('ready', this._isReady); | ||||||
|       } |       } | ||||||
|  | |||||||
| @ -56,6 +56,7 @@ module.exports = { | |||||||
|     ], |     ], | ||||||
|     fallback: { |     fallback: { | ||||||
|       'path': require.resolve("path-browserify"), |       'path': require.resolve("path-browserify"), | ||||||
|  |       'process': require.resolve("process/browser"), | ||||||
|     }, |     }, | ||||||
|   }, |   }, | ||||||
|   module: { |   module: { | ||||||
| @ -79,7 +80,7 @@ module.exports = { | |||||||
|   plugins: [ |   plugins: [ | ||||||
|     // Some modules assume presence of Buffer and process.
 |     // Some modules assume presence of Buffer and process.
 | ||||||
|     new ProvidePlugin({ |     new ProvidePlugin({ | ||||||
|       process: 'process/browser', |       process: 'process', | ||||||
|       Buffer: ['buffer', 'Buffer'] |       Buffer: ['buffer', 'Buffer'] | ||||||
|     }), |     }), | ||||||
|     // To strip all locales except “en”
 |     // To strip all locales except “en”
 | ||||||
|  | |||||||
| @ -18,7 +18,7 @@ | |||||||
|     "test:client": "GRIST_SESSION_COOKIE=grist_test_cookie mocha ${DEBUG:+'-b'} '_build/test/client/**/*.js'", |     "test:client": "GRIST_SESSION_COOKIE=grist_test_cookie mocha ${DEBUG:+'-b'} '_build/test/client/**/*.js'", | ||||||
|     "test:common": "GRIST_SESSION_COOKIE=grist_test_cookie mocha ${DEBUG:+'-b'} '_build/test/common/**/*.js'", |     "test:common": "GRIST_SESSION_COOKIE=grist_test_cookie mocha ${DEBUG:+'-b'} '_build/test/common/**/*.js'", | ||||||
|     "test:server": "TEST_CLEAN_DATABASE=true TEST_SUITE=server TEST_SUITE_FOR_TIMINGS=server TIMINGS_FILE=test/timings/server.txt GRIST_SESSION_COOKIE=grist_test_cookie mocha ${DEBUG:+'-b'} -g \"${GREP_TESTS}\" -R test/xunit-file '_build/test/server/**/*.js' '_build/test/gen-server/**/*.js'", |     "test:server": "TEST_CLEAN_DATABASE=true TEST_SUITE=server TEST_SUITE_FOR_TIMINGS=server TIMINGS_FILE=test/timings/server.txt GRIST_SESSION_COOKIE=grist_test_cookie mocha ${DEBUG:+'-b'} -g \"${GREP_TESTS}\" -R test/xunit-file '_build/test/server/**/*.js' '_build/test/gen-server/**/*.js'", | ||||||
|     "test:smoke": "mocha _build/test/nbrowser/Smoke.js", |     "test:smoke": "LANGUAGE=en_US mocha _build/test/nbrowser/Smoke.js", | ||||||
|     "test:docker": "./test/test_under_docker.sh", |     "test:docker": "./test/test_under_docker.sh", | ||||||
|     "test:python": "sandbox_venv3/bin/python sandbox/grist/runtests.py ${GREP_TESTS:+discover -p \"test*${GREP_TESTS}*.py\"}", |     "test:python": "sandbox_venv3/bin/python sandbox/grist/runtests.py ${GREP_TESTS:+discover -p \"test*${GREP_TESTS}*.py\"}", | ||||||
|     "cli": "NODE_PATH=_build:_build/stubs:_build/ext node _build/app/server/companion.js", |     "cli": "NODE_PATH=_build:_build/stubs:_build/ext node _build/app/server/companion.js", | ||||||
| @ -76,7 +76,7 @@ | |||||||
|     "@types/redlock": "3.0.2", |     "@types/redlock": "3.0.2", | ||||||
|     "@types/saml2-js": "2.0.1", |     "@types/saml2-js": "2.0.1", | ||||||
|     "@types/selenium-webdriver": "4.1.15", |     "@types/selenium-webdriver": "4.1.15", | ||||||
|     "@types/sinon": "5.0.5", |     "@types/sinon": "17.0.3", | ||||||
|     "@types/sqlite3": "3.1.6", |     "@types/sqlite3": "3.1.6", | ||||||
|     "@types/swagger-ui": "3.52.4", |     "@types/swagger-ui": "3.52.4", | ||||||
|     "@types/tmp": "0.0.33", |     "@types/tmp": "0.0.33", | ||||||
| @ -100,7 +100,7 @@ | |||||||
|     "nodemon": "^2.0.4", |     "nodemon": "^2.0.4", | ||||||
|     "otplib": "12.0.1", |     "otplib": "12.0.1", | ||||||
|     "proper-lockfile": "4.1.2", |     "proper-lockfile": "4.1.2", | ||||||
|     "sinon": "7.1.1", |     "sinon": "17.0.1", | ||||||
|     "source-map-loader": "^0.2.4", |     "source-map-loader": "^0.2.4", | ||||||
|     "tmp-promise": "1.0.5", |     "tmp-promise": "1.0.5", | ||||||
|     "ts-interface-builder": "0.3.2", |     "ts-interface-builder": "0.3.2", | ||||||
|  | |||||||
							
								
								
									
										1
									
								
								stubs/app/server/declarations.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								stubs/app/server/declarations.d.ts
									
									
									
									
										vendored
									
									
								
							| @ -28,6 +28,7 @@ declare module "redis" { | |||||||
|   function createClient(url?: string): RedisClient; |   function createClient(url?: string): RedisClient; | ||||||
| 
 | 
 | ||||||
|   class RedisClient { |   class RedisClient { | ||||||
|  |     public readonly connected: boolean; | ||||||
|     public eval(args: any[], callback?: (err: Error | null, res: any) => void): any; |     public eval(args: any[], callback?: (err: Error | null, res: any) => void): any; | ||||||
| 
 | 
 | ||||||
|     public subscribe(channel: string): void; |     public subscribe(channel: string): void; | ||||||
|  | |||||||
| @ -46,7 +46,7 @@ describe('SafeBrowser', function() { | |||||||
| 
 | 
 | ||||||
|     browserProcesses = []; |     browserProcesses = []; | ||||||
|     sandbox.stub(SafeBrowser, 'createWorker').callsFake(createProcess); |     sandbox.stub(SafeBrowser, 'createWorker').callsFake(createProcess); | ||||||
|     sandbox.stub(SafeBrowser, 'createView').callsFake(createProcess); |     sandbox.stub(SafeBrowser, 'createView').callsFake(createProcess as any); | ||||||
|     sandbox.stub(PluginInstance.prototype, 'getRenderTarget').returns(noop); |     sandbox.stub(PluginInstance.prototype, 'getRenderTarget').returns(noop); | ||||||
|     disposeSpy = sandbox.spy(Disposable.prototype, 'dispose'); |     disposeSpy = sandbox.spy(Disposable.prototype, 'dispose'); | ||||||
|   }); |   }); | ||||||
|  | |||||||
| @ -153,9 +153,8 @@ describe('dispose', function() { | |||||||
|       assert.equal(baz.dispose.callCount, 1); |       assert.equal(baz.dispose.callCount, 1); | ||||||
|       assert(baz.dispose.calledBefore(bar.dispose)); |       assert(baz.dispose.calledBefore(bar.dispose)); | ||||||
| 
 | 
 | ||||||
|       const name = consoleErrors[0][1];  // may be Foo, or minified.
 |       const name = consoleErrors[0][1]; | ||||||
|       assert(name === 'Foo' || name === 'o');  // this may not be reliable,
 |       assert(name === Foo.name); | ||||||
|                                                // just what I happen to see.
 |  | ||||||
|       assert.deepEqual(consoleErrors[0], ['Error constructing %s:', name, 'Error: test-error1']); |       assert.deepEqual(consoleErrors[0], ['Error constructing %s:', name, 'Error: test-error1']); | ||||||
|       assert.deepEqual(consoleErrors[1], ['Error constructing %s:', name, 'Error: test-error2']); |       assert.deepEqual(consoleErrors[1], ['Error constructing %s:', name, 'Error: test-error2']); | ||||||
|       assert.deepEqual(consoleErrors[2], ['Error constructing %s:', name, 'Error: test-error3']); |       assert.deepEqual(consoleErrors[2], ['Error constructing %s:', name, 'Error: test-error3']); | ||||||
|  | |||||||
							
								
								
									
										56
									
								
								test/gen-server/lib/DocWorkerMap.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								test/gen-server/lib/DocWorkerMap.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,56 @@ | |||||||
|  | // Test for DocWorkerMap.ts
 | ||||||
|  | 
 | ||||||
|  | import { DocWorkerMap } from 'app/gen-server/lib/DocWorkerMap'; | ||||||
|  | import { DocWorkerInfo } from 'app/server/lib/DocWorkerMap'; | ||||||
|  | import {expect} from 'chai'; | ||||||
|  | import sinon from 'sinon'; | ||||||
|  | 
 | ||||||
|  | describe('DocWorkerMap', () => { | ||||||
|  |   const sandbox = sinon.createSandbox(); | ||||||
|  |   afterEach(() => { | ||||||
|  |     sandbox.restore(); | ||||||
|  |   }); | ||||||
|  | 
 | ||||||
|  |   describe('isWorkerRegistered', () => { | ||||||
|  |     const baseWorkerInfo: DocWorkerInfo = { | ||||||
|  |       id: 'workerId', | ||||||
|  |       internalUrl: 'internalUrl', | ||||||
|  |       publicUrl: 'publicUrl', | ||||||
|  |       group: undefined | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     [ | ||||||
|  |       { | ||||||
|  |         itMsg: 'should check if worker is registered', | ||||||
|  |         sisMemberAsyncResolves: 1, | ||||||
|  |         expectedResult: true, | ||||||
|  |         expectedKey: 'workers-available-default' | ||||||
|  |       }, | ||||||
|  |       { | ||||||
|  |         itMsg: 'should check if worker is registered in a certain group', | ||||||
|  |         sisMemberAsyncResolves: 1, | ||||||
|  |         group: 'dummygroup', | ||||||
|  |         expectedResult: true, | ||||||
|  |         expectedKey: 'workers-available-dummygroup' | ||||||
|  |       }, | ||||||
|  |       { | ||||||
|  |         itMsg: 'should return false if worker is not registered', | ||||||
|  |         sisMemberAsyncResolves: 0, | ||||||
|  |         expectedResult: false, | ||||||
|  |         expectedKey: 'workers-available-default' | ||||||
|  |       } | ||||||
|  |     ].forEach(ctx => { | ||||||
|  |       it(ctx.itMsg, async () => { | ||||||
|  |         const sismemberAsyncStub = sinon.stub().resolves(ctx.sisMemberAsyncResolves); | ||||||
|  |         const stubDocWorkerMap = { | ||||||
|  |           _client: { sismemberAsync: sismemberAsyncStub } | ||||||
|  |         }; | ||||||
|  |         const result = await DocWorkerMap.prototype.isWorkerRegistered.call( | ||||||
|  |           stubDocWorkerMap, {...baseWorkerInfo, group: ctx.group } | ||||||
|  |         ); | ||||||
|  |         expect(result).to.equal(ctx.expectedResult); | ||||||
|  |         expect(sismemberAsyncStub.calledOnceWith(ctx.expectedKey, baseWorkerInfo.id)).to.equal(true); | ||||||
|  |       }); | ||||||
|  |     }); | ||||||
|  |   }); | ||||||
|  | }); | ||||||
| @ -402,20 +402,19 @@ describe('Comm', function() { | |||||||
| 
 | 
 | ||||||
|       // Intercept the call to _onClose to know when it occurs, since we are trying to hit a
 |       // Intercept the call to _onClose to know when it occurs, since we are trying to hit a
 | ||||||
|       // situation where 'close' and 'failedSend' events happen in either order.
 |       // situation where 'close' and 'failedSend' events happen in either order.
 | ||||||
|       const stubOnClose = sandbox.stub(Client.prototype as any, '_onClose') |       const stubOnClose: any = sandbox.stub(Client.prototype as any, '_onClose') | ||||||
|         .callsFake(async function(this: Client) { |         .callsFake(function(this: Client) { | ||||||
|           if (!options.closeHappensFirst) { await delay(10); } |  | ||||||
|           eventsSeen.push('close'); |           eventsSeen.push('close'); | ||||||
|           return (stubOnClose as any).wrappedMethod.apply(this, arguments); |           return stubOnClose.wrappedMethod.apply(this, arguments); | ||||||
|         }); |         }); | ||||||
| 
 | 
 | ||||||
|       // Intercept calls to client.sendMessage(), to know when it fails, and possibly to delay the
 |       // Intercept calls to client.sendMessage(), to know when it fails, and possibly to delay the
 | ||||||
|       // failures to hit a particular order in which 'close' and 'failedSend' events are seen by
 |       // failures to hit a particular order in which 'close' and 'failedSend' events are seen by
 | ||||||
|       // Client.ts. This is the only reliable way I found to reproduce this order of events.
 |       // Client.ts. This is the only reliable way I found to reproduce this order of events.
 | ||||||
|       const stubSendToWebsocket = sandbox.stub(Client.prototype as any, '_sendToWebsocket') |       const stubSendToWebsocket: any = sandbox.stub(Client.prototype as any, '_sendToWebsocket') | ||||||
|         .callsFake(async function(this: Client) { |         .callsFake(async function(this: Client) { | ||||||
|           try { |           try { | ||||||
|             return await (stubSendToWebsocket as any).wrappedMethod.apply(this, arguments); |             return await stubSendToWebsocket.wrappedMethod.apply(this, arguments); | ||||||
|           } catch (err) { |           } catch (err) { | ||||||
|             if (options.closeHappensFirst) { await delay(100); } |             if (options.closeHappensFirst) { await delay(100); } | ||||||
|             eventsSeen.push('failedSend'); |             eventsSeen.push('failedSend'); | ||||||
|  | |||||||
| @ -48,7 +48,7 @@ describe("MinIOExternalStorage", function () { | |||||||
| 
 | 
 | ||||||
|       s3.listObjects.returns(fakeStream); |       s3.listObjects.returns(fakeStream); | ||||||
| 
 | 
 | ||||||
|       const extStorage = new MinIOExternalStorage(dummyBucket, dummyOptions, 42, s3); |       const extStorage = new MinIOExternalStorage(dummyBucket, dummyOptions, 42, s3 as any); | ||||||
|       const result = await extStorage.versions(key); |       const result = await extStorage.versions(key); | ||||||
| 
 | 
 | ||||||
|       assert.deepEqual(result, []); |       assert.deepEqual(result, []); | ||||||
| @ -74,7 +74,7 @@ describe("MinIOExternalStorage", function () { | |||||||
|       ]); |       ]); | ||||||
| 
 | 
 | ||||||
|       s3.listObjects.returns(fakeStream); |       s3.listObjects.returns(fakeStream); | ||||||
|       const extStorage = new MinIOExternalStorage(dummyBucket, dummyOptions, 42, s3); |       const extStorage = new MinIOExternalStorage(dummyBucket, dummyOptions, 42, s3 as any); | ||||||
|       // when
 |       // when
 | ||||||
|       const result = await extStorage.versions(key); |       const result = await extStorage.versions(key); | ||||||
|       // then
 |       // then
 | ||||||
| @ -107,7 +107,7 @@ describe("MinIOExternalStorage", function () { | |||||||
|       let {fakeStream} = makeFakeStream(objectsFromS3); |       let {fakeStream} = makeFakeStream(objectsFromS3); | ||||||
| 
 | 
 | ||||||
|       s3.listObjects.returns(fakeStream); |       s3.listObjects.returns(fakeStream); | ||||||
|       const extStorage = new MinIOExternalStorage(dummyBucket, dummyOptions, 42, s3); |       const extStorage = new MinIOExternalStorage(dummyBucket, dummyOptions, 42, s3 as any); | ||||||
| 
 | 
 | ||||||
|       // when
 |       // when
 | ||||||
|       const result = await extStorage.versions(key); |       const result = await extStorage.versions(key); | ||||||
| @ -142,10 +142,10 @@ describe("MinIOExternalStorage", function () { | |||||||
|       const fakeStream = new stream.Readable({objectMode: true}); |       const fakeStream = new stream.Readable({objectMode: true}); | ||||||
|       const error = new Error("dummy-error"); |       const error = new Error("dummy-error"); | ||||||
|       sandbox.stub(fakeStream, "_read") |       sandbox.stub(fakeStream, "_read") | ||||||
|         .returns(fakeStream) |         .returns(fakeStream as any) | ||||||
|         .callsFake(() => fakeStream.emit('error', error)); |         .callsFake(() => fakeStream.emit('error', error)); | ||||||
|       s3.listObjects.returns(fakeStream); |       s3.listObjects.returns(fakeStream); | ||||||
|       const extStorage = new MinIOExternalStorage(dummyBucket, dummyOptions, 42, s3); |       const extStorage = new MinIOExternalStorage(dummyBucket, dummyOptions, 42, s3 as any); | ||||||
| 
 | 
 | ||||||
|       // when
 |       // when
 | ||||||
|       const result = extStorage.versions(key); |       const result = extStorage.versions(key); | ||||||
| @ -154,4 +154,4 @@ describe("MinIOExternalStorage", function () { | |||||||
|       return assert.isRejected(result, error); |       return assert.isRejected(result, error); | ||||||
|     }); |     }); | ||||||
|   }); |   }); | ||||||
| }); | }); | ||||||
|  | |||||||
							
								
								
									
										159
									
								
								yarn.lock
									
									
									
									
									
								
							
							
						
						
									
										159
									
								
								yarn.lock
									
									
									
									
									
								
							| @ -510,39 +510,40 @@ | |||||||
|   resolved "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz" |   resolved "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz" | ||||||
|   integrity sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ== |   integrity sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ== | ||||||
| 
 | 
 | ||||||
| "@sinonjs/commons@^1", "@sinonjs/commons@^1.2.0", "@sinonjs/commons@^1.3.0", "@sinonjs/commons@^1.7.0": | "@sinonjs/commons@^2.0.0": | ||||||
|   version "1.8.3" |   version "2.0.0" | ||||||
|   resolved "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz" |   resolved "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz#fd4ca5b063554307e8327b4564bd56d3b73924a3" | ||||||
|   integrity sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ== |   integrity sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg== | ||||||
|   dependencies: |   dependencies: | ||||||
|     type-detect "4.0.8" |     type-detect "4.0.8" | ||||||
| 
 | 
 | ||||||
| "@sinonjs/formatio@^3.0.0", "@sinonjs/formatio@^3.2.1": | "@sinonjs/commons@^3.0.0": | ||||||
|   version "3.2.2" |   version "3.0.1" | ||||||
|   resolved "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-3.2.2.tgz" |   resolved "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz#1029357e44ca901a615585f6d27738dbc89084cd" | ||||||
|   integrity sha512-B8SEsgd8gArBLMD6zpRw3juQ2FVSsmdd7qlevyDqzS9WTCtvF55/gAL+h6gue8ZvPYcdiPdvueM/qm//9XzyTQ== |   integrity sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ== | ||||||
|   dependencies: |   dependencies: | ||||||
|     "@sinonjs/commons" "^1" |     type-detect "4.0.8" | ||||||
|     "@sinonjs/samsam" "^3.1.0" |  | ||||||
| 
 | 
 | ||||||
| "@sinonjs/samsam@^2.1.2": | "@sinonjs/fake-timers@^11.2.2": | ||||||
|   version "2.1.3" |   version "11.2.2" | ||||||
|   resolved "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-2.1.3.tgz" |   resolved "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-11.2.2.tgz#50063cc3574f4a27bd8453180a04171c85cc9699" | ||||||
|   integrity sha512-8zNeBkSKhU9a5cRNbpCKau2WWPfan+Q2zDlcXvXyhn9EsMqgYs4qzo0XHNVlXC6ABQL8fT6nV+zzo5RTHJzyXw== |   integrity sha512-G2piCSxQ7oWOxwGSAyFHfPIsyeJGXYtc6mFbnFA+kRXkiEnTl8c/8jul2S329iFBnDI9HGoeWWAZvuvOkZccgw== | ||||||
| 
 |  | ||||||
| "@sinonjs/samsam@^3.1.0": |  | ||||||
|   version "3.3.3" |  | ||||||
|   resolved "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-3.3.3.tgz" |  | ||||||
|   integrity sha512-bKCMKZvWIjYD0BLGnNrxVuw4dkWCYsLqFOUWw8VgKF/+5Y+mE7LfHWPIYoDXowH+3a9LsWDMo0uAP8YDosPvHQ== |  | ||||||
|   dependencies: |   dependencies: | ||||||
|     "@sinonjs/commons" "^1.3.0" |     "@sinonjs/commons" "^3.0.0" | ||||||
|     array-from "^2.1.1" |  | ||||||
|     lodash "^4.17.15" |  | ||||||
| 
 | 
 | ||||||
| "@sinonjs/text-encoding@^0.7.1": | "@sinonjs/samsam@^8.0.0": | ||||||
|   version "0.7.1" |   version "8.0.0" | ||||||
|   resolved "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz" |   resolved "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-8.0.0.tgz#0d488c91efb3fa1442e26abea81759dfc8b5ac60" | ||||||
|   integrity sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ== |   integrity sha512-Bp8KUVlLp8ibJZrnvq2foVhP0IVX2CIprMJPK0vqGqgrDa0OHVKeZyBykqskkrdxV6yKBPmGasO8LVjAKR3Gew== | ||||||
|  |   dependencies: | ||||||
|  |     "@sinonjs/commons" "^2.0.0" | ||||||
|  |     lodash.get "^4.4.2" | ||||||
|  |     type-detect "^4.0.8" | ||||||
|  | 
 | ||||||
|  | "@sinonjs/text-encoding@^0.7.2": | ||||||
|  |   version "0.7.2" | ||||||
|  |   resolved "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.2.tgz#5981a8db18b56ba38ef0efb7d995b12aa7b51918" | ||||||
|  |   integrity sha512-sXXKG+uL9IrKqViTtao2Ws6dy0znu9sOaP1di/jKGW1M6VssO8vlpXCQcpZ+jisQ1tTFAC5Jo/EOzFbggBagFQ== | ||||||
| 
 | 
 | ||||||
| "@socket.io/component-emitter@~3.1.0": | "@socket.io/component-emitter@~3.1.0": | ||||||
|   version "3.1.0" |   version "3.1.0" | ||||||
| @ -951,10 +952,17 @@ | |||||||
|     "@types/mime" "*" |     "@types/mime" "*" | ||||||
|     "@types/node" "*" |     "@types/node" "*" | ||||||
| 
 | 
 | ||||||
| "@types/sinon@5.0.5": | "@types/sinon@17.0.3": | ||||||
|   version "5.0.5" |   version "17.0.3" | ||||||
|   resolved "https://registry.npmjs.org/@types/sinon/-/sinon-5.0.5.tgz" |   resolved "https://registry.npmjs.org/@types/sinon/-/sinon-17.0.3.tgz#9aa7e62f0a323b9ead177ed23a36ea757141a5fa" | ||||||
|   integrity sha512-Wnuv66VhvAD2LEJfZkq8jowXGxe+gjVibeLCYcVBp7QLdw0BFx2sRkKzoiiDkYEPGg5VyqO805Rcj0stVjQwCQ== |   integrity sha512-j3uovdn8ewky9kRBG19bOwaZbexJu/XjtkHyjvUgt4xfPFz18dcORIMqnYh66Fx3Powhcr85NT5+er3+oViapw== | ||||||
|  |   dependencies: | ||||||
|  |     "@types/sinonjs__fake-timers" "*" | ||||||
|  | 
 | ||||||
|  | "@types/sinonjs__fake-timers@*": | ||||||
|  |   version "8.1.5" | ||||||
|  |   resolved "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.5.tgz#5fd3592ff10c1e9695d377020c033116cc2889f2" | ||||||
|  |   integrity sha512-mQkU2jY8jJEF7YHjHvsQO8+3ughTL1mcnn96igfhONmR+fUPSKIkefQYpSe8bsly2Ep7oQbn/6VG5/9/0qcArQ== | ||||||
| 
 | 
 | ||||||
| "@types/sizzle@*": | "@types/sizzle@*": | ||||||
|   version "2.3.2" |   version "2.3.2" | ||||||
| @ -1581,11 +1589,6 @@ array-flatten@1.1.1: | |||||||
|   resolved "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz" |   resolved "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz" | ||||||
|   integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= |   integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= | ||||||
| 
 | 
 | ||||||
| array-from@^2.1.1: |  | ||||||
|   version "2.1.1" |  | ||||||
|   resolved "https://registry.npmjs.org/array-from/-/array-from-2.1.1.tgz" |  | ||||||
|   integrity sha1-z+nYwmYoudxa7MYqn12PHzUsEZU= |  | ||||||
| 
 |  | ||||||
| array-map@~0.0.0: | array-map@~0.0.0: | ||||||
|   version "0.0.0" |   version "0.0.0" | ||||||
|   resolved "https://registry.npmjs.org/array-map/-/array-map-0.0.0.tgz" |   resolved "https://registry.npmjs.org/array-map/-/array-map-0.0.0.tgz" | ||||||
| @ -2948,10 +2951,10 @@ diff@5.0.0: | |||||||
|   resolved "https://registry.yarnpkg.com/diff/-/diff-5.0.0.tgz#7ed6ad76d859d030787ec35855f5b1daf31d852b" |   resolved "https://registry.yarnpkg.com/diff/-/diff-5.0.0.tgz#7ed6ad76d859d030787ec35855f5b1daf31d852b" | ||||||
|   integrity sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w== |   integrity sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w== | ||||||
| 
 | 
 | ||||||
| diff@^3.5.0: | diff@^5.1.0: | ||||||
|   version "3.5.0" |   version "5.2.0" | ||||||
|   resolved "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz" |   resolved "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz#26ded047cd1179b78b9537d5ef725503ce1ae531" | ||||||
|   integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA== |   integrity sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A== | ||||||
| 
 | 
 | ||||||
| diffie-hellman@^5.0.0: | diffie-hellman@^5.0.0: | ||||||
|   version "5.0.3" |   version "5.0.3" | ||||||
| @ -4833,11 +4836,6 @@ is-yarn-global@^0.3.0: | |||||||
|   resolved "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz" |   resolved "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz" | ||||||
|   integrity sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw== |   integrity sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw== | ||||||
| 
 | 
 | ||||||
| isarray@0.0.1: |  | ||||||
|   version "0.0.1" |  | ||||||
|   resolved "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz" |  | ||||||
|   integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= |  | ||||||
| 
 |  | ||||||
| isarray@~1.0.0: | isarray@~1.0.0: | ||||||
|   version "1.0.0" |   version "1.0.0" | ||||||
|   resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" |   resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" | ||||||
| @ -5037,10 +5035,10 @@ jszip@^3.10.1, jszip@^3.5.0: | |||||||
|     readable-stream "~2.3.6" |     readable-stream "~2.3.6" | ||||||
|     setimmediate "^1.0.5" |     setimmediate "^1.0.5" | ||||||
| 
 | 
 | ||||||
| just-extend@^4.0.2: | just-extend@^6.2.0: | ||||||
|   version "4.2.1" |   version "6.2.0" | ||||||
|   resolved "https://registry.npmjs.org/just-extend/-/just-extend-4.2.1.tgz" |   resolved "https://registry.npmjs.org/just-extend/-/just-extend-6.2.0.tgz#b816abfb3d67ee860482e7401564672558163947" | ||||||
|   integrity sha512-g3UB796vUFIY90VIv/WX3L2c8CS2MdWUww3CNrYmqza1Fg0DURc2K/O4YrnklBdQarSJ/y8JnJYDGc+1iumQjg== |   integrity sha512-cYofQu2Xpom82S6qD778jBDpwvvy39s1l/hrYij2u9AMdQcGRpaBu6kY4mVhuno5kJVi1DAz4aiphA2WI1/OAw== | ||||||
| 
 | 
 | ||||||
| jwa@^1.4.1: | jwa@^1.4.1: | ||||||
|   version "1.4.1" |   version "1.4.1" | ||||||
| @ -5307,18 +5305,6 @@ log-symbols@4.1.0: | |||||||
|     chalk "^4.1.0" |     chalk "^4.1.0" | ||||||
|     is-unicode-supported "^0.1.0" |     is-unicode-supported "^0.1.0" | ||||||
| 
 | 
 | ||||||
| lolex@^3.0.0: |  | ||||||
|   version "3.1.0" |  | ||||||
|   resolved "https://registry.npmjs.org/lolex/-/lolex-3.1.0.tgz" |  | ||||||
|   integrity sha512-zFo5MgCJ0rZ7gQg69S4pqBsLURbFw11X68C18OcJjJQbqaXm2NoTrGl1IMM3TIz0/BnN1tIs2tzmmqvCsOMMjw== |  | ||||||
| 
 |  | ||||||
| lolex@^5.0.1: |  | ||||||
|   version "5.1.2" |  | ||||||
|   resolved "https://registry.npmjs.org/lolex/-/lolex-5.1.2.tgz" |  | ||||||
|   integrity sha512-h4hmjAvHTmd+25JSwrtTIuwbKdwg5NzZVRMLn9saij4SZaepCrTCxPr35H/3bjwfMJtN+t3CX8672UIkglz28A== |  | ||||||
|   dependencies: |  | ||||||
|     "@sinonjs/commons" "^1.7.0" |  | ||||||
| 
 |  | ||||||
| loupe@^2.3.1: | loupe@^2.3.1: | ||||||
|   version "2.3.6" |   version "2.3.6" | ||||||
|   resolved "https://registry.yarnpkg.com/loupe/-/loupe-2.3.6.tgz#76e4af498103c532d1ecc9be102036a21f787b53" |   resolved "https://registry.yarnpkg.com/loupe/-/loupe-2.3.6.tgz#76e4af498103c532d1ecc9be102036a21f787b53" | ||||||
| @ -5796,16 +5782,16 @@ nice-napi@^1.0.2: | |||||||
|     node-addon-api "^3.0.0" |     node-addon-api "^3.0.0" | ||||||
|     node-gyp-build "^4.2.2" |     node-gyp-build "^4.2.2" | ||||||
| 
 | 
 | ||||||
| nise@^1.4.6: | nise@^5.1.5: | ||||||
|   version "1.5.3" |   version "5.1.9" | ||||||
|   resolved "https://registry.npmjs.org/nise/-/nise-1.5.3.tgz" |   resolved "https://registry.npmjs.org/nise/-/nise-5.1.9.tgz#0cb73b5e4499d738231a473cd89bd8afbb618139" | ||||||
|   integrity sha512-Ymbac/94xeIrMf59REBPOv0thr+CJVFMhrlAkW/gjCIE58BGQdCj0x7KRCb3yz+Ga2Rz3E9XXSvUyyxqqhjQAQ== |   integrity sha512-qOnoujW4SV6e40dYxJOb3uvuoPHtmLzIk4TFo+j0jPJoC+5Z9xja5qH5JZobEPsa8+YYphMrOSwnrshEhG2qww== | ||||||
|   dependencies: |   dependencies: | ||||||
|     "@sinonjs/formatio" "^3.2.1" |     "@sinonjs/commons" "^3.0.0" | ||||||
|     "@sinonjs/text-encoding" "^0.7.1" |     "@sinonjs/fake-timers" "^11.2.2" | ||||||
|     just-extend "^4.0.2" |     "@sinonjs/text-encoding" "^0.7.2" | ||||||
|     lolex "^5.0.1" |     just-extend "^6.2.0" | ||||||
|     path-to-regexp "^1.7.0" |     path-to-regexp "^6.2.1" | ||||||
| 
 | 
 | ||||||
| node-abort-controller@3.0.1: | node-abort-controller@3.0.1: | ||||||
|   version "3.0.1" |   version "3.0.1" | ||||||
| @ -6237,12 +6223,10 @@ path-to-regexp@0.1.7: | |||||||
|   resolved "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz" |   resolved "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz" | ||||||
|   integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= |   integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= | ||||||
| 
 | 
 | ||||||
| path-to-regexp@^1.7.0: | path-to-regexp@^6.2.1: | ||||||
|   version "1.8.0" |   version "6.2.1" | ||||||
|   resolved "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz" |   resolved "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.1.tgz#d54934d6798eb9e5ef14e7af7962c945906918e5" | ||||||
|   integrity sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA== |   integrity sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw== | ||||||
|   dependencies: |  | ||||||
|     isarray "0.0.1" |  | ||||||
| 
 | 
 | ||||||
| path-type@^4.0.0: | path-type@^4.0.0: | ||||||
|   version "4.0.0" |   version "4.0.0" | ||||||
| @ -7209,20 +7193,17 @@ simple-concat@^1.0.0: | |||||||
|   resolved "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz" |   resolved "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz" | ||||||
|   integrity sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q== |   integrity sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q== | ||||||
| 
 | 
 | ||||||
| sinon@7.1.1: | sinon@17.0.1: | ||||||
|   version "7.1.1" |   version "17.0.1" | ||||||
|   resolved "https://registry.npmjs.org/sinon/-/sinon-7.1.1.tgz" |   resolved "https://registry.npmjs.org/sinon/-/sinon-17.0.1.tgz#26b8ef719261bf8df43f925924cccc96748e407a" | ||||||
|   integrity sha512-iYagtjLVt1vN3zZY7D8oH7dkjNJEjLjyuzy8daX5+3bbQl8gaohrheB9VfH1O3L6LKuue5WTJvFluHiuZ9y3nQ== |   integrity sha512-wmwE19Lie0MLT+ZYNpDymasPHUKTaZHUH/pKEubRXIzySv9Atnlw+BUMGCzWgV7b7wO+Hw6f1TEOr0IUnmU8/g== | ||||||
|   dependencies: |   dependencies: | ||||||
|     "@sinonjs/commons" "^1.2.0" |     "@sinonjs/commons" "^3.0.0" | ||||||
|     "@sinonjs/formatio" "^3.0.0" |     "@sinonjs/fake-timers" "^11.2.2" | ||||||
|     "@sinonjs/samsam" "^2.1.2" |     "@sinonjs/samsam" "^8.0.0" | ||||||
|     diff "^3.5.0" |     diff "^5.1.0" | ||||||
|     lodash.get "^4.4.2" |     nise "^5.1.5" | ||||||
|     lolex "^3.0.0" |     supports-color "^7.2.0" | ||||||
|     nise "^1.4.6" |  | ||||||
|     supports-color "^5.5.0" |  | ||||||
|     type-detect "^4.0.8" |  | ||||||
| 
 | 
 | ||||||
| slash@^3.0.0: | slash@^3.0.0: | ||||||
|   version "3.0.0" |   version "3.0.0" | ||||||
| @ -7502,7 +7483,7 @@ supports-color@^5.3.0, supports-color@^5.5.0: | |||||||
|   dependencies: |   dependencies: | ||||||
|     has-flag "^3.0.0" |     has-flag "^3.0.0" | ||||||
| 
 | 
 | ||||||
| supports-color@^7.1.0: | supports-color@^7.1.0, supports-color@^7.2.0: | ||||||
|   version "7.2.0" |   version "7.2.0" | ||||||
|   resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" |   resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" | ||||||
|   integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== |   integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user