feat(typespec): add TypeSpec models for Storage, Functions, and PostgREST#53
Draft
grdsdev wants to merge 8 commits into
Draft
feat(typespec): add TypeSpec models for Storage, Functions, and PostgREST#53grdsdev wants to merge 8 commits into
grdsdev wants to merge 8 commits into
Conversation
Adds a Smithy model for the PostgREST HTTP API boundary: From (SELECT), Insert, Upsert, Update, Delete, and Rpc operations. The model captures paths, HTTP methods, standard headers (Prefer, Range, Content-Profile, Accept-Profile), and response headers (Content-Range). Dynamic query params (filters, column selection, ordering) are captured via @httpQueryParams Map<String, String> — the query builder in each SDK populates this map at runtime; Smithy cannot express PostgREST's filter syntax (id=eq.5, name=like.*foo*) as fixed shapes. Also ignores the smithy/build/ directory to keep the repo clean.
…REST Parallel to the Smithy models in smithy/ — same APIs, different IDL — for comparing the two as source-of-truth candidates for SDK codegen. Key differences from Smithy output: - Explicit application/octet-stream content-type on binary bodies (TUS chunk, Functions invoke) via @Header contentType, producing format: binary in OpenAPI instead of Smithy's format: byte (which required patch-openapi.py to fix) - PostgREST row bodies use `unknown` (maps to {} in JSON Schema — any JSON value) instead of bytes/format: byte, accurately representing user-defined row structures - Dynamic query params use @query(#{explode: true}) so each PostgREST filter becomes its own query parameter (?select=*&id=eq.5) rather than a single packed value - Integer fields emit int32/int64 formats; Smithy emits generic number - Void responses use 204 No Content; Smithy emits 200 - Schemas are reused via $ref; Smithy generates per-operation wrapper types Compile: cd typespec && npm install && npx tsp compile . Output: typespec/openapi/@typespec/openapi3/
- Add named query params: select, order, limit (integer), offset (integer) as separate typed members on each table operation instead of collapsing everything into one Record<string> params map - Add columns param to insert, on_conflict param to upsert - Add filters: Record<string> (explode: true) for dynamic column filters, separate from the fixed named params - Add FilterOperator enum with all 24 PostgREST operators (matches Smithy) - Split RPC into rpc (POST) + rpcGet (GET) — GET takes args: Record<string> - Add doc comments to all operations and params - Regenerate openapi.Supabase.PostgREST.yaml
Add Objects_upload (POST) and Objects_update (PUT) on /{bucketId}/{wildcardPath}
using @multipartBody with cacheControl (optional string) and file (bytes) parts.
TypeSpec's @multipartBody emits correct multipart/form-data with format:binary
natively — no post-generation patching needed, unlike the Smithy pipeline which
required patch-openapi.py to inject these operations manually.
…r bodies Replace unknown with bytes + explicit @Header contentType: application/octet-stream on both response models (RowsResponse, InsertResponse) and request bodies. This makes swift-openapi-generator emit HTTPBody (streaming binary) instead of OpenAPIValueContainer (any-JSON), matching the Smithy output and letting the SDK layer decode the raw bytes into whatever Decodable type the caller requested.
Functions: each invoke method (POST/PUT/PATCH/DELETE) now uses @SharedRoute to express four request body content types in one OpenAPI operation: application/json → OpenAPIValueContainer (any JSON) application/octet-stream → HTTPBody (binary) text/plain → String application/x-www-form-urlencoded → String TypeSpec 0.65 @SharedRoute concatenates variant names into the operationId; patch-openapi.py rewrites them to the canonical short form. PostgREST: revert request bodies from bytes/octet-stream back to unknown (→ application/json / OpenAPIValueContainer). PostgREST bodies ARE JSON (row arrays/objects); only response bodies warrant HTTPBody for raw decoding.
Each invoke method now returns one of three content types depending on what the function sends back: application/json → any JSON value application/octet-stream → binary text/plain → string Uses the same @SharedRoute pattern as request bodies: Json/Text/Form variants return JsonResponse/TextResponse/JsonResponse respectively; Binary returns OctetStreamResponse. TypeSpec merges them into three response content entries.
…/* content type Remove @SharedRoute multi-variant approach in favour of a single operation per HTTP method. A variable contentType header alongside bytes body causes TypeSpec to emit content-type */* in OpenAPI, which swift-openapi-generator maps to case any(HTTPBody) - generic enough for JSON, binary, text, event-stream, etc. This also removes the need for patch-openapi.py entirely.
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
Adds canonical TypeSpec models for Storage, Functions, and PostgREST as a direct parallel to the Smithy models — same APIs, different IDL — to compare the two as source-of-truth candidates for SDK codegen.
typespec/storage.tsp— Storage API (buckets, objects, TUS resumable uploads), grouped intointerfaces (Buckets,Objects,TusUploads)typespec/functions.tsp— Edge Functions API (one operation per HTTP method on/functions/v1/{functionName})typespec/postgrest.tsp— PostgREST API (table CRUD + RPC), withRecord<string>for dynamic query paramstypespec/openapi/@typespec/openapi3/— committed generated OpenAPI 3.0 artifacts (no patching needed)Compile:
cd typespec && npm install && npx tsp compile .Key differences from the Smithy output
application/octet-stream✓ butformat: bytebefore patchingapplication/octet-stream+format: binarydirectly via@header contentTypetype: string, format: byte(wrong){}(any JSON value) viaunknownstyle: form→explode: true(correct)@query(#{explode: true})→ same correct defaultnumberint32/int64with formatGetBucketResponseContentetc.)$refreuse — no duplicates"400"statusdefaultcatch-alloperationIdListBuckets)Buckets_list)npm install+npx tsp compileKnown limitations (shared with Smithy)
UploadObject/UpdateObject) — no native multipart support in TypeSpec; Smithy handles this viapatch-openapi.py{+wildcardPath}) — TypeSpec emits valid OpenAPI (drops the+) but loses greedy-match semantics; Smithy emits invalid OpenAPI (keeps+inside the param name)