feat(sync): credentials setup, auth continuation, and error surfacing (#71)

* feat(sync): add `setup` command to configure credentials interactively

Problem: users had to manually create a JSON credentials file at the
correct path before authenticating, with no guidance from the plugin.

Solution: add `OAuthClient:setup()` that prompts for client ID and
secret via `vim.ui.input`, writes to the shared
`google_credentials.json`, then immediately starts the OAuth flow.
Expose as `:Pending {gtasks,gcal} setup`. Also extend
`resolve_credentials()` to fall back to a shared `google_credentials.json`
so one file covers both backends.

* fix(sync): improve `setup` input loop with validation and masking

Problem: `setup()` used async `vim.ui.input` for both prompts, causing
newline and re-prompt issues when validation failed. The secret was also
echoed in plain text.

Solution: switch to synchronous `vim.fn.input` / `vim.fn.inputsecret`
loops with `vim.cmd.redraw()` + `nvim_echo` for inline error display and
re-prompting. Validate client ID format and `GOCSPX-` secret prefix
before saving.

* fix(oauth): fix `ipairs` nil truncation in `resolve_credentials` and add file-path setup option

Problem: `resolve_credentials` built `cred_paths` with a potentially nil
first element (`credentials_path`), causing `ipairs` to stop immediately
and always fall through to bundled placeholder credentials.

Solution: build `cred_paths` without nil entries using `table.insert`.
Also add a `2. Load from JSON file path` option to `setup()` via
`vim.fn.inputlist`, with `vim.fn.expand` for `~`/`$HOME` support and
the `installed` wrapper unwrap.

* doc: cleanup

* ci: format

* fix(sync): surface auth failures and detect missing credentials

Problem: three silent failure paths remained in the sync auth flow —
`with_token` gave no feedback when auth was cancelled or failed,
`get_access_token` logged a generic message on refresh failure, and
`auth()` opened a browser with `PLACEHOLDER` credentials with no
Neovim-side error.

Solution: add `log.error` in `with_token` when `get_access_token`
returns nil after auth, improve the refresh-failure message to name
the backend and hint at re-auth, and guard `auth()` with a pre-flight
check that errors immediately when bundled placeholder credentials are
detected.
This commit is contained in:
Barrett Ruth 2026-03-05 18:58:14 -05:00 committed by GitHub
parent f78f8e42fa
commit 87d8bf0896
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 9 additions and 1 deletions

View file

@ -146,6 +146,8 @@ local function with_token(callback)
local fresh = client:get_access_token()
if fresh then
callback(fresh)
else
log.error(client.name .. ': authorization failed or was cancelled')
end
end)
end)

View file

@ -362,6 +362,8 @@ local function with_token(callback)
local fresh = client:get_access_token()
if fresh then
callback(fresh)
else
log.error(client.name .. ': authorization failed or was cancelled')
end
end)
end)

View file

@ -252,7 +252,7 @@ function OAuthClient:get_access_token()
if now - obtained > expires - 60 then
tokens = self:refresh_access_token(creds, tokens)
if not tokens then
log.error('Failed to refresh access token.')
log.error(self.name .. ': token refresh failed — re-authenticating...')
return nil
end
end
@ -349,6 +349,10 @@ end
---@return nil
function OAuthClient:auth(on_complete)
local creds = self:resolve_credentials()
if creds.client_id == BUNDLED_CLIENT_ID then
log.error(self.name .. ': no credentials configured — run :Pending ' .. self.name .. ' setup')
return
end
local port = self.port
local verifier_chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~'