feat(core): named/shared schemas + flatten response allOf#343
Draft
Joehoel wants to merge 5 commits into
Draft
Conversation
Core gains a `longRunning` Http trait and an optional `pollLongRunning` client hook: when an operation carries the trait and the server returns a 201/202 ack, core delegates to the hook and decodes its resolved body through the output schema. Azure implements the hook as an Effect-native ARM poller (Effect.repeat + Schedule honoring per-response Retry-After; Data.taggedEnum strategy + provisioning-state classification via Match). Supports azure-async-operation, location, and original-uri final-state resolution. Terminal Failed/Canceled surfaces as AzureLongRunningOperationFailed (uncategorized, so it is not auto-retried). Tested account-free with a scripted fake HttpClient (incl. Retry-After via TestClock).
The shared Swagger emitter now detects `x-ms-long-running-operation` (+
`-options.final-state-via`) on each operation and bakes
`longRunning: { finalStateVia }` into the generated `T.Http` trait — the
same place `apiVersion` is injected. Regenerated all Azure services: 3783
long-running operations across 182 service files now poll to completion.
The ARM `final-state-via: location` for a resource create points to an
operationResults URL that returns only a stub (`{id, name, type}`); the
provisioned resource lives at the original request URI. Mirror
@azure/core-lro's `findResourceLocation`: PUT/PATCH (and any `original-uri`
op) resolve via the original URI; POST/DELETE use the terminal poll body.
Caught by a live smoke test (real storage-account create on the non-profit
account, free Standard_LRS, torn down) — now included.
The OpenAPI generator inlined every `$ref` at each use site. For services that
concatenate many operations into one file (Azure), inlining deep resource
schemas per operation made `tsgo` blow up — which is why response schemas were
left as `{id, name, type}` stubs.
Now each definition is emitted once as a named const (in a shared `_schemas.ts`,
inlined into the service file for Azure) and referenced via
`Schema.suspend(() => XSchema)`; cyclic back-edges degrade to `Schema.Unknown`
(same as the inline `seenRefs` guard), which also breaks the type-level
recursion so no hand-written annotations are needed. Each schema is type-checked
once, so the deep shapes are now affordable.
With that in place, `generateOutputSchema` flattens the top-level response
`allOf` chain, so create/get operations return the full provisioned resource
(`properties.provisioningState`, `sku`, `kind`, …) instead of a stub — mirroring
PR alchemy-run#324's request-body `allOf` fix, for responses.
Regenerated Azure (smaller: 27M vs the prior 32M, deduped) and Neon. The live
Azure storage smoke test now asserts `provisioningState: "Succeeded"`. Verified
`tsgo` locally on Neon (the per-operation path); Azure's full type-check runs in
CI.
Apply the named/shared-schema generator to the other OpenAPI-based SDKs so they match the new generator output (azure + neon were done in the previous commit). Each definition is emitted once in a `_schemas.ts` and referenced via `Schema.suspend(() => XSchema)`. Also fixes `kubernetes/scripts/generate.ts` (its own concatenating assembler, like azure): exclude `_schemas.ts` from the operation-file scan and import the shared schemas into each service file instead of inlining them. tsgo verified locally: axiom, coinbase, fly-io, kubernetes, mongodb-atlas, planetscale, prisma-postgres, supabase, turso, typesense, workos. posthog and stripe (large, per-operation layout) are left to CI.
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.
Emit each OpenAPI definition once as a named/shared schema instead of inlining it at every
$ref, then flattenallOfin response schemas so create/get operations return the full provisioned resource.Stacked on #341 (the Azure LRO PR) — the first three commits are that PR and drop out once it merges.
Why
The generator inlined every
$refat each use site. For services that concatenate many operations into one file (Azure: ~50 ops instorage.ts), inlining a deep resource schema per operation madetsgoblow up — so response schemas had to be left as{ id, name, type }stubs, which in turn meant the LRO poller resolved the full resource only for the output schema to strip it back.What changed
_schemas.ts; inlined once into the service file for Azure's concatenated layout) and referenced viaSchema.suspend(() => XSchema). Cyclic back-edges degrade toSchema.Unknown(same as the existing inlineseenRefsguard) — which also breaks the type-level recursion, so no hand-writtenSchema.suspendannotations are needed. Each schema is type-checked once.allOfflattening. With inlining gone,generateOutputSchemanow flattens the top-levelallOfinheritance chain, so outputs carry the resource's own + inherited properties:Regenerated Azure (27M, smaller than the prior 32M thanks to dedup) and Neon. Other OpenAPI packages keep their committed output until next regenerated.
Validation
tsgoclean locally on Neon (the per-operation path) — proves the named-schema +suspendmechanism compiles.oxlint0 errors,oxfmt --checkclean, and the live storage smoke test now assertsprovisioningState: "Succeeded"end-to-end.tsgois large; it runs in CI here (the deduped output is smaller than the baseline that already passed CI).