@firebase/app 0.7.17 → 0.7.19-2022216223411

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs.js CHANGED
@@ -62,7 +62,7 @@ function isVersionServiceProvider(provider) {
62
62
  }
63
63
 
64
64
  var name$o = "@firebase/app";
65
- var version$1 = "0.7.17";
65
+ var version$1 = "0.7.19-2022216223411";
66
66
 
67
67
  /**
68
68
  * @license
@@ -129,7 +129,7 @@ var name$2 = "@firebase/firestore";
129
129
  var name$1 = "@firebase/firestore-compat";
130
130
 
131
131
  var name = "firebase";
132
- var version = "9.6.7";
132
+ var version = "9.6.9-2022216223411";
133
133
 
134
134
  /**
135
135
  * @license
@@ -271,6 +271,12 @@ function _registerComponent(component) {
271
271
  * @internal
272
272
  */
273
273
  function _getProvider(app, name) {
274
+ var heartbeatController = app.container
275
+ .getProvider('heartbeat')
276
+ .getImmediate({ optional: true });
277
+ if (heartbeatController) {
278
+ void heartbeatController.triggerHeartbeat();
279
+ }
274
280
  return app.container.getProvider(name);
275
281
  }
276
282
  /**
@@ -320,6 +326,10 @@ var ERRORS = (_a = {},
320
326
  _a["invalid-app-argument" /* INVALID_APP_ARGUMENT */] = 'firebase.{$appName}() takes either no argument or a ' +
321
327
  'Firebase App instance.',
322
328
  _a["invalid-log-argument" /* INVALID_LOG_ARGUMENT */] = 'First argument to `onLog` must be null or a function.',
329
+ _a["storage-open" /* STORAGE_OPEN */] = 'Error thrown when opening storage. Original error: {$originalErrorMessage}.',
330
+ _a["storage-get" /* STORAGE_GET */] = 'Error thrown when reading from storage. Original error: {$originalErrorMessage}.',
331
+ _a["storage-set" /* STORAGE_WRITE */] = 'Error thrown when writing to storage. Original error: {$originalErrorMessage}.',
332
+ _a["storage-delete" /* STORAGE_DELETE */] = 'Error thrown when deleting from storage. Original error: {$originalErrorMessage}.',
323
333
  _a);
324
334
  var ERROR_FACTORY = new util.ErrorFactory('app', 'Firebase', ERRORS);
325
335
 
@@ -625,6 +635,402 @@ function setLogLevel(logLevel) {
625
635
  logger$1.setLogLevel(logLevel);
626
636
  }
627
637
 
638
+ /**
639
+ * @license
640
+ * Copyright 2021 Google LLC
641
+ *
642
+ * Licensed under the Apache License, Version 2.0 (the "License");
643
+ * you may not use this file except in compliance with the License.
644
+ * You may obtain a copy of the License at
645
+ *
646
+ * http://www.apache.org/licenses/LICENSE-2.0
647
+ *
648
+ * Unless required by applicable law or agreed to in writing, software
649
+ * distributed under the License is distributed on an "AS IS" BASIS,
650
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
651
+ * See the License for the specific language governing permissions and
652
+ * limitations under the License.
653
+ */
654
+ var DB_NAME = 'firebase-heartbeat-database';
655
+ var DB_VERSION = 1;
656
+ var STORE_NAME = 'firebase-heartbeat-store';
657
+ var dbPromise = null;
658
+ function getDbPromise() {
659
+ if (!dbPromise) {
660
+ dbPromise = util.openDB(DB_NAME, DB_VERSION, function (db, oldVersion) {
661
+ // We don't use 'break' in this switch statement, the fall-through
662
+ // behavior is what we want, because if there are multiple versions between
663
+ // the old version and the current version, we want ALL the migrations
664
+ // that correspond to those versions to run, not only the last one.
665
+ // eslint-disable-next-line default-case
666
+ switch (oldVersion) {
667
+ case 0:
668
+ db.createObjectStore(STORE_NAME);
669
+ }
670
+ }).catch(function (e) {
671
+ throw ERROR_FACTORY.create("storage-open" /* STORAGE_OPEN */, {
672
+ originalErrorMessage: e.message
673
+ });
674
+ });
675
+ }
676
+ return dbPromise;
677
+ }
678
+ function readHeartbeatsFromIndexedDB(app) {
679
+ return tslib.__awaiter(this, void 0, void 0, function () {
680
+ var db, e_1;
681
+ return tslib.__generator(this, function (_a) {
682
+ switch (_a.label) {
683
+ case 0:
684
+ _a.trys.push([0, 2, , 3]);
685
+ return [4 /*yield*/, getDbPromise()];
686
+ case 1:
687
+ db = _a.sent();
688
+ return [2 /*return*/, db
689
+ .transaction(STORE_NAME)
690
+ .objectStore(STORE_NAME)
691
+ .get(computeKey(app))];
692
+ case 2:
693
+ e_1 = _a.sent();
694
+ throw ERROR_FACTORY.create("storage-get" /* STORAGE_GET */, {
695
+ originalErrorMessage: e_1.message
696
+ });
697
+ case 3: return [2 /*return*/];
698
+ }
699
+ });
700
+ });
701
+ }
702
+ function writeHeartbeatsToIndexedDB(app, heartbeatObject) {
703
+ return tslib.__awaiter(this, void 0, void 0, function () {
704
+ var db, tx, objectStore, e_2;
705
+ return tslib.__generator(this, function (_a) {
706
+ switch (_a.label) {
707
+ case 0:
708
+ _a.trys.push([0, 3, , 4]);
709
+ return [4 /*yield*/, getDbPromise()];
710
+ case 1:
711
+ db = _a.sent();
712
+ tx = db.transaction(STORE_NAME, 'readwrite');
713
+ objectStore = tx.objectStore(STORE_NAME);
714
+ return [4 /*yield*/, objectStore.put(heartbeatObject, computeKey(app))];
715
+ case 2:
716
+ _a.sent();
717
+ return [2 /*return*/, tx.complete];
718
+ case 3:
719
+ e_2 = _a.sent();
720
+ throw ERROR_FACTORY.create("storage-set" /* STORAGE_WRITE */, {
721
+ originalErrorMessage: e_2.message
722
+ });
723
+ case 4: return [2 /*return*/];
724
+ }
725
+ });
726
+ });
727
+ }
728
+ function computeKey(app) {
729
+ return app.name + "!" + app.options.appId;
730
+ }
731
+
732
+ /**
733
+ * @license
734
+ * Copyright 2021 Google LLC
735
+ *
736
+ * Licensed under the Apache License, Version 2.0 (the "License");
737
+ * you may not use this file except in compliance with the License.
738
+ * You may obtain a copy of the License at
739
+ *
740
+ * http://www.apache.org/licenses/LICENSE-2.0
741
+ *
742
+ * Unless required by applicable law or agreed to in writing, software
743
+ * distributed under the License is distributed on an "AS IS" BASIS,
744
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
745
+ * See the License for the specific language governing permissions and
746
+ * limitations under the License.
747
+ */
748
+ var MAX_HEADER_BYTES = 1024;
749
+ // 30 days
750
+ var STORED_HEARTBEAT_RETENTION_MAX_MILLIS = 30 * 24 * 60 * 60 * 1000;
751
+ var HeartbeatServiceImpl = /** @class */ (function () {
752
+ function HeartbeatServiceImpl(container) {
753
+ var _this = this;
754
+ this.container = container;
755
+ /**
756
+ * In-memory cache for heartbeats, used by getHeartbeatsHeader() to generate
757
+ * the header string.
758
+ * Stores one record per date. This will be consolidated into the standard
759
+ * format of one record per user agent string before being sent as a header.
760
+ * Populated from indexedDB when the controller is instantiated and should
761
+ * be kept in sync with indexedDB.
762
+ * Leave public for easier testing.
763
+ */
764
+ this._heartbeatsCache = null;
765
+ var app = this.container.getProvider('app').getImmediate();
766
+ this._storage = new HeartbeatStorageImpl(app);
767
+ this._heartbeatsCachePromise = this._storage.read().then(function (result) {
768
+ _this._heartbeatsCache = result;
769
+ return result;
770
+ });
771
+ }
772
+ /**
773
+ * Called to report a heartbeat. The function will generate
774
+ * a HeartbeatsByUserAgent object, update heartbeatsCache, and persist it
775
+ * to IndexedDB.
776
+ * Note that we only store one heartbeat per day. So if a heartbeat for today is
777
+ * already logged, subsequent calls to this function in the same day will be ignored.
778
+ */
779
+ HeartbeatServiceImpl.prototype.triggerHeartbeat = function () {
780
+ return tslib.__awaiter(this, void 0, void 0, function () {
781
+ var platformLogger, agent, date, _a;
782
+ return tslib.__generator(this, function (_b) {
783
+ switch (_b.label) {
784
+ case 0:
785
+ platformLogger = this.container
786
+ .getProvider('platform-logger')
787
+ .getImmediate();
788
+ agent = platformLogger.getPlatformInfoString();
789
+ date = getUTCDateString();
790
+ if (!(this._heartbeatsCache === null)) return [3 /*break*/, 2];
791
+ _a = this;
792
+ return [4 /*yield*/, this._heartbeatsCachePromise];
793
+ case 1:
794
+ _a._heartbeatsCache = _b.sent();
795
+ _b.label = 2;
796
+ case 2:
797
+ // Do not store a heartbeat if one is already stored for this day
798
+ // or if a header has already been sent today.
799
+ if (this._heartbeatsCache.lastSentHeartbeatDate === date ||
800
+ this._heartbeatsCache.heartbeats.some(function (singleDateHeartbeat) { return singleDateHeartbeat.date === date; })) {
801
+ return [2 /*return*/];
802
+ }
803
+ else {
804
+ // There is no entry for this date. Create one.
805
+ this._heartbeatsCache.heartbeats.push({ date: date, agent: agent });
806
+ }
807
+ // Remove entries older than 30 days.
808
+ this._heartbeatsCache.heartbeats = this._heartbeatsCache.heartbeats.filter(function (singleDateHeartbeat) {
809
+ var hbTimestamp = new Date(singleDateHeartbeat.date).valueOf();
810
+ var now = Date.now();
811
+ return now - hbTimestamp <= STORED_HEARTBEAT_RETENTION_MAX_MILLIS;
812
+ });
813
+ return [2 /*return*/, this._storage.overwrite(this._heartbeatsCache)];
814
+ }
815
+ });
816
+ });
817
+ };
818
+ /**
819
+ * Returns a base64 encoded string which can be attached to the heartbeat-specific header directly.
820
+ * It also clears all heartbeats from memory as well as in IndexedDB.
821
+ *
822
+ * NOTE: Consuming product SDKs should not send the header if this method
823
+ * returns an empty string.
824
+ */
825
+ HeartbeatServiceImpl.prototype.getHeartbeatsHeader = function () {
826
+ return tslib.__awaiter(this, void 0, void 0, function () {
827
+ var date, _a, heartbeatsToSend, unsentEntries, headerString;
828
+ return tslib.__generator(this, function (_b) {
829
+ switch (_b.label) {
830
+ case 0:
831
+ if (!(this._heartbeatsCache === null)) return [3 /*break*/, 2];
832
+ return [4 /*yield*/, this._heartbeatsCachePromise];
833
+ case 1:
834
+ _b.sent();
835
+ _b.label = 2;
836
+ case 2:
837
+ // If it's still null or the array is empty, there is no data to send.
838
+ if (this._heartbeatsCache === null ||
839
+ this._heartbeatsCache.heartbeats.length === 0) {
840
+ return [2 /*return*/, ''];
841
+ }
842
+ date = getUTCDateString();
843
+ _a = extractHeartbeatsForHeader(this._heartbeatsCache.heartbeats), heartbeatsToSend = _a.heartbeatsToSend, unsentEntries = _a.unsentEntries;
844
+ headerString = util.base64urlEncodeWithoutPadding(JSON.stringify({ version: 2, heartbeats: heartbeatsToSend }));
845
+ // Store last sent date to prevent another being logged/sent for the same day.
846
+ this._heartbeatsCache.lastSentHeartbeatDate = date;
847
+ if (!(unsentEntries.length > 0)) return [3 /*break*/, 4];
848
+ // Store any unsent entries if they exist.
849
+ this._heartbeatsCache.heartbeats = unsentEntries;
850
+ // This seems more likely than emptying the array (below) to lead to some odd state
851
+ // since the cache isn't empty and this will be called again on the next request,
852
+ // and is probably safest if we await it.
853
+ return [4 /*yield*/, this._storage.overwrite(this._heartbeatsCache)];
854
+ case 3:
855
+ // This seems more likely than emptying the array (below) to lead to some odd state
856
+ // since the cache isn't empty and this will be called again on the next request,
857
+ // and is probably safest if we await it.
858
+ _b.sent();
859
+ return [3 /*break*/, 5];
860
+ case 4:
861
+ this._heartbeatsCache.heartbeats = [];
862
+ // Do not wait for this, to reduce latency.
863
+ void this._storage.overwrite(this._heartbeatsCache);
864
+ _b.label = 5;
865
+ case 5: return [2 /*return*/, headerString];
866
+ }
867
+ });
868
+ });
869
+ };
870
+ return HeartbeatServiceImpl;
871
+ }());
872
+ function getUTCDateString() {
873
+ var today = new Date();
874
+ // Returns date format 'YYYY-MM-DD'
875
+ return today.toISOString().substring(0, 10);
876
+ }
877
+ function extractHeartbeatsForHeader(heartbeatsCache, maxSize) {
878
+ var e_1, _a;
879
+ if (maxSize === void 0) { maxSize = MAX_HEADER_BYTES; }
880
+ // Heartbeats grouped by user agent in the standard format to be sent in
881
+ // the header.
882
+ var heartbeatsToSend = [];
883
+ // Single date format heartbeats that are not sent.
884
+ var unsentEntries = heartbeatsCache.slice();
885
+ var _loop_1 = function (singleDateHeartbeat) {
886
+ // Look for an existing entry with the same user agent.
887
+ var heartbeatEntry = heartbeatsToSend.find(function (hb) { return hb.agent === singleDateHeartbeat.agent; });
888
+ if (!heartbeatEntry) {
889
+ // If no entry for this user agent exists, create one.
890
+ heartbeatsToSend.push({
891
+ agent: singleDateHeartbeat.agent,
892
+ dates: [singleDateHeartbeat.date]
893
+ });
894
+ if (countBytes(heartbeatsToSend) > maxSize) {
895
+ // If the header would exceed max size, remove the added heartbeat
896
+ // entry and stop adding to the header.
897
+ heartbeatsToSend.pop();
898
+ return "break";
899
+ }
900
+ }
901
+ else {
902
+ heartbeatEntry.dates.push(singleDateHeartbeat.date);
903
+ // If the header would exceed max size, remove the added date
904
+ // and stop adding to the header.
905
+ if (countBytes(heartbeatsToSend) > maxSize) {
906
+ heartbeatEntry.dates.pop();
907
+ return "break";
908
+ }
909
+ }
910
+ // Pop unsent entry from queue. (Skipped if adding the entry exceeded
911
+ // quota and the loop breaks early.)
912
+ unsentEntries = unsentEntries.slice(1);
913
+ };
914
+ try {
915
+ for (var heartbeatsCache_1 = tslib.__values(heartbeatsCache), heartbeatsCache_1_1 = heartbeatsCache_1.next(); !heartbeatsCache_1_1.done; heartbeatsCache_1_1 = heartbeatsCache_1.next()) {
916
+ var singleDateHeartbeat = heartbeatsCache_1_1.value;
917
+ var state_1 = _loop_1(singleDateHeartbeat);
918
+ if (state_1 === "break")
919
+ break;
920
+ }
921
+ }
922
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
923
+ finally {
924
+ try {
925
+ if (heartbeatsCache_1_1 && !heartbeatsCache_1_1.done && (_a = heartbeatsCache_1.return)) _a.call(heartbeatsCache_1);
926
+ }
927
+ finally { if (e_1) throw e_1.error; }
928
+ }
929
+ return {
930
+ heartbeatsToSend: heartbeatsToSend,
931
+ unsentEntries: unsentEntries
932
+ };
933
+ }
934
+ var HeartbeatStorageImpl = /** @class */ (function () {
935
+ function HeartbeatStorageImpl(app) {
936
+ this.app = app;
937
+ this._canUseIndexedDBPromise = this.runIndexedDBEnvironmentCheck();
938
+ }
939
+ HeartbeatStorageImpl.prototype.runIndexedDBEnvironmentCheck = function () {
940
+ return tslib.__awaiter(this, void 0, void 0, function () {
941
+ return tslib.__generator(this, function (_a) {
942
+ if (!util.isIndexedDBAvailable()) {
943
+ return [2 /*return*/, false];
944
+ }
945
+ else {
946
+ return [2 /*return*/, util.validateIndexedDBOpenable()
947
+ .then(function () { return true; })
948
+ .catch(function () { return false; })];
949
+ }
950
+ });
951
+ });
952
+ };
953
+ /**
954
+ * Read all heartbeats.
955
+ */
956
+ HeartbeatStorageImpl.prototype.read = function () {
957
+ return tslib.__awaiter(this, void 0, void 0, function () {
958
+ var canUseIndexedDB, idbHeartbeatObject;
959
+ return tslib.__generator(this, function (_a) {
960
+ switch (_a.label) {
961
+ case 0: return [4 /*yield*/, this._canUseIndexedDBPromise];
962
+ case 1:
963
+ canUseIndexedDB = _a.sent();
964
+ if (!!canUseIndexedDB) return [3 /*break*/, 2];
965
+ return [2 /*return*/, { heartbeats: [] }];
966
+ case 2: return [4 /*yield*/, readHeartbeatsFromIndexedDB(this.app)];
967
+ case 3:
968
+ idbHeartbeatObject = _a.sent();
969
+ return [2 /*return*/, idbHeartbeatObject || { heartbeats: [] }];
970
+ }
971
+ });
972
+ });
973
+ };
974
+ // overwrite the storage with the provided heartbeats
975
+ HeartbeatStorageImpl.prototype.overwrite = function (heartbeatsObject) {
976
+ var _a;
977
+ return tslib.__awaiter(this, void 0, void 0, function () {
978
+ var canUseIndexedDB, existingHeartbeatsObject;
979
+ return tslib.__generator(this, function (_b) {
980
+ switch (_b.label) {
981
+ case 0: return [4 /*yield*/, this._canUseIndexedDBPromise];
982
+ case 1:
983
+ canUseIndexedDB = _b.sent();
984
+ if (!!canUseIndexedDB) return [3 /*break*/, 2];
985
+ return [2 /*return*/];
986
+ case 2: return [4 /*yield*/, this.read()];
987
+ case 3:
988
+ existingHeartbeatsObject = _b.sent();
989
+ return [2 /*return*/, writeHeartbeatsToIndexedDB(this.app, {
990
+ lastSentHeartbeatDate: (_a = heartbeatsObject.lastSentHeartbeatDate) !== null && _a !== void 0 ? _a : existingHeartbeatsObject.lastSentHeartbeatDate,
991
+ heartbeats: heartbeatsObject.heartbeats
992
+ })];
993
+ }
994
+ });
995
+ });
996
+ };
997
+ // add heartbeats
998
+ HeartbeatStorageImpl.prototype.add = function (heartbeatsObject) {
999
+ var _a;
1000
+ return tslib.__awaiter(this, void 0, void 0, function () {
1001
+ var canUseIndexedDB, existingHeartbeatsObject;
1002
+ return tslib.__generator(this, function (_b) {
1003
+ switch (_b.label) {
1004
+ case 0: return [4 /*yield*/, this._canUseIndexedDBPromise];
1005
+ case 1:
1006
+ canUseIndexedDB = _b.sent();
1007
+ if (!!canUseIndexedDB) return [3 /*break*/, 2];
1008
+ return [2 /*return*/];
1009
+ case 2: return [4 /*yield*/, this.read()];
1010
+ case 3:
1011
+ existingHeartbeatsObject = _b.sent();
1012
+ return [2 /*return*/, writeHeartbeatsToIndexedDB(this.app, {
1013
+ lastSentHeartbeatDate: (_a = heartbeatsObject.lastSentHeartbeatDate) !== null && _a !== void 0 ? _a : existingHeartbeatsObject.lastSentHeartbeatDate,
1014
+ heartbeats: tslib.__spreadArray(tslib.__spreadArray([], tslib.__read(existingHeartbeatsObject.heartbeats)), tslib.__read(heartbeatsObject.heartbeats))
1015
+ })];
1016
+ }
1017
+ });
1018
+ });
1019
+ };
1020
+ return HeartbeatStorageImpl;
1021
+ }());
1022
+ /**
1023
+ * Calculate bytes of a HeartbeatsByUserAgent array after being wrapped
1024
+ * in a platform logging header JSON object, stringified, and converted
1025
+ * to base 64.
1026
+ */
1027
+ function countBytes(heartbeatsCache) {
1028
+ // base64 has a restricted set of characters, all of which should be 1 byte.
1029
+ return util.base64urlEncodeWithoutPadding(
1030
+ // heartbeatsCache wrapper properties
1031
+ JSON.stringify({ version: 2, heartbeats: heartbeatsCache })).length;
1032
+ }
1033
+
628
1034
  /**
629
1035
  * @license
630
1036
  * Copyright 2019 Google LLC
@@ -643,6 +1049,7 @@ function setLogLevel(logLevel) {
643
1049
  */
644
1050
  function registerCoreComponents(variant) {
645
1051
  _registerComponent(new component.Component('platform-logger', function (container) { return new PlatformLoggerServiceImpl(container); }, "PRIVATE" /* PRIVATE */));
1052
+ _registerComponent(new component.Component('heartbeat', function (container) { return new HeartbeatServiceImpl(container); }, "PRIVATE" /* PRIVATE */));
646
1053
  // Register `app` package.
647
1054
  registerVersion(name$o, version$1, variant);
648
1055
  // BUILD_TARGET will be replaced by values like esm5, esm2017, cjs5, etc during the compilation