@atproto-labs/simple-store-redis 0.0.1

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 ADDED
@@ -0,0 +1,7 @@
1
+ # @atproto-labs/simple-store-redis
2
+
3
+ ## 0.0.1
4
+
5
+ ### Patch Changes
6
+
7
+ - [#4149](https://github.com/bluesky-social/atproto/pull/4149) [`8914f9abd`](https://github.com/bluesky-social/atproto/commit/8914f9abde2059c551d7e4c8d104227986098b82) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Initial implementation of redis based `SimpleStore` implementation
package/LICENSE.txt ADDED
@@ -0,0 +1,7 @@
1
+ Dual MIT/Apache-2.0 License
2
+
3
+ Copyright (c) 2022-2025 Bluesky Social PBC, and Contributors
4
+
5
+ Except as otherwise noted in individual files, this software is licensed under the MIT license (<http://opensource.org/licenses/MIT>), or the Apache License, Version 2.0 (<http://www.apache.org/licenses/LICENSE-2.0>).
6
+
7
+ Downstream projects and end users may chose either license individually, or both together, at their discretion. The motivation for this dual-licensing is the additional software patent assurance provided by Apache 2.0.
@@ -0,0 +1,26 @@
1
+ import type { Redis } from 'ioredis';
2
+ import { Awaitable, GetOptions, SimpleStore, Value } from '@atproto-labs/simple-store';
3
+ export type { Awaitable, GetOptions, SimpleStore, Value };
4
+ export type Encoder<K extends string, V extends Value> = (value: V, key: K) => Awaitable<string>;
5
+ export type Decoder<K extends string, V extends Value> = (value: string, key: K) => Awaitable<V>;
6
+ export declare const defaultEncoder: Encoder<any, Value>;
7
+ export declare const defaultDecoder: Decoder<any, Value>;
8
+ export type SimpleStoreRedisOptions<K extends string, V extends Value> = {
9
+ keyPrefix: string;
10
+ /** In milliseconds */
11
+ ttl?: number;
12
+ /** @default JSON.stringify */
13
+ encode?: Encoder<K, V>;
14
+ /** @default JSON.parse */
15
+ decode?: Decoder<K, V>;
16
+ };
17
+ export declare class SimpleStoreRedis<K extends string, V extends Value> implements SimpleStore<K, V> {
18
+ protected readonly redis: Redis;
19
+ protected readonly options: SimpleStoreRedisOptions<K, V>;
20
+ constructor(redis: Redis, options: SimpleStoreRedisOptions<K, V>);
21
+ protected encodeKey(key: K): string;
22
+ get(key: K, options?: GetOptions): Promise<V | undefined>;
23
+ set(key: K, value: V): Promise<void>;
24
+ del(key: K): Promise<void>;
25
+ }
26
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAA;AACpC,OAAO,EACL,SAAS,EACT,UAAU,EACV,WAAW,EACX,KAAK,EACN,MAAM,4BAA4B,CAAA;AAEnC,YAAY,EAAE,SAAS,EAAE,UAAU,EAAE,WAAW,EAAE,KAAK,EAAE,CAAA;AAEzD,MAAM,MAAM,OAAO,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,KAAK,IAAI,CACvD,KAAK,EAAE,CAAC,EACR,GAAG,EAAE,CAAC,KACH,SAAS,CAAC,MAAM,CAAC,CAAA;AACtB,MAAM,MAAM,OAAO,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,KAAK,IAAI,CACvD,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,CAAC,KACH,SAAS,CAAC,CAAC,CAAC,CAAA;AAEjB,eAAO,MAAM,cAAc,EAAE,OAAO,CAAC,GAAG,EAAE,KAAK,CACxB,CAAA;AACvB,eAAO,MAAM,cAAc,EAAE,OAAO,CAAC,GAAG,EAAE,KAAK,CAAgC,CAAA;AAE/E,MAAM,MAAM,uBAAuB,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,KAAK,IAAI;IACvE,SAAS,EAAE,MAAM,CAAA;IACjB,sBAAsB;IACtB,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,8BAA8B;IAC9B,MAAM,CAAC,EAAE,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;IACtB,0BAA0B;IAC1B,MAAM,CAAC,EAAE,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;CACvB,CAAA;AAED,qBAAa,gBAAgB,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,KAAK,CAC7D,YAAW,WAAW,CAAC,CAAC,EAAE,CAAC,CAAC;IAG1B,SAAS,CAAC,QAAQ,CAAC,KAAK,EAAE,KAAK;IAC/B,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,uBAAuB,CAAC,CAAC,EAAE,CAAC,CAAC;gBADtC,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,uBAAuB,CAAC,CAAC,EAAE,CAAC,CAAC;IAU3D,SAAS,CAAC,SAAS,CAAC,GAAG,EAAE,CAAC,GAAG,MAAM;IAI7B,GAAG,CAAC,GAAG,EAAE,CAAC,EAAE,OAAO,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC;IASzD,GAAG,CAAC,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAQpC,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;CAIjC"}
package/dist/index.js ADDED
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SimpleStoreRedis = exports.defaultDecoder = exports.defaultEncoder = void 0;
4
+ const defaultEncoder = (value) => JSON.stringify(value);
5
+ exports.defaultEncoder = defaultEncoder;
6
+ const defaultDecoder = (value) => JSON.parse(value);
7
+ exports.defaultDecoder = defaultDecoder;
8
+ class SimpleStoreRedis {
9
+ constructor(redis, options) {
10
+ Object.defineProperty(this, "redis", {
11
+ enumerable: true,
12
+ configurable: true,
13
+ writable: true,
14
+ value: redis
15
+ });
16
+ Object.defineProperty(this, "options", {
17
+ enumerable: true,
18
+ configurable: true,
19
+ writable: true,
20
+ value: options
21
+ });
22
+ if (!options.keyPrefix) {
23
+ throw new TypeError(`keyPrefix must be a non-empty string`);
24
+ }
25
+ if (options.ttl != null && options.ttl <= 0) {
26
+ throw new TypeError(`ttl must be greater than 0`);
27
+ }
28
+ }
29
+ encodeKey(key) {
30
+ return `${this.options.keyPrefix}${key}`;
31
+ }
32
+ async get(key, options) {
33
+ const eKey = this.encodeKey(key);
34
+ const eValue = await this.redis.get(eKey);
35
+ if (eValue == null)
36
+ return undefined;
37
+ options?.signal?.throwIfAborted();
38
+ const { decode = exports.defaultDecoder } = this.options;
39
+ return decode(eValue, key);
40
+ }
41
+ async set(key, value) {
42
+ const eKey = this.encodeKey(key);
43
+ const { encode = exports.defaultEncoder, ttl } = this.options;
44
+ const eValue = await encode(value, key);
45
+ if (ttl)
46
+ await this.redis.set(eKey, eValue, 'PX', ttl);
47
+ else
48
+ await this.redis.set(eKey, eValue);
49
+ }
50
+ async del(key) {
51
+ const eKey = this.encodeKey(key);
52
+ await this.redis.del(eKey);
53
+ }
54
+ }
55
+ exports.SimpleStoreRedis = SimpleStoreRedis;
56
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAmBO,MAAM,cAAc,GAAwB,CAAC,KAAK,EAAE,EAAE,CAC3D,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAA;AADV,QAAA,cAAc,kBACJ;AAChB,MAAM,cAAc,GAAwB,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;AAAlE,QAAA,cAAc,kBAAoD;AAY/E,MAAa,gBAAgB;IAG3B,YACqB,KAAY,EACZ,OAAsC;QADzD;;;;mBAAmB,KAAK;WAAO;QAC/B;;;;mBAAmB,OAAO;WAA+B;QAEzD,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC;YACvB,MAAM,IAAI,SAAS,CAAC,sCAAsC,CAAC,CAAA;QAC7D,CAAC;QACD,IAAI,OAAO,CAAC,GAAG,IAAI,IAAI,IAAI,OAAO,CAAC,GAAG,IAAI,CAAC,EAAE,CAAC;YAC5C,MAAM,IAAI,SAAS,CAAC,4BAA4B,CAAC,CAAA;QACnD,CAAC;IACH,CAAC;IAES,SAAS,CAAC,GAAM;QACxB,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,GAAG,GAAoB,EAAE,CAAA;IAC3D,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,GAAM,EAAE,OAAoB;QACpC,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAA;QAChC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;QACzC,IAAI,MAAM,IAAI,IAAI;YAAE,OAAO,SAAS,CAAA;QACpC,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,CAAA;QACjC,MAAM,EAAE,MAAM,GAAG,sBAAiC,EAAE,GAAG,IAAI,CAAC,OAAO,CAAA;QACnE,OAAO,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IAC5B,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,GAAM,EAAE,KAAQ;QACxB,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAA;QAChC,MAAM,EAAE,MAAM,GAAG,sBAAc,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,OAAO,CAAA;QACrD,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,KAAK,EAAE,GAAG,CAAC,CAAA;QACvC,IAAI,GAAG;YAAE,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,CAAC,CAAA;;YACjD,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,CAAA;IACzC,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,GAAM;QACd,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAA;QAChC,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;IAC5B,CAAC;CACF;AAxCD,4CAwCC"}
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "@atproto-labs/simple-store-redis",
3
+ "version": "0.0.1",
4
+ "license": "MIT",
5
+ "description": "Redis based simple-store implementation",
6
+ "keywords": [
7
+ "cache",
8
+ "node",
9
+ "memory"
10
+ ],
11
+ "homepage": "https://atproto.com",
12
+ "repository": {
13
+ "type": "git",
14
+ "url": "https://github.com/bluesky-social/atproto",
15
+ "directory": "packages/internal/simple-store-redis"
16
+ },
17
+ "type": "commonjs",
18
+ "main": "dist/index.js",
19
+ "types": "dist/index.d.ts",
20
+ "exports": {
21
+ ".": {
22
+ "types": "./dist/index.d.ts",
23
+ "default": "./dist/index.js"
24
+ }
25
+ },
26
+ "dependencies": {
27
+ "@atproto-labs/simple-store": "0.3.0"
28
+ },
29
+ "devDependencies": {
30
+ "typescript": "^5.6.3"
31
+ },
32
+ "peerDependencies": {
33
+ "ioredis": "^5.3.2"
34
+ },
35
+ "scripts": {
36
+ "build": "tsc --build tsconfig.build.json"
37
+ }
38
+ }
package/src/index.ts ADDED
@@ -0,0 +1,74 @@
1
+ import type { Redis } from 'ioredis'
2
+ import {
3
+ Awaitable,
4
+ GetOptions,
5
+ SimpleStore,
6
+ Value,
7
+ } from '@atproto-labs/simple-store'
8
+
9
+ export type { Awaitable, GetOptions, SimpleStore, Value }
10
+
11
+ export type Encoder<K extends string, V extends Value> = (
12
+ value: V,
13
+ key: K,
14
+ ) => Awaitable<string>
15
+ export type Decoder<K extends string, V extends Value> = (
16
+ value: string,
17
+ key: K,
18
+ ) => Awaitable<V>
19
+
20
+ export const defaultEncoder: Encoder<any, Value> = (value) =>
21
+ JSON.stringify(value)
22
+ export const defaultDecoder: Decoder<any, Value> = (value) => JSON.parse(value)
23
+
24
+ export type SimpleStoreRedisOptions<K extends string, V extends Value> = {
25
+ keyPrefix: string
26
+ /** In milliseconds */
27
+ ttl?: number
28
+ /** @default JSON.stringify */
29
+ encode?: Encoder<K, V>
30
+ /** @default JSON.parse */
31
+ decode?: Decoder<K, V>
32
+ }
33
+
34
+ export class SimpleStoreRedis<K extends string, V extends Value>
35
+ implements SimpleStore<K, V>
36
+ {
37
+ constructor(
38
+ protected readonly redis: Redis,
39
+ protected readonly options: SimpleStoreRedisOptions<K, V>,
40
+ ) {
41
+ if (!options.keyPrefix) {
42
+ throw new TypeError(`keyPrefix must be a non-empty string`)
43
+ }
44
+ if (options.ttl != null && options.ttl <= 0) {
45
+ throw new TypeError(`ttl must be greater than 0`)
46
+ }
47
+ }
48
+
49
+ protected encodeKey(key: K): string {
50
+ return `${this.options.keyPrefix}${key satisfies string}`
51
+ }
52
+
53
+ async get(key: K, options?: GetOptions): Promise<V | undefined> {
54
+ const eKey = this.encodeKey(key)
55
+ const eValue = await this.redis.get(eKey)
56
+ if (eValue == null) return undefined
57
+ options?.signal?.throwIfAborted()
58
+ const { decode = defaultDecoder as Decoder<any, V> } = this.options
59
+ return decode(eValue, key)
60
+ }
61
+
62
+ async set(key: K, value: V): Promise<void> {
63
+ const eKey = this.encodeKey(key)
64
+ const { encode = defaultEncoder, ttl } = this.options
65
+ const eValue = await encode(value, key)
66
+ if (ttl) await this.redis.set(eKey, eValue, 'PX', ttl)
67
+ else await this.redis.set(eKey, eValue)
68
+ }
69
+
70
+ async del(key: K): Promise<void> {
71
+ const eKey = this.encodeKey(key)
72
+ await this.redis.del(eKey)
73
+ }
74
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "extends": "../../../tsconfig/node.json",
3
+ "compilerOptions": {
4
+ "rootDir": "./src",
5
+ "outDir": "./dist"
6
+ },
7
+ "include": ["./src"]
8
+ }
@@ -0,0 +1 @@
1
+ {"root":["./src/index.ts"],"version":"5.8.3"}
package/tsconfig.json ADDED
@@ -0,0 +1,4 @@
1
+ {
2
+ "include": [],
3
+ "references": [{ "path": "./tsconfig.build.json" }]
4
+ }