@fedify/redis 2.0.0-dev.1875 → 2.0.0-dev.196

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/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright 2024–2025 Hong Minhee
3
+ Copyright 2024–2026 Hong Minhee
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy of
6
6
  this software and associated documentation files (the "Software"), to deal in
package/README.md CHANGED
@@ -38,10 +38,10 @@ const federation = createFederation({
38
38
  });
39
39
  ~~~~
40
40
 
41
- [JSR]: https://jsr.io/@fedify/redis
42
41
  [JSR badge]: https://jsr.io/badges/@fedify/redis
43
- [npm]: https://www.npmjs.com/package/@fedify/redis
42
+ [JSR]: https://jsr.io/@fedify/redis
44
43
  [npm badge]: https://img.shields.io/npm/v/@fedify/redis?logo=npm
44
+ [npm]: https://www.npmjs.com/package/@fedify/redis
45
45
  [Fedify]: https://fedify.dev/
46
46
  [`KvStore`]: https://jsr.io/@fedify/fedify/doc/federation/~/KvStore
47
47
  [`MessageQueue`]: https://jsr.io/@fedify/fedify/doc/federation/~/MessageQueue
package/dist/kv.cjs CHANGED
@@ -36,6 +36,7 @@ const node_buffer = require_rolldown_runtime.__toESM(require("node:buffer"));
36
36
  var RedisKvStore = class {
37
37
  #redis;
38
38
  #keyPrefix;
39
+ #keyPrefixStr;
39
40
  #codec;
40
41
  #textEncoder = new TextEncoder();
41
42
  /**
@@ -46,6 +47,7 @@ var RedisKvStore = class {
46
47
  constructor(redis, options = {}) {
47
48
  this.#redis = redis;
48
49
  this.#keyPrefix = options.keyPrefix ?? "fedify::";
50
+ this.#keyPrefixStr = typeof this.#keyPrefix === "string" ? this.#keyPrefix : new TextDecoder().decode(new Uint8Array(this.#keyPrefix));
49
51
  this.#codec = options.codec ?? new require_codec.JsonCodec();
50
52
  }
51
53
  #serializeKey(key) {
@@ -70,6 +72,45 @@ var RedisKvStore = class {
70
72
  const serializedKey = this.#serializeKey(key);
71
73
  await this.#redis.del(serializedKey);
72
74
  }
75
+ #deserializeKey(redisKey) {
76
+ const suffix = redisKey.slice(this.#keyPrefixStr.length);
77
+ return suffix.split("::").map((p) => p.replaceAll("_:", ":"));
78
+ }
79
+ /**
80
+ * {@inheritDoc KvStore.list}
81
+ * @since 1.10.0
82
+ */
83
+ async *list(prefix) {
84
+ let pattern;
85
+ let exactKey = null;
86
+ if (prefix == null || prefix.length === 0) pattern = `${this.#keyPrefixStr}*`;
87
+ else {
88
+ const prefixKey = this.#serializeKey(prefix);
89
+ const prefixKeyFullStr = typeof prefixKey === "string" ? prefixKey : new TextDecoder().decode(new Uint8Array(prefixKey));
90
+ exactKey = prefixKey;
91
+ pattern = `${prefixKeyFullStr}::*`;
92
+ }
93
+ if (exactKey != null) {
94
+ const exactValue = await this.#redis.getBuffer(exactKey);
95
+ if (exactValue != null) yield {
96
+ key: prefix,
97
+ value: this.#codec.decode(exactValue)
98
+ };
99
+ }
100
+ let cursor = "0";
101
+ do {
102
+ const [nextCursor, keys] = await this.#redis.scan(cursor, "MATCH", pattern, "COUNT", 100);
103
+ cursor = nextCursor;
104
+ for (const key of keys) {
105
+ const encodedValue = await this.#redis.getBuffer(key);
106
+ if (encodedValue == null) continue;
107
+ yield {
108
+ key: this.#deserializeKey(key),
109
+ value: this.#codec.decode(encodedValue)
110
+ };
111
+ }
112
+ } while (cursor !== "0");
113
+ }
73
114
  };
74
115
 
75
116
  //#endregion
package/dist/kv.d.cts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { Codec } from "./codec.cjs";
2
- import { KvKey, KvStore, KvStoreSetOptions } from "@fedify/fedify";
2
+ import { KvKey, KvStore, KvStoreListEntry, KvStoreSetOptions } from "@fedify/fedify";
3
3
  import { Cluster, Redis, RedisKey } from "ioredis";
4
4
 
5
5
  //#region src/kv.d.ts
@@ -11,12 +11,12 @@ interface RedisKvStoreOptions {
11
11
  * The prefix to use for all keys in the key–value store in Redis.
12
12
  * Defaults to `"fedify::"`.
13
13
  */
14
- keyPrefix?: RedisKey;
14
+ readonly keyPrefix?: RedisKey;
15
15
  /**
16
16
  * The codec to use for encoding and decoding values in the key–value store.
17
17
  * Defaults to {@link JsonCodec}.
18
18
  */
19
- codec?: Codec;
19
+ readonly codec?: Codec;
20
20
  }
21
21
  /**
22
22
  * A key–value store that uses Redis as the underlying storage.
@@ -56,6 +56,11 @@ declare class RedisKvStore implements KvStore {
56
56
  get<T = unknown>(key: KvKey): Promise<T | undefined>;
57
57
  set(key: KvKey, value: unknown, options?: KvStoreSetOptions | undefined): Promise<void>;
58
58
  delete(key: KvKey): Promise<void>;
59
+ /**
60
+ * {@inheritDoc KvStore.list}
61
+ * @since 1.10.0
62
+ */
63
+ list(prefix?: KvKey): AsyncIterable<KvStoreListEntry>;
59
64
  }
60
65
  //#endregion
61
66
  export { RedisKvStore, RedisKvStoreOptions };
package/dist/kv.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { Temporal } from "@js-temporal/polyfill";
2
2
  import { Codec } from "./codec.js";
3
- import { KvKey, KvStore, KvStoreSetOptions } from "@fedify/fedify";
3
+ import { KvKey, KvStore, KvStoreListEntry, KvStoreSetOptions } from "@fedify/fedify";
4
4
  import { Cluster, Redis, RedisKey } from "ioredis";
5
5
 
6
6
  //#region src/kv.d.ts
@@ -12,12 +12,12 @@ interface RedisKvStoreOptions {
12
12
  * The prefix to use for all keys in the key–value store in Redis.
13
13
  * Defaults to `"fedify::"`.
14
14
  */
15
- keyPrefix?: RedisKey;
15
+ readonly keyPrefix?: RedisKey;
16
16
  /**
17
17
  * The codec to use for encoding and decoding values in the key–value store.
18
18
  * Defaults to {@link JsonCodec}.
19
19
  */
20
- codec?: Codec;
20
+ readonly codec?: Codec;
21
21
  }
22
22
  /**
23
23
  * A key–value store that uses Redis as the underlying storage.
@@ -57,6 +57,11 @@ declare class RedisKvStore implements KvStore {
57
57
  get<T = unknown>(key: KvKey): Promise<T | undefined>;
58
58
  set(key: KvKey, value: unknown, options?: KvStoreSetOptions | undefined): Promise<void>;
59
59
  delete(key: KvKey): Promise<void>;
60
+ /**
61
+ * {@inheritDoc KvStore.list}
62
+ * @since 1.10.0
63
+ */
64
+ list(prefix?: KvKey): AsyncIterable<KvStoreListEntry>;
60
65
  }
61
66
  //#endregion
62
67
  export { RedisKvStore, RedisKvStoreOptions };
package/dist/kv.js CHANGED
@@ -35,6 +35,7 @@ import { Buffer } from "node:buffer";
35
35
  var RedisKvStore = class {
36
36
  #redis;
37
37
  #keyPrefix;
38
+ #keyPrefixStr;
38
39
  #codec;
39
40
  #textEncoder = new TextEncoder();
40
41
  /**
@@ -45,6 +46,7 @@ var RedisKvStore = class {
45
46
  constructor(redis, options = {}) {
46
47
  this.#redis = redis;
47
48
  this.#keyPrefix = options.keyPrefix ?? "fedify::";
49
+ this.#keyPrefixStr = typeof this.#keyPrefix === "string" ? this.#keyPrefix : new TextDecoder().decode(new Uint8Array(this.#keyPrefix));
48
50
  this.#codec = options.codec ?? new JsonCodec();
49
51
  }
50
52
  #serializeKey(key) {
@@ -69,6 +71,45 @@ var RedisKvStore = class {
69
71
  const serializedKey = this.#serializeKey(key);
70
72
  await this.#redis.del(serializedKey);
71
73
  }
74
+ #deserializeKey(redisKey) {
75
+ const suffix = redisKey.slice(this.#keyPrefixStr.length);
76
+ return suffix.split("::").map((p) => p.replaceAll("_:", ":"));
77
+ }
78
+ /**
79
+ * {@inheritDoc KvStore.list}
80
+ * @since 1.10.0
81
+ */
82
+ async *list(prefix) {
83
+ let pattern;
84
+ let exactKey = null;
85
+ if (prefix == null || prefix.length === 0) pattern = `${this.#keyPrefixStr}*`;
86
+ else {
87
+ const prefixKey = this.#serializeKey(prefix);
88
+ const prefixKeyFullStr = typeof prefixKey === "string" ? prefixKey : new TextDecoder().decode(new Uint8Array(prefixKey));
89
+ exactKey = prefixKey;
90
+ pattern = `${prefixKeyFullStr}::*`;
91
+ }
92
+ if (exactKey != null) {
93
+ const exactValue = await this.#redis.getBuffer(exactKey);
94
+ if (exactValue != null) yield {
95
+ key: prefix,
96
+ value: this.#codec.decode(exactValue)
97
+ };
98
+ }
99
+ let cursor = "0";
100
+ do {
101
+ const [nextCursor, keys] = await this.#redis.scan(cursor, "MATCH", pattern, "COUNT", 100);
102
+ cursor = nextCursor;
103
+ for (const key of keys) {
104
+ const encodedValue = await this.#redis.getBuffer(key);
105
+ if (encodedValue == null) continue;
106
+ yield {
107
+ key: this.#deserializeKey(key),
108
+ value: this.#codec.decode(encodedValue)
109
+ };
110
+ }
111
+ } while (cursor !== "0");
112
+ }
72
113
  };
73
114
 
74
115
  //#endregion
package/dist/mq.d.cts CHANGED
@@ -13,35 +13,35 @@ interface RedisMessageQueueOptions {
13
13
  * This is used to prevent multiple workers from processing the same message,
14
14
  * so it should be unique for each worker.
15
15
  */
16
- workerId?: string;
16
+ readonly workerId?: string;
17
17
  /**
18
18
  * The Pub/Sub channel key to use for the message queue. `"fedify_channel"`
19
19
  * by default.
20
20
  * @default `"fedify_channel"`
21
21
  */
22
- channelKey?: RedisKey;
22
+ readonly channelKey?: RedisKey;
23
23
  /**
24
24
  * The Sorted Set key to use for the delayed message queue. `"fedify_queue"`
25
25
  * by default.
26
26
  * @default `"fedify_queue"`
27
27
  */
28
- queueKey?: RedisKey;
28
+ readonly queueKey?: RedisKey;
29
29
  /**
30
30
  * The key to use for locking the message queue. `"fedify_lock"` by default.
31
31
  * @default `"fedify_lock"`
32
32
  */
33
- lockKey?: RedisKey;
33
+ readonly lockKey?: RedisKey;
34
34
  /**
35
35
  * The codec to use for encoding and decoding messages in the key–value store.
36
36
  * Defaults to {@link JsonCodec}.
37
37
  * @default {@link JsonCodec}
38
38
  */
39
- codec?: Codec;
39
+ readonly codec?: Codec;
40
40
  /**
41
41
  * The poll interval for the message queue. 5 seconds by default.
42
42
  * @default `{ seconds: 5 }`
43
43
  */
44
- pollInterval?: Temporal.Duration | Temporal.DurationLike;
44
+ readonly pollInterval?: Temporal.Duration | Temporal.DurationLike;
45
45
  }
46
46
  /**
47
47
  * A message queue that uses Redis as the underlying storage.
@@ -78,7 +78,7 @@ declare class RedisMessageQueue implements MessageQueue, Disposable {
78
78
  */
79
79
  constructor(redis: () => Redis | Cluster, options?: RedisMessageQueueOptions);
80
80
  enqueue(message: any, options?: MessageQueueEnqueueOptions): Promise<void>;
81
- enqueueMany(messages: any[], options?: MessageQueueEnqueueOptions): Promise<void>;
81
+ enqueueMany(messages: readonly any[], options?: MessageQueueEnqueueOptions): Promise<void>;
82
82
  listen(handler: (message: any) => void | Promise<void>, options?: MessageQueueListenOptions): Promise<void>;
83
83
  [Symbol.dispose](): void;
84
84
  }
package/dist/mq.d.ts CHANGED
@@ -14,35 +14,35 @@ interface RedisMessageQueueOptions {
14
14
  * This is used to prevent multiple workers from processing the same message,
15
15
  * so it should be unique for each worker.
16
16
  */
17
- workerId?: string;
17
+ readonly workerId?: string;
18
18
  /**
19
19
  * The Pub/Sub channel key to use for the message queue. `"fedify_channel"`
20
20
  * by default.
21
21
  * @default `"fedify_channel"`
22
22
  */
23
- channelKey?: RedisKey;
23
+ readonly channelKey?: RedisKey;
24
24
  /**
25
25
  * The Sorted Set key to use for the delayed message queue. `"fedify_queue"`
26
26
  * by default.
27
27
  * @default `"fedify_queue"`
28
28
  */
29
- queueKey?: RedisKey;
29
+ readonly queueKey?: RedisKey;
30
30
  /**
31
31
  * The key to use for locking the message queue. `"fedify_lock"` by default.
32
32
  * @default `"fedify_lock"`
33
33
  */
34
- lockKey?: RedisKey;
34
+ readonly lockKey?: RedisKey;
35
35
  /**
36
36
  * The codec to use for encoding and decoding messages in the key–value store.
37
37
  * Defaults to {@link JsonCodec}.
38
38
  * @default {@link JsonCodec}
39
39
  */
40
- codec?: Codec;
40
+ readonly codec?: Codec;
41
41
  /**
42
42
  * The poll interval for the message queue. 5 seconds by default.
43
43
  * @default `{ seconds: 5 }`
44
44
  */
45
- pollInterval?: Temporal.Duration | Temporal.DurationLike;
45
+ readonly pollInterval?: Temporal.Duration | Temporal.DurationLike;
46
46
  }
47
47
  /**
48
48
  * A message queue that uses Redis as the underlying storage.
@@ -79,7 +79,7 @@ declare class RedisMessageQueue implements MessageQueue, Disposable {
79
79
  */
80
80
  constructor(redis: () => Redis | Cluster, options?: RedisMessageQueueOptions);
81
81
  enqueue(message: any, options?: MessageQueueEnqueueOptions): Promise<void>;
82
- enqueueMany(messages: any[], options?: MessageQueueEnqueueOptions): Promise<void>;
82
+ enqueueMany(messages: readonly any[], options?: MessageQueueEnqueueOptions): Promise<void>;
83
83
  listen(handler: (message: any) => void | Promise<void>, options?: MessageQueueListenOptions): Promise<void>;
84
84
  [Symbol.dispose](): void;
85
85
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fedify/redis",
3
- "version": "2.0.0-dev.1875+d712d60c",
3
+ "version": "2.0.0-dev.196+c3cfc0a9",
4
4
  "description": "Redis drivers for Fedify",
5
5
  "keywords": [
6
6
  "fedify",
@@ -78,17 +78,18 @@
78
78
  ],
79
79
  "dependencies": {
80
80
  "@js-temporal/polyfill": "^0.5.1",
81
- "@logtape/logtape": "^1.1.1"
81
+ "@logtape/logtape": "^2.0.0"
82
82
  },
83
83
  "peerDependencies": {
84
- "ioredis": "^5.6.1",
85
- "@fedify/fedify": "^2.0.0-dev.1875+d712d60c"
84
+ "ioredis": "^5.8.2",
85
+ "@fedify/fedify": "^2.0.0-dev.196+c3cfc0a9"
86
86
  },
87
87
  "devDependencies": {
88
88
  "@std/async": "npm:@jsr/std__async@^1.0.13",
89
89
  "@types/node": "^22.17.0",
90
90
  "tsdown": "^0.12.9",
91
- "typescript": "^5.9.3"
91
+ "typescript": "^5.9.3",
92
+ "@fedify/fixture": "^2.0.0"
92
93
  },
93
94
  "scripts": {
94
95
  "build": "tsdown",