137 lines
4.2 KiB
TypeScript
137 lines
4.2 KiB
TypeScript
// Manage webhook subscriptions on the Remanso API. Resolves your PDS from
|
|
// your AT Protocol handle, logs in with an app password, then registers or
|
|
// deletes webhooks against the Remanso API.
|
|
//
|
|
// deno task webhooks register --url https://your-receiver --verb bulk-create
|
|
// deno task webhooks delete-all
|
|
//
|
|
// Inputs (env or flag, env preferred):
|
|
// ATPROTO_HANDLE / --handle e.g. alice.eurosky.social
|
|
// ATPROTO_APP_PASSWORD / --app-password app password (NOT your account password)
|
|
// REMANSO_API / --api default: https://api.remanso.space
|
|
|
|
const HELP = `
|
|
Usage:
|
|
deno task webhooks register \\
|
|
--url <receiver-url> \\
|
|
[--verb create|delete|bulk-create] \\
|
|
[--method POST] \\
|
|
[--token <outbound-bearer>]
|
|
|
|
deno task webhooks list
|
|
|
|
deno task webhooks delete --id <id>
|
|
|
|
deno task webhooks delete-all
|
|
|
|
Inputs (env or flag, env preferred):
|
|
ATPROTO_HANDLE / --handle your AT Protocol handle
|
|
ATPROTO_APP_PASSWORD / --app-password app password (NOT your account password)
|
|
REMANSO_API / --api default: https://api.remanso.space
|
|
|
|
Your PDS is resolved automatically from the handle.
|
|
`;
|
|
|
|
import {
|
|
createSession,
|
|
parseArgs,
|
|
resolveDidToPds,
|
|
resolveHandleToDid,
|
|
} from "./_atproto-session.ts";
|
|
|
|
const die = (msg: string): never => {
|
|
console.error(`error: ${msg}`);
|
|
console.error(HELP);
|
|
Deno.exit(1);
|
|
};
|
|
|
|
const main = async () => {
|
|
const [command, ...rest] = Deno.args;
|
|
if (!command || command === "--help" || command === "-h") {
|
|
console.log(HELP);
|
|
Deno.exit(command ? 0 : 1);
|
|
}
|
|
|
|
const flags = parseArgs(rest);
|
|
const handle = flags.handle ?? Deno.env.get("ATPROTO_HANDLE");
|
|
const password = flags["app-password"] ??
|
|
Deno.env.get("ATPROTO_APP_PASSWORD");
|
|
const api = flags.api ?? Deno.env.get("REMANSO_API") ??
|
|
"https://api.remanso.space";
|
|
|
|
if (!handle) die("ATPROTO_HANDLE (or --handle) is required");
|
|
if (!password) die("ATPROTO_APP_PASSWORD (or --app-password) is required");
|
|
|
|
const did = await resolveHandleToDid(handle);
|
|
const pds = await resolveDidToPds(did);
|
|
console.log(`[resolve] ${handle} → ${did} via ${pds}`);
|
|
const session = await createSession(pds, handle, password);
|
|
|
|
if (command === "register") {
|
|
const url = flags.url ?? die("--url is required for register");
|
|
const body: Record<string, unknown> = {
|
|
method: flags.method ?? "POST",
|
|
url,
|
|
};
|
|
if (flags.verb) body.verb = flags.verb;
|
|
if (flags.token) body.token = flags.token;
|
|
const res = await fetch(`${api}/${session.did}/webhooks`, {
|
|
method: "POST",
|
|
headers: {
|
|
"Authorization": `Bearer ${session.accessJwt}`,
|
|
"Content-Type": "application/json",
|
|
},
|
|
body: JSON.stringify(body),
|
|
});
|
|
if (!res.ok) {
|
|
console.error(`register failed (${res.status}): ${await res.text()}`);
|
|
Deno.exit(1);
|
|
}
|
|
console.log(JSON.stringify(await res.json(), null, 2));
|
|
return;
|
|
}
|
|
|
|
if (command === "list") {
|
|
const res = await fetch(`${api}/${session.did}/webhooks`, {
|
|
headers: { "Authorization": `Bearer ${session.accessJwt}` },
|
|
});
|
|
if (!res.ok) {
|
|
console.error(`list failed (${res.status}): ${await res.text()}`);
|
|
Deno.exit(1);
|
|
}
|
|
console.log(JSON.stringify(await res.json(), null, 2));
|
|
return;
|
|
}
|
|
|
|
if (command === "delete") {
|
|
const id = flags.id ?? die("--id is required for delete");
|
|
const res = await fetch(`${api}/${session.did}/webhooks/${id}`, {
|
|
method: "DELETE",
|
|
headers: { "Authorization": `Bearer ${session.accessJwt}` },
|
|
});
|
|
if (!res.ok) {
|
|
console.error(`delete failed (${res.status}): ${await res.text()}`);
|
|
Deno.exit(1);
|
|
}
|
|
console.log(`[done] webhook ${id} deleted`);
|
|
return;
|
|
}
|
|
|
|
if (command === "delete-all") {
|
|
const res = await fetch(`${api}/${session.did}/webhooks`, {
|
|
method: "DELETE",
|
|
headers: { "Authorization": `Bearer ${session.accessJwt}` },
|
|
});
|
|
if (!res.ok) {
|
|
console.error(`delete failed (${res.status}): ${await res.text()}`);
|
|
Deno.exit(1);
|
|
}
|
|
console.log(`[done] all webhooks for ${session.did} deleted`);
|
|
return;
|
|
}
|
|
|
|
die(`unknown command: ${command}`);
|
|
};
|
|
|
|
await main();
|