From 3a97527fe4061cef8f0eceb47d791e475b5f3d07 Mon Sep 17 00:00:00 2001 From: Travis Fischer Date: Mon, 17 Oct 2022 18:16:35 -0400 Subject: [PATCH] feat: remove got; add ky for fetch support to notion-client --- packages/notion-client/package.json | 8 +- packages/notion-client/src/browser.ts | 2 + packages/notion-client/src/index.ts | 2 +- ...i.test.ts => notion-api-universal.test.ts} | 2 +- .../notion-client/src/notion-api-universal.ts | 4 + packages/notion-client/src/notion-api.ts | 90 ++++++------- packages/notion-client/src/temp | 31 ----- packages/notion-client/tsup.config.ts | 35 ++++-- yarn.lock | 118 ++++++++++++++++++ 9 files changed, 195 insertions(+), 97 deletions(-) create mode 100644 packages/notion-client/src/browser.ts rename packages/notion-client/src/{notion-api.test.ts => notion-api-universal.test.ts} (96%) create mode 100644 packages/notion-client/src/notion-api-universal.ts delete mode 100644 packages/notion-client/src/temp diff --git a/packages/notion-client/package.json b/packages/notion-client/package.json index 12793b79c..8ca922332 100644 --- a/packages/notion-client/package.json +++ b/packages/notion-client/package.json @@ -9,12 +9,13 @@ "main": "./build/index.js", "module": "./build/index.js", "types": "./build/index.d.ts", + "browser": "./build/browser.js", "sideEffects": false, "files": [ "build" ], "engines": { - "node": ">=12" + "node": ">=14.8" }, "scripts": { "build": "tsup", @@ -22,11 +23,14 @@ "test": "ava" }, "dependencies": { - "got": "^11.8.1", + "ky": "^0.31.4", "notion-types": "^6.15.4", "notion-utils": "^6.15.4", "p-map": "^5.3.0" }, + "optionalDependencies": { + "ky-universal": "^0.11.0" + }, "ava": { "snapshotDir": ".snapshots", "extensions": { diff --git a/packages/notion-client/src/browser.ts b/packages/notion-client/src/browser.ts new file mode 100644 index 000000000..e61382baa --- /dev/null +++ b/packages/notion-client/src/browser.ts @@ -0,0 +1,2 @@ +export * from './notion-api' +export * from './types' diff --git a/packages/notion-client/src/index.ts b/packages/notion-client/src/index.ts index e61382baa..70ab1b991 100644 --- a/packages/notion-client/src/index.ts +++ b/packages/notion-client/src/index.ts @@ -1,2 +1,2 @@ -export * from './notion-api' +export * from './notion-api-universal' export * from './types' diff --git a/packages/notion-client/src/notion-api.test.ts b/packages/notion-client/src/notion-api-universal.test.ts similarity index 96% rename from packages/notion-client/src/notion-api.test.ts rename to packages/notion-client/src/notion-api-universal.test.ts index 91f759134..726a82fd2 100644 --- a/packages/notion-client/src/notion-api.test.ts +++ b/packages/notion-client/src/notion-api-universal.test.ts @@ -1,6 +1,6 @@ import test from 'ava' -import { NotionAPI } from './notion-api' +import { NotionAPI } from './notion-api-universal' const pageIdFixturesSuccess = [ '067dd719-a912-471e-a9a3-ac10710e7fdf', diff --git a/packages/notion-client/src/notion-api-universal.ts b/packages/notion-client/src/notion-api-universal.ts new file mode 100644 index 000000000..d598a5d6e --- /dev/null +++ b/packages/notion-client/src/notion-api-universal.ts @@ -0,0 +1,4 @@ +// This adds Node.js support for `fetch` and `abort-controller` +import 'ky-universal' + +export { NotionAPI } from './notion-api' diff --git a/packages/notion-client/src/notion-api.ts b/packages/notion-client/src/notion-api.ts index 1fef7c47b..432135426 100644 --- a/packages/notion-client/src/notion-api.ts +++ b/packages/notion-client/src/notion-api.ts @@ -1,6 +1,7 @@ // import { promises as fs } from 'fs' import * as notion from 'notion-types' -import got, { OptionsOfJSONResponseBody } from 'got' +import ky from 'ky' +import type { Options as KyOptions } from 'ky' import { getBlockCollectionId, getPageContentBlockIds, @@ -19,23 +20,27 @@ export class NotionAPI { private readonly _authToken?: string private readonly _activeUser?: string private readonly _userTimeZone: string + private readonly _kyOptions?: KyOptions constructor({ apiBaseUrl = 'https://www.notion.so/api/v3', authToken, activeUser, - userTimeZone = 'America/New_York' + userTimeZone = 'America/New_York', + kyOptions }: { apiBaseUrl?: string authToken?: string userLocale?: string userTimeZone?: string activeUser?: string + kyOptions?: KyOptions } = {}) { this._apiBaseUrl = apiBaseUrl this._authToken = authToken this._activeUser = activeUser this._userTimeZone = userTimeZone + this._kyOptions = kyOptions } public async getPage( @@ -47,7 +52,7 @@ export class NotionAPI { signFileUrls = true, chunkLimit = 100, chunkNumber = 0, - gotOptions + kyOptions }: { concurrency?: number fetchMissingBlocks?: boolean @@ -55,13 +60,13 @@ export class NotionAPI { signFileUrls?: boolean chunkLimit?: number chunkNumber?: number - gotOptions?: OptionsOfJSONResponseBody + kyOptions?: KyOptions } = {} ): Promise { const page = await this.getPageRaw(pageId, { chunkLimit, chunkNumber, - gotOptions + kyOptions }) const recordMap = page?.recordMap as notion.ExtendedRecordMap @@ -91,10 +96,9 @@ export class NotionAPI { break } - const newBlocks = await this.getBlocks( - pendingBlockIds, - gotOptions - ).then((res) => res.recordMap.block) + const newBlocks = await this.getBlocks(pendingBlockIds, kyOptions).then( + (res) => res.recordMap.block + ) recordMap.block = { ...recordMap.block, ...newBlocks } } @@ -143,7 +147,7 @@ export class NotionAPI { collectionViewId, collectionView, { - gotOptions + kyOptions } ) @@ -194,7 +198,7 @@ export class NotionAPI { // because it is preferable for many use cases as opposed to making these API calls // lazily from the client-side. if (signFileUrls) { - await this.addSignedUrls({ recordMap, contentBlockIds, gotOptions }) + await this.addSignedUrls({ recordMap, contentBlockIds, kyOptions }) } return recordMap @@ -203,11 +207,11 @@ export class NotionAPI { public async addSignedUrls({ recordMap, contentBlockIds, - gotOptions = {} + kyOptions = {} }: { recordMap: notion.ExtendedRecordMap contentBlockIds?: string[] - gotOptions?: OptionsOfJSONResponseBody + kyOptions?: KyOptions }) { recordMap.signed_urls = {} @@ -255,7 +259,7 @@ export class NotionAPI { try { const { signedUrls } = await this.getSignedFileUrls( allFileInstances, - gotOptions + kyOptions ) if (signedUrls.length === allFileInstances.length) { @@ -275,13 +279,13 @@ export class NotionAPI { public async getPageRaw( pageId: string, { - gotOptions, + kyOptions, chunkLimit = 100, chunkNumber = 0 }: { chunkLimit?: number chunkNumber?: number - gotOptions?: OptionsOfJSONResponseBody + kyOptions?: KyOptions } = {} ) { const parsedPageId = parsePageId(pageId) @@ -301,7 +305,7 @@ export class NotionAPI { return this.fetch({ endpoint: 'loadPageChunk', body, - gotOptions + kyOptions }) } @@ -314,7 +318,7 @@ export class NotionAPI { searchQuery = '', userTimeZone = this._userTimeZone, loadContentCover = true, - gotOptions + kyOptions }: { type?: notion.CollectionViewType limit?: number @@ -322,7 +326,7 @@ export class NotionAPI { userTimeZone?: string userLocale?: string loadContentCover?: boolean - gotOptions?: OptionsOfJSONResponseBody + kyOptions?: KyOptions } = {} ) { const type = collectionView?.type @@ -493,27 +497,21 @@ export class NotionAPI { }, loader }, - gotOptions + kyOptions }) } - public async getUsers( - userIds: string[], - gotOptions?: OptionsOfJSONResponseBody - ) { + public async getUsers(userIds: string[], kyOptions?: KyOptions) { return this.fetch>({ endpoint: 'getRecordValues', body: { requests: userIds.map((id) => ({ id, table: 'notion_user' })) }, - gotOptions + kyOptions }) } - public async getBlocks( - blockIds: string[], - gotOptions?: OptionsOfJSONResponseBody - ) { + public async getBlocks(blockIds: string[], kyOptions?: KyOptions) { return this.fetch({ endpoint: 'syncRecordValues', body: { @@ -524,27 +522,24 @@ export class NotionAPI { version: -1 })) }, - gotOptions + kyOptions }) } public async getSignedFileUrls( urls: types.SignedUrlRequest[], - gotOptions?: OptionsOfJSONResponseBody + kyOptions?: KyOptions ) { return this.fetch({ endpoint: 'getSignedFileUrls', body: { urls }, - gotOptions + kyOptions }) } - public async search( - params: notion.SearchParams, - gotOptions?: OptionsOfJSONResponseBody - ) { + public async search(params: notion.SearchParams, kyOptions?: KyOptions) { const body = { type: 'BlocksInAncestor', source: 'quick_find_public', @@ -569,24 +564,25 @@ export class NotionAPI { return this.fetch({ endpoint: 'search', body, - gotOptions + kyOptions }) } public async fetch({ endpoint, body, - gotOptions, + kyOptions, headers: clientHeaders }: { endpoint: string body: object - gotOptions?: OptionsOfJSONResponseBody + kyOptions?: KyOptions headers?: any }): Promise { const headers: any = { ...clientHeaders, - ...gotOptions?.headers, + ...this._kyOptions?.headers, + ...kyOptions?.headers, 'Content-Type': 'application/json' } @@ -600,21 +596,13 @@ export class NotionAPI { const url = `${this._apiBaseUrl}/${endpoint}` - return got + return ky .post(url, { - ...gotOptions, + ...this._kyOptions, + ...kyOptions, json: body, headers }) .json() - - // return fetch(url, { - // method: 'post', - // body: JSON.stringify(body), - // headers - // }).then((res) => { - // console.log(endpoint, res) - // return res.json() - // }) } } diff --git a/packages/notion-client/src/temp b/packages/notion-client/src/temp deleted file mode 100644 index 9b7110123..000000000 --- a/packages/notion-client/src/temp +++ /dev/null @@ -1,31 +0,0 @@ - if (fetchParents) { - let block = recordMap.block[pageId]?.value - - while (block && block.id !== rootBlockId) { - console.log('finding parent of', block?.id) - - const parentBlockId = block.parent_id - const parentBlock = recordMap.block[parentBlockId]?.value - - if (parentBlock) { - console.log('have parent', parentBlockId) - block = parentBlock - } else { - console.log('fetching parent', parentBlockId) - - const newBlocks = await this.getBlocks([parentBlockId]).then( - (res) => res.recordMap.block - ) - - console.log('parent blocks fetched', newBlocks) - - if (!newBlocks[parentBlockId]?.value) { - // unable to find parent - break - } - - recordMap.block = { ...recordMap.block, ...newBlocks } - } - } - } - diff --git a/packages/notion-client/tsup.config.ts b/packages/notion-client/tsup.config.ts index fe76afc8c..b13f961e8 100644 --- a/packages/notion-client/tsup.config.ts +++ b/packages/notion-client/tsup.config.ts @@ -1,13 +1,26 @@ import { defineConfig } from 'tsup' -export default defineConfig({ - entry: ['src/index.ts'], - outDir: 'build', - target: 'node14', - platform: 'node', - format: ['esm'], - splitting: false, - sourcemap: true, - minify: true, - shims: false -}) +export default defineConfig([ + { + entry: ['src/index.ts'], + outDir: 'build', + target: 'node14.8', + platform: 'node', + format: ['esm'], + splitting: false, + sourcemap: true, + minify: true, + shims: false + }, + { + entry: ['src/browser.ts'], + outDir: 'build', + target: 'es2015', + platform: 'browser', + format: ['esm'], + splitting: false, + sourcemap: true, + minify: true, + shims: false + } +]) diff --git a/yarn.lock b/yarn.lock index 42639e433..e25749006 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3367,6 +3367,13 @@ abbrev@1: resolved "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz" integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== +abort-controller@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" + integrity sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg== + dependencies: + event-target-shim "^5.0.0" + accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.8: version "1.3.8" resolved "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz" @@ -5188,6 +5195,11 @@ dashdash@^1.12.0: dependencies: assert-plus "^1.0.0" +data-uri-to-buffer@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-4.0.0.tgz#b5db46aea50f6176428ac05b73be39a57701a64b" + integrity sha512-Vr3mLBA8qWmcuschSLAOogKgQ/Jwxulv3RNE4FXnYWRGujzrRWQI4m12fQqRkwX06C0KanhLr4hK+GydchZsaA== + data-urls@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz" @@ -6317,6 +6329,11 @@ etag@~1.8.1: resolved "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz" integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= +event-target-shim@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" + integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== + eventemitter3@^4.0.0, eventemitter3@^4.0.4, eventemitter3@^4.0.7: version "4.0.7" resolved "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz" @@ -6489,6 +6506,14 @@ fb-watchman@^2.0.0: dependencies: bser "2.1.1" +fetch-blob@^3.1.2, fetch-blob@^3.1.4: + version "3.2.0" + resolved "https://registry.yarnpkg.com/fetch-blob/-/fetch-blob-3.2.0.tgz#f09b8d4bbd45adc6f0c20b7e787e793e309dcce9" + integrity sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ== + dependencies: + node-domexception "^1.0.0" + web-streams-polyfill "^3.0.3" + figures@^3.0.0: version "3.2.0" resolved "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz" @@ -6668,6 +6693,13 @@ format-number@^3.0.0: resolved "https://registry.npmjs.org/format-number/-/format-number-3.0.0.tgz" integrity sha512-RWcbtINcRZ2DWCo4EcJgOJUYIwtsY5LKlTtL5OX1vfGsxEEK5mKaGxZC0p4Mgy63vXR12rut3lnjwCQ8YIlRMw== +formdata-polyfill@^4.0.10: + version "4.0.10" + resolved "https://registry.yarnpkg.com/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz#24807c31c9d402e002ab3d8c720144ceb8848423" + integrity sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g== + dependencies: + fetch-blob "^3.1.2" + forwarded@0.2.0: version "0.2.0" resolved "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz" @@ -8582,6 +8614,19 @@ klona@^2.0.4, klona@^2.0.5: resolved "https://registry.npmjs.org/klona/-/klona-2.0.5.tgz" integrity sha512-pJiBpiXMbt7dkzXe8Ghj/u4FfXOOa98fPW+bihOJ4SjnoijweJrNThJfd3ifXpXhREjpoF2mZVH1GfS9LV3kHQ== +ky-universal@^0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/ky-universal/-/ky-universal-0.11.0.tgz#f5edf857865aaaea416a1968222148ad7d9e4017" + integrity sha512-65KyweaWvk+uKKkCrfAf+xqN2/epw1IJDtlyCPxYffFCMR8u1sp2U65NtWpnozYfZxQ6IUzIlvUcw+hQ82U2Xw== + dependencies: + abort-controller "^3.0.0" + node-fetch "^3.2.10" + +ky@^0.31.4: + version "0.31.4" + resolved "https://registry.yarnpkg.com/ky/-/ky-0.31.4.tgz#c629a707053a92611cefa23079a0b0b60131b4b4" + integrity sha512-OFuAD3riwhAfHK3J4FrhlujFRpm0ELBEfDHZfFpw89OTozQt3NLF39lNblUO5udj5vSkyaBKnLai/rFCzBfISQ== + language-subtag-registry@~0.3.2: version "0.3.21" resolved "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.21.tgz" @@ -9482,6 +9527,11 @@ node-addon-api@^3.2.0: resolved "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz" integrity sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A== +node-domexception@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/node-domexception/-/node-domexception-1.0.0.tgz#6888db46a1f71c0b76b3f7555016b63fe64766e5" + integrity sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ== + node-fetch@^2.6.1: version "2.6.7" resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz" @@ -9489,6 +9539,15 @@ node-fetch@^2.6.1: dependencies: whatwg-url "^5.0.0" +node-fetch@^3.2.10: + version "3.2.10" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-3.2.10.tgz#e8347f94b54ae18b57c9c049ef641cef398a85c8" + integrity sha512-MhuzNwdURnZ1Cp4XTazr69K0BTizsBroX7Zx3UgDSVcZYKF/6p0CBe4EUb/hLqmzVhl0UpYfgRljQ4yxE+iCxA== + dependencies: + data-uri-to-buffer "^4.0.0" + fetch-blob "^3.1.4" + formdata-polyfill "^4.0.10" + node-forge@^1: version "1.3.1" resolved "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz" @@ -9602,6 +9661,41 @@ normalize-url@^7.0.3: resolved "https://registry.npmjs.org/normalize-url/-/normalize-url-7.0.3.tgz" integrity sha512-RiCOdwdPnzvwcBFJE4iI1ss3dMVRIrEzFpn8ftje6iBfzBInqlnRrNhxcLwBEKjPPXQKzm1Ptlxtaiv9wdcj5w== +notion-client@^6.15.6: + version "6.15.6" + resolved "https://registry.yarnpkg.com/notion-client/-/notion-client-6.15.6.tgz#3dfd0cbd8d2256bdbc93b5549d9cb86e3c33ced3" + integrity sha512-/ze9bHNhi09IvSo+loAelGVf2VsrnPaXoGtea/VUQq0adTvgcQhC1u37BwaK5G8bS/crVC277+KWlgdJOBIxeQ== + dependencies: + got "^11.8.1" + notion-types "^6.15.6" + notion-utils "^6.15.6" + p-map "^5.3.0" + +notion-compat@^6.15.6: + version "6.15.6" + resolved "https://registry.yarnpkg.com/notion-compat/-/notion-compat-6.15.6.tgz#5cf110407a95db45330dd49488d74b76a3506fba" + integrity sha512-M5jzca7JiinoTY7xIiLkfsbX6mpK/YiZlHnFUE3WlLxiQRItpgTTMp3BiH3Sq6L2lc28OSUT+y0u2QrFius2Ng== + dependencies: + notion-types "^6.15.6" + notion-utils "^6.15.6" + p-queue "^7.2.0" + +notion-types@^6.15.6: + version "6.15.6" + resolved "https://registry.yarnpkg.com/notion-types/-/notion-types-6.15.6.tgz#eabbb28e1c514f421f0ffbf06ecdecd90e8ec8e3" + integrity sha512-JgLWDN4oHg/1sNdHDCeKUfdPl1AYsjOTnYkq+Zn7vITPykxbhw7nIxbAJ7owWUTro1cYTPh+GVmdX0mPiZGujg== + +notion-utils@^6.15.6: + version "6.15.6" + resolved "https://registry.yarnpkg.com/notion-utils/-/notion-utils-6.15.6.tgz#d172faa2c29d62eac71b4e17ed01336d5e372d02" + integrity sha512-Ys7lQ5KWmrk9ZmpFquomQcVRdQqmZMRAl0aFhoqirVgeyKtq/i5IZoHCw8jCY8732WlaEAUnBid56nN33N2fRQ== + dependencies: + is-url-superb "^6.1.0" + mem "^9.0.2" + normalize-url "^7.0.3" + notion-types "^6.15.6" + p-queue "^7.2.0" + npm-bundled@^1.1.1: version "1.1.2" resolved "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.2.tgz" @@ -11241,6 +11335,25 @@ react-modal@^3.14.3: react-lifecycles-compat "^3.0.0" warning "^4.0.3" +react-notion-x@^6.15.6: + version "6.15.6" + resolved "https://registry.yarnpkg.com/react-notion-x/-/react-notion-x-6.15.6.tgz#af42e836dce9f5d3ece97f2796c09608c49347de" + integrity sha512-s8FVh8bs2vb32VLvPq21V0rjeWtF+U6Fudaxfx9yA6vVvQ5kgF9RRyc7eNlKpLPfq/HMEqLE52hZW+ecQ15PZQ== + dependencies: + "@fisch0920/medium-zoom" "^1.0.7" + "@matejmazur/react-katex" "^3.1.3" + katex "^0.15.3" + notion-types "^6.15.6" + notion-utils "^6.15.6" + prismjs "^1.27.0" + react-fast-compare "^3.2.0" + react-hotkeys-hook "^3.0.3" + react-image "^4.0.3" + react-lazy-images "^1.1.0" + react-modal "^3.14.3" + react-pdf "^5.7.1" + react-use "^17.3.1" + react-pdf@^5.7.1: version "5.7.1" resolved "https://registry.npmjs.org/react-pdf/-/react-pdf-5.7.1.tgz" @@ -13574,6 +13687,11 @@ wcwidth@^1.0.0: dependencies: defaults "^1.0.3" +web-streams-polyfill@^3.0.3: + version "3.2.1" + resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz#71c2718c52b45fd49dbeee88634b3a60ceab42a6" + integrity sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q== + webidl-conversions@^3.0.0: version "3.0.1" resolved "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz"