forked from
rocksky.app/rocksky
A decentralized music tracking and discovery platform built on AT Protocol 馃幍
1import chalk from "chalk";
2import { consola } from "consola";
3import { ctx } from "context";
4import type * as FeedGenerator from "lexicon/types/app/rocksky/feed/generator";
5import { createAgent } from "lib/agent";
6import prompts from "prompts";
7
8const args = process.argv.slice(2);
9
10if (args.length === 0) {
11 consola.error("Please provide user author identifier (handle or DID).");
12 console.log(`Usage: ${chalk.cyan("npm run feed -- <handle|did>")}`);
13 process.exit(1);
14}
15
16const name = await prompts({
17 type: "text",
18 name: "value",
19 message: "What is the feed name?",
20});
21
22if (name.value.length < 3 || name.value.length > 240) {
23 consola.error("Feed name must be between 3 and 240 characters.");
24 process.exit(1);
25}
26
27const description = await prompts({
28 type: "text",
29 name: "value",
30 message: "Please provide a short description of the feed",
31});
32
33if (description.value.length > 3000) {
34 consola.error("Description is too long. Maximum length is 3000 characters.");
35 process.exit(1);
36}
37
38const did = await prompts({
39 type: "text",
40 name: "value",
41 message: "What is the feed DID?",
42});
43
44if (!/^did:web:[a-zA-Z0-9_.-]{3,30}$/.test(did.value)) {
45 consola.error(
46 "Invalid DID format. It should start with 'did:web:' followed by 3 to 30 alphanumeric characters, underscores, hyphens, or periods.",
47 );
48 process.exit(1);
49}
50
51const rkey = await prompts({
52 type: "text",
53 name: "value",
54 message: "What is the record key (rkey) for the feed?",
55});
56
57if (!/^[a-zA-Z0-9_-]{3,30}$/.test(rkey.value)) {
58 consola.error(
59 "Invalid record key. Only alphanumeric characters, underscores, and hyphens are allowed. Length must be between 3 and 30 characters.",
60 );
61 process.exit(1);
62}
63
64consola.info("Creating feed with the following details:");
65consola.info("---");
66consola.info("Feed name:", name.value);
67consola.info("Description:", description.value);
68consola.info("DID:", did.value);
69consola.info("Record key (rkey):", rkey.value);
70
71const confirm = await prompts({
72 type: "confirm",
73 name: "value",
74 message: "Do you want to proceed?",
75 initial: true,
76});
77
78if (!confirm.value) {
79 consola.info("Feed creation cancelled.");
80 process.exit(0);
81}
82
83let userDid = args[0];
84
85if (!userDid.startsWith("did:plc:")) {
86 userDid = await ctx.baseIdResolver.handle.resolve(userDid);
87}
88
89const agent = await createAgent(ctx.oauthClient, userDid);
90
91consola.info(
92 `Writing ${chalk.greenBright("app.rocksky.feed.generator")} record...`,
93);
94
95const record: FeedGenerator.Record = {
96 $type: "app.rocksky.feed.generator",
97 displayName: name.value,
98 description: description.value,
99 did: did.value,
100 createdAt: new Date().toISOString(),
101};
102
103const res = await agent.com.atproto.repo.createRecord({
104 repo: agent.assertDid,
105 collection: "app.rocksky.feed.generator",
106 record,
107 rkey: rkey.value,
108});
109
110consola.info(chalk.greenBright("Feed created successfully!"));
111consola.info(`Record created at: ${chalk.cyan(res.data.uri)}`);
112
113process.exit(0);