chore: version bump and clean up c1c21ad5
Steve · 2026-02-26 19:40 6 file(s) · +17 −96
packages/cli/biome.json +1 −1
2 2
	"$schema": "https://biomejs.dev/schemas/2.3.13/schema.json",
3 3
	"extends": ["../../biome.json"],
4 4
	"files": {
5 -
		"includes": ["**", "!!**/dist"]
5 +
		"includes": ["!!**/dist"]
6 6
	}
7 7
}
packages/cli/package.json +1 −1
1 1
{
2 2
	"name": "sequoia-cli",
3 -
	"version": "0.4.0",
3 +
	"version": "0.5.0",
4 4
	"type": "module",
5 5
	"bin": {
6 6
		"sequoia": "dist/index.js"
packages/cli/src/commands/add.ts +3 −1
40 40
		intro("Add Sequoia Component");
41 41
42 42
		// Validate component name
43 -
		const component = AVAILABLE_COMPONENTS.find((c) => c.name === componentName);
43 +
		const component = AVAILABLE_COMPONENTS.find(
44 +
			(c) => c.name === componentName,
45 +
		);
44 46
		if (!component) {
45 47
			log.error(`Component '${componentName}' not found`);
46 48
			log.info("Available components:");
packages/cli/src/components/sequoia-subscribe.js +1 −86
127 127
// ============================================================================
128 128
129 129
/**
130 -
 * Resolve a DID to its PDS URL.
131 -
 * Supports did:plc and did:web methods.
132 -
 * @param {string} did - Decentralized Identifier
133 -
 * @returns {Promise<string>} PDS URL
134 -
 */
135 -
async function resolvePDS(did) {
136 -
	let pdsUrl;
137 -
138 -
	if (did.startsWith("did:plc:")) {
139 -
		const didDocUrl = `https://plc.directory/${did}`;
140 -
		const didDocResponse = await fetch(didDocUrl);
141 -
		if (!didDocResponse.ok) {
142 -
			throw new Error(`Could not fetch DID document: ${didDocResponse.status}`);
143 -
		}
144 -
		const didDoc = await didDocResponse.json();
145 -
146 -
		const pdsService = didDoc.service?.find(
147 -
			(s) => s.id === "#atproto_pds" || s.type === "AtprotoPersonalDataServer",
148 -
		);
149 -
		pdsUrl = pdsService?.serviceEndpoint;
150 -
	} else if (did.startsWith("did:web:")) {
151 -
		const domain = did.replace("did:web:", "");
152 -
		const didDocUrl = `https://${domain}/.well-known/did.json`;
153 -
		const didDocResponse = await fetch(didDocUrl);
154 -
		if (!didDocResponse.ok) {
155 -
			throw new Error(`Could not fetch DID document: ${didDocResponse.status}`);
156 -
		}
157 -
		const didDoc = await didDocResponse.json();
158 -
159 -
		const pdsService = didDoc.service?.find(
160 -
			(s) => s.id === "#atproto_pds" || s.type === "AtprotoPersonalDataServer",
161 -
		);
162 -
		pdsUrl = pdsService?.serviceEndpoint;
163 -
	} else {
164 -
		throw new Error(`Unsupported DID method: ${did}`);
165 -
	}
166 -
167 -
	if (!pdsUrl) {
168 -
		throw new Error("Could not find PDS URL for user");
169 -
	}
170 -
171 -
	return pdsUrl;
172 -
}
173 -
174 -
/**
175 -
 * Create a site.standard.graph.subscription record in the subscriber's PDS.
176 -
 * @param {string} did - DID of the subscriber
177 -
 * @param {string} accessToken - AT Protocol access token
178 -
 * @param {string} publicationUri - AT URI of the publication to subscribe to
179 -
 * @returns {Promise<{uri: string, cid: string}>} The created record's URI and CID
180 -
 */
181 -
async function createRecord(did, accessToken, publicationUri) {
182 -
	const pdsUrl = await resolvePDS(did);
183 -
184 -
	const collection = "site.standard.graph.subscription";
185 -
	const url = `${pdsUrl}/xrpc/com.atproto.repo.createRecord`;
186 -
	const response = await fetch(url, {
187 -
		method: "POST",
188 -
		headers: {
189 -
			"Content-Type": "application/json",
190 -
			Authorization: `Bearer ${accessToken}`,
191 -
		},
192 -
		body: JSON.stringify({
193 -
			repo: did,
194 -
			collection,
195 -
			record: {
196 -
				$type: "site.standard.graph.subscription",
197 -
				publication: publicationUri,
198 -
			},
199 -
		}),
200 -
	});
201 -
202 -
	if (!response.ok) {
203 -
		const body = await response.json().catch(() => ({}));
204 -
		const message = body?.message ?? body?.error ?? `HTTP ${response.status}`;
205 -
		throw new Error(`Failed to create record: ${message}`);
206 -
	}
207 -
208 -
	const data = await response.json();
209 -
	return { uri: data.uri, cid: data.cid };
210 -
}
211 -
212 -
/**
213 130
 * Fetch the publication AT URI from the host site's well-known endpoint.
214 131
 * @param {string} [origin] - Origin to fetch from (defaults to current page origin)
215 132
 * @returns {Promise<string>} Publication AT URI
219 136
	const url = `${base}/.well-known/site.standard.publication`;
220 137
	const response = await fetch(url);
221 138
	if (!response.ok) {
222 -
		throw new Error(
223 -
			`Could not fetch publication URI: ${response.status}`,
224 -
		);
139 +
		throw new Error(`Could not fetch publication URI: ${response.status}`);
225 140
	}
226 141
227 142
	// Accept either plain text (the AT URI itself) or JSON with a `uri` field.
packages/cli/src/index.ts +1 −1
36 36
37 37
> https://tangled.org/stevedylan.dev/sequoia
38 38
	`,
39 -
	version: "0.4.0",
39 +
	version: "0.5.0",
40 40
	cmds: {
41 41
		add: addCommand,
42 42
		auth: authCommand,
packages/cli/src/lib/atproto.ts +10 −6
622 622
	agent: Agent,
623 623
	options: CreateBlueskyPostOptions,
624 624
): Promise<StrongRef> {
625 -
	const { title, description, bskyPost, canonicalUrl, coverImage, publishedAt } = options;
625 +
	const {
626 +
		title,
627 +
		description,
628 +
		bskyPost,
629 +
		canonicalUrl,
630 +
		coverImage,
631 +
		publishedAt,
632 +
	} = options;
626 633
627 634
	// Build post text: title + description
628 635
	// Max 300 graphemes for Bluesky posts
633 640
	if (bskyPost) {
634 641
		// Custom bsky post overrides any default behavior
635 642
		postText = bskyPost;
636 -
	}
637 -
	else if (description) {
643 +
	} else if (description) {
638 644
		// Try: title + description
639 645
		const fullText = `${title}\n\n${description}`;
640 646
		if (countGraphemes(fullText) <= MAX_GRAPHEMES) {
642 648
		} else {
643 649
			// Truncate description to fit
644 650
			const availableForDesc =
645 -
				MAX_GRAPHEMES -
646 -
				countGraphemes(title) -
647 -
				countGraphemes("\n\n");
651 +
				MAX_GRAPHEMES - countGraphemes(title) - countGraphemes("\n\n");
648 652
			if (availableForDesc > 10) {
649 653
				const truncatedDesc = truncateToGraphemes(
650 654
					description,