+1
deno.lock
+1
deno.lock
···
14
14
"npm:@atcute/atproto@^3.1.9": "3.1.9",
15
15
"npm:@atcute/client@^4.0.5": "4.0.5",
16
16
"npm:@atcute/jetstream@^1.1.2": "1.1.2",
17
+
"npm:@atcute/lex-cli@*": "2.3.1",
17
18
"npm:@atcute/lex-cli@^2.3.1": "2.3.1",
18
19
"npm:@atcute/lexicons@^1.2.2": "1.2.2",
19
20
"npm:@atcute/tid@^1.0.3": "1.0.3",
+21
-20
packages/consumer/mod.test.ts
+21
-20
packages/consumer/mod.test.ts
···
5
5
import type { Client, CredentialManager } from "@atcute/client";
6
6
import type { Did, Handle, ResourceUri } from "@atcute/lexicons";
7
7
import { now } from "@atcute/tid";
8
+
import type { AppCisternLexiconItem } from "@cistern/lexicon";
8
9
9
10
// Helper to create a mock Consumer instance
10
11
function createMockConsumer(
···
194
195
value: {
195
196
$type: "app.cistern.lexicon.item",
196
197
tid: testTid,
197
-
ciphertext: encrypted.cipherText,
198
-
nonce: encrypted.nonce,
198
+
ciphertext: { $bytes: encrypted.cipherText },
199
+
nonce: { $bytes: encrypted.nonce },
199
200
algorithm: "x_wing-xchacha20_poly1305-sha3_512",
200
201
pubkey: "at://did:plc:test/app.cistern.lexicon.pubkey/key1",
201
-
payload: encrypted.content,
202
+
payload: { $bytes: encrypted.content },
202
203
contentLength: encrypted.length,
203
-
contentHash: encrypted.hash,
204
-
},
204
+
contentHash: { $bytes: encrypted.hash },
205
+
} as AppCisternLexiconItem.Main,
205
206
},
206
207
],
207
208
cursor: undefined,
···
256
257
value: {
257
258
$type: "app.cistern.lexicon.item",
258
259
tid: testTid,
259
-
ciphertext: encrypted.cipherText,
260
-
nonce: encrypted.nonce,
260
+
ciphertext: { $bytes: encrypted.cipherText },
261
+
nonce: { $bytes: encrypted.nonce },
261
262
algorithm: "x_wing-xchacha20_poly1305-sha3_512",
262
263
pubkey:
263
264
"at://did:plc:test/app.cistern.lexicon.pubkey/different-key",
264
-
payload: encrypted.content,
265
+
payload: { $bytes: encrypted.content },
265
266
contentLength: encrypted.length,
266
-
contentHash: encrypted.hash,
267
-
},
267
+
contentHash: { $bytes: encrypted.hash },
268
+
} as AppCisternLexiconItem.Main,
268
269
},
269
270
],
270
271
cursor: undefined,
···
324
325
value: {
325
326
$type: "app.cistern.lexicon.item",
326
327
tid: tid1,
327
-
ciphertext: encrypted1.cipherText,
328
-
nonce: encrypted1.nonce,
328
+
ciphertext: { $bytes: encrypted1.cipherText },
329
+
nonce: { $bytes: encrypted1.nonce },
329
330
algorithm: "x_wing-xchacha20_poly1305-sha3_512",
330
331
pubkey:
331
332
"at://did:plc:test/app.cistern.lexicon.pubkey/key1",
332
-
payload: encrypted1.content,
333
+
payload: { $bytes: encrypted1.content },
333
334
contentLength: encrypted1.length,
334
-
contentHash: encrypted1.hash,
335
-
},
335
+
contentHash: { $bytes: encrypted1.hash },
336
+
} as AppCisternLexiconItem.Main,
336
337
},
337
338
],
338
339
cursor: "next-page",
···
348
349
value: {
349
350
$type: "app.cistern.lexicon.item",
350
351
tid: tid2,
351
-
ciphertext: encrypted2.cipherText,
352
-
nonce: encrypted2.nonce,
352
+
ciphertext: { $bytes: encrypted2.cipherText },
353
+
nonce: { $bytes: encrypted2.nonce },
353
354
algorithm: "x_wing-xchacha20_poly1305-sha3_512",
354
355
pubkey:
355
356
"at://did:plc:test/app.cistern.lexicon.pubkey/key1",
356
-
payload: encrypted2.content,
357
+
payload: { $bytes: encrypted2.content },
357
358
contentLength: encrypted2.length,
358
-
contentHash: encrypted2.hash,
359
-
},
359
+
contentHash: { $bytes: encrypted2.hash },
360
+
} as AppCisternLexiconItem.Main,
360
361
},
361
362
],
362
363
cursor: undefined,
+9
-9
packages/consumer/mod.ts
+9
-9
packages/consumer/mod.ts
···
62
62
$type: "app.cistern.lexicon.pubkey",
63
63
name,
64
64
algorithm: "x_wing",
65
-
content: keys.publicKey.toBase64(),
65
+
content: { $bytes: keys.publicKey.toBase64() },
66
66
createdAt: new Date().toISOString(),
67
67
};
68
68
const res = await this.rpc.post("com.atproto.repo.createRecord", {
···
126
126
if (item.pubkey !== this.keypair.publicKey) continue;
127
127
128
128
const decrypted = decryptText(this.keypair.privateKey, {
129
-
nonce: item.nonce,
130
-
cipherText: item.ciphertext,
131
-
content: item.payload,
132
-
hash: item.contentHash,
129
+
nonce: item.nonce.$bytes,
130
+
cipherText: item.ciphertext.$bytes,
131
+
content: item.payload.$bytes,
132
+
hash: item.contentHash.$bytes,
133
133
length: item.contentLength,
134
134
});
135
135
···
175
175
}
176
176
177
177
const decrypted = decryptText(this.keypair.privateKey, {
178
-
nonce: record.nonce,
179
-
cipherText: record.ciphertext,
180
-
content: record.payload,
181
-
hash: record.contentHash,
178
+
nonce: record.nonce.$bytes,
179
+
cipherText: record.ciphertext.$bytes,
180
+
content: record.payload.$bytes,
181
+
hash: record.contentHash.$bytes,
182
182
length: record.contentLength,
183
183
});
184
184
+8
-10
packages/lexicon/lexicons/app/cistern/lexicon/item.json
+8
-10
packages/lexicon/lexicons/app/cistern/lexicon/item.json
···
25
25
"format": "tid"
26
26
},
27
27
"ciphertext": {
28
-
"type": "string",
29
-
"description": "Encapsulated shared ciphertext",
30
-
"maxLength": 2000
28
+
"type": "bytes",
29
+
"description": "Encapsulated shared ciphertext"
31
30
},
32
31
"nonce": {
33
-
"type": "string",
34
-
"description": "Base64-encoded nonce used for content encryption",
35
-
"maxLength": 32
32
+
"type": "bytes",
33
+
"description": "Nonce used for content encryption"
36
34
},
37
35
"algorithm": {
38
36
"type": "string",
···
45
43
"format": "at-uri"
46
44
},
47
45
"payload": {
48
-
"type": "string",
49
-
"description": "Base64-encoded encrypted item contents"
46
+
"type": "bytes",
47
+
"description": "Encrypted item contents"
50
48
},
51
49
"contentLength": {
52
50
"type": "integer",
53
51
"description": "Original content length in bytes"
54
52
},
55
53
"contentHash": {
56
-
"type": "string",
57
-
"description": "Base64-encoded hash of the decrypted contents. Verify this before accepting the decrypted message. The algorithm is identified under `algorithm`"
54
+
"type": "bytes",
55
+
"description": "Hash of the decrypted contents. Verify this before accepting the decrypted message. The algorithm is identified under `algorithm`"
58
56
}
59
57
}
60
58
}
+2
-2
packages/lexicon/lexicons/app/cistern/lexicon/pubkey.json
+2
-2
packages/lexicon/lexicons/app/cistern/lexicon/pubkey.json
···
21
21
"description": "KEM algorithm used to generate this key"
22
22
},
23
23
"content": {
24
-
"type": "string",
25
-
"description": "Contents of the public key, encoded in base64"
24
+
"type": "bytes",
25
+
"description": "Contents of the public key"
26
26
},
27
27
"createdAt": {
28
28
"type": "string",
+7
-13
packages/lexicon/src/types/app/cistern/lexicon/item.ts
+7
-13
packages/lexicon/src/types/app/cistern/lexicon/item.ts
···
14
14
>(),
15
15
/**
16
16
* Encapsulated shared ciphertext
17
-
* @maxLength 2000
18
17
*/
19
-
ciphertext: /*#__PURE__*/ v.constrain(/*#__PURE__*/ v.string(), [
20
-
/*#__PURE__*/ v.stringLength(0, 2000),
21
-
]),
18
+
ciphertext: /*#__PURE__*/ v.bytes(),
22
19
/**
23
-
* Base64-encoded hash of the decrypted contents. Verify this before accepting the decrypted message. The algorithm is identified under `algorithm`
20
+
* Hash of the decrypted contents. Verify this before accepting the decrypted message. The algorithm is identified under `algorithm`
24
21
*/
25
-
contentHash: /*#__PURE__*/ v.string(),
22
+
contentHash: /*#__PURE__*/ v.bytes(),
26
23
/**
27
24
* Original content length in bytes
28
25
*/
29
26
contentLength: /*#__PURE__*/ v.integer(),
30
27
/**
31
-
* Base64-encoded nonce used for content encryption
32
-
* @maxLength 32
28
+
* Nonce used for content encryption
33
29
*/
34
-
nonce: /*#__PURE__*/ v.constrain(/*#__PURE__*/ v.string(), [
35
-
/*#__PURE__*/ v.stringLength(0, 32),
36
-
]),
30
+
nonce: /*#__PURE__*/ v.bytes(),
37
31
/**
38
-
* Base64-encoded encrypted item contents
32
+
* Encrypted item contents
39
33
*/
40
-
payload: /*#__PURE__*/ v.string(),
34
+
payload: /*#__PURE__*/ v.bytes(),
41
35
/**
42
36
* URI to the public key used to encrypt this item
43
37
*/
+2
-2
packages/lexicon/src/types/app/cistern/lexicon/pubkey.ts
+2
-2
packages/lexicon/src/types/app/cistern/lexicon/pubkey.ts
···
11
11
*/
12
12
algorithm: /*#__PURE__*/ v.string<"x_wing" | (string & {})>(),
13
13
/**
14
-
* Contents of the public key, encoded in base64
14
+
* Contents of the public key
15
15
*/
16
-
content: /*#__PURE__*/ v.string(),
16
+
content: /*#__PURE__*/ v.bytes(),
17
17
createdAt: /*#__PURE__*/ v.datetimeString(),
18
18
/**
19
19
* A memorable name for this public key. Avoid using revealing names, such as "Graham's Macbook"
+10
-9
packages/producer/mod.test.ts
+10
-9
packages/producer/mod.test.ts
···
4
4
import type { ProducerParams, PublicKeyOption } from "./types.ts";
5
5
import type { Client, CredentialManager } from "@atcute/client";
6
6
import type { Did, Handle, ResourceUri } from "@atcute/lexicons";
7
+
import type { AppCisternLexiconPubkey } from "@cistern/lexicon";
7
8
8
9
// Helper to create a mock Producer instance
9
10
function createMockProducer(
···
175
176
$type: "app.cistern.lexicon.pubkey",
176
177
name: "Key 1",
177
178
algorithm: "x_wing",
178
-
content: new Uint8Array(32).toBase64(),
179
+
content: { $bytes: new Uint8Array(32).toBase64() },
179
180
createdAt: new Date().toISOString(),
180
-
},
181
+
} as AppCisternLexiconPubkey.Main,
181
182
},
182
183
{
183
184
uri: "at://did:plc:test/app.cistern.lexicon.pubkey/key2",
···
185
186
$type: "app.cistern.lexicon.pubkey",
186
187
name: "Key 2",
187
188
algorithm: "x_wing",
188
-
content: new Uint8Array(32).toBase64(),
189
+
content: { $bytes: new Uint8Array(32).toBase64() },
189
190
createdAt: new Date().toISOString(),
190
-
},
191
+
} as AppCisternLexiconPubkey.Main,
191
192
},
192
193
],
193
194
cursor: undefined,
···
216
217
async fn() {
217
218
let callCount = 0;
218
219
const mockRpc = {
219
-
get: (endpoint: string, params?: { params?: { cursor?: string } }) => {
220
+
get: (endpoint: string, _params?: { params?: { cursor?: string } }) => {
220
221
if (endpoint === "com.atproto.repo.listRecords") {
221
222
callCount++;
222
223
···
231
232
$type: "app.cistern.lexicon.pubkey",
232
233
name: "Key 1",
233
234
algorithm: "x_wing",
234
-
content: new Uint8Array(32).toBase64(),
235
+
content: { $bytes: new Uint8Array(32).toBase64() },
235
236
createdAt: new Date().toISOString(),
236
-
},
237
+
} as AppCisternLexiconPubkey.Main,
237
238
},
238
239
],
239
240
cursor: "next-page",
···
250
251
$type: "app.cistern.lexicon.pubkey",
251
252
name: "Key 2",
252
253
algorithm: "x_wing",
253
-
content: new Uint8Array(32).toBase64(),
254
+
content: { $bytes: new Uint8Array(32).toBase64() },
254
255
createdAt: new Date().toISOString(),
255
-
},
256
+
} as AppCisternLexiconPubkey.Main,
256
257
},
257
258
],
258
259
cursor: undefined,
+6
-6
packages/producer/mod.ts
+6
-6
packages/producer/mod.ts
···
41
41
publicKey = {
42
42
uri: res.data.uri,
43
43
name: record.name,
44
-
content: record.content,
44
+
content: record.content.$bytes,
45
45
};
46
46
}
47
47
···
82
82
$type: "app.cistern.lexicon.item",
83
83
tid: now(),
84
84
algorithm: "x_wing-xchacha20_poly1305-sha3_512",
85
-
ciphertext: payload.cipherText,
86
-
contentHash: payload.hash,
85
+
ciphertext: { $bytes: payload.cipherText },
86
+
contentHash: { $bytes: payload.hash },
87
87
contentLength: payload.length,
88
-
nonce: payload.nonce,
89
-
payload: payload.content,
88
+
nonce: { $bytes: payload.nonce },
89
+
payload: { $bytes: payload.content },
90
90
pubkey: this.publicKey.uri,
91
91
};
92
92
···
139
139
140
140
yield {
141
141
uri: record.uri,
142
-
content: item.content,
142
+
content: item.content.$bytes,
143
143
name: item.name,
144
144
};
145
145
}