fix(sdk): preserve SSE event payload types
This commit is contained in:
parent
7a17925495
commit
8a8b572e9f
4 changed files with 43 additions and 22 deletions
|
|
@ -34,6 +34,8 @@ type OpenApiSchema = {
|
|||
additionalProperties?: OpenApiSchema | boolean
|
||||
allOf?: OpenApiSchema[]
|
||||
anyOf?: OpenApiSchema[]
|
||||
contentMediaType?: string
|
||||
contentSchema?: OpenApiSchema
|
||||
description?: string
|
||||
enum?: Array<string | boolean>
|
||||
items?: OpenApiSchema
|
||||
|
|
@ -88,6 +90,7 @@ function matchLegacyOpenApi(input: Record<string, unknown>) {
|
|||
// payload and inside an annotated union arm. Resolve these by inlining the
|
||||
// actual schema from any parent union that references them.
|
||||
fixSelfReferencingComponents(spec)
|
||||
collapseJsonSseComponents(spec)
|
||||
|
||||
// Effect's Schema.optional emits `anyOf: [T, {type:"null"}]` in OpenAPI,
|
||||
// but the legacy SDK expected plain `T` for optional fields. Strip null
|
||||
|
|
@ -229,6 +232,26 @@ function collapseDuplicateComponents(spec: OpenApiSpec) {
|
|||
}
|
||||
}
|
||||
|
||||
function collapseJsonSseComponents(spec: OpenApiSpec) {
|
||||
const schemas = spec.components?.schemas
|
||||
if (!schemas) return
|
||||
for (const [name, schema] of Object.entries(schemas)) {
|
||||
const ref = schema.contentMediaType === "application/json" ? schema.contentSchema?.$ref : undefined
|
||||
const target = ref?.replace("#/components/schemas/", "")
|
||||
if (schema.type !== "string" || !target || !schemas[target]) continue
|
||||
// Effect represents JSON SSE payloads as encoded string schemas, but the
|
||||
// generated SDK's SSE client already decodes them. Keep the payload union
|
||||
// under its stable, unsuffixed component name instead of exposing `string`.
|
||||
const canonical = name.replace(/\d+$/, "")
|
||||
if (target.replace(/\d+$/, "") !== canonical) continue
|
||||
schemas[canonical] = schemas[target]
|
||||
rewriteRefs(spec, name, canonical)
|
||||
rewriteRefs(spec, target, canonical)
|
||||
if (name !== canonical) delete schemas[name]
|
||||
if (target !== canonical) delete schemas[target]
|
||||
}
|
||||
}
|
||||
|
||||
function normalizeComponentNames(spec: OpenApiSpec) {
|
||||
const schemas = spec.components?.schemas
|
||||
if (!schemas) return
|
||||
|
|
|
|||
|
|
@ -99,6 +99,22 @@ describe("PublicApi OpenAPI v2 errors", () => {
|
|||
})
|
||||
})
|
||||
|
||||
test("exposes decoded SSE payload schemas", () => {
|
||||
const spec = OpenApi.fromApi(PublicApi) as OpenApiSpec
|
||||
|
||||
expect(spec.paths["/api/event"]?.get?.responses?.["200"]?.content?.["text/event-stream"]?.schema?.$ref).toBe(
|
||||
"#/components/schemas/V2Event",
|
||||
)
|
||||
expect(spec.components.schemas.V2Event?.anyOf?.length).toBeGreaterThan(0)
|
||||
expect(spec.components.schemas.V2Event1).toBeUndefined()
|
||||
|
||||
expect(
|
||||
spec.paths["/api/session/{sessionID}/event"]?.get?.responses?.["200"]?.content?.["text/event-stream"]?.schema
|
||||
?.properties?.data?.$ref,
|
||||
).toBe("#/components/schemas/SessionDurableEvent")
|
||||
expect(spec.components.schemas.SessionDurableEvent1).toBeUndefined()
|
||||
})
|
||||
|
||||
test("preserves /api auth responses", () => {
|
||||
const spec = OpenApi.fromApi(PublicApi) as OpenApiSpec
|
||||
|
||||
|
|
|
|||
|
|
@ -2766,8 +2766,6 @@ export type SessionHistory = {
|
|||
hasMore: boolean
|
||||
}
|
||||
|
||||
export type SessionDurableEvent1 = string
|
||||
|
||||
export type SessionMessagesResponse = {
|
||||
data: Array<SessionMessage>
|
||||
cursor: {
|
||||
|
|
@ -2847,7 +2845,7 @@ export type QuestionRejected2 = {
|
|||
}
|
||||
}
|
||||
|
||||
export type V2Event1 =
|
||||
export type V2Event =
|
||||
| ModelsDevRefreshed
|
||||
| IntegrationUpdated
|
||||
| IntegrationConnectionUpdated
|
||||
|
|
@ -2937,8 +2935,6 @@ export type V2Event1 =
|
|||
| ServerConnected
|
||||
| GlobalDisposed
|
||||
|
||||
export type V2Event = string
|
||||
|
||||
export type ForbiddenError = {
|
||||
_tag: "ForbiddenError"
|
||||
message: string
|
||||
|
|
@ -11897,7 +11893,7 @@ export type V2SessionEventsResponses = {
|
|||
200: {
|
||||
id: string
|
||||
event: string
|
||||
data: SessionDurableEvent1
|
||||
data: SessionDurableEvent
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11260,7 +11260,7 @@
|
|||
"type": "string"
|
||||
},
|
||||
"data": {
|
||||
"$ref": "#/components/schemas/SessionDurableEvent1"
|
||||
"$ref": "#/components/schemas/SessionDurableEvent"
|
||||
}
|
||||
},
|
||||
"required": ["id", "event", "data"],
|
||||
|
|
@ -23732,13 +23732,6 @@
|
|||
"required": ["data", "hasMore"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"SessionDurableEvent1": {
|
||||
"type": "string",
|
||||
"contentSchema": {
|
||||
"$ref": "#/components/schemas/SessionDurableEvent"
|
||||
},
|
||||
"contentMediaType": "application/json"
|
||||
},
|
||||
"SessionMessagesResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
|
@ -23975,7 +23968,7 @@
|
|||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"V2Event1": {
|
||||
"V2Event": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/Models-devRefreshed"
|
||||
|
|
@ -24243,13 +24236,6 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"V2Event": {
|
||||
"type": "string",
|
||||
"contentSchema": {
|
||||
"$ref": "#/components/schemas/V2Event1"
|
||||
},
|
||||
"contentMediaType": "application/json"
|
||||
},
|
||||
"ForbiddenError": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue