Encrypted, ephemeral, private memos on atproto

feat(producer): stub module and interface

graham.systems 6509a72c 13407fbd

verified
Changed files
+119
packages
+14
deno.lock
··· 10 10 "jsr:@std/assert@^1.0.14": "1.0.14", 11 11 "jsr:@std/expect@^1.0.17": "1.0.17", 12 12 "jsr:@std/internal@^1.0.10": "1.0.10", 13 + "npm:@atcute/atproto@^3.1.9": "3.1.9", 13 14 "npm:@atcute/client@^4.0.5": "4.0.5", 14 15 "npm:@atcute/lex-cli@^2.3.1": "2.3.1", 15 16 "npm:@atcute/lexicons@^1.2.2": "1.2.2", ··· 53 54 } 54 55 }, 55 56 "npm": { 57 + "@atcute/atproto@3.1.9": { 58 + "integrity": "sha512-DyWwHCTdR4hY2BPNbLXgVmm7lI+fceOwWbE4LXbGvbvVtSn+ejSVFaAv01Ra3kWDha0whsOmbJL8JP0QPpf1+w==", 59 + "dependencies": [ 60 + "@atcute/lexicons" 61 + ] 62 + }, 56 63 "@atcute/client@4.0.5": { 57 64 "integrity": "sha512-R8Qen8goGmEkynYGg2m6XFlVmz0GTDvQ+9w+4QqOob+XMk8/WDpF4aImev7WKEde/rV2gjcqW7zM8E6W9NShDA==", 58 65 "dependencies": [ ··· 179 186 "npm:@atcute/lex-cli@^2.3.1", 180 187 "npm:@atcute/lexicons@^1.2.2", 181 188 "npm:@atproto/lexicon@~0.5.1" 189 + ] 190 + }, 191 + "packages/producer": { 192 + "dependencies": [ 193 + "npm:@atcute/atproto@^3.1.9", 194 + "npm:@atcute/client@^4.0.5", 195 + "npm:@atcute/lexicons@^1.2.2" 182 196 ] 183 197 }, 184 198 "packages/shared": {
+11
packages/producer/deno.jsonc
··· 1 + { 2 + "name": "@cistern/producer", 3 + "exports": { 4 + ".": "./mod.ts" 5 + }, 6 + "imports": { 7 + "@atcute/atproto": "npm:@atcute/atproto@^3.1.9", 8 + "@atcute/client": "npm:@atcute/client@^4.0.5", 9 + "@atcute/lexicons": "npm:@atcute/lexicons@^1.2.2" 10 + } 11 + }
+79
packages/producer/mod.ts
··· 1 + import { produceRequirements } from "@cistern/shared"; 2 + import type { 3 + LocalPublicKey, 4 + ProducerOptions, 5 + ProducerParams, 6 + } from "./types.ts"; 7 + import { type Did, is } from "@atcute/lexicons"; 8 + import type { Client, CredentialManager } from "@atcute/client"; 9 + import { AppCisternLexiconPubkey } from "@cistern/lexicon"; 10 + 11 + import type {} from "@atcute/atproto"; 12 + 13 + export async function createProducer( 14 + { publicKey, ...opts }: ProducerOptions, 15 + ): Promise<Producer> { 16 + const reqs = await produceRequirements(opts); 17 + 18 + let record: AppCisternLexiconPubkey.Main | undefined; 19 + if (typeof publicKey === "string") { 20 + // Fetch record contents from PDS 21 + const res = await reqs.rpc.get("com.atproto.repo.getRecord", { 22 + params: { 23 + repo: reqs.miniDoc.did, 24 + rkey: publicKey, 25 + collection: "app.cistern.lexicon.pubkey", 26 + }, 27 + }); 28 + 29 + if (!res.ok) { 30 + throw new Error( 31 + `invalid public key record ID ${publicKey}, got: ${res.status} ${res.data.error}`, 32 + ); 33 + } 34 + 35 + record = res.data.value as AppCisternLexiconPubkey.Main; 36 + } else if (is(AppCisternLexiconPubkey.mainSchema, publicKey)) { 37 + record = publicKey; 38 + } else if (publicKey) { 39 + throw new Error( 40 + "provided public key does not validate against lexicon schema", 41 + ); 42 + } 43 + 44 + return new Producer({ ...reqs, options: { ...opts, publicKey: record } }); 45 + } 46 + 47 + export class Producer { 48 + did: Did; 49 + rpc: Client; 50 + manager: CredentialManager; 51 + publicKey?: LocalPublicKey; 52 + 53 + constructor(params: ProducerParams) { 54 + this.did = params.miniDoc.did; 55 + this.rpc = params.rpc; 56 + this.manager = params.manager; 57 + this.publicKey = params.options.publicKey; 58 + } 59 + 60 + /** 61 + * Creates an item and saves it as a record in the user's PDS 62 + * @todo Error if there is no selected public key 63 + * @todo Construct valid item 64 + * @todo Save item to PDS 65 + */ 66 + async createItem() {} 67 + 68 + /** 69 + * Lists public keys registered in the user's PDS 70 + * @todo List public keys 71 + */ 72 + async listPublicKeys() {} 73 + 74 + /** 75 + * Sets a public key as the main encryption key 76 + * @todo Replace local key with provided key 77 + */ 78 + selectPublicKey() {} 79 + }
+15
packages/producer/types.ts
··· 1 + import type { BaseClientOptions, ClientRequirements } from "@cistern/shared"; 2 + import type { AppCisternLexiconPubkey } from "@cistern/lexicon"; 3 + import type { RecordKey } from "@atcute/lexicons"; 4 + 5 + export type LocalPublicKey = AppCisternLexiconPubkey.Main; 6 + 7 + export interface ProducerOptions extends BaseClientOptions { 8 + publicKey?: RecordKey | LocalPublicKey; 9 + } 10 + 11 + export type ProducerParams = ClientRequirements<ProducerOptions> & { 12 + options: { 13 + publicKey?: AppCisternLexiconPubkey.Main; 14 + }; 15 + };