From 05102c5bc9d70c57b9eabfea6460be007ef96840 Mon Sep 17 00:00:00 2001 From: Federico Date: Fri, 5 Nov 2021 13:59:31 +0100 Subject: [PATCH] Update dependencies and lint repo --- .github/workflows/esm-lint.yml | 21 +++-- index.test-d.ts | 28 +++--- index.ts | 110 ++++++++++++------------ license | 2 +- package.json | 152 ++++++++++++++++----------------- readme.md | 14 +-- test/index.js | 43 +++++----- tsconfig.json | 9 +- 8 files changed, 189 insertions(+), 190 deletions(-) diff --git a/.github/workflows/esm-lint.yml b/.github/workflows/esm-lint.yml index cc6b5c2..b07fc1c 100644 --- a/.github/workflows/esm-lint.yml +++ b/.github/workflows/esm-lint.yml @@ -2,7 +2,9 @@ env: IMPORT_TEXT: import storageCache from NPM_MODULE_NAME: webext-storage-cache -# DO NOT EDIT BELOW, USE: npx ghat fregante/ghatemplates/esm-lint --exclude 'jobs.Node' --exclude 'jobs.Rollup' +# FILE GENERATED WITH: npx ghat fregante/ghatemplates/esm-lint +# SOURCE: https://github.com/fregante/ghatemplates +# OPTIONS: {"exclude":["jobs.Node","jobs.Rollup"]} name: ESM on: @@ -12,6 +14,7 @@ on: push: branches: - master + - main jobs: Pack: runs-on: ubuntu-latest @@ -20,7 +23,7 @@ jobs: - run: npm install - run: npm run build --if-present - run: npm pack --dry-run - - run: npm pack --silent 2>/dev/null | xargs cat | tar -xz + - run: npm pack --silent 2>/dev/null | xargs -n1 tar -xzf - uses: actions/upload-artifact@v2 with: path: package @@ -30,8 +33,8 @@ jobs: steps: - uses: actions/download-artifact@v2 - run: npm install ./artifact - - run: 'echo "${{ env.IMPORT_TEXT }} ''${{ env.NPM_MODULE_NAME }}''" > index.js' - - run: webpack ./index.js + - run: echo "${{ env.IMPORT_TEXT }} '${{ env.NPM_MODULE_NAME }}'" > index.js + - run: webpack --entry ./index.js - run: cat dist/main.js Parcel: runs-on: ubuntu-latest @@ -39,16 +42,16 @@ jobs: steps: - uses: actions/download-artifact@v2 - run: npm install ./artifact - - run: 'echo "${{ env.IMPORT_TEXT }} ''${{ env.NPM_MODULE_NAME }}''" > index.js' - - run: npx parcel@1 build index.js + - run: echo "${{ env.IMPORT_TEXT }} '${{ env.NPM_MODULE_NAME }}'" > index.js + - run: npx parcel@2 build index.js - run: cat dist/index.js Snowpack: runs-on: ubuntu-latest needs: Pack steps: - uses: actions/download-artifact@v2 - - run: 'echo ''{}'' > package.json' - - run: 'echo "${{ env.IMPORT_TEXT }} ''${{ env.NPM_MODULE_NAME }}''" > index.js' + - run: echo '{}' > package.json + - run: echo "${{ env.IMPORT_TEXT }} '${{ env.NPM_MODULE_NAME }}'" > index.js - run: npm install ./artifact - run: npx snowpack@2 build - run: cat build/web_modules/$NPM_MODULE_NAME.js @@ -58,6 +61,6 @@ jobs: steps: - uses: actions/download-artifact@v2 - run: npm install ./artifact - - run: 'echo "${{ env.IMPORT_TEXT }} ''${{ env.NPM_MODULE_NAME }}''" > index.ts' + - run: echo "${{ env.IMPORT_TEXT }} '${{ env.NPM_MODULE_NAME }}'" > index.ts - run: tsc index.ts - run: cat index.js diff --git a/index.test-d.ts b/index.test-d.ts index 8637ed9..1bfbb09 100644 --- a/index.test-d.ts +++ b/index.test-d.ts @@ -22,16 +22,16 @@ expectType<(n: number) => Promise>(cachedPower); expectType(await cachedPower(1)); expectType<(n: string) => Promise>( - cache.function(async (n: string) => Number(n)) + cache.function(async (n: string) => Number(n)), ); expectType<(n: string) => Promise>( - cache.function(async (n: string) => Number(n)) + cache.function(async (n: string) => Number(n)), ); -async function identity(x: string): Promise ; -async function identity(x: number): Promise ; -async function identity(x: number | string): Promise { +async function identity(x: string): Promise; +async function identity(x: number): Promise; +async function identity(x: number | string): Promise { return x; } @@ -42,30 +42,30 @@ expectNotAssignable>(cache.function(identity)('1')); expectType<(n: string) => Promise>( cache.function(async (n: string) => Number(n), { - maxAge: {days: 20} - }) + maxAge: {days: 20}, + }), ); expectType<(n: string) => Promise>( cache.function(async (n: string) => Number(n), { maxAge: {days: 20}, - staleWhileRevalidate: {days: 5} - }) + staleWhileRevalidate: {days: 5}, + }), ); expectType<(date: Date) => Promise>( cache.function(async (date: Date) => String(date.getHours()), { - cacheKey: ([date]) => date.toLocaleString() - }) + cacheKey: ([date]) => date.toLocaleString(), + }), ); expectType<(date: Date) => Promise>( cache.function(async (date: Date) => String(date.getHours()), { - shouldRevalidate: date => typeof date === 'string' - }) + shouldRevalidate: date => typeof date === 'string', + }), ); // This function won't be cached expectType<(n: undefined[]) => Promise>( - cache.function(async (n: undefined[]) => n[1]) + cache.function(async (n: undefined[]) => n[1]), ); diff --git a/index.ts b/index.ts index b1d28bc..1719503 100644 --- a/index.ts +++ b/index.ts @@ -1,50 +1,34 @@ import microMemoize from 'micro-memoize'; import {isBackgroundPage} from 'webext-detect-page'; import toMilliseconds, {TimeDescriptor} from '@sindresorhus/to-milliseconds'; - -// @ts-expect-error -// eslint-disable-next-line @typescript-eslint/promise-function-async -const getPromise = (executor: () => void) => (key?): Promise => new Promise((resolve, reject) => { - // @ts-expect-error - executor(key, result => { - if (chrome.runtime.lastError) { - reject(chrome.runtime.lastError); - } else { - resolve(result); - } - }); -}); +import chromeP from 'webext-polyfill-kinda'; function timeInTheFuture(time: TimeDescriptor): number { return Date.now() + toMilliseconds(time); } -// @ts-expect-error -const storageGet = getPromise((...args) => chrome.storage.local.get(...args)); -// @ts-expect-error -const storageSet = getPromise((...args) => chrome.storage.local.set(...args)); -// @ts-expect-error -const storageRemove = getPromise((...args) => chrome.storage.local.remove(...args)); - type Primitive = boolean | number | string; type Value = Primitive | Primitive[] | Record; // No circular references: Record https://github.com/Microsoft/TypeScript/issues/14174 // No index signature: {[key: string]: Value} https://github.com/microsoft/TypeScript/issues/15300#issuecomment-460226926 -interface CacheItem { - data: TValue; +interface CacheItem { + data: Value; maxAge: number; } -type Cache = Record>; +type Cache = Record>; async function has(key: string): Promise { - return await _get(key, false) !== undefined; + return (await _get(key, false)) !== undefined; } -async function _get(key: string, remove: boolean): Promise | undefined> { +async function _get( + key: string, + remove: boolean, +): Promise | undefined> { const internalKey = `cache:${key}`; - const storageData = await storageGet>(internalKey); + const storageData = await chromeP.storage.local.get(internalKey) as Cache; const cachedItem = storageData[internalKey]; if (cachedItem === undefined) { @@ -54,7 +38,7 @@ async function _get(key: string, remove: boolean): Promise if (Date.now() > cachedItem.maxAge) { if (remove) { - await storageRemove(internalKey); + await chromeP.storage.local.remove(internalKey); } return; @@ -63,11 +47,17 @@ async function _get(key: string, remove: boolean): Promise return cachedItem; } -async function get(key: string): Promise { - return (await _get(key, true))?.data; +async function get( + key: string, +): Promise { + return (await _get(key, true))?.data; } -async function set(key: string, value: TValue, maxAge: TimeDescriptor = {days: 30}): Promise { +async function set( + key: string, + value: ScopedValue, + maxAge: TimeDescriptor = {days: 30}, +): Promise { if (arguments.length < 2) { throw new TypeError('Expected a value as the second argument'); } @@ -76,11 +66,11 @@ async function set(key: string, value: TValue, maxAge: Tim await delete_(key); } else { const internalKey = `cache:${key}`; - await storageSet({ + await chromeP.storage.local.set({ [internalKey]: { data: value, - maxAge: timeInTheFuture(maxAge) - } + maxAge: timeInTheFuture(maxAge), + }, }); } @@ -89,11 +79,13 @@ async function set(key: string, value: TValue, maxAge: Tim async function delete_(key: string): Promise { const internalKey = `cache:${key}`; - return storageRemove(internalKey); + return chromeP.storage.local.remove(internalKey); } -async function deleteWithLogic(logic?: (x: CacheItem) => boolean): Promise { - const wholeCache = await storageGet>(); +async function deleteWithLogic( + logic?: (x: CacheItem) => boolean, +): Promise { + const wholeCache = (await chromeP.storage.local.get()) as Record; const removableItems = []; for (const [key, value] of Object.entries(wholeCache)) { if (key.startsWith('cache:') && (logic?.(value) ?? true)) { @@ -102,7 +94,7 @@ async function deleteWithLogic(logic?: (x: CacheItem) => boolean): Promis } if (removableItems.length > 0) { - await storageRemove(removableItems); + await chromeP.storage.local.remove(removableItems); } } @@ -114,22 +106,30 @@ async function clear(): Promise { await deleteWithLogic(); } -interface MemoizedFunctionOptions { +interface MemoizedFunctionOptions { maxAge?: TimeDescriptor; staleWhileRevalidate?: TimeDescriptor; - cacheKey?: (args: TArgs) => string; - shouldRevalidate?: (cachedValue: TValue) => boolean; + cacheKey?: (args: Arguments) => string; + shouldRevalidate?: (cachedValue: ScopedValue) => boolean; } function function_< - TValue extends Value, - TFunction extends (...args: any[]) => Promise, - TArgs extends Parameters + ScopedValue extends Value, + Getter extends (...args: any[]) => Promise, + Arguments extends Parameters, >( - getter: TFunction, - {cacheKey, maxAge = {days: 30}, staleWhileRevalidate = {days: 0}, shouldRevalidate}: MemoizedFunctionOptions = {} -): TFunction { - const getSet = async (key: string, args: TArgs): Promise => { + getter: Getter, + { + cacheKey, + maxAge = {days: 30}, + staleWhileRevalidate = {days: 0}, + shouldRevalidate, + }: MemoizedFunctionOptions = {}, +): Getter { + const getSet = async ( + key: string, + args: Arguments, + ): Promise => { const freshValue = await getter(...args); if (freshValue === undefined) { await delete_(key); @@ -138,12 +138,12 @@ function function_< const milliseconds = toMilliseconds(maxAge) + toMilliseconds(staleWhileRevalidate); - return set(key, freshValue, {milliseconds}); + return set(key, freshValue, {milliseconds}); }; - return microMemoize((async (...args: TArgs) => { - const userKey = cacheKey ? cacheKey(args) : args[0] as string; - const cachedItem = await _get(userKey, false); + return microMemoize((async (...args: Arguments) => { + const userKey = cacheKey ? cacheKey(args) : (args[0] as string); + const cachedItem = await _get(userKey, false); if (cachedItem === undefined || shouldRevalidate?.(cachedItem.data)) { return getSet(userKey, args); } @@ -154,7 +154,7 @@ function function_< } return cachedItem.data; - }) as TFunction); + }) as Getter); } const cache = { @@ -163,7 +163,7 @@ const cache = { set, clear, function: function_, - delete: delete_ + delete: delete_, }; function init(): void { @@ -178,7 +178,7 @@ function init(): void { if (chrome.alarms) { chrome.alarms.create('webext-storage-cache', { delayInMinutes: 1, - periodInMinutes: 60 * 24 + periodInMinutes: 60 * 24, }); let lastRun = 0; // Homemade debouncing due to `chrome.alarms` potentially queueing this function @@ -189,7 +189,7 @@ function init(): void { } }); } else { - setTimeout(deleteExpired, 60000); // Purge cache on launch, but wait a bit + setTimeout(deleteExpired, 60_000); // Purge cache on launch, but wait a bit setInterval(deleteExpired, 1000 * 3600 * 24); } } diff --git a/license b/license index 4f98a21..e342b5c 100644 --- a/license +++ b/license @@ -1,6 +1,6 @@ MIT License -Copyright (c) Federico Brigante (bfred.it) +Copyright (c) Federico Brigante (https://fregante.com) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: diff --git a/package.json b/package.json index 8b770a2..f7ac4a2 100644 --- a/package.json +++ b/package.json @@ -1,79 +1,77 @@ { - "name": "webext-storage-cache", - "version": "4.2.0", - "description": "WebExtensions module: Map-like promised cache storage with expiration. Chrome and Firefox.", - "keywords": [ - "await", - "background page", - "browser", - "cache", - "chrome", - "content script", - "expirating", - "extension", - "firefox", - "map", - "options page", - "promises", - "self-cleaning", - "temporary", - "web-ext", - "webext" - ], - "repository": "fregante/webext-storage-cache", - "license": "MIT", - "author": "Federico Brigante (bfred.it)", - "contributors": [ - "Connor Love" - ], - "type": "module", - "main": "index.js", - "module": "index.js", - "files": [ - "index.js", - "index.d.ts" - ], - "scripts": { - "build": "tsc", - "prepack": "tsc --sourceMap false", - "test": "tsc && tsd && ava && xo", - "watch": "tsc --watch" - }, - "xo": { - "envs": [ - "browser", - "webextensions" - ], - "rules": { - "@typescript-eslint/return-await": 0, - "import/extensions": 0, - "import/no-unassigned-import": 0, - "import/no-useless-path-segments": 0, - "no-promise-executor-return": 0, - "unicorn/import-index": 0, - "unicorn/no-object-as-default-parameter": 0 - } - }, - "ava": { - "nodeArguments": [ - "--experimental-modules" - ] - }, - "dependencies": { - "@sindresorhus/to-milliseconds": "^1.2.0", - "micro-memoize": "^4.0.9", - "webext-detect-page": "^2.0.5" - }, - "devDependencies": { - "@babel/core": "^7.12.7", - "@sindresorhus/tsconfig": "^0.8.0", - "@types/chrome": "0.0.126", - "@types/sinon-chrome": "^2.2.10", - "ava": "^3.13.0", - "sinon": "^9.2.1", - "sinon-chrome": "^3.0.1", - "tsd": "^0.13.1", - "typescript": "^4.1.2", - "xo": "^0.35.0" - } + "name": "webext-storage-cache", + "version": "4.2.0", + "description": "Map-like promised cache storage with expiration. WebExtensions module for Chrome, Firefox, Safari", + "keywords": [ + "await", + "background page", + "browser", + "cache", + "chrome", + "content script", + "expirating", + "extension", + "firefox", + "map", + "options page", + "promises", + "self-cleaning", + "temporary", + "web-ext", + "webext" + ], + "repository": "fregante/webext-storage-cache", + "funding": "https://github.com/sponsors/fregante", + "license": "MIT", + "author": "Federico Brigante (https://fregante.com)", + "contributors": [ + "Connor Love" + ], + "type": "module", + "main": "index.js", + "module": "index.js", + "files": [ + "index.js", + "index.d.ts" + ], + "scripts": { + "build": "tsc", + "prepack": "tsc --sourceMap false", + "test": "tsc && tsd && ava && xo", + "watch": "tsc --watch" + }, + "xo": { + "envs": [ + "browser", + "webextensions" + ], + "rules": { + "@typescript-eslint/return-await": 0, + "import/extensions": 0, + "import/no-unassigned-import": 0, + "import/no-useless-path-segments": 0, + "no-promise-executor-return": 0, + "unicorn/import-index": 0, + "unicorn/no-object-as-default-parameter": 0 + } + }, + "dependencies": { + "@sindresorhus/to-milliseconds": "^2.0.0", + "micro-memoize": "^4.0.9", + "webext-detect-page": "^3.1.0", + "webext-polyfill-kinda": "^0.9.0" + }, + "devDependencies": { + "@babel/core": "^7.16.0", + "@sindresorhus/tsconfig": "^2.0.0", + "@types/chrome": "0.0.163", + "@types/firefox-webext-browser": "^94.0.0", + "@types/sinon-chrome": "^2.2.11", + "ava": "^3.15.0", + "sinon": "^12.0.1", + "sinon-chrome": "^3.0.1", + "tsd": "^0.18.0", + "typescript": "^4.4.4", + "xo": "^0.46.4" + } } diff --git a/readme.md b/readme.md index 96e7479..dfef7b8 100644 --- a/readme.md +++ b/readme.md @@ -247,13 +247,13 @@ const json = await cachedGetHTML('https://google.com'); ## Related -* [webext-options-sync](https://github.com/fregante/webext-options-sync) - Helps you manage and autosave your extension's options. -* [webext-domain-permission-toggle](https://github.com/fregante/webext-domain-permission-toggle) - Browser-action context menu to request permission for the current tab. -* [webext-dynamic-content-scripts](https://github.com/fregante/webext-dynamic-content-scripts) - Automatically inject your `content_scripts` on custom domains. -* [webext-detect-page](https://github.com/fregante/webext-detect-page) - Detects where the current browser extension code is being run. -* [webext-content-script-ping](https://github.com/fregante/webext-content-script-ping) - One-file interface to detect whether your content script have loaded. -* [`Awesome WebExtensions`](https://github.com/fregante/Awesome-WebExtensions): A curated list of awesome resources for Web Extensions development. +- [webext-detect-page](https://github.com/fregante/webext-detect-page) - Detects where the current browser extension code is being run. +- [webext-dynamic-content-scripts](https://github.com/fregante/webext-dynamic-content-scripts) - Automatically registers your content_scripts on domains added via permission.request +- [webext-options-sync](https://github.com/fregante/webext-options-sync) - Helps you manage and autosave your extension's options. +- [webext-detect-page](https://github.com/fregante/webext-detect-page) - Detects where the current browser extension code is being run. +- [webext-base-css](https://github.com/fregante/webext-base-css) - Extremely minimal stylesheet/setup for Web Extensions’ options pages (also dark mode) +- [More…](https://github.com/fregante/webext-fun) ## License -MIT © [Federico Brigante](https://bfred.it) +MIT © [Federico Brigante](https://fregante.com) diff --git a/test/index.js b/test/index.js index 873cf23..42ba8cd 100644 --- a/test/index.js +++ b/test/index.js @@ -1,8 +1,8 @@ import test from 'ava'; import sinon from 'sinon'; import './_fixtures.js'; -import cache from '../index.js'; import toMilliseconds from '@sindresorhus/to-milliseconds'; +import cache from '../index.js'; const getUsernameDemo = async name => name.slice(1).toUpperCase(); @@ -16,7 +16,7 @@ function createCache(daysFromToday, wholeCache) { .withArgs(key) .yields({[key]: { data, - maxAge: timeInTheFuture({days: daysFromToday}) + maxAge: timeInTheFuture({days: daysFromToday}), }}); } } @@ -34,14 +34,14 @@ test.serial('get() with empty cache', async t => { test.serial('get() with cache', async t => { createCache(10, { - 'cache:name': 'Rico' + 'cache:name': 'Rico', }); t.is(await cache.get('name'), 'Rico'); }); test.serial('get() with expired cache', async t => { createCache(-10, { - 'cache:name': 'Rico' + 'cache:name': 'Rico', }); t.is(await cache.get('name'), undefined); }); @@ -52,20 +52,23 @@ test.serial('has() with empty cache', async t => { test.serial('has() with cache', async t => { createCache(10, { - 'cache:name': 'Rico' + 'cache:name': 'Rico', }); t.is(await cache.has('name'), true); }); test.serial('has() with expired cache', async t => { createCache(-10, { - 'cache:name': 'Rico' + 'cache:name': 'Rico', }); t.is(await cache.has('name'), false); }); test.serial('set() without a value', async t => { - await t.throwsAsync(cache.set('name'), {instanceOf: TypeError, message: 'Expected a value as the second argument'}); + await t.throwsAsync(cache.set('name'), { + instanceOf: TypeError, + message: 'Expected a value as the second argument', + }); }); test.serial('set() with undefined', async t => { @@ -99,7 +102,7 @@ test.serial('function() with empty cache', async t => { test.serial('function() with cache', async t => { createCache(10, { - 'cache:@anne': 'ANNE' + 'cache:@anne': 'ANNE', }); const spy = sinon.spy(getUsernameDemo); @@ -114,7 +117,7 @@ test.serial('function() with cache', async t => { test.serial('function() with expired cache', async t => { createCache(-10, { - 'cache:@anne': 'ONNA' + 'cache:@anne': 'ONNA', }); const spy = sinon.spy(getUsernameDemo); @@ -135,7 +138,7 @@ test.serial('function() with empty cache and staleWhileRevalidate', async t => { const spy = sinon.spy(getUsernameDemo); const call = cache.function(spy, { maxAge: {days: maxAge}, - staleWhileRevalidate: {days: staleWhileRevalidate} + staleWhileRevalidate: {days: staleWhileRevalidate}, }); t.is(await call('@anne'), 'ANNE'); @@ -153,13 +156,13 @@ test.serial('function() with empty cache and staleWhileRevalidate', async t => { test.serial('function() with fresh cache and staleWhileRevalidate', async t => { createCache(30, { - 'cache:@anne': 'ANNE' + 'cache:@anne': 'ANNE', }); const spy = sinon.spy(getUsernameDemo); const call = cache.function(spy, { maxAge: {days: 1}, - staleWhileRevalidate: {days: 29} + staleWhileRevalidate: {days: 29}, }); t.is(await call('@anne'), 'ANNE'); @@ -176,13 +179,13 @@ test.serial('function() with fresh cache and staleWhileRevalidate', async t => { test.serial('function() with stale cache and staleWhileRevalidate', async t => { createCache(15, { - 'cache:@anne': 'ANNE' + 'cache:@anne': 'ANNE', }); const spy = sinon.spy(getUsernameDemo); const call = cache.function(spy, { maxAge: {days: 1}, - staleWhileRevalidate: {days: 29} + staleWhileRevalidate: {days: 29}, }); t.is(await call('@anne'), 'ANNE'); @@ -201,7 +204,7 @@ test.serial('function() with stale cache and staleWhileRevalidate', async t => { test.serial('function() varies cache by function argument', async t => { createCache(10, { - 'cache:@anne': 'ANNE' + 'cache:@anne': 'ANNE', }); const spy = sinon.spy(getUsernameDemo); @@ -216,7 +219,7 @@ test.serial('function() varies cache by function argument', async t => { test.serial('function() ignores second argument by default', async t => { createCache(10, { - 'cache:@anne': 'ANNE' + 'cache:@anne': 'ANNE', }); const spy = sinon.spy(getUsernameDemo); @@ -229,12 +232,12 @@ test.serial('function() ignores second argument by default', async t => { test.serial('function() accepts custom cache key generator', async t => { createCache(10, { - 'cache:@anne,1': 'ANNE,1' + 'cache:@anne,1': 'ANNE,1', }); const spy = sinon.spy(getUsernameDemo); const call = cache.function(spy, { - cacheKey: arguments_ => arguments_.join() + cacheKey: arguments_ => arguments_.join(','), }); await call('@anne', 1); @@ -249,12 +252,12 @@ test.serial('function() accepts custom cache key generator', async t => { test.serial('function() verifies cache with shouldRevalidate callback', async t => { createCache(10, { - 'cache:@anne': '@anne' + 'cache:@anne': '@anne', }); const spy = sinon.spy(getUsernameDemo); const call = cache.function(spy, { - shouldRevalidate: value => value.startsWith('@') + shouldRevalidate: value => value.startsWith('@'), }); t.is(await call('@anne'), 'ANNE'); diff --git a/tsconfig.json b/tsconfig.json index 554c662..57ddcfc 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,13 +1,8 @@ { - "extends": "@sindresorhus/tsconfig", + "extends": "@sindresorhus/tsconfig/tsconfig.json", "compilerOptions": { "outDir": ".", - "target": "es2018", - "module": "esnext", - "noUncheckedIndexedAccess": false, - "lib": [ - "DOM" - ] + "noUncheckedIndexedAccess": false }, "files": [ "index.ts"