From 6509a72c2df79c99b31ffdaee591a3fd54d04411 Mon Sep 17 00:00:00 2001 From: Graham Barber Date: Sun, 09 Nov 2025 18:36:43 +0000 Subject: [PATCH] feat(producer): stub module and interface --- deno.lock | 14 ++++++++++++++ packages/producer/deno.jsonc | 11 +++++++++++ packages/producer/mod.ts | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ packages/producer/types.ts | 15 +++++++++++++++ 4 file(s) changed, 119 insertion(s)(+), 0 deletion(s)(-) diff --git a/deno.lock b/deno.lock --- a/deno.lock +++ b/deno.lock @@ -10,6 +10,7 @@ "jsr:@std/assert@^1.0.14": "1.0.14", "jsr:@std/expect@^1.0.17": "1.0.17", "jsr:@std/internal@^1.0.10": "1.0.10", + "npm:@atcute/atproto@^3.1.9": "3.1.9", "npm:@atcute/client@^4.0.5": "4.0.5", "npm:@atcute/lex-cli@^2.3.1": "2.3.1", "npm:@atcute/lexicons@^1.2.2": "1.2.2", @@ -53,6 +54,12 @@ } }, "npm": { + "@atcute/atproto@3.1.9": { + "integrity": "sha512-DyWwHCTdR4hY2BPNbLXgVmm7lI+fceOwWbE4LXbGvbvVtSn+ejSVFaAv01Ra3kWDha0whsOmbJL8JP0QPpf1+w==", + "dependencies": [ + "@atcute/lexicons" + ] + }, "@atcute/client@4.0.5": { "integrity": "sha512-R8Qen8goGmEkynYGg2m6XFlVmz0GTDvQ+9w+4QqOob+XMk8/WDpF4aImev7WKEde/rV2gjcqW7zM8E6W9NShDA==", "dependencies": [ @@ -179,6 +186,13 @@ "npm:@atcute/lex-cli@^2.3.1", "npm:@atcute/lexicons@^1.2.2", "npm:@atproto/lexicon@~0.5.1" + ] + }, + "packages/producer": { + "dependencies": [ + "npm:@atcute/atproto@^3.1.9", + "npm:@atcute/client@^4.0.5", + "npm:@atcute/lexicons@^1.2.2" ] }, "packages/shared": { diff --git a/packages/producer/deno.jsonc b/packages/producer/deno.jsonc new file mode 100644 --- /dev/null +++ b/packages/producer/deno.jsonc @@ -0,0 +1,11 @@ +{ + "name": "@cistern/producer", + "exports": { + ".": "./mod.ts" + }, + "imports": { + "@atcute/atproto": "npm:@atcute/atproto@^3.1.9", + "@atcute/client": "npm:@atcute/client@^4.0.5", + "@atcute/lexicons": "npm:@atcute/lexicons@^1.2.2" + } +} diff --git a/packages/producer/mod.ts b/packages/producer/mod.ts new file mode 100644 --- /dev/null +++ b/packages/producer/mod.ts @@ -0,0 +1,79 @@ +import { produceRequirements } from "@cistern/shared"; +import type { + LocalPublicKey, + ProducerOptions, + ProducerParams, +} from "./types.ts"; +import { type Did, is } from "@atcute/lexicons"; +import type { Client, CredentialManager } from "@atcute/client"; +import { AppCisternLexiconPubkey } from "@cistern/lexicon"; + +import type {} from "@atcute/atproto"; + +export async function createProducer( + { publicKey, ...opts }: ProducerOptions, +): Promise { + const reqs = await produceRequirements(opts); + + let record: AppCisternLexiconPubkey.Main | undefined; + if (typeof publicKey === "string") { + // Fetch record contents from PDS + const res = await reqs.rpc.get("com.atproto.repo.getRecord", { + params: { + repo: reqs.miniDoc.did, + rkey: publicKey, + collection: "app.cistern.lexicon.pubkey", + }, + }); + + if (!res.ok) { + throw new Error( + `invalid public key record ID ${publicKey}, got: ${res.status} ${res.data.error}`, + ); + } + + record = res.data.value as AppCisternLexiconPubkey.Main; + } else if (is(AppCisternLexiconPubkey.mainSchema, publicKey)) { + record = publicKey; + } else if (publicKey) { + throw new Error( + "provided public key does not validate against lexicon schema", + ); + } + + return new Producer({ ...reqs, options: { ...opts, publicKey: record } }); +} + +export class Producer { + did: Did; + rpc: Client; + manager: CredentialManager; + publicKey?: LocalPublicKey; + + constructor(params: ProducerParams) { + this.did = params.miniDoc.did; + this.rpc = params.rpc; + this.manager = params.manager; + this.publicKey = params.options.publicKey; + } + + /** + * Creates an item and saves it as a record in the user's PDS + * @todo Error if there is no selected public key + * @todo Construct valid item + * @todo Save item to PDS + */ + async createItem() {} + + /** + * Lists public keys registered in the user's PDS + * @todo List public keys + */ + async listPublicKeys() {} + + /** + * Sets a public key as the main encryption key + * @todo Replace local key with provided key + */ + selectPublicKey() {} +} diff --git a/packages/producer/types.ts b/packages/producer/types.ts new file mode 100644 --- /dev/null +++ b/packages/producer/types.ts @@ -0,0 +1,15 @@ +import type { BaseClientOptions, ClientRequirements } from "@cistern/shared"; +import type { AppCisternLexiconPubkey } from "@cistern/lexicon"; +import type { RecordKey } from "@atcute/lexicons"; + +export type LocalPublicKey = AppCisternLexiconPubkey.Main; + +export interface ProducerOptions extends BaseClientOptions { + publicKey?: RecordKey | LocalPublicKey; +} + +export type ProducerParams = ClientRequirements & { + options: { + publicKey?: AppCisternLexiconPubkey.Main; + }; +}; -- tangled.sh