@syncframe/redis 0.2.0 → 0.3.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/README.md +2 -0
- package/dist/index.d.ts +11 -11
- package/dist/index.js +35 -35
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
Redis-backed [`SyncStore`](https://www.npmjs.com/package/@syncframe/core) and `SyncTransport` adapters for [`@syncframe/core`](https://www.npmjs.com/package/@syncframe/core), so a `SyncServer` can persist anchors and fan out snapshots across processes and serverless instances.
|
|
4
4
|
|
|
5
|
+
Docs and demos: [syncframe.jkvc.ai](https://syncframe.jkvc.ai/)
|
|
6
|
+
|
|
5
7
|
The adapters are **connection-injected** — you pass in your own [`ioredis`](https://www.npmjs.com/package/ioredis) clients, so connection, auth, and pooling stay in your app. The dependency on core is type-only, so this package adds no runtime coupling.
|
|
6
8
|
|
|
7
9
|
## Install
|
package/dist/index.d.ts
CHANGED
|
@@ -23,7 +23,7 @@ interface RedisStoreOptions {
|
|
|
23
23
|
}
|
|
24
24
|
/**
|
|
25
25
|
* Anchors, meta, and content data are stored as JSON under namespaced keys.
|
|
26
|
-
* The set of channel ids per
|
|
26
|
+
* The set of channel ids per namespace is tracked in a Redis set so `listAnchors`
|
|
27
27
|
* (and therefore snapshot building) works without key scanning.
|
|
28
28
|
*/
|
|
29
29
|
declare class RedisStore implements SyncStore {
|
|
@@ -35,14 +35,14 @@ declare class RedisStore implements SyncStore {
|
|
|
35
35
|
private channelsKey;
|
|
36
36
|
private metaKey;
|
|
37
37
|
private contentKey;
|
|
38
|
-
getAnchor(
|
|
39
|
-
setAnchor(
|
|
40
|
-
deleteAnchor(
|
|
41
|
-
listAnchors(
|
|
42
|
-
getMeta(
|
|
43
|
-
setMeta(
|
|
44
|
-
getContentData(
|
|
45
|
-
setContentData(
|
|
38
|
+
getAnchor(namespace: string, channelId: string): Promise<AnyAnchor | null>;
|
|
39
|
+
setAnchor(namespace: string, channelId: string, anchor: AnyAnchor): Promise<void>;
|
|
40
|
+
deleteAnchor(namespace: string, channelId: string): Promise<void>;
|
|
41
|
+
listAnchors(namespace: string): Promise<Record<string, AnyAnchor | null>>;
|
|
42
|
+
getMeta(namespace: string): Promise<Record<string, unknown>>;
|
|
43
|
+
setMeta(namespace: string, meta: Record<string, unknown>): Promise<void>;
|
|
44
|
+
getContentData(namespace: string): Promise<Record<string, unknown> | null>;
|
|
45
|
+
setContentData(namespace: string, data: Record<string, unknown>): Promise<void>;
|
|
46
46
|
}
|
|
47
47
|
interface RedisTransportOptions {
|
|
48
48
|
/** Client used to PUBLISH snapshots. */
|
|
@@ -61,8 +61,8 @@ declare class RedisTransport implements SyncTransport {
|
|
|
61
61
|
private readonly prefix;
|
|
62
62
|
constructor(options: RedisTransportOptions);
|
|
63
63
|
private channel;
|
|
64
|
-
publish(
|
|
65
|
-
subscribe(
|
|
64
|
+
publish(namespace: string, snapshot: CoreSnapshot): Promise<void>;
|
|
65
|
+
subscribe(namespace: string, handler: (snapshot: CoreSnapshot) => void): Promise<() => void>;
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
export { RedisStore, type RedisStoreOptions, RedisTransport, type RedisTransportOptions };
|
package/dist/index.js
CHANGED
|
@@ -11,57 +11,57 @@ var RedisStore = class {
|
|
|
11
11
|
this.redis = options.redis;
|
|
12
12
|
this.prefix = options.prefix ?? DEFAULT_PREFIX;
|
|
13
13
|
}
|
|
14
|
-
ns(
|
|
15
|
-
return `${this.prefix}:${
|
|
14
|
+
ns(namespace) {
|
|
15
|
+
return `${this.prefix}:${namespace}`;
|
|
16
16
|
}
|
|
17
|
-
anchorKey(
|
|
18
|
-
return `${this.ns(
|
|
17
|
+
anchorKey(namespace, channelId) {
|
|
18
|
+
return `${this.ns(namespace)}:anchor:${channelId}`;
|
|
19
19
|
}
|
|
20
|
-
channelsKey(
|
|
21
|
-
return `${this.ns(
|
|
20
|
+
channelsKey(namespace) {
|
|
21
|
+
return `${this.ns(namespace)}:channels`;
|
|
22
22
|
}
|
|
23
|
-
metaKey(
|
|
24
|
-
return `${this.ns(
|
|
23
|
+
metaKey(namespace) {
|
|
24
|
+
return `${this.ns(namespace)}:meta`;
|
|
25
25
|
}
|
|
26
|
-
contentKey(
|
|
27
|
-
return `${this.ns(
|
|
26
|
+
contentKey(namespace) {
|
|
27
|
+
return `${this.ns(namespace)}:content`;
|
|
28
28
|
}
|
|
29
|
-
async getAnchor(
|
|
30
|
-
return readJson(this.redis, this.anchorKey(
|
|
29
|
+
async getAnchor(namespace, channelId) {
|
|
30
|
+
return readJson(this.redis, this.anchorKey(namespace, channelId));
|
|
31
31
|
}
|
|
32
|
-
async setAnchor(
|
|
32
|
+
async setAnchor(namespace, channelId, anchor) {
|
|
33
33
|
await Promise.all([
|
|
34
|
-
this.redis.set(this.anchorKey(
|
|
35
|
-
this.redis.sadd(this.channelsKey(
|
|
34
|
+
this.redis.set(this.anchorKey(namespace, channelId), JSON.stringify(anchor)),
|
|
35
|
+
this.redis.sadd(this.channelsKey(namespace), channelId)
|
|
36
36
|
]);
|
|
37
37
|
}
|
|
38
|
-
async deleteAnchor(
|
|
38
|
+
async deleteAnchor(namespace, channelId) {
|
|
39
39
|
await Promise.all([
|
|
40
|
-
this.redis.del(this.anchorKey(
|
|
41
|
-
this.redis.srem(this.channelsKey(
|
|
40
|
+
this.redis.del(this.anchorKey(namespace, channelId)),
|
|
41
|
+
this.redis.srem(this.channelsKey(namespace), channelId)
|
|
42
42
|
]);
|
|
43
43
|
}
|
|
44
|
-
async listAnchors(
|
|
45
|
-
const channels = await this.redis.smembers(this.channelsKey(
|
|
44
|
+
async listAnchors(namespace) {
|
|
45
|
+
const channels = await this.redis.smembers(this.channelsKey(namespace));
|
|
46
46
|
const entries = await Promise.all(
|
|
47
47
|
channels.map(async (channelId) => [
|
|
48
48
|
channelId,
|
|
49
|
-
await this.getAnchor(
|
|
49
|
+
await this.getAnchor(namespace, channelId)
|
|
50
50
|
])
|
|
51
51
|
);
|
|
52
52
|
return Object.fromEntries(entries);
|
|
53
53
|
}
|
|
54
|
-
async getMeta(
|
|
55
|
-
return await readJson(this.redis, this.metaKey(
|
|
54
|
+
async getMeta(namespace) {
|
|
55
|
+
return await readJson(this.redis, this.metaKey(namespace)) ?? {};
|
|
56
56
|
}
|
|
57
|
-
async setMeta(
|
|
58
|
-
await this.redis.set(this.metaKey(
|
|
57
|
+
async setMeta(namespace, meta) {
|
|
58
|
+
await this.redis.set(this.metaKey(namespace), JSON.stringify(meta));
|
|
59
59
|
}
|
|
60
|
-
async getContentData(
|
|
61
|
-
return readJson(this.redis, this.contentKey(
|
|
60
|
+
async getContentData(namespace) {
|
|
61
|
+
return readJson(this.redis, this.contentKey(namespace));
|
|
62
62
|
}
|
|
63
|
-
async setContentData(
|
|
64
|
-
await this.redis.set(this.contentKey(
|
|
63
|
+
async setContentData(namespace, data) {
|
|
64
|
+
await this.redis.set(this.contentKey(namespace), JSON.stringify(data));
|
|
65
65
|
}
|
|
66
66
|
};
|
|
67
67
|
var RedisTransport = class {
|
|
@@ -73,15 +73,15 @@ var RedisTransport = class {
|
|
|
73
73
|
this.createSubscriber = options.createSubscriber;
|
|
74
74
|
this.prefix = options.prefix ?? DEFAULT_PREFIX;
|
|
75
75
|
}
|
|
76
|
-
channel(
|
|
77
|
-
return `${this.prefix}:${
|
|
76
|
+
channel(namespace) {
|
|
77
|
+
return `${this.prefix}:${namespace}:updates`;
|
|
78
78
|
}
|
|
79
|
-
async publish(
|
|
80
|
-
await this.redis.publish(this.channel(
|
|
79
|
+
async publish(namespace, snapshot) {
|
|
80
|
+
await this.redis.publish(this.channel(namespace), JSON.stringify(snapshot));
|
|
81
81
|
}
|
|
82
|
-
async subscribe(
|
|
82
|
+
async subscribe(namespace, handler) {
|
|
83
83
|
const subscriber = this.createSubscriber();
|
|
84
|
-
const channel = this.channel(
|
|
84
|
+
const channel = this.channel(namespace);
|
|
85
85
|
subscriber.on("message", (incoming, message) => {
|
|
86
86
|
if (incoming === channel) handler(JSON.parse(message));
|
|
87
87
|
});
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"names":[],"mappings":";AAyBA,IAAM,cAAA,GAAiB,WAAA;AAEvB,eAAe,QAAA,CAAY,OAAc,GAAA,EAAgC;AACvE,EAAA,MAAM,GAAA,GAAM,MAAM,KAAA,CAAM,GAAA,CAAI,GAAG,CAAA;AAC/B,EAAA,OAAO,GAAA,GAAO,IAAA,CAAK,KAAA,CAAM,GAAG,CAAA,GAAU,IAAA;AACxC;AAcO,IAAM,aAAN,MAAsC;AAAA,EAC1B,KAAA;AAAA,EACA,MAAA;AAAA,EAEjB,YAAY,OAAA,EAA4B;AACtC,IAAA,IAAA,CAAK,QAAQ,OAAA,CAAQ,KAAA;AACrB,IAAA,IAAA,CAAK,MAAA,GAAS,QAAQ,MAAA,IAAU,cAAA;AAAA,EAClC;AAAA,EAEQ,GAAG,
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * @syncframe/redis — Redis-backed adapters for @syncframe/core.\n *\n * Implements core's `SyncStore` and `SyncTransport` interfaces on top of Redis,\n * so a `SyncServer` can persist anchors and fan out snapshots across processes\n * and serverless instances.\n *\n * Core stays zero-dependency: these adapters only *implement* its interfaces.\n * Every `@syncframe/core` and `ioredis` import here is type-only and erased at\n * compile time — the package has no runtime dependency on core, and the Redis\n * client is injected by the caller (so connection, auth, and pooling concerns\n * live in the application, not here).\n */\n\nimport type Redis from 'ioredis';\n// Type-only imports from core's server entry. That entry is React-free, so it\n// never pulls hooks (which reference DOM globals) into this non-DOM package's\n// type-check.\nimport type {\n SyncStore,\n SyncTransport,\n AnyAnchor,\n CoreSnapshot,\n} from '@syncframe/core/server';\n\nconst DEFAULT_PREFIX = 'syncframe';\n\nasync function readJson<T>(redis: Redis, key: string): Promise<T | null> {\n const raw = await redis.get(key);\n return raw ? (JSON.parse(raw) as T) : null;\n}\n\nexport interface RedisStoreOptions {\n /** Client used for all commands. */\n redis: Redis;\n /** Key namespace prefix. Default `\"syncframe\"`. */\n prefix?: string;\n}\n\n/**\n * Anchors, meta, and content data are stored as JSON under namespaced keys.\n * The set of channel ids per namespace is tracked in a Redis set so `listAnchors`\n * (and therefore snapshot building) works without key scanning.\n */\nexport class RedisStore implements SyncStore {\n private readonly redis: Redis;\n private readonly prefix: string;\n\n constructor(options: RedisStoreOptions) {\n this.redis = options.redis;\n this.prefix = options.prefix ?? DEFAULT_PREFIX;\n }\n\n private ns(namespace: string): string {\n return `${this.prefix}:${namespace}`;\n }\n private anchorKey(namespace: string, channelId: string): string {\n return `${this.ns(namespace)}:anchor:${channelId}`;\n }\n private channelsKey(namespace: string): string {\n return `${this.ns(namespace)}:channels`;\n }\n private metaKey(namespace: string): string {\n return `${this.ns(namespace)}:meta`;\n }\n private contentKey(namespace: string): string {\n return `${this.ns(namespace)}:content`;\n }\n\n async getAnchor(namespace: string, channelId: string): Promise<AnyAnchor | null> {\n return readJson<AnyAnchor>(this.redis, this.anchorKey(namespace, channelId));\n }\n\n async setAnchor(namespace: string, channelId: string, anchor: AnyAnchor): Promise<void> {\n await Promise.all([\n this.redis.set(this.anchorKey(namespace, channelId), JSON.stringify(anchor)),\n this.redis.sadd(this.channelsKey(namespace), channelId),\n ]);\n }\n\n async deleteAnchor(namespace: string, channelId: string): Promise<void> {\n await Promise.all([\n this.redis.del(this.anchorKey(namespace, channelId)),\n this.redis.srem(this.channelsKey(namespace), channelId),\n ]);\n }\n\n async listAnchors(namespace: string): Promise<Record<string, AnyAnchor | null>> {\n const channels = await this.redis.smembers(this.channelsKey(namespace));\n const entries = await Promise.all(\n channels.map(async (channelId): Promise<[string, AnyAnchor | null]> => [\n channelId,\n await this.getAnchor(namespace, channelId),\n ]),\n );\n return Object.fromEntries(entries);\n }\n\n async getMeta(namespace: string): Promise<Record<string, unknown>> {\n return (await readJson<Record<string, unknown>>(this.redis, this.metaKey(namespace))) ?? {};\n }\n\n async setMeta(namespace: string, meta: Record<string, unknown>): Promise<void> {\n await this.redis.set(this.metaKey(namespace), JSON.stringify(meta));\n }\n\n async getContentData(namespace: string): Promise<Record<string, unknown> | null> {\n return readJson<Record<string, unknown>>(this.redis, this.contentKey(namespace));\n }\n\n async setContentData(namespace: string, data: Record<string, unknown>): Promise<void> {\n await this.redis.set(this.contentKey(namespace), JSON.stringify(data));\n }\n}\n\nexport interface RedisTransportOptions {\n /** Client used to PUBLISH snapshots. */\n redis: Redis;\n /**\n * Factory for a fresh subscriber connection. A Redis connection in subscribe\n * mode can't issue other commands, so each `subscribe()` gets its own.\n */\n createSubscriber: () => Redis;\n /** Channel namespace prefix. Default `\"syncframe\"`. */\n prefix?: string;\n}\n\nexport class RedisTransport implements SyncTransport {\n private readonly redis: Redis;\n private readonly createSubscriber: () => Redis;\n private readonly prefix: string;\n\n constructor(options: RedisTransportOptions) {\n this.redis = options.redis;\n this.createSubscriber = options.createSubscriber;\n this.prefix = options.prefix ?? DEFAULT_PREFIX;\n }\n\n private channel(namespace: string): string {\n return `${this.prefix}:${namespace}:updates`;\n }\n\n async publish(namespace: string, snapshot: CoreSnapshot): Promise<void> {\n await this.redis.publish(this.channel(namespace), JSON.stringify(snapshot));\n }\n\n async subscribe(\n namespace: string,\n handler: (snapshot: CoreSnapshot) => void,\n ): Promise<() => void> {\n const subscriber = this.createSubscriber();\n const channel = this.channel(namespace);\n\n subscriber.on('message', (incoming: string, message: string) => {\n if (incoming === channel) handler(JSON.parse(message) as CoreSnapshot);\n });\n await subscriber.subscribe(channel);\n\n return () => {\n void subscriber.quit();\n };\n }\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@syncframe/redis",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Redis-backed SyncStore + SyncTransport adapters for @syncframe/core",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"url": "git+https://github.com/jkvc/syncframe.git",
|
|
19
19
|
"directory": "packages/redis"
|
|
20
20
|
},
|
|
21
|
-
"homepage": "https://
|
|
21
|
+
"homepage": "https://syncframe.jkvc.ai/",
|
|
22
22
|
"bugs": "https://github.com/jkvc/syncframe/issues",
|
|
23
23
|
"main": "./dist/index.js",
|
|
24
24
|
"types": "./dist/index.d.ts",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"dist"
|
|
33
33
|
],
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@syncframe/core": "^0.
|
|
35
|
+
"@syncframe/core": "^0.3.0"
|
|
36
36
|
},
|
|
37
37
|
"peerDependencies": {
|
|
38
38
|
"ioredis": "^5"
|