@fedify/botkit-redis 0.5.0-dev.0
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 +661 -0
- package/README.md +106 -0
- package/dist/mod.d.ts +129 -0
- package/dist/mod.d.ts.map +1 -0
- package/dist/mod.js +534 -0
- package/dist/mod.js.map +1 -0
- package/package.json +63 -0
package/README.md
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
@fedify/botkit-redis
|
|
2
|
+
====================
|
|
3
|
+
|
|
4
|
+
[![JSR][JSR badge]][JSR]
|
|
5
|
+
[![npm][npm badge]][npm]
|
|
6
|
+
[![GitHub Actions][GitHub Actions badge]][GitHub Actions]
|
|
7
|
+
|
|
8
|
+
This package is a [Redis]-based repository implementation for [BotKit]. It
|
|
9
|
+
provides shared persistent storage for bots running on either [Deno] or
|
|
10
|
+
[Node.js], using Redis data structures for BotKit repository data.
|
|
11
|
+
|
|
12
|
+
[JSR badge]: https://jsr.io/badges/@fedify/botkit-redis
|
|
13
|
+
[JSR]: https://jsr.io/@fedify/botkit-redis
|
|
14
|
+
[npm badge]: https://img.shields.io/npm/v/@fedify/botkit-redis?logo=npm
|
|
15
|
+
[npm]: https://www.npmjs.com/package/@fedify/botkit-redis
|
|
16
|
+
[GitHub Actions badge]: https://github.com/fedify-dev/botkit/actions/workflows/main.yaml/badge.svg
|
|
17
|
+
[GitHub Actions]: https://github.com/fedify-dev/botkit/actions/workflows/main.yaml
|
|
18
|
+
[Redis]: https://redis.io/
|
|
19
|
+
[BotKit]: https://botkit.fedify.dev/
|
|
20
|
+
[Deno]: https://deno.land/
|
|
21
|
+
[Node.js]: https://nodejs.org/
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
Installation
|
|
25
|
+
------------
|
|
26
|
+
|
|
27
|
+
~~~~ sh
|
|
28
|
+
deno add jsr:@fedify/botkit-redis
|
|
29
|
+
npm add @fedify/botkit-redis
|
|
30
|
+
pnpm add @fedify/botkit-redis
|
|
31
|
+
yarn add @fedify/botkit-redis
|
|
32
|
+
~~~~
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
Usage
|
|
36
|
+
-----
|
|
37
|
+
|
|
38
|
+
The `RedisRepository` can be used as a drop-in repository implementation for
|
|
39
|
+
BotKit:
|
|
40
|
+
|
|
41
|
+
~~~~ typescript
|
|
42
|
+
import { createBot, MemoryKvStore } from "@fedify/botkit";
|
|
43
|
+
import { RedisRepository } from "@fedify/botkit-redis";
|
|
44
|
+
|
|
45
|
+
const bot = createBot({
|
|
46
|
+
username: "mybot",
|
|
47
|
+
kv: new MemoryKvStore(),
|
|
48
|
+
repository: new RedisRepository({
|
|
49
|
+
url: "redis://localhost:6379/0",
|
|
50
|
+
prefix: "botkit",
|
|
51
|
+
}),
|
|
52
|
+
});
|
|
53
|
+
~~~~
|
|
54
|
+
|
|
55
|
+
You can also inject an existing node-redis client. In that case the
|
|
56
|
+
repository does not own the client and `close()` will not shut it down:
|
|
57
|
+
|
|
58
|
+
~~~~ typescript
|
|
59
|
+
import { RedisRepository } from "@fedify/botkit-redis";
|
|
60
|
+
import { createClient } from "redis";
|
|
61
|
+
|
|
62
|
+
const client = createClient({ url: "redis://localhost:6379/0" });
|
|
63
|
+
await client.connect();
|
|
64
|
+
|
|
65
|
+
const repository = new RedisRepository({
|
|
66
|
+
client,
|
|
67
|
+
prefix: "botkit",
|
|
68
|
+
});
|
|
69
|
+
~~~~
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
Options
|
|
73
|
+
-------
|
|
74
|
+
|
|
75
|
+
The `RedisRepository` constructor accepts the following options:
|
|
76
|
+
|
|
77
|
+
- **`url`**: A Redis connection string for an internally managed client.
|
|
78
|
+
|
|
79
|
+
- **`client`**: An existing node-redis compatible client to use.
|
|
80
|
+
|
|
81
|
+
- **`prefix`** (optional): Redis key prefix used for BotKit data. Defaults
|
|
82
|
+
to `"botkit"`.
|
|
83
|
+
|
|
84
|
+
- **`clientOptions`** (optional): Additional node-redis client options.
|
|
85
|
+
This option is only valid together with `url`.
|
|
86
|
+
|
|
87
|
+
The options are mutually exclusive: use either `client` or `url`.
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
Features
|
|
91
|
+
--------
|
|
92
|
+
|
|
93
|
+
- **Cross-runtime**: Works with both Deno and Node.js using node-redis.
|
|
94
|
+
|
|
95
|
+
- **Shared persistent storage**: Suitable for multi-process deployments
|
|
96
|
+
backed by Redis.
|
|
97
|
+
|
|
98
|
+
- **Key namespacing**: Keeps BotKit data under a configurable Redis prefix.
|
|
99
|
+
|
|
100
|
+
- **Full `Repository` API**: Implements BotKit repository storage for key
|
|
101
|
+
pairs, messages, followers, follows, followees, quote authorizations, and
|
|
102
|
+
poll votes.
|
|
103
|
+
|
|
104
|
+
- **Explicit resource ownership**: Repositories created from a URL own their
|
|
105
|
+
Redis client, while repositories created from an injected client leave
|
|
106
|
+
lifecycle control to the caller.
|
package/dist/mod.d.ts
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { ActorScopedRepository, Repository, RepositoryGetFollowersOptions, RepositoryGetMessagesOptions, Uuid } from "@fedify/botkit/repository";
|
|
2
|
+
import { Actor, Announce, Create, Follow, QuoteAuthorization } from "@fedify/vocab";
|
|
3
|
+
import { RedisClientOptions } from "redis";
|
|
4
|
+
|
|
5
|
+
//#region src/mod.d.ts
|
|
6
|
+
interface RedisClientLike {
|
|
7
|
+
readonly isOpen?: boolean;
|
|
8
|
+
connect?(): Promise<unknown>;
|
|
9
|
+
quit?(): Promise<unknown>;
|
|
10
|
+
close?(): Promise<unknown> | unknown;
|
|
11
|
+
sendCommand(args: readonly string[]): Promise<unknown>;
|
|
12
|
+
}
|
|
13
|
+
interface RedisRepositoryOptionsBase {
|
|
14
|
+
/**
|
|
15
|
+
* The Redis key prefix under which all BotKit data is stored.
|
|
16
|
+
* @default `"botkit"`
|
|
17
|
+
*/
|
|
18
|
+
readonly prefix?: string;
|
|
19
|
+
}
|
|
20
|
+
interface RedisRepositoryOptionsWithClient extends RedisRepositoryOptionsBase {
|
|
21
|
+
/**
|
|
22
|
+
* A pre-configured Redis client to use. It must already be connected.
|
|
23
|
+
*/
|
|
24
|
+
readonly client: RedisClientLike;
|
|
25
|
+
/**
|
|
26
|
+
* Disallowed when `client` is provided.
|
|
27
|
+
*/
|
|
28
|
+
readonly url?: never;
|
|
29
|
+
/**
|
|
30
|
+
* Disallowed when `client` is provided.
|
|
31
|
+
*/
|
|
32
|
+
readonly clientOptions?: never;
|
|
33
|
+
}
|
|
34
|
+
interface RedisRepositoryOptionsWithUrl extends RedisRepositoryOptionsBase {
|
|
35
|
+
/**
|
|
36
|
+
* A Redis connection string to connect with.
|
|
37
|
+
*/
|
|
38
|
+
readonly url: string | URL;
|
|
39
|
+
/**
|
|
40
|
+
* Disallowed when `url` is provided.
|
|
41
|
+
*/
|
|
42
|
+
readonly client?: never;
|
|
43
|
+
/**
|
|
44
|
+
* Additional node-redis client options.
|
|
45
|
+
*/
|
|
46
|
+
readonly clientOptions?: Omit<RedisClientOptions, "url">;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Options for creating a Redis repository.
|
|
50
|
+
* @since 0.5.0
|
|
51
|
+
*/
|
|
52
|
+
type RedisRepositoryOptions = RedisRepositoryOptionsWithClient | RedisRepositoryOptionsWithUrl;
|
|
53
|
+
/**
|
|
54
|
+
* A repository for storing bot data using Redis.
|
|
55
|
+
* @since 0.5.0
|
|
56
|
+
*/
|
|
57
|
+
declare class RedisRepository implements Repository, AsyncDisposable {
|
|
58
|
+
private readonly client;
|
|
59
|
+
private readonly ownsClient;
|
|
60
|
+
private readonly ready;
|
|
61
|
+
/**
|
|
62
|
+
* The Redis key prefix under which all BotKit data is stored.
|
|
63
|
+
*/
|
|
64
|
+
readonly prefix: string;
|
|
65
|
+
/**
|
|
66
|
+
* Creates a new Redis repository.
|
|
67
|
+
* @param options The options for creating the repository.
|
|
68
|
+
*/
|
|
69
|
+
constructor(options: RedisRepositoryOptions);
|
|
70
|
+
[Symbol.asyncDispose](): Promise<void>;
|
|
71
|
+
/**
|
|
72
|
+
* Closes the owned Redis connection.
|
|
73
|
+
*/
|
|
74
|
+
close(): Promise<void>;
|
|
75
|
+
private key;
|
|
76
|
+
private botKey;
|
|
77
|
+
private command;
|
|
78
|
+
private get;
|
|
79
|
+
private set;
|
|
80
|
+
private del;
|
|
81
|
+
private sAdd;
|
|
82
|
+
private sRem;
|
|
83
|
+
private sCard;
|
|
84
|
+
private zAdd;
|
|
85
|
+
private zRem;
|
|
86
|
+
private zRange;
|
|
87
|
+
private zRangeByScore;
|
|
88
|
+
private zCard;
|
|
89
|
+
private nextSequence;
|
|
90
|
+
private withRedisLock;
|
|
91
|
+
setKeyPairs(identifier: string, keyPairs: CryptoKeyPair[]): Promise<void>;
|
|
92
|
+
getKeyPairs(identifier: string): Promise<CryptoKeyPair[] | undefined>;
|
|
93
|
+
addMessage(identifier: string, id: Uuid, activity: Create | Announce): Promise<void>;
|
|
94
|
+
updateMessage(identifier: string, id: Uuid, updater: (existing: Create | Announce) => Create | Announce | undefined | Promise<Create | Announce | undefined>): Promise<boolean>;
|
|
95
|
+
removeMessage(identifier: string, id: Uuid): Promise<Create | Announce | undefined>;
|
|
96
|
+
getMessages(identifier: string, options?: RepositoryGetMessagesOptions): AsyncIterable<Create | Announce>;
|
|
97
|
+
getMessage(identifier: string, id: Uuid): Promise<Create | Announce | undefined>;
|
|
98
|
+
countMessages(identifier: string): Promise<number>;
|
|
99
|
+
addFollower(identifier: string, followId: URL, follower: Actor): Promise<void>;
|
|
100
|
+
removeFollower(identifier: string, followId: URL, followerId: URL): Promise<Actor | undefined>;
|
|
101
|
+
private cleanupFollower;
|
|
102
|
+
hasFollower(identifier: string, followerId: URL): Promise<boolean>;
|
|
103
|
+
getFollowers(identifier: string, options?: RepositoryGetFollowersOptions): AsyncIterable<Actor>;
|
|
104
|
+
countFollowers(identifier: string): Promise<number>;
|
|
105
|
+
addSentFollow(identifier: string, id: Uuid, follow: Follow): Promise<void>;
|
|
106
|
+
removeSentFollow(identifier: string, id: Uuid): Promise<Follow | undefined>;
|
|
107
|
+
getSentFollow(identifier: string, id: Uuid): Promise<Follow | undefined>;
|
|
108
|
+
addFollowee(identifier: string, followeeId: URL, follow: Follow): Promise<void>;
|
|
109
|
+
removeFollowee(identifier: string, followeeId: URL): Promise<Follow | undefined>;
|
|
110
|
+
getFollowee(identifier: string, followeeId: URL): Promise<Follow | undefined>;
|
|
111
|
+
findFollowedBots(followeeId: URL): AsyncIterable<string>;
|
|
112
|
+
addQuoteAuthorization(identifier: string, id: Uuid, authorization: QuoteAuthorization): Promise<void>;
|
|
113
|
+
getQuoteAuthorization(identifier: string, id: Uuid): Promise<QuoteAuthorization | undefined>;
|
|
114
|
+
findQuoteAuthorization(identifier: string, interactingObject: URL): Promise<QuoteAuthorization | undefined>;
|
|
115
|
+
removeQuoteAuthorization(identifier: string, id: Uuid): Promise<QuoteAuthorization | undefined>;
|
|
116
|
+
addQuoteAuthorizationReference(identifier: string, authorization: URL, messageId: Uuid, attribution?: URL): Promise<void>;
|
|
117
|
+
findQuoteAuthorizationReference(identifier: string, authorization: URL): Promise<Uuid | undefined>;
|
|
118
|
+
findQuoteAuthorizationReferenceIdentifiers(authorization: URL): AsyncIterable<string>;
|
|
119
|
+
findQuoteAuthorizationReferenceAttribution(identifier: string, authorization: URL): Promise<URL | undefined>;
|
|
120
|
+
removeQuoteAuthorizationReference(identifier: string, authorization: URL): Promise<void>;
|
|
121
|
+
vote(identifier: string, messageId: Uuid, voterId: URL, option: string): Promise<void>;
|
|
122
|
+
countVoters(identifier: string, messageId: Uuid): Promise<number>;
|
|
123
|
+
countVotes(identifier: string, messageId: Uuid): Promise<Readonly<Record<string, number>>>;
|
|
124
|
+
forIdentifier(identifier: string): ActorScopedRepository;
|
|
125
|
+
private quoteAuthorizationLockKey;
|
|
126
|
+
}
|
|
127
|
+
//#endregion
|
|
128
|
+
export { RedisRepository, RedisRepositoryOptions };
|
|
129
|
+
//# sourceMappingURL=mod.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mod.d.ts","names":[],"sources":["../src/mod.ts"],"sourcesContent":[],"mappings":"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"}
|