Repository navigation
fix(web): Infra repeat abort, REST credential errors and SDK preflight cache - #4179
Merged
Merged
Conversation
…T API, and cache SDK preflights
…d REST credential errors
|
Sandchest reviewed Sandchest reviews every change for vulnerabilities an attacker could use · 6 credits · Review details |
Contributor
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
Member
Author
|
hey @greptileai, please re-review the PR |
# Conflicts: # apps/web/__tests__/unit/developer-api-contract.test.ts
Member
Author
|
hey @greptileai, please re-review the PR |
This branch was successfully deployed
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.

Eight follow-ups on the Cap Infra developer API: five from the app-builder persona and three from the speech persona. This is a sibling of #4176 and touches none of its changed lines.
Repeated abort answers 200
POST /api/developer/sdk/v1/upload/multipart/abortalready answered200 { "success": true }when the same upload was aborted twice, because storage accepts the repeat. If storage instead answersNoSuchUpload, abort now also returns 200, so a repeat behaves the same on every storage backend. The docs and OpenAPI said this answered 404. They now say abort is safe to repeat.Presign keeps signing without a storage check
The open
uploadIdis not stored on the video row. Initiate finds it by listing open uploads in storage. The only JSON column on the row that is free during an upload isprocessing, and that holds the encode state. Status resolution, stored-bytes accounting and the claim and release paths all read it, and they reset it to null. A storageListPartscall on every presign is ruled out, because presign is on the hot path.Presign is left as it was. The docs and OpenAPI now say that signing does not contact storage. A wrong or aborted
uploadIdfails at the partPUT, and complete answers404 upload_not_found. Storing the id would also miss uploads already open when this deploys.Distinct REST credential errors
withDeveloperSecretAuthnow separates the cases the SDK routes already separate:Authorizationheader401 invalid_secret_key, "Invalid secret key"401 invalid_secret_key, "Missing secret key", with a hint that no header was sentcpk_public key401 invalid_secret_key, "Invalid secret key"403 public_key_not_allowed, "Public keys cannot call the REST API"csk_value401 invalid_secret_keycsk_key401 invalid_secret_key, "Invalid or revoked secret key"Code change: a public key on the REST API now gets
403 public_key_not_allowedinstead of401 invalid_secret_key. The SDK routes already use that code. Every other code is unchanged. OpenAPI lists the 403 on every REST operation throughrestErrors, and the sharedForbiddendescription names the code.Preflight cache on the SDK upload routes
developerSdkCorssetsmaxAge: 7200, so OPTIONS answers on the upload routes carryAccess-Control-Max-Age: 7200. Browsers stop preflighting every part. Hono only adds the header to preflight answers.Usage after deletes: not a bug, nothing changed
The report saw
/usage12 s above the listed videos shortly after some deletes. The code has no window in which a deleted video counts:deletedAtto the primary database before it answers 200./usagereads that same database throughgetAppStorage, filtered ondeletedAt IS NULL, statusreadyand a duration set.x-vercel-cache: BYPASS.The likely cause is in the test app. Its library lists videos with
?userId=, while/usagecovers the whole app. The persona also ran the Node upload example on the 12 s demo clip with and without auserId. A clip with nouserIdcounts in usage but never appears in a user-scoped list. That also fits the reading being correct after the final cleanup.Ledger order across page edges
GET /transactionsordered rows bycreatedAt desc, id descin SQL, thenorderLedgerRowsput each second's rows in balance-chain order inside the fetched page. Ids are random andcreatedAthas one-second resolution. So when a same-second group straddled a page edge, the two pages split it by id, and the balance chain broke at the edge. The CSV export had the same break at its 1,000-row batch edges.No SQL key gives the chain order without a migration. Instead:
listAppLedger(the REST API) keeps the samelimit/offsetquery, which now locates the page. When the page is not the whole ledger, a second query reads every row in the seconds the page spans. They are ordered the same way a single page would order them, and the page is sliced out from the position of its first row. That position is the first row's index in the second query's SQL order, so there is still no count. A first page that holds the whole ledger stays one query.readAppLedger(the CSV export) finishes the last second of each full batch before it yields. The next batch starts strictly before that second.listAppLedgerPage) are unchanged. They are a view, and nothing reconciles them page by page.The docs now say the order holds across page edges and does not depend on
limit.Speech seconds and the charge
Get Usage gains one sentence.
speech.secondsis measured audio, while each transcript is charged on its length rounded to a whole second and then down to a whole micro-credit, so seconds times the rate can differ slightly frommicroCredits. For the exact charge, usemicroCreditsor each transcript'scostMicroCredits. The API is unchanged.A web page at a transcript URL
When the first bytes of a transcript URL are HTML (
<!doctype htmlor<html, any case, after an optional BOM and whitespace), the transcript fails with the message "The URL returned a web page, not a media file". The code staysunsupported_format.looksLikeHtmlshares the BOM and whitespace skip withlooksLikePlaylist. XML, playlists and other bytes keep the old message.Tests
developer-sdk-upload.test.ts: a first abort, a repeat abort and an abort that storage answers withNoSuchUploadall return200 { success: true }. This replaces the test that expected 404.developer-api-contract.test.ts:access-control-max-age: 7200on initiate, presign-part, complete and abort.cpk_key gets 403public_key_not_allowedand reads no billing.csk_key keep their answers.developer-transcripts-api,developer-transactions-apianddeveloper-upload-token-flownow expect 403public_key_not_allowedfor a public key.infra-ledger-paging.test.ts: nine rows across three seconds, five of them in one second, with ids out of chain order. Walking withlimit1, 2, 3, 4, 5 and 8 gives the same ids as one page of 100, and the chain has no break. Exporting in batches of 2, 3 and 4 gives the same order. Both tests fail against main's ledger store.developer-transcribe-download.test.ts: an HTML page, one after a BOM and blank lines in upper case, and<HTMLwith no doctype get the web page message. XML, a playlist and random bytes keep the old one. Every case keepsunsupported_format, stores nothing and charges nothing.Against main's
utils.tsandinfra-video-upload.ts, 12 of the first five items' tests fail. Across the web unit suite (8,540 passed), the only failure isshare-stage-identity.test.ts, which fails the same way when run on its own and touches nothing changed here.

Confidence Score: 5/5
The PR appears safe to merge; no new actionable issues were found.Summary
This PR makes repeated upload aborts succeed, distinguishes missing and public REST credentials, and caches SDK preflight answers for two hours.
Tests were not run during this review.
Reviews (8) · Last reviewed commit: "Merge branch 'main' into fix/infra-rest-..." · Reviewed by Greptile