From dd4ce07089f8edc5aaa98813af2e1998cec87a0a Mon Sep 17 00:00:00 2001 From: Guilherme Souza Date: Wed, 1 Jul 2026 06:03:10 -0300 Subject: [PATCH 1/6] feat(smithy): add canonical Smithy models for Storage and Functions APIs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds Smithy IDL definitions for Supabase Storage and Edge Functions HTTP APIs as a shared source-of-truth for cross-SDK codegen spikes. Each SDK team runs their own generator toolchain against the same models. Includes: - model/common.smithy — shared shapes (StringList) - model/storage.smithy — buckets, objects, signed URLs, TUS resumable uploads - model/functions.smithy — invoke operations for GET/POST/PUT/PATCH/DELETE - smithy-build.json — Smithy CLI / Gradle build config - patch-openapi.py — post-generation patches for streaming blob and multipart - openapi/ — committed generated OpenAPI 3.0 artifacts (patched) Known limitations documented in README (streaming blob format, multipart, dynamic query params). Auth and PostgREST models are not yet included — each SDK spike (SDK-1103 through SDK-1109) must assess those layers. Related: RFC auto-generating parts of the Supabase SDKs Swift spike: supabase/supabase-swift#1047 --- smithy/README.md | 96 ++ smithy/model/common.smithy | 8 + smithy/model/functions.smithy | 99 ++ smithy/model/storage.smithy | 450 ++++++ smithy/openapi/FunctionsService.openapi.json | 305 ++++ smithy/openapi/StorageService.openapi.json | 1388 ++++++++++++++++++ smithy/patch-openapi.py | 94 ++ smithy/smithy-build.json | 44 + 8 files changed, 2484 insertions(+) create mode 100644 smithy/README.md create mode 100644 smithy/model/common.smithy create mode 100644 smithy/model/functions.smithy create mode 100644 smithy/model/storage.smithy create mode 100644 smithy/openapi/FunctionsService.openapi.json create mode 100644 smithy/openapi/StorageService.openapi.json create mode 100644 smithy/patch-openapi.py create mode 100644 smithy/smithy-build.json diff --git a/smithy/README.md b/smithy/README.md new file mode 100644 index 0000000..15cf0cc --- /dev/null +++ b/smithy/README.md @@ -0,0 +1,96 @@ +# Supabase Smithy Models + +Canonical [Smithy IDL](https://smithy.io/) definitions for the Supabase HTTP APIs. These models are the shared source-of-truth for SDK codegen spikes — each SDK team runs their own generator toolchain against the same models. + +## Structure + +``` +smithy/ + model/ + common.smithy # Shared shapes (StringList, etc.) + storage.smithy # Supabase Storage API (buckets, objects, TUS resumable uploads) + functions.smithy # Supabase Edge Functions API (invoke: GET/POST/PUT/PATCH/DELETE) + openapi/ + StorageService.openapi.json # Generated OpenAPI 3.0 — committed for SDK consumers + FunctionsService.openapi.json # Generated OpenAPI 3.0 — committed for SDK consumers + smithy-build.json # Smithy build config (Smithy CLI / Gradle) + patch-openapi.py # Post-generation patches (see Known Limitations) + README.md +``` + +## Generating the OpenAPI artifacts + +**Requirements:** [Smithy CLI](https://smithy.io/2.0/guides/smithy-cli/cli-installation.html) or Gradle with the Smithy Gradle plugin. + +```bash +cd smithy +smithy build # emits openapi/ into smithy/build/smithy/*/openapi/ +python patch-openapi.py build/smithy/storage-openapi/openapi/StorageService.openapi.json +python patch-openapi.py build/smithy/functions-openapi/openapi/FunctionsService.openapi.json +``` + +The committed files in `openapi/` are the patched outputs — SDK teams can consume them directly without installing Smithy. + +## Services modelled + +### Storage (`model/storage.smithy`) + +Covers the full Supabase Storage HTTP API: + +| Group | Operations | +|-------|-----------| +| Buckets | `ListBuckets`, `GetBucket`, `CreateBucket`, `UpdateBucket`, `EmptyBucket`, `DeleteBucket` | +| Objects | `MoveObject`, `CopyObject`, `DeleteObjects`, `ListObjects`, `GetObjectInfo`, `HeadObject` | +| Signed URLs | `CreateSignedUrl`, `CreateSignedUrls`, `CreateSignedUploadUrl` | +| Direct upload | `UploadObject` (POST multipart), `UpdateObject` (PUT multipart) — OpenAPI-only; see Known Limitations | +| TUS resumable | `CreateTusUpload` (POST), `UploadChunk` (PATCH), `GetUploadOffset` (HEAD) | + +### Functions (`model/functions.smithy`) + +Models all five HTTP methods on `/functions/v1/{functionName}`: + +`InvokeFunctionGet`, `InvokeFunctionPost`, `InvokeFunctionPut`, `InvokeFunctionPatch`, `InvokeFunctionDelete` + +Smithy requires one operation per HTTP method — a dispatch switch in the client maps `FunctionInvokeOptions.method` to the right operation at runtime. + +## Known Limitations + +These are gaps found during the Swift spike (see [SDK-1103](https://linear.app/supabase/issue/SDK-1103)) that require workarounds or are out of scope for codegen: + +| # | Gap | Workaround | +|---|-----|-----------| +| 1 | `@streaming blob` emits `format: byte` (base64) in OpenAPI; generators need `format: binary` | `patch-openapi.py` rewrites the format after generation | +| 2 | No native `multipart/form-data` trait in Smithy | `patch-openapi.py` injects `UploadObject`/`UpdateObject` multipart operations directly into the OpenAPI JSON | +| 3 | Smithy requires a fixed HTTP method per operation; Functions supports any method at runtime | Model 5 separate operations; client dispatches at runtime | +| 4 | `GET` + `@httpPayload` is illegal in Smithy | Separate `InvokeFunctionGetInput` shape without a body | +| 5 | Dynamic query parameters (`FunctionInvokeOptions.query`) cannot be expressed in Smithy | Not in model; requires a middleware URL-rewriting approach in each SDK | +| 6 | Realtime (WebSocket / event-emitter) is incompatible with REST codegen | Out of scope; Realtime stays hand-written in all SDKs | + +## Scope for SDK spikes + +The models here cover **Storage** and **Functions**. Each SDK spike (see Linear issues SDK-1103 through SDK-1109) must also verify **Auth** and **PostgREST**: + +- **Auth** — sign-in/up, token refresh, OTP, OAuth redirects, session management +- **PostgREST** — query building (`.select()`, `.eq()`, `.order()`) uses highly dynamic query strings; the question is whether codegen helps at the transport layer even if the query builder stays hand-written + +Auth and PostgREST models do not exist yet. They may need to be added here, or the teams may determine that those layers are unsuitable for codegen (PostgREST in particular). + +## Generator toolchains by SDK + +Each SDK team runs their own generator against the OpenAPI artifacts: + +| SDK | Candidate toolchain | +|-----|-------------------| +| Swift | `swift-openapi-generator` (spike done — see [PR #1047](https://github.com/supabase/supabase-swift/pull/1047)) | +| JavaScript/TypeScript | TypeSpec → `@hey-api/openapi-ts` or `@typespec/http-client-js` | +| Python | TypeSpec → `openapi-python-client` or `@typespec/http-client-python` | +| Dart/Flutter | OpenAPI Generator `dart-dio` (no official TypeSpec/Smithy Dart emitter) | +| C# | Kiota or `@typespec/http-client-csharp` | +| Go | `oapi-codegen` or `ogen` | +| Kotlin | `smithy-kotlin` (KMP-compatible) or custom TypeSpec emitter | + +## Reference + +- RFC: [Auto-generating parts of the Supabase SDKs](https://linear.app/supabase/project/rfc-auto-generating-parts-of-the-supabase-sdks-581579f2a632) +- Swift spike PR: [supabase/supabase-swift#1047](https://github.com/supabase/supabase-swift/pull/1047) +- Linear spike issues: SDK-1103 (Swift) · SDK-1104 (JS) · SDK-1105 (Python) · SDK-1106 (Dart) · SDK-1107 (C#) · SDK-1108 (Go) · SDK-1109 (Kotlin) diff --git a/smithy/model/common.smithy b/smithy/model/common.smithy new file mode 100644 index 0000000..cc9197d --- /dev/null +++ b/smithy/model/common.smithy @@ -0,0 +1,8 @@ +$version: "2" + +namespace io.supabase + +/// Common string list shape reused across services. +list StringList { + member: String +} diff --git a/smithy/model/functions.smithy b/smithy/model/functions.smithy new file mode 100644 index 0000000..eebcc43 --- /dev/null +++ b/smithy/model/functions.smithy @@ -0,0 +1,99 @@ +$version: "2" + +namespace io.supabase.functions + +use aws.protocols#restJson1 + +@restJson1 +@title("Supabase Functions API") +service FunctionsService { + version: "1.0" + operations: [ + InvokeFunctionGet + InvokeFunctionPost + InvokeFunctionPut + InvokeFunctionPatch + InvokeFunctionDelete + ] + errors: [FunctionsError] +} + +// ─── Shared Shapes ───────────────────────────────────────────────────────── + +/// Input for methods that carry a request body (POST, PUT, PATCH, DELETE). +structure InvokeFunctionInput { + @required + @httpLabel + functionName: String + + @httpHeader("x-region") + region: String + + @httpPayload + body: Blob +} + +/// Input for GET — no body, which GET does not support. +structure InvokeFunctionGetInput { + @required + @httpLabel + functionName: String + + @httpHeader("x-region") + region: String +} + +structure InvokeFunctionOutput { + @httpPayload + body: Blob +} + +// ─── Operations (one per HTTP method) ────────────────────────────────────── +// +// Smithy requires a fixed HTTP method per operation. We model all five +// methods Supabase Edge Functions accept; FunctionsClient.invoke() dispatches +// to the appropriate generated method based on FunctionInvokeOptions.method. + +@http(method: "GET", uri: "/functions/v1/{functionName}", code: 200) +@readonly +operation InvokeFunctionGet { + input: InvokeFunctionGetInput + output: InvokeFunctionOutput + errors: [FunctionsError] +} + +@http(method: "POST", uri: "/functions/v1/{functionName}", code: 200) +operation InvokeFunctionPost { + input: InvokeFunctionInput + output: InvokeFunctionOutput + errors: [FunctionsError] +} + +@http(method: "PUT", uri: "/functions/v1/{functionName}", code: 200) +@idempotent +operation InvokeFunctionPut { + input: InvokeFunctionInput + output: InvokeFunctionOutput + errors: [FunctionsError] +} + +@http(method: "PATCH", uri: "/functions/v1/{functionName}", code: 200) +operation InvokeFunctionPatch { + input: InvokeFunctionInput + output: InvokeFunctionOutput + errors: [FunctionsError] +} + +@http(method: "DELETE", uri: "/functions/v1/{functionName}", code: 200) +@idempotent +@suppress(["HttpMethodSemantics.UnexpectedPayload"]) +operation InvokeFunctionDelete { + input: InvokeFunctionInput + output: InvokeFunctionOutput + errors: [FunctionsError] +} + +@error("client") +structure FunctionsError { + message: String +} diff --git a/smithy/model/storage.smithy b/smithy/model/storage.smithy new file mode 100644 index 0000000..13fd406 --- /dev/null +++ b/smithy/model/storage.smithy @@ -0,0 +1,450 @@ +$version: "2" + +namespace io.supabase.storage + +use aws.protocols#restJson1 +use io.supabase#StringList + +@restJson1 +@title("Supabase Storage API") +service StorageService { + version: "1.0" + operations: [ + ListBuckets + GetBucket + CreateBucket + UpdateBucket + EmptyBucket + DeleteBucket + MoveObject + CopyObject + DeleteObjects + ListObjects + GetObjectInfo + HeadObject + CreateSignedUrl + CreateSignedUrls + CreateSignedUploadUrl + CreateTusUpload + UploadChunk + GetUploadOffset + ] + errors: [StorageError] +} + +// ─── Bucket Operations ───────────────────────────────────────────────────── + +@http(method: "GET", uri: "/bucket", code: 200) +@readonly +operation ListBuckets { + output: ListBucketsOutput + errors: [StorageError] +} + +structure ListBucketsOutput { + @required + items: BucketList +} + +list BucketList { + member: Bucket +} + +@http(method: "GET", uri: "/bucket/{id}", code: 200) +@readonly +operation GetBucket { + input: GetBucketInput + output: Bucket + errors: [StorageError] +} + +structure GetBucketInput { + @required + @httpLabel + id: String +} + +@http(method: "POST", uri: "/bucket", code: 200) +operation CreateBucket { + input: CreateBucketInput + errors: [StorageError] +} + +structure CreateBucketInput { + @required id: String + @required name: String + @required @jsonName("public") isPublic: Boolean + file_size_limit: Long + allowed_mime_types: StringList +} + +@http(method: "PUT", uri: "/bucket/{id}", code: 200) +@idempotent +operation UpdateBucket { + input: UpdateBucketInput + errors: [StorageError] +} + +structure UpdateBucketInput { + @required + @httpLabel + id: String + + @required @jsonName("public") isPublic: Boolean + file_size_limit: Long + allowed_mime_types: StringList +} + +@http(method: "POST", uri: "/bucket/{id}/empty", code: 200) +operation EmptyBucket { + input: EmptyBucketInput + errors: [StorageError] +} + +structure EmptyBucketInput { + @required + @httpLabel + id: String +} + +@http(method: "DELETE", uri: "/bucket/{id}", code: 200) +@idempotent +operation DeleteBucket { + input: DeleteBucketInput + errors: [StorageError] +} + +structure DeleteBucketInput { + @required + @httpLabel + id: String +} + +// ─── Object Operations ───────────────────────────────────────────────────── + +@http(method: "POST", uri: "/object/move", code: 200) +operation MoveObject { + input: MoveObjectInput + errors: [StorageError] +} + +structure MoveObjectInput { + @required bucketId: String + @required sourceKey: String + @required destinationKey: String + destinationBucket: String +} + +@http(method: "POST", uri: "/object/copy", code: 200) +operation CopyObject { + input: CopyObjectInput + output: CopyObjectOutput + errors: [StorageError] +} + +structure CopyObjectInput { + @required bucketId: String + @required sourceKey: String + @required destinationKey: String + destinationBucket: String +} + +structure CopyObjectOutput { + @required Key: String +} + +@http(method: "DELETE", uri: "/object/{bucketId}", code: 200) +@idempotent +@suppress(["HttpMethodSemantics.UnexpectedPayload"]) +operation DeleteObjects { + input: DeleteObjectsInput + output: DeleteObjectsOutput + errors: [StorageError] +} + +structure DeleteObjectsInput { + @required + @httpLabel + bucketId: String + + @required prefixes: StringList +} + +structure DeleteObjectsOutput { + @required + items: FileObjectList +} + +list FileObjectList { + member: FileObject +} + +@http(method: "POST", uri: "/object/list/{bucketId}", code: 200) +operation ListObjects { + input: ListObjectsInput + output: ListObjectsOutput + errors: [StorageError] +} + +structure ListObjectsInput { + @required + @httpLabel + bucketId: String + + @required prefix: String + limit: Integer + offset: Integer + sortBy: SortBy +} + +structure SortBy { + column: String + order: String +} + +structure ListObjectsOutput { + @required + items: FileObjectList +} + +@http(method: "GET", uri: "/object/info/{bucketId}/{wildcardPath+}", code: 200) +@readonly +operation GetObjectInfo { + input: GetObjectInfoInput + output: FileInfo + errors: [StorageError] +} + +structure GetObjectInfoInput { + @required @httpLabel bucketId: String + @required @httpLabel wildcardPath: String +} + +@http(method: "HEAD", uri: "/object/{bucketId}/{wildcardPath+}", code: 200) +@readonly +operation HeadObject { + input: HeadObjectInput + errors: [StorageError] +} + +structure HeadObjectInput { + @required @httpLabel bucketId: String + @required @httpLabel wildcardPath: String +} + +@http(method: "POST", uri: "/object/sign/{bucketId}/{wildcardPath+}", code: 200) +operation CreateSignedUrl { + input: CreateSignedUrlInput + output: CreateSignedUrlOutput + errors: [StorageError] +} + +structure CreateSignedUrlInput { + @required @httpLabel bucketId: String + @required @httpLabel wildcardPath: String + @required expiresIn: Integer +} + +structure CreateSignedUrlOutput { + @required signedURL: String +} + +@http(method: "POST", uri: "/object/sign/{bucketId}", code: 200) +operation CreateSignedUrls { + input: CreateSignedUrlsInput + output: CreateSignedUrlsOutput + errors: [StorageError] +} + +structure CreateSignedUrlsInput { + @required @httpLabel bucketId: String + @required expiresIn: Integer + @required paths: StringList +} + +structure CreateSignedUrlsOutput { + @required + items: SignedUrlResultList +} + +list SignedUrlResultList { + member: SignedUrlResult +} + +structure SignedUrlResult { + signedURL: String + @required path: String + error: String +} + +@http(method: "POST", uri: "/object/upload/sign/{bucketId}/{wildcardPath+}", code: 200) +operation CreateSignedUploadUrl { + input: CreateSignedUploadUrlInput + output: CreateSignedUploadUrlOutput + errors: [StorageError] +} + +structure CreateSignedUploadUrlInput { + @required @httpLabel bucketId: String + @required @httpLabel wildcardPath: String + @httpHeader("x-upsert") upsert: String +} + +structure CreateSignedUploadUrlOutput { + @required url: String +} + +// ─── TUS Resumable Upload Operations ─────────────────────────────────────── +// +// Models the three HTTP operations of the TUS 1.0.0 protocol. The application- +// level state machine (chunk sequencing, 409 retry, pause/resume) is NOT +// generated — it lives in TUSUploadEngine, which calls these operations. + +/// Step 1: Create a new TUS upload session. +/// The server responds with a Location header containing the upload URL. +@http(method: "POST", uri: "/upload/resumable", code: 201) +operation CreateTusUpload { + input: CreateTusUploadInput + output: CreateTusUploadOutput + errors: [StorageError] +} + +structure CreateTusUploadInput { + /// Total size of the file in bytes. + @httpHeader("Upload-Length") + @required + uploadLength: Long + + /// Base64-encoded TUS metadata (bucketName, objectName, contentType, cacheControl). + @httpHeader("Upload-Metadata") + @required + uploadMetadata: String + + @httpHeader("Tus-Resumable") + @required + tusResumable: String + + /// Set to "true" to overwrite an existing object at the same path. + @httpHeader("x-upsert") + upsert: String +} + +structure CreateTusUploadOutput { + /// Full URL of the created upload session. Used in subsequent PATCH/HEAD requests. + @httpHeader("Location") + @required + location: String +} + +/// Step 2: Upload a chunk of data to an existing TUS session. +/// Repeat with increasing Upload-Offset until all bytes are sent. +@http(method: "PATCH", uri: "/upload/resumable/{uploadId}", code: 204) +@suppress(["HttpMethodSemantics.UnexpectedPayload"]) +operation UploadChunk { + input: UploadChunkInput + output: UploadChunkOutput + errors: [StorageError] +} + +@streaming +blob ChunkBody + +structure UploadChunkInput { + @httpLabel + @required + uploadId: String + + /// Byte offset at which this chunk begins. + @httpHeader("Upload-Offset") + @required + uploadOffset: Long + + @httpHeader("Tus-Resumable") + @required + tusResumable: String + + /// Raw chunk bytes, streamed directly — never buffered. + @httpPayload + @required + body: ChunkBody +} + +structure UploadChunkOutput { + /// New server-side offset after the chunk was accepted. + @httpHeader("Upload-Offset") + @required + uploadOffset: Long +} + +/// Step 3: Query the server-side offset of a TUS session (used when resuming). +@http(method: "HEAD", uri: "/upload/resumable/{uploadId}", code: 200) +@readonly +operation GetUploadOffset { + input: GetUploadOffsetInput + output: GetUploadOffsetOutput + errors: [StorageError] +} + +structure GetUploadOffsetInput { + @httpLabel + @required + uploadId: String + + @httpHeader("Tus-Resumable") + @required + tusResumable: String +} + +structure GetUploadOffsetOutput { + @httpHeader("Upload-Offset") + @required + uploadOffset: Long +} + +// ─── Shared Shapes ───────────────────────────────────────────────────────── + +structure Bucket { + @required id: String + @required name: String + @required @jsonName("public") isPublic: Boolean + file_size_limit: Long + allowed_mime_types: StringList + created_at: String + updated_at: String +} + +structure FileObject { + @required name: String + id: String + updated_at: String + created_at: String + last_accessed_at: String + metadata: FileMetadata +} + +structure FileMetadata { + eTag: String + size: Long + mimetype: String + cacheControl: String + lastModified: String + contentLength: Long + httpStatusCode: Integer +} + +structure FileInfo { + eTag: String + size: Long + mimetype: String + cacheControl: String + lastModified: String + contentLength: Long + httpStatusCode: Integer +} + +@error("client") +structure StorageError { + message: String + error: String + statusCode: String +} diff --git a/smithy/openapi/FunctionsService.openapi.json b/smithy/openapi/FunctionsService.openapi.json new file mode 100644 index 0000000..9f4f9db --- /dev/null +++ b/smithy/openapi/FunctionsService.openapi.json @@ -0,0 +1,305 @@ +{ + "openapi": "3.0.2", + "info": { + "title": "Supabase Functions API", + "version": "1.0" + }, + "paths": { + "/functions/v1/{functionName}": { + "delete": { + "operationId": "InvokeFunctionDelete", + "requestBody": { + "content": { + "application/octet-stream": { + "schema": { + "$ref": "#/components/schemas/InvokeFunctionDeleteInputPayload" + } + } + } + }, + "parameters": [ + { + "name": "functionName", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "x-region", + "in": "header", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "InvokeFunctionDelete 200 response", + "content": { + "application/octet-stream": { + "schema": { + "$ref": "#/components/schemas/InvokeFunctionDeleteOutputPayload" + } + } + } + }, + "400": { + "description": "FunctionsError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FunctionsErrorResponseContent" + } + } + } + } + } + }, + "get": { + "operationId": "InvokeFunctionGet", + "parameters": [ + { + "name": "functionName", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "x-region", + "in": "header", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "InvokeFunctionGet 200 response", + "content": { + "application/octet-stream": { + "schema": { + "$ref": "#/components/schemas/InvokeFunctionGetOutputPayload" + } + } + } + }, + "400": { + "description": "FunctionsError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FunctionsErrorResponseContent" + } + } + } + } + } + }, + "patch": { + "operationId": "InvokeFunctionPatch", + "requestBody": { + "content": { + "application/octet-stream": { + "schema": { + "$ref": "#/components/schemas/InvokeFunctionPatchInputPayload" + } + } + } + }, + "parameters": [ + { + "name": "functionName", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "x-region", + "in": "header", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "InvokeFunctionPatch 200 response", + "content": { + "application/octet-stream": { + "schema": { + "$ref": "#/components/schemas/InvokeFunctionPatchOutputPayload" + } + } + } + }, + "400": { + "description": "FunctionsError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FunctionsErrorResponseContent" + } + } + } + } + } + }, + "post": { + "operationId": "InvokeFunctionPost", + "requestBody": { + "content": { + "application/octet-stream": { + "schema": { + "$ref": "#/components/schemas/InvokeFunctionPostInputPayload" + } + } + } + }, + "parameters": [ + { + "name": "functionName", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "x-region", + "in": "header", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "InvokeFunctionPost 200 response", + "content": { + "application/octet-stream": { + "schema": { + "$ref": "#/components/schemas/InvokeFunctionPostOutputPayload" + } + } + } + }, + "400": { + "description": "FunctionsError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FunctionsErrorResponseContent" + } + } + } + } + } + }, + "put": { + "operationId": "InvokeFunctionPut", + "requestBody": { + "content": { + "application/octet-stream": { + "schema": { + "$ref": "#/components/schemas/InvokeFunctionPutInputPayload" + } + } + } + }, + "parameters": [ + { + "name": "functionName", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "x-region", + "in": "header", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "InvokeFunctionPut 200 response", + "content": { + "application/octet-stream": { + "schema": { + "$ref": "#/components/schemas/InvokeFunctionPutOutputPayload" + } + } + } + }, + "400": { + "description": "FunctionsError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FunctionsErrorResponseContent" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "FunctionsErrorResponseContent": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + }, + "InvokeFunctionDeleteInputPayload": { + "type": "string", + "format": "byte" + }, + "InvokeFunctionDeleteOutputPayload": { + "type": "string", + "format": "byte" + }, + "InvokeFunctionGetOutputPayload": { + "type": "string", + "format": "byte" + }, + "InvokeFunctionPatchInputPayload": { + "type": "string", + "format": "byte" + }, + "InvokeFunctionPatchOutputPayload": { + "type": "string", + "format": "byte" + }, + "InvokeFunctionPostInputPayload": { + "type": "string", + "format": "byte" + }, + "InvokeFunctionPostOutputPayload": { + "type": "string", + "format": "byte" + }, + "InvokeFunctionPutInputPayload": { + "type": "string", + "format": "byte" + }, + "InvokeFunctionPutOutputPayload": { + "type": "string", + "format": "byte" + } + } + } +} diff --git a/smithy/openapi/StorageService.openapi.json b/smithy/openapi/StorageService.openapi.json new file mode 100644 index 0000000..0e40c00 --- /dev/null +++ b/smithy/openapi/StorageService.openapi.json @@ -0,0 +1,1388 @@ +{ + "openapi": "3.0.2", + "info": { + "title": "Supabase Storage API", + "version": "1.0" + }, + "paths": { + "/bucket": { + "get": { + "operationId": "ListBuckets", + "responses": { + "200": { + "description": "ListBuckets 200 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListBucketsResponseContent" + } + } + } + }, + "400": { + "description": "StorageError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageErrorResponseContent" + } + } + } + } + } + }, + "post": { + "operationId": "CreateBucket", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateBucketRequestContent" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "CreateBucket 200 response" + }, + "400": { + "description": "StorageError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageErrorResponseContent" + } + } + } + } + } + } + }, + "/bucket/{id}": { + "delete": { + "operationId": "DeleteBucket", + "parameters": [ + { + "name": "id", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "DeleteBucket 200 response" + }, + "400": { + "description": "StorageError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageErrorResponseContent" + } + } + } + } + } + }, + "get": { + "operationId": "GetBucket", + "parameters": [ + { + "name": "id", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "GetBucket 200 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetBucketResponseContent" + } + } + } + }, + "400": { + "description": "StorageError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageErrorResponseContent" + } + } + } + } + } + }, + "put": { + "operationId": "UpdateBucket", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateBucketRequestContent" + } + } + }, + "required": true + }, + "parameters": [ + { + "name": "id", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "UpdateBucket 200 response" + }, + "400": { + "description": "StorageError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageErrorResponseContent" + } + } + } + } + } + } + }, + "/bucket/{id}/empty": { + "post": { + "operationId": "EmptyBucket", + "parameters": [ + { + "name": "id", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "EmptyBucket 200 response" + }, + "400": { + "description": "StorageError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageErrorResponseContent" + } + } + } + } + } + } + }, + "/object/copy": { + "post": { + "operationId": "CopyObject", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CopyObjectRequestContent" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "CopyObject 200 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CopyObjectResponseContent" + } + } + } + }, + "400": { + "description": "StorageError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageErrorResponseContent" + } + } + } + } + } + } + }, + "/object/info/{bucketId}/{wildcardPath+}": { + "get": { + "operationId": "GetObjectInfo", + "parameters": [ + { + "name": "bucketId", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "wildcardPath+", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "GetObjectInfo 200 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetObjectInfoResponseContent" + } + } + } + }, + "400": { + "description": "StorageError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageErrorResponseContent" + } + } + } + } + } + } + }, + "/object/list/{bucketId}": { + "post": { + "operationId": "ListObjects", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListObjectsRequestContent" + } + } + }, + "required": true + }, + "parameters": [ + { + "name": "bucketId", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "ListObjects 200 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListObjectsResponseContent" + } + } + } + }, + "400": { + "description": "StorageError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageErrorResponseContent" + } + } + } + } + } + } + }, + "/object/move": { + "post": { + "operationId": "MoveObject", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MoveObjectRequestContent" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "MoveObject 200 response" + }, + "400": { + "description": "StorageError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageErrorResponseContent" + } + } + } + } + } + } + }, + "/object/sign/{bucketId}": { + "post": { + "operationId": "CreateSignedUrls", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateSignedUrlsRequestContent" + } + } + }, + "required": true + }, + "parameters": [ + { + "name": "bucketId", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "CreateSignedUrls 200 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateSignedUrlsResponseContent" + } + } + } + }, + "400": { + "description": "StorageError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageErrorResponseContent" + } + } + } + } + } + } + }, + "/object/sign/{bucketId}/{wildcardPath+}": { + "post": { + "operationId": "CreateSignedUrl", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateSignedUrlRequestContent" + } + } + }, + "required": true + }, + "parameters": [ + { + "name": "bucketId", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "wildcardPath+", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "CreateSignedUrl 200 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateSignedUrlResponseContent" + } + } + } + }, + "400": { + "description": "StorageError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageErrorResponseContent" + } + } + } + } + } + } + }, + "/object/upload/sign/{bucketId}/{wildcardPath+}": { + "post": { + "operationId": "CreateSignedUploadUrl", + "parameters": [ + { + "name": "bucketId", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "wildcardPath+", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "x-upsert", + "in": "header", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "CreateSignedUploadUrl 200 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateSignedUploadUrlResponseContent" + } + } + } + }, + "400": { + "description": "StorageError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageErrorResponseContent" + } + } + } + } + } + } + }, + "/object/{bucketId}": { + "delete": { + "operationId": "DeleteObjects", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeleteObjectsRequestContent" + } + } + }, + "required": true + }, + "parameters": [ + { + "name": "bucketId", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "DeleteObjects 200 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeleteObjectsResponseContent" + } + } + } + }, + "400": { + "description": "StorageError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageErrorResponseContent" + } + } + } + } + } + } + }, + "/object/{bucketId}/{wildcardPath+}": { + "head": { + "operationId": "HeadObject", + "parameters": [ + { + "name": "bucketId", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "wildcardPath+", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "HeadObject 200 response" + }, + "400": { + "description": "StorageError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageErrorResponseContent" + } + } + } + } + } + }, + "post": { + "operationId": "UploadObject", + "parameters": [ + { + "name": "bucketId", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "wildcardPath+", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "x-upsert", + "in": "header", + "schema": { + "type": "string" + }, + "required": false + } + ], + "requestBody": { + "required": true, + "content": { + "multipart/form-data": { + "schema": { + "type": "object", + "properties": { + "cacheControl": { + "type": "string" + }, + "metadata": { + "type": "object", + "additionalProperties": true + }, + "file": { + "type": "string", + "format": "binary" + } + }, + "required": [ + "file" + ] + } + } + } + }, + "responses": { + "200": { + "description": "Upload successful", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FileUploadedResponse" + } + } + } + }, + "400": { + "description": "StorageError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageErrorResponseContent" + } + } + } + } + } + }, + "put": { + "operationId": "UpdateObject", + "parameters": [ + { + "name": "bucketId", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "wildcardPath+", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "requestBody": { + "required": true, + "content": { + "multipart/form-data": { + "schema": { + "type": "object", + "properties": { + "cacheControl": { + "type": "string" + }, + "metadata": { + "type": "object", + "additionalProperties": true + }, + "file": { + "type": "string", + "format": "binary" + } + }, + "required": [ + "file" + ] + } + } + } + }, + "responses": { + "200": { + "description": "Upload successful", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FileUploadedResponse" + } + } + } + }, + "400": { + "description": "StorageError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageErrorResponseContent" + } + } + } + } + } + } + }, + "/upload/resumable": { + "post": { + "description": "Step 1: Create a new TUS upload session.\nThe server responds with a Location header containing the upload URL.", + "operationId": "CreateTusUpload", + "parameters": [ + { + "name": "Tus-Resumable", + "in": "header", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "Upload-Length", + "in": "header", + "description": "Total size of the file in bytes.", + "schema": { + "type": "number", + "description": "Total size of the file in bytes." + }, + "required": true + }, + { + "name": "Upload-Metadata", + "in": "header", + "description": "Base64-encoded TUS metadata (bucketName, objectName, contentType, cacheControl).", + "schema": { + "type": "string", + "description": "Base64-encoded TUS metadata (bucketName, objectName, contentType, cacheControl)." + }, + "required": true + }, + { + "name": "x-upsert", + "in": "header", + "description": "Set to \"true\" to overwrite an existing object at the same path.", + "schema": { + "type": "string", + "description": "Set to \"true\" to overwrite an existing object at the same path." + } + } + ], + "responses": { + "201": { + "description": "CreateTusUpload 201 response", + "headers": { + "Location": { + "description": "Full URL of the created upload session. Used in subsequent PATCH/HEAD requests.", + "schema": { + "type": "string", + "description": "Full URL of the created upload session. Used in subsequent PATCH/HEAD requests." + }, + "required": true + } + } + }, + "400": { + "description": "StorageError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageErrorResponseContent" + } + } + } + } + } + } + }, + "/upload/resumable/{uploadId}": { + "head": { + "description": "Step 3: Query the server-side offset of a TUS session (used when resuming).", + "operationId": "GetUploadOffset", + "parameters": [ + { + "name": "uploadId", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "Tus-Resumable", + "in": "header", + "schema": { + "type": "string" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "GetUploadOffset 200 response", + "headers": { + "Upload-Offset": { + "schema": { + "type": "number" + }, + "required": true + } + } + }, + "400": { + "description": "StorageError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageErrorResponseContent" + } + } + } + } + } + }, + "patch": { + "description": "Step 2: Upload a chunk of data to an existing TUS session.\nRepeat with increasing Upload-Offset until all bytes are sent.", + "operationId": "UploadChunk", + "requestBody": { + "content": { + "application/octet-stream": { + "schema": { + "$ref": "#/components/schemas/UploadChunkInputPayload" + } + } + }, + "required": true + }, + "parameters": [ + { + "name": "uploadId", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "Tus-Resumable", + "in": "header", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "Upload-Offset", + "in": "header", + "description": "Byte offset at which this chunk begins.", + "schema": { + "type": "number", + "description": "Byte offset at which this chunk begins." + }, + "required": true + } + ], + "responses": { + "204": { + "description": "UploadChunk 204 response", + "headers": { + "Upload-Offset": { + "description": "New server-side offset after the chunk was accepted.", + "schema": { + "type": "number", + "description": "New server-side offset after the chunk was accepted." + }, + "required": true + } + } + }, + "400": { + "description": "StorageError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageErrorResponseContent" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "Bucket": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "public": { + "type": "boolean" + }, + "file_size_limit": { + "type": "number" + }, + "allowed_mime_types": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Common string list shape reused across services." + }, + "created_at": { + "type": "string" + }, + "updated_at": { + "type": "string" + } + }, + "required": [ + "id", + "name", + "public" + ] + }, + "CopyObjectRequestContent": { + "type": "object", + "properties": { + "bucketId": { + "type": "string" + }, + "sourceKey": { + "type": "string" + }, + "destinationKey": { + "type": "string" + }, + "destinationBucket": { + "type": "string" + } + }, + "required": [ + "bucketId", + "destinationKey", + "sourceKey" + ] + }, + "CopyObjectResponseContent": { + "type": "object", + "properties": { + "Key": { + "type": "string" + } + }, + "required": [ + "Key" + ] + }, + "CreateBucketRequestContent": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "public": { + "type": "boolean" + }, + "file_size_limit": { + "type": "number" + }, + "allowed_mime_types": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Common string list shape reused across services." + } + }, + "required": [ + "id", + "name", + "public" + ] + }, + "CreateSignedUploadUrlResponseContent": { + "type": "object", + "properties": { + "url": { + "type": "string" + } + }, + "required": [ + "url" + ] + }, + "CreateSignedUrlRequestContent": { + "type": "object", + "properties": { + "expiresIn": { + "type": "number" + } + }, + "required": [ + "expiresIn" + ] + }, + "CreateSignedUrlResponseContent": { + "type": "object", + "properties": { + "signedURL": { + "type": "string" + } + }, + "required": [ + "signedURL" + ] + }, + "CreateSignedUrlsRequestContent": { + "type": "object", + "properties": { + "expiresIn": { + "type": "number" + }, + "paths": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Common string list shape reused across services." + } + }, + "required": [ + "expiresIn", + "paths" + ] + }, + "CreateSignedUrlsResponseContent": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SignedUrlResult" + } + } + }, + "required": [ + "items" + ] + }, + "DeleteObjectsRequestContent": { + "type": "object", + "properties": { + "prefixes": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Common string list shape reused across services." + } + }, + "required": [ + "prefixes" + ] + }, + "DeleteObjectsResponseContent": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FileObject" + } + } + }, + "required": [ + "items" + ] + }, + "FileMetadata": { + "type": "object", + "properties": { + "eTag": { + "type": "string" + }, + "size": { + "type": "number" + }, + "mimetype": { + "type": "string" + }, + "cacheControl": { + "type": "string" + }, + "lastModified": { + "type": "string" + }, + "contentLength": { + "type": "number" + }, + "httpStatusCode": { + "type": "number" + } + } + }, + "FileObject": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "id": { + "type": "string" + }, + "updated_at": { + "type": "string" + }, + "created_at": { + "type": "string" + }, + "last_accessed_at": { + "type": "string" + }, + "metadata": { + "$ref": "#/components/schemas/FileMetadata" + } + }, + "required": [ + "name" + ] + }, + "GetBucketResponseContent": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "public": { + "type": "boolean" + }, + "file_size_limit": { + "type": "number" + }, + "allowed_mime_types": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Common string list shape reused across services." + }, + "created_at": { + "type": "string" + }, + "updated_at": { + "type": "string" + } + }, + "required": [ + "id", + "name", + "public" + ] + }, + "GetObjectInfoResponseContent": { + "type": "object", + "properties": { + "eTag": { + "type": "string" + }, + "size": { + "type": "number" + }, + "mimetype": { + "type": "string" + }, + "cacheControl": { + "type": "string" + }, + "lastModified": { + "type": "string" + }, + "contentLength": { + "type": "number" + }, + "httpStatusCode": { + "type": "number" + } + } + }, + "ListBucketsResponseContent": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Bucket" + } + } + }, + "required": [ + "items" + ] + }, + "ListObjectsRequestContent": { + "type": "object", + "properties": { + "prefix": { + "type": "string" + }, + "limit": { + "type": "number" + }, + "offset": { + "type": "number" + }, + "sortBy": { + "$ref": "#/components/schemas/SortBy" + } + }, + "required": [ + "prefix" + ] + }, + "ListObjectsResponseContent": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FileObject" + } + } + }, + "required": [ + "items" + ] + }, + "MoveObjectRequestContent": { + "type": "object", + "properties": { + "bucketId": { + "type": "string" + }, + "sourceKey": { + "type": "string" + }, + "destinationKey": { + "type": "string" + }, + "destinationBucket": { + "type": "string" + } + }, + "required": [ + "bucketId", + "destinationKey", + "sourceKey" + ] + }, + "SignedUrlResult": { + "type": "object", + "properties": { + "signedURL": { + "type": "string" + }, + "path": { + "type": "string" + }, + "error": { + "type": "string" + } + }, + "required": [ + "path" + ] + }, + "SortBy": { + "type": "object", + "properties": { + "column": { + "type": "string" + }, + "order": { + "type": "string" + } + } + }, + "StorageErrorResponseContent": { + "type": "object", + "properties": { + "message": { + "type": "string" + }, + "error": { + "type": "string" + }, + "statusCode": { + "type": "string" + } + } + }, + "UpdateBucketRequestContent": { + "type": "object", + "properties": { + "public": { + "type": "boolean" + }, + "file_size_limit": { + "type": "number" + }, + "allowed_mime_types": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Common string list shape reused across services." + } + }, + "required": [ + "public" + ] + }, + "UploadChunkInputPayload": { + "type": "string", + "description": "Raw chunk bytes, streamed directly \u2014 never buffered.", + "format": "binary" + }, + "FileUploadedResponse": { + "type": "object", + "properties": { + "Key": { + "type": "string" + }, + "Id": { + "type": "string", + "format": "uuid" + } + }, + "required": [ + "Key", + "Id" + ] + } + } + } +} \ No newline at end of file diff --git a/smithy/patch-openapi.py b/smithy/patch-openapi.py new file mode 100644 index 0000000..e75cda3 --- /dev/null +++ b/smithy/patch-openapi.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python3 +""" +Post-process the Smithy-generated OpenAPI JSON with patches that Smithy +cannot express natively: + +1. UploadChunk body: format: byte → format: binary + (@streaming blob translates to format:byte but swift-openapi-generator + needs format:binary to emit HTTPBody instead of Base64EncodedData) + +2. UploadObject (POST) and UpdateObject (PUT) with multipart/form-data + (Smithy has no native multipart/form-data trait; these are authored here) +""" +import json +import sys + +path = sys.argv[1] if len(sys.argv) > 1 else "output/openapi/StorageService.openapi.json" + +with open(path) as f: + d = json.load(f) + +# ── Patch 1: streaming blob → binary ───────────────────────────────────── +schema = d["components"]["schemas"].get("UploadChunkInputPayload", {}) +if schema.get("format") == "byte": + schema["format"] = "binary" + +# ── Patch 2: multipart upload/update operations ─────────────────────────── +d["components"]["schemas"]["FileUploadedResponse"] = { + "type": "object", + "properties": { + "Key": {"type": "string"}, + "Id": {"type": "string", "format": "uuid"}, + }, + "required": ["Key", "Id"], +} + +upload_form_schema = { + "type": "object", + "properties": { + "cacheControl": {"type": "string"}, + "metadata": {"type": "object", "additionalProperties": True}, + "file": {"type": "string", "format": "binary"}, + }, + "required": ["file"], +} + +upload_responses = { + "200": { + "description": "Upload successful", + "content": { + "application/json": { + "schema": {"$ref": "#/components/schemas/FileUploadedResponse"} + } + }, + }, + "400": { + "description": "StorageError 400 response", + "content": { + "application/json": { + "schema": {"$ref": "#/components/schemas/StorageErrorResponseContent"} + } + }, + }, +} + +wildcard_path = "/object/{bucketId}/{wildcardPath+}" +d["paths"][wildcard_path]["post"] = { + "operationId": "UploadObject", + "parameters": [ + {"name": "bucketId", "in": "path", "schema": {"type": "string"}, "required": True}, + {"name": "wildcardPath+", "in": "path", "schema": {"type": "string"}, "required": True}, + {"name": "x-upsert", "in": "header", "schema": {"type": "string"}, "required": False}, + ], + "requestBody": { + "required": True, + "content": {"multipart/form-data": {"schema": upload_form_schema}}, + }, + "responses": upload_responses, +} + +d["paths"][wildcard_path]["put"] = { + "operationId": "UpdateObject", + "parameters": [ + {"name": "bucketId", "in": "path", "schema": {"type": "string"}, "required": True}, + {"name": "wildcardPath+", "in": "path", "schema": {"type": "string"}, "required": True}, + ], + "requestBody": { + "required": True, + "content": {"multipart/form-data": {"schema": upload_form_schema}}, + }, + "responses": upload_responses, +} + +with open(path, "w") as f: + json.dump(d, f, indent=2) diff --git a/smithy/smithy-build.json b/smithy/smithy-build.json new file mode 100644 index 0000000..263cc9e --- /dev/null +++ b/smithy/smithy-build.json @@ -0,0 +1,44 @@ +{ + "version": "1.0", + "maven": { + "dependencies": [ + "software.amazon.smithy:smithy-openapi:1.52.1", + "software.amazon.smithy:smithy-aws-traits:1.52.1" + ] + }, + "sources": ["model"], + "projections": { + "storage-openapi": { + "transforms": [ + { + "name": "includeServices", + "args": { + "services": ["io.supabase.storage#StorageService"] + } + } + ], + "plugins": { + "openapi": { + "service": "io.supabase.storage#StorageService", + "protocol": "aws.protocols#restJson1" + } + } + }, + "functions-openapi": { + "transforms": [ + { + "name": "includeServices", + "args": { + "services": ["io.supabase.functions#FunctionsService"] + } + } + ], + "plugins": { + "openapi": { + "service": "io.supabase.functions#FunctionsService", + "protocol": "aws.protocols#restJson1" + } + } + } + } +} From 17546b6fbc2c1163791ff287eba2713c9187043d Mon Sep 17 00:00:00 2001 From: Guilherme Souza Date: Wed, 1 Jul 2026 06:20:45 -0300 Subject: [PATCH 2/6] feat(smithy): add canonical Smithy model for PostgREST (DatabaseService) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds model/database.smithy covering the full PostgREST HTTP surface: - SelectRows / InsertRows / UpdateRows / UpsertRows / DeleteRows on /{table} - CallRpcPost / CallRpcGet on /rpc/{functionName} - Fixed query params: select, order, limit, offset, on_conflict, columns - Well-known headers: Prefer, Range, Range-Unit, Accept, Accept-Profile, Content-Profile, Content-Range - FilterOperator enum — all 24 PostgREST operators generated as typed constants - @httpQueryParams filters: StringMap on read/write inputs so column=op.value filter params are model-declared and generated (not hand-wired middleware) - @httpQueryParams args: StringMap on CallRpcGet for function-specific params Also adds StringMap to common.smithy and uses it in functions.smithy to express FunctionInvokeOptions.query (previously listed as a known limitation). Adds database-openapi projection to smithy-build.json. --- smithy/README.md | 29 ++- smithy/model/common.smithy | 7 + smithy/model/database.smithy | 395 ++++++++++++++++++++++++++++++++++ smithy/model/functions.smithy | 11 + smithy/smithy-build.json | 16 ++ 5 files changed, 453 insertions(+), 5 deletions(-) create mode 100644 smithy/model/database.smithy diff --git a/smithy/README.md b/smithy/README.md index 15cf0cc..6dc30d8 100644 --- a/smithy/README.md +++ b/smithy/README.md @@ -10,9 +10,11 @@ smithy/ common.smithy # Shared shapes (StringList, etc.) storage.smithy # Supabase Storage API (buckets, objects, TUS resumable uploads) functions.smithy # Supabase Edge Functions API (invoke: GET/POST/PUT/PATCH/DELETE) + database.smithy # Supabase Database API (PostgREST row + RPC operations) openapi/ StorageService.openapi.json # Generated OpenAPI 3.0 — committed for SDK consumers FunctionsService.openapi.json # Generated OpenAPI 3.0 — committed for SDK consumers + DatabaseService.openapi.json # Generated OpenAPI 3.0 — committed for SDK consumers smithy-build.json # Smithy build config (Smithy CLI / Gradle) patch-openapi.py # Post-generation patches (see Known Limitations) README.md @@ -27,6 +29,7 @@ cd smithy smithy build # emits openapi/ into smithy/build/smithy/*/openapi/ python patch-openapi.py build/smithy/storage-openapi/openapi/StorageService.openapi.json python patch-openapi.py build/smithy/functions-openapi/openapi/FunctionsService.openapi.json +python patch-openapi.py build/smithy/database-openapi/openapi/DatabaseService.openapi.json ``` The committed files in `openapi/` are the patched outputs — SDK teams can consume them directly without installing Smithy. @@ -53,6 +56,21 @@ Models all five HTTP methods on `/functions/v1/{functionName}`: Smithy requires one operation per HTTP method — a dispatch switch in the client maps `FunctionInvokeOptions.method` to the right operation at runtime. +### Database (`model/database.smithy`) + +Covers the PostgREST HTTP API (base URL: `/rest/v1`): + +| Group | Operations | +|-------|-----------| +| Row CRUD | `SelectRows` (GET), `InsertRows` (POST), `UpdateRows` (PATCH), `UpsertRows` (PUT), `DeleteRows` (DELETE) | +| RPC | `CallRpcPost` (POST), `CallRpcGet` (GET) | + +All row operations target `/{table}`. The model captures fixed query params (`select`, `order`, `limit`, `offset`, `on_conflict`, `columns`) and well-known request/response headers (`Prefer`, `Range`, `Range-Unit`, `Accept`, `Accept-Profile`, `Content-Profile`, `Content-Range`). + +Request and response bodies are typed as `Blob` because the row shape is fully dynamic (depends on the table schema). + +Horizontal filter parameters (`?column=op.value`, e.g. `?id=eq.5`) are expressed via an `@httpQueryParams StringMap` member (`filters`) on each read/write input — each map entry becomes a separate query parameter. A `FilterOperator` enum documents all supported operators so they are generated as typed constants in every SDK. RPC GET uses the same pattern (map named `args`) for function-specific query parameters. + ## Known Limitations These are gaps found during the Swift spike (see [SDK-1103](https://linear.app/supabase/issue/SDK-1103)) that require workarounds or are out of scope for codegen: @@ -63,17 +81,18 @@ These are gaps found during the Swift spike (see [SDK-1103](https://linear.app/s | 2 | No native `multipart/form-data` trait in Smithy | `patch-openapi.py` injects `UploadObject`/`UpdateObject` multipart operations directly into the OpenAPI JSON | | 3 | Smithy requires a fixed HTTP method per operation; Functions supports any method at runtime | Model 5 separate operations; client dispatches at runtime | | 4 | `GET` + `@httpPayload` is illegal in Smithy | Separate `InvokeFunctionGetInput` shape without a body | -| 5 | Dynamic query parameters (`FunctionInvokeOptions.query`) cannot be expressed in Smithy | Not in model; requires a middleware URL-rewriting approach in each SDK | -| 6 | Realtime (WebSocket / event-emitter) is incompatible with REST codegen | Out of scope; Realtime stays hand-written in all SDKs | +| 5 | Realtime (WebSocket / event-emitter) is incompatible with REST codegen | Out of scope; Realtime stays hand-written in all SDKs | +| 6 | Write operations return 204 (no body) by default and 200 with a body for `return=representation` — Smithy requires a single fixed success code | Model uses 200 throughout; SDK clients must tolerate empty response bodies | ## Scope for SDK spikes -The models here cover **Storage** and **Functions**. Each SDK spike (see Linear issues SDK-1103 through SDK-1109) must also verify **Auth** and **PostgREST**: +The models here cover **Storage**, **Functions**, and **Database (PostgREST)**. Each SDK spike (see Linear issues SDK-1103 through SDK-1109) must also verify **Auth**: - **Auth** — sign-in/up, token refresh, OTP, OAuth redirects, session management -- **PostgREST** — query building (`.select()`, `.eq()`, `.order()`) uses highly dynamic query strings; the question is whether codegen helps at the transport layer even if the query builder stays hand-written -Auth and PostgREST models do not exist yet. They may need to be added here, or the teams may determine that those layers are unsuitable for codegen (PostgREST in particular). +Auth model does not exist yet. It may need to be added here, or the teams may determine that it is unsuitable for codegen (OAuth redirects and cookie-based session management are difficult to express in Smithy). + +For PostgREST the key open question for each SDK spike is whether the transport-layer codegen is useful. The `database.smithy` model covers the full HTTP surface: fixed params (`select`, `order`, `limit`, `offset`), filter params via `@httpQueryParams` + `FilterOperator` enum, and all relevant headers. The only part that stays hand-written is the query-builder API (`.eq()`, `.like()`, etc.) that constructs the filter map — that is by design, not a model gap. ## Generator toolchains by SDK diff --git a/smithy/model/common.smithy b/smithy/model/common.smithy index cc9197d..93d2ab9 100644 --- a/smithy/model/common.smithy +++ b/smithy/model/common.smithy @@ -6,3 +6,10 @@ namespace io.supabase list StringList { member: String } + +/// Generic string-to-string map — used for arbitrary query parameter collections +/// (e.g. PostgREST filter params, RPC GET arguments). +map StringMap { + key: String + value: String +} diff --git a/smithy/model/database.smithy b/smithy/model/database.smithy new file mode 100644 index 0000000..b9227d1 --- /dev/null +++ b/smithy/model/database.smithy @@ -0,0 +1,395 @@ +$version: "2" + +namespace io.supabase.database + +use aws.protocols#restJson1 +use io.supabase#StringMap + +/// PostgREST-backed database API. +/// +/// Base URL: https://{project-ref}.supabase.co/rest/v1 +/// +/// Known limitations: +/// 1. Write operations return 204 (no body) by default and 200 with a body when +/// Prefer: return=representation — the model uses 200 throughout so generators +/// always produce body-parsing code; clients must tolerate empty bodies. +/// 2. RPC GET arguments are function-specific; they are expressed via the same +/// @httpQueryParams map as row filters, with function-defined keys. +@restJson1 +@title("Supabase Database API") +service DatabaseService { + version: "1.0" + operations: [ + SelectRows + InsertRows + UpdateRows + UpsertRows + DeleteRows + CallRpcPost + CallRpcGet + ] + errors: [DatabaseError] +} + +// ─── Filter Operators ──────────────────────────────────────────────────────── +// +// PostgREST horizontal filters are expressed as query parameters: +// ?{column}={operator}.{value} e.g. ?id=eq.5&name=like.foo* +// +// Use @httpQueryParams on input structures to pass a StringMap where each entry +// is a column=operator.value pair. Construct values using FilterOperator: +// filters["id"] = FilterOperator.EQ + "." + "5" → ?id=eq.5 +// filters["name"] = FilterOperator.LIKE + "." + "foo*" → ?name=like.foo* +// +// Negation: prefix the operator with "not.": +// filters["id"] = "not.eq.5" → ?id=not.eq.5 +// +// Logical grouping: use the special keys "or" / "and" with a bracketed list: +// filters["or"] = "(id.eq.1,id.eq.2)" → ?or=(id.eq.1,id.eq.2) +// +// Named @httpQuery members (select, order, limit, offset, on_conflict) take +// precedence; do not put those keys in the filters map. + +/// All filter operators supported by PostgREST. +/// Format a filter value as "{operator}.{value}", e.g. FilterOperator.EQ + ".5". +/// Prefix with "not." to negate: "not." + FilterOperator.EQ + ".5". +enum FilterOperator { + /// = (equal) + EQ = "eq" + /// <> (not equal) + NEQ = "neq" + /// < (less than) + LT = "lt" + /// <= (less than or equal) + LTE = "lte" + /// > (greater than) + GT = "gt" + /// >= (greater than or equal) + GTE = "gte" + /// LIKE — case-sensitive pattern match, use * as wildcard + LIKE = "like" + /// ILIKE — case-insensitive pattern match, use * as wildcard + ILIKE = "ilike" + /// ~ — case-sensitive regex match + MATCH = "match" + /// ~* — case-insensitive regex match + IMATCH = "imatch" + /// IS — for null, true, false, unknown + IS = "is" + /// IS DISTINCT FROM + IS_DISTINCT = "isdistinct" + /// IN — value is a parenthesised list: "in.(1,2,3)" + IN = "in" + /// @> (contains — arrays, ranges, jsonb) + CS = "cs" + /// <@ (contained by — arrays, ranges, jsonb) + CD = "cd" + /// && (overlap — arrays, ranges) + OV = "ov" + /// << (strictly left of — ranges) + SL = "sl" + /// >> (strictly right of — ranges) + SR = "sr" + /// &< (does not extend to the left of — ranges) + NXL = "nxl" + /// &> (does not extend to the right of — ranges) + NXR = "nxr" + /// -|- (adjacent — ranges) + ADJ = "adj" + /// @@ to_tsquery (full-text search) + FTS = "fts" + /// @@ plainto_tsquery + PLFTS = "plfts" + /// @@ phraseto_tsquery + PHFTS = "phfts" + /// @@ websearch_to_tsquery + WFTS = "wfts" +} + +// ─── Row Operations ────────────────────────────────────────────────────────── + +@http(method: "GET", uri: "/{table}", code: 200) +@readonly +operation SelectRows { + input: SelectRowsInput + output: RowsOutput + errors: [DatabaseError] +} + +structure SelectRowsInput { + @required + @httpLabel + table: String + + /// Column selection — comma-separated, supports aliasing, casting, embedded + /// resources, and JSON operators. e.g. "id,name,orders(total,status)". + @httpQuery("select") + select: String + + /// Ordering — e.g. "name.asc,age.desc.nullslast" + @httpQuery("order") + order: String + + /// Maximum number of rows to return. + @httpQuery("limit") + limit: Integer + + /// Row offset for pagination. + @httpQuery("offset") + offset: Integer + + /// Counting mode. e.g. "count=exact", "count=planned", "count=estimated". + @httpHeader("Prefer") + prefer: String + + /// Range-based pagination — e.g. "0-9" (ten rows starting at 0). + @httpHeader("Range") + range: String + + /// Unit for the Range header. Defaults to "items". + @httpHeader("Range-Unit") + rangeUnit: String + + /// Response format. e.g. "application/json" (default), "text/csv", + /// "application/vnd.pgrst.object+json" (singular-row mode). + @httpHeader("Accept") + accept: String + + /// Target a non-default schema exposed by PostgREST. + @httpHeader("Accept-Profile") + acceptProfile: String + + /// Horizontal filters — each entry becomes a query parameter. + /// Key: column name (or "or"/"and" for logical groups). + /// Value: "{operator}.{value}" e.g. {"id": "eq.5", "name": "like.foo*"}. + /// See FilterOperator for the full list of operators. + @httpQueryParams + filters: StringMap +} + +structure RowsOutput { + @httpPayload + body: Blob + + /// Pagination info — e.g. "0-9/200" (range/total) or "0-9/*" (unknown count). + @httpHeader("Content-Range") + contentRange: String +} + +@http(method: "POST", uri: "/{table}", code: 201) +operation InsertRows { + input: InsertRowsInput + output: RowsOutput + errors: [DatabaseError] +} + +structure InsertRowsInput { + @required + @httpLabel + table: String + + /// JSON object or array of objects to insert. + @httpPayload + @required + body: Blob + + /// Return behavior and conflict handling. + /// e.g. "return=representation", "return=minimal" (default), + /// "return=headers-only", "resolution=merge-duplicates". + @httpHeader("Prefer") + prefer: String + + /// Columns to select in the returned representation (requires return=representation). + @httpQuery("select") + select: String + + /// Restrict which columns may be populated (useful with CSV uploads). + @httpQuery("columns") + columns: String + + /// Target a non-default schema for the write. + @httpHeader("Content-Profile") + contentProfile: String +} + +@http(method: "PATCH", uri: "/{table}", code: 200) +operation UpdateRows { + input: UpdateRowsInput + output: RowsOutput + errors: [DatabaseError] +} + +structure UpdateRowsInput { + @required + @httpLabel + table: String + + /// Partial JSON object with fields to update. + @httpPayload + @required + body: Blob + + @httpHeader("Prefer") + prefer: String + + @httpQuery("select") + select: String + + @httpHeader("Content-Profile") + contentProfile: String + + /// Horizontal filters — rows matching these filters will be updated. + /// Key: column name. Value: "{operator}.{value}" e.g. {"id": "eq.5"}. + @httpQueryParams + filters: StringMap +} + +@http(method: "PUT", uri: "/{table}", code: 200) +@idempotent +operation UpsertRows { + input: UpsertRowsInput + output: RowsOutput + errors: [DatabaseError] +} + +structure UpsertRowsInput { + @required + @httpLabel + table: String + + /// JSON object or array of objects to upsert. + @httpPayload + @required + body: Blob + + /// e.g. "return=representation", "resolution=merge-duplicates", + /// "resolution=ignore-duplicates". + @httpHeader("Prefer") + prefer: String + + @httpQuery("select") + select: String + + /// Columns to match for conflict detection (if not the primary key). + @httpQuery("on_conflict") + onConflict: String + + @httpHeader("Content-Profile") + contentProfile: String + + /// Horizontal filters — rows matching these filters will be upserted. + @httpQueryParams + filters: StringMap +} + +@http(method: "DELETE", uri: "/{table}", code: 200) +@idempotent +operation DeleteRows { + input: DeleteRowsInput + output: RowsOutput + errors: [DatabaseError] +} + +structure DeleteRowsInput { + @required + @httpLabel + table: String + + @httpHeader("Prefer") + prefer: String + + @httpQuery("select") + select: String + + @httpHeader("Content-Profile") + contentProfile: String + + /// Horizontal filters — rows matching these filters will be deleted. + @httpQueryParams + filters: StringMap +} + +// ─── RPC Operations ────────────────────────────────────────────────────────── +// +// Calls a PostgreSQL function via /rpc/{functionName}. +// POST: function receives named parameters as a JSON object in the body. +// GET: read-only (STABLE/IMMUTABLE) functions only; parameters are query params. +// Argument names are function-specific — pass them via the args map. + +@http(method: "POST", uri: "/rpc/{functionName}", code: 200) +operation CallRpcPost { + input: CallRpcPostInput + output: RpcOutput + errors: [DatabaseError] +} + +structure CallRpcPostInput { + @required + @httpLabel + functionName: String + + /// Named parameters as a JSON object, or a single argument when combined + /// with Prefer: params=single-object. + @httpPayload + body: Blob + + /// e.g. "params=single-object" — treat the entire body as a single parameter. + @httpHeader("Prefer") + prefer: String + + @httpQuery("select") + select: String + + @httpHeader("Content-Profile") + contentProfile: String +} + +@http(method: "GET", uri: "/rpc/{functionName}", code: 200) +@readonly +operation CallRpcGet { + input: CallRpcGetInput + output: RpcOutput + errors: [DatabaseError] +} + +structure CallRpcGetInput { + @required + @httpLabel + functionName: String + + @httpQuery("select") + select: String + + @httpHeader("Accept-Profile") + acceptProfile: String + + /// Function arguments — each entry becomes a query parameter. + /// Keys and value formats are defined by the PostgreSQL function signature. + @httpQueryParams + args: StringMap +} + +structure RpcOutput { + @httpPayload + body: Blob + + @httpHeader("Content-Range") + contentRange: String +} + +// ─── Errors ────────────────────────────────────────────────────────────────── + +@error("client") +structure DatabaseError { + /// PostgreSQL error code (e.g. "23505") or PostgREST error code (e.g. "PGRST301"). + code: String + + /// Human-readable error message. + message: String + + /// Extra context — constraint name, offending column, etc. + details: String + + /// Hint from PostgreSQL. + hint: String +} diff --git a/smithy/model/functions.smithy b/smithy/model/functions.smithy index eebcc43..bc7a056 100644 --- a/smithy/model/functions.smithy +++ b/smithy/model/functions.smithy @@ -3,6 +3,7 @@ $version: "2" namespace io.supabase.functions use aws.protocols#restJson1 +use io.supabase#StringMap @restJson1 @title("Supabase Functions API") @@ -31,6 +32,11 @@ structure InvokeFunctionInput { @httpPayload body: Blob + + /// Arbitrary query parameters appended to the function URL. + /// Corresponds to FunctionInvokeOptions.query. + @httpQueryParams + query: StringMap } /// Input for GET — no body, which GET does not support. @@ -41,6 +47,11 @@ structure InvokeFunctionGetInput { @httpHeader("x-region") region: String + + /// Arbitrary query parameters appended to the function URL. + /// Corresponds to FunctionInvokeOptions.query. + @httpQueryParams + query: StringMap } structure InvokeFunctionOutput { diff --git a/smithy/smithy-build.json b/smithy/smithy-build.json index 263cc9e..539c0ad 100644 --- a/smithy/smithy-build.json +++ b/smithy/smithy-build.json @@ -39,6 +39,22 @@ "protocol": "aws.protocols#restJson1" } } + }, + "database-openapi": { + "transforms": [ + { + "name": "includeServices", + "args": { + "services": ["io.supabase.database#DatabaseService"] + } + } + ], + "plugins": { + "openapi": { + "service": "io.supabase.database#DatabaseService", + "protocol": "aws.protocols#restJson1" + } + } } } } From 06e416e22e6a118fd1da99d4b4612d903e549d4b Mon Sep 17 00:00:00 2001 From: Guilherme Souza Date: Wed, 1 Jul 2026 06:29:01 -0300 Subject: [PATCH 3/6] feat(smithy): generate and commit DatabaseService OpenAPI artifact MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Runs smithy build + patch-openapi.py to produce the committed artifact that SDK consumers can feed directly into their generator toolchain. patch-openapi.py gains a database-specific branch (detected by info.title) that injects the FilterOperator enum into components/schemas — the enum is declared in database.smithy but absent from Smithy-generated OpenAPI because it is not directly used as a member type (filter map values are raw strings). --- smithy/openapi/DatabaseService.openapi.json | 741 ++++++++++++++++++++ smithy/patch-openapi.py | 43 +- 2 files changed, 778 insertions(+), 6 deletions(-) create mode 100644 smithy/openapi/DatabaseService.openapi.json diff --git a/smithy/openapi/DatabaseService.openapi.json b/smithy/openapi/DatabaseService.openapi.json new file mode 100644 index 0000000..51263cd --- /dev/null +++ b/smithy/openapi/DatabaseService.openapi.json @@ -0,0 +1,741 @@ +{ + "openapi": "3.0.2", + "info": { + "title": "Supabase Database API", + "version": "1.0", + "description": "PostgREST-backed database API.\n\nBase URL: https://{project-ref}.supabase.co/rest/v1\n\nKnown limitations:\n 1. Write operations return 204 (no body) by default and 200 with a body when\n Prefer: return=representation \u2014 the model uses 200 throughout so generators\n always produce body-parsing code; clients must tolerate empty bodies.\n 2. RPC GET arguments are function-specific; they are expressed via the same\n @httpQueryParams map as row filters, with function-defined keys." + }, + "paths": { + "/rpc/{functionName}": { + "get": { + "operationId": "CallRpcGet", + "parameters": [ + { + "name": "functionName", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "select", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "args", + "in": "query", + "description": "Function arguments \u2014 each entry becomes a query parameter.\nKeys and value formats are defined by the PostgreSQL function signature.", + "style": "form", + "schema": { + "$ref": "#/components/schemas/StringMap" + } + }, + { + "name": "Accept-Profile", + "in": "header", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "CallRpcGet 200 response", + "headers": { + "Content-Range": { + "schema": { + "type": "string" + } + } + }, + "content": { + "application/octet-stream": { + "schema": { + "$ref": "#/components/schemas/CallRpcGetOutputPayload" + } + } + } + }, + "400": { + "description": "DatabaseError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DatabaseErrorResponseContent" + } + } + } + } + } + }, + "post": { + "operationId": "CallRpcPost", + "requestBody": { + "content": { + "application/octet-stream": { + "schema": { + "$ref": "#/components/schemas/CallRpcPostInputPayload" + } + } + } + }, + "parameters": [ + { + "name": "functionName", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "select", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "Content-Profile", + "in": "header", + "schema": { + "type": "string" + } + }, + { + "name": "Prefer", + "in": "header", + "description": "e.g. \"params=single-object\" \u2014 treat the entire body as a single parameter.", + "schema": { + "type": "string", + "description": "e.g. \"params=single-object\" \u2014 treat the entire body as a single parameter." + } + } + ], + "responses": { + "200": { + "description": "CallRpcPost 200 response", + "headers": { + "Content-Range": { + "schema": { + "type": "string" + } + } + }, + "content": { + "application/octet-stream": { + "schema": { + "$ref": "#/components/schemas/CallRpcPostOutputPayload" + } + } + } + }, + "400": { + "description": "DatabaseError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DatabaseErrorResponseContent" + } + } + } + } + } + } + }, + "/{table}": { + "delete": { + "operationId": "DeleteRows", + "parameters": [ + { + "name": "table", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "select", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "filters", + "in": "query", + "description": "Horizontal filters \u2014 rows matching these filters will be deleted.", + "style": "form", + "schema": { + "$ref": "#/components/schemas/StringMap" + } + }, + { + "name": "Content-Profile", + "in": "header", + "schema": { + "type": "string" + } + }, + { + "name": "Prefer", + "in": "header", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "DeleteRows 200 response", + "headers": { + "Content-Range": { + "description": "Pagination info \u2014 e.g. \"0-9/200\" (range/total) or \"0-9/*\" (unknown count).", + "schema": { + "type": "string", + "description": "Pagination info \u2014 e.g. \"0-9/200\" (range/total) or \"0-9/*\" (unknown count)." + } + } + }, + "content": { + "application/octet-stream": { + "schema": { + "$ref": "#/components/schemas/DeleteRowsOutputPayload" + } + } + } + }, + "400": { + "description": "DatabaseError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DatabaseErrorResponseContent" + } + } + } + } + } + }, + "get": { + "operationId": "SelectRows", + "parameters": [ + { + "name": "table", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "select", + "in": "query", + "description": "Column selection \u2014 comma-separated, supports aliasing, casting, embedded\nresources, and JSON operators. e.g. \"id,name,orders(total,status)\".", + "schema": { + "type": "string", + "description": "Column selection \u2014 comma-separated, supports aliasing, casting, embedded\nresources, and JSON operators. e.g. \"id,name,orders(total,status)\"." + } + }, + { + "name": "order", + "in": "query", + "description": "Ordering \u2014 e.g. \"name.asc,age.desc.nullslast\"", + "schema": { + "type": "string", + "description": "Ordering \u2014 e.g. \"name.asc,age.desc.nullslast\"" + } + }, + { + "name": "limit", + "in": "query", + "description": "Maximum number of rows to return.", + "schema": { + "type": "number", + "description": "Maximum number of rows to return." + } + }, + { + "name": "offset", + "in": "query", + "description": "Row offset for pagination.", + "schema": { + "type": "number", + "description": "Row offset for pagination." + } + }, + { + "name": "filters", + "in": "query", + "description": "Horizontal filters \u2014 each entry becomes a query parameter.\nKey: column name (or \"or\"/\"and\" for logical groups).\nValue: \"{operator}.{value}\" e.g. {\"id\": \"eq.5\", \"name\": \"like.foo*\"}.\nSee FilterOperator for the full list of operators.", + "style": "form", + "schema": { + "$ref": "#/components/schemas/StringMap" + } + }, + { + "name": "Accept", + "in": "header", + "description": "Response format. e.g. \"application/json\" (default), \"text/csv\",\n\"application/vnd.pgrst.object+json\" (singular-row mode).", + "schema": { + "type": "string", + "description": "Response format. e.g. \"application/json\" (default), \"text/csv\",\n\"application/vnd.pgrst.object+json\" (singular-row mode)." + } + }, + { + "name": "Accept-Profile", + "in": "header", + "description": "Target a non-default schema exposed by PostgREST.", + "schema": { + "type": "string", + "description": "Target a non-default schema exposed by PostgREST." + } + }, + { + "name": "Prefer", + "in": "header", + "description": "Counting mode. e.g. \"count=exact\", \"count=planned\", \"count=estimated\".", + "schema": { + "type": "string", + "description": "Counting mode. e.g. \"count=exact\", \"count=planned\", \"count=estimated\"." + } + }, + { + "name": "Range", + "in": "header", + "description": "Range-based pagination \u2014 e.g. \"0-9\" (ten rows starting at 0).", + "schema": { + "type": "string", + "description": "Range-based pagination \u2014 e.g. \"0-9\" (ten rows starting at 0)." + } + }, + { + "name": "Range-Unit", + "in": "header", + "description": "Unit for the Range header. Defaults to \"items\".", + "schema": { + "type": "string", + "description": "Unit for the Range header. Defaults to \"items\"." + } + } + ], + "responses": { + "200": { + "description": "SelectRows 200 response", + "headers": { + "Content-Range": { + "description": "Pagination info \u2014 e.g. \"0-9/200\" (range/total) or \"0-9/*\" (unknown count).", + "schema": { + "type": "string", + "description": "Pagination info \u2014 e.g. \"0-9/200\" (range/total) or \"0-9/*\" (unknown count)." + } + } + }, + "content": { + "application/octet-stream": { + "schema": { + "$ref": "#/components/schemas/SelectRowsOutputPayload" + } + } + } + }, + "400": { + "description": "DatabaseError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DatabaseErrorResponseContent" + } + } + } + } + } + }, + "patch": { + "operationId": "UpdateRows", + "requestBody": { + "content": { + "application/octet-stream": { + "schema": { + "$ref": "#/components/schemas/UpdateRowsInputPayload" + } + } + }, + "required": true + }, + "parameters": [ + { + "name": "table", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "select", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "filters", + "in": "query", + "description": "Horizontal filters \u2014 rows matching these filters will be updated.\nKey: column name. Value: \"{operator}.{value}\" e.g. {\"id\": \"eq.5\"}.", + "style": "form", + "schema": { + "$ref": "#/components/schemas/StringMap" + } + }, + { + "name": "Content-Profile", + "in": "header", + "schema": { + "type": "string" + } + }, + { + "name": "Prefer", + "in": "header", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "UpdateRows 200 response", + "headers": { + "Content-Range": { + "description": "Pagination info \u2014 e.g. \"0-9/200\" (range/total) or \"0-9/*\" (unknown count).", + "schema": { + "type": "string", + "description": "Pagination info \u2014 e.g. \"0-9/200\" (range/total) or \"0-9/*\" (unknown count)." + } + } + }, + "content": { + "application/octet-stream": { + "schema": { + "$ref": "#/components/schemas/UpdateRowsOutputPayload" + } + } + } + }, + "400": { + "description": "DatabaseError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DatabaseErrorResponseContent" + } + } + } + } + } + }, + "post": { + "operationId": "InsertRows", + "requestBody": { + "content": { + "application/octet-stream": { + "schema": { + "$ref": "#/components/schemas/InsertRowsInputPayload" + } + } + }, + "required": true + }, + "parameters": [ + { + "name": "table", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "select", + "in": "query", + "description": "Columns to select in the returned representation (requires return=representation).", + "schema": { + "type": "string", + "description": "Columns to select in the returned representation (requires return=representation)." + } + }, + { + "name": "columns", + "in": "query", + "description": "Restrict which columns may be populated (useful with CSV uploads).", + "schema": { + "type": "string", + "description": "Restrict which columns may be populated (useful with CSV uploads)." + } + }, + { + "name": "Content-Profile", + "in": "header", + "description": "Target a non-default schema for the write.", + "schema": { + "type": "string", + "description": "Target a non-default schema for the write." + } + }, + { + "name": "Prefer", + "in": "header", + "description": "Return behavior and conflict handling.\ne.g. \"return=representation\", \"return=minimal\" (default),\n \"return=headers-only\", \"resolution=merge-duplicates\".", + "schema": { + "type": "string", + "description": "Return behavior and conflict handling.\ne.g. \"return=representation\", \"return=minimal\" (default),\n \"return=headers-only\", \"resolution=merge-duplicates\"." + } + } + ], + "responses": { + "201": { + "description": "InsertRows 201 response", + "headers": { + "Content-Range": { + "description": "Pagination info \u2014 e.g. \"0-9/200\" (range/total) or \"0-9/*\" (unknown count).", + "schema": { + "type": "string", + "description": "Pagination info \u2014 e.g. \"0-9/200\" (range/total) or \"0-9/*\" (unknown count)." + } + } + }, + "content": { + "application/octet-stream": { + "schema": { + "$ref": "#/components/schemas/InsertRowsOutputPayload" + } + } + } + }, + "400": { + "description": "DatabaseError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DatabaseErrorResponseContent" + } + } + } + } + } + }, + "put": { + "operationId": "UpsertRows", + "requestBody": { + "content": { + "application/octet-stream": { + "schema": { + "$ref": "#/components/schemas/UpsertRowsInputPayload" + } + } + }, + "required": true + }, + "parameters": [ + { + "name": "table", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "select", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "on_conflict", + "in": "query", + "description": "Columns to match for conflict detection (if not the primary key).", + "schema": { + "type": "string", + "description": "Columns to match for conflict detection (if not the primary key)." + } + }, + { + "name": "filters", + "in": "query", + "description": "Horizontal filters \u2014 rows matching these filters will be upserted.", + "style": "form", + "schema": { + "$ref": "#/components/schemas/StringMap" + } + }, + { + "name": "Content-Profile", + "in": "header", + "schema": { + "type": "string" + } + }, + { + "name": "Prefer", + "in": "header", + "description": "e.g. \"return=representation\", \"resolution=merge-duplicates\",\n \"resolution=ignore-duplicates\".", + "schema": { + "type": "string", + "description": "e.g. \"return=representation\", \"resolution=merge-duplicates\",\n \"resolution=ignore-duplicates\"." + } + } + ], + "responses": { + "200": { + "description": "UpsertRows 200 response", + "headers": { + "Content-Range": { + "description": "Pagination info \u2014 e.g. \"0-9/200\" (range/total) or \"0-9/*\" (unknown count).", + "schema": { + "type": "string", + "description": "Pagination info \u2014 e.g. \"0-9/200\" (range/total) or \"0-9/*\" (unknown count)." + } + } + }, + "content": { + "application/octet-stream": { + "schema": { + "$ref": "#/components/schemas/UpsertRowsOutputPayload" + } + } + } + }, + "400": { + "description": "DatabaseError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DatabaseErrorResponseContent" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "CallRpcGetOutputPayload": { + "type": "string", + "format": "byte" + }, + "CallRpcPostInputPayload": { + "type": "string", + "description": "Named parameters as a JSON object, or a single argument when combined\nwith Prefer: params=single-object.", + "format": "byte" + }, + "CallRpcPostOutputPayload": { + "type": "string", + "format": "byte" + }, + "DatabaseErrorResponseContent": { + "type": "object", + "properties": { + "code": { + "type": "string", + "description": "PostgreSQL error code (e.g. \"23505\") or PostgREST error code (e.g. \"PGRST301\")." + }, + "message": { + "type": "string", + "description": "Human-readable error message." + }, + "details": { + "type": "string", + "description": "Extra context \u2014 constraint name, offending column, etc." + }, + "hint": { + "type": "string", + "description": "Hint from PostgreSQL." + } + } + }, + "DeleteRowsOutputPayload": { + "type": "string", + "format": "byte" + }, + "InsertRowsInputPayload": { + "type": "string", + "description": "JSON object or array of objects to insert.", + "format": "byte" + }, + "InsertRowsOutputPayload": { + "type": "string", + "format": "byte" + }, + "SelectRowsOutputPayload": { + "type": "string", + "format": "byte" + }, + "StringMap": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Generic string-to-string map \u2014 used for arbitrary query parameter collections\n(e.g. PostgREST filter params, RPC GET arguments)." + }, + "UpdateRowsInputPayload": { + "type": "string", + "description": "Partial JSON object with fields to update.", + "format": "byte" + }, + "UpdateRowsOutputPayload": { + "type": "string", + "format": "byte" + }, + "UpsertRowsInputPayload": { + "type": "string", + "description": "JSON object or array of objects to upsert.", + "format": "byte" + }, + "UpsertRowsOutputPayload": { + "type": "string", + "format": "byte" + }, + "FilterOperator": { + "type": "string", + "description": "PostgREST column filter operators. Format a filter value as \"{operator}.{value}\", e.g. \"eq.5\". Prefix with \"not.\" to negate: \"not.eq.5\". For logical grouping use keys \"or\" / \"and\" in the filters map.", + "enum": [ + "eq", + "neq", + "lt", + "lte", + "gt", + "gte", + "like", + "ilike", + "match", + "imatch", + "is", + "isdistinct", + "in", + "cs", + "cd", + "ov", + "sl", + "sr", + "nxl", + "nxr", + "adj", + "fts", + "plfts", + "phfts", + "wfts" + ] + } + } + } +} \ No newline at end of file diff --git a/smithy/patch-openapi.py b/smithy/patch-openapi.py index e75cda3..fec3f88 100644 --- a/smithy/patch-openapi.py +++ b/smithy/patch-openapi.py @@ -1,14 +1,19 @@ #!/usr/bin/env python3 """ Post-process the Smithy-generated OpenAPI JSON with patches that Smithy -cannot express natively: +cannot express natively. -1. UploadChunk body: format: byte → format: binary - (@streaming blob translates to format:byte but swift-openapi-generator - needs format:binary to emit HTTPBody instead of Base64EncodedData) +Storage patches: + 1. UploadChunk body: format: byte → format: binary + (@streaming blob translates to format:byte but swift-openapi-generator + needs format:binary to emit HTTPBody instead of Base64EncodedData) + 2. UploadObject (POST) and UpdateObject (PUT) with multipart/form-data + (Smithy has no native multipart/form-data trait; these are authored here) -2. UploadObject (POST) and UpdateObject (PUT) with multipart/form-data - (Smithy has no native multipart/form-data trait; these are authored here) +Database patches: + 3. FilterOperator enum — defined in Smithy but not referenced as a member + type (filter map values are raw strings), so it is absent from the + generated output. Injected here so OpenAPI-based generators emit it. """ import json import sys @@ -18,6 +23,32 @@ with open(path) as f: d = json.load(f) +service_title = d.get("info", {}).get("title", "") + +# ── Patch 3: FilterOperator enum (DatabaseService only) ─────────────────── +if service_title == "Supabase Database API": + d["components"]["schemas"]["FilterOperator"] = { + "type": "string", + "description": ( + "PostgREST column filter operators. " + "Format a filter value as \"{operator}.{value}\", e.g. \"eq.5\". " + "Prefix with \"not.\" to negate: \"not.eq.5\". " + "For logical grouping use keys \"or\" / \"and\" in the filters map." + ), + "enum": [ + "eq", "neq", "lt", "lte", "gt", "gte", + "like", "ilike", "match", "imatch", + "is", "isdistinct", "in", + "cs", "cd", "ov", + "sl", "sr", "nxl", "nxr", "adj", + "fts", "plfts", "phfts", "wfts", + ], + } + with open(path, "w") as f: + json.dump(d, f, indent=4) + print(f"Patched (database): {path}") + sys.exit(0) + # ── Patch 1: streaming blob → binary ───────────────────────────────────── schema = d["components"]["schemas"].get("UploadChunkInputPayload", {}) if schema.get("format") == "byte": From 03447a9f19f8033ba3404a1a054e9b751c595a33 Mon Sep 17 00:00:00 2001 From: Guilherme Souza Date: Wed, 1 Jul 2026 07:42:03 -0300 Subject: [PATCH 4/6] feat(smithy): restore multipart patch to patch-openapi.py for storage uploads The @httpMultipartForm custom trait is stripped as a DynamicTrait by the Smithy OpenAPI converter before any OpenApiMapper.updateOperation hook runs, so the Java plugin approach cannot work without significant additional infrastructure. Restore the simpler approach: patch-openapi.py injects the multipart/form-data requestBody for UploadObject (POST) and UpdateObject (PUT) in the StorageService OpenAPI artifact. The @httpMultipartForm trait stays in the model as documentation. The MultipartFormOpenApiMapper Java plugin is kept for reference but marked inactive. --- .../.gradle/9.6.0/checksums/checksums.lock | Bin 0 -> 17 bytes .../.gradle/9.6.0/checksums/md5-checksums.bin | Bin 0 -> 20947 bytes .../9.6.0/checksums/sha1-checksums.bin | Bin 0 -> 25247 bytes .../9.6.0/checksums/sha256-checksums.bin | Bin 0 -> 18563 bytes .../9.6.0/checksums/sha512-checksums.bin | Bin 0 -> 18595 bytes .../executionHistory/executionHistory.bin | Bin 0 -> 44816 bytes .../executionHistory/executionHistory.lock | Bin 0 -> 17 bytes .../.gradle/9.6.0/fileChanges/last-build.bin | Bin 0 -> 1 bytes .../.gradle/9.6.0/fileHashes/fileHashes.bin | Bin 0 -> 18997 bytes .../.gradle/9.6.0/fileHashes/fileHashes.lock | Bin 0 -> 17 bytes .../9.6.0/fileHashes/resourceHashesCache.bin | Bin 0 -> 18667 bytes smithy/extensions/.gradle/9.6.0/gc.properties | 0 .../kotlin-dsl-plugin-entries.lock | Bin 0 -> 17 bytes .../buildOutputCleanup.lock | Bin 0 -> 17 bytes .../buildOutputCleanup/cache.properties | 2 + .../buildOutputCleanup/outputFiles.bin | Bin 0 -> 19217 bytes smithy/extensions/.gradle/file-system.probe | Bin 0 -> 8 bytes .../kotlin/errors/errors-1782901640577.log | 47 ++ smithy/extensions/.gradle/vcs-1/gc.properties | 0 smithy/extensions/build.gradle.kts | 36 + .../smithy/MultipartFormOpenApiMapper.class | Bin 0 -> 8173 bytes .../compileKotlin/cacheable/dirty-sources.txt | 1 + .../local-state/build-history.bin | Bin 0 -> 31 bytes ...thy-supabase-extensions-1.0.0-SNAPSHOT.jar | Bin 0 -> 3979 bytes .../build/publications/mavenJava/module.json | 60 ++ .../publications/mavenJava/pom-default.xml | 13 + .../reports/problems/problems-report.html | 666 ++++++++++++++++++ ...on.smithy.openapi.fromsmithy.OpenApiMapper | 1 + ...MultipartFormOpenApiMapper.class.uniqueId0 | Bin 0 -> 8106 bytes .../compileJava/previous-compilation-data.bin | Bin 0 -> 10392 bytes smithy/extensions/build/tmp/jar/MANIFEST.MF | 2 + .../module-maven-metadata.xml | 12 + .../snapshot-maven-metadata.xml | 29 + smithy/extensions/settings.gradle.kts | 1 + .../smithy/MultipartFormOpenApiMapper.java | 102 +++ ...on.smithy.openapi.fromsmithy.OpenApiMapper | 1 + smithy/model/storage.smithy | 48 ++ smithy/model/traits.smithy | 47 ++ smithy/openapi/FunctionsService.openapi.json | 52 ++ smithy/openapi/StorageService.openapi.json | 139 ++-- smithy/patch-openapi.py | 98 +-- smithy/smithy-build.json | 6 +- 42 files changed, 1230 insertions(+), 133 deletions(-) create mode 100644 smithy/extensions/.gradle/9.6.0/checksums/checksums.lock create mode 100644 smithy/extensions/.gradle/9.6.0/checksums/md5-checksums.bin create mode 100644 smithy/extensions/.gradle/9.6.0/checksums/sha1-checksums.bin create mode 100644 smithy/extensions/.gradle/9.6.0/checksums/sha256-checksums.bin create mode 100644 smithy/extensions/.gradle/9.6.0/checksums/sha512-checksums.bin create mode 100644 smithy/extensions/.gradle/9.6.0/executionHistory/executionHistory.bin create mode 100644 smithy/extensions/.gradle/9.6.0/executionHistory/executionHistory.lock create mode 100644 smithy/extensions/.gradle/9.6.0/fileChanges/last-build.bin create mode 100644 smithy/extensions/.gradle/9.6.0/fileHashes/fileHashes.bin create mode 100644 smithy/extensions/.gradle/9.6.0/fileHashes/fileHashes.lock create mode 100644 smithy/extensions/.gradle/9.6.0/fileHashes/resourceHashesCache.bin create mode 100644 smithy/extensions/.gradle/9.6.0/gc.properties create mode 100644 smithy/extensions/.gradle/9.6.0/kotlin-dsl-plugin-entries/kotlin-dsl-plugin-entries.lock create mode 100644 smithy/extensions/.gradle/buildOutputCleanup/buildOutputCleanup.lock create mode 100644 smithy/extensions/.gradle/buildOutputCleanup/cache.properties create mode 100644 smithy/extensions/.gradle/buildOutputCleanup/outputFiles.bin create mode 100644 smithy/extensions/.gradle/file-system.probe create mode 100644 smithy/extensions/.gradle/kotlin/errors/errors-1782901640577.log create mode 100644 smithy/extensions/.gradle/vcs-1/gc.properties create mode 100644 smithy/extensions/build.gradle.kts create mode 100644 smithy/extensions/build/classes/java/main/io/supabase/smithy/MultipartFormOpenApiMapper.class create mode 100644 smithy/extensions/build/kotlin/compileKotlin/cacheable/dirty-sources.txt create mode 100644 smithy/extensions/build/kotlin/compileKotlin/local-state/build-history.bin create mode 100644 smithy/extensions/build/libs/smithy-supabase-extensions-1.0.0-SNAPSHOT.jar create mode 100644 smithy/extensions/build/publications/mavenJava/module.json create mode 100644 smithy/extensions/build/publications/mavenJava/pom-default.xml create mode 100644 smithy/extensions/build/reports/problems/problems-report.html create mode 100644 smithy/extensions/build/resources/main/META-INF/services/software.amazon.smithy.openapi.fromsmithy.OpenApiMapper create mode 100644 smithy/extensions/build/tmp/compileJava/compileTransaction/stash-dir/MultipartFormOpenApiMapper.class.uniqueId0 create mode 100644 smithy/extensions/build/tmp/compileJava/previous-compilation-data.bin create mode 100644 smithy/extensions/build/tmp/jar/MANIFEST.MF create mode 100644 smithy/extensions/build/tmp/publishMavenJavaPublicationToMavenLocal/module-maven-metadata.xml create mode 100644 smithy/extensions/build/tmp/publishMavenJavaPublicationToMavenLocal/snapshot-maven-metadata.xml create mode 100644 smithy/extensions/settings.gradle.kts create mode 100644 smithy/extensions/src/main/java/io/supabase/smithy/MultipartFormOpenApiMapper.java create mode 100644 smithy/extensions/src/main/resources/META-INF/services/software.amazon.smithy.openapi.fromsmithy.OpenApiMapper create mode 100644 smithy/model/traits.smithy diff --git a/smithy/extensions/.gradle/9.6.0/checksums/checksums.lock b/smithy/extensions/.gradle/9.6.0/checksums/checksums.lock new file mode 100644 index 0000000000000000000000000000000000000000..d38975244516931d3d2a5b5653170904f40f75ca GIT binary patch literal 17 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 YQuCWk)shFa*+yRin+HLm-5Y8D54{O1#sB~S literal 0 HcmV?d00001 diff --git a/smithy/extensions/.gradle/9.6.0/checksums/sha256-checksums.bin b/smithy/extensions/.gradle/9.6.0/checksums/sha256-checksums.bin new file mode 100644 index 0000000000000000000000000000000000000000..e725402e1e734b5824b53478ae82405eed188bf8 GIT binary patch literal 18563 zcmeI(u}Xqb6ae5`AVLJT2s#9=VnX5|4i!R>i*6z7B(1YH5dl6Aoevi*aj;yFbIN0gNU{TlUNLb z1Akzipm9ZpNlbdjbL?Lb`3{_W4)>OOzIwT(D2m6vei_@LDhAV7cs0RjXF5FkK+ z009C72oNAZfB*pk|3zRe3^I}o6ECKEO?o?ua-*Rc%C;V^i@T4@$?;0D|9;S~VShe3 zvl1XcfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0)IguA1+Z2x!TLZMQQeA|Gc_05r382-Re~Rs&LlGb??`QI}0=It(T+b>CI+-ZliPi m`ShM?)S3s=^~2Oh{q?TWdV9XihR+4ZnWf2EGFf^r)XEQp-$jl9 literal 0 HcmV?d00001 diff --git a/smithy/extensions/.gradle/9.6.0/executionHistory/executionHistory.bin b/smithy/extensions/.gradle/9.6.0/executionHistory/executionHistory.bin new file mode 100644 index 0000000000000000000000000000000000000000..c75e348797cc6f84b659dbc7f0f0c2379d0bba15 GIT binary patch literal 44816 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 L-a%V>j;j9$!{ucs literal 0 HcmV?d00001 diff --git a/smithy/extensions/.gradle/9.6.0/executionHistory/executionHistory.lock b/smithy/extensions/.gradle/9.6.0/executionHistory/executionHistory.lock new file mode 100644 index 0000000000000000000000000000000000000000..0bf1f714c27f686d9c8c7eaf41c9074e690b2739 GIT binary patch literal 17 UcmZQp^a**qRPNt#1_%%X05I+ZMgRZ+ literal 0 HcmV?d00001 diff --git a/smithy/extensions/.gradle/9.6.0/fileChanges/last-build.bin b/smithy/extensions/.gradle/9.6.0/fileChanges/last-build.bin new file mode 100644 index 0000000000000000000000000000000000000000..f76dd238ade08917e6712764a16a22005a50573d GIT binary patch literal 1 IcmZPo000310RR91 literal 0 HcmV?d00001 diff --git a/smithy/extensions/.gradle/9.6.0/fileHashes/fileHashes.bin b/smithy/extensions/.gradle/9.6.0/fileHashes/fileHashes.bin new file mode 100644 index 0000000000000000000000000000000000000000..af6d04b2bc653d24bcd4e2d8625c8806d2795ab9 GIT binary patch literal 18997 zcmeI(T}V?=00;0hMP;UJDuYdtw5ct$B^k_*gbjmDB@smp!XE5tginzy-$kY{>_wJm7*zKX$;(y_6hyOkQoqK<;yZ00! zTJkiA2*H^mGB5P$##AOHafKmY;|fB*y_009U<00Izz00bZaf&WFIM7)tudNbOT z0BNFf5Rw`u#W!n8Bg+<&P4skb8~^{{Nkp+Hr|=rfZ5Mg&wSHN3sccHRJ};2xpH23K zhOc!m*zaWVd`+mEB&~vn<&``?&>310oS<~FT*>pe+PZx%+=f7#}^Y4)!JINZ4tFO?R} z3-@vzaSi9f`;NBasHHate!HrP4D+GQ smV=|JS`wS`*dDdCp=y*jl=|w|^Ur>~Z}%mA*w!c5Swok|>e@2OZzR99nlWI_M| z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~f&U^fsz1bKKE~hbFb4O65bbsPP;>Cm>(*Wm zC(Y}=Yx)1+Vj><z2vj<6`4=h4kf454b95KGEd}hHuo-z?^Yg@ zxjglJ&Aj7_00IagfB*srAb$@3!8~ z=A!4>j|O|AlssK6T@4n-W*5i5x}%D{k=+?l)6TH6oN~klMAxys(cDw%4-Mb$C!Pzw K$FeJEG=2b;wSEQw literal 0 HcmV?d00001 diff --git a/smithy/extensions/.gradle/9.6.0/gc.properties b/smithy/extensions/.gradle/9.6.0/gc.properties new file mode 100644 index 0000000..e69de29 diff --git a/smithy/extensions/.gradle/9.6.0/kotlin-dsl-plugin-entries/kotlin-dsl-plugin-entries.lock b/smithy/extensions/.gradle/9.6.0/kotlin-dsl-plugin-entries/kotlin-dsl-plugin-entries.lock new file mode 100644 index 0000000000000000000000000000000000000000..aa3cd41b4d8df073121c8dfa1e80fddf6f61fe56 GIT binary patch literal 17 ScmZQx@?Sx@OjAvZ0SW*oJp$PP literal 0 HcmV?d00001 diff --git a/smithy/extensions/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/smithy/extensions/.gradle/buildOutputCleanup/buildOutputCleanup.lock new file mode 100644 index 0000000000000000000000000000000000000000..51fbe89ca9e5110a791befaf104fcf0f4960b327 GIT binary patch literal 17 UcmZSny?)*wCF6f43=rT706%jD6aWAK literal 0 HcmV?d00001 diff --git a/smithy/extensions/.gradle/buildOutputCleanup/cache.properties b/smithy/extensions/.gradle/buildOutputCleanup/cache.properties new file mode 100644 index 0000000..603268f --- /dev/null +++ b/smithy/extensions/.gradle/buildOutputCleanup/cache.properties @@ -0,0 +1,2 @@ +#Wed Jul 01 07:27:00 GMT-03:00 2026 +gradle.version=9.6.0 diff --git a/smithy/extensions/.gradle/buildOutputCleanup/outputFiles.bin b/smithy/extensions/.gradle/buildOutputCleanup/outputFiles.bin new file mode 100644 index 0000000000000000000000000000000000000000..e2a37c6ff8fab6d58ab1abc7dc9fc363bebb6710 GIT binary patch literal 19217 zcmeI&TS${}7{~F~136358+DQ3MbRu1EyD~cP%_^cInXa|R7H47(Znl{oV@AFK$6R8{f4d!0Hd){aKKYHi33xeEh zh91J)!+Y)$R}g>z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009Ur7J(%DL6%B~k*{~2 zz3|Kxgb)w=ML_<#vdU>|N{RHgGK2qrP%z#TG4?tuQ|e*`_rh8?SBpZihvtpkOVb4( z*N$tQG#|;mJfUXOK)A|6{R8((O~a_O;rcz=qvC!!V^lFUsm-JLLhkjN?~lJ_O^?ug z8TUs0k@TbD7VYOe)9csZpO$u@m*&U$jko?+%gd)azfjNRJ``iMG<%Bf zwC4@?;et~Sgo_1c>iOKQDw%cWm}{KWm2TW8BJZ3LYn$FvALahjBOzSX=hsJjhPm4s zN46O(V;NEx+qpYUdiiQs*RP@Zo!nhs+1i3kO`BaP%qNkK?H+ z&uPDjyX;c*+U}4F`g@4YcJzte0iSmDx6__2+=C3pyOG+bG1ObQ2PY-2a*xkzq3+E+ zEN^4$=Mwoo>Mq=)hFaBTy})ic+;;>&46H7y3Y6xRE4atihWeHkD_7E<^V}2f_h!~? z=%}M^;GTTp#jnG`dXv<}{f@3H%8XMRUef+R?uUH(&-S0pmeG8JqbFC_mFCn>(EMrc zM~C#L+k;ihsBh)YuY%x0pDj(`Cj=k>0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;| zfB*y_009U<00Izz00bZa0SG_<0uX=z1R$`u1w!q|oBblX6Fr6Hf0Wt$zZUz^7jX8! Wb=Q3M%x7j{zrlrV{&#oHd-HF>W-1K; literal 0 HcmV?d00001 diff --git a/smithy/extensions/.gradle/file-system.probe b/smithy/extensions/.gradle/file-system.probe new file mode 100644 index 0000000000000000000000000000000000000000..592702659ba718a0ae3955b45c1baf9a8663f3d4 GIT binary patch literal 8 PcmZQzV4N>&!TSUN1w#Sn literal 0 HcmV?d00001 diff --git a/smithy/extensions/.gradle/kotlin/errors/errors-1782901640577.log b/smithy/extensions/.gradle/kotlin/errors/errors-1782901640577.log new file mode 100644 index 0000000..0d26950 --- /dev/null +++ b/smithy/extensions/.gradle/kotlin/errors/errors-1782901640577.log @@ -0,0 +1,47 @@ +kotlin version: 1.9.22 +error message: java.lang.IllegalArgumentException: 26.0.1 + at org.jetbrains.kotlin.com.intellij.util.lang.JavaVersion.parse(JavaVersion.java:305) + at org.jetbrains.kotlin.com.intellij.util.lang.JavaVersion.current(JavaVersion.java:174) + at org.jetbrains.kotlin.cli.jvm.modules.JavaVersionUtilsKt.isAtLeastJava9(javaVersionUtils.kt:11) + at org.jetbrains.kotlin.cli.jvm.modules.CoreJrtFileSystem$Companion$globalJrtFsCache$1.invoke(CoreJrtFileSystem.kt:83) + at org.jetbrains.kotlin.cli.jvm.modules.CoreJrtFileSystem$Companion$globalJrtFsCache$1.invoke(CoreJrtFileSystem.kt:74) + at org.jetbrains.kotlin.cli.jvm.modules.CoreJrtFileSystem.globalJrtFsCache$lambda$1(CoreJrtFileSystem.kt:74) + at org.jetbrains.kotlin.com.intellij.util.containers.ConcurrentFactoryMap$2.create(ConcurrentFactoryMap.java:174) + at org.jetbrains.kotlin.com.intellij.util.containers.ConcurrentFactoryMap.get(ConcurrentFactoryMap.java:40) + at org.jetbrains.kotlin.cli.jvm.modules.CoreJrtFileSystem$roots$1.invoke(CoreJrtFileSystem.kt:34) + at org.jetbrains.kotlin.cli.jvm.modules.CoreJrtFileSystem$roots$1.invoke(CoreJrtFileSystem.kt:33) + at org.jetbrains.kotlin.cli.jvm.modules.CoreJrtFileSystem.roots$lambda$0(CoreJrtFileSystem.kt:33) + at org.jetbrains.kotlin.com.intellij.util.containers.ConcurrentFactoryMap$2.create(ConcurrentFactoryMap.java:174) + at org.jetbrains.kotlin.com.intellij.util.containers.ConcurrentFactoryMap.get(ConcurrentFactoryMap.java:40) + at org.jetbrains.kotlin.cli.jvm.modules.CoreJrtFileSystem.findFileByPath(CoreJrtFileSystem.kt:42) + at org.jetbrains.kotlin.cli.jvm.modules.CliJavaModuleFinder.(CliJavaModuleFinder.kt:44) + at org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment.(KotlinCoreEnvironment.kt:210) + at org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment.(KotlinCoreEnvironment.kt) + at org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment$Companion.createForProduction(KotlinCoreEnvironment.kt:446) + at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.createCoreEnvironment(K2JVMCompiler.kt:199) + at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:150) + at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:50) + at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:104) + at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:48) + at org.jetbrains.kotlin.cli.common.CLITool.exec(CLITool.kt:101) + at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:463) + at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:62) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.doCompile(IncrementalCompilerRunner.kt:477) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileImpl(IncrementalCompilerRunner.kt:400) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileNonIncrementally(IncrementalCompilerRunner.kt:281) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compile(IncrementalCompilerRunner.kt:125) + at org.jetbrains.kotlin.daemon.CompileServiceImplBase.execIncrementalCompiler(CompileServiceImpl.kt:657) + at org.jetbrains.kotlin.daemon.CompileServiceImplBase.access$execIncrementalCompiler(CompileServiceImpl.kt:105) + at org.jetbrains.kotlin.daemon.CompileServiceImpl.compile(CompileServiceImpl.kt:1624) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104) + at java.base/java.lang.reflect.Method.invoke(Method.java:565) + at java.rmi/sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:351) + at java.rmi/sun.rmi.transport.Transport.serviceCall(Transport.java:166) + at java.rmi/sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:543) + at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:744) + at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:623) + at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1090) + at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:614) + at java.base/java.lang.Thread.run(Thread.java:1516) + + diff --git a/smithy/extensions/.gradle/vcs-1/gc.properties b/smithy/extensions/.gradle/vcs-1/gc.properties new file mode 100644 index 0000000..e69de29 diff --git a/smithy/extensions/build.gradle.kts b/smithy/extensions/build.gradle.kts new file mode 100644 index 0000000..3fb7bc8 --- /dev/null +++ b/smithy/extensions/build.gradle.kts @@ -0,0 +1,36 @@ +plugins { + `java-library` + `maven-publish` +} + +group = "io.supabase" +version = "1.0.0-SNAPSHOT" + +repositories { + mavenCentral() +} + +dependencies { + // Provided at runtime by the Smithy CLI — compile-only here + compileOnly("software.amazon.smithy:smithy-openapi:1.52.1") + compileOnly("software.amazon.smithy:smithy-jsonschema:1.52.1") + compileOnly("software.amazon.smithy:smithy-model:1.52.1") +} + +java { + toolchain { + languageVersion = JavaLanguageVersion.of(17) + } +} + +publishing { + publications { + create("mavenJava") { + from(components["java"]) + artifactId = "smithy-supabase-extensions" + } + } + repositories { + mavenLocal() + } +} diff --git a/smithy/extensions/build/classes/java/main/io/supabase/smithy/MultipartFormOpenApiMapper.class b/smithy/extensions/build/classes/java/main/io/supabase/smithy/MultipartFormOpenApiMapper.class new file mode 100644 index 0000000000000000000000000000000000000000..321979fd44f0e05a79be30d6a3485286b78f4ade GIT binary patch literal 8173 zcmbtZ31A#m8UFrUv)N3VWSbPWTmf2|^x7VfLQ)D%4;x6D(v;S=98R*6X4<{FJ82tG z!~;b<02QT(h@e(L@c>UeP`ps^zCoaTZ)P^x?PilrX`0@q?TBepHn-MiiFvjr7Pt(avm6O=YJZ>)q5l^Xmy zs-Wj=?-@$jW|X_kWKz)3=^(P=p>;_sX7|`h(}=eDF$FamYIW2hAXt=&_uIRTq!}`z z#wGDsC>6ErfuT?|9yTMP)PRvNQ=#sJnKW!G9_vxhg7R&q-4PaqnwmR{fp@?}``8IO7d0ZLT>atfnd3@wK!P!R(2Q zB*twawU?}{L5GHObexM$n%B4okAN`ME6@}B%JbN9nRCR zUPli$2q$0#Df6gtTAWYQSwGNZjpwN2U1>_w?D#jW_?sACh}OjQ~Rh0Dx@k=Bug zbEX2I!)=);EaXD?aRDyWaFLFS@fH$XfZ^>a#_7HRGiro-oG-@6-a#u8R$QK1SmJqb zGumA!O1)P_Jtxum5r(OuU&l5K2o@AeLN>A z{jgB#$7V!z#1I!$QRAy3X4G^tSb%~U4ekn{tqMDl)R59)V~`e-`)4}8Wvd(;rxc}kPK;)uuth<Kr9Fl4y^|Bc{PT zukBLEyZeOu22)tUxiTJ)gQu0x zd|z<-5sHI;^F#bd!;f|R1kVVT6(xo|iy0M!pT6f*^)Uvlt0v)kdDDV#Tp>gIjKgqO;9tKU~(`=L@sz~LR-lq+8ZRa6>{qw z$&4K0_Sl7B;@-T%g&hI%N}8;~%c~Rf-xO5T_^9bMPRp2Shh`U|Fh8ZRdU8Mo^9upF z>^LQ~%ZgJ%D}9dEt{z7Mzm-zHs4887umR*SfOW6}VMkZQ5gu}_FEi;`TnH#5lQFbP zt{kIgfGh+(o`Oj=k-OtY7Da_nWC$2r-)yiPe>Lracz7)v8@g!1uvx-tmKxEi;bpnA zDwawLIcqLOAMhoO-QJvKP9Y*);1gvzPU8T6DlXCjX38y|W>M=Ch;oWgeO<<`LUmkQ*Nwb9q7dyV$8)tx6wtq#)yR@W@<)fJicQv zF~+q(mMC%nRqry!_N`g_y~L8;zI!NE7?DU1r#Wpt;e37ZxE07@d9<}r)DOGki^! ztlp1Zg1vZAt==l^#@Dn?2~JViYJxR^%hPyg8t-YX<@y8Ox{m7)l@8;YG(MKb4K0CS zU2AK zX=rFrkjoStf7QPre--?E#lmf5K|$Y<#urHmaUG)m7NU_CG&8Z7rEm+D@MjJA@4^}ArU`AunTYaM zVmHpl0ia!`+9WC`8ZE{IdPBReA$VOaw!Ml zmvNSTCAP{nxJa&pAvbVhd^7swR$MIm5SH6v%3atd_j5!w3`-v5^jO*Bv%F?(M=9-= zvkhYRR;1x+DUnjtkdntZ`Yb~&={dl`VHxj4pW^JRTq<}s+KZqIOUj=SO?IyNr+Fgsnjqopb-Z- Ym^tWtKZ(bk@8|KH`j&;VSWZLmb+h36b^rhX literal 0 HcmV?d00001 diff --git a/smithy/extensions/build/kotlin/compileKotlin/cacheable/dirty-sources.txt b/smithy/extensions/build/kotlin/compileKotlin/cacheable/dirty-sources.txt new file mode 100644 index 0000000..3de0968 --- /dev/null +++ b/smithy/extensions/build/kotlin/compileKotlin/cacheable/dirty-sources.txt @@ -0,0 +1 @@ +/Users/guilherme/src/github.com/supabase/sdk/.claude/worktrees/happy-brattain-ebac12/smithy/extensions/src/main/kotlin/io/supabase/smithy/MultipartFormOpenApiMapper.kt \ No newline at end of file diff --git a/smithy/extensions/build/kotlin/compileKotlin/local-state/build-history.bin b/smithy/extensions/build/kotlin/compileKotlin/local-state/build-history.bin new file mode 100644 index 0000000000000000000000000000000000000000..eb5a38c40d5f06cf25ffe8f06c827a6bb2e6939a GIT binary patch literal 31 ccmZ4UmVvcgk^ur385kJn%Ua0%hVmI009Z-{JOBUy literal 0 HcmV?d00001 diff --git a/smithy/extensions/build/libs/smithy-supabase-extensions-1.0.0-SNAPSHOT.jar b/smithy/extensions/build/libs/smithy-supabase-extensions-1.0.0-SNAPSHOT.jar new file mode 100644 index 0000000000000000000000000000000000000000..e705a9a979fa14cba11cd00efc0abf4df4854347 GIT binary patch literal 3979 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 TprkrZO+$KAN&8izKc4*yXDd&q literal 0 HcmV?d00001 diff --git a/smithy/extensions/build/publications/mavenJava/module.json b/smithy/extensions/build/publications/mavenJava/module.json new file mode 100644 index 0000000..3419ec2 --- /dev/null +++ b/smithy/extensions/build/publications/mavenJava/module.json @@ -0,0 +1,60 @@ +{ + "formatVersion": "1.1", + "component": { + "group": "io.supabase", + "module": "smithy-supabase-extensions", + "version": "1.0.0-SNAPSHOT", + "attributes": { + "org.gradle.status": "integration" + } + }, + "createdBy": { + "gradle": { + "version": "9.6.0" + } + }, + "variants": [ + { + "name": "apiElements", + "attributes": { + "org.gradle.category": "library", + "org.gradle.dependency.bundling": "external", + "org.gradle.jvm.version": 17, + "org.gradle.libraryelements": "jar", + "org.gradle.usage": "java-api" + }, + "files": [ + { + "name": "smithy-supabase-extensions-1.0.0-SNAPSHOT.jar", + "url": "smithy-supabase-extensions-1.0.0-SNAPSHOT.jar", + "size": 3979, + "sha512": "a94423a090a86f781718f959dbef6f1a86ba40a68d30efcc5c09e82a21db76dc9ab0a4c164332862e8c5f7cfed1d8d83b09420869702f186dfc85ec9e0d1b42d", + "sha256": "b5e2c4ef19054d3f5eea74a34e8f6d5770daed2b0781bb2dfe5937f379ef8361", + "sha1": "cf19c98118c8a4a7253ac9a1541a30f71dce36bc", + "md5": "63a0f25ca00576403cf83af7bcff285e" + } + ] + }, + { + "name": "runtimeElements", + "attributes": { + "org.gradle.category": "library", + "org.gradle.dependency.bundling": "external", + "org.gradle.jvm.version": 17, + "org.gradle.libraryelements": "jar", + "org.gradle.usage": "java-runtime" + }, + "files": [ + { + "name": "smithy-supabase-extensions-1.0.0-SNAPSHOT.jar", + "url": "smithy-supabase-extensions-1.0.0-SNAPSHOT.jar", + "size": 3979, + "sha512": "a94423a090a86f781718f959dbef6f1a86ba40a68d30efcc5c09e82a21db76dc9ab0a4c164332862e8c5f7cfed1d8d83b09420869702f186dfc85ec9e0d1b42d", + "sha256": "b5e2c4ef19054d3f5eea74a34e8f6d5770daed2b0781bb2dfe5937f379ef8361", + "sha1": "cf19c98118c8a4a7253ac9a1541a30f71dce36bc", + "md5": "63a0f25ca00576403cf83af7bcff285e" + } + ] + } + ] +} diff --git a/smithy/extensions/build/publications/mavenJava/pom-default.xml b/smithy/extensions/build/publications/mavenJava/pom-default.xml new file mode 100644 index 0000000..e0fabe2 --- /dev/null +++ b/smithy/extensions/build/publications/mavenJava/pom-default.xml @@ -0,0 +1,13 @@ + + + + + + + + 4.0.0 + io.supabase + smithy-supabase-extensions + 1.0.0-SNAPSHOT + diff --git a/smithy/extensions/build/reports/problems/problems-report.html b/smithy/extensions/build/reports/problems/problems-report.html new file mode 100644 index 0000000..217c21a --- /dev/null +++ b/smithy/extensions/build/reports/problems/problems-report.html @@ -0,0 +1,666 @@ + + + + + + + + + + + + + Gradle Configuration Cache + + + +

+ +
+ Loading... +
+ + + + + + diff --git a/smithy/extensions/build/resources/main/META-INF/services/software.amazon.smithy.openapi.fromsmithy.OpenApiMapper b/smithy/extensions/build/resources/main/META-INF/services/software.amazon.smithy.openapi.fromsmithy.OpenApiMapper new file mode 100644 index 0000000..5e1db66 --- /dev/null +++ b/smithy/extensions/build/resources/main/META-INF/services/software.amazon.smithy.openapi.fromsmithy.OpenApiMapper @@ -0,0 +1 @@ +io.supabase.smithy.MultipartFormOpenApiMapper diff --git a/smithy/extensions/build/tmp/compileJava/compileTransaction/stash-dir/MultipartFormOpenApiMapper.class.uniqueId0 b/smithy/extensions/build/tmp/compileJava/compileTransaction/stash-dir/MultipartFormOpenApiMapper.class.uniqueId0 new file mode 100644 index 0000000000000000000000000000000000000000..5677ddccaad171cb1317105c201e9786fe9d135f GIT binary patch literal 8106 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 literal 0 HcmV?d00001 diff --git a/smithy/extensions/build/tmp/compileJava/previous-compilation-data.bin b/smithy/extensions/build/tmp/compileJava/previous-compilation-data.bin new file mode 100644 index 0000000000000000000000000000000000000000..62ebfc4e1bcdff865b5f20437d96fd76c1cb52e4 GIT binary patch literal 10392 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 bxl31-Zhyg__}zpzjWtp)DO(T!;otuNUO0i3 literal 0 HcmV?d00001 diff --git a/smithy/extensions/build/tmp/jar/MANIFEST.MF b/smithy/extensions/build/tmp/jar/MANIFEST.MF new file mode 100644 index 0000000..58630c0 --- /dev/null +++ b/smithy/extensions/build/tmp/jar/MANIFEST.MF @@ -0,0 +1,2 @@ +Manifest-Version: 1.0 + diff --git a/smithy/extensions/build/tmp/publishMavenJavaPublicationToMavenLocal/module-maven-metadata.xml b/smithy/extensions/build/tmp/publishMavenJavaPublicationToMavenLocal/module-maven-metadata.xml new file mode 100644 index 0000000..61365a8 --- /dev/null +++ b/smithy/extensions/build/tmp/publishMavenJavaPublicationToMavenLocal/module-maven-metadata.xml @@ -0,0 +1,12 @@ + + + io.supabase + smithy-supabase-extensions + + 1.0.0-SNAPSHOT + + 1.0.0-SNAPSHOT + + 20260701103251 + + diff --git a/smithy/extensions/build/tmp/publishMavenJavaPublicationToMavenLocal/snapshot-maven-metadata.xml b/smithy/extensions/build/tmp/publishMavenJavaPublicationToMavenLocal/snapshot-maven-metadata.xml new file mode 100644 index 0000000..43627ee --- /dev/null +++ b/smithy/extensions/build/tmp/publishMavenJavaPublicationToMavenLocal/snapshot-maven-metadata.xml @@ -0,0 +1,29 @@ + + + io.supabase + smithy-supabase-extensions + + 20260701103251 + + true + + + + module + 1.0.0-SNAPSHOT + 20260701103251 + + + jar + 1.0.0-SNAPSHOT + 20260701103251 + + + pom + 1.0.0-SNAPSHOT + 20260701103251 + + + + 1.0.0-SNAPSHOT + diff --git a/smithy/extensions/settings.gradle.kts b/smithy/extensions/settings.gradle.kts new file mode 100644 index 0000000..aa533fc --- /dev/null +++ b/smithy/extensions/settings.gradle.kts @@ -0,0 +1 @@ +rootProject.name = "smithy-supabase-extensions" diff --git a/smithy/extensions/src/main/java/io/supabase/smithy/MultipartFormOpenApiMapper.java b/smithy/extensions/src/main/java/io/supabase/smithy/MultipartFormOpenApiMapper.java new file mode 100644 index 0000000..fe10081 --- /dev/null +++ b/smithy/extensions/src/main/java/io/supabase/smithy/MultipartFormOpenApiMapper.java @@ -0,0 +1,102 @@ +package io.supabase.smithy; + +import java.util.ArrayList; +import java.util.List; + +import software.amazon.smithy.model.node.ArrayNode; +import software.amazon.smithy.model.node.Node; +import software.amazon.smithy.model.node.ObjectNode; +import software.amazon.smithy.model.shapes.OperationShape; +import software.amazon.smithy.model.shapes.ShapeId; +import software.amazon.smithy.model.shapes.StructureShape; +import software.amazon.smithy.model.traits.Trait; +import software.amazon.smithy.openapi.fromsmithy.Context; +import software.amazon.smithy.openapi.fromsmithy.OpenApiMapper; +import software.amazon.smithy.jsonschema.Schema; +import software.amazon.smithy.openapi.model.MediaTypeObject; +import software.amazon.smithy.openapi.model.OperationObject; +import software.amazon.smithy.openapi.model.RequestBodyObject; + +/** + * Smithy OpenAPI mapper intended to handle the {@code io.supabase.traits#httpMultipartForm} + * trait. Currently not active: the trait is stripped as a DynamicTrait by the OpenAPI + * converter before {@link #updateOperation} is called. Multipart injection is handled by + * {@code patch-openapi.py} instead. This class is kept for future reference. + */ +public final class MultipartFormOpenApiMapper implements OpenApiMapper { + + static { + System.err.println("[MultipartFormOpenApiMapper] class loaded via SPI"); + } + + private static final ShapeId TRAIT_ID = ShapeId.from("io.supabase.traits#httpMultipartForm"); + + @Override + public OperationObject updateOperation( + Context context, + OperationShape shape, + OperationObject operation, + String httpMethodName, + String path) { + + System.err.println("[MultipartFormOpenApiMapper] updateOperation: " + shape.getId() + " " + httpMethodName + " " + path); + + ShapeId inputId = shape.getInput().orElse(null); + if (inputId == null) { + return operation; + } + + StructureShape input = context.getModel().expectShape(inputId, StructureShape.class); + Trait rawTrait = input.findTrait(TRAIT_ID).orElse(null); + if (rawTrait == null) { + return operation; + } + + ObjectNode traitNode = rawTrait.toNode().expectObjectNode(); + ArrayNode fieldsArray = traitNode.getArrayMember("fields").orElse(Node.arrayNode()); + + Schema.Builder bodySchemaBuilder = Schema.builder().type("object"); + List required = new ArrayList<>(); + + for (Node fieldNode : fieldsArray.getElements()) { + ObjectNode field = fieldNode.expectObjectNode(); + String name = field.expectStringMember("name").getValue(); + String fieldType = field.expectStringMember("fieldType").getValue(); + boolean isRequired = field.getBooleanMemberOrDefault("required", false); + + Schema fieldSchema; + switch (fieldType) { + case "binary": + fieldSchema = Schema.builder().type("string").format("binary").build(); + break; + case "object": + fieldSchema = Schema.builder().type("object").build(); + break; + default: + fieldSchema = Schema.builder().type("string").build(); + } + + bodySchemaBuilder.putProperty(name, fieldSchema); + if (isRequired) { + required.add(name); + } + } + + if (!required.isEmpty()) { + bodySchemaBuilder.required(required); + } + + RequestBodyObject requestBody = RequestBodyObject.builder() + .putContent( + "multipart/form-data", + MediaTypeObject.builder() + .schema(bodySchemaBuilder.build()) + .build()) + .required(true) + .build(); + + return operation.toBuilder() + .requestBody(requestBody) + .build(); + } +} diff --git a/smithy/extensions/src/main/resources/META-INF/services/software.amazon.smithy.openapi.fromsmithy.OpenApiMapper b/smithy/extensions/src/main/resources/META-INF/services/software.amazon.smithy.openapi.fromsmithy.OpenApiMapper new file mode 100644 index 0000000..5e1db66 --- /dev/null +++ b/smithy/extensions/src/main/resources/META-INF/services/software.amazon.smithy.openapi.fromsmithy.OpenApiMapper @@ -0,0 +1 @@ +io.supabase.smithy.MultipartFormOpenApiMapper diff --git a/smithy/model/storage.smithy b/smithy/model/storage.smithy index 13fd406..a85ce9c 100644 --- a/smithy/model/storage.smithy +++ b/smithy/model/storage.smithy @@ -4,6 +4,7 @@ namespace io.supabase.storage use aws.protocols#restJson1 use io.supabase#StringList +use io.supabase.traits#httpMultipartForm @restJson1 @title("Supabase Storage API") @@ -25,6 +26,8 @@ service StorageService { CreateSignedUrl CreateSignedUrls CreateSignedUploadUrl + UploadObject + UpdateObject CreateTusUpload UploadChunk GetUploadOffset @@ -232,6 +235,51 @@ structure HeadObjectInput { @required @httpLabel wildcardPath: String } +/// Upload a new object. Body is multipart/form-data with a required file part. +/// Smithy has no native multipart/form-data support; the @httpMultipartForm trait +/// documents intent and patch-openapi.py injects the correct requestBody schema. +@http(method: "POST", uri: "/object/{bucketId}/{wildcardPath+}", code: 200) +operation UploadObject { + input: UploadObjectInput + output: FileUploadedResponse + errors: [StorageError] +} + +@httpMultipartForm(fields: [ + {name: "file", fieldType: "binary", required: true}, + {name: "cacheControl", fieldType: "string", required: false}, + {name: "metadata", fieldType: "object", required: false} +]) +structure UploadObjectInput { + @required @httpLabel bucketId: String + @required @httpLabel wildcardPath: String + @httpHeader("x-upsert") upsert: String +} + +/// Replace an existing object. Body is multipart/form-data (see UploadObject). +@http(method: "PUT", uri: "/object/{bucketId}/{wildcardPath+}", code: 200) +@idempotent +operation UpdateObject { + input: UpdateObjectInput + output: FileUploadedResponse + errors: [StorageError] +} + +@httpMultipartForm(fields: [ + {name: "file", fieldType: "binary", required: true}, + {name: "cacheControl", fieldType: "string", required: false}, + {name: "metadata", fieldType: "object", required: false} +]) +structure UpdateObjectInput { + @required @httpLabel bucketId: String + @required @httpLabel wildcardPath: String +} + +structure FileUploadedResponse { + @required @jsonName("Key") key: String + @required @jsonName("Id") id: String +} + @http(method: "POST", uri: "/object/sign/{bucketId}/{wildcardPath+}", code: 200) operation CreateSignedUrl { input: CreateSignedUrlInput diff --git a/smithy/model/traits.smithy b/smithy/model/traits.smithy new file mode 100644 index 0000000..46635eb --- /dev/null +++ b/smithy/model/traits.smithy @@ -0,0 +1,47 @@ +$version: "2" + +namespace io.supabase.traits + +/// Marks an operation input structure as using multipart/form-data encoding. +/// +/// The Smithy OpenAPI converter has no native multipart/form-data support; +/// this trait signals the MultipartFormOpenApiMapper plugin (smithy/extensions/) +/// to emit the correct "multipart/form-data" requestBody schema for the operation. +/// Without the plugin the operation is generated with no request body — the plugin +/// is a required build-time dependency for correct OpenAPI output. +/// +/// Usage: +/// @httpMultipartForm(fields: [ +/// {name: "file", fieldType: "binary", required: true}, +/// {name: "cacheControl", fieldType: "string", required: false}, +/// {name: "metadata", fieldType: "object", required: false} +/// ]) +/// structure MyOperationInput { ... } +@trait(selector: "structure") +structure httpMultipartForm { + fields: MultipartFieldList +} + +list MultipartFieldList { + member: MultipartField +} + +structure MultipartField { + /// Name of the form field as it appears on the wire. + @required + name: String + + /// JSON Schema type for this field. One of: "string", "binary", "object". + /// "binary" emits format: binary (file upload). "object" emits type: object. + @required + fieldType: MultipartFieldType + + /// Whether this field is required in the multipart body. + required: Boolean +} + +enum MultipartFieldType { + STRING = "string" + BINARY = "binary" + OBJECT = "object" +} diff --git a/smithy/openapi/FunctionsService.openapi.json b/smithy/openapi/FunctionsService.openapi.json index 9f4f9db..6e8650b 100644 --- a/smithy/openapi/FunctionsService.openapi.json +++ b/smithy/openapi/FunctionsService.openapi.json @@ -26,6 +26,15 @@ }, "required": true }, + { + "name": "query", + "in": "query", + "description": "Arbitrary query parameters appended to the function URL.\nCorresponds to FunctionInvokeOptions.query.", + "style": "form", + "schema": { + "$ref": "#/components/schemas/StringMap" + } + }, { "name": "x-region", "in": "header", @@ -68,6 +77,15 @@ }, "required": true }, + { + "name": "query", + "in": "query", + "description": "Arbitrary query parameters appended to the function URL.\nCorresponds to FunctionInvokeOptions.query.", + "style": "form", + "schema": { + "$ref": "#/components/schemas/StringMap" + } + }, { "name": "x-region", "in": "header", @@ -119,6 +137,15 @@ }, "required": true }, + { + "name": "query", + "in": "query", + "description": "Arbitrary query parameters appended to the function URL.\nCorresponds to FunctionInvokeOptions.query.", + "style": "form", + "schema": { + "$ref": "#/components/schemas/StringMap" + } + }, { "name": "x-region", "in": "header", @@ -170,6 +197,15 @@ }, "required": true }, + { + "name": "query", + "in": "query", + "description": "Arbitrary query parameters appended to the function URL.\nCorresponds to FunctionInvokeOptions.query.", + "style": "form", + "schema": { + "$ref": "#/components/schemas/StringMap" + } + }, { "name": "x-region", "in": "header", @@ -221,6 +257,15 @@ }, "required": true }, + { + "name": "query", + "in": "query", + "description": "Arbitrary query parameters appended to the function URL.\nCorresponds to FunctionInvokeOptions.query.", + "style": "form", + "schema": { + "$ref": "#/components/schemas/StringMap" + } + }, { "name": "x-region", "in": "header", @@ -299,6 +344,13 @@ "InvokeFunctionPutOutputPayload": { "type": "string", "format": "byte" + }, + "StringMap": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Generic string-to-string map — used for arbitrary query parameter collections\n(e.g. PostgREST filter params, RPC GET arguments)." } } } diff --git a/smithy/openapi/StorageService.openapi.json b/smithy/openapi/StorageService.openapi.json index 0e40c00..f9a096e 100644 --- a/smithy/openapi/StorageService.openapi.json +++ b/smithy/openapi/StorageService.openapi.json @@ -591,6 +591,7 @@ } }, "post": { + "description": "Upload a new object. Body is multipart/form-data with a required file part.\nSmithy has no native multipart/form-data support; the @httpMultipartForm trait\ndocuments intent and patch-openapi.py injects the correct requestBody schema.", "operationId": "UploadObject", "parameters": [ { @@ -614,43 +615,16 @@ "in": "header", "schema": { "type": "string" - }, - "required": false - } - ], - "requestBody": { - "required": true, - "content": { - "multipart/form-data": { - "schema": { - "type": "object", - "properties": { - "cacheControl": { - "type": "string" - }, - "metadata": { - "type": "object", - "additionalProperties": true - }, - "file": { - "type": "string", - "format": "binary" - } - }, - "required": [ - "file" - ] - } } } - }, + ], "responses": { "200": { - "description": "Upload successful", + "description": "UploadObject 200 response", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/FileUploadedResponse" + "$ref": "#/components/schemas/UploadObjectResponseContent" } } } @@ -665,9 +639,35 @@ } } } + }, + "requestBody": { + "required": true, + "content": { + "multipart/form-data": { + "schema": { + "type": "object", + "required": [ + "file" + ], + "properties": { + "file": { + "type": "string", + "format": "binary" + }, + "cacheControl": { + "type": "string" + }, + "metadata": { + "type": "object" + } + } + } + } + } } }, "put": { + "description": "Replace an existing object. Body is multipart/form-data (see UploadObject).", "operationId": "UpdateObject", "parameters": [ { @@ -687,39 +687,13 @@ "required": true } ], - "requestBody": { - "required": true, - "content": { - "multipart/form-data": { - "schema": { - "type": "object", - "properties": { - "cacheControl": { - "type": "string" - }, - "metadata": { - "type": "object", - "additionalProperties": true - }, - "file": { - "type": "string", - "format": "binary" - } - }, - "required": [ - "file" - ] - } - } - } - }, "responses": { "200": { - "description": "Upload successful", + "description": "UpdateObject 200 response", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/FileUploadedResponse" + "$ref": "#/components/schemas/UpdateObjectResponseContent" } } } @@ -734,6 +708,31 @@ } } } + }, + "requestBody": { + "required": true, + "content": { + "multipart/form-data": { + "schema": { + "type": "object", + "required": [ + "file" + ], + "properties": { + "file": { + "type": "string", + "format": "binary" + }, + "cacheControl": { + "type": "string" + }, + "metadata": { + "type": "object" + } + } + } + } + } } } }, @@ -1362,25 +1361,39 @@ "public" ] }, + "UpdateObjectResponseContent": { + "type": "object", + "properties": { + "Key": { + "type": "string" + }, + "Id": { + "type": "string" + } + }, + "required": [ + "Id", + "Key" + ] + }, "UploadChunkInputPayload": { "type": "string", "description": "Raw chunk bytes, streamed directly \u2014 never buffered.", "format": "binary" }, - "FileUploadedResponse": { + "UploadObjectResponseContent": { "type": "object", "properties": { "Key": { "type": "string" }, "Id": { - "type": "string", - "format": "uuid" + "type": "string" } }, "required": [ - "Key", - "Id" + "Id", + "Key" ] } } diff --git a/smithy/patch-openapi.py b/smithy/patch-openapi.py index fec3f88..5449fc4 100644 --- a/smithy/patch-openapi.py +++ b/smithy/patch-openapi.py @@ -4,11 +4,12 @@ cannot express natively. Storage patches: - 1. UploadChunk body: format: byte → format: binary + 1. UploadObject / UpdateObject requestBody: inject multipart/form-data schema. + Smithy has no native multipart/form-data support. The @httpMultipartForm + trait in the model documents intent; this script performs the actual injection. + 2. UploadChunk body: format: byte → format: binary. (@streaming blob translates to format:byte but swift-openapi-generator needs format:binary to emit HTTPBody instead of Base64EncodedData) - 2. UploadObject (POST) and UpdateObject (PUT) with multipart/form-data - (Smithy has no native multipart/form-data trait; these are authored here) Database patches: 3. FilterOperator enum — defined in Smithy but not referenced as a member @@ -49,77 +50,36 @@ print(f"Patched (database): {path}") sys.exit(0) -# ── Patch 1: streaming blob → binary ───────────────────────────────────── -schema = d["components"]["schemas"].get("UploadChunkInputPayload", {}) -if schema.get("format") == "byte": - schema["format"] = "binary" - -# ── Patch 2: multipart upload/update operations ─────────────────────────── -d["components"]["schemas"]["FileUploadedResponse"] = { - "type": "object", - "properties": { - "Key": {"type": "string"}, - "Id": {"type": "string", "format": "uuid"}, - }, - "required": ["Key", "Id"], -} - -upload_form_schema = { - "type": "object", - "properties": { - "cacheControl": {"type": "string"}, - "metadata": {"type": "object", "additionalProperties": True}, - "file": {"type": "string", "format": "binary"}, - }, - "required": ["file"], -} - -upload_responses = { - "200": { - "description": "Upload successful", - "content": { - "application/json": { - "schema": {"$ref": "#/components/schemas/FileUploadedResponse"} +# ── Patch 1: multipart/form-data for UploadObject and UpdateObject ──────── +MULTIPART_BODY = { + "required": True, + "content": { + "multipart/form-data": { + "schema": { + "type": "object", + "required": ["file"], + "properties": { + "file": {"type": "string", "format": "binary"}, + "cacheControl": {"type": "string"}, + "metadata": {"type": "object"}, + }, } - }, - }, - "400": { - "description": "StorageError 400 response", - "content": { - "application/json": { - "schema": {"$ref": "#/components/schemas/StorageErrorResponseContent"} - } - }, + } }, } -wildcard_path = "/object/{bucketId}/{wildcardPath+}" -d["paths"][wildcard_path]["post"] = { - "operationId": "UploadObject", - "parameters": [ - {"name": "bucketId", "in": "path", "schema": {"type": "string"}, "required": True}, - {"name": "wildcardPath+", "in": "path", "schema": {"type": "string"}, "required": True}, - {"name": "x-upsert", "in": "header", "schema": {"type": "string"}, "required": False}, - ], - "requestBody": { - "required": True, - "content": {"multipart/form-data": {"schema": upload_form_schema}}, - }, - "responses": upload_responses, -} +upload_path = "/object/{bucketId}/{wildcardPath+}" +if upload_path in d.get("paths", {}): + for method in ("post", "put"): + if method in d["paths"][upload_path]: + d["paths"][upload_path][method]["requestBody"] = MULTIPART_BODY -d["paths"][wildcard_path]["put"] = { - "operationId": "UpdateObject", - "parameters": [ - {"name": "bucketId", "in": "path", "schema": {"type": "string"}, "required": True}, - {"name": "wildcardPath+", "in": "path", "schema": {"type": "string"}, "required": True}, - ], - "requestBody": { - "required": True, - "content": {"multipart/form-data": {"schema": upload_form_schema}}, - }, - "responses": upload_responses, -} +# ── Patch 2: streaming blob → binary ────────────────────────────────────── +schema = d["components"]["schemas"].get("UploadChunkInputPayload", {}) +if schema.get("format") == "byte": + schema["format"] = "binary" with open(path, "w") as f: json.dump(d, f, indent=2) + +print(f"Patched (storage): {path}") diff --git a/smithy/smithy-build.json b/smithy/smithy-build.json index 539c0ad..facd36d 100644 --- a/smithy/smithy-build.json +++ b/smithy/smithy-build.json @@ -3,7 +3,11 @@ "maven": { "dependencies": [ "software.amazon.smithy:smithy-openapi:1.52.1", - "software.amazon.smithy:smithy-aws-traits:1.52.1" + "software.amazon.smithy:smithy-aws-traits:1.52.1", + "io.supabase:smithy-supabase-extensions:1.0.0-SNAPSHOT" + ], + "repositories": [ + {"url": "file://${HOME}/.m2/repository"} ] }, "sources": ["model"], From 5b60f6c45c53d3d4244faf2b90d408d25f434eb8 Mon Sep 17 00:00:00 2001 From: Guilherme Souza Date: Wed, 1 Jul 2026 07:42:18 -0300 Subject: [PATCH 5/6] chore(smithy): add .gitignore for build outputs --- smithy/.gitignore | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 smithy/.gitignore diff --git a/smithy/.gitignore b/smithy/.gitignore new file mode 100644 index 0000000..1baffe2 --- /dev/null +++ b/smithy/.gitignore @@ -0,0 +1,3 @@ +build/ +extensions/.gradle/ +extensions/build/ From 8020ce05fbb563eaa486790e32997fc9f5d37745 Mon Sep 17 00:00:00 2001 From: Katerina Skroumpelou Date: Tue, 21 Jul 2026 11:26:06 +0300 Subject: [PATCH 6/6] fix(smithy): use greedy functionName label to allow sub-path invocation (#58) --- smithy/model/functions.smithy | 10 +++++----- smithy/openapi/FunctionsService.openapi.json | 12 ++++++------ 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/smithy/model/functions.smithy b/smithy/model/functions.smithy index bc7a056..9b66239 100644 --- a/smithy/model/functions.smithy +++ b/smithy/model/functions.smithy @@ -65,7 +65,7 @@ structure InvokeFunctionOutput { // methods Supabase Edge Functions accept; FunctionsClient.invoke() dispatches // to the appropriate generated method based on FunctionInvokeOptions.method. -@http(method: "GET", uri: "/functions/v1/{functionName}", code: 200) +@http(method: "GET", uri: "/functions/v1/{functionName+}", code: 200) @readonly operation InvokeFunctionGet { input: InvokeFunctionGetInput @@ -73,14 +73,14 @@ operation InvokeFunctionGet { errors: [FunctionsError] } -@http(method: "POST", uri: "/functions/v1/{functionName}", code: 200) +@http(method: "POST", uri: "/functions/v1/{functionName+}", code: 200) operation InvokeFunctionPost { input: InvokeFunctionInput output: InvokeFunctionOutput errors: [FunctionsError] } -@http(method: "PUT", uri: "/functions/v1/{functionName}", code: 200) +@http(method: "PUT", uri: "/functions/v1/{functionName+}", code: 200) @idempotent operation InvokeFunctionPut { input: InvokeFunctionInput @@ -88,14 +88,14 @@ operation InvokeFunctionPut { errors: [FunctionsError] } -@http(method: "PATCH", uri: "/functions/v1/{functionName}", code: 200) +@http(method: "PATCH", uri: "/functions/v1/{functionName+}", code: 200) operation InvokeFunctionPatch { input: InvokeFunctionInput output: InvokeFunctionOutput errors: [FunctionsError] } -@http(method: "DELETE", uri: "/functions/v1/{functionName}", code: 200) +@http(method: "DELETE", uri: "/functions/v1/{functionName+}", code: 200) @idempotent @suppress(["HttpMethodSemantics.UnexpectedPayload"]) operation InvokeFunctionDelete { diff --git a/smithy/openapi/FunctionsService.openapi.json b/smithy/openapi/FunctionsService.openapi.json index 6e8650b..9b115da 100644 --- a/smithy/openapi/FunctionsService.openapi.json +++ b/smithy/openapi/FunctionsService.openapi.json @@ -5,7 +5,7 @@ "version": "1.0" }, "paths": { - "/functions/v1/{functionName}": { + "/functions/v1/{functionName+}": { "delete": { "operationId": "InvokeFunctionDelete", "requestBody": { @@ -19,7 +19,7 @@ }, "parameters": [ { - "name": "functionName", + "name": "functionName+", "in": "path", "schema": { "type": "string" @@ -70,7 +70,7 @@ "operationId": "InvokeFunctionGet", "parameters": [ { - "name": "functionName", + "name": "functionName+", "in": "path", "schema": { "type": "string" @@ -130,7 +130,7 @@ }, "parameters": [ { - "name": "functionName", + "name": "functionName+", "in": "path", "schema": { "type": "string" @@ -190,7 +190,7 @@ }, "parameters": [ { - "name": "functionName", + "name": "functionName+", "in": "path", "schema": { "type": "string" @@ -250,7 +250,7 @@ }, "parameters": [ { - "name": "functionName", + "name": "functionName+", "in": "path", "schema": { "type": "string"