Something went wrong. Try again.
Monorepo for Tangled tangled.org
Something went wrong. Try again.
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495import { ClientResponseError } from "@atcute/client";import * as v from "@atcute/lexicons/validations";import type { OAuthUserAgent } from "@atcute/oauth-browser-client";import { hostForServiceDid, mintServiceAuth } from "$lib/auth/agent";import { buildUrl, toResponseError } from "$lib/api/_request";import { CREATE_DELEGATE_NSID, LIST_DELEGATES_ENDPOINT, LIST_DELEGATES_NSID, listDelegatesSchema} from "$lib/api/tranquil";
export { CREATE_DELEGATE_NSID, LIST_DELEGATES_NSID };
// The gate mints its own response, distinct from Tranquil's createAccount output.const createdDelegateSchema = v.object({ controllerDid: v.didString(), did: v.didString(), handle: v.handleString()});
export type CreatedDelegate = v.InferInput<typeof createdDelegateSchema>;
export const GATE_CREATE_DELEGATE_NSID = "sh.tangled.delegation.createAccount";
export interface DelegationService { serviceUrl: string; serviceDid?: string; fetch?: typeof globalThis.fetch;}
export const provisionDelegate = async ( agent: OAuthUserAgent, handle: string, service: DelegationService): Promise<CreatedDelegate> => { if (!service.serviceUrl || !service.serviceDid) throw new Error("Organization creation is not configured."); let token: string; try { token = await mintServiceAuth(agent, { aud: service.serviceDid, lxm: CREATE_DELEGATE_NSID }); } catch (cause) { if (cause instanceof ClientResponseError && cause.status === 403) { throw new Error("Sign in again to grant Tangled permission to create organizations.", { cause }); } throw cause; } const response = await (service.fetch ?? globalThis.fetch)( buildUrl(service.serviceUrl, GATE_CREATE_DELEGATE_NSID), { method: "POST", headers: { "content-type": "application/json", authorization: `Bearer ${token}` }, body: JSON.stringify({ handle }) } ); if (!response.ok) { const error = await toResponseError(response); const messages: Record<string, string> = { VerifiedEmailRequired: "Verify an email address in Settings → Emails before creating an organization.", // Tranquil enforces the per-controller delegate cap and reports it as // InvalidDelegation; the gate relays Tranquil's error code and message. InvalidDelegation: "You have reached the limit on organizations you can create.", UpstreamUnavailable: "Organization creation is temporarily unavailable. Please try again later." }; throw new Error(messages[error.error] ?? error.message); } const account = v.parse(createdDelegateSchema, await response.json()); if (account.controllerDid !== agent.sub) throw new Error("The organization was assigned to an unexpected owner."); return account;};
// Remote controllers mint this token on their own PDS and list on Tranquil.export const listDelegatedAccounts = async ( agent: OAuthUserAgent, serviceDid: string, fetch: typeof globalThis.fetch = globalThis.fetch) => { const host = hostForServiceDid(serviceDid); if (!host) throw new Error("Organization accounts are not configured."); const token = await mintServiceAuth(agent, { aud: serviceDid, lxm: LIST_DELEGATES_NSID }); const response = await fetch(buildUrl(`https://${host}`, LIST_DELEGATES_ENDPOINT), { headers: { authorization: `Bearer ${token}` } }); if (!response.ok) throw await toResponseError(response); return v.parse(listDelegatesSchema, await response.json()).accounts;};