feat(google-docs): managed OAuth-redirect Picker (no API key, no BYOK) (#620)

* feat(google-docs): managed OAuth-redirect Picker (no API key, no BYOK)

Adds the managed (rowboat-mode) Google Docs picker via Google's trigger_onepick
flow. The Rowboat backend runs a standalone drive.file OAuth with the company
client, renders the Picker inside the browser consent screen, and deep-links the
selection back; the desktop downloads the picked doc with the fresh drive.file
token the backend returns. No Picker API key, appId, or BYOK credentials on the
desktop.

- core: importGoogleDocWithToken downloads a picked doc with an explicit token;
  fetch/metadata helpers take an optional Drive client and share writeDocxAndLink.
  claimPickedFilesViaBackend claims the parked file ids + token from the api.
- main: google-picker-managed.ts opens the backend start URL and resolves on the
  rowboat://oauth/google/picker/done deep link; deeplink.ts routes that completion.
- ipc: google-docs:pickViaManaged.
- renderer: the picker dialog gates on Rowboat sign-in (the picker grants
  drive.file per-file, so no pre-existing connection or scope is required).

Backend contract: rowboatlabs/rowboatx-backend#7
(GET /oauth/google/picker/{start,callback}, POST /v1/google-oauth/claim-picked).

* chore(google-docs): remove the dead API-key/system-browser Picker

The managed picker replaced the only consumer (the picker dialog), so the
experimental API-key Picker is now unused. Removes:
- main: google-docs:openPicker handler (system-browser loopback Picker)
- shared: google-docs:openPicker + google-docs:getAccessToken IPC schemas
- core: getGoogleAccessToken (token plumbing for the client-side Picker)
- renderer: lib/google-picker.ts (Picker JS SDK loader)

Kept GoogleClientIdModal / google-credentials-store — still used by the
general BYOK Google connect in onboarding, connectors, and settings.
This commit is contained in:
gagan 2026-06-22 13:57:37 -07:00 committed by GitHub
parent 875b65d279
commit 67b521489c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 314 additions and 447 deletions

View file

@ -650,27 +650,6 @@ const ipcSchemas = {
missingScopes: z.array(z.string()),
}),
},
// Live Google OAuth access token for driving the Google Picker in the renderer.
'google-docs:getAccessToken': {
req: z.null(),
res: z.object({
accessToken: z.string().nullable(),
}),
},
// Open a Google Picker in a dedicated BrowserWindow (avoids session-cookie
// issues when running the Picker widget inside the renderer iframe).
'google-docs:openPicker': {
req: z.object({
accessToken: z.string(),
apiKey: z.string().optional(),
appId: z.string().optional(),
}),
res: z.object({
id: z.string(),
name: z.string(),
mimeType: z.string(),
}).nullable(),
},
'google-docs:import': {
req: z.object({
fileId: z.string().min(1),
@ -687,6 +666,24 @@ const ipcSchemas = {
}),
}),
},
// Managed OAuth-redirect Picker: the Rowboat backend runs the pick with the
// company Google client; the desktop opens the start URL, waits for the deep
// link, and imports with the existing managed token. No API key or BYOK creds.
'google-docs:pickViaManaged': {
req: z.object({
targetFolder: RelPath,
}),
res: z.object({
path: RelPath,
doc: z.object({
id: z.string(),
name: z.string(),
url: z.string(),
modifiedTime: z.string().nullable(),
owner: z.string().nullable(),
}),
}).nullable(),
},
'google-docs:refreshSnapshot': {
req: z.object({
path: RelPath,