vendor: 11,656 bytes, lines 1-305
1const instanceOfAny = (object, constructors) => constructors.some((c) => object instanceof c); 2 3let idbProxyableTypes; 4let cursorAdvanceMethods; 5// This is a function to prevent it throwing up in node environments. 6function getIdbProxyableTypes() { 7 return (idbProxyableTypes || 8 (idbProxyableTypes = [ 9 IDBDatabase, 10 IDBObjectStore, 11 IDBIndex, 12 IDBCursor, 13 IDBTransaction, 14 ])); 15} 16// This is a function to prevent it throwing up in node environments. 17function getCursorAdvanceMethods() { 18 return (cursorAdvanceMethods || 19 (cursorAdvanceMethods = [ 20 IDBCursor.prototype.advance, 21 IDBCursor.prototype.continue, 22 IDBCursor.prototype.continuePrimaryKey, 23 ])); 24} 25const transactionDoneMap = new WeakMap(); 26const transformCache = new WeakMap(); 27const reverseTransformCache = new WeakMap(); 28function promisifyRequest(request) { 29 const promise = new Promise((resolve, reject) => { 30 const unlisten = () => { 31 request.removeEventListener('success', success); 32 request.removeEventListener('error', error); 33 }; 34 const success = () => { 35 resolve(wrap(request.result)); 36 unlisten(); 37 }; 38 const error = () => { 39 reject(request.error); 40 unlisten(); 41 }; 42 request.addEventListener('success', success); 43 request.addEventListener('error', error); 44 }); 45 // This mapping exists in reverseTransformCache but doesn't exist in transformCache. This 46 // is because we create many promises from a single IDBRequest. 47 reverseTransformCache.set(promise, request); 48 return promise; 49} 50function cacheDonePromiseForTransaction(tx) { 51 // Early bail if we've already created a done promise for this transaction. 52 if (transactionDoneMap.has(tx)) 53 return; 54 const done = new Promise((resolve, reject) => { 55 const unlisten = () => { 56 tx.removeEventListener('complete', complete); 57 tx.removeEventListener('error', error); 58 tx.removeEventListener('abort', error); 59 }; 60 const complete = () => { 61 resolve(); 62 unlisten(); 63 }; 64 const error = () => { 65 reject(tx.error || new DOMException('AbortError', 'AbortError')); 66 unlisten(); 67 }; 68 tx.addEventListener('complete', complete); 69 tx.addEventListener('error', error); 70 tx.addEventListener('abort', error); 71 }); 72 // Cache it for later retrieval. 73 transactionDoneMap.set(tx, done); 74} 75let idbProxyTraps = { 76 get(target, prop, receiver) { 77 if (target instanceof IDBTransaction) { 78 // Special handling for transaction.done. 79 if (prop === 'done') 80 return transactionDoneMap.get(target); 81 // Make tx.store return the only store in the transaction, or undefined if there are many. 82 if (prop === 'store') { 83 return receiver.objectStoreNames[1] 84 ? undefined 85 : receiver.objectStore(receiver.objectStoreNames[0]); 86 } 87 } 88 // Else transform whatever we get back. 89 return wrap(target[prop]); 90 }, 91 set(target, prop, value) { 92 target[prop] = value; 93 return true; 94 }, 95 has(target, prop) { 96 if (target instanceof IDBTransaction && 97 (prop === 'done' || prop === 'store')) { 98 return true; 99 } 100 return prop in target; 101 }, 102}; 103function replaceTraps(callback) { 104 idbProxyTraps = callback(idbProxyTraps); 105} 106function wrapFunction(func) { 107 // Due to expected object equality (which is enforced by the caching in `wrap`), we 108 // only create one new func per func. 109 // Cursor methods are special, as the behaviour is a little more different to standard IDB. In 110 // IDB, you advance the cursor and wait for a new 'success' on the IDBRequest that gave you the 111 // cursor. It's kinda like a promise that can resolve with many values. That doesn't make sense 112 // with real promises, so each advance methods returns a new promise for the cursor object, or 113 // undefined if the end of the cursor has been reached. 114 if (getCursorAdvanceMethods().includes(func)) { 115 return function (...args) { 116 // Calling the original function with the proxy as 'this' causes ILLEGAL INVOCATION, so we use 117 // the original object. 118 func.apply(unwrap(this), args); 119 return wrap(this.request); 120 }; 121 } 122 return function (...args) { 123 // Calling the original function with the proxy as 'this' causes ILLEGAL INVOCATION, so we use 124 // the original object. 125 return wrap(func.apply(unwrap(this), args)); 126 }; 127} 128function transformCachableValue(value) { 129 if (typeof value === 'function') 130 return wrapFunction(value); 131 // This doesn't return, it just creates a 'done' promise for the transaction, 132 // which is later returned for transaction.done (see idbObjectHandler). 133 if (value instanceof IDBTransaction) 134 cacheDonePromiseForTransaction(value); 135 if (instanceOfAny(value, getIdbProxyableTypes())) 136 return new Proxy(value, idbProxyTraps); 137 // Return the same value back if we're not going to transform it. 138 return value; 139} 140function wrap(value) { 141 // We sometimes generate multiple promises from a single IDBRequest (eg when cursoring), because 142 // IDB is weird and a single IDBRequest can yield many responses, so these can't be cached. 143 if (value instanceof IDBRequest) 144 return promisifyRequest(value); 145 // If we've already transformed this value before, reuse the transformed value. 146 // This is faster, but it also provides object equality. 147 if (transformCache.has(value)) 148 return transformCache.get(value); 149 const newValue = transformCachableValue(value); 150 // Not all types are transformed. 151 // These may be primitive types, so they can't be WeakMap keys. 152 if (newValue !== value) { 153 transformCache.set(value, newValue); 154 reverseTransformCache.set(newValue, value); 155 } 156 return newValue; 157} 158const unwrap = (value) => reverseTransformCache.get(value); 159 160/** 161 * Open a database. 162 * 163 * @param name Name of the database. 164 * @param version Schema version. 165 * @param callbacks Additional callbacks. 166 */ 167function openDB(name, version, { blocked, upgrade, blocking, terminated } = {}) { 168 const request = indexedDB.open(name, version); 169 const openPromise = wrap(request); 170 if (upgrade) { 171 request.addEventListener('upgradeneeded', (event) => { 172 upgrade(wrap(request.result), event.oldVersion, event.newVersion, wrap(request.transaction), event); 173 }); 174 } 175 if (blocked) { 176 request.addEventListener('blocked', (event) => blocked( 177 // Casting due to https://github.com/microsoft/TypeScript-DOM-lib-generator/pull/1405 178 event.oldVersion, event.newVersion, event)); 179 } 180 openPromise 181 .then((db) => { 182 if (terminated) 183 db.addEventListener('close', () => terminated()); 184 if (blocking) { 185 db.addEventListener('versionchange', (event) => blocking(event.oldVersion, event.newVersion, event)); 186 } 187 }) 188 .catch(() => { }); 189 return openPromise; 190} 191/** 192 * Delete a database. 193 * 194 * @param name Name of the database. 195 */ 196function deleteDB(name, { blocked } = {}) { 197 const request = indexedDB.deleteDatabase(name); 198 if (blocked) { 199 request.addEventListener('blocked', (event) => blocked( 200 // Casting due to https://github.com/microsoft/TypeScript-DOM-lib-generator/pull/1405 201 event.oldVersion, event)); 202 } 203 return wrap(request).then(() => undefined); 204} 205 206const readMethods = ['get', 'getKey', 'getAll', 'getAllKeys', 'count']; 207const writeMethods = ['put', 'add', 'delete', 'clear']; 208const cachedMethods = new Map(); 209function getMethod(target, prop) { 210 if (!(target instanceof IDBDatabase && 211 !(prop in target) && 212 typeof prop === 'string')) { 213 return; 214 } 215 if (cachedMethods.get(prop)) 216 return cachedMethods.get(prop); 217 const targetFuncName = prop.replace(/FromIndex$/, ''); 218 const useIndex = prop !== targetFuncName; 219 const isWrite = writeMethods.includes(targetFuncName); 220 if ( 221 // Bail if the target doesn't exist on the target. Eg, getAll isn't in Edge. 222 !(targetFuncName in (useIndex ? IDBIndex : IDBObjectStore).prototype) || 223 !(isWrite || readMethods.includes(targetFuncName))) { 224 return; 225 } 226 const method = async function (storeName, ...args) { 227 // isWrite ? 'readwrite' : undefined gzipps better, but fails in Edge :( 228 const tx = this.transaction(storeName, isWrite ? 'readwrite' : 'readonly'); 229 let target = tx.store; 230 if (useIndex) 231 target = target.index(args.shift()); 232 // Must reject if op rejects. 233 // If it's a write operation, must reject if tx.done rejects. 234 // Must reject with op rejection first. 235 // Must resolve with op value. 236 // Must handle both promises (no unhandled rejections) 237 return (await Promise.all([ 238 target[targetFuncName](...args), 239 isWrite && tx.done, 240 ]))[0]; 241 }; 242 cachedMethods.set(prop, method); 243 return method; 244} 245replaceTraps((oldTraps) => ({ 246 ...oldTraps, 247 get: (target, prop, receiver) => getMethod(target, prop) || oldTraps.get(target, prop, receiver), 248 has: (target, prop) => !!getMethod(target, prop) || oldTraps.has(target, prop), 249})); 250 251const advanceMethodProps = ['continue', 'continuePrimaryKey', 'advance']; 252const methodMap = {}; 253const advanceResults = new WeakMap(); 254const ittrProxiedCursorToOriginalProxy = new WeakMap(); 255const cursorIteratorTraps = { 256 get(target, prop) { 257 if (!advanceMethodProps.includes(prop)) 258 return target[prop]; 259 let cachedFunc = methodMap[prop]; 260 if (!cachedFunc) { 261 cachedFunc = methodMap[prop] = function (...args) { 262 advanceResults.set(this, ittrProxiedCursorToOriginalProxy.get(this)[prop](...args)); 263 }; 264 } 265 return cachedFunc; 266 }, 267}; 268async function* iterate(...args) { 269 // tslint:disable-next-line:no-this-assignment 270 let cursor = this; 271 if (!(cursor instanceof IDBCursor)) { 272 cursor = await cursor.openCursor(...args); 273 } 274 if (!cursor) 275 return; 276 cursor = cursor; 277 const proxiedCursor = new Proxy(cursor, cursorIteratorTraps); 278 ittrProxiedCursorToOriginalProxy.set(proxiedCursor, cursor); 279 // Map this double-proxy back to the original, so other cursor methods work. 280 reverseTransformCache.set(proxiedCursor, unwrap(cursor)); 281 while (cursor) { 282 yield proxiedCursor; 283 // If one of the advancing methods was not called, call continue(). 284 cursor = await (advanceResults.get(proxiedCursor) || cursor.continue()); 285 advanceResults.delete(proxiedCursor); 286 } 287} 288function isIteratorProp(target, prop) { 289 return ((prop === Symbol.asyncIterator && 290 instanceOfAny(target, [IDBIndex, IDBObjectStore, IDBCursor])) || 291 (prop === 'iterate' && instanceOfAny(target, [IDBIndex, IDBObjectStore]))); 292} 293replaceTraps((oldTraps) => ({ 294 ...oldTraps, 295 get(target, prop, receiver) { 296 if (isIteratorProp(target, prop)) 297 return iterate; 298 return oldTraps.get(target, prop, receiver); 299 }, 300 has(target, prop) { 301 return isIteratorProp(target, prop) || oldTraps.has(target, prop); 302 }, 303})); 304 305export { deleteDB, openDB, unwrap, wrap };
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.