Skip to content

Commit ae33fee

Browse files
committed
WorkersKvStore class
1 parent 77c62d3 commit ae33fee

10 files changed

Lines changed: 78 additions & 9 deletions

File tree

CHANGES.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,18 @@ To be released. Note that 1.6.0 was skipped due to a mistake in the versioning.
3939
- Added `HttpMessageSignaturesSpecDeterminer` interface.
4040
- Added `--first-knock` option to `fedify lookup` command.
4141

42+
- Added `WorkersKvStore` class. [[#233], [#241], [#242]]
43+
4244
- The minimum supported version of Node.js is now 22.0.0.
4345

4446
[RFC 9421]: https://www.rfc-editor.org/rfc/rfc9421
4547
[#208]: https://github.com/fedify-dev/fedify/issues/208
4648
[#227]: https://github.com/fedify-dev/fedify/issues/227
49+
[#233]: https://github.com/fedify-dev/fedify/issues/233
4750
[#235]: https://github.com/fedify-dev/fedify/pull/235
4851
[#237]: https://github.com/fedify-dev/fedify/pull/237
52+
[#241]: https://github.com/fedify-dev/fedify/issues/241
53+
[#242]: https://github.com/fedify-dev/fedify/pull/242
4954

5055

5156
Version 1.5.3

fedify/deno.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,15 @@
1111
"./sig": "./sig/mod.ts",
1212
"./vocab": "./vocab/mod.ts",
1313
"./webfinger": "./webfinger/mod.ts",
14+
"./x/cfworkers": "./x/cfworkers.ts",
1415
"./x/denokv": "./x/denokv.ts",
1516
"./x/fresh": "./x/fresh.ts",
1617
"./x/hono": "./x/hono.ts",
1718
"./x/sveltekit": "./x/sveltekit.ts"
1819
},
1920
"imports": {
2021
"@cfworker/json-schema": "npm:@cfworker/json-schema@^4.1.1",
22+
"@cloudflare/workers-types": "npm:@cloudflare/workers-types@^4.20250529.0",
2123
"@es-toolkit/es-toolkit": "jsr:@es-toolkit/es-toolkit@^1.38.0",
2224
"@hongminhee/deno-mock-fetch": "jsr:@hongminhee/deno-mock-fetch@^0.3.2",
2325
"@hugoalh/http-header-link": "jsr:@hugoalh/http-header-link@^1.0.2",

fedify/federation/handler.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1233,7 +1233,7 @@ test("handleInbox()", async () => {
12331233

12341234
onNotFoundCalled = null;
12351235
const signedRequest = await signRequest(
1236-
unsignedRequest.clone(),
1236+
unsignedRequest.clone() as Request,
12371237
rsaPrivateKey3,
12381238
rsaPublicKey3.id!,
12391239
);

fedify/federation/middleware.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1303,7 +1303,7 @@ test("FederationImpl.sendActivity()", async (t) => {
13031303
let request: Request | null = null;
13041304
fetchMock.post("https://example.com/inbox", async (cl) => {
13051305
verified = [];
1306-
request = cl.request!.clone();
1306+
request = cl.request!.clone() as Request;
13071307
const options = {
13081308
documentLoader: mockDocumentLoader,
13091309
contextLoader: mockDocumentLoader,
@@ -1485,7 +1485,7 @@ test("ContextImpl.sendActivity()", async (t) => {
14851485
let collectionSyncHeader: string | null = null;
14861486
fetchMock.post("https://example.com/inbox", async (cl) => {
14871487
verified = [];
1488-
request = cl.request!.clone();
1488+
request = cl.request!.clone() as Request;
14891489
collectionSyncHeader = cl.request!.headers.get(
14901490
"Collection-Synchronization",
14911491
);
@@ -2072,7 +2072,7 @@ test("InboxContextImpl.forwardActivity()", async (t) => {
20722072
let request: Request | null = null;
20732073
fetchMock.post("https://example.com/inbox", async (cl) => {
20742074
verified = [];
2075-
request = cl.request!.clone();
2075+
request = cl.request!.clone() as Request;
20762076
const options = {
20772077
documentLoader: mockDocumentLoader,
20782078
contextLoader: mockDocumentLoader,

fedify/federation/send.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ test("sendActivity()", async (t) => {
169169
"https://example.com/inbox",
170170
async (cl) => {
171171
httpSigVerified = false;
172-
request = cl.request!.clone();
172+
request = cl.request!.clone() as Request;
173173
const options = {
174174
documentLoader: mockDocumentLoader,
175175
contextLoader: mockDocumentLoader,

fedify/package.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,10 @@
6868
"types": "./dist/webfinger/mod.d.ts",
6969
"import": "./dist/webfinger/mod.js"
7070
},
71+
"./x/cfworkers": {
72+
"types": "./dist/x/cfworkers.d.ts",
73+
"import": "./dist/x/cfworkers.js"
74+
},
7175
"./x/hono": {
7276
"types": "./dist/x/hono.d.ts",
7377
"import": "./dist/x/hono.js"
@@ -99,6 +103,7 @@
99103
"urlpattern-polyfill": "^10.1.0"
100104
},
101105
"devDependencies": {
106+
"@cloudflare/workers-types": "^4.20250529.0",
102107
"@hongminhee/deno-mock-fetch": "jsr:^0.3.2",
103108
"@std/assert": "jsr:^0.226.0",
104109
"@std/path": "jsr:^1.0.9",

fedify/pnpm-lock.yaml

Lines changed: 11 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

fedify/sig/http.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -610,7 +610,7 @@ async function verifyRequestDraft(
610610
return null;
611611
}
612612
const originalRequest = request;
613-
request = request.clone();
613+
request = request.clone() as Request;
614614
const dateHeader = request.headers.get("Date");
615615
if (dateHeader == null) {
616616
logger.debug(
@@ -909,7 +909,7 @@ async function verifyRequestRfc9421(
909909
}
910910

911911
const originalRequest = request;
912-
request = request.clone();
912+
request = request.clone() as Request;
913913

914914
// Check for required headers
915915
const signatureInputHeader = request.headers.get("Signature-Input");

fedify/tsdown.config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ export default defineConfig({
1313
"./testing/mod.ts",
1414
"./vocab/mod.ts",
1515
"./webfinger/mod.ts",
16+
"./x/cfworkers.ts",
1617
"./x/hono.ts",
1718
"./x/sveltekit.ts",
1819
...(await Array.fromAsync(glob(`**/*.test.ts`)))

fedify/x/cfworkers.ts

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import type { KVNamespace } from "@cloudflare/workers-types/experimental";
2+
import type { KvKey, KvStore, KvStoreSetOptions } from "../federation/kv.ts";
3+
4+
/**
5+
* Implementation of the KvStore interface for Cloudflare Workers KV binding.
6+
* This class provides a wrapper around Cloudflare's KV namespace to store and
7+
* retrieve JSON-serializable values using structured keys.
8+
* @since 1.6.0
9+
*/
10+
export class WorkersKvStore implements KvStore {
11+
#namespace: KVNamespace<string>;
12+
13+
constructor(namespace: KVNamespace<string>) {
14+
this.#namespace = namespace;
15+
}
16+
17+
#encodeKey(key: KvKey): string {
18+
return JSON.stringify(key);
19+
}
20+
21+
async get<T = unknown>(key: KvKey): Promise<T | undefined> {
22+
const encodedKey = this.#encodeKey(key);
23+
const value = await this.#namespace.get(encodedKey);
24+
return value == null ? undefined : JSON.parse(value) as T;
25+
}
26+
27+
async set(
28+
key: KvKey,
29+
value: unknown,
30+
options?: KvStoreSetOptions,
31+
): Promise<void> {
32+
const encodedKey = this.#encodeKey(key);
33+
await this.#namespace.put(
34+
encodedKey,
35+
JSON.stringify(value),
36+
options?.ttl == null ? {} : {
37+
// According to Cloudflare Workers KV documentation,
38+
// the minimum TTL is 60 seconds:
39+
expirationTtl: Math.max(options.ttl.total("seconds"), 60),
40+
},
41+
);
42+
}
43+
44+
delete(key: KvKey): Promise<void> {
45+
return this.#namespace.delete(this.#encodeKey(key));
46+
}
47+
}

0 commit comments

Comments
 (0)