@fedify/redis 0.4.0 → 1.8.0-pr.278.944

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 Hong Minhee
3
+ Copyright 2024–2025 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
@@ -40,60 +40,10 @@ const federation = createFederation({
40
40
  Installation
41
41
  ------------
42
42
 
43
- ### Deno
44
-
45
43
  ~~~~ sh
46
- deno add @fedify/redis
44
+ deno add jsr:@fedify/redis # Deno
45
+ npm add @fedify/redis # npm
46
+ pnpm add @fedify/redis # pnpm
47
+ yarn add @fedify/redis # Yarn
48
+ bun add @fedify/redis # Bun
47
49
  ~~~~
48
-
49
- ### Node.js
50
-
51
- ~~~~ sh
52
- npm install @fedify/redis
53
- ~~~~
54
-
55
- ### Bun
56
-
57
- ~~~~ sh
58
- bun add @fedify/redis
59
- ~~~~
60
-
61
-
62
- Changelog
63
- ---------
64
-
65
- ### Version 0.4.0
66
-
67
- Released on March 28, 2025.
68
-
69
- - Added `RedisMessageQueue.enqueueMany()` method for efficiently enqueueing
70
- multiple messages in a single transaction.
71
-
72
- - Updated *@js-temporal/polyfill* to 0.5.0 for Node.js and Bun. On Deno,
73
- there is no change because the polyfill is not used.
74
-
75
- ### Version 0.3.0
76
-
77
- Released on October 4, 2024.
78
-
79
- - Polling is now more efficient.
80
- - Renamed `RedisMessageQueueOptions.loopInterval` option to `pollInterval`
81
- option.
82
-
83
- ### Version 0.2.0
84
-
85
- Released on September 26, 2024.
86
-
87
- - Let `RedisMessageQueue` follow up the latest `MessageQueue` interface,
88
- which was updated in Fedify 1.0.0.
89
- - Added some example code.
90
-
91
- ### Version 0.1.1
92
-
93
- Released on June 22, 2024.
94
-
95
- - Exported `@fedify/redis/mq` module.
96
-
97
- ### Version 0.1.0
98
-
99
- Initial release. Released on June 22, 2024.
@@ -0,0 +1,51 @@
1
+ import { Temporal } from "@js-temporal/polyfill";
2
+ import { Buffer } from "node:buffer";
3
+
4
+ //#region codec.d.ts
5
+ /**
6
+ * Encode and decodes JavaScript objects to and from binary data.
7
+ */
8
+ interface Codec {
9
+ /**
10
+ * Encodes a JavaScript object to binary data.
11
+ * @param value The JavaScript object to encode.
12
+ * @returns The encoded binary data.
13
+ * @throws {EncodingError} If the JavaScript object cannot be encoded.
14
+ */
15
+ encode(value: unknown): Buffer;
16
+ /**
17
+ * Decodes a JavaScript object from binary data.
18
+ * @param encoded The binary data to decode.
19
+ * @returns The decoded JavaScript object.
20
+ * @throws {DecodingError} If the binary data is invalid.
21
+ */
22
+ decode(encoded: Buffer): unknown;
23
+ }
24
+ /**
25
+ * An error that occurs when encoding or decoding data.
26
+ */
27
+ declare class CodecError extends Error {
28
+ constructor(message: string);
29
+ }
30
+ /**
31
+ * An error that occurs when encoding data.
32
+ */
33
+ declare class EncodingError extends CodecError {
34
+ constructor(message: string);
35
+ }
36
+ /**
37
+ * An error that occurs when decoding data.
38
+ */
39
+ declare class DecodingError extends CodecError {
40
+ constructor(message: string);
41
+ }
42
+ /**
43
+ * A codec that encodes and decodes JavaScript objects to and from JSON.
44
+ */
45
+ declare class JsonCodec implements Codec {
46
+ #private;
47
+ encode(value: unknown): Buffer;
48
+ decode(encoded: Buffer): unknown;
49
+ }
50
+ //#endregion
51
+ export { Codec, CodecError, DecodingError, EncodingError, JsonCodec };
package/dist/codec.js ADDED
@@ -0,0 +1,62 @@
1
+
2
+ import { Temporal } from "@js-temporal/polyfill";
3
+
4
+ import { Buffer } from "node:buffer";
5
+
6
+ //#region codec.ts
7
+ /**
8
+ * An error that occurs when encoding or decoding data.
9
+ */
10
+ var CodecError = class extends Error {
11
+ constructor(message) {
12
+ super(message);
13
+ this.name = "CodecError";
14
+ }
15
+ };
16
+ /**
17
+ * An error that occurs when encoding data.
18
+ */
19
+ var EncodingError = class extends CodecError {
20
+ constructor(message) {
21
+ super(message);
22
+ this.name = "EncodingError";
23
+ }
24
+ };
25
+ /**
26
+ * An error that occurs when decoding data.
27
+ */
28
+ var DecodingError = class extends CodecError {
29
+ constructor(message) {
30
+ super(message);
31
+ this.name = "DecodingError";
32
+ }
33
+ };
34
+ /**
35
+ * A codec that encodes and decodes JavaScript objects to and from JSON.
36
+ */
37
+ var JsonCodec = class {
38
+ #textEncoder = new TextEncoder();
39
+ #textDecoder = new TextDecoder();
40
+ encode(value) {
41
+ let json;
42
+ try {
43
+ json = JSON.stringify(value);
44
+ } catch (e) {
45
+ if (e instanceof TypeError) throw new EncodingError(e.message);
46
+ throw e;
47
+ }
48
+ return Buffer.from(this.#textEncoder.encode(json));
49
+ }
50
+ decode(encoded) {
51
+ const json = this.#textDecoder.decode(encoded);
52
+ try {
53
+ return JSON.parse(json);
54
+ } catch (e) {
55
+ if (e instanceof SyntaxError) throw new DecodingError(e.message);
56
+ throw e;
57
+ }
58
+ }
59
+ };
60
+
61
+ //#endregion
62
+ export { CodecError, DecodingError, EncodingError, JsonCodec };
package/dist/kv.d.ts ADDED
@@ -0,0 +1,50 @@
1
+ import { Temporal } from "@js-temporal/polyfill";
2
+ import { Codec } from "./codec.js";
3
+ import { KvKey, KvStore, KvStoreSetOptions } from "@fedify/fedify";
4
+ import { Redis, RedisKey } from "ioredis";
5
+
6
+ //#region kv.d.ts
7
+ /**
8
+ * Options for {@link RedisKvStore} class.
9
+ */
10
+ interface RedisKvStoreOptions {
11
+ /**
12
+ * The prefix to use for all keys in the key-value store in Redis.
13
+ * Defaults to `"fedify::"`.
14
+ */
15
+ keyPrefix?: RedisKey;
16
+ /**
17
+ * The codec to use for encoding and decoding values in the key-value store.
18
+ * Defaults to {@link JsonCodec}.
19
+ */
20
+ codec?: Codec;
21
+ }
22
+ /**
23
+ * A key-value store that uses Redis as the underlying storage.
24
+ *
25
+ * @example
26
+ * ```ts ignore
27
+ * import { createFederation } from "@fedify/fedify";
28
+ * import { RedisKvStore } from "@fedify/redis";
29
+ * import { Redis } from "ioredis";
30
+ *
31
+ * const federation = createFederation({
32
+ * // ...
33
+ * kv: new RedisKvStore(new Redis()),
34
+ * });
35
+ * ```
36
+ */
37
+ declare class RedisKvStore implements KvStore {
38
+ #private;
39
+ /**
40
+ * Creates a new Redis key-value store.
41
+ * @param redis The Redis client to use.
42
+ * @param options The options for the key-value store.
43
+ */
44
+ constructor(redis: Redis, options?: RedisKvStoreOptions);
45
+ get<T = unknown>(key: KvKey): Promise<T | undefined>;
46
+ set(key: KvKey, value: unknown, options?: KvStoreSetOptions | undefined): Promise<void>;
47
+ delete(key: KvKey): Promise<void>;
48
+ }
49
+ //#endregion
50
+ export { RedisKvStore, RedisKvStoreOptions };
package/dist/kv.js ADDED
@@ -0,0 +1,63 @@
1
+
2
+ import { Temporal } from "@js-temporal/polyfill";
3
+
4
+ import { JsonCodec } from "./codec.js";
5
+ import { Buffer } from "node:buffer";
6
+
7
+ //#region kv.ts
8
+ /**
9
+ * A key-value store that uses Redis as the underlying storage.
10
+ *
11
+ * @example
12
+ * ```ts ignore
13
+ * import { createFederation } from "@fedify/fedify";
14
+ * import { RedisKvStore } from "@fedify/redis";
15
+ * import { Redis } from "ioredis";
16
+ *
17
+ * const federation = createFederation({
18
+ * // ...
19
+ * kv: new RedisKvStore(new Redis()),
20
+ * });
21
+ * ```
22
+ */
23
+ var RedisKvStore = class {
24
+ #redis;
25
+ #keyPrefix;
26
+ #codec;
27
+ #textEncoder = new TextEncoder();
28
+ /**
29
+ * Creates a new Redis key-value store.
30
+ * @param redis The Redis client to use.
31
+ * @param options The options for the key-value store.
32
+ */
33
+ constructor(redis, options = {}) {
34
+ this.#redis = redis;
35
+ this.#keyPrefix = options.keyPrefix ?? "fedify::";
36
+ this.#codec = options.codec ?? new JsonCodec();
37
+ }
38
+ #serializeKey(key) {
39
+ const suffix = key.map((part) => part.replaceAll(":", "_:")).join("::");
40
+ if (typeof this.#keyPrefix === "string") return `${this.#keyPrefix}${suffix}`;
41
+ const suffixBytes = this.#textEncoder.encode(suffix);
42
+ return Buffer.concat([new Uint8Array(this.#keyPrefix), suffixBytes]);
43
+ }
44
+ async get(key) {
45
+ const serializedKey = this.#serializeKey(key);
46
+ const encodedValue = await this.#redis.getBuffer(serializedKey);
47
+ if (encodedValue == null) return void 0;
48
+ return this.#codec.decode(encodedValue);
49
+ }
50
+ async set(key, value, options) {
51
+ const serializedKey = this.#serializeKey(key);
52
+ const encodedValue = this.#codec.encode(value);
53
+ if (options?.ttl != null) await this.#redis.setex(serializedKey, options.ttl.total("second"), encodedValue);
54
+ else await this.#redis.set(serializedKey, encodedValue);
55
+ }
56
+ async delete(key) {
57
+ const serializedKey = this.#serializeKey(key);
58
+ await this.#redis.del(serializedKey);
59
+ }
60
+ };
61
+
62
+ //#endregion
63
+ export { RedisKvStore };
package/dist/mod.d.ts ADDED
@@ -0,0 +1,5 @@
1
+ import { Temporal } from "@js-temporal/polyfill";
2
+ import { Codec, CodecError, DecodingError, EncodingError, JsonCodec } from "./codec.js";
3
+ import { RedisKvStore, RedisKvStoreOptions } from "./kv.js";
4
+ import { RedisMessageQueue, RedisMessageQueueOptions } from "./mq.js";
5
+ export { Codec, CodecError, DecodingError, EncodingError, JsonCodec, RedisKvStore, RedisKvStoreOptions, RedisMessageQueue, RedisMessageQueueOptions };
package/dist/mod.js ADDED
@@ -0,0 +1,8 @@
1
+
2
+ import { Temporal } from "@js-temporal/polyfill";
3
+
4
+ import { CodecError, DecodingError, EncodingError, JsonCodec } from "./codec.js";
5
+ import { RedisKvStore } from "./kv.js";
6
+ import { RedisMessageQueue } from "./mq.js";
7
+
8
+ export { CodecError, DecodingError, EncodingError, JsonCodec, RedisKvStore, RedisMessageQueue };
package/dist/mq.d.ts ADDED
@@ -0,0 +1,76 @@
1
+ import { Temporal } from "@js-temporal/polyfill";
2
+ import { Codec } from "./codec.js";
3
+ import { MessageQueue, MessageQueueEnqueueOptions, MessageQueueListenOptions } from "@fedify/fedify";
4
+ import { Redis, RedisKey } from "ioredis";
5
+
6
+ //#region mq.d.ts
7
+ /**
8
+ * Options for {@link RedisMessageQueue} class.
9
+ */
10
+ interface RedisMessageQueueOptions {
11
+ /**
12
+ * The unique identifier for the worker that is processing messages from the
13
+ * queue. If this is not specified, a random identifier will be generated.
14
+ * This is used to prevent multiple workers from processing the same message,
15
+ * so it should be unique for each worker.
16
+ */
17
+ workerId?: string;
18
+ /**
19
+ * The Pub/Sub channel key to use for the message queue. `"fedify_channel"`
20
+ * by default.
21
+ * @default `"fedify_channel"`
22
+ */
23
+ channelKey?: RedisKey;
24
+ /**
25
+ * The Sorted Set key to use for the delayed message queue. `"fedify_queue"`
26
+ * by default.
27
+ * @default `"fedify_queue"`
28
+ */
29
+ queueKey?: RedisKey;
30
+ /**
31
+ * The key to use for locking the message queue. `"fedify_lock"` by default.
32
+ * @default `"fedify_lock"`
33
+ */
34
+ lockKey?: RedisKey;
35
+ /**
36
+ * The codec to use for encoding and decoding messages in the key-value store.
37
+ * Defaults to {@link JsonCodec}.
38
+ * @default {@link JsonCodec}
39
+ */
40
+ codec?: Codec;
41
+ /**
42
+ * The poll interval for the message queue. 5 seconds by default.
43
+ * @default `{ seconds: 5 }`
44
+ */
45
+ pollInterval?: Temporal.Duration | Temporal.DurationLike;
46
+ }
47
+ /**
48
+ * A message queue that uses Redis as the underlying storage.
49
+ *
50
+ * @example
51
+ * ```ts ignore
52
+ * import { createFederation } from "@fedify/fedify";
53
+ * import { RedisMessageQueue } from "@fedify/redis";
54
+ * import { Redis } from "ioredis";
55
+ *
56
+ * const federation = createFederation({
57
+ * // ...
58
+ * queue: new RedisMessageQueue(() => new Redis()),
59
+ * });
60
+ * ```
61
+ */
62
+ declare class RedisMessageQueue implements MessageQueue, Disposable {
63
+ #private;
64
+ /**
65
+ * Creates a new Redis message queue.
66
+ * @param redis The Redis client factory.
67
+ * @param options The options for the message queue.
68
+ */
69
+ constructor(redis: () => Redis, options?: RedisMessageQueueOptions);
70
+ enqueue(message: any, options?: MessageQueueEnqueueOptions): Promise<void>;
71
+ enqueueMany(messages: any[], options?: MessageQueueEnqueueOptions): Promise<void>;
72
+ listen(handler: (message: any) => void | Promise<void>, options?: MessageQueueListenOptions): Promise<void>;
73
+ [Symbol.dispose](): void;
74
+ }
75
+ //#endregion
76
+ export { RedisMessageQueue, RedisMessageQueueOptions };
package/dist/mq.js ADDED
@@ -0,0 +1,144 @@
1
+
2
+ import { Temporal } from "@js-temporal/polyfill";
3
+
4
+ import { JsonCodec } from "./codec.js";
5
+ import { getLogger } from "@logtape/logtape";
6
+
7
+ //#region mq.ts
8
+ const logger = getLogger([
9
+ "fedify",
10
+ "redis",
11
+ "mq"
12
+ ]);
13
+ /**
14
+ * A message queue that uses Redis as the underlying storage.
15
+ *
16
+ * @example
17
+ * ```ts ignore
18
+ * import { createFederation } from "@fedify/fedify";
19
+ * import { RedisMessageQueue } from "@fedify/redis";
20
+ * import { Redis } from "ioredis";
21
+ *
22
+ * const federation = createFederation({
23
+ * // ...
24
+ * queue: new RedisMessageQueue(() => new Redis()),
25
+ * });
26
+ * ```
27
+ */
28
+ var RedisMessageQueue = class {
29
+ #redis;
30
+ #subRedis;
31
+ #workerId;
32
+ #channelKey;
33
+ #queueKey;
34
+ #lockKey;
35
+ #codec;
36
+ #pollIntervalMs;
37
+ #loopHandle;
38
+ /**
39
+ * Creates a new Redis message queue.
40
+ * @param redis The Redis client factory.
41
+ * @param options The options for the message queue.
42
+ */
43
+ constructor(redis, options = {}) {
44
+ this.#redis = redis();
45
+ this.#subRedis = redis();
46
+ this.#workerId = options.workerId ?? crypto.randomUUID();
47
+ this.#channelKey = options.channelKey ?? "fedify_channel";
48
+ this.#queueKey = options.queueKey ?? "fedify_queue";
49
+ this.#lockKey = options.lockKey ?? "fedify_lock";
50
+ this.#codec = options.codec ?? new JsonCodec();
51
+ this.#pollIntervalMs = Temporal.Duration.from(options.pollInterval ?? { seconds: 5 }).total("millisecond");
52
+ }
53
+ async enqueue(message, options) {
54
+ const ts = options?.delay == null ? 0 : Temporal.Now.instant().add(options.delay).epochMilliseconds;
55
+ const encodedMessage = this.#codec.encode([crypto.randomUUID(), message]);
56
+ await this.#redis.zadd(this.#queueKey, ts, encodedMessage);
57
+ if (ts < 1) this.#redis.publish(this.#channelKey, "");
58
+ }
59
+ async enqueueMany(messages, options) {
60
+ if (messages.length === 0) return;
61
+ const ts = options?.delay == null ? 0 : Temporal.Now.instant().add(options.delay).epochMilliseconds;
62
+ const multi = this.#redis.multi();
63
+ for (const message of messages) {
64
+ const encodedMessage = this.#codec.encode([crypto.randomUUID(), message]);
65
+ multi.zadd(this.#queueKey, ts, encodedMessage);
66
+ }
67
+ await multi.exec();
68
+ if (ts < 1) this.#redis.publish(this.#channelKey, "");
69
+ }
70
+ async #poll() {
71
+ logger.debug("Polling for messages...");
72
+ const result = await this.#redis.set(this.#lockKey, this.#workerId, "EX", Math.floor(this.#pollIntervalMs / 1e3 * 2), "NX");
73
+ if (result == null) {
74
+ logger.debug("Another worker is already processing messages; skipping...");
75
+ return;
76
+ }
77
+ logger.debug("Acquired lock; processing messages...");
78
+ const messages = await this.#redis.zrangebyscoreBuffer(this.#queueKey, 0, Temporal.Now.instant().epochMilliseconds);
79
+ logger.debug("Found {messages} messages to process.", { messages: messages.length });
80
+ try {
81
+ if (messages.length < 1) return;
82
+ const encodedMessage = messages[0];
83
+ await this.#redis.zrem(this.#queueKey, encodedMessage);
84
+ const [_, message] = this.#codec.decode(encodedMessage);
85
+ return message;
86
+ } finally {
87
+ await this.#redis.del(this.#lockKey);
88
+ }
89
+ }
90
+ async listen(handler, options = {}) {
91
+ if (this.#loopHandle != null) throw new Error("Already listening");
92
+ const signal = options.signal;
93
+ const poll = async () => {
94
+ while (!signal?.aborted) {
95
+ let message;
96
+ try {
97
+ message = await this.#poll();
98
+ } catch (error) {
99
+ logger.error("Error polling for messages: {error}", { error });
100
+ return;
101
+ }
102
+ if (message === void 0) return;
103
+ await handler(message);
104
+ }
105
+ };
106
+ const promise = this.#subRedis.subscribe(this.#channelKey, () => {
107
+ this.#subRedis.on("message", poll);
108
+ signal?.addEventListener("abort", () => {
109
+ this.#subRedis.off("message", poll);
110
+ });
111
+ });
112
+ signal?.addEventListener("abort", () => {
113
+ for (const timeout of timeouts) clearTimeout(timeout);
114
+ });
115
+ const timeouts = /* @__PURE__ */ new Set();
116
+ while (!signal?.aborted) {
117
+ let timeout;
118
+ await new Promise((resolve) => {
119
+ signal?.addEventListener("abort", resolve);
120
+ timeout = setTimeout(() => {
121
+ signal?.removeEventListener("abort", resolve);
122
+ resolve(0);
123
+ }, this.#pollIntervalMs);
124
+ timeouts.add(timeout);
125
+ });
126
+ if (timeout != null) timeouts.delete(timeout);
127
+ await poll();
128
+ }
129
+ return await new Promise((resolve) => {
130
+ signal?.addEventListener("abort", () => {
131
+ promise.catch(() => resolve()).then(() => resolve());
132
+ });
133
+ promise.catch(() => resolve()).then(() => resolve());
134
+ });
135
+ }
136
+ [Symbol.dispose]() {
137
+ clearInterval(this.#loopHandle);
138
+ this.#redis.disconnect();
139
+ this.#subRedis.disconnect();
140
+ }
141
+ };
142
+
143
+ //#endregion
144
+ export { RedisMessageQueue };
package/package.json CHANGED
@@ -1,73 +1,75 @@
1
1
  {
2
2
  "name": "@fedify/redis",
3
- "version": "0.4.0",
3
+ "version": "1.8.0-pr.278.944+76bf32a2",
4
4
  "description": "Redis drivers for Fedify",
5
5
  "keywords": [
6
6
  "fedify",
7
7
  "redis"
8
8
  ],
9
+ "license": "MIT",
9
10
  "author": {
10
11
  "name": "Hong Minhee",
11
12
  "email": "hong@minhee.org",
12
13
  "url": "https://hongminhee.org/"
13
14
  },
14
- "homepage": "https://github.com/fedify-dev/redis",
15
+ "homepage": "https://fedify.dev/",
15
16
  "repository": {
16
17
  "type": "git",
17
- "url": "git+https://github.com/fedify-dev/redis.git"
18
+ "url": "git+https://github.com/fedify-dev/fedify.git",
19
+ "directory": "redis"
18
20
  },
19
- "license": "MIT",
20
21
  "bugs": {
21
- "url": "https://github.com/fedify-dev/redis/issues"
22
+ "url": "https://github.com/fedify-dev/fedify/issues"
22
23
  },
23
- "main": "./script/mod.js",
24
- "module": "./esm/mod.js",
25
- "types": "./types/mod.d.ts",
24
+ "funding": [
25
+ "https://opencollective.com/fedify",
26
+ "https://github.com/sponsors/dahlia"
27
+ ],
28
+ "type": "module",
29
+ "main": "./dist/mod.js",
30
+ "module": "./dist/mod.js",
31
+ "types": "./dist/mod.d.ts",
26
32
  "exports": {
27
33
  ".": {
28
- "import": {
29
- "types": "./types/mod.d.ts",
30
- "default": "./esm/mod.js"
31
- },
32
- "require": {
33
- "types": "./types/mod.d.ts",
34
- "default": "./script/mod.js"
35
- }
34
+ "types": "./dist/mod.d.ts",
35
+ "import": "./dist/mod.js"
36
+ },
37
+ "./codec": {
38
+ "types": "./dist/codec.d.ts",
39
+ "import": "./dist/codec.js"
36
40
  },
37
41
  "./kv": {
38
- "import": {
39
- "types": "./types/src/kv.d.ts",
40
- "default": "./esm/src/kv.js"
41
- },
42
- "require": {
43
- "types": "./types/src/kv.d.ts",
44
- "default": "./script/src/kv.js"
45
- }
42
+ "types": "./dist/kv.d.ts",
43
+ "import": "./dist/kv.js"
46
44
  },
47
45
  "./mq": {
48
- "import": {
49
- "types": "./types/src/mq.d.ts",
50
- "default": "./esm/src/mq.js"
51
- },
52
- "require": {
53
- "types": "./types/src/mq.d.ts",
54
- "default": "./script/src/mq.js"
55
- }
56
- }
46
+ "types": "./dist/mq.d.ts",
47
+ "import": "./dist/mq.js"
48
+ },
49
+ "./package.json": "./package.json"
57
50
  },
58
- "funding": [
59
- "https://opencollective.com/fedify",
60
- "https://github.com/sponsors/dahlia"
51
+ "files": [
52
+ "dist",
53
+ "package.json"
61
54
  ],
62
55
  "dependencies": {
63
- "@fedify/fedify": "1.5.0",
64
- "@logtape/logtape": "^0.9.0",
65
- "ioredis": "^5.4.1",
66
- "@deno/shim-deno": "~0.18.0",
67
- "@js-temporal/polyfill": "^0.5.0"
56
+ "@js-temporal/polyfill": "^0.5.1",
57
+ "@logtape/logtape": "^1.0.0"
58
+ },
59
+ "peerDependencies": {
60
+ "ioredis": "^5.6.1",
61
+ "@fedify/fedify": "1.8.0-pr.278.944+76bf32a2"
68
62
  },
69
63
  "devDependencies": {
70
- "@types/node": "^20.9.0"
64
+ "@std/async": "npm:@jsr/std__async@^1.0.13",
65
+ "@types/node": "^22.16.0",
66
+ "tsdown": "^0.12.9",
67
+ "typescript": "^5.8.3"
71
68
  },
72
- "_generatedBy": "dnt@dev"
69
+ "scripts": {
70
+ "build": "tsdown",
71
+ "prepublish": "tsdown",
72
+ "test": "tsdown && node --experimental-transform-types --test",
73
+ "test:bun": "tsdown && bun test --timeout=10000"
74
+ }
73
75
  }