initial update

This commit is contained in:
jackbeeby
2025-05-15 13:32:55 +10:00
commit 7b07a49fbe
4412 changed files with 909535 additions and 0 deletions

21
node_modules/@apollo/utils.keyvaluecache/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2022 Apollo Graph, Inc. (Formerly Meteor Development Group, Inc.)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

67
node_modules/@apollo/utils.keyvaluecache/README.md generated vendored Normal file
View File

@@ -0,0 +1,67 @@
# KeyValueCache interface
```ts
export interface KeyValueCache<V = string> {
get(key: string): Promise<V | undefined>;
set(key: string, value: V, options?: KeyValueCacheSetOptions): Promise<void>;
delete(key: string): Promise<boolean | void>;
}
```
This interface defines a minimally-compatible cache intended for (but not limited to) use by Apollo Server. It is notably implemented by `KeyvAdapter` from the `@apollo/utils.keyvadapter` package. (`KeyvAdapter` in conjunction with a `Keyv` is probably more interesting to you unless you're actually building a cache!)
# InMemoryLRUCache
This class wraps `lru-cache` and implements the `KeyValueCache` interface. It accepts `LRUCache.Options` as the constructor argument and passes them to the `LRUCache` which is created. A default `maxSize` and `sizeCalculator` are provided in order to prevent an unbounded cache; these can both be tweaked via the constructor argument.
```ts
const cache = new InMemoryLRUCache({
// create a larger-than-default `LRUCache`
maxSize: Math.pow(2, 20) * 50,
});
```
# PrefixingKeyValueCache
This class wraps a `KeyValueCache` in order to provide a specified prefix for keys entering the cache via this wrapper.
```ts
const cache = new InMemoryLRUCache();
const prefixedCache = new PrefixingKeyValueCache(cache, "apollo:");
```
One reason to use this is if a single piece of software wants to use a cache for multiple features. For example, you can pass a `KeyValueCache` as the `cache` option to `@apollo/server`'s `ApolloServer` class; it provides this cache to plugins and other features as a default cache to use (if the user does not provide the specific plugin its own cache). Each feature uses `PrefixingKeyValueCache` with a different prefix to prevent different features from stomping on each others' data.
However, if you are configuring one of those features explicitly, you may _not_ want this prefix to be added. In that case, you can wrap your cache in a cache returned by `PrefixingKeyValueCache.cacheDangerouslyDoesNotNeedPrefixesForIsolation`. The only difference between this cache and the cache that it wraps is that when it is passed directly to a `PrefixingKeyValueCache`, no prefix is applied.
That is, let's say you are using a class that is implemented like this:
```ts
class SomePlugin {
private cache: KeyValueCache;
constructor(cache: KeyValueCache) {
this.cache = new PrefixingKeyValueCache(cache, "some:");
}
}
```
If you set up your plugin as `new SomePlugin({ cache: myRedisCache })` then the plugin will add `some:` to all keys when interacting with your cache, but if you set it up as `new SomePlugin({ cache: PrefixingKeyValueCache.cacheDangerouslyDoesNotNeedPrefixesForIsolation(myRedisCache) })`, then the plugin will not apply its prefix. You should only do this if you feel confident that this feature's use of this cache will not overlap with another feature: perhaps this is the only feature you have configured to use this cache, or perhaps the feature provides suitable control over cache keys that you can ensure isolation without needing the plugin's prefix.
Software like `ApolloServer` that passes a single `KeyValueCache` to several features should throw if a `PrefixesAreUnnecessaryForIsolationCache` is provided to it; it can check this condition with the static `PrefixingKeyValueCache.prefixesAreUnnecessaryForIsolation` method (which is safer than an `instanceof` check in case there are multiple copies of `@apollo/utils.keyvaluecache` installed).
# ErrorsAreMissesCache
This class wraps a `KeyValueCache` in order to provide error tolerance for caches which connect via a client like Redis. In the event that there's an _error_, this wrapper will treat it as a cache miss (and log the error instead, if a `logger` is provided).
An example usage (which makes use of the `keyv` Redis client and our `KeyvAdapter`) would look something like this:
```ts
import Keyv from "keyv";
import { KeyvAdapter } from "@apollo/utils.keyvadapter";
import { ErrorsAreMissesCache } from "@apollo/utils.keyvaluecache";
const redisCache = new Keyv("redis://user:pass@localhost:6379");
const faultTolerantCache = new ErrorsAreMissesCache(
new KeyvAdapter(redisCache),
);
```

View File

@@ -0,0 +1,13 @@
import type { KeyValueCache } from "./KeyValueCache";
import type { Logger } from "@apollo/utils.logger";
export declare class ErrorsAreMissesCache<V = string> implements KeyValueCache<V> {
private cache;
private logger?;
constructor(cache: KeyValueCache<V>, logger?: Logger | undefined);
get(key: string): Promise<V | undefined>;
set(key: string, value: V, opts?: {
ttl?: number;
}): Promise<void>;
delete(key: string): Promise<boolean | void>;
}
//# sourceMappingURL=ErrorsAreMissesCache.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"ErrorsAreMissesCache.d.ts","sourceRoot":"","sources":["../src/ErrorsAreMissesCache.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAOnD,qBAAa,oBAAoB,CAAC,CAAC,GAAG,MAAM,CAAE,YAAW,aAAa,CAAC,CAAC,CAAC;IAC3D,OAAO,CAAC,KAAK;IAAoB,OAAO,CAAC,MAAM,CAAC;gBAAxC,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,EAAU,MAAM,CAAC,oBAAQ;IAE9D,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC;IAexC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,CAAC,EAAE;QAAE,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAIlE,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC;CAGnD"}

View File

@@ -0,0 +1,33 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ErrorsAreMissesCache = void 0;
class ErrorsAreMissesCache {
constructor(cache, logger) {
this.cache = cache;
this.logger = logger;
}
async get(key) {
try {
return await this.cache.get(key);
}
catch (e) {
if (this.logger) {
if (e instanceof Error) {
this.logger.error(e.message);
}
else {
this.logger.error(e);
}
}
return undefined;
}
}
async set(key, value, opts) {
return this.cache.set(key, value, opts);
}
async delete(key) {
return this.cache.delete(key);
}
}
exports.ErrorsAreMissesCache = ErrorsAreMissesCache;
//# sourceMappingURL=ErrorsAreMissesCache.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"ErrorsAreMissesCache.js","sourceRoot":"","sources":["../src/ErrorsAreMissesCache.ts"],"names":[],"mappings":";;;AAQA,MAAa,oBAAoB;IAC/B,YAAoB,KAAuB,EAAU,MAAe;QAAhD,UAAK,GAAL,KAAK,CAAkB;QAAU,WAAM,GAAN,MAAM,CAAS;IAAG,CAAC;IAExE,KAAK,CAAC,GAAG,CAAC,GAAW;QACnB,IAAI;YACF,OAAO,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;SAClC;QAAC,OAAO,CAAC,EAAE;YACV,IAAI,IAAI,CAAC,MAAM,EAAE;gBACf,IAAI,CAAC,YAAY,KAAK,EAAE;oBACtB,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;iBAC9B;qBAAM;oBACL,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;iBACtB;aACF;YACD,OAAO,SAAS,CAAC;SAClB;IACH,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,GAAW,EAAE,KAAQ,EAAE,IAAuB;QACtD,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;IAC1C,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,GAAW;QACtB,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAChC,CAAC;CACF;AAzBD,oDAyBC"}

View File

@@ -0,0 +1,13 @@
import LRUCache from "lru-cache";
import type { KeyValueCache, KeyValueCacheSetOptions } from "./KeyValueCache";
export declare class InMemoryLRUCache<T = string> implements KeyValueCache<T> {
private cache;
constructor(lruCacheOpts?: LRUCache.Options<string, T>);
static sizeCalculation<T>(item: T): number;
set(key: string, value: T, options?: KeyValueCacheSetOptions): Promise<void>;
get(key: string): Promise<T | undefined>;
delete(key: string): Promise<boolean>;
clear(): void;
keys(): string[];
}
//# sourceMappingURL=InMemoryLRUCache.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"InMemoryLRUCache.d.ts","sourceRoot":"","sources":["../src/InMemoryLRUCache.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,WAAW,CAAC;AACjC,OAAO,KAAK,EAAE,aAAa,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAG9E,qBAAa,gBAAgB,CAAC,CAAC,GAAG,MAAM,CAAE,YAAW,aAAa,CAAC,CAAC,CAAC;IACnE,OAAO,CAAC,KAAK,CAAsB;gBAEvB,YAAY,CAAC,EAAE,QAAQ,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IActD,MAAM,CAAC,eAAe,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;IAW3B,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,CAAC,EAAE,uBAAuB;IAQ5D,GAAG,CAAC,GAAG,EAAE,MAAM;IAIf,MAAM,CAAC,GAAG,EAAE,MAAM;IAIxB,KAAK;IAIL,IAAI;CAIL"}

View File

@@ -0,0 +1,47 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.InMemoryLRUCache = void 0;
const lru_cache_1 = __importDefault(require("lru-cache"));
class InMemoryLRUCache {
constructor(lruCacheOpts) {
this.cache = new lru_cache_1.default({
sizeCalculation: InMemoryLRUCache.sizeCalculation,
maxSize: Math.pow(2, 20) * 30,
...lruCacheOpts,
});
}
static sizeCalculation(item) {
if (typeof item === "string") {
return item.length;
}
if (typeof item === "object") {
return Buffer.byteLength(JSON.stringify(item), "utf8");
}
return 1;
}
async set(key, value, options) {
if (options === null || options === void 0 ? void 0 : options.ttl) {
this.cache.set(key, value, { ttl: options.ttl * 1000 });
}
else {
this.cache.set(key, value);
}
}
async get(key) {
return this.cache.get(key);
}
async delete(key) {
return this.cache.delete(key);
}
clear() {
this.cache.clear();
}
keys() {
return [...this.cache.keys()];
}
}
exports.InMemoryLRUCache = InMemoryLRUCache;
//# sourceMappingURL=InMemoryLRUCache.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"InMemoryLRUCache.js","sourceRoot":"","sources":["../src/InMemoryLRUCache.ts"],"names":[],"mappings":";;;;;;AAAA,0DAAiC;AAIjC,MAAa,gBAAgB;IAG3B,YAAY,YAA0C;QACpD,IAAI,CAAC,KAAK,GAAG,IAAI,mBAAQ,CAAC;YACxB,eAAe,EAAE,gBAAgB,CAAC,eAAe;YAGjD,OAAO,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,EAAE;YAC7B,GAAG,YAAY;SAChB,CAAC,CAAC;IACL,CAAC;IAMD,MAAM,CAAC,eAAe,CAAI,IAAO;QAC/B,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE;YAC5B,OAAO,IAAI,CAAC,MAAM,CAAC;SACpB;QACD,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE;YAE5B,OAAO,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,CAAC;SACxD;QACD,OAAO,CAAC,CAAC;IACX,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,GAAW,EAAE,KAAQ,EAAE,OAAiC;QAChE,IAAI,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,GAAG,EAAE;YAChB,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,GAAG,IAAI,EAAE,CAAC,CAAC;SACzD;aAAM;YACL,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;SAC5B;IACH,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,GAAW;QACnB,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC7B,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,GAAW;QACtB,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAChC,CAAC;IAED,KAAK;QACH,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;IACrB,CAAC;IAED,IAAI;QAEF,OAAO,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;IAChC,CAAC;CACF;AApDD,4CAoDC"}

View File

@@ -0,0 +1,9 @@
export interface KeyValueCache<V = string> {
get(key: string): Promise<V | undefined>;
set(key: string, value: V, options?: KeyValueCacheSetOptions): Promise<void>;
delete(key: string): Promise<boolean | void>;
}
export interface KeyValueCacheSetOptions {
ttl?: number | null;
}
//# sourceMappingURL=KeyValueCache.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"KeyValueCache.d.ts","sourceRoot":"","sources":["../src/KeyValueCache.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa,CAAC,CAAC,GAAG,MAAM;IACvC,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC;IACzC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,CAAC,EAAE,uBAAuB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7E,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC;CAC9C;AAED,MAAM,WAAW,uBAAuB;IAKtC,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB"}

View File

@@ -0,0 +1,3 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=KeyValueCache.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"KeyValueCache.js","sourceRoot":"","sources":["../src/KeyValueCache.ts"],"names":[],"mappings":""}

View File

@@ -0,0 +1,15 @@
import type { KeyValueCache, KeyValueCacheSetOptions } from ".";
declare const prefixesAreUnnecessaryForIsolationSymbol: unique symbol;
export declare class PrefixingKeyValueCache<V = string> implements KeyValueCache<V> {
private wrapped;
private prefix;
[prefixesAreUnnecessaryForIsolationSymbol]?: true;
constructor(wrapped: KeyValueCache<V>, prefix: string);
get(key: string): Promise<V | undefined>;
set(key: string, value: V, options?: KeyValueCacheSetOptions): Promise<void>;
delete(key: string): Promise<boolean | void>;
static prefixesAreUnnecessaryForIsolation<V = string>(c: KeyValueCache<V>): boolean;
static cacheDangerouslyDoesNotNeedPrefixesForIsolation<V = string>(c: KeyValueCache<V>): KeyValueCache<V>;
}
export {};
//# sourceMappingURL=PrefixingKeyValueCache.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"PrefixingKeyValueCache.d.ts","sourceRoot":"","sources":["../src/PrefixingKeyValueCache.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,uBAAuB,EAAE,MAAM,GAAG,CAAC;AAEhE,QAAA,MAAM,wCAAwC,eAE7C,CAAC;AAYF,qBAAa,sBAAsB,CAAC,CAAC,GAAG,MAAM,CAAE,YAAW,aAAa,CAAC,CAAC,CAAC;IAI7D,OAAO,CAAC,OAAO;IAH3B,OAAO,CAAC,MAAM,CAAS;IACvB,CAAC,wCAAwC,CAAC,CAAC,EAAE,IAAI,CAAC;gBAE9B,OAAO,EAAE,aAAa,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM;IAa7D,GAAG,CAAC,GAAG,EAAE,MAAM;IAGf,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,CAAC,EAAE,uBAAuB;IAG5D,MAAM,CAAC,GAAG,EAAE,MAAM;IAOlB,MAAM,CAAC,kCAAkC,CAAC,CAAC,GAAG,MAAM,EAClD,CAAC,EAAE,aAAa,CAAC,CAAC,CAAC,GAClB,OAAO;IAIV,MAAM,CAAC,+CAA+C,CAAC,CAAC,GAAG,MAAM,EAC/D,CAAC,EAAE,aAAa,CAAC,CAAC,CAAC,GAClB,aAAa,CAAC,CAAC,CAAC;CAGpB"}

View File

@@ -0,0 +1,50 @@
"use strict";
var _a;
Object.defineProperty(exports, "__esModule", { value: true });
exports.PrefixingKeyValueCache = void 0;
const prefixesAreUnnecessaryForIsolationSymbol = Symbol("prefixesAreUnnecessaryForIsolation");
class PrefixingKeyValueCache {
constructor(wrapped, prefix) {
this.wrapped = wrapped;
if (PrefixingKeyValueCache.prefixesAreUnnecessaryForIsolation(wrapped)) {
this.prefix = "";
this[prefixesAreUnnecessaryForIsolationSymbol] = true;
}
else {
this.prefix = prefix;
}
}
get(key) {
return this.wrapped.get(this.prefix + key);
}
set(key, value, options) {
return this.wrapped.set(this.prefix + key, value, options);
}
delete(key) {
return this.wrapped.delete(this.prefix + key);
}
static prefixesAreUnnecessaryForIsolation(c) {
return prefixesAreUnnecessaryForIsolationSymbol in c;
}
static cacheDangerouslyDoesNotNeedPrefixesForIsolation(c) {
return new PrefixesAreUnnecessaryForIsolationCache(c);
}
}
exports.PrefixingKeyValueCache = PrefixingKeyValueCache;
class PrefixesAreUnnecessaryForIsolationCache {
constructor(wrapped) {
this.wrapped = wrapped;
this[_a] = true;
}
get(key) {
return this.wrapped.get(key);
}
set(key, value, options) {
return this.wrapped.set(key, value, options);
}
delete(key) {
return this.wrapped.delete(key);
}
}
_a = prefixesAreUnnecessaryForIsolationSymbol;
//# sourceMappingURL=PrefixingKeyValueCache.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"PrefixingKeyValueCache.js","sourceRoot":"","sources":["../src/PrefixingKeyValueCache.ts"],"names":[],"mappings":";;;;AAEA,MAAM,wCAAwC,GAAG,MAAM,CACrD,oCAAoC,CACrC,CAAC;AAYF,MAAa,sBAAsB;IAIjC,YAAoB,OAAyB,EAAE,MAAc;QAAzC,YAAO,GAAP,OAAO,CAAkB;QAC3C,IAAI,sBAAsB,CAAC,kCAAkC,CAAC,OAAO,CAAC,EAAE;YACtE,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC;YAKjB,IAAI,CAAC,wCAAwC,CAAC,GAAG,IAAI,CAAC;SACvD;aAAM;YACL,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;SACtB;IACH,CAAC;IAED,GAAG,CAAC,GAAW;QACb,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC;IAC7C,CAAC;IACD,GAAG,CAAC,GAAW,EAAE,KAAQ,EAAE,OAAiC;QAC1D,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,GAAG,GAAG,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;IAC7D,CAAC;IACD,MAAM,CAAC,GAAW;QAChB,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC;IAChD,CAAC;IAKD,MAAM,CAAC,kCAAkC,CACvC,CAAmB;QAEnB,OAAO,wCAAwC,IAAI,CAAC,CAAC;IACvD,CAAC;IAED,MAAM,CAAC,+CAA+C,CACpD,CAAmB;QAEnB,OAAO,IAAI,uCAAuC,CAAC,CAAC,CAAC,CAAC;IACxD,CAAC;CACF;AAzCD,wDAyCC;AAID,MAAM,uCAAuC;IAK3C,YAAoB,OAAyB;QAAzB,YAAO,GAAP,OAAO,CAAkB;QAF7C,QAA0C,GAAG,IAAI,CAAC;IAEF,CAAC;IAEjD,GAAG,CAAC,GAAW;QACb,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC/B,CAAC;IACD,GAAG,CAAC,GAAW,EAAE,KAAQ,EAAE,OAAiC;QAC1D,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;IAC/C,CAAC;IACD,MAAM,CAAC,GAAW;QAChB,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAClC,CAAC;CACF;KAbE,wCAAwC"}

View File

@@ -0,0 +1,5 @@
export type { KeyValueCache, KeyValueCacheSetOptions } from "./KeyValueCache";
export { PrefixingKeyValueCache } from "./PrefixingKeyValueCache";
export { InMemoryLRUCache } from "./InMemoryLRUCache";
export { ErrorsAreMissesCache } from "./ErrorsAreMissesCache";
//# sourceMappingURL=index.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,aAAa,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAC9E,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC"}

10
node_modules/@apollo/utils.keyvaluecache/dist/index.js generated vendored Normal file
View File

@@ -0,0 +1,10 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ErrorsAreMissesCache = exports.InMemoryLRUCache = exports.PrefixingKeyValueCache = void 0;
var PrefixingKeyValueCache_1 = require("./PrefixingKeyValueCache");
Object.defineProperty(exports, "PrefixingKeyValueCache", { enumerable: true, get: function () { return PrefixingKeyValueCache_1.PrefixingKeyValueCache; } });
var InMemoryLRUCache_1 = require("./InMemoryLRUCache");
Object.defineProperty(exports, "InMemoryLRUCache", { enumerable: true, get: function () { return InMemoryLRUCache_1.InMemoryLRUCache; } });
var ErrorsAreMissesCache_1 = require("./ErrorsAreMissesCache");
Object.defineProperty(exports, "ErrorsAreMissesCache", { enumerable: true, get: function () { return ErrorsAreMissesCache_1.ErrorsAreMissesCache; } });
//# sourceMappingURL=index.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AACA,mEAAkE;AAAzD,gIAAA,sBAAsB,OAAA;AAC/B,uDAAsD;AAA7C,oHAAA,gBAAgB,OAAA;AACzB,+DAA8D;AAArD,4HAAA,oBAAoB,OAAA"}

27
node_modules/@apollo/utils.keyvaluecache/package.json generated vendored Normal file
View File

@@ -0,0 +1,27 @@
{
"name": "@apollo/utils.keyvaluecache",
"version": "2.1.1",
"description": "Minimal key-value cache interface",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"repository": {
"type": "git",
"url": "git+https://github.com/apollographql/apollo-utils.git",
"directory": "packages/keyValueCache/"
},
"keywords": [
"apollo",
"graphql",
"typescript",
"node"
],
"author": "Apollo <packages@apollographql.com>",
"license": "MIT",
"engines": {
"node": ">=14"
},
"dependencies": {
"@apollo/utils.logger": "^2.0.1",
"lru-cache": "^7.14.1"
}
}

View File

@@ -0,0 +1,34 @@
import type { KeyValueCache } from "./KeyValueCache";
import type { Logger } from "@apollo/utils.logger";
/**
* This cache wraps a KeyValueCache and returns undefined (a cache miss) for any
* errors thrown by the underlying cache. You can also provide a logger to
* capture these errors rather than just swallow them.
*/
export class ErrorsAreMissesCache<V = string> implements KeyValueCache<V> {
constructor(private cache: KeyValueCache<V>, private logger?: Logger) {}
async get(key: string): Promise<V | undefined> {
try {
return await this.cache.get(key);
} catch (e) {
if (this.logger) {
if (e instanceof Error) {
this.logger.error(e.message);
} else {
this.logger.error(e);
}
}
return undefined;
}
}
async set(key: string, value: V, opts?: { ttl?: number }): Promise<void> {
return this.cache.set(key, value, opts);
}
async delete(key: string): Promise<boolean | void> {
return this.cache.delete(key);
}
}

View File

@@ -0,0 +1,57 @@
import LRUCache from "lru-cache";
import type { KeyValueCache, KeyValueCacheSetOptions } from "./KeyValueCache";
// LRUCache wrapper to implement the KeyValueCache interface.
export class InMemoryLRUCache<T = string> implements KeyValueCache<T> {
private cache: LRUCache<string, T>;
constructor(lruCacheOpts?: LRUCache.Options<string, T>) {
this.cache = new LRUCache({
sizeCalculation: InMemoryLRUCache.sizeCalculation,
// Create ~about~ a 30MiB cache by default. Configurable by providing
// `lruCacheOpts`.
maxSize: Math.pow(2, 20) * 30,
...lruCacheOpts,
});
}
/**
* default size calculator for strings and serializable objects, else naively
* return 1
*/
static sizeCalculation<T>(item: T) {
if (typeof item === "string") {
return item.length;
}
if (typeof item === "object") {
// will throw if the object has circular references
return Buffer.byteLength(JSON.stringify(item), "utf8");
}
return 1;
}
async set(key: string, value: T, options?: KeyValueCacheSetOptions) {
if (options?.ttl) {
this.cache.set(key, value, { ttl: options.ttl * 1000 });
} else {
this.cache.set(key, value);
}
}
async get(key: string) {
return this.cache.get(key);
}
async delete(key: string) {
return this.cache.delete(key);
}
clear() {
this.cache.clear();
}
keys() {
// LRUCache.keys() returns a generator (we just want an array)
return [...this.cache.keys()];
}
}

View File

@@ -0,0 +1,13 @@
export interface KeyValueCache<V = string> {
get(key: string): Promise<V | undefined>;
set(key: string, value: V, options?: KeyValueCacheSetOptions): Promise<void>;
delete(key: string): Promise<boolean | void>;
}
export interface KeyValueCacheSetOptions {
/**
* Specified in **seconds**, the time-to-live (TTL) value limits the lifespan
* of the data being stored in the cache.
*/
ttl?: number | null;
}

View File

@@ -0,0 +1,78 @@
import type { KeyValueCache, KeyValueCacheSetOptions } from ".";
const prefixesAreUnnecessaryForIsolationSymbol = Symbol(
"prefixesAreUnnecessaryForIsolation",
);
// PrefixingKeyValueCache wraps another cache and adds a prefix to all keys used
// by all operations. This allows multiple features to share the same underlying
// cache without conflicts.
//
// Note that PrefixingKeyValueCache explicitly does not implement methods like
// flush() that aren't part of KeyValueCache, even though most KeyValueCache
// implementations also have a flush() method. Most implementations of flush()
// send a simple command that wipes the entire backend cache system, which
// wouldn't support "only wipe the part of the cache with this prefix", so
// trying to provide a flush() method here could be confusingly dangerous.
export class PrefixingKeyValueCache<V = string> implements KeyValueCache<V> {
private prefix: string;
[prefixesAreUnnecessaryForIsolationSymbol]?: true;
constructor(private wrapped: KeyValueCache<V>, prefix: string) {
if (PrefixingKeyValueCache.prefixesAreUnnecessaryForIsolation(wrapped)) {
this.prefix = "";
// If we try to again prefix this cache, we should still skip the
// prefixing. (This would be cleaner if we made PrefixingKeyValueCaches
// via a static method rather than the constructor and could just return
// `wrapped`...)
this[prefixesAreUnnecessaryForIsolationSymbol] = true;
} else {
this.prefix = prefix;
}
}
get(key: string) {
return this.wrapped.get(this.prefix + key);
}
set(key: string, value: V, options?: KeyValueCacheSetOptions) {
return this.wrapped.set(this.prefix + key, value, options);
}
delete(key: string) {
return this.wrapped.delete(this.prefix + key);
}
// Checks to see if a cache is a PrefixesAreUnnecessaryForIsolationCache,
// without using instanceof (so that installing multiple copies of this
// package doesn't break things).
static prefixesAreUnnecessaryForIsolation<V = string>(
c: KeyValueCache<V>,
): boolean {
return prefixesAreUnnecessaryForIsolationSymbol in c;
}
static cacheDangerouslyDoesNotNeedPrefixesForIsolation<V = string>(
c: KeyValueCache<V>,
): KeyValueCache<V> {
return new PrefixesAreUnnecessaryForIsolationCache(c);
}
}
// This class lets you opt a cache out of the prefixing provided by
// PrefixingKeyValueCache. See the README for details.
class PrefixesAreUnnecessaryForIsolationCache<V = string>
implements KeyValueCache<V>
{
[prefixesAreUnnecessaryForIsolationSymbol] = true;
constructor(private wrapped: KeyValueCache<V>) {}
get(key: string) {
return this.wrapped.get(key);
}
set(key: string, value: V, options?: KeyValueCacheSetOptions) {
return this.wrapped.set(key, value, options);
}
delete(key: string) {
return this.wrapped.delete(key);
}
}

View File

@@ -0,0 +1,58 @@
import type { Logger } from "@apollo/utils.logger";
import { ErrorsAreMissesCache } from "../ErrorsAreMissesCache";
import type { KeyValueCache } from "../KeyValueCache";
describe("ErrorsAreMissesCache", () => {
const knownErrorMessage = "Service is down";
const errorProneCache: KeyValueCache = {
async get() {
throw new Error(knownErrorMessage);
},
async set() {},
async delete() {},
};
it("returns undefined when the underlying cache throws an error", async () => {
const errorsAreMisses = new ErrorsAreMissesCache(errorProneCache);
await expect(errorProneCache.get("foo")).rejects.toBeInstanceOf(Error);
await expect(errorsAreMisses.get("foo")).resolves.toBe(undefined);
});
it("logs to provided logger when underlying cache throws", async () => {
let loggedMessage = "";
const logger: Logger = {
debug() {},
info() {},
warn() {},
error: (message) => {
loggedMessage = message;
},
};
const errorsAreMisses = new ErrorsAreMissesCache(errorProneCache, logger);
await expect(errorsAreMisses.get("foo")).resolves.toBe(undefined);
expect(loggedMessage).toBe(knownErrorMessage);
});
it("passes through calls to the underlying cache", async () => {
const mockCache: KeyValueCache = {
get: jest.fn(async () => "foo"),
set: jest.fn(),
delete: jest.fn(),
};
const errorsAreMisses = new ErrorsAreMissesCache(mockCache);
await expect(errorsAreMisses.get("key")).resolves.toBe("foo");
expect(mockCache.get).toHaveBeenCalledWith("key");
await errorsAreMisses.set("key", "foo");
expect(mockCache.set).toHaveBeenCalledWith("key", "foo", undefined);
await errorsAreMisses.set("keyWithTTL", "foo", { ttl: 1000 });
expect(mockCache.set).toHaveBeenLastCalledWith("keyWithTTL", "foo", {
ttl: 1000,
});
await errorsAreMisses.delete("key");
expect(mockCache.delete).toHaveBeenCalledWith("key");
});
});

View File

@@ -0,0 +1,47 @@
import { InMemoryLRUCache } from "..";
describe("InMemoryLRUCache", () => {
const cache = new InMemoryLRUCache();
it("can set and get", async () => {
await cache.set("hello", "world");
expect(await cache.get("hello")).toEqual("world");
expect(await cache.get("missing")).toEqual(undefined);
});
it("can set and delete", async () => {
await cache.set("hello2", "world");
expect(await cache.get("hello2")).toEqual("world");
await cache.delete("hello2");
expect(await cache.get("hello2")).toEqual(undefined);
});
it("can expire keys based on ttl", async () => {
await cache.set("short", "s", { ttl: 0.01 });
await cache.set("long", "l", { ttl: 0.05 });
expect(await cache.get("short")).toEqual("s");
expect(await cache.get("long")).toEqual("l");
await sleep(15);
expect(await cache.get("short")).toEqual(undefined);
expect(await cache.get("long")).toEqual("l");
await sleep(40);
expect(await cache.get("short")).toEqual(undefined);
expect(await cache.get("long")).toEqual(undefined);
});
it("does not expire when ttl is null", async () => {
await cache.set("forever", "yours", { ttl: null });
expect(await cache.get("forever")).toEqual("yours");
await sleep(1000);
expect(await cache.get("forever")).toEqual("yours");
});
});
async function sleep(ms: number) {
return new Promise((resolve) => setTimeout(resolve, ms));
}

View File

@@ -0,0 +1,48 @@
import { InMemoryLRUCache } from "..";
import { PrefixingKeyValueCache } from "../PrefixingKeyValueCache";
describe("PrefixingKeyValueCache", () => {
it("prefixes", async () => {
const inner = new InMemoryLRUCache();
const prefixing = new PrefixingKeyValueCache(inner, "prefix:");
await prefixing.set("foo", "bar");
expect(await prefixing.get("foo")).toBe("bar");
expect(await inner.get("prefix:foo")).toBe("bar");
await prefixing.delete("foo");
expect(await prefixing.get("foo")).toBe(undefined);
});
it("PrefixesAreUnnecessaryForIsolationCache", async () => {
const inner = new InMemoryLRUCache();
const prefixesAreUnnecessaryForIsolationCache =
PrefixingKeyValueCache.cacheDangerouslyDoesNotNeedPrefixesForIsolation(
inner,
);
const prefixing = new PrefixingKeyValueCache(
prefixesAreUnnecessaryForIsolationCache,
"prefix:",
);
for (const cache of [prefixesAreUnnecessaryForIsolationCache, prefixing]) {
await cache.set("x", "a");
expect(await cache.get("x")).toBe("a");
expect(inner.keys().length).toBe(1);
// The prefix is not applied!
expect(await inner.get("x")).toBe("a");
await cache.delete("x");
expect(await cache.get("x")).toBe(undefined);
expect(inner.keys().length).toBe(0);
}
expect(
PrefixingKeyValueCache.prefixesAreUnnecessaryForIsolation(inner),
).toBe(false);
expect(
PrefixingKeyValueCache.prefixesAreUnnecessaryForIsolation(
prefixesAreUnnecessaryForIsolationCache,
),
).toBe(true);
expect(
PrefixingKeyValueCache.prefixesAreUnnecessaryForIsolation(prefixing),
).toBe(true);
});
});

View File

@@ -0,0 +1,101 @@
import { expectType } from "ts-expect";
import type { KeyValueCache } from "..";
describe("KeyValueCache", () => {
const minimalCompatibleCache = {
get: async (_key: string) => undefined,
set: async (_key: string, _value: string, _options?: { ttl?: number }) =>
undefined,
delete: async (_key: string) => undefined,
};
it("minimum implementation type-checks", () => {
expectType<KeyValueCache<string>>(minimalCompatibleCache);
});
describe("type-check failures", () => {
it("get", () => {
const { get, ...cacheNoGet } = minimalCompatibleCache;
// @ts-expect-error
expectType<KeyValueCache<string>>(cacheNoGet);
{
const cacheBadGet = {
...minimalCompatibleCache,
// no async
get: (_key: string) => undefined,
};
// @ts-expect-error
expectType<KeyValueCache<string>>(cacheBadGet);
}
{
const cacheBadGet = {
...minimalCompatibleCache,
// incompatible type
get: async (_key: number) => undefined,
};
// @ts-expect-error
expectType<KeyValueCache<string>>(cacheBadGet);
}
});
it("set", () => {
const { set, ...cacheNoSet } = minimalCompatibleCache;
// @ts-expect-error
expectType<KeyValueCache<string>>(cacheNoSet);
{
const cacheBadSet = {
...minimalCompatibleCache,
// no async
set: (_key: string) => undefined,
};
// @ts-expect-error
expectType<KeyValueCache<string>>(cacheBadSet);
}
{
const cacheBadSet = {
...minimalCompatibleCache,
// incompatible type
set: async (_key: number) => undefined,
};
// @ts-expect-error
expectType<KeyValueCache<string>>(cacheBadSet);
}
});
it("delete", () => {
const { delete: _delete, ...cacheNoDelete } = minimalCompatibleCache;
// @ts-expect-error
expectType<KeyValueCache<string>>(cacheNoDelete);
{
const cacheBadDelete = {
...minimalCompatibleCache,
// no async
delete: (_key: string) => undefined,
};
// @ts-expect-error
expectType<KeyValueCache<string>>(cacheBadDelete);
}
{
const cacheBadDelete = {
...minimalCompatibleCache,
// incompatible type
delete: async (_key: number) => undefined,
};
// @ts-expect-error
expectType<KeyValueCache<string>>(cacheBadDelete);
}
});
});
});

View File

@@ -0,0 +1,12 @@
{
"extends": "../../../../tsconfig.test.base",
"include": ["**/*"],
"references": [
{
"path": "../../"
},
{
"path": "../../../logger"
}
]
}

View File

@@ -0,0 +1,4 @@
export type { KeyValueCache, KeyValueCacheSetOptions } from "./KeyValueCache";
export { PrefixingKeyValueCache } from "./PrefixingKeyValueCache";
export { InMemoryLRUCache } from "./InMemoryLRUCache";
export { ErrorsAreMissesCache } from "./ErrorsAreMissesCache";