index.cjs 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. 'use strict';
  2. Object.defineProperty(exports, '__esModule', { value: true });
  3. function promisifyRequest(request) {
  4. return new Promise((resolve, reject) => {
  5. // @ts-ignore - file size hacks
  6. request.oncomplete = request.onsuccess = () => resolve(request.result);
  7. // @ts-ignore - file size hacks
  8. request.onabort = request.onerror = () => reject(request.error);
  9. });
  10. }
  11. function createStore(dbName, storeName) {
  12. const request = indexedDB.open(dbName);
  13. request.onupgradeneeded = () => request.result.createObjectStore(storeName);
  14. const dbp = promisifyRequest(request);
  15. return (txMode, callback) => dbp.then((db) => callback(db.transaction(storeName, txMode).objectStore(storeName)));
  16. }
  17. let defaultGetStoreFunc;
  18. function defaultGetStore() {
  19. if (!defaultGetStoreFunc) {
  20. defaultGetStoreFunc = createStore('keyval-store', 'keyval');
  21. }
  22. return defaultGetStoreFunc;
  23. }
  24. /**
  25. * Get a value by its key.
  26. *
  27. * @param key
  28. * @param customStore Method to get a custom store. Use with caution (see the docs).
  29. */
  30. function get(key, customStore = defaultGetStore()) {
  31. return customStore('readonly', (store) => promisifyRequest(store.get(key)));
  32. }
  33. /**
  34. * Set a value with a key.
  35. *
  36. * @param key
  37. * @param value
  38. * @param customStore Method to get a custom store. Use with caution (see the docs).
  39. */
  40. function set(key, value, customStore = defaultGetStore()) {
  41. return customStore('readwrite', (store) => {
  42. store.put(value, key);
  43. return promisifyRequest(store.transaction);
  44. });
  45. }
  46. /**
  47. * Set multiple values at once. This is faster than calling set() multiple times.
  48. * It's also atomic – if one of the pairs can't be added, none will be added.
  49. *
  50. * @param entries Array of entries, where each entry is an array of `[key, value]`.
  51. * @param customStore Method to get a custom store. Use with caution (see the docs).
  52. */
  53. function setMany(entries, customStore = defaultGetStore()) {
  54. return customStore('readwrite', (store) => {
  55. entries.forEach((entry) => store.put(entry[1], entry[0]));
  56. return promisifyRequest(store.transaction);
  57. });
  58. }
  59. /**
  60. * Get multiple values by their keys
  61. *
  62. * @param keys
  63. * @param customStore Method to get a custom store. Use with caution (see the docs).
  64. */
  65. function getMany(keys, customStore = defaultGetStore()) {
  66. return customStore('readonly', (store) => Promise.all(keys.map((key) => promisifyRequest(store.get(key)))));
  67. }
  68. /**
  69. * Update a value. This lets you see the old value and update it as an atomic operation.
  70. *
  71. * @param key
  72. * @param updater A callback that takes the old value and returns a new value.
  73. * @param customStore Method to get a custom store. Use with caution (see the docs).
  74. */
  75. function update(key, updater, customStore = defaultGetStore()) {
  76. return customStore('readwrite', (store) =>
  77. // Need to create the promise manually.
  78. // If I try to chain promises, the transaction closes in browsers
  79. // that use a promise polyfill (IE10/11).
  80. new Promise((resolve, reject) => {
  81. store.get(key).onsuccess = function () {
  82. try {
  83. store.put(updater(this.result), key);
  84. resolve(promisifyRequest(store.transaction));
  85. }
  86. catch (err) {
  87. reject(err);
  88. }
  89. };
  90. }));
  91. }
  92. /**
  93. * Delete a particular key from the store.
  94. *
  95. * @param key
  96. * @param customStore Method to get a custom store. Use with caution (see the docs).
  97. */
  98. function del(key, customStore = defaultGetStore()) {
  99. return customStore('readwrite', (store) => {
  100. store.delete(key);
  101. return promisifyRequest(store.transaction);
  102. });
  103. }
  104. /**
  105. * Delete multiple keys at once.
  106. *
  107. * @param keys List of keys to delete.
  108. * @param customStore Method to get a custom store. Use with caution (see the docs).
  109. */
  110. function delMany(keys, customStore = defaultGetStore()) {
  111. return customStore('readwrite', (store) => {
  112. keys.forEach((key) => store.delete(key));
  113. return promisifyRequest(store.transaction);
  114. });
  115. }
  116. /**
  117. * Clear all values in the store.
  118. *
  119. * @param customStore Method to get a custom store. Use with caution (see the docs).
  120. */
  121. function clear(customStore = defaultGetStore()) {
  122. return customStore('readwrite', (store) => {
  123. store.clear();
  124. return promisifyRequest(store.transaction);
  125. });
  126. }
  127. function eachCursor(store, callback) {
  128. store.openCursor().onsuccess = function () {
  129. if (!this.result)
  130. return;
  131. callback(this.result);
  132. this.result.continue();
  133. };
  134. return promisifyRequest(store.transaction);
  135. }
  136. /**
  137. * Get all keys in the store.
  138. *
  139. * @param customStore Method to get a custom store. Use with caution (see the docs).
  140. */
  141. function keys(customStore = defaultGetStore()) {
  142. return customStore('readonly', (store) => {
  143. // Fast path for modern browsers
  144. if (store.getAllKeys) {
  145. return promisifyRequest(store.getAllKeys());
  146. }
  147. const items = [];
  148. return eachCursor(store, (cursor) => items.push(cursor.key)).then(() => items);
  149. });
  150. }
  151. /**
  152. * Get all values in the store.
  153. *
  154. * @param customStore Method to get a custom store. Use with caution (see the docs).
  155. */
  156. function values(customStore = defaultGetStore()) {
  157. return customStore('readonly', (store) => {
  158. // Fast path for modern browsers
  159. if (store.getAll) {
  160. return promisifyRequest(store.getAll());
  161. }
  162. const items = [];
  163. return eachCursor(store, (cursor) => items.push(cursor.value)).then(() => items);
  164. });
  165. }
  166. /**
  167. * Get all entries in the store. Each entry is an array of `[key, value]`.
  168. *
  169. * @param customStore Method to get a custom store. Use with caution (see the docs).
  170. */
  171. function entries(customStore = defaultGetStore()) {
  172. return customStore('readonly', (store) => {
  173. // Fast path for modern browsers
  174. // (although, hopefully we'll get a simpler path some day)
  175. if (store.getAll && store.getAllKeys) {
  176. return Promise.all([
  177. promisifyRequest(store.getAllKeys()),
  178. promisifyRequest(store.getAll()),
  179. ]).then(([keys, values]) => keys.map((key, i) => [key, values[i]]));
  180. }
  181. const items = [];
  182. return customStore('readonly', (store) => eachCursor(store, (cursor) => items.push([cursor.key, cursor.value])).then(() => items));
  183. });
  184. }
  185. exports.clear = clear;
  186. exports.createStore = createStore;
  187. exports.del = del;
  188. exports.delMany = delMany;
  189. exports.entries = entries;
  190. exports.get = get;
  191. exports.getMany = getMany;
  192. exports.keys = keys;
  193. exports.promisifyRequest = promisifyRequest;
  194. exports.set = set;
  195. exports.setMany = setMany;
  196. exports.update = update;
  197. exports.values = values;