@adaptic/utils 0.0.376 → 0.0.378

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 CHANGED
@@ -40,6 +40,54 @@ var path__namespace = /*#__PURE__*/_interopNamespaceDefault(path);
40
40
 
41
41
  // Keep track of a single instance of Apollo client
42
42
  let apolloClientInstance = null;
43
+ // Track if auth has been configured
44
+ let authConfigured = false;
45
+ /**
46
+ * Configure the Apollo client authentication with a dynamic token provider.
47
+ * This should be called once during app initialization before making any
48
+ * @adaptic/backend-legacy API calls.
49
+ *
50
+ * The token provider function will be called for each GraphQL request,
51
+ * allowing for dynamic token retrieval (e.g., from session storage, SecretsManager, etc.)
52
+ *
53
+ * @param provider - Function that returns the auth token (sync or async)
54
+ *
55
+ * @example
56
+ * // Configure with an environment variable
57
+ * configureAuth(() => process.env.GRAPHQL_API_KEY || '');
58
+ *
59
+ * @example
60
+ * // Configure with NextAuth session token (async)
61
+ * configureAuth(async () => {
62
+ * const session = await auth();
63
+ * return session?.accessToken || '';
64
+ * });
65
+ *
66
+ * @example
67
+ * // Configure with SecretsManager
68
+ * configureAuth(() => {
69
+ * const secrets = getSecretsManager();
70
+ * return secrets.getGraphQLConfig().apiKey || '';
71
+ * });
72
+ */
73
+ const configureAuth = (provider) => {
74
+ if (authConfigured) {
75
+ console.warn('[adaptic] Auth provider already configured. Calling configureAuth again will reset the client.');
76
+ }
77
+ adaptic$1.setTokenProvider(provider);
78
+ authConfigured = true;
79
+ // Reset the cached client so it picks up the new auth on next request
80
+ if (apolloClientInstance) {
81
+ apolloClientInstance = null;
82
+ console.log('[adaptic] Apollo client reset due to auth configuration change');
83
+ }
84
+ };
85
+ /**
86
+ * Check if Apollo auth has been configured.
87
+ */
88
+ const isAuthConfigured = () => {
89
+ return authConfigured;
90
+ };
43
91
  /**
44
92
  * Returns a shared Apollo client instance with connection pooling.
45
93
  * This should be used for all @adaptic/backend-legacy operations.
@@ -4247,6 +4295,12 @@ class Queue {
4247
4295
 
4248
4296
  this.#head = this.#head.next;
4249
4297
  this.#size--;
4298
+
4299
+ // Clean up tail reference when queue becomes empty
4300
+ if (!this.#head) {
4301
+ this.#tail = undefined;
4302
+ }
4303
+
4250
4304
  return current.value;
4251
4305
  }
4252
4306
 
@@ -13863,6 +13917,7 @@ class LRUCache {
13863
13917
  #sizes;
13864
13918
  #starts;
13865
13919
  #ttls;
13920
+ #autopurgeTimers;
13866
13921
  #hasDispose;
13867
13922
  #hasFetchMethod;
13868
13923
  #hasDisposeAfter;
@@ -13881,6 +13936,7 @@ class LRUCache {
13881
13936
  // properties
13882
13937
  starts: c.#starts,
13883
13938
  ttls: c.#ttls,
13939
+ autopurgeTimers: c.#autopurgeTimers,
13884
13940
  sizes: c.#sizes,
13885
13941
  keyMap: c.#keyMap,
13886
13942
  keyList: c.#keyList,
@@ -13982,13 +14038,11 @@ class LRUCache {
13982
14038
  throw new TypeError('sizeCalculation set to non-function');
13983
14039
  }
13984
14040
  }
13985
- if (memoMethod !== undefined &&
13986
- typeof memoMethod !== 'function') {
14041
+ if (memoMethod !== undefined && typeof memoMethod !== 'function') {
13987
14042
  throw new TypeError('memoMethod must be a function if defined');
13988
14043
  }
13989
14044
  this.#memoMethod = memoMethod;
13990
- if (fetchMethod !== undefined &&
13991
- typeof fetchMethod !== 'function') {
14045
+ if (fetchMethod !== undefined && typeof fetchMethod !== 'function') {
13992
14046
  throw new TypeError('fetchMethod must be a function if specified');
13993
14047
  }
13994
14048
  this.#fetchMethod = fetchMethod;
@@ -14043,9 +14097,7 @@ class LRUCache {
14043
14097
  this.updateAgeOnGet = !!updateAgeOnGet;
14044
14098
  this.updateAgeOnHas = !!updateAgeOnHas;
14045
14099
  this.ttlResolution =
14046
- isPosInt(ttlResolution) || ttlResolution === 0 ?
14047
- ttlResolution
14048
- : 1;
14100
+ isPosInt(ttlResolution) || ttlResolution === 0 ? ttlResolution : 1;
14049
14101
  this.ttlAutopurge = !!ttlAutopurge;
14050
14102
  this.ttl = ttl || 0;
14051
14103
  if (this.ttl) {
@@ -14080,10 +14132,21 @@ class LRUCache {
14080
14132
  const starts = new ZeroArray(this.#max);
14081
14133
  this.#ttls = ttls;
14082
14134
  this.#starts = starts;
14135
+ const purgeTimers = this.ttlAutopurge ?
14136
+ new Array(this.#max)
14137
+ : undefined;
14138
+ this.#autopurgeTimers = purgeTimers;
14083
14139
  this.#setItemTTL = (index, ttl, start = this.#perf.now()) => {
14084
14140
  starts[index] = ttl !== 0 ? start : 0;
14085
14141
  ttls[index] = ttl;
14086
- if (ttl !== 0 && this.ttlAutopurge) {
14142
+ // clear out the purge timer if we're setting TTL to 0, and
14143
+ // previously had a ttl purge timer running, so it doesn't
14144
+ // fire unnecessarily.
14145
+ if (purgeTimers?.[index]) {
14146
+ clearTimeout(purgeTimers[index]);
14147
+ purgeTimers[index] = undefined;
14148
+ }
14149
+ if (ttl !== 0 && purgeTimers) {
14087
14150
  const t = setTimeout(() => {
14088
14151
  if (this.#isStale(index)) {
14089
14152
  this.#delete(this.#keyList[index], 'expire');
@@ -14095,6 +14158,7 @@ class LRUCache {
14095
14158
  t.unref();
14096
14159
  }
14097
14160
  /* c8 ignore stop */
14161
+ purgeTimers[index] = t;
14098
14162
  }
14099
14163
  };
14100
14164
  this.#updateItemAge = index => {
@@ -14286,8 +14350,7 @@ class LRUCache {
14286
14350
  *keys() {
14287
14351
  for (const i of this.#indexes()) {
14288
14352
  const k = this.#keyList[i];
14289
- if (k !== undefined &&
14290
- !this.#isBackgroundFetch(this.#valList[i])) {
14353
+ if (k !== undefined && !this.#isBackgroundFetch(this.#valList[i])) {
14291
14354
  yield k;
14292
14355
  }
14293
14356
  }
@@ -14301,8 +14364,7 @@ class LRUCache {
14301
14364
  *rkeys() {
14302
14365
  for (const i of this.#rindexes()) {
14303
14366
  const k = this.#keyList[i];
14304
- if (k !== undefined &&
14305
- !this.#isBackgroundFetch(this.#valList[i])) {
14367
+ if (k !== undefined && !this.#isBackgroundFetch(this.#valList[i])) {
14306
14368
  yield k;
14307
14369
  }
14308
14370
  }
@@ -14314,8 +14376,7 @@ class LRUCache {
14314
14376
  *values() {
14315
14377
  for (const i of this.#indexes()) {
14316
14378
  const v = this.#valList[i];
14317
- if (v !== undefined &&
14318
- !this.#isBackgroundFetch(this.#valList[i])) {
14379
+ if (v !== undefined && !this.#isBackgroundFetch(this.#valList[i])) {
14319
14380
  yield this.#valList[i];
14320
14381
  }
14321
14382
  }
@@ -14329,8 +14390,7 @@ class LRUCache {
14329
14390
  *rvalues() {
14330
14391
  for (const i of this.#rindexes()) {
14331
14392
  const v = this.#valList[i];
14332
- if (v !== undefined &&
14333
- !this.#isBackgroundFetch(this.#valList[i])) {
14393
+ if (v !== undefined && !this.#isBackgroundFetch(this.#valList[i])) {
14334
14394
  yield this.#valList[i];
14335
14395
  }
14336
14396
  }
@@ -14688,6 +14748,10 @@ class LRUCache {
14688
14748
  }
14689
14749
  }
14690
14750
  this.#removeItemSize(head);
14751
+ if (this.#autopurgeTimers?.[head]) {
14752
+ clearTimeout(this.#autopurgeTimers[head]);
14753
+ this.#autopurgeTimers[head] = undefined;
14754
+ }
14691
14755
  // if we aren't about to use the index, then null these out
14692
14756
  if (free) {
14693
14757
  this.#keyList[head] = undefined;
@@ -14760,8 +14824,7 @@ class LRUCache {
14760
14824
  peek(k, peekOptions = {}) {
14761
14825
  const { allowStale = this.allowStale } = peekOptions;
14762
14826
  const index = this.#keyMap.get(k);
14763
- if (index === undefined ||
14764
- (!allowStale && this.#isStale(index))) {
14827
+ if (index === undefined || (!allowStale && this.#isStale(index))) {
14765
14828
  return;
14766
14829
  }
14767
14830
  const v = this.#valList[index];
@@ -14807,7 +14870,7 @@ class LRUCache {
14807
14870
  // cache and ignore the abort, or if it's still pending on this specific
14808
14871
  // background request, then write it to the cache.
14809
14872
  const vl = this.#valList[index];
14810
- if (vl === p || ignoreAbort && updateCache && vl === undefined) {
14873
+ if (vl === p || (ignoreAbort && updateCache && vl === undefined)) {
14811
14874
  if (v === undefined) {
14812
14875
  if (bf.__staleWhileFetching !== undefined) {
14813
14876
  this.#valList[index] = bf.__staleWhileFetching;
@@ -14871,8 +14934,7 @@ class LRUCache {
14871
14934
  // defer check until we are actually aborting,
14872
14935
  // so fetchMethod can override.
14873
14936
  ac.signal.addEventListener('abort', () => {
14874
- if (!options.ignoreFetchAbort ||
14875
- options.allowStaleOnFetchAbort) {
14937
+ if (!options.ignoreFetchAbort || options.allowStaleOnFetchAbort) {
14876
14938
  res(undefined);
14877
14939
  // when it eventually resolves, update the cache.
14878
14940
  if (options.allowStaleOnFetchAbort) {
@@ -15104,6 +15166,10 @@ class LRUCache {
15104
15166
  if (this.#size !== 0) {
15105
15167
  const index = this.#keyMap.get(k);
15106
15168
  if (index !== undefined) {
15169
+ if (this.#autopurgeTimers?.[index]) {
15170
+ clearTimeout(this.#autopurgeTimers?.[index]);
15171
+ this.#autopurgeTimers[index] = undefined;
15172
+ }
15107
15173
  deleted = true;
15108
15174
  if (this.#size === 1) {
15109
15175
  this.#clear(reason);
@@ -15179,6 +15245,11 @@ class LRUCache {
15179
15245
  if (this.#ttls && this.#starts) {
15180
15246
  this.#ttls.fill(0);
15181
15247
  this.#starts.fill(0);
15248
+ for (const t of this.#autopurgeTimers ?? []) {
15249
+ if (t !== undefined)
15250
+ clearTimeout(t);
15251
+ }
15252
+ this.#autopurgeTimers?.fill(undefined);
15182
15253
  }
15183
15254
  if (this.#sizes) {
15184
15255
  this.#sizes.fill(0);
@@ -16790,6 +16861,8 @@ const adaptic = {
16790
16861
  backend: {
16791
16862
  fetchAssetOverview: fetchAssetOverview,
16792
16863
  getApolloClient: getSharedApolloClient,
16864
+ configureAuth: configureAuth,
16865
+ isAuthConfigured: isAuthConfigured,
16793
16866
  },
16794
16867
  alpaca: {
16795
16868
  TradingAPI: AlpacaTradingAPI,