feat!: align with Iceberg REST OpenAPI spec for v1#48
Merged
Conversation
jgoux
approved these changes
May 18, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Aligns the client with the Apache Iceberg REST Catalog OpenAPI spec ahead of the 1.0.0 release, fixes #32 by replacing the static
catalogNameflow with the spec-recommendedwarehouse->GET /v1/config->prefixflow, and adds a spec-conformance test layer so we cannot silently drift from the spec going forward.What changed
Spec alignment (breaking)
listNamespacesandlistTablesnow take an options bag and return paginated objects:listNamespaces({ parent?, pageToken?, pageSize? }) -> { namespaces, nextPageToken? }listTables(namespace, { pageToken?, pageSize? }) -> { identifiers, nextPageToken? }updateTablebody is the spec-aligned{ requirements?, updates }shape. The legacy{ properties }/{ schema }shorthand is replaced byTableUpdatevariants (e.g.{ action: 'set-properties', updates: {...} }).commitTableis added as a spec-named alias./v1/config+warehouse(closes #32)warehouseconstructor option. On first use the client callsGET /v1/config?warehouse=...once and uses the server-returnedoverrides.prefix(falling back todefaults.prefix, then to the warehouse string itself if/configis unavailable). Memoized per instance.catalogNamestays as a permanent alias forwarehouseso existing call sites (notably@supabase/storage-js'sStorageAnalyticsClient) keep compiling.loadConfig()accessor returns the cachedCatalogConfig.Transport features
Idempotency-Key(UUIDv7, generated client-side) is emitted on every POST/DELETE mutation:createNamespace,dropNamespace,updateNamespaceProperties,createTable,updateTable,dropTable.loadTable(id, { ifNoneMatch })returnsnullon 304. Overloaded soloadTable(id)keeps returning a non-nullableTableMetadata.loadTableResult(id, options?)returns the full spec-shapedLoadTableResult(metadata, metadata-location, config, storage-credentials) plus the capturedETagso callers can feed it back into a futureifNoneMatch.Type fidelity
TableUpdate(23 actions: assign-uuid, upgrade-format-version, add-schema, set-current-schema, add-spec, set-default-spec, add-sort-order, set-default-sort-order, add-snapshot, set-snapshot-ref, remove-snapshots, remove-snapshot-ref, set-location, set-properties, remove-properties, set-statistics, remove-statistics, set-partition-statistics, remove-partition-statistics, remove-partition-specs, remove-schemas, add-encryption-key, remove-encryption-key) andTableRequirement(8 assertions).CatalogConfig,StorageCredential,Snapshot,SnapshotReference,StatisticsFile,PartitionStatisticsFile,EncryptedKey,BlobMetadata,LoadTableResult,LoadTableResultWithEtag,RegisterTableRequest,RenameTableRequest,UpdateNamespacePropertiesRequest,UpdateNamespacePropertiesResponse,ListNamespacesOptions,ListNamespacesResult,ListTablesOptions,ListTablesResult,LoadTableOptions.src/index.ts.Spec-conformance test layer (
test/spec-conformance/)Three layers verify alignment from different angles:
paths.test.ts): exercises every public method against a mock fetch and asserts the emitted(METHOD, path)matches a real spec operation. Also asserts every mutation request carries anIdempotency-KeyUUIDv7 header.schemas.test.ts): loads the bundled OpenAPI YAML, registers every component schema with Ajv, and validates request bodies and response fixtures against the live schemas.types.test.ts): generated types from the YAML are asserted against handwritten types viaexpectTypeOf().toExtend()so the type checker catches drift.CI runs
pnpm gen:spec-typesbeforepnpm type-checkandpnpm test, so a spec change immediately surfaces as a type error or a failing schema/path test.Docs and examples
If-None-Matchsection, expanded TypeScript Types export list, and a "Migrating from 0.x to 1.0" table at the top.examples/basic-usage.tsandexamples/supabase-storage-usage.tsupdated for the paginated return shape.Why
The 0.x client diverged from the spec in several places that mattered: namespace/table listings did not surface
nextPageTokenso any catalog with more than a page of entries silently truncated;Idempotency-Keywas never sent so retries could double-write; and thecatalogNameflow could not address per-warehouse catalogs (Cloudflare R2, Tabular) that need server-sideprefixresolution. Issue #32 surfaced the warehouse case from a real user; the rest of the gaps were caught while doing the audit. Cutting 1.0 is a chance to fix all of these together with one well-publicized break, and the conformance test layer keeps us honest from this point on.Breaking changes
listNamespacesandlistTablesreturn{ items, nextPageToken? }instead of arrays. Callers must destructure or read the.namespaces/.identifiersproperty.listNamespacesno longer takes a parent identifier directly; it takes{ parent, pageToken?, pageSize? }.updateTablebody is{ requirements?, updates }; the old{ properties }shorthand is gone (use{ updates: [{ action: 'set-properties', updates: {...} }] }).catalogNameis preserved as a permanent alias forwarehouse, andloadTable(id)(no options) keeps its non-nullTableMetadatareturn via TS overloads, to keep the downstream blast radius tight. Confirmed audit ofsupabase,storage, andsupabase-js: only@supabase/storage-js'sStorageAnalyticsClientis affected, and the migration there is a single proxy-wrapper update.Test plan
pnpm test, 93 tests across 7 files including the new spec-conformance suite)pnpm type-check)pnpm lint).d.ts(pnpm build)tabulario/iceberg-rest(pnpm test:integration:ci, 20/20)pnpm test:compatibility)warehouse->/v1/config-> server-returnedprefixflow via the new unit tests intest/catalog/IcebergRestCatalog.test.ts