Something went wrong. Try again.
Monorepo for Tangled tangled.org
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119import type { Did } from "@atcute/lexicons/syntax";import type { OAuthUserAgent } from "@atcute/oauth-browser-client";import { getOrCreateDelegatedSession } from "#lib/api/actAs.ts";import type { BobbinContext } from "#lib/api/client.ts";import { organizationRole, type OrganizationRole } from "#lib/api/organizations.ts";import { collect } from "#lib/api/pagination.ts";import { getRepoByRepoDid } from "#lib/api/records.ts";import { addCollaborator, removeCollaborator } from "#lib/api/repoSettings.ts";import { didOf } from "#lib/api/syntax.ts";import { didFromUri } from "#lib/api/uri.ts";import { addController, getScopePresets, listControllers, removeController} from "#lib/api/tranquil.ts";
export interface OrganizationMember { did: Did; handle?: string; role: OrganizationRole; grantedAt: string;}
export const listOrganizationMembers = async ( controllerAgent: OAuthUserAgent, orgDid: Did): Promise<OrganizationMember[]> => { const orgAgent = await getOrCreateDelegatedSession(controllerAgent, orgDid); const controllers = await listControllers(orgAgent); return controllers .filter((controller) => controller.isActive) .map((controller) => ({ did: controller.did, handle: controller.handle, role: organizationRole(controller.grantedScopes), grantedAt: controller.grantedAt }));};
export const inviteOrganizationMembers = async ( controllerAgent: OAuthUserAgent, orgDid: Did, dids: readonly Did[]): Promise<void> => { const orgAgent = await getOrCreateDelegatedSession(controllerAgent, orgDid); const editor = (await getScopePresets(orgAgent)).find((preset) => preset.name === "editor"); if (!editor) throw new Error("The organization's PDS does not offer an editor role."); for (const did of dids) { await addController(orgAgent, { controllerDid: did, grantedScopes: editor.scopes }); }};
export interface MemberCollaboration { repoDid: Did; name: string; knot: string;}
export const listMemberCollaborations = async ( ctx: BobbinContext, orgDid: Did, memberDid: Did): Promise<MemberCollaboration[]> => { const repos = await collect(ctx, "org.tangled.repo.listRepos", { subject: orgDid, limit: 100 }); const found = await Promise.all( repos.map(async (item): Promise<MemberCollaboration | null> => { const repoDid = didOf(didFromUri(item.uri)); const collaborators = await collect(ctx, "org.tangled.repo.listCollaborators", { subject: repoDid, limit: 100 }); if (!collaborators.some((collaborator) => collaborator.subject === memberDid)) return null; const repo = await getRepoByRepoDid(ctx, repoDid); if (!repo.knot) return null; return { repoDid, name: repo.value.declaration.name, knot: repo.knot }; }) ); return found.filter((collaboration) => collaboration !== null);};
// remove the member first, then each grant; a failed grant comes back to the callerexport const removeOrganizationMember = async ( controllerAgent: OAuthUserAgent, orgDid: Did, memberDid: Did, collaborations: readonly MemberCollaboration[] = []): Promise<MemberCollaboration[]> => { const orgAgent = await getOrCreateDelegatedSession(controllerAgent, orgDid); await removeController(orgAgent, memberDid); const failed: MemberCollaboration[] = []; for (const collaboration of collaborations) { await removeCollaborator( orgAgent, collaboration.knot, collaboration.repoDid, memberDid ).catch(() => failed.push(collaboration)); } return failed;};
export const addMembersAsCollaborators = async ( orgAgent: OAuthUserAgent, knot: string, repoDid: Did): Promise<void> => { const controllers = await listControllers(orgAgent); const results = await Promise.allSettled( controllers .filter((controller) => controller.isActive && controller.did !== orgAgent.sub) .map((controller) => addCollaborator(orgAgent, knot, repoDid, controller.did)) ); const failed = results.filter((result) => result.status === "rejected").length; if (failed > 0) throw new Error(`Could not add ${failed} organization member(s) as collaborators.`);};