Use connectors.google.calendar for Calendar access. The host owns the account connection, OAuth, permission prompts, and provider calls. Apps do not receive credentials or call the provider directly.
Merge this fragment into the project's descriptor and complete its host-reviewed access change:
{ "requests": { "connectors": { "google.calendar": ["events.read"] } } }
A connected account is not a project grant. Call ensureAccess({ operation: 'events.read' }) from the app's access action before listing its grant-filtered accounts. Use the returned account identity for subsequent calls. Choose a calendar from an authorized selection; listing calendars separately requires calendars.read. Never call a data method merely to provoke consent.
This function reads one bounded page from an already selected calendar. timeMin and timeMax are RFC 3339 timestamps. If present, preserve nextPageToken unchanged for the next page.
import { connectors } from '@ispo/sdk'
export async function readCalendarEvents(calendarId: string, timeMin: string, timeMax: string) {
const { accountId } = await connectors.google.calendar.ensureAccess({ operation: 'events.read' })
return connectors.google.calendar.listEvents({
accountId,
calendarId,
timeMin,
timeMax,
maxResults: 25,
singleEvents: true,
orderBy: 'startTime',
})
}
ensureAccess can open the host's consent flow; it makes no provider data request. listEvents reads data without creating an event. Repeating a read may return newer data. Keep denial and unavailable-account states visible. Restore access through the host, then retry deliberately; never switch to raw OAuth or provider APIs.
Creating, updating, or deleting events uses separate events.write authority and changes provider data. Do not automatically retry a write after an uncertain outcome: inspect the calendar first. The shown calls have no caller cancellation signal; a timeout does not establish rollback.
Typecheck, run inside ISPO, acquire access once, and compare the returned events with the selected calendar and time range. Exercise denied access and a disconnected account. A successful render alone does not prove a provider write succeeded.