Skip to content

Commit 4104661

Browse files
committed
Merge tag '2.1.5'
Fedify 2.1.5
2 parents 61141c6 + ea03b77 commit 4104661

8 files changed

Lines changed: 365 additions & 52 deletions

File tree

CHANGES.md

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,43 @@ To be released.
5959
[#656]: https://github.com/fedify-dev/fedify/pull/656
6060

6161

62+
Version 2.1.5
63+
-------------
64+
65+
Released on April 8, 2026.
66+
67+
### @fedify/fedify
68+
69+
- Fixed `Context.getActorKeyPairs()` assigning the same key ID to both
70+
the `CryptographicKey` (used for HTTP Signatures and Linked Data
71+
Signatures) and the `Multikey` (used for Object Integrity Proofs) within
72+
an `ActorKeyPair`. The `Multikey` now receives a distinct ID
73+
(`#multikey-1`, `#multikey-2`, …) so that the actor document no longer
74+
contains two objects sharing the same `id`, which was invalid JSON-LD.
75+
Object Integrity Proof signatures now reference the correct `Multikey` ID
76+
instead of the `CryptographicKey` ID. [[#663]]
77+
78+
- Object Integrity Proofs signing now takes place before activity fanout,
79+
so all recipients receive the same pre-signed activity. Previously, OIP
80+
signing was deferred until after fanout, meaning each fanout worker would
81+
re-sign independently with potentially different timestamps and the fanout
82+
message itself contained an unsigned activity.
83+
84+
[#663]: https://github.com/fedify-dev/fedify/issues/663
85+
86+
### @fedify/cfworkers
87+
88+
- Fixed a remaining TypeScript type mismatch for Cloudflare Workers users who
89+
pass `wrangler types` or `@cloudflare/vite-plugin` generated KV bindings to
90+
`WorkersKvStore`. The package now accepts a minimal structural KV binding
91+
interface for `WorkersKvStore` and `WorkersMessageQueue`'s `orderingKv`
92+
option instead of requiring the nominal `KVNamespace` type imported from
93+
`@cloudflare/workers-types`, so generated local declarations compile
94+
without casts or `@ts-expect-error`. [[#665]]
95+
96+
[#665]: https://github.com/fedify-dev/fedify/issues/665
97+
98+
6299
Version 2.1.4
63100
-------------
64101

@@ -349,6 +386,39 @@ Released on March 24, 2026.
349386
[#599]: https://github.com/fedify-dev/fedify/pull/599
350387

351388

389+
Version 2.0.12
390+
--------------
391+
392+
Released on April 8, 2026.
393+
394+
### @fedify/fedify
395+
396+
- Fixed `Context.getActorKeyPairs()` assigning the same key ID to both
397+
the `CryptographicKey` (used for HTTP Signatures and Linked Data
398+
Signatures) and the `Multikey` (used for Object Integrity Proofs) within
399+
an `ActorKeyPair`. The `Multikey` now receives a distinct ID
400+
(`#multikey-1`, `#multikey-2`, …) so that the actor document no longer
401+
contains two objects sharing the same `id`, which was invalid JSON-LD.
402+
Object Integrity Proof signatures now reference the correct `Multikey` ID
403+
instead of the `CryptographicKey` ID. [[#663]]
404+
405+
- Object Integrity Proofs signing now takes place before activity fanout,
406+
so all recipients receive the same pre-signed activity. Previously, OIP
407+
signing was deferred until after fanout, meaning each fanout worker would
408+
re-sign independently with potentially different timestamps and the fanout
409+
message itself contained an unsigned activity.
410+
411+
### @fedify/cfworkers
412+
413+
- Fixed a remaining TypeScript type mismatch for Cloudflare Workers users who
414+
pass `wrangler types` or `@cloudflare/vite-plugin` generated KV bindings to
415+
`WorkersKvStore`. The package now accepts a minimal structural KV binding
416+
interface for `WorkersKvStore` and `WorkersMessageQueue`'s `orderingKv`
417+
option instead of requiring the nominal `KVNamespace` type imported from
418+
`@cloudflare/workers-types`, so generated local declarations compile
419+
without casts or `@ts-expect-error`. [[#665]]
420+
421+
352422
Version 2.0.11
353423
--------------
354424

@@ -1151,6 +1221,29 @@ Released on February 22, 2026.
11511221
[#351]: https://github.com/fedify-dev/fedify/issues/351
11521222

11531223

1224+
Version 1.10.8
1225+
--------------
1226+
1227+
Released on April 8, 2026.
1228+
1229+
### @fedify/fedify
1230+
1231+
- Fixed `Context.getActorKeyPairs()` assigning the same key ID to both
1232+
the `CryptographicKey` (used for HTTP Signatures and Linked Data
1233+
Signatures) and the `Multikey` (used for Object Integrity Proofs) within
1234+
an `ActorKeyPair`. The `Multikey` now receives a distinct ID
1235+
(`#multikey-1`, `#multikey-2`, …) so that the actor document no longer
1236+
contains two objects sharing the same `id`, which was invalid JSON-LD.
1237+
Object Integrity Proof signatures now reference the correct `Multikey` ID
1238+
instead of the `CryptographicKey` ID. [[#663]]
1239+
1240+
- Object Integrity Proofs signing now takes place before activity fanout,
1241+
so all recipients receive the same pre-signed activity. Previously, OIP
1242+
signing was deferred until after fanout, meaning each fanout worker would
1243+
re-sign independently with potentially different timestamps and the fanout
1244+
message itself contained an unsigned activity.
1245+
1246+
11541247
Version 1.10.7
11551248
--------------
11561249

@@ -1351,6 +1444,29 @@ Released on December 24, 2025.
13511444
- Implemented `list()` method in `WorkersKvStore`. [[#498], [#500]]
13521445

13531446

1447+
Version 1.9.9
1448+
-------------
1449+
1450+
Released on April 8, 2026.
1451+
1452+
### @fedify/fedify
1453+
1454+
- Fixed `Context.getActorKeyPairs()` assigning the same key ID to both
1455+
the `CryptographicKey` (used for HTTP Signatures and Linked Data
1456+
Signatures) and the `Multikey` (used for Object Integrity Proofs) within
1457+
an `ActorKeyPair`. The `Multikey` now receives a distinct ID
1458+
(`#multikey-1`, `#multikey-2`, …) so that the actor document no longer
1459+
contains two objects sharing the same `id`, which was invalid JSON-LD.
1460+
Object Integrity Proof signatures now reference the correct `Multikey` ID
1461+
instead of the `CryptographicKey` ID. [[#663]]
1462+
1463+
- Object Integrity Proofs signing now takes place before activity fanout,
1464+
so all recipients receive the same pre-signed activity. Previously, OIP
1465+
signing was deferred until after fanout, meaning each fanout worker would
1466+
re-sign independently with potentially different timestamps and the fanout
1467+
message itself contained an unsigned activity.
1468+
1469+
13541470
Version 1.9.8
13551471
-------------
13561472

packages/cfworkers/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@
6666
"build": "pnpm --filter @fedify/cfworkers... run build:self",
6767
"prepack": "pnpm build",
6868
"prepublish": "pnpm build",
69-
"test": "vitest run"
69+
"pretest": "pnpm build",
70+
"test": "tsc -p test/typecheck/tsconfig.json --noEmit && vitest run"
7071
}
7172
}

packages/cfworkers/src/mod.ts

Lines changed: 66 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,7 @@
88
* @module
99
* @since 1.9.0
1010
*/
11-
import type {
12-
KVNamespace,
13-
MessageSendRequest,
14-
Queue,
15-
} from "@cloudflare/workers-types";
11+
import type { MessageSendRequest, Queue } from "@cloudflare/workers-types";
1612
import type {
1713
KvKey,
1814
KvStore,
@@ -27,6 +23,67 @@ interface KvMetadata {
2723
expires?: number;
2824
}
2925

26+
interface WorkersKvNamespaceGetWithMetadataResult<Value, Metadata> {
27+
readonly value: Value | null;
28+
readonly metadata: Metadata | null;
29+
}
30+
31+
interface WorkersKvNamespaceListKey<Metadata, Key extends string = string> {
32+
readonly name: Key;
33+
readonly expiration?: number;
34+
readonly metadata?: Metadata;
35+
}
36+
37+
interface WorkersKvNamespaceListResult<Metadata, Key extends string = string> {
38+
readonly list_complete: boolean;
39+
readonly keys: readonly WorkersKvNamespaceListKey<Metadata, Key>[];
40+
readonly cursor?: string;
41+
}
42+
43+
interface WorkersKvNamespaceListOptions {
44+
readonly limit?: number;
45+
readonly prefix?: string | null;
46+
readonly cursor?: string | null;
47+
}
48+
49+
interface WorkersKvNamespacePutOptions {
50+
readonly expiration?: number;
51+
readonly expirationTtl?: number;
52+
readonly metadata?: unknown;
53+
}
54+
55+
/**
56+
* Minimal Cloudflare Workers KV binding shape used by this package.
57+
* Compatible with both `@cloudflare/workers-types` and `wrangler types`
58+
* generated declarations.
59+
* @since 2.0.12
60+
*/
61+
export interface WorkersKvNamespaceLike<Key extends string = string> {
62+
get(key: Key): Promise<string | null>;
63+
get<ExpectedValue = unknown>(
64+
key: Key,
65+
type: "json",
66+
): Promise<ExpectedValue | null>;
67+
getWithMetadata<Metadata = unknown>(
68+
key: Key,
69+
): Promise<WorkersKvNamespaceGetWithMetadataResult<string, Metadata>>;
70+
getWithMetadata<ExpectedValue = unknown, Metadata = unknown>(
71+
key: Key,
72+
type: "json",
73+
): Promise<
74+
WorkersKvNamespaceGetWithMetadataResult<ExpectedValue, Metadata>
75+
>;
76+
put(
77+
key: Key,
78+
value: string,
79+
options?: WorkersKvNamespacePutOptions,
80+
): Promise<void>;
81+
delete(key: Key): Promise<void>;
82+
list<Metadata = unknown>(
83+
options?: WorkersKvNamespaceListOptions,
84+
): Promise<WorkersKvNamespaceListResult<Metadata, Key>>;
85+
}
86+
3087
/**
3188
* Internal message wrapper that includes ordering key metadata.
3289
*/
@@ -74,9 +131,9 @@ export interface ProcessMessageResult {
74131
* @since 1.9.0
75132
*/
76133
export class WorkersKvStore implements KvStore {
77-
#namespace: KVNamespace<string>;
134+
#namespace: WorkersKvNamespaceLike<string>;
78135

79-
constructor(namespace: KVNamespace<string>) {
136+
constructor(namespace: WorkersKvNamespaceLike<string>) {
80137
this.#namespace = namespace;
81138
}
82139

@@ -202,7 +259,7 @@ export interface WorkersMessageQueueOptions {
202259
* guarantees are best-effort. For strict ordering requirements, consider
203260
* using Durable Objects.
204261
*/
205-
readonly orderingKv?: KVNamespace<string>;
262+
readonly orderingKv?: WorkersKvNamespaceLike<string>;
206263

207264
/**
208265
* The prefix for ordering key lock keys. Defaults to `"__fedify_ordering_"`.
@@ -233,7 +290,7 @@ export interface WorkersMessageQueueOptions {
233290
*/
234291
export class WorkersMessageQueue implements MessageQueue {
235292
#queue: Queue;
236-
#orderingKv?: KVNamespace<string>;
293+
#orderingKv?: WorkersKvNamespaceLike<string>;
237294
#orderingKeyPrefix: string;
238295
#orderingLockTtl: number;
239296

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"compilerOptions": {
3+
"target": "ESNext",
4+
"module": "ESNext",
5+
"moduleResolution": "bundler",
6+
"strict": true,
7+
"esModuleInterop": true,
8+
"skipLibCheck": true
9+
},
10+
"include": [
11+
"./**/*.ts"
12+
]
13+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import type { Queue } from "@cloudflare/workers-types";
2+
import { WorkersKvStore, WorkersMessageQueue } from "../../dist/mod.js";
3+
4+
interface GeneratedKvGetWithMetadataResult<Value, Metadata> {
5+
readonly value: Value | null;
6+
readonly metadata: Metadata | null;
7+
readonly cacheStatus: string | null;
8+
}
9+
10+
interface GeneratedKvListKey<Metadata, Key extends string = string> {
11+
readonly name: Key;
12+
readonly expiration?: number;
13+
readonly metadata?: Metadata;
14+
}
15+
16+
type GeneratedKvListResult<Metadata, Key extends string = string> =
17+
| {
18+
readonly list_complete: false;
19+
readonly keys: readonly GeneratedKvListKey<Metadata, Key>[];
20+
readonly cursor: string;
21+
readonly cacheStatus: string | null;
22+
}
23+
| {
24+
readonly list_complete: true;
25+
readonly keys: readonly GeneratedKvListKey<Metadata, Key>[];
26+
readonly cacheStatus: string | null;
27+
};
28+
29+
/**
30+
* Mirrors the minimal single-key Cloudflare KV declaration shape emitted by
31+
* `wrangler types`, but comes from a distinct local declaration source.
32+
*/
33+
interface GeneratedKvNamespace<Key extends string = string> {
34+
get(key: Key): Promise<string | null>;
35+
get<ExpectedValue = unknown>(
36+
key: Key,
37+
type: "json",
38+
): Promise<ExpectedValue | null>;
39+
getWithMetadata<Metadata = unknown>(
40+
key: Key,
41+
): Promise<GeneratedKvGetWithMetadataResult<string, Metadata>>;
42+
getWithMetadata<ExpectedValue = unknown, Metadata = unknown>(
43+
key: Key,
44+
type: "json",
45+
): Promise<GeneratedKvGetWithMetadataResult<ExpectedValue, Metadata>>;
46+
put(
47+
key: Key,
48+
value: string | ArrayBuffer | ArrayBufferView | ReadableStream,
49+
options?: {
50+
expiration?: number;
51+
expirationTtl?: number;
52+
metadata?: any | null;
53+
},
54+
): Promise<void>;
55+
delete(key: Key): Promise<void>;
56+
list<Metadata = unknown>(
57+
options?: {
58+
limit?: number;
59+
prefix?: string | null;
60+
cursor?: string | null;
61+
},
62+
): Promise<GeneratedKvListResult<Metadata, Key>>;
63+
}
64+
65+
declare const queue: Queue;
66+
declare const generatedKv: GeneratedKvNamespace<string>;
67+
68+
new WorkersKvStore(generatedKv);
69+
new WorkersMessageQueue(queue, { orderingKv: generatedKv });

packages/fedify/src/federation/context.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -876,7 +876,10 @@ export interface GetSignedKeyOptions {
876876
*/
877877
export interface ActorKeyPair extends CryptoKeyPair {
878878
/**
879-
* The URI of the public key, which is used for verifying HTTP Signatures.
879+
* The URI of the public key for {@link CryptographicKey}, which is used for
880+
* verifying HTTP Signatures and Linked Data Signatures. Note that this is
881+
* the ID of the {@link cryptographicKey}, not of the {@link multikey};
882+
* the {@link Multikey} instance has a distinct ID of its own.
880883
*/
881884
readonly keyId: URL;
882885

0 commit comments

Comments
 (0)