diff --git a/packages/cozy-doctypes/package.json b/packages/cozy-doctypes/package.json index 6008261ecd..27543d884e 100644 --- a/packages/cozy-doctypes/package.json +++ b/packages/cozy-doctypes/package.json @@ -18,9 +18,13 @@ "@babel/cli": "7.2.3", "babel-preset-cozy-app": "^1.5.1", "btoa": "1.2.1", + "cozy-client": "6.34.0", "cozy-client-js": "0.14.2", "jest": "24.1.0" }, + "peerDependencies": { + "cozy-client": "6.34.0" + }, "scripts": { "lint": "cd ../../; yarn lint packages/cozy-doctypes", "build": "babel src -d dist", diff --git a/packages/cozy-doctypes/src/Document.js b/packages/cozy-doctypes/src/Document.js index 374485fc82..89b89037e1 100644 --- a/packages/cozy-doctypes/src/Document.js +++ b/packages/cozy-doctypes/src/Document.js @@ -10,6 +10,7 @@ const groupBy = require('lodash/groupBy') const sortBy = require('lodash/sortBy') const get = require('lodash/get') const { parallelMap } = require('./utils') +const CozyClient = require('cozy-client').default const log = require('cozy-logger').namespace('Document') const querystring = require('querystring') @@ -63,6 +64,11 @@ const withoutUndefined = x => omitBy(x, isUndefined) const flagForDeletion = x => Object.assign({}, x, { _deleted: true }) class Document { + /** + * Registers a client + * + * @param {object} client - Cozy client from either cozy-client or cozy-client-js + */ static registerClient(client) { if (!this.cozyClient) { this.cozyClient = client @@ -75,7 +81,29 @@ class Document { } } + static unregisterClient() { + this.cozyClient = null + } + + /** + * Returns true if Document uses a CozyClient (from cozy-client package) + * + * @returns {boolean} true if Document uses a CozyClient + **/ + static usesCozyClient() { + return this.cozyClient instanceof CozyClient + } + static getIndex(doctype, fields) { + if (this.usesCozyClient()) { + throw new Error('This method is not implemented yet with CozyClient') + } + + return this._getIndex(doctype, fields) + } + + // getIndex method that uses cozy-client-js + static _getIndex(doctype, fields) { const key = `${doctype}:${fields.slice().join(',')}` const index = indexes[key] if (!index) { @@ -108,6 +136,15 @@ class Document { } static async createOrUpdate(attributes) { + if (this.usesCozyClient()) { + throw new Error('This method is not implemented yet with CozyClient') + } + + return this._createOrUpdate(attributes) + } + + // createOrUpdate method that uses cozy-client-js + static async _createOrUpdate(attributes) { const selector = fromPairs( this.idAttributes.map(idAttribute => [ idAttribute, @@ -168,6 +205,15 @@ class Document { } static create(attributes) { + if (this.usesCozyClient()) { + throw new Error('This method is not implemented yet with CozyClient') + } + + return this._create(attributes) + } + + // create method that uses cozy-client-js + static _create(attributes) { return this.cozyClient.data.create(this.doctype, attributes) } @@ -186,12 +232,25 @@ class Document { } static query(index, options) { + if (this.usesCozyClient()) { + throw new Error('This method is not implemented yet with CozyClient') + } + + return this._query(index, options) + } + + // query method that uses cozy-client-js + static _query(index, options) { return this.cozyClient.data.query(index, options) } static async fetchAll() { + const stackClient = this.usesCozyClient() + ? this.cozyClient.stackClient + : this.cozyClient + try { - const result = await this.cozyClient.fetchJSON( + const result = await stackClient.fetchJSON( 'GET', `/data/${this.doctype}/_all_docs?include_docs=true` ) @@ -208,11 +267,15 @@ class Document { } static async updateAll(docs) { + const stackClient = this.usesCozyClient() + ? this.cozyClient.stackClient + : this.cozyClient + if (!docs || !docs.length) { return Promise.resolve([]) } try { - const update = await this.cozyClient.fetchJSON( + const update = await stackClient.fetchJSON( 'POST', `/data/${this.doctype}/_bulk_docs`, { @@ -291,6 +354,10 @@ class Document { * @param {[type]} options { includeDesign: false, includeDeleted: false } */ static async fetchChanges(since, options = {}) { + const stackClient = this.usesCozyClient() + ? this.cozyClient.stackClient + : this.cozyClient + const queryParams = { since, include_docs: 'true' @@ -298,7 +365,7 @@ class Document { if (options.params) { Object.assign(queryParams, options.params) } - const result = await this.cozyClient.fetchJSON( + const result = await stackClient.fetchJSON( 'GET', `/data/${this.doctype}/_changes?${querystring.stringify(queryParams)}` ) @@ -335,6 +402,15 @@ class Document { * */ static async queryAll(selector, index) { + if (this.usesCozyClient()) { + throw new Error('This method is not implemented yet with CozyClient') + } + + return this._queryAll(selector, index) + } + + // queryAll method that uses cozy-client-js + static async _queryAll(selector, index) { if (!selector) { // fetchAll is faster in this case return await this.fetchAll() @@ -366,9 +442,12 @@ class Document { * @return {Promise} - Promise resolving to an array of documents, unfound document are filtered */ static async getAll(ids) { + const stackClient = this.usesCozyClient() + ? this.cozyClient.stackClient + : this.cozyClient let resp try { - resp = await this.cozyClient.fetchJSON( + resp = await stackClient.fetchJSON( 'POST', `/data/${this.doctype}/_all_docs?include_docs=true`, { diff --git a/packages/cozy-doctypes/src/Document.spec.js b/packages/cozy-doctypes/src/Document.spec.js index d36f1d196c..a1fc3ee044 100644 --- a/packages/cozy-doctypes/src/Document.spec.js +++ b/packages/cozy-doctypes/src/Document.spec.js @@ -1,5 +1,5 @@ const Document = require('./Document') -const { cozyClient } = require('./testUtils') +const { cozyClientJS, cozyClient } = require('./testUtils') class Simpson extends Document {} Simpson.doctype = 'io.cozy.simpsons' @@ -8,39 +8,49 @@ Simpson.idAttributes = ['name'] describe('Document', () => { let queryResult = [] beforeAll(() => { - cozyClient.data.query.mockImplementation(() => Promise.resolve(queryResult)) - Document.registerClient(cozyClient) + cozyClientJS.data.query.mockImplementation(() => + Promise.resolve(queryResult) + ) + }) + + beforeEach(() => { + Document.registerClient(cozyClientJS) }) afterEach(() => { jest.restoreAllMocks() + Document.unregisterClient() }) - afterAll(() => { - Document.registerClient(null) + describe('registerClient', () => { + it('client cannot be registered twice', () => { + expect(() => { + const newClient = {} + Document.registerClient(newClient) + }).toThrow('Document cannot be re-registered to a client.') + }) }) - it('client cannot be registered twice', () => { - expect(() => { - const newClient = {} - Document.registerClient(newClient) - }).toThrow('Document cannot be re-registered to a client.') + describe('usesCozyClient', () => { + it('should return false', () => { + expect(Document.usesCozyClient()).toBe(false) + }) }) it('should do create or update', async () => { const marge = { name: 'Marge' } await Simpson.createOrUpdate(marge) - expect(cozyClient.data.query).toHaveBeenCalledWith(expect.anything(), { + expect(cozyClientJS.data.query).toHaveBeenCalledWith(expect.anything(), { selector: { name: 'Marge' } }) - expect(cozyClient.data.create).toHaveBeenCalledTimes(1) - expect(cozyClient.data.updateAttributes).toHaveBeenCalledTimes(0) + expect(cozyClientJS.data.create).toHaveBeenCalledTimes(1) + expect(cozyClientJS.data.updateAttributes).toHaveBeenCalledTimes(0) queryResult = [{ _id: 5, ...marge }] await Simpson.createOrUpdate(marge) - expect(cozyClient.data.create).toHaveBeenCalledTimes(1) - expect(cozyClient.data.updateAttributes).toHaveBeenCalledTimes(1) + expect(cozyClientJS.data.create).toHaveBeenCalledTimes(1) + expect(cozyClientJS.data.updateAttributes).toHaveBeenCalledTimes(1) }) it('should update updatedAt cozyMetadata on create or update', async () => { @@ -109,7 +119,7 @@ describe('Document', () => { it('should do bulk fetch', async () => { await Simpson.fetchAll() - expect(cozyClient.fetchJSON).toHaveBeenCalledWith( + expect(cozyClientJS.fetchJSON).toHaveBeenCalledWith( 'GET', '/data/io.cozy.simpsons/_all_docs?include_docs=true' ) @@ -168,21 +178,21 @@ describe('Document', () => { }) it('should not do anything if passed empty list', async () => { - jest.spyOn(cozyClient.data, 'create').mockReset() - jest.spyOn(cozyClient, 'fetchJSON').mockReset() + jest.spyOn(cozyClientJS.data, 'create').mockReset() + jest.spyOn(cozyClientJS, 'fetchJSON').mockReset() const res = await Simpson.updateAll([]) - expect(cozyClient.data.create).not.toHaveBeenCalled() - expect(cozyClient.fetchJSON).not.toHaveBeenCalled() + expect(cozyClientJS.data.create).not.toHaveBeenCalled() + expect(cozyClientJS.fetchJSON).not.toHaveBeenCalled() expect(res).toEqual([]) }) it('should create database when bulk updating', async () => { jest - .spyOn(cozyClient.data, 'create') + .spyOn(cozyClientJS.data, 'create') .mockReset() .mockResolvedValue({ _id: 1 }) jest - .spyOn(cozyClient, 'fetchJSON') + .spyOn(cozyClientJS, 'fetchJSON') .mockReset() .mockRejectedValueOnce({ reason: { reason: 'Database does not exist.' } @@ -200,7 +210,7 @@ describe('Document', () => { { _id: 2, name: 'Homer' } ]) - expect(cozyClient.data.create).toHaveBeenCalledWith('io.cozy.simpsons', { + expect(cozyClientJS.data.create).toHaveBeenCalledWith('io.cozy.simpsons', { _id: 1, name: 'Marge' }) @@ -213,7 +223,7 @@ describe('Document', () => { { _id: 1, name: 'Marge' }, { _id: 2, name: 'Homer' } ]) - expect(cozyClient.fetchJSON).toHaveBeenCalledWith( + expect(cozyClientJS.fetchJSON).toHaveBeenCalledWith( 'POST', '/data/io.cozy.simpsons/_bulk_docs', { @@ -227,13 +237,13 @@ describe('Document', () => { describe('fetch changes', () => { beforeEach(() => { - cozyClient.fetchJSON.mockReset() + cozyClientJS.fetchJSON.mockReset() }) afterEach(() => { - cozyClient.fetchJSON.mockReset() + cozyClientJS.fetchJSON.mockReset() }) it('should work in simple case', async () => { - cozyClient.fetchJSON.mockReturnValueOnce( + cozyClientJS.fetchJSON.mockReturnValueOnce( Promise.resolve({ last_seq: 'new-seq', results: [ @@ -246,7 +256,7 @@ describe('Document', () => { ) const changes = await Simpson.fetchChanges('my-seq') - expect(cozyClient.fetchJSON).toHaveBeenCalledWith( + expect(cozyClientJS.fetchJSON).toHaveBeenCalledWith( 'GET', '/data/io.cozy.simpsons/_changes?since=my-seq&include_docs=true' ) @@ -257,7 +267,7 @@ describe('Document', () => { }) it('should support query options', async () => { - cozyClient.fetchJSON.mockReturnValueOnce( + cozyClientJS.fetchJSON.mockReturnValueOnce( Promise.resolve({ last_seq: 'new-seq', results: [] @@ -267,7 +277,7 @@ describe('Document', () => { await Simpson.fetchChanges('my-seq', { params: { descending: true, limit: 1 } }) - expect(cozyClient.fetchJSON).toHaveBeenCalledWith( + expect(cozyClientJS.fetchJSON).toHaveBeenCalledWith( 'GET', '/data/io.cozy.simpsons/_changes?since=my-seq&include_docs=true&descending=true&limit=1' ) @@ -276,11 +286,11 @@ describe('Document', () => { describe('query all', () => { afterEach(() => { - cozyClient.data.query.mockReset() + cozyClientJS.data.query.mockReset() }) it('should repeatedly call query until all documents have been fetched', async () => { let i = 0 - cozyClient.data.query.mockImplementation(() => { + cozyClientJS.data.query.mockImplementation(() => { let docs if (i == 0) { docs = [{ _id: 1, name: 'Lisa' }] @@ -299,35 +309,35 @@ describe('Document', () => { return Promise.resolve(resp) }) const docs = await Simpson.queryAll({ name: { $exists: true } }) - expect(cozyClient.data.defineIndex).toHaveBeenCalledWith( + expect(cozyClientJS.data.defineIndex).toHaveBeenCalledWith( 'io.cozy.simpsons', ['name'] ) expect(docs.length).toBe(4) expect( - cozyClient.data.query.mock.calls.slice(-4).map(x => x[1].skip) + cozyClientJS.data.query.mock.calls.slice(-4).map(x => x[1].skip) ).toEqual([0, 1, 2, 3]) }) }) describe('get all', () => { beforeEach(() => { - cozyClient.fetchJSON.mockReset() + cozyClientJS.fetchJSON.mockReset() }) afterEach(() => { - cozyClient.fetchJSON.mockReset() + cozyClientJS.fetchJSON.mockReset() }) it('should work', async () => { - cozyClient.fetchJSON.mockResolvedValueOnce({ + cozyClientJS.fetchJSON.mockResolvedValueOnce({ rows: [ { doc: { _id: '123abde', name: 'Lisa' } }, { doc: { _id: '2123asb', name: 'Bart' } } ] }) const docs = await Simpson.getAll(['123abde', '2123asb']) - expect(cozyClient.fetchJSON).toHaveBeenCalledWith( + expect(cozyClientJS.fetchJSON).toHaveBeenCalledWith( 'POST', '/data/io.cozy.simpsons/_all_docs?include_docs=true', { @@ -341,7 +351,7 @@ describe('Document', () => { }) it('should return empty list in case of error', async () => { - cozyClient.fetchJSON.mockRejectedValueOnce({ + cozyClientJS.fetchJSON.mockRejectedValueOnce({ message: 'not_found' }) const docs = await Simpson.getAll(['notexisting']) @@ -358,9 +368,186 @@ describe('Document', () => { SubSimpson.fetch() - expect(cozyClient.fetchJSON).toHaveBeenLastCalledWith( + expect(cozyClientJS.fetchJSON).toHaveBeenLastCalledWith( 'GET', '/data/io.cozy.simpsons/_all_docs' ) }) }) + +describe('Document used with CozyClient', () => { + beforeEach(() => { + Document.registerClient(cozyClient) + }) + + afterEach(() => { + jest.restoreAllMocks() + Document.unregisterClient() + }) + + describe('usesCozyClient', () => { + it('should return true', () => { + expect(Document.usesCozyClient()).toBe(true) + }) + }) + + describe('getIndex', () => { + it('should throw an error if used with a CozyClient', () => { + expect(() => Document.getIndex('io.cozy.simpsons', ['name'])).toThrow( + 'This method is not implemented yet with CozyClient' + ) + }) + }) + + describe('createOrUpdate', () => { + it('should throw an error if used with a CozyClient', async () => { + expect.assertions(1) + await expect(Document.createOrUpdate({})).rejects.toEqual( + new Error('This method is not implemented yet with CozyClient') + ) + }) + }) + + describe('create', () => { + it('should throw an error if used with a CozyClient', () => { + expect(() => Document.create({})).toThrow( + new Error('This method is not implemented yet with CozyClient') + ) + }) + }) + + describe('query', () => { + it('should throw an error if used with a CozyClient', () => { + expect(() => Document.query({})).toThrow( + new Error('This method is not implemented yet with CozyClient') + ) + }) + }) + + describe('queryAll', () => { + it('should throw an error if used with a CozyClient', async () => { + expect.assertions(1) + await expect( + Document.queryAll({ name: { $exists: true } }) + ).rejects.toEqual( + new Error('This method is not implemented yet with CozyClient') + ) + }) + }) + + describe('getAll', () => { + beforeEach(() => { + cozyClient.stackClient.fetchJSON.mockReset() + }) + + afterEach(() => { + cozyClient.stackClient.fetchJSON.mockReset() + }) + + it('should work', async () => { + cozyClient.stackClient.fetchJSON.mockResolvedValueOnce({ + rows: [ + { doc: { _id: '123abde', name: 'Lisa' } }, + { doc: { _id: '2123asb', name: 'Bart' } } + ] + }) + const docs = await Simpson.getAll(['123abde', '2123asb']) + expect(cozyClient.stackClient.fetchJSON).toHaveBeenCalledWith( + 'POST', + '/data/io.cozy.simpsons/_all_docs?include_docs=true', + { + keys: ['123abde', '2123asb'] + } + ) + expect(docs).toEqual([ + { _id: '123abde', name: 'Lisa' }, + { _id: '2123asb', name: 'Bart' } + ]) + }) + + it('should return empty list in case of error', async () => { + cozyClient.stackClient.fetchJSON.mockRejectedValueOnce({ + message: 'not_found' + }) + const docs = await Simpson.getAll(['notexisting']) + expect(docs).toEqual([]) + }) + }) + + describe('fetchChanges', () => { + beforeEach(() => { + cozyClient.stackClient.fetchJSON.mockReset() + }) + + afterEach(() => { + cozyClient.stackClient.fetchJSON.mockReset() + }) + + it('should work in simple case', async () => { + cozyClient.stackClient.fetchJSON.mockReturnValueOnce( + Promise.resolve({ + last_seq: 'new-seq', + results: [ + { doc: { _id: '1', name: 'Lisa' } }, + { doc: null }, + { doc: { _id: '_design/view' } }, + { doc: { _id: '2', _deleted: true, name: 'Bart' } } + ] + }) + ) + + const changes = await Simpson.fetchChanges('my-seq') + expect(cozyClient.stackClient.fetchJSON).toHaveBeenCalledWith( + 'GET', + '/data/io.cozy.simpsons/_changes?since=my-seq&include_docs=true' + ) + expect(changes).toEqual({ + newLastSeq: 'new-seq', + documents: [{ _id: '1', name: 'Lisa' }] + }) + }) + + it('should support query options', async () => { + cozyClient.stackClient.fetchJSON.mockReturnValueOnce( + Promise.resolve({ + last_seq: 'new-seq', + results: [] + }) + ) + + await Simpson.fetchChanges('my-seq', { + params: { descending: true, limit: 1 } + }) + expect(cozyClient.stackClient.fetchJSON).toHaveBeenCalledWith( + 'GET', + '/data/io.cozy.simpsons/_changes?since=my-seq&include_docs=true&descending=true&limit=1' + ) + }) + }) + + describe('fetchAll', () => { + it('should do bulk fetch', async () => { + await Simpson.fetchAll() + expect(cozyClient.stackClient.fetchJSON).toHaveBeenCalledWith( + 'GET', + '/data/io.cozy.simpsons/_all_docs?include_docs=true' + ) + }) + }) + + describe('updateAll', () => { + beforeEach(() => { + cozyClient.stackClient.fetchJSON.mockReset() + }) + + afterEach(() => { + cozyClient.stackClient.fetchJSON.mockReset() + }) + + it('should not do anything if passed empty list', async () => { + const res = await Simpson.updateAll([]) + expect(cozyClient.stackClient.fetchJSON).not.toHaveBeenCalled() + expect(res).toEqual([]) + }) + }) +}) diff --git a/packages/cozy-doctypes/src/banking/BalanceHistory.spec.js b/packages/cozy-doctypes/src/banking/BalanceHistory.spec.js index 602f332151..7d539acf69 100644 --- a/packages/cozy-doctypes/src/banking/BalanceHistory.spec.js +++ b/packages/cozy-doctypes/src/banking/BalanceHistory.spec.js @@ -1,13 +1,13 @@ const BalanceHistory = require('./BalanceHistory') const Document = require('../Document') -const { cozyClient } = require('../testUtils') +const { cozyClientJS } = require('../testUtils') describe('Balance history', () => { let queryResult = [] beforeAll(() => { - Document.registerClient(cozyClient) - cozyClient.data.query.mockImplementation(() => { + Document.registerClient(cozyClientJS) + cozyClientJS.data.query.mockImplementation(() => { return Promise.resolve(queryResult) }) }) @@ -25,13 +25,13 @@ describe('Balance history', () => { it('should update or create on year + account linked', async () => { await BalanceHistory.createOrUpdate(doc) - expect(cozyClient.data.query).toHaveBeenCalledWith(expect.anything(), { + expect(cozyClientJS.data.query).toHaveBeenCalledWith(expect.anything(), { selector: { year: 2018, 'relationships.account.data._id': 3 } }) - expect(cozyClient.data.create).toHaveBeenCalledTimes(1) + expect(cozyClientJS.data.create).toHaveBeenCalledTimes(1) queryResult = [ { @@ -47,6 +47,6 @@ describe('Balance history', () => { ] await BalanceHistory.createOrUpdate(doc) - expect(cozyClient.data.create).toHaveBeenCalledTimes(1) + expect(cozyClientJS.data.create).toHaveBeenCalledTimes(1) }) }) diff --git a/packages/cozy-doctypes/src/testUtils.js b/packages/cozy-doctypes/src/testUtils.js index 23e24f3dc6..53b6433073 100644 --- a/packages/cozy-doctypes/src/testUtils.js +++ b/packages/cozy-doctypes/src/testUtils.js @@ -1,5 +1,10 @@ +const CozyClient = require('cozy-client').default +const CozyStackClient = require('cozy-stack-client').default + +jest.mock('cozy-stack-client') + module.exports = { - cozyClient: { + cozyClientJS: { data: { defineIndex: jest.fn().mockResolvedValue({ name: 'index' }), query: jest.fn().mockResolvedValue([]), @@ -7,5 +12,8 @@ module.exports = { create: jest.fn() }, fetchJSON: jest.fn().mockReturnValue({ rows: [] }) - } + }, + cozyClient: new CozyClient({ + stackClient: new CozyStackClient() + }) } diff --git a/yarn.lock b/yarn.lock index b205bc19c7..8f5551df51 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3764,6 +3764,23 @@ cozy-client@^6.27.0: redux-thunk "2.3.0" sift "6.0.0" +cozy-client@^6.34.0: + version "6.34.0" + resolved "https://registry.yarnpkg.com/cozy-client/-/cozy-client-6.34.0.tgz#fcaac796f9689757c5b1f540e9d3b013f4c60f71" + integrity sha512-PmE4xeg9mtCWTlJjnTNO3NYzDbnuZADFA26KuMsihZEjgQZ/AQaVi0z+6julEEo10fTrRqQ+rWjYFMHUox2c0Q== + dependencies: + cozy-device-helper "1.6.3" + cozy-stack-client "^6.33.0" + lodash "4.17.11" + microee "0.0.6" + prop-types "15.6.2" + react "16.7.0" + react-redux "5.0.7" + redux "3.7.2" + redux-thunk "2.3.0" + sift "6.0.0" + url-search-params-polyfill "^6.0.0" + cozy-device-helper@1.6.3: version "1.6.3" resolved "https://registry.yarnpkg.com/cozy-device-helper/-/cozy-device-helper-1.6.3.tgz#186cf0682921fa3ec7c2343d94fb84f317c992ba" @@ -3794,6 +3811,15 @@ cozy-stack-client@^6.25.0: mime-types "2.1.24" qs "6.7.0" +cozy-stack-client@^6.33.0: + version "6.33.0" + resolved "https://registry.yarnpkg.com/cozy-stack-client/-/cozy-stack-client-6.33.0.tgz#62eca6b63f1d7202ae5032b28b47461be5e85199" + integrity sha512-7S8xPcd03BoEd/VFhBv/vxB/2P0U2SLK/wgFoLor7lPHJ00Al8q/pFFgDIb8r1eoK247augH/JrcDUGbSIhVQA== + dependencies: + detect-node "2.0.4" + mime-types "2.1.24" + qs "6.7.0" + cozy-ui@19.35.4: version "19.35.4" resolved "https://registry.yarnpkg.com/cozy-ui/-/cozy-ui-19.35.4.tgz#c8225cd0dda36b7cc440b02d3066e8b04828b990" @@ -15207,6 +15233,11 @@ url-polyfill@1.1.0: resolved "https://registry.yarnpkg.com/url-polyfill/-/url-polyfill-1.1.0.tgz#d34e1a596d954b864bc8608f84c592820df422db" integrity sha512-QAbzqCwd84yA6VyjV30aZXla+lrRmczDurvlsVnK+tFOu677ZNGz8shcFWQRp5BF9/z7qvNiCQLqpWPtVoUEBg== +url-search-params-polyfill@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/url-search-params-polyfill/-/url-search-params-polyfill-6.0.0.tgz#f5e5fc230d56125f5b0ba67d9cbcd6555fa347e3" + integrity sha512-69Bl5s3SiEgcHe8SMpzLGOyag27BQeTeSaP/CfVHkKc/VdUHtNjaP2PnhshFVC021221ItueOzuMMGofZ/HDmQ== + url@^0.11.0: version "0.11.0" resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1"