// OAuth scope for logged-in writes. The PDS enforces granular repo scopes with ?action=, // so we request exactly the actions we use. Shared by the browser client (dev loopback) // and the hosted /client-metadata.json (production). // // Two tiers, granted incrementally: // BASE first sign-in asks for this only: `atproto` plus the community-membership record. // Signing in makes you a member and nothing more, so the first consent screen is small. // FULL everything else (like / repost / follow / RSVP / post / feed preferences). Requested // once, via step-up, the first time a member does one of those (see lib/auth-step-up.ts). // A superset of BASE, so the single re-consent covers every action from then on. // // client-metadata.json (and the dev loopback client_id) declare FULL as the maximum the client // may ever request; an individual sign-in can request any subset, which is how BASE-then-FULL works. // Community membership: a self-asserted `eu.atcommons.member` record on the user's own PDS. // `update` is needed because the record's `countries[]` accumulates (joining a second country // adds to the list); `delete` backs "Leave". No `nl.atproto.member` scope — that namespace is // abandoned, not migrated. const MEMBERSHIP_SCOPE = [ 'repo:eu.atcommons.member?action=create', 'repo:eu.atcommons.member?action=update', 'repo:eu.atcommons.member?action=delete', ]; // Everything beyond membership: the actions a signed-in member takes on posts and events. const ACTIVITY_SCOPE = [ 'repo:app.bsky.feed.like?action=create', 'repo:app.bsky.feed.like?action=delete', 'repo:app.bsky.feed.repost?action=create', 'repo:app.bsky.feed.repost?action=delete', 'repo:app.bsky.graph.follow?action=create', 'repo:app.bsky.graph.follow?action=delete', // Feed subscribe = saved-feeds preferences (stored on the PDS via get/putPreferences). // If a PDS does not grant these, native subscribe fails and we fall back to the deeplink. 'rpc:app.bsky.actor.getPreferences?aud=*', 'rpc:app.bsky.actor.putPreferences?aud=*', 'repo:app.bsky.feed.post?action=create', 'repo:community.lexicon.calendar.rsvp?action=create', 'repo:community.lexicon.calendar.rsvp?action=delete', ]; /** Tier 1 — requested at first sign-in. Just enough to record community membership. */ export const OAUTH_SCOPE_BASE = ['atproto', ...MEMBERSHIP_SCOPE].join(' '); /** Tier 2 — the full set, requested once via step-up. Superset of BASE. */ export const OAUTH_SCOPE_FULL = ['atproto', ...ACTIVITY_SCOPE, ...MEMBERSHIP_SCOPE].join(' '); /** The maximum scope the client may request (declared in client-metadata + loopback client_id). */ export const OAUTH_SCOPE = OAUTH_SCOPE_FULL; /** A FULL-only scope atom. Its presence in a session's granted scope means step-up has happened * and the member can already like / repost / follow / RSVP / post. */ export const STEP_UP_MARKER = 'repo:app.bsky.feed.like?action=create';