This repository has no description
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2026 sol pbc
3
4import { TID } from '@atproto/common-web';
5import { CAP_COLLECTION } from './constants.js';
6import { resolveRef } from './cap-ref.js';
7
8export async function publishCap(agent, input) {
9 if (input.repo == null || input.repo !== agent.did) {
10 throw new Error('write target must match authenticated agent');
11 }
12 if (input.swapCid != null && input.rkey == null) {
13 throw new Error('swap CID requires an rkey');
14 }
15 if (input.reply) {
16 const { root, parent } = input.reply;
17 if (
18 !root
19 || !parent
20 || typeof root.uri !== 'string'
21 || typeof root.cid !== 'string'
22 || typeof parent.uri !== 'string'
23 || typeof parent.cid !== 'string'
24 ) {
25 throw new Error('reply must include valid root and parent references');
26 }
27 }
28 if (input.embed) {
29 const external = input.embed.external;
30 if (
31 !external
32 || typeof external.uri !== 'string'
33 || typeof external.title !== 'string'
34 || typeof external.description !== 'string'
35 ) {
36 throw new Error('embed must include a valid external value');
37 }
38 }
39
40 const record = {
41 $type: CAP_COLLECTION,
42 text: input.text || '',
43 title: input.title,
44 description: input.description,
45 ref: input.ref,
46 createdAt: input.createdAt,
47 };
48 if (input.beacon) record.beacon = input.beacon;
49 if (input.kind) record.kind = input.kind;
50 if (input.recap) record.recap = input.recap;
51 if (input.reply) record.reply = input.reply;
52 if (input.embed) record.embed = input.embed;
53
54 const rkey = input.rkey ?? TID.nextStr();
55 const putArgs = {
56 repo: input.repo,
57 collection: CAP_COLLECTION,
58 rkey,
59 record,
60 validate: false,
61 };
62 if (input.swapCid != null) putArgs.swapRecord = input.swapCid;
63
64 const putRes = await agent.com.atproto.repo.putRecord(putArgs);
65 return {
66 uri: putRes.data.uri,
67 cid: putRes.data.cid,
68 ref: resolveRef(record, putRes.data.cid),
69 rkey,
70 record,
71 response: putRes.data,
72 };
73}