@firebase/database 0.13.9 → 0.13.10-canary.09dfc3aac

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/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Unreleased
2
2
 
3
+ ## 0.13.10
4
+
5
+ ### Patch Changes
6
+
7
+ - [`4af28c1a4`](https://github.com/firebase/firebase-js-sdk/commit/4af28c1a42bd25ce2353f694ca1724c6101cbce5) [#6682](https://github.com/firebase/firebase-js-sdk/pull/6682) - Upgrade TypeScript to 4.7.4.
8
+
9
+ - Updated dependencies [[`4af28c1a4`](https://github.com/firebase/firebase-js-sdk/commit/4af28c1a42bd25ce2353f694ca1724c6101cbce5)]:
10
+ - @firebase/auth-interop-types@0.1.7
11
+ - @firebase/component@0.5.21
12
+ - @firebase/logger@0.3.4
13
+ - @firebase/util@1.7.3
14
+
3
15
  ## 0.13.9
4
16
 
5
17
  ### Patch Changes
@@ -1,10 +1,10 @@
1
- import { getApp, _getProvider, SDK_VERSION as SDK_VERSION$1, _registerComponent, registerVersion } from '@firebase/app';
1
+ import { _getProvider, getApp, SDK_VERSION as SDK_VERSION$1, _registerComponent, registerVersion } from '@firebase/app';
2
2
  import { Component } from '@firebase/component';
3
- import { stringify, jsonEval, contains, assert, isNodeSdk, base64, stringToByteArray, Sha1, deepCopy, base64Encode, isMobileCordova, stringLength, Deferred, safeGet, isAdmin, isValidFormat, isEmpty, isReactNative, assertionError, map, querystring, errorPrefix, getModularInstance, getDefaultEmulatorHostnameAndPort, createMockUserToken } from '@firebase/util';
3
+ import { stringify, jsonEval, contains, assert, isNodeSdk, stringToByteArray, Sha1, base64, deepCopy, base64Encode, isMobileCordova, stringLength, Deferred, safeGet, isAdmin, isValidFormat, isEmpty, isReactNative, assertionError, map, querystring, errorPrefix, getModularInstance, getDefaultEmulatorHostnameAndPort, createMockUserToken } from '@firebase/util';
4
4
  import { Logger, LogLevel } from '@firebase/logger';
5
5
 
6
6
  const name = "@firebase/database";
7
- const version = "0.13.9";
7
+ const version = "0.13.10-canary.09dfc3aac";
8
8
 
9
9
  /**
10
10
  * @license
@@ -5951,153 +5951,6 @@ class ValueIndex extends Index {
5951
5951
  }
5952
5952
  const VALUE_INDEX = new ValueIndex();
5953
5953
 
5954
- /**
5955
- * @license
5956
- * Copyright 2017 Google LLC
5957
- *
5958
- * Licensed under the Apache License, Version 2.0 (the "License");
5959
- * you may not use this file except in compliance with the License.
5960
- * You may obtain a copy of the License at
5961
- *
5962
- * http://www.apache.org/licenses/LICENSE-2.0
5963
- *
5964
- * Unless required by applicable law or agreed to in writing, software
5965
- * distributed under the License is distributed on an "AS IS" BASIS,
5966
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
5967
- * See the License for the specific language governing permissions and
5968
- * limitations under the License.
5969
- */
5970
- // Modeled after base64 web-safe chars, but ordered by ASCII.
5971
- const PUSH_CHARS = '-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz';
5972
- const MIN_PUSH_CHAR = '-';
5973
- const MAX_PUSH_CHAR = 'z';
5974
- const MAX_KEY_LEN = 786;
5975
- /**
5976
- * Fancy ID generator that creates 20-character string identifiers with the
5977
- * following properties:
5978
- *
5979
- * 1. They're based on timestamp so that they sort *after* any existing ids.
5980
- * 2. They contain 72-bits of random data after the timestamp so that IDs won't
5981
- * collide with other clients' IDs.
5982
- * 3. They sort *lexicographically* (so the timestamp is converted to characters
5983
- * that will sort properly).
5984
- * 4. They're monotonically increasing. Even if you generate more than one in
5985
- * the same timestamp, the latter ones will sort after the former ones. We do
5986
- * this by using the previous random bits but "incrementing" them by 1 (only
5987
- * in the case of a timestamp collision).
5988
- */
5989
- const nextPushId = (function () {
5990
- // Timestamp of last push, used to prevent local collisions if you push twice
5991
- // in one ms.
5992
- let lastPushTime = 0;
5993
- // We generate 72-bits of randomness which get turned into 12 characters and
5994
- // appended to the timestamp to prevent collisions with other clients. We
5995
- // store the last characters we generated because in the event of a collision,
5996
- // we'll use those same characters except "incremented" by one.
5997
- const lastRandChars = [];
5998
- return function (now) {
5999
- const duplicateTime = now === lastPushTime;
6000
- lastPushTime = now;
6001
- let i;
6002
- const timeStampChars = new Array(8);
6003
- for (i = 7; i >= 0; i--) {
6004
- timeStampChars[i] = PUSH_CHARS.charAt(now % 64);
6005
- // NOTE: Can't use << here because javascript will convert to int and lose
6006
- // the upper bits.
6007
- now = Math.floor(now / 64);
6008
- }
6009
- assert(now === 0, 'Cannot push at time == 0');
6010
- let id = timeStampChars.join('');
6011
- if (!duplicateTime) {
6012
- for (i = 0; i < 12; i++) {
6013
- lastRandChars[i] = Math.floor(Math.random() * 64);
6014
- }
6015
- }
6016
- else {
6017
- // If the timestamp hasn't changed since last push, use the same random
6018
- // number, except incremented by 1.
6019
- for (i = 11; i >= 0 && lastRandChars[i] === 63; i--) {
6020
- lastRandChars[i] = 0;
6021
- }
6022
- lastRandChars[i]++;
6023
- }
6024
- for (i = 0; i < 12; i++) {
6025
- id += PUSH_CHARS.charAt(lastRandChars[i]);
6026
- }
6027
- assert(id.length === 20, 'nextPushId: Length should be 20.');
6028
- return id;
6029
- };
6030
- })();
6031
- const successor = function (key) {
6032
- if (key === '' + INTEGER_32_MAX) {
6033
- // See https://firebase.google.com/docs/database/web/lists-of-data#data-order
6034
- return MIN_PUSH_CHAR;
6035
- }
6036
- const keyAsInt = tryParseInt(key);
6037
- if (keyAsInt != null) {
6038
- return '' + (keyAsInt + 1);
6039
- }
6040
- const next = new Array(key.length);
6041
- for (let i = 0; i < next.length; i++) {
6042
- next[i] = key.charAt(i);
6043
- }
6044
- if (next.length < MAX_KEY_LEN) {
6045
- next.push(MIN_PUSH_CHAR);
6046
- return next.join('');
6047
- }
6048
- let i = next.length - 1;
6049
- while (i >= 0 && next[i] === MAX_PUSH_CHAR) {
6050
- i--;
6051
- }
6052
- // `successor` was called on the largest possible key, so return the
6053
- // MAX_NAME, which sorts larger than all keys.
6054
- if (i === -1) {
6055
- return MAX_NAME;
6056
- }
6057
- const source = next[i];
6058
- const sourcePlusOne = PUSH_CHARS.charAt(PUSH_CHARS.indexOf(source) + 1);
6059
- next[i] = sourcePlusOne;
6060
- return next.slice(0, i + 1).join('');
6061
- };
6062
- // `key` is assumed to be non-empty.
6063
- const predecessor = function (key) {
6064
- if (key === '' + INTEGER_32_MIN) {
6065
- return MIN_NAME;
6066
- }
6067
- const keyAsInt = tryParseInt(key);
6068
- if (keyAsInt != null) {
6069
- return '' + (keyAsInt - 1);
6070
- }
6071
- const next = new Array(key.length);
6072
- for (let i = 0; i < next.length; i++) {
6073
- next[i] = key.charAt(i);
6074
- }
6075
- // If `key` ends in `MIN_PUSH_CHAR`, the largest key lexicographically
6076
- // smaller than `key`, is `key[0:key.length - 1]`. The next key smaller
6077
- // than that, `predecessor(predecessor(key))`, is
6078
- //
6079
- // `key[0:key.length - 2] + (key[key.length - 1] - 1) + \
6080
- // { MAX_PUSH_CHAR repeated MAX_KEY_LEN - (key.length - 1) times }
6081
- //
6082
- // analogous to increment/decrement for base-10 integers.
6083
- //
6084
- // This works because lexigographic comparison works character-by-character,
6085
- // using length as a tie-breaker if one key is a prefix of the other.
6086
- if (next[next.length - 1] === MIN_PUSH_CHAR) {
6087
- if (next.length === 1) {
6088
- // See https://firebase.google.com/docs/database/web/lists-of-data#orderbykey
6089
- return '' + INTEGER_32_MAX;
6090
- }
6091
- delete next[next.length - 1];
6092
- return next.join('');
6093
- }
6094
- // Replace the last character with it's immediate predecessor, and
6095
- // fill the suffix of the key with MAX_PUSH_CHAR. This is the
6096
- // lexicographically largest possible key smaller than `key`.
6097
- next[next.length - 1] = PUSH_CHARS.charAt(PUSH_CHARS.indexOf(next[next.length - 1]) - 1);
6098
- return next.join('') + MAX_PUSH_CHAR.repeat(MAX_KEY_LEN - next.length);
6099
- };
6100
-
6101
5954
  /**
6102
5955
  * @license
6103
5956
  * Copyright 2017 Google LLC
@@ -6266,6 +6119,8 @@ class RangedFilter {
6266
6119
  this.index_ = params.getIndex();
6267
6120
  this.startPost_ = RangedFilter.getStartPost_(params);
6268
6121
  this.endPost_ = RangedFilter.getEndPost_(params);
6122
+ this.startIsInclusive_ = !params.startAfterSet_;
6123
+ this.endIsInclusive_ = !params.endBeforeSet_;
6269
6124
  }
6270
6125
  getStartPost() {
6271
6126
  return this.startPost_;
@@ -6274,8 +6129,13 @@ class RangedFilter {
6274
6129
  return this.endPost_;
6275
6130
  }
6276
6131
  matches(node) {
6277
- return (this.index_.compare(this.getStartPost(), node) <= 0 &&
6278
- this.index_.compare(node, this.getEndPost()) <= 0);
6132
+ const isWithinStart = this.startIsInclusive_
6133
+ ? this.index_.compare(this.getStartPost(), node) <= 0
6134
+ : this.index_.compare(this.getStartPost(), node) < 0;
6135
+ const isWithinEnd = this.endIsInclusive_
6136
+ ? this.index_.compare(node, this.getEndPost()) <= 0
6137
+ : this.index_.compare(node, this.getEndPost()) < 0;
6138
+ return isWithinStart && isWithinEnd;
6279
6139
  }
6280
6140
  updateChild(snap, key, newChild, affectedPath, source, optChangeAccumulator) {
6281
6141
  if (!this.matches(new NamedNode(key, newChild))) {
@@ -6353,10 +6213,22 @@ class RangedFilter {
6353
6213
  */
6354
6214
  class LimitedFilter {
6355
6215
  constructor(params) {
6216
+ this.withinDirectionalStart = (node) => this.reverse_ ? this.withinEndPost(node) : this.withinStartPost(node);
6217
+ this.withinDirectionalEnd = (node) => this.reverse_ ? this.withinStartPost(node) : this.withinEndPost(node);
6218
+ this.withinStartPost = (node) => {
6219
+ const compareRes = this.index_.compare(this.rangedFilter_.getStartPost(), node);
6220
+ return this.startIsInclusive_ ? compareRes <= 0 : compareRes < 0;
6221
+ };
6222
+ this.withinEndPost = (node) => {
6223
+ const compareRes = this.index_.compare(node, this.rangedFilter_.getEndPost());
6224
+ return this.endIsInclusive_ ? compareRes <= 0 : compareRes < 0;
6225
+ };
6356
6226
  this.rangedFilter_ = new RangedFilter(params);
6357
6227
  this.index_ = params.getIndex();
6358
6228
  this.limit_ = params.getLimit();
6359
6229
  this.reverse_ = !params.isViewFromLeft();
6230
+ this.startIsInclusive_ = !params.startAfterSet_;
6231
+ this.endIsInclusive_ = !params.endBeforeSet_;
6360
6232
  }
6361
6233
  updateChild(snap, key, newChild, affectedPath, source, optChangeAccumulator) {
6362
6234
  if (!this.rangedFilter_.matches(new NamedNode(key, newChild))) {
@@ -6397,23 +6269,18 @@ class LimitedFilter {
6397
6269
  let count = 0;
6398
6270
  while (iterator.hasNext() && count < this.limit_) {
6399
6271
  const next = iterator.getNext();
6400
- let inRange;
6401
- if (this.reverse_) {
6402
- inRange =
6403
- this.index_.compare(this.rangedFilter_.getStartPost(), next) <= 0;
6272
+ if (!this.withinDirectionalStart(next)) {
6273
+ // if we have not reached the start, skip to the next element
6274
+ continue;
6404
6275
  }
6405
- else {
6406
- inRange =
6407
- this.index_.compare(next, this.rangedFilter_.getEndPost()) <= 0;
6276
+ else if (!this.withinDirectionalEnd(next)) {
6277
+ // if we have reached the end, stop adding elements
6278
+ break;
6408
6279
  }
6409
- if (inRange) {
6280
+ else {
6410
6281
  filtered = filtered.updateImmediateChild(next.name, next.node);
6411
6282
  count++;
6412
6283
  }
6413
- else {
6414
- // if we have reached the end post, we cannot keep adding elemments
6415
- break;
6416
- }
6417
6284
  }
6418
6285
  }
6419
6286
  else {
@@ -6421,32 +6288,19 @@ class LimitedFilter {
6421
6288
  filtered = newSnap.withIndex(this.index_);
6422
6289
  // Don't support priorities on queries
6423
6290
  filtered = filtered.updatePriority(ChildrenNode.EMPTY_NODE);
6424
- let startPost;
6425
- let endPost;
6426
- let cmp;
6427
6291
  let iterator;
6428
6292
  if (this.reverse_) {
6429
6293
  iterator = filtered.getReverseIterator(this.index_);
6430
- startPost = this.rangedFilter_.getEndPost();
6431
- endPost = this.rangedFilter_.getStartPost();
6432
- const indexCompare = this.index_.getCompare();
6433
- cmp = (a, b) => indexCompare(b, a);
6434
6294
  }
6435
6295
  else {
6436
6296
  iterator = filtered.getIterator(this.index_);
6437
- startPost = this.rangedFilter_.getStartPost();
6438
- endPost = this.rangedFilter_.getEndPost();
6439
- cmp = this.index_.getCompare();
6440
6297
  }
6441
6298
  let count = 0;
6442
- let foundStartPost = false;
6443
6299
  while (iterator.hasNext()) {
6444
6300
  const next = iterator.getNext();
6445
- if (!foundStartPost && cmp(startPost, next) <= 0) {
6446
- // start adding
6447
- foundStartPost = true;
6448
- }
6449
- const inRange = foundStartPost && count < this.limit_ && cmp(next, endPost) <= 0;
6301
+ const inRange = count < this.limit_ &&
6302
+ this.withinDirectionalStart(next) &&
6303
+ this.withinDirectionalEnd(next);
6450
6304
  if (inRange) {
6451
6305
  count++;
6452
6306
  }
@@ -6577,10 +6431,10 @@ class QueryParams {
6577
6431
  this.limitSet_ = false;
6578
6432
  this.startSet_ = false;
6579
6433
  this.startNameSet_ = false;
6580
- this.startAfterSet_ = false;
6434
+ this.startAfterSet_ = false; // can only be true if startSet_ is true
6581
6435
  this.endSet_ = false;
6582
6436
  this.endNameSet_ = false;
6583
- this.endBeforeSet_ = false;
6437
+ this.endBeforeSet_ = false; // can only be true if endSet_ is true
6584
6438
  this.limit_ = 0;
6585
6439
  this.viewFrom_ = '';
6586
6440
  this.indexStartValue_ = null;
@@ -6592,12 +6446,6 @@ class QueryParams {
6592
6446
  hasStart() {
6593
6447
  return this.startSet_;
6594
6448
  }
6595
- hasStartAfter() {
6596
- return this.startAfterSet_;
6597
- }
6598
- hasEndBefore() {
6599
- return this.endBeforeSet_;
6600
- }
6601
6449
  /**
6602
6450
  * @returns True if it would return from left.
6603
6451
  */
@@ -6686,10 +6534,12 @@ class QueryParams {
6686
6534
  copy.limitSet_ = this.limitSet_;
6687
6535
  copy.limit_ = this.limit_;
6688
6536
  copy.startSet_ = this.startSet_;
6537
+ copy.startAfterSet_ = this.startAfterSet_;
6689
6538
  copy.indexStartValue_ = this.indexStartValue_;
6690
6539
  copy.startNameSet_ = this.startNameSet_;
6691
6540
  copy.indexStartName_ = this.indexStartName_;
6692
6541
  copy.endSet_ = this.endSet_;
6542
+ copy.endBeforeSet_ = this.endBeforeSet_;
6693
6543
  copy.indexEndValue_ = this.indexEndValue_;
6694
6544
  copy.endNameSet_ = this.endNameSet_;
6695
6545
  copy.indexEndName_ = this.indexEndName_;
@@ -6742,21 +6592,11 @@ function queryParamsStartAt(queryParams, indexValue, key) {
6742
6592
  }
6743
6593
  function queryParamsStartAfter(queryParams, indexValue, key) {
6744
6594
  let params;
6745
- if (queryParams.index_ === KEY_INDEX) {
6746
- if (typeof indexValue === 'string') {
6747
- indexValue = successor(indexValue);
6748
- }
6595
+ if (queryParams.index_ === KEY_INDEX || !!key) {
6749
6596
  params = queryParamsStartAt(queryParams, indexValue, key);
6750
6597
  }
6751
6598
  else {
6752
- let childKey;
6753
- if (key == null) {
6754
- childKey = MAX_NAME;
6755
- }
6756
- else {
6757
- childKey = successor(key);
6758
- }
6759
- params = queryParamsStartAt(queryParams, indexValue, childKey);
6599
+ params = queryParamsStartAt(queryParams, indexValue, MAX_NAME);
6760
6600
  }
6761
6601
  params.startAfterSet_ = true;
6762
6602
  return params;
@@ -6779,22 +6619,12 @@ function queryParamsEndAt(queryParams, indexValue, key) {
6779
6619
  return newParams;
6780
6620
  }
6781
6621
  function queryParamsEndBefore(queryParams, indexValue, key) {
6782
- let childKey;
6783
6622
  let params;
6784
- if (queryParams.index_ === KEY_INDEX) {
6785
- if (typeof indexValue === 'string') {
6786
- indexValue = predecessor(indexValue);
6787
- }
6623
+ if (queryParams.index_ === KEY_INDEX || !!key) {
6788
6624
  params = queryParamsEndAt(queryParams, indexValue, key);
6789
6625
  }
6790
6626
  else {
6791
- if (key == null) {
6792
- childKey = MIN_NAME;
6793
- }
6794
- else {
6795
- childKey = predecessor(key);
6796
- }
6797
- params = queryParamsEndAt(queryParams, indexValue, childKey);
6627
+ params = queryParamsEndAt(queryParams, indexValue, MIN_NAME);
6798
6628
  }
6799
6629
  params.endBeforeSet_ = true;
6800
6630
  return params;
@@ -6830,17 +6660,21 @@ function queryParamsToRestQueryStringParameters(queryParams) {
6830
6660
  }
6831
6661
  qs["orderBy" /* ORDER_BY */] = stringify(orderBy);
6832
6662
  if (queryParams.startSet_) {
6833
- qs["startAt" /* START_AT */] = stringify(queryParams.indexStartValue_);
6663
+ const startParam = queryParams.startAfterSet_
6664
+ ? "startAfter" /* START_AFTER */
6665
+ : "startAt" /* START_AT */;
6666
+ qs[startParam] = stringify(queryParams.indexStartValue_);
6834
6667
  if (queryParams.startNameSet_) {
6835
- qs["startAt" /* START_AT */] +=
6836
- ',' + stringify(queryParams.indexStartName_);
6668
+ qs[startParam] += ',' + stringify(queryParams.indexStartName_);
6837
6669
  }
6838
6670
  }
6839
6671
  if (queryParams.endSet_) {
6840
- qs["endAt" /* END_AT */] = stringify(queryParams.indexEndValue_);
6672
+ const endParam = queryParams.endBeforeSet_
6673
+ ? "endBefore" /* END_BEFORE */
6674
+ : "endAt" /* END_AT */;
6675
+ qs[endParam] = stringify(queryParams.indexEndValue_);
6841
6676
  if (queryParams.endNameSet_) {
6842
- qs["endAt" /* END_AT */] +=
6843
- ',' + stringify(queryParams.indexEndName_);
6677
+ qs[endParam] += ',' + stringify(queryParams.indexEndName_);
6844
6678
  }
6845
6679
  }
6846
6680
  if (queryParams.limitSet_) {
@@ -6862,12 +6696,16 @@ function queryParamsGetQueryObject(queryParams) {
6862
6696
  obj["sn" /* INDEX_START_NAME */] =
6863
6697
  queryParams.indexStartName_;
6864
6698
  }
6699
+ obj["sin" /* INDEX_START_IS_INCLUSIVE */] =
6700
+ !queryParams.startAfterSet_;
6865
6701
  }
6866
6702
  if (queryParams.endSet_) {
6867
6703
  obj["ep" /* INDEX_END_VALUE */] = queryParams.indexEndValue_;
6868
6704
  if (queryParams.endNameSet_) {
6869
6705
  obj["en" /* INDEX_END_NAME */] = queryParams.indexEndName_;
6870
6706
  }
6707
+ obj["ein" /* INDEX_END_IS_INCLUSIVE */] =
6708
+ !queryParams.endBeforeSet_;
6871
6709
  }
6872
6710
  if (queryParams.limitSet_) {
6873
6711
  obj["l" /* LIMIT */] = queryParams.limit_;
@@ -12005,6 +11843,81 @@ const parseDatabaseURL = function (dataURL) {
12005
11843
  };
12006
11844
  };
12007
11845
 
11846
+ /**
11847
+ * @license
11848
+ * Copyright 2017 Google LLC
11849
+ *
11850
+ * Licensed under the Apache License, Version 2.0 (the "License");
11851
+ * you may not use this file except in compliance with the License.
11852
+ * You may obtain a copy of the License at
11853
+ *
11854
+ * http://www.apache.org/licenses/LICENSE-2.0
11855
+ *
11856
+ * Unless required by applicable law or agreed to in writing, software
11857
+ * distributed under the License is distributed on an "AS IS" BASIS,
11858
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11859
+ * See the License for the specific language governing permissions and
11860
+ * limitations under the License.
11861
+ */
11862
+ // Modeled after base64 web-safe chars, but ordered by ASCII.
11863
+ const PUSH_CHARS = '-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz';
11864
+ /**
11865
+ * Fancy ID generator that creates 20-character string identifiers with the
11866
+ * following properties:
11867
+ *
11868
+ * 1. They're based on timestamp so that they sort *after* any existing ids.
11869
+ * 2. They contain 72-bits of random data after the timestamp so that IDs won't
11870
+ * collide with other clients' IDs.
11871
+ * 3. They sort *lexicographically* (so the timestamp is converted to characters
11872
+ * that will sort properly).
11873
+ * 4. They're monotonically increasing. Even if you generate more than one in
11874
+ * the same timestamp, the latter ones will sort after the former ones. We do
11875
+ * this by using the previous random bits but "incrementing" them by 1 (only
11876
+ * in the case of a timestamp collision).
11877
+ */
11878
+ const nextPushId = (function () {
11879
+ // Timestamp of last push, used to prevent local collisions if you push twice
11880
+ // in one ms.
11881
+ let lastPushTime = 0;
11882
+ // We generate 72-bits of randomness which get turned into 12 characters and
11883
+ // appended to the timestamp to prevent collisions with other clients. We
11884
+ // store the last characters we generated because in the event of a collision,
11885
+ // we'll use those same characters except "incremented" by one.
11886
+ const lastRandChars = [];
11887
+ return function (now) {
11888
+ const duplicateTime = now === lastPushTime;
11889
+ lastPushTime = now;
11890
+ let i;
11891
+ const timeStampChars = new Array(8);
11892
+ for (i = 7; i >= 0; i--) {
11893
+ timeStampChars[i] = PUSH_CHARS.charAt(now % 64);
11894
+ // NOTE: Can't use << here because javascript will convert to int and lose
11895
+ // the upper bits.
11896
+ now = Math.floor(now / 64);
11897
+ }
11898
+ assert(now === 0, 'Cannot push at time == 0');
11899
+ let id = timeStampChars.join('');
11900
+ if (!duplicateTime) {
11901
+ for (i = 0; i < 12; i++) {
11902
+ lastRandChars[i] = Math.floor(Math.random() * 64);
11903
+ }
11904
+ }
11905
+ else {
11906
+ // If the timestamp hasn't changed since last push, use the same random
11907
+ // number, except incremented by 1.
11908
+ for (i = 11; i >= 0 && lastRandChars[i] === 63; i--) {
11909
+ lastRandChars[i] = 0;
11910
+ }
11911
+ lastRandChars[i]++;
11912
+ }
11913
+ for (i = 0; i < 12; i++) {
11914
+ id += PUSH_CHARS.charAt(lastRandChars[i]);
11915
+ }
11916
+ assert(id.length === 20, 'nextPushId: Length should be 20.');
11917
+ return id;
11918
+ };
11919
+ })();
11920
+
12008
11921
  /**
12009
11922
  * @license
12010
11923
  * Copyright 2017 Google LLC