@atproto/space 0.0.0-spaces-alpha-20260818022935
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/CHANGELOG.md +11 -0
- package/LICENSE.txt +7 -0
- package/dist/commit.d.ts +25 -0
- package/dist/commit.d.ts.map +1 -0
- package/dist/commit.js +80 -0
- package/dist/commit.js.map +1 -0
- package/dist/credential.d.ts +77 -0
- package/dist/credential.d.ts.map +1 -0
- package/dist/credential.js +160 -0
- package/dist/credential.js.map +1 -0
- package/dist/dpop.d.ts +40 -0
- package/dist/dpop.d.ts.map +1 -0
- package/dist/dpop.js +96 -0
- package/dist/dpop.js.map +1 -0
- package/dist/error.d.ts +12 -0
- package/dist/error.d.ts.map +1 -0
- package/dist/error.js +21 -0
- package/dist/error.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/lthash.d.ts +18 -0
- package/dist/lthash.d.ts.map +1 -0
- package/dist/lthash.js +68 -0
- package/dist/lthash.js.map +1 -0
- package/dist/repo-commit.d.ts +51 -0
- package/dist/repo-commit.d.ts.map +1 -0
- package/dist/repo-commit.js +137 -0
- package/dist/repo-commit.js.map +1 -0
- package/dist/space-members.d.ts +27 -0
- package/dist/space-members.d.ts.map +1 -0
- package/dist/space-members.js +111 -0
- package/dist/space-members.js.map +1 -0
- package/dist/space-repo.d.ts +33 -0
- package/dist/space-repo.d.ts.map +1 -0
- package/dist/space-repo.js +136 -0
- package/dist/space-repo.js.map +1 -0
- package/dist/storage/index.d.ts +3 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +19 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/storage/memory-members-storage.d.ts +12 -0
- package/dist/storage/memory-members-storage.d.ts.map +1 -0
- package/dist/storage/memory-members-storage.js +36 -0
- package/dist/storage/memory-members-storage.js.map +1 -0
- package/dist/storage/memory-repo-storage.d.ts +17 -0
- package/dist/storage/memory-repo-storage.d.ts.map +1 -0
- package/dist/storage/memory-repo-storage.js +56 -0
- package/dist/storage/memory-repo-storage.js.map +1 -0
- package/dist/storage/types.d.ts +14 -0
- package/dist/storage/types.d.ts.map +1 -0
- package/dist/storage/types.js +3 -0
- package/dist/storage/types.js.map +1 -0
- package/dist/sync/car.d.ts +13 -0
- package/dist/sync/car.d.ts.map +1 -0
- package/dist/sync/car.js +185 -0
- package/dist/sync/car.js.map +1 -0
- package/dist/sync/consumer.d.ts +39 -0
- package/dist/sync/consumer.d.ts.map +1 -0
- package/dist/sync/consumer.js +89 -0
- package/dist/sync/consumer.js.map +1 -0
- package/dist/sync/index.d.ts +3 -0
- package/dist/sync/index.d.ts.map +1 -0
- package/dist/sync/index.js +3 -0
- package/dist/sync/index.js.map +1 -0
- package/dist/sync/provider.d.ts +25 -0
- package/dist/sync/provider.d.ts.map +1 -0
- package/dist/sync/provider.js +60 -0
- package/dist/sync/provider.js.map +1 -0
- package/dist/sync/repo-index.d.ts +19 -0
- package/dist/sync/repo-index.d.ts.map +1 -0
- package/dist/sync/repo-index.js +58 -0
- package/dist/sync/repo-index.js.map +1 -0
- package/dist/types.d.ts +49 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +35 -0
- package/dist/types.js.map +1 -0
- package/dist/util.d.ts +6 -0
- package/dist/util.d.ts.map +1 -0
- package/dist/util.js +14 -0
- package/dist/util.js.map +1 -0
- package/package.json +44 -0
- package/src/credential.ts +262 -0
- package/src/dpop.ts +166 -0
- package/src/error.ts +38 -0
- package/src/index.ts +8 -0
- package/src/lthash.ts +80 -0
- package/src/repo-commit.ts +171 -0
- package/src/sync/consumer.ts +149 -0
- package/src/sync/index.ts +2 -0
- package/src/sync/provider.ts +82 -0
- package/src/types.ts +62 -0
- package/src/util.ts +21 -0
- package/tests/credential.test.ts +323 -0
- package/tests/dpop.test.ts +234 -0
- package/tests/lthash.test.ts +97 -0
- package/tests/repo-commit.test.ts +281 -0
- package/tests/sync.test.ts +385 -0
- package/tsconfig.build.json +16 -0
- package/tsconfig.build.tsbuildinfo +1 -0
- package/tsconfig.json +7 -0
- package/tsconfig.test.json +11 -0
- package/tsconfig.test.tsbuildinfo +1 -0
- package/tsconfig.tests.tsbuildinfo +1 -0
- package/vitest.config.ts +5 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAA;AAC/B,cAAc,WAAW,CAAA;AACzB,cAAc,YAAY,CAAA;AAC1B,cAAc,aAAa,CAAA;AAC3B,cAAc,kBAAkB,CAAA;AAChC,cAAc,iBAAiB,CAAA;AAC/B,cAAc,YAAY,CAAA;AAC1B,cAAc,WAAW,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export * from './credential.js';
|
|
2
|
+
export * from './dpop.js';
|
|
3
|
+
export * from './error.js';
|
|
4
|
+
export * from './lthash.js';
|
|
5
|
+
export * from './repo-commit.js';
|
|
6
|
+
export * from './sync/index.js';
|
|
7
|
+
export * from './types.js';
|
|
8
|
+
export * from './util.js';
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAA;AAC/B,cAAc,WAAW,CAAA;AACzB,cAAc,YAAY,CAAA;AAC1B,cAAc,aAAa,CAAA;AAC3B,cAAc,kBAAkB,CAAA;AAChC,cAAc,iBAAiB,CAAA;AAC/B,cAAc,YAAY,CAAA;AAC1B,cAAc,WAAW,CAAA","sourcesContent":["export * from './credential.js'\nexport * from './dpop.js'\nexport * from './error.js'\nexport * from './lthash.js'\nexport * from './repo-commit.js'\nexport * from './sync/index.js'\nexport * from './types.js'\nexport * from './util.js'\n"]}
|
package/dist/lthash.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export declare const LTHASH_STATE_BYTES: number;
|
|
2
|
+
/**
|
|
3
|
+
* A homomorphic set hash. Each element expands to 1024 little-endian u16 lanes
|
|
4
|
+
* which are summed into the state mod 2^16. Addition and subtraction commute, so
|
|
5
|
+
* the state depends only on the current set, not on insertion order.
|
|
6
|
+
*/
|
|
7
|
+
export declare class LtHash {
|
|
8
|
+
private readonly bytes;
|
|
9
|
+
private readonly lanes;
|
|
10
|
+
constructor(state?: Uint8Array | null);
|
|
11
|
+
add(element: string): this;
|
|
12
|
+
remove(element: string): this;
|
|
13
|
+
state(): Uint8Array;
|
|
14
|
+
digest(): Uint8Array;
|
|
15
|
+
isEmpty(): boolean;
|
|
16
|
+
equals(other: LtHash): boolean;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=lthash.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lthash.d.ts","sourceRoot":"","sources":["../src/lthash.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,kBAAkB,QAAqB,CAAA;AAEpD;;;;GAIG;AACH,qBAAa,MAAM;IAGjB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAY;IAClC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAa;IAEnC,YAAY,KAAK,CAAC,EAAE,UAAU,GAAG,IAAI,EAUpC;IAED,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAMzB;IAED,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAM5B;IAGD,KAAK,IAAI,UAAU,CAElB;IAED,MAAM,IAAI,UAAU,CAEnB;IAED,OAAO,IAAI,OAAO,CAKjB;IAED,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAK7B;CACF"}
|
package/dist/lthash.js
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { blake3 } from '@noble/hashes/blake3';
|
|
2
|
+
import { sha256 } from '@noble/hashes/sha256';
|
|
3
|
+
const LANES = 1024;
|
|
4
|
+
const LANE_BYTES = 2; // @NOTE cannot change without reworking the Uint16Array impl
|
|
5
|
+
export const LTHASH_STATE_BYTES = LANES * LANE_BYTES; // 2048
|
|
6
|
+
/**
|
|
7
|
+
* A homomorphic set hash. Each element expands to 1024 little-endian u16 lanes
|
|
8
|
+
* which are summed into the state mod 2^16. Addition and subtraction commute, so
|
|
9
|
+
* the state depends only on the current set, not on insertion order.
|
|
10
|
+
*/
|
|
11
|
+
export class LtHash {
|
|
12
|
+
constructor(state) {
|
|
13
|
+
if (state && state.length !== LTHASH_STATE_BYTES) {
|
|
14
|
+
throw new Error(`LtHash state must be ${LTHASH_STATE_BYTES} bytes, got ${state.length}`);
|
|
15
|
+
}
|
|
16
|
+
const buffer = new ArrayBuffer(LTHASH_STATE_BYTES);
|
|
17
|
+
this.bytes = new Uint8Array(buffer);
|
|
18
|
+
this.lanes = new Uint16Array(buffer);
|
|
19
|
+
if (state)
|
|
20
|
+
this.bytes.set(state);
|
|
21
|
+
}
|
|
22
|
+
add(element) {
|
|
23
|
+
const lanes = expand(element);
|
|
24
|
+
for (let i = 0; i < LANES; i++) {
|
|
25
|
+
this.lanes[i] += lanes[i];
|
|
26
|
+
}
|
|
27
|
+
return this;
|
|
28
|
+
}
|
|
29
|
+
remove(element) {
|
|
30
|
+
const lanes = expand(element);
|
|
31
|
+
for (let i = 0; i < LANES; i++) {
|
|
32
|
+
this.lanes[i] -= lanes[i];
|
|
33
|
+
}
|
|
34
|
+
return this;
|
|
35
|
+
}
|
|
36
|
+
// The full state, for persistence.
|
|
37
|
+
state() {
|
|
38
|
+
return new Uint8Array(this.bytes);
|
|
39
|
+
}
|
|
40
|
+
digest() {
|
|
41
|
+
return sha256(this.bytes);
|
|
42
|
+
}
|
|
43
|
+
isEmpty() {
|
|
44
|
+
for (let i = 0; i < LANES; i++) {
|
|
45
|
+
if (this.lanes[i] !== 0)
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
equals(other) {
|
|
51
|
+
for (let i = 0; i < LANES; i++) {
|
|
52
|
+
if (this.lanes[i] !== other.lanes[i])
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
// Expand to 1024 u16 lanes with BLAKE3 in XOF mode.
|
|
59
|
+
const expand = (element) => {
|
|
60
|
+
const expanded = blake3(new TextEncoder().encode(element), {
|
|
61
|
+
dkLen: LTHASH_STATE_BYTES,
|
|
62
|
+
});
|
|
63
|
+
// Copy: the result may be a view at an offset a Uint16Array can't straddle.
|
|
64
|
+
const buffer = new ArrayBuffer(LTHASH_STATE_BYTES);
|
|
65
|
+
new Uint8Array(buffer).set(expanded);
|
|
66
|
+
return new Uint16Array(buffer);
|
|
67
|
+
};
|
|
68
|
+
//# sourceMappingURL=lthash.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lthash.js","sourceRoot":"","sources":["../src/lthash.ts"],"names":[],"mappings":"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","sourcesContent":["import { blake3 } from '@noble/hashes/blake3'\nimport { sha256 } from '@noble/hashes/sha256'\n\nconst LANES = 1024\nconst LANE_BYTES = 2 // @NOTE cannot change without reworking the Uint16Array impl\nexport const LTHASH_STATE_BYTES = LANES * LANE_BYTES // 2048\n\n/**\n * A homomorphic set hash. Each element expands to 1024 little-endian u16 lanes\n * which are summed into the state mod 2^16. Addition and subtraction commute, so\n * the state depends only on the current set, not on insertion order.\n */\nexport class LtHash {\n // Two views over one buffer: bytes for I/O, lanes for u16 arithmetic (which\n // wraps mod 2^16 on its own).\n private readonly bytes: Uint8Array\n private readonly lanes: Uint16Array\n\n constructor(state?: Uint8Array | null) {\n if (state && state.length !== LTHASH_STATE_BYTES) {\n throw new Error(\n `LtHash state must be ${LTHASH_STATE_BYTES} bytes, got ${state.length}`,\n )\n }\n const buffer = new ArrayBuffer(LTHASH_STATE_BYTES)\n this.bytes = new Uint8Array(buffer)\n this.lanes = new Uint16Array(buffer)\n if (state) this.bytes.set(state)\n }\n\n add(element: string): this {\n const lanes = expand(element)\n for (let i = 0; i < LANES; i++) {\n this.lanes[i] += lanes[i]\n }\n return this\n }\n\n remove(element: string): this {\n const lanes = expand(element)\n for (let i = 0; i < LANES; i++) {\n this.lanes[i] -= lanes[i]\n }\n return this\n }\n\n // The full state, for persistence.\n state(): Uint8Array {\n return new Uint8Array(this.bytes)\n }\n\n digest(): Uint8Array {\n return sha256(this.bytes)\n }\n\n isEmpty(): boolean {\n for (let i = 0; i < LANES; i++) {\n if (this.lanes[i] !== 0) return false\n }\n return true\n }\n\n equals(other: LtHash): boolean {\n for (let i = 0; i < LANES; i++) {\n if (this.lanes[i] !== other.lanes[i]) return false\n }\n return true\n }\n}\n\n// Expand to 1024 u16 lanes with BLAKE3 in XOF mode.\nconst expand = (element: string): Uint16Array => {\n const expanded = blake3(new TextEncoder().encode(element), {\n dkLen: LTHASH_STATE_BYTES,\n })\n // Copy: the result may be a view at an offset a Uint16Array can't straddle.\n const buffer = new ArrayBuffer(LTHASH_STATE_BYTES)\n new Uint8Array(buffer).set(expanded)\n return new Uint16Array(buffer)\n}\n"]}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { type Keypair } from '@atproto/crypto';
|
|
2
|
+
import { type Cid } from '@atproto/lex-data';
|
|
3
|
+
import { LtHash } from './lthash.js';
|
|
4
|
+
import { type CommitCtx, type RecordPath, type RepoIndex, type RepoOp, type SignedCommit } from './types.js';
|
|
5
|
+
export declare class RepoCommit {
|
|
6
|
+
setHash: LtHash;
|
|
7
|
+
constructor(setHash?: LtHash);
|
|
8
|
+
static fromState(state: Uint8Array | null | undefined): RepoCommit;
|
|
9
|
+
static fromRecords(records: Iterable<RecordPath & {
|
|
10
|
+
cid: Cid;
|
|
11
|
+
}>): RepoCommit;
|
|
12
|
+
static fromIndex(index: RepoIndex): RepoCommit;
|
|
13
|
+
add(collection: string, rkey: string, cid: Cid): this;
|
|
14
|
+
remove(collection: string, rkey: string, cid: Cid): this;
|
|
15
|
+
applyOp(op: RepoOp): this;
|
|
16
|
+
applyOps(ops: Iterable<RepoOp>): this;
|
|
17
|
+
/**
|
|
18
|
+
* Whether this repo's contents match a signed commit. Verify the commit first —
|
|
19
|
+
* on its own this says nothing about authenticity.
|
|
20
|
+
*/
|
|
21
|
+
matches(commit: SignedCommit): boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Sign a commit over the current contents.
|
|
24
|
+
*
|
|
25
|
+
* The signature covers only the ctx, never the digest, so a leaked commit proves
|
|
26
|
+
* nothing about what the author wrote. The digest is bound to the ctx by a
|
|
27
|
+
* symmetric MAC instead: readers get integrity, third parties get nothing. A
|
|
28
|
+
* fresh `ikm` per commit means each reader receives a distinct one.
|
|
29
|
+
*/
|
|
30
|
+
sign(ctx: CommitCtx, keypair: Keypair): Promise<SignedCommit>;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Verify a commit's signature (authenticity) and MAC (integrity). Once this passes,
|
|
34
|
+
* `hash` is trusted as the author's claim about their repo, which is what makes
|
|
35
|
+
* {@link RepoCommit#matches} meaningful.
|
|
36
|
+
*/
|
|
37
|
+
export declare const verifyCommit: (commit: SignedCommit, ctx: CommitCtx, didKey: string) => Promise<boolean>;
|
|
38
|
+
/**
|
|
39
|
+
* ```
|
|
40
|
+
* ctx = "atproto-space-v1"
|
|
41
|
+
* || uint16be(len(space)) || space
|
|
42
|
+
* || uint16be(len(author)) || author
|
|
43
|
+
* || uint16be(len(rev)) || rev
|
|
44
|
+
* || uint16be(len(ikm)) || ikm
|
|
45
|
+
* ```
|
|
46
|
+
*
|
|
47
|
+
* Length prefixes are big-endian per the TLS variable-length vector convention —
|
|
48
|
+
* deliberately the opposite byte order from the set hash's lanes.
|
|
49
|
+
*/
|
|
50
|
+
export declare const encodeCommitCtx: (ctx: CommitCtx, ikm: Uint8Array) => Uint8Array;
|
|
51
|
+
//# sourceMappingURL=repo-commit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repo-commit.d.ts","sourceRoot":"","sources":["../src/repo-commit.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,OAAO,EAKb,MAAM,iBAAiB,CAAA;AACxB,OAAO,EAAE,KAAK,GAAG,EAAa,MAAM,mBAAmB,CAAA;AACvD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACpC,OAAO,EAEL,KAAK,SAAS,EACd,KAAK,UAAU,EACf,KAAK,SAAS,EACd,KAAK,MAAM,EACX,KAAK,YAAY,EAClB,MAAM,YAAY,CAAA;AAGnB,qBAAa,UAAU;IACF,OAAO,EAAE,MAAM;IAAlC,YAAmB,OAAO,GAAE,MAAqB,EAAI;IAGrD,MAAM,CAAC,SAAS,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,GAAG,SAAS,GAAG,UAAU,CAEjE;IAED,MAAM,CAAC,WAAW,CAAC,OAAO,EAAE,QAAQ,CAAC,UAAU,GAAG;QAAE,GAAG,EAAE,GAAG,CAAA;KAAE,CAAC,GAAG,UAAU,CAM3E;IAGD,MAAM,CAAC,SAAS,CAAC,KAAK,EAAE,SAAS,GAAG,UAAU,CAM7C;IAED,GAAG,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,GAAG,IAAI,CAGpD;IAED,MAAM,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,GAAG,IAAI,CAGvD;IAED,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAIxB;IAED,QAAQ,CAAC,GAAG,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,IAAI,CAKpC;IAED;;;OAGG;IACH,OAAO,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAErC;IAED;;;;;;;OAOG;IACG,IAAI,CAAC,GAAG,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,YAAY,CAAC,CAYlE;CACF;AAED;;;;GAIG;AACH,eAAO,MAAM,YAAY,WACf,YAAY,OACf,SAAS,UACN,MAAM,KACb,OAAO,CAAC,OAAO,CASjB,CAAA;AAYD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,eAAe,QACrB,SAAS,OACT,UAAU,KACd,UA2BF,CAAA"}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { hkdfSha256, hmacSha256, randomBytes, verifySignature, } from '@atproto/crypto';
|
|
2
|
+
import { ui8Equals } from '@atproto/lex-data';
|
|
3
|
+
import { LtHash } from './lthash.js';
|
|
4
|
+
import { COMMIT_VERSION, } from './types.js';
|
|
5
|
+
import { formatSetHashElement } from './util.js';
|
|
6
|
+
export class RepoCommit {
|
|
7
|
+
constructor(setHash = new LtHash()) {
|
|
8
|
+
this.setHash = setHash;
|
|
9
|
+
}
|
|
10
|
+
// nullish state yields an empty repo
|
|
11
|
+
static fromState(state) {
|
|
12
|
+
return new RepoCommit(new LtHash(state));
|
|
13
|
+
}
|
|
14
|
+
static fromRecords(records) {
|
|
15
|
+
const commit = new RepoCommit();
|
|
16
|
+
for (const { collection, rkey, cid } of records) {
|
|
17
|
+
commit.add(collection, rkey, cid);
|
|
18
|
+
}
|
|
19
|
+
return commit;
|
|
20
|
+
}
|
|
21
|
+
// Fold in every record an index describes, to compare against a commit.
|
|
22
|
+
static fromIndex(index) {
|
|
23
|
+
const commit = new RepoCommit();
|
|
24
|
+
for (const [path, cid] of Object.entries(index)) {
|
|
25
|
+
commit.setHash.add(`${path}/${cid.toString()}`);
|
|
26
|
+
}
|
|
27
|
+
return commit;
|
|
28
|
+
}
|
|
29
|
+
add(collection, rkey, cid) {
|
|
30
|
+
this.setHash.add(formatSetHashElement(collection, rkey, cid));
|
|
31
|
+
return this;
|
|
32
|
+
}
|
|
33
|
+
remove(collection, rkey, cid) {
|
|
34
|
+
this.setHash.remove(formatSetHashElement(collection, rkey, cid));
|
|
35
|
+
return this;
|
|
36
|
+
}
|
|
37
|
+
applyOp(op) {
|
|
38
|
+
if (op.prev)
|
|
39
|
+
this.remove(op.collection, op.rkey, op.prev);
|
|
40
|
+
if (op.cid)
|
|
41
|
+
this.add(op.collection, op.rkey, op.cid);
|
|
42
|
+
return this;
|
|
43
|
+
}
|
|
44
|
+
applyOps(ops) {
|
|
45
|
+
for (const op of ops) {
|
|
46
|
+
this.applyOp(op);
|
|
47
|
+
}
|
|
48
|
+
return this;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Whether this repo's contents match a signed commit. Verify the commit first —
|
|
52
|
+
* on its own this says nothing about authenticity.
|
|
53
|
+
*/
|
|
54
|
+
matches(commit) {
|
|
55
|
+
return ui8Equals(this.setHash.digest(), commit.hash);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Sign a commit over the current contents.
|
|
59
|
+
*
|
|
60
|
+
* The signature covers only the ctx, never the digest, so a leaked commit proves
|
|
61
|
+
* nothing about what the author wrote. The digest is bound to the ctx by a
|
|
62
|
+
* symmetric MAC instead: readers get integrity, third parties get nothing. A
|
|
63
|
+
* fresh `ikm` per commit means each reader receives a distinct one.
|
|
64
|
+
*/
|
|
65
|
+
async sign(ctx, keypair) {
|
|
66
|
+
const hash = this.setHash.digest();
|
|
67
|
+
const ikm = randomBytes(32);
|
|
68
|
+
const ctxBytes = encodeCommitCtx(ctx, ikm);
|
|
69
|
+
return {
|
|
70
|
+
ver: COMMIT_VERSION,
|
|
71
|
+
hash,
|
|
72
|
+
ikm,
|
|
73
|
+
mac: computeMac(ikm, ctxBytes, hash),
|
|
74
|
+
sig: await keypair.sign(ctxBytes),
|
|
75
|
+
rev: ctx.rev,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Verify a commit's signature (authenticity) and MAC (integrity). Once this passes,
|
|
81
|
+
* `hash` is trusted as the author's claim about their repo, which is what makes
|
|
82
|
+
* {@link RepoCommit#matches} meaningful.
|
|
83
|
+
*/
|
|
84
|
+
export const verifyCommit = async (commit, ctx, didKey) => {
|
|
85
|
+
if (commit.ver !== COMMIT_VERSION)
|
|
86
|
+
return false;
|
|
87
|
+
if (commit.rev !== ctx.rev)
|
|
88
|
+
return false;
|
|
89
|
+
const ctxBytes = encodeCommitCtx(ctx, commit.ikm);
|
|
90
|
+
const mac = computeMac(commit.ikm, ctxBytes, commit.hash);
|
|
91
|
+
if (!ui8Equals(mac, commit.mac))
|
|
92
|
+
return false;
|
|
93
|
+
return verifySignature(didKey, ctxBytes, commit.sig);
|
|
94
|
+
};
|
|
95
|
+
const computeMac = (ikm, ctxBytes, hash) => {
|
|
96
|
+
return hmacSha256(hkdfSha256(ikm, ctxBytes), hash);
|
|
97
|
+
};
|
|
98
|
+
const DOMAIN_PREFIX = new TextEncoder().encode('atproto-space-v1');
|
|
99
|
+
/**
|
|
100
|
+
* ```
|
|
101
|
+
* ctx = "atproto-space-v1"
|
|
102
|
+
* || uint16be(len(space)) || space
|
|
103
|
+
* || uint16be(len(author)) || author
|
|
104
|
+
* || uint16be(len(rev)) || rev
|
|
105
|
+
* || uint16be(len(ikm)) || ikm
|
|
106
|
+
* ```
|
|
107
|
+
*
|
|
108
|
+
* Length prefixes are big-endian per the TLS variable-length vector convention —
|
|
109
|
+
* deliberately the opposite byte order from the set hash's lanes.
|
|
110
|
+
*/
|
|
111
|
+
export const encodeCommitCtx = (ctx, ikm) => {
|
|
112
|
+
const encoder = new TextEncoder();
|
|
113
|
+
const fields = [
|
|
114
|
+
encoder.encode(ctx.space),
|
|
115
|
+
encoder.encode(ctx.author),
|
|
116
|
+
encoder.encode(ctx.rev),
|
|
117
|
+
ikm,
|
|
118
|
+
];
|
|
119
|
+
let size = DOMAIN_PREFIX.length;
|
|
120
|
+
for (const field of fields) {
|
|
121
|
+
if (field.length > 0xffff) {
|
|
122
|
+
throw new Error('commit ctx field exceeds uint16 length prefix');
|
|
123
|
+
}
|
|
124
|
+
size += 2 + field.length;
|
|
125
|
+
}
|
|
126
|
+
const out = new Uint8Array(size);
|
|
127
|
+
out.set(DOMAIN_PREFIX);
|
|
128
|
+
let offset = DOMAIN_PREFIX.length;
|
|
129
|
+
for (const field of fields) {
|
|
130
|
+
out[offset++] = (field.length >>> 8) & 0xff;
|
|
131
|
+
out[offset++] = field.length & 0xff;
|
|
132
|
+
out.set(field, offset);
|
|
133
|
+
offset += field.length;
|
|
134
|
+
}
|
|
135
|
+
return out;
|
|
136
|
+
};
|
|
137
|
+
//# sourceMappingURL=repo-commit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repo-commit.js","sourceRoot":"","sources":["../src/repo-commit.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type Keypair,\n hkdfSha256,\n hmacSha256,\n randomBytes,\n verifySignature,\n} from '@atproto/crypto'\nimport { type Cid, ui8Equals } from '@atproto/lex-data'\nimport { LtHash } from './lthash.js'\nimport {\n COMMIT_VERSION,\n type CommitCtx,\n type RecordPath,\n type RepoIndex,\n type RepoOp,\n type SignedCommit,\n} from './types.js'\nimport { formatSetHashElement } from './util.js'\n\nexport class RepoCommit {\n constructor(public setHash: LtHash = new LtHash()) {}\n\n // nullish state yields an empty repo\n static fromState(state: Uint8Array | null | undefined): RepoCommit {\n return new RepoCommit(new LtHash(state))\n }\n\n static fromRecords(records: Iterable<RecordPath & { cid: Cid }>): RepoCommit {\n const commit = new RepoCommit()\n for (const { collection, rkey, cid } of records) {\n commit.add(collection, rkey, cid)\n }\n return commit\n }\n\n // Fold in every record an index describes, to compare against a commit.\n static fromIndex(index: RepoIndex): RepoCommit {\n const commit = new RepoCommit()\n for (const [path, cid] of Object.entries(index)) {\n commit.setHash.add(`${path}/${cid.toString()}`)\n }\n return commit\n }\n\n add(collection: string, rkey: string, cid: Cid): this {\n this.setHash.add(formatSetHashElement(collection, rkey, cid))\n return this\n }\n\n remove(collection: string, rkey: string, cid: Cid): this {\n this.setHash.remove(formatSetHashElement(collection, rkey, cid))\n return this\n }\n\n applyOp(op: RepoOp): this {\n if (op.prev) this.remove(op.collection, op.rkey, op.prev)\n if (op.cid) this.add(op.collection, op.rkey, op.cid)\n return this\n }\n\n applyOps(ops: Iterable<RepoOp>): this {\n for (const op of ops) {\n this.applyOp(op)\n }\n return this\n }\n\n /**\n * Whether this repo's contents match a signed commit. Verify the commit first —\n * on its own this says nothing about authenticity.\n */\n matches(commit: SignedCommit): boolean {\n return ui8Equals(this.setHash.digest(), commit.hash)\n }\n\n /**\n * Sign a commit over the current contents.\n *\n * The signature covers only the ctx, never the digest, so a leaked commit proves\n * nothing about what the author wrote. The digest is bound to the ctx by a\n * symmetric MAC instead: readers get integrity, third parties get nothing. A\n * fresh `ikm` per commit means each reader receives a distinct one.\n */\n async sign(ctx: CommitCtx, keypair: Keypair): Promise<SignedCommit> {\n const hash = this.setHash.digest()\n const ikm = randomBytes(32)\n const ctxBytes = encodeCommitCtx(ctx, ikm)\n return {\n ver: COMMIT_VERSION,\n hash,\n ikm,\n mac: computeMac(ikm, ctxBytes, hash),\n sig: await keypair.sign(ctxBytes),\n rev: ctx.rev,\n }\n }\n}\n\n/**\n * Verify a commit's signature (authenticity) and MAC (integrity). Once this passes,\n * `hash` is trusted as the author's claim about their repo, which is what makes\n * {@link RepoCommit#matches} meaningful.\n */\nexport const verifyCommit = async (\n commit: SignedCommit,\n ctx: CommitCtx,\n didKey: string,\n): Promise<boolean> => {\n if (commit.ver !== COMMIT_VERSION) return false\n if (commit.rev !== ctx.rev) return false\n\n const ctxBytes = encodeCommitCtx(ctx, commit.ikm)\n const mac = computeMac(commit.ikm, ctxBytes, commit.hash)\n if (!ui8Equals(mac, commit.mac)) return false\n\n return verifySignature(didKey, ctxBytes, commit.sig)\n}\n\nconst computeMac = (\n ikm: Uint8Array,\n ctxBytes: Uint8Array,\n hash: Uint8Array,\n): Uint8Array => {\n return hmacSha256(hkdfSha256(ikm, ctxBytes), hash)\n}\n\nconst DOMAIN_PREFIX = new TextEncoder().encode('atproto-space-v1')\n\n/**\n * ```\n * ctx = \"atproto-space-v1\"\n * || uint16be(len(space)) || space\n * || uint16be(len(author)) || author\n * || uint16be(len(rev)) || rev\n * || uint16be(len(ikm)) || ikm\n * ```\n *\n * Length prefixes are big-endian per the TLS variable-length vector convention —\n * deliberately the opposite byte order from the set hash's lanes.\n */\nexport const encodeCommitCtx = (\n ctx: CommitCtx,\n ikm: Uint8Array,\n): Uint8Array => {\n const encoder = new TextEncoder()\n const fields = [\n encoder.encode(ctx.space),\n encoder.encode(ctx.author),\n encoder.encode(ctx.rev),\n ikm,\n ]\n\n let size = DOMAIN_PREFIX.length\n for (const field of fields) {\n if (field.length > 0xffff) {\n throw new Error('commit ctx field exceeds uint16 length prefix')\n }\n size += 2 + field.length\n }\n\n const out = new Uint8Array(size)\n out.set(DOMAIN_PREFIX)\n let offset = DOMAIN_PREFIX.length\n for (const field of fields) {\n out[offset++] = (field.length >>> 8) & 0xff\n out[offset++] = field.length & 0xff\n out.set(field, offset)\n offset += field.length\n }\n return out\n}\n"]}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Keypair } from '@atproto/crypto';
|
|
2
|
+
import { LtHash } from './lthash.js';
|
|
3
|
+
import { SpaceMembersStorage } from './storage/index.js';
|
|
4
|
+
import { MemberCommitData, MemberWriteOp, SignedCommit, SpaceContext } from './types.js';
|
|
5
|
+
type Params = {
|
|
6
|
+
storage: SpaceMembersStorage;
|
|
7
|
+
setHash?: LtHash;
|
|
8
|
+
};
|
|
9
|
+
export declare class SpaceMembers {
|
|
10
|
+
storage: SpaceMembersStorage;
|
|
11
|
+
setHash: LtHash;
|
|
12
|
+
constructor(params: Params);
|
|
13
|
+
static create(storage: SpaceMembersStorage): SpaceMembers;
|
|
14
|
+
static load(storage: SpaceMembersStorage): Promise<SpaceMembers>;
|
|
15
|
+
static loadOrCreate(storage: SpaceMembersStorage): Promise<SpaceMembers>;
|
|
16
|
+
static recompute(storage: SpaceMembersStorage): Promise<SpaceMembers>;
|
|
17
|
+
formatCommit(ops: MemberWriteOp | MemberWriteOp[]): Promise<MemberCommitData>;
|
|
18
|
+
applyCommit(commit: MemberCommitData): Promise<void>;
|
|
19
|
+
addMember(did: string): Promise<MemberCommitData>;
|
|
20
|
+
removeMember(did: string): Promise<MemberCommitData>;
|
|
21
|
+
getMembers(): Promise<string[]>;
|
|
22
|
+
isMember(did: string): Promise<boolean>;
|
|
23
|
+
commit(space: SpaceContext, keypair: Keypair): Promise<SignedCommit>;
|
|
24
|
+
verifyCommit(space: SpaceContext, commit: SignedCommit): boolean;
|
|
25
|
+
}
|
|
26
|
+
export { MemberAlreadyExistsError, MemberNotFoundError } from './error.js';
|
|
27
|
+
//# sourceMappingURL=space-members.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"space-members.d.ts","sourceRoot":"","sources":["../src/space-members.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAA;AAGzC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACpC,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAA;AACxD,OAAO,EACL,gBAAgB,EAEhB,aAAa,EAEb,YAAY,EACZ,YAAY,EACb,MAAM,YAAY,CAAA;AAEnB,KAAK,MAAM,GAAG;IACZ,OAAO,EAAE,mBAAmB,CAAA;IAC5B,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB,CAAA;AAED,qBAAa,YAAY;IACvB,OAAO,EAAE,mBAAmB,CAAA;IAC5B,OAAO,EAAE,MAAM,CAAA;gBAEH,MAAM,EAAE,MAAM;IAK1B,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,mBAAmB,GAAG,YAAY;WAI5C,IAAI,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,YAAY,CAAC;WAQzD,YAAY,CACvB,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,YAAY,CAAC;WAQX,SAAS,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,YAAY,CAAC;IASrE,YAAY,CAChB,GAAG,EAAE,aAAa,GAAG,aAAa,EAAE,GACnC,OAAO,CAAC,gBAAgB,CAAC;IAmCtB,WAAW,CAAC,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAKpD,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IASjD,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAWpD,UAAU,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAI/B,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAMvC,MAAM,CAAC,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,YAAY,CAAC;IAI1E,YAAY,CAAC,KAAK,EAAE,YAAY,EAAE,MAAM,EAAE,YAAY,GAAG,OAAO;CAMjE;AAED,OAAO,EAAE,wBAAwB,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAA"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MemberNotFoundError = exports.MemberAlreadyExistsError = exports.SpaceMembers = void 0;
|
|
4
|
+
const commit_js_1 = require("./commit.js");
|
|
5
|
+
const error_js_1 = require("./error.js");
|
|
6
|
+
const lthash_js_1 = require("./lthash.js");
|
|
7
|
+
const types_js_1 = require("./types.js");
|
|
8
|
+
class SpaceMembers {
|
|
9
|
+
constructor(params) {
|
|
10
|
+
this.storage = params.storage;
|
|
11
|
+
this.setHash = params.setHash ?? new lthash_js_1.LtHash();
|
|
12
|
+
}
|
|
13
|
+
static create(storage) {
|
|
14
|
+
return new SpaceMembers({ storage });
|
|
15
|
+
}
|
|
16
|
+
static async load(storage) {
|
|
17
|
+
const stored = await storage.getSetHashState();
|
|
18
|
+
if (stored) {
|
|
19
|
+
return new SpaceMembers({ storage, setHash: new lthash_js_1.LtHash(stored) });
|
|
20
|
+
}
|
|
21
|
+
return SpaceMembers.recompute(storage);
|
|
22
|
+
}
|
|
23
|
+
static async loadOrCreate(storage) {
|
|
24
|
+
const stored = await storage.getSetHashState();
|
|
25
|
+
if (stored) {
|
|
26
|
+
return new SpaceMembers({ storage, setHash: new lthash_js_1.LtHash(stored) });
|
|
27
|
+
}
|
|
28
|
+
return new SpaceMembers({ storage });
|
|
29
|
+
}
|
|
30
|
+
static async recompute(storage) {
|
|
31
|
+
const setHash = new lthash_js_1.LtHash();
|
|
32
|
+
const members = await storage.getMembers();
|
|
33
|
+
for (const did of members) {
|
|
34
|
+
setHash.add(did);
|
|
35
|
+
}
|
|
36
|
+
return new SpaceMembers({ storage, setHash });
|
|
37
|
+
}
|
|
38
|
+
async formatCommit(ops) {
|
|
39
|
+
const operations = Array.isArray(ops) ? ops : [ops];
|
|
40
|
+
const prepared = [];
|
|
41
|
+
const newSetHash = new lthash_js_1.LtHash(this.setHash.toBytes());
|
|
42
|
+
for (const op of operations) {
|
|
43
|
+
if (op.action === types_js_1.MemberOpAction.Add) {
|
|
44
|
+
const exists = await this.storage.isMember(op.did);
|
|
45
|
+
if (exists) {
|
|
46
|
+
throw new error_js_1.MemberAlreadyExistsError(op.did);
|
|
47
|
+
}
|
|
48
|
+
newSetHash.add(op.did);
|
|
49
|
+
prepared.push({
|
|
50
|
+
action: types_js_1.MemberOpAction.Add,
|
|
51
|
+
did: op.did,
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
else if (op.action === types_js_1.MemberOpAction.Remove) {
|
|
55
|
+
const exists = await this.storage.isMember(op.did);
|
|
56
|
+
if (!exists) {
|
|
57
|
+
throw new error_js_1.MemberNotFoundError(op.did);
|
|
58
|
+
}
|
|
59
|
+
newSetHash.remove(op.did);
|
|
60
|
+
prepared.push({
|
|
61
|
+
action: types_js_1.MemberOpAction.Remove,
|
|
62
|
+
did: op.did,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return {
|
|
67
|
+
ops: prepared,
|
|
68
|
+
setHash: newSetHash.toBytes(),
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
async applyCommit(commit) {
|
|
72
|
+
await this.storage.applyCommit(commit);
|
|
73
|
+
this.setHash = new lthash_js_1.LtHash(commit.setHash);
|
|
74
|
+
}
|
|
75
|
+
async addMember(did) {
|
|
76
|
+
const commit = await this.formatCommit({
|
|
77
|
+
action: types_js_1.MemberOpAction.Add,
|
|
78
|
+
did,
|
|
79
|
+
});
|
|
80
|
+
await this.applyCommit(commit);
|
|
81
|
+
return commit;
|
|
82
|
+
}
|
|
83
|
+
async removeMember(did) {
|
|
84
|
+
const commit = await this.formatCommit({
|
|
85
|
+
action: types_js_1.MemberOpAction.Remove,
|
|
86
|
+
did,
|
|
87
|
+
});
|
|
88
|
+
await this.applyCommit(commit);
|
|
89
|
+
return commit;
|
|
90
|
+
}
|
|
91
|
+
// Reads
|
|
92
|
+
async getMembers() {
|
|
93
|
+
return this.storage.getMembers();
|
|
94
|
+
}
|
|
95
|
+
async isMember(did) {
|
|
96
|
+
return this.storage.isMember(did);
|
|
97
|
+
}
|
|
98
|
+
// Signed commits
|
|
99
|
+
async commit(space, keypair) {
|
|
100
|
+
return (0, commit_js_1.createCommit)(this.setHash, space, keypair);
|
|
101
|
+
}
|
|
102
|
+
verifyCommit(space, commit) {
|
|
103
|
+
return (commit.hash.equals(this.setHash.digest()) &&
|
|
104
|
+
(0, commit_js_1.verifyCommit)(space, commit));
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
exports.SpaceMembers = SpaceMembers;
|
|
108
|
+
var error_js_2 = require("./error.js");
|
|
109
|
+
Object.defineProperty(exports, "MemberAlreadyExistsError", { enumerable: true, get: function () { return error_js_2.MemberAlreadyExistsError; } });
|
|
110
|
+
Object.defineProperty(exports, "MemberNotFoundError", { enumerable: true, get: function () { return error_js_2.MemberNotFoundError; } });
|
|
111
|
+
//# sourceMappingURL=space-members.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"space-members.js","sourceRoot":"","sources":["../src/space-members.ts"],"names":[],"mappings":"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","sourcesContent":["import { Keypair } from '@atproto/crypto'\nimport { createCommit, verifyCommit } from './commit.js'\nimport { MemberAlreadyExistsError, MemberNotFoundError } from './error.js'\nimport { LtHash } from './lthash.js'\nimport { SpaceMembersStorage } from './storage/index.js'\nimport {\n MemberCommitData,\n MemberOpAction,\n MemberWriteOp,\n PreparedMemberOp,\n SignedCommit,\n SpaceContext,\n} from './types.js'\n\ntype Params = {\n storage: SpaceMembersStorage\n setHash?: LtHash\n}\n\nexport class SpaceMembers {\n storage: SpaceMembersStorage\n setHash: LtHash\n\n constructor(params: Params) {\n this.storage = params.storage\n this.setHash = params.setHash ?? new LtHash()\n }\n\n static create(storage: SpaceMembersStorage): SpaceMembers {\n return new SpaceMembers({ storage })\n }\n\n static async load(storage: SpaceMembersStorage): Promise<SpaceMembers> {\n const stored = await storage.getSetHashState()\n if (stored) {\n return new SpaceMembers({ storage, setHash: new LtHash(stored) })\n }\n return SpaceMembers.recompute(storage)\n }\n\n static async loadOrCreate(\n storage: SpaceMembersStorage,\n ): Promise<SpaceMembers> {\n const stored = await storage.getSetHashState()\n if (stored) {\n return new SpaceMembers({ storage, setHash: new LtHash(stored) })\n }\n return new SpaceMembers({ storage })\n }\n\n static async recompute(storage: SpaceMembersStorage): Promise<SpaceMembers> {\n const setHash = new LtHash()\n const members = await storage.getMembers()\n for (const did of members) {\n setHash.add(did)\n }\n return new SpaceMembers({ storage, setHash })\n }\n\n async formatCommit(\n ops: MemberWriteOp | MemberWriteOp[],\n ): Promise<MemberCommitData> {\n const operations = Array.isArray(ops) ? ops : [ops]\n const prepared: PreparedMemberOp[] = []\n const newSetHash = new LtHash(this.setHash.toBytes())\n\n for (const op of operations) {\n if (op.action === MemberOpAction.Add) {\n const exists = await this.storage.isMember(op.did)\n if (exists) {\n throw new MemberAlreadyExistsError(op.did)\n }\n newSetHash.add(op.did)\n prepared.push({\n action: MemberOpAction.Add,\n did: op.did,\n })\n } else if (op.action === MemberOpAction.Remove) {\n const exists = await this.storage.isMember(op.did)\n if (!exists) {\n throw new MemberNotFoundError(op.did)\n }\n newSetHash.remove(op.did)\n prepared.push({\n action: MemberOpAction.Remove,\n did: op.did,\n })\n }\n }\n\n return {\n ops: prepared,\n setHash: newSetHash.toBytes(),\n }\n }\n\n async applyCommit(commit: MemberCommitData): Promise<void> {\n await this.storage.applyCommit(commit)\n this.setHash = new LtHash(commit.setHash)\n }\n\n async addMember(did: string): Promise<MemberCommitData> {\n const commit = await this.formatCommit({\n action: MemberOpAction.Add,\n did,\n })\n await this.applyCommit(commit)\n return commit\n }\n\n async removeMember(did: string): Promise<MemberCommitData> {\n const commit = await this.formatCommit({\n action: MemberOpAction.Remove,\n did,\n })\n await this.applyCommit(commit)\n return commit\n }\n\n // Reads\n\n async getMembers(): Promise<string[]> {\n return this.storage.getMembers()\n }\n\n async isMember(did: string): Promise<boolean> {\n return this.storage.isMember(did)\n }\n\n // Signed commits\n\n async commit(space: SpaceContext, keypair: Keypair): Promise<SignedCommit> {\n return createCommit(this.setHash, space, keypair)\n }\n\n verifyCommit(space: SpaceContext, commit: SignedCommit): boolean {\n return (\n commit.hash.equals(this.setHash.digest()) &&\n verifyCommit(space, commit)\n )\n }\n}\n\nexport { MemberAlreadyExistsError, MemberNotFoundError } from './error.js'\n"]}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { Keypair } from '@atproto/crypto';
|
|
2
|
+
import { LtHash } from './lthash.js';
|
|
3
|
+
import { SpaceRepoStorage } from './storage/index.js';
|
|
4
|
+
import { CommitData, RecordWriteOp, RepoRecord, SignedCommit, SpaceContext } from './types.js';
|
|
5
|
+
type Params = {
|
|
6
|
+
storage: SpaceRepoStorage;
|
|
7
|
+
did: string;
|
|
8
|
+
setHash?: LtHash;
|
|
9
|
+
};
|
|
10
|
+
export declare class SpaceRepo {
|
|
11
|
+
storage: SpaceRepoStorage;
|
|
12
|
+
did: string;
|
|
13
|
+
setHash: LtHash;
|
|
14
|
+
constructor(params: Params);
|
|
15
|
+
static create(storage: SpaceRepoStorage, did: string): SpaceRepo;
|
|
16
|
+
static load(storage: SpaceRepoStorage, did: string): Promise<SpaceRepo>;
|
|
17
|
+
static loadOrCreate(storage: SpaceRepoStorage, did: string): Promise<SpaceRepo>;
|
|
18
|
+
static recompute(storage: SpaceRepoStorage, did: string): Promise<SpaceRepo>;
|
|
19
|
+
formatCommit(writes: RecordWriteOp | RecordWriteOp[]): Promise<CommitData>;
|
|
20
|
+
applyCommit(commit: CommitData): Promise<void>;
|
|
21
|
+
applyWrites(writes: RecordWriteOp | RecordWriteOp[]): Promise<CommitData>;
|
|
22
|
+
getRecord(collection: string, rkey: string): Promise<RepoRecord | null>;
|
|
23
|
+
listCollections(): Promise<string[]>;
|
|
24
|
+
listRecords(collection: string): Promise<{
|
|
25
|
+
rkey: string;
|
|
26
|
+
record: RepoRecord;
|
|
27
|
+
}[]>;
|
|
28
|
+
commit(space: SpaceContext, keypair: Keypair): Promise<SignedCommit>;
|
|
29
|
+
verifyCommit(space: SpaceContext, commit: SignedCommit): boolean;
|
|
30
|
+
verifyCommitSig(space: SpaceContext, commit: SignedCommit, didKey: string): Promise<boolean>;
|
|
31
|
+
}
|
|
32
|
+
export { RecordAlreadyExistsError, RecordNotFoundError } from './error.js';
|
|
33
|
+
//# sourceMappingURL=space-repo.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"space-repo.d.ts","sourceRoot":"","sources":["../src/space-repo.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAA;AAIzC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACpC,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AACrD,OAAO,EACL,UAAU,EAEV,aAAa,EACb,UAAU,EACV,YAAY,EACZ,YAAY,EAEb,MAAM,YAAY,CAAA;AAGnB,KAAK,MAAM,GAAG;IACZ,OAAO,EAAE,gBAAgB,CAAA;IACzB,GAAG,EAAE,MAAM,CAAA;IACX,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB,CAAA;AAED,qBAAa,SAAS;IACpB,OAAO,EAAE,gBAAgB,CAAA;IACzB,GAAG,EAAE,MAAM,CAAA;IACX,OAAO,EAAE,MAAM,CAAA;gBAEH,MAAM,EAAE,MAAM;IAM1B,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,gBAAgB,EAAE,GAAG,EAAE,MAAM,GAAG,SAAS;WAInD,IAAI,CACf,OAAO,EAAE,gBAAgB,EACzB,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,SAAS,CAAC;WAQR,YAAY,CACvB,OAAO,EAAE,gBAAgB,EACzB,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,SAAS,CAAC;WAQR,SAAS,CACpB,OAAO,EAAE,gBAAgB,EACzB,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,SAAS,CAAC;IAYf,YAAY,CAChB,MAAM,EAAE,aAAa,GAAG,aAAa,EAAE,GACtC,OAAO,CAAC,UAAU,CAAC;IA+DhB,WAAW,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAK9C,WAAW,CACf,MAAM,EAAE,aAAa,GAAG,aAAa,EAAE,GACtC,OAAO,CAAC,UAAU,CAAC;IAQhB,SAAS,CACb,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;IAIvB,eAAe,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAIpC,WAAW,CACf,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,UAAU,CAAA;KAAE,EAAE,CAAC;IAM5C,MAAM,CAAC,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,YAAY,CAAC;IAO1E,YAAY,CAAC,KAAK,EAAE,YAAY,EAAE,MAAM,EAAE,YAAY,GAAG,OAAO;IAOhE,eAAe,CACb,KAAK,EAAE,YAAY,EACnB,MAAM,EAAE,YAAY,EACpB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,OAAO,CAAC;CAGpB;AAED,OAAO,EAAE,wBAAwB,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAA"}
|