refactor(notes-ui): subclass app-client VaultClient (drop duplicated request loop) - #155
Merged
Conversation
…request loop)
app-client 0.1.0-rc.3 lifted `request`, `requestWithRetry`, and
`requestCursorWithRetry` to `protected` (parachute-app#10), closing
the loop from notes#153's reviewer-flagged follow-up. Notes' VaultClient
now subclasses `@openparachute/app-client`'s base instead of cloning the
request/retry/error-classification loop.
- 219 lines deleted from `packages/notes-ui/src/lib/vault/client.ts`
- 691 lines deleted from `packages/notes-ui/src/lib/vault/client.test.ts`
(base-class behaviors are covered by app-client's own suite; 14
Notes-specific tests retained)
Notes-specific surface retained on the subclass:
- `renameTag` / `mergeTags` / `deleteTag` — tag-curation endpoints
- `listTagsWithSchema` — `/api/tags?include_schema=true` (schema-audit)
- `linkAttachment` — alias of base `addAttachment` (preserves Notes'
semantic + avoids a sweeping rename)
- `fetchAttachmentBlob` — audio/image render path; carries its own
retry loop because the base's `request*` always parses JSON
Notes' previous narrow `updateTag` override was dropped — the base
class's `TagUpsertPayload`-shaped `updateTag` accepts the same
`{description, parent_names}` shape `schema-ensure.ts` already passes,
and the caller ignores the return value.
Bundle delta: +3.8 kB raw / +0.9 kB gzip on the main chunk (the
subclass mirrors a handful of auth-callback fields on the instance so
the blob path can drive its own retry loop without reaching into the
base's `private` state).
Verification:
- `bun run typecheck` clean
- `bun run lint` clean
- `bun run test` — 767/767 pass
- `bun run build` — clean
Bumps `@openparachute/notes-ui` to 0.1.0-rc.3.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ob onAuthRevoked detail
Two reviewer nits from notes#155:
1. `linkAttachment` now delegates to the inherited `addAttachment`
rather than re-implementing the POST via `this.request(...)`. The
wire shape is identical (POST `/api/notes/:id/attachments`); the
thin wrapper preserves the Notes-facing name + semantic ("link an
already-uploaded blob") while inheriting any future wire-shape
changes from app-client automatically. Many callers reference
`linkAttachment` directly (NoteNew, queue, queries, tests) so the
alias stays.
2. `fetchBlobWithRetry` (the 401/403 path on attachment-blob loads)
now parses the response body for `error_type` + `message` and
forwards them to `onAuthRevoked` as the detail object, matching
notes#150's enhanced-error shape and the base class's
`requestWithRetry` behavior. Previously the blob path called
`onAuthRevoked?.(res.status)` and dropped the detail, so banners
triggered by attachment failures lost the parsed reason.
Body is read once with `res.text().catch(() => "")` before the
refresh-and-retry branch, mirroring the base class. Non-JSON bodies
leave detail undefined.
Reviewer nit #3 (a test specifically exercising the `setAccessToken`
override) is intentionally deferred — the dual-token sync is already
exercised indirectly by the `fetchAttachmentBlob` 401-retry test,
which verifies the rotated token reaches the second fetch call.
Tests: 768 passing (one new test added for the enhanced-detail blob
path). Typecheck + lint clean.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
app-client 0.1.0-rc.3 lifted
request/requestWithRetry/requestCursorWithRetrytoprotected(parachute-app#10),closing the loop from notes#153's reviewer follow-up. Notes' VaultClient
now subclasses
@openparachute/app-client's base class instead ofcloning the request loop.
packages/notes-ui/src/lib/vault/client.ts(486 → 267).
packages/notes-ui/src/lib/vault/client.test.ts(997 → 306). Base-class behaviors are covered by app-client's own
suite; 14 Notes-specific tests retained.
Notes-specific surface retained on the subclass
renameTag/mergeTags/deleteTaglistTagsWithSchema/api/tags?include_schema=truefor schema-audit runner (notes#129)linkAttachmentaddAttachment— preserves Notes' caller-facing name + avoids a sweeping renamefetchAttachmentBlobrequest*always parses JSONBehaviour change worth flagging
Notes' previous narrow
updateTagoverride was dropped. The baseclass's
updateTagaccepts a widerTagUpsertPayloadand returns aTagRecord; the existing call sites (schema-ensure.ts→ 2 calls)pass
{description, parent_names}(a subset ofTagUpsertPayload) andawaitwithout consuming the return — so the surface isbackward-compatible at the call site.
Bundle delta
Main chunk: 415.90 → 419.70 kB (+3.8 kB raw, +0.9 kB gzip). The
subclass mirrors a handful of auth-callback fields on the instance so
the blob path can drive its own retry loop without reaching into the
base's
privatestate — see file header for the rationale.Cross-refs
f5b70cb)request*→protectedin app-client: parachute-app#10 (rc.3)Test plan
bun run typecheck— cleanbun run lint— cleanbun run test— 767/767 pass (90 files)bun run build— cleanparachute-app, verifyvaultInfo / queryNotes / createNote / linkAttachment /
fetchAttachmentBlob (audio playback) / renameTag all still work
onAuthRevokedwhen the post-refresh retry also 401s🤖 Generated with Claude Code