offline.js 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. import { makeOfflineTransport } from '@sentry/core';
  2. import { serializeEnvelope, parseEnvelope } from '@sentry/utils';
  3. // 'Store', 'promisifyRequest' and 'createStore' were originally copied from the 'idb-keyval' package before being
  4. // modified and simplified: https://github.com/jakearchibald/idb-keyval
  5. //
  6. // At commit: 0420a704fd6cbb4225429c536b1f61112d012fca
  7. // Original licence:
  8. // Copyright 2016, Jake Archibald
  9. //
  10. // Licensed under the Apache License, Version 2.0 (the "License");
  11. // you may not use this file except in compliance with the License.
  12. // You may obtain a copy of the License at
  13. //
  14. // http://www.apache.org/licenses/LICENSE-2.0
  15. //
  16. // Unless required by applicable law or agreed to in writing, software
  17. // distributed under the License is distributed on an "AS IS" BASIS,
  18. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  19. // See the License for the specific language governing permissions and
  20. // limitations under the License.
  21. function promisifyRequest(request) {
  22. return new Promise((resolve, reject) => {
  23. // @ts-expect-error - file size hacks
  24. request.oncomplete = request.onsuccess = () => resolve(request.result);
  25. // @ts-expect-error - file size hacks
  26. request.onabort = request.onerror = () => reject(request.error);
  27. });
  28. }
  29. /** Create or open an IndexedDb store */
  30. function createStore(dbName, storeName) {
  31. const request = indexedDB.open(dbName);
  32. request.onupgradeneeded = () => request.result.createObjectStore(storeName);
  33. const dbp = promisifyRequest(request);
  34. return callback => dbp.then(db => callback(db.transaction(storeName, 'readwrite').objectStore(storeName)));
  35. }
  36. function keys(store) {
  37. return promisifyRequest(store.getAllKeys() );
  38. }
  39. /** Insert into the store */
  40. function insert(store, value, maxQueueSize) {
  41. return store(store => {
  42. return keys(store).then(keys => {
  43. if (keys.length >= maxQueueSize) {
  44. return;
  45. }
  46. // We insert with an incremented key so that the entries are popped in order
  47. store.put(value, Math.max(...keys, 0) + 1);
  48. return promisifyRequest(store.transaction);
  49. });
  50. });
  51. }
  52. /** Pop the oldest value from the store */
  53. function pop(store) {
  54. return store(store => {
  55. return keys(store).then(keys => {
  56. if (keys.length === 0) {
  57. return undefined;
  58. }
  59. return promisifyRequest(store.get(keys[0])).then(value => {
  60. store.delete(keys[0]);
  61. return promisifyRequest(store.transaction).then(() => value);
  62. });
  63. });
  64. });
  65. }
  66. function createIndexedDbStore(options) {
  67. let store;
  68. // Lazily create the store only when it's needed
  69. function getStore() {
  70. if (store == undefined) {
  71. store = createStore(options.dbName || 'sentry-offline', options.storeName || 'queue');
  72. }
  73. return store;
  74. }
  75. return {
  76. insert: async (env) => {
  77. try {
  78. const serialized = await serializeEnvelope(env, options.textEncoder);
  79. await insert(getStore(), serialized, options.maxQueueSize || 30);
  80. } catch (_) {
  81. //
  82. }
  83. },
  84. pop: async () => {
  85. try {
  86. const deserialized = await pop(getStore());
  87. if (deserialized) {
  88. return parseEnvelope(
  89. deserialized,
  90. options.textEncoder || new TextEncoder(),
  91. options.textDecoder || new TextDecoder(),
  92. );
  93. }
  94. } catch (_) {
  95. //
  96. }
  97. return undefined;
  98. },
  99. };
  100. }
  101. function makeIndexedDbOfflineTransport(
  102. createTransport,
  103. ) {
  104. return options => createTransport({ ...options, createStore: createIndexedDbStore });
  105. }
  106. /**
  107. * Creates a transport that uses IndexedDb to store events when offline.
  108. */
  109. function makeBrowserOfflineTransport(
  110. createTransport,
  111. ) {
  112. return makeIndexedDbOfflineTransport(makeOfflineTransport(createTransport));
  113. }
  114. export { createStore, insert, makeBrowserOfflineTransport, pop };
  115. //# sourceMappingURL=offline.js.map