Spaces:
Sleeping
Sleeping
| // --------------------------------------------------------------------------- | |
| // OAuth 2.1 scope definitions for TREK MCP | |
| // --------------------------------------------------------------------------- | |
| export const SCOPES = { | |
| TRIPS_READ: 'trips:read', | |
| TRIPS_WRITE: 'trips:write', | |
| TRIPS_DELETE: 'trips:delete', | |
| TRIPS_SHARE: 'trips:share', | |
| PLACES_READ: 'places:read', | |
| PLACES_WRITE: 'places:write', | |
| ATLAS_READ: 'atlas:read', | |
| ATLAS_WRITE: 'atlas:write', | |
| PACKING_READ: 'packing:read', | |
| PACKING_WRITE: 'packing:write', | |
| TODOS_READ: 'todos:read', | |
| TODOS_WRITE: 'todos:write', | |
| BUDGET_READ: 'budget:read', | |
| BUDGET_WRITE: 'budget:write', | |
| RESERVATIONS_READ: 'reservations:read', | |
| RESERVATIONS_WRITE: 'reservations:write', | |
| COLLAB_READ: 'collab:read', | |
| COLLAB_WRITE: 'collab:write', | |
| NOTIFICATIONS_READ: 'notifications:read', | |
| NOTIFICATIONS_WRITE: 'notifications:write', | |
| VACAY_READ: 'vacay:read', | |
| VACAY_WRITE: 'vacay:write', | |
| GEO_READ: 'geo:read', | |
| WEATHER_READ: 'weather:read', | |
| JOURNEY_READ: 'journey:read', | |
| JOURNEY_WRITE: 'journey:write', | |
| JOURNEY_SHARE: 'journey:share', | |
| } as const; | |
| export type Scope = typeof SCOPES[keyof typeof SCOPES]; | |
| export const ALL_SCOPES: Scope[] = Object.values(SCOPES) as Scope[]; | |
| export interface ScopeInfo { | |
| label: string; | |
| description: string; | |
| group: string; | |
| } | |
| export const SCOPE_INFO: Record<Scope, ScopeInfo> = { | |
| 'trips:read': { label: 'View trips & itineraries', description: 'Read trips, days, day notes, and members', group: 'Trips' }, | |
| 'trips:write': { label: 'Edit trips & itineraries', description: 'Create and update trips, days, notes, and manage members', group: 'Trips' }, | |
| 'trips:delete': { label: 'Delete trips', description: 'Permanently delete entire trips — this action is irreversible', group: 'Trips' }, | |
| 'trips:share': { label: 'Manage share links', description: 'Create, update, and revoke public share links for trips', group: 'Trips' }, | |
| 'places:read': { label: 'View places & map data', description: 'Read places, day assignments, tags, and categories', group: 'Places' }, | |
| 'places:write': { label: 'Manage places', description: 'Create, update, and delete places, assignments, and tags', group: 'Places' }, | |
| 'atlas:read': { label: 'View Atlas', description: 'Read visited countries, regions, and bucket list', group: 'Atlas' }, | |
| 'atlas:write': { label: 'Manage Atlas', description: 'Mark countries and regions visited, manage bucket list', group: 'Atlas' }, | |
| 'packing:read': { label: 'View packing lists', description: 'Read packing items, bags, and category assignees', group: 'Packing' }, | |
| 'packing:write': { label: 'Manage packing lists', description: 'Add, update, delete, toggle, and reorder packing items and bags', group: 'Packing' }, | |
| 'todos:read': { label: 'View to-do lists', description: 'Read trip to-do items and category assignees', group: 'To-dos' }, | |
| 'todos:write': { label: 'Manage to-do lists', description: 'Create, update, toggle, delete, and reorder to-do items', group: 'To-dos' }, | |
| 'budget:read': { label: 'View budget', description: 'Read budget items and expense breakdown', group: 'Budget' }, | |
| 'budget:write': { label: 'Manage budget', description: 'Create, update, and delete budget items', group: 'Budget' }, | |
| 'reservations:read': { label: 'View reservations', description: 'Read reservations and accommodation details', group: 'Reservations' }, | |
| 'reservations:write': { label: 'Manage reservations', description: 'Create, update, delete, and reorder reservations', group: 'Reservations' }, | |
| 'collab:read': { label: 'View collaboration', description: 'Read collab notes, polls, and messages', group: 'Collaboration' }, | |
| 'collab:write': { label: 'Manage collaboration', description: 'Create, update, and delete collab notes, polls, and messages', group: 'Collaboration' }, | |
| 'notifications:read': { label: 'View notifications', description: 'Read in-app notifications and unread counts', group: 'Notifications' }, | |
| 'notifications:write': { label: 'Manage notifications', description: 'Mark notifications as read and respond to them', group: 'Notifications' }, | |
| 'vacay:read': { label: 'View vacation plans', description: 'Read vacation planning data, entries, and stats', group: 'Vacation' }, | |
| 'vacay:write': { label: 'Manage vacation plans', description: 'Create and manage vacation entries, holidays, and team plans', group: 'Vacation' }, | |
| 'geo:read': { label: 'Maps & geocoding', description: 'Search locations, resolve map URLs, and reverse geocode coordinates', group: 'Geo' }, | |
| 'weather:read': { label: 'Weather forecasts', description: 'Fetch weather forecasts for trip locations and dates', group: 'Weather' }, | |
| 'journey:read': { label: 'View journeys', description: 'Read journeys, entries, and contributor list', group: 'Journey' }, | |
| 'journey:write': { label: 'Manage journeys', description: 'Create, update, and delete journeys and their entries', group: 'Journey' }, | |
| 'journey:share': { label: 'Manage journey links', description: 'Create, update, and revoke public share links for journeys', group: 'Journey' }, | |
| }; | |
| // --------------------------------------------------------------------------- | |
| // Scope enforcement helpers | |
| // null scopes = static trek_ token = full access | |
| // --------------------------------------------------------------------------- | |
| /** trips:read OR trips:write OR trips:delete OR trips:share all grant read access to trips */ | |
| export function canReadTrips(scopes: string[] | null): boolean { | |
| if (!scopes) return true; | |
| return scopes.some(s => s === 'trips:read' || s === 'trips:write' || s === 'trips:delete' || s === 'trips:share'); | |
| } | |
| /** group:write grants write access; for trips canReadTrips handles read */ | |
| export function canWrite(scopes: string[] | null, group: string): boolean { | |
| if (!scopes) return true; | |
| return scopes.includes(`${group}:write`); | |
| } | |
| /** group:read OR group:write grant read access */ | |
| export function canRead(scopes: string[] | null, group: string): boolean { | |
| if (!scopes) return true; | |
| return scopes.some(s => s === `${group}:read` || s === `${group}:write`); | |
| } | |
| /** trips:delete is a separate scope from trips:write */ | |
| export function canDeleteTrips(scopes: string[] | null): boolean { | |
| if (!scopes) return true; | |
| return scopes.includes('trips:delete'); | |
| } | |
| /** trips:share is a separate scope for managing public share links */ | |
| export function canShareTrips(scopes: string[] | null): boolean { | |
| if (!scopes) return true; | |
| return scopes.includes('trips:share'); | |
| } | |
| /** journey:share is a separate scope for managing public share links for journeys */ | |
| export function canShareJourneys(scopes: string[] | null): boolean { | |
| if (!scopes) return true; | |
| return scopes.includes('journey:share'); | |
| } | |
| export function validateScopes(requestedScopes: string[]): { valid: boolean; invalid: string[] } { | |
| const invalid = requestedScopes.filter(s => !ALL_SCOPES.includes(s as Scope)); | |
| return { valid: invalid.length === 0, invalid }; | |
| } | |