diff --git a/.speakeasy/out.openapi.yaml b/.speakeasy/out.openapi.yaml index 730bd710..29bd6133 100644 --- a/.speakeasy/out.openapi.yaml +++ b/.speakeasy/out.openapi.yaml @@ -15033,9 +15033,23 @@ paths: x-speakeasy-max-method-params: 1 x-speakeasy-name-override: createSpeech parameters: - - $ref: "#/components/parameters/AppIdentifier" - - $ref: "#/components/parameters/AppDisplayName" - - $ref: "#/components/parameters/AppCategories" + - name: HTTP-Referer + in: header + x-speakeasy-globals-hidden: true + schema: + type: string + - name: X-OpenRouter-Title + in: header + x-speakeasy-name-override: appTitle + x-speakeasy-globals-hidden: true + schema: + type: string + - name: X-OpenRouter-Categories + in: header + x-speakeasy-name-override: appCategories + x-speakeasy-globals-hidden: true + schema: + type: string /audio/transcriptions: post: description: Transcribes audio into text. Accepts base64-encoded audio input and returns the transcribed text. @@ -15173,9 +15187,23 @@ paths: x-speakeasy-max-method-params: 1 x-speakeasy-name-override: createTranscription parameters: - - $ref: "#/components/parameters/AppIdentifier" - - $ref: "#/components/parameters/AppDisplayName" - - $ref: "#/components/parameters/AppCategories" + - name: HTTP-Referer + in: header + x-speakeasy-globals-hidden: true + schema: + type: string + - name: X-OpenRouter-Title + in: header + x-speakeasy-name-override: appTitle + x-speakeasy-globals-hidden: true + schema: + type: string + - name: X-OpenRouter-Categories + in: header + x-speakeasy-name-override: appCategories + x-speakeasy-globals-hidden: true + schema: + type: string /auth/keys: post: description: Exchange an authorization code from the PKCE flow for a user-controlled API key diff --git a/.speakeasy/overlays/add-headers.overlay.yaml b/.speakeasy/overlays/add-headers.overlay.yaml index 4cfc85bf..709294e6 100644 --- a/.speakeasy/overlays/add-headers.overlay.yaml +++ b/.speakeasy/overlays/add-headers.overlay.yaml @@ -52,3 +52,57 @@ actions: - $ref: "#/components/parameters/AppIdentifier" - $ref: "#/components/parameters/AppDisplayName" - $ref: "#/components/parameters/AppCategories" + + # Hide app-identification globals on STT/TTS so the body remains the only + # method argument while constructor-level headers still apply. + - target: $.paths["/audio/transcriptions"].parameters + description: Drop $ref-based header params on STT so only the hidden inlines remain + remove: true + + - target: $.paths["/audio/speech"].parameters + description: Drop $ref-based header params on TTS so only the hidden inlines remain + remove: true + + - target: $.paths["/audio/transcriptions"] + description: Add hidden app-identification headers on STT so globals still apply but the method signature stays flat + update: + parameters: + - name: HTTP-Referer + in: header + x-speakeasy-globals-hidden: true + schema: + type: string + - name: X-OpenRouter-Title + in: header + x-speakeasy-name-override: appTitle + x-speakeasy-globals-hidden: true + schema: + type: string + - name: X-OpenRouter-Categories + in: header + x-speakeasy-name-override: appCategories + x-speakeasy-globals-hidden: true + schema: + type: string + + - target: $.paths["/audio/speech"] + description: Add hidden app-identification headers on TTS so globals still apply but the method signature stays flat + update: + parameters: + - name: HTTP-Referer + in: header + x-speakeasy-globals-hidden: true + schema: + type: string + - name: X-OpenRouter-Title + in: header + x-speakeasy-name-override: appTitle + x-speakeasy-globals-hidden: true + schema: + type: string + - name: X-OpenRouter-Categories + in: header + x-speakeasy-name-override: appCategories + x-speakeasy-globals-hidden: true + schema: + type: string diff --git a/src/funcs/sttCreateTranscription.ts b/src/funcs/sttCreateTranscription.ts index e4e330ab..d26ee8de 100644 --- a/src/funcs/sttCreateTranscription.ts +++ b/src/funcs/sttCreateTranscription.ts @@ -23,7 +23,6 @@ import { OpenRouterError } from "../models/errors/openroutererror.js"; import { ResponseValidationError } from "../models/errors/responsevalidationerror.js"; import { SDKValidationError } from "../models/errors/sdkvalidationerror.js"; import * as models from "../models/index.js"; -import * as operations from "../models/operations/index.js"; import { APICall, APIPromise } from "../types/async.js"; import { Result } from "../types/fp.js"; @@ -35,7 +34,7 @@ import { Result } from "../types/fp.js"; */ export function sttCreateTranscription( client: OpenRouterCore, - request: operations.CreateAudioTranscriptionsRequest, + request: models.STTRequest, options?: RequestOptions, ): APIPromise< Result< @@ -69,7 +68,7 @@ export function sttCreateTranscription( async function $do( client: OpenRouterCore, - request: operations.CreateAudioTranscriptionsRequest, + request: models.STTRequest, options?: RequestOptions, ): Promise< [ @@ -99,34 +98,32 @@ async function $do( > { const parsed = safeParse( request, - (value) => - operations.CreateAudioTranscriptionsRequest$outboundSchema.parse(value), + (value) => models.STTRequest$outboundSchema.parse(value), "Input validation failed", ); if (!parsed.ok) { return [parsed, { status: "invalid" }]; } const payload = parsed.value; - const body = encodeJSON("body", payload.STTRequest, { explode: true }); + const body = encodeJSON("body", payload, { explode: true }); const path = pathToFunc("/audio/transcriptions")(); const headers = new Headers(compactMap({ "Content-Type": "application/json", Accept: "application/json", - "HTTP-Referer": encodeSimple( - "HTTP-Referer", - payload["HTTP-Referer"] ?? client._options.httpReferer, - { explode: false, charEncoding: "none" }, - ), + "HTTP-Referer": encodeSimple("HTTP-Referer", client._options.httpReferer, { + explode: false, + charEncoding: "none", + }), "X-OpenRouter-Categories": encodeSimple( "X-OpenRouter-Categories", - payload.appCategories ?? client._options.appCategories, + client._options.appCategories, { explode: false, charEncoding: "none" }, ), "X-OpenRouter-Title": encodeSimple( "X-OpenRouter-Title", - payload.appTitle ?? client._options.appTitle, + client._options.appTitle, { explode: false, charEncoding: "none" }, ), })); diff --git a/src/funcs/ttsCreateSpeech.ts b/src/funcs/ttsCreateSpeech.ts index a4054d79..690b9f60 100644 --- a/src/funcs/ttsCreateSpeech.ts +++ b/src/funcs/ttsCreateSpeech.ts @@ -23,7 +23,7 @@ import * as errors from "../models/errors/index.js"; import { OpenRouterError } from "../models/errors/openroutererror.js"; import { ResponseValidationError } from "../models/errors/responsevalidationerror.js"; import { SDKValidationError } from "../models/errors/sdkvalidationerror.js"; -import * as operations from "../models/operations/index.js"; +import * as models from "../models/index.js"; import { APICall, APIPromise } from "../types/async.js"; import { Result } from "../types/fp.js"; @@ -35,7 +35,7 @@ import { Result } from "../types/fp.js"; */ export function ttsCreateSpeech( client: OpenRouterCore, - request: operations.CreateAudioSpeechRequest, + request: models.SpeechRequest, options?: RequestOptions, ): APIPromise< Result< @@ -69,7 +69,7 @@ export function ttsCreateSpeech( async function $do( client: OpenRouterCore, - request: operations.CreateAudioSpeechRequest, + request: models.SpeechRequest, options?: RequestOptions, ): Promise< [ @@ -99,33 +99,32 @@ async function $do( > { const parsed = safeParse( request, - (value) => operations.CreateAudioSpeechRequest$outboundSchema.parse(value), + (value) => models.SpeechRequest$outboundSchema.parse(value), "Input validation failed", ); if (!parsed.ok) { return [parsed, { status: "invalid" }]; } const payload = parsed.value; - const body = encodeJSON("body", payload.SpeechRequest, { explode: true }); + const body = encodeJSON("body", payload, { explode: true }); const path = pathToFunc("/audio/speech")(); const headers = new Headers(compactMap({ "Content-Type": "application/json", Accept: "audio/*", - "HTTP-Referer": encodeSimple( - "HTTP-Referer", - payload["HTTP-Referer"] ?? client._options.httpReferer, - { explode: false, charEncoding: "none" }, - ), + "HTTP-Referer": encodeSimple("HTTP-Referer", client._options.httpReferer, { + explode: false, + charEncoding: "none", + }), "X-OpenRouter-Categories": encodeSimple( "X-OpenRouter-Categories", - payload.appCategories ?? client._options.appCategories, + client._options.appCategories, { explode: false, charEncoding: "none" }, ), "X-OpenRouter-Title": encodeSimple( "X-OpenRouter-Title", - payload.appTitle ?? client._options.appTitle, + client._options.appTitle, { explode: false, charEncoding: "none" }, ), })); diff --git a/src/models/operations/createaudiospeech.ts b/src/models/operations/createaudiospeech.ts index 1f24c6fa..c9b2d445 100644 --- a/src/models/operations/createaudiospeech.ts +++ b/src/models/operations/createaudiospeech.ts @@ -3,10 +3,6 @@ * @generated-id: 70089adf9736 */ -import * as z from "zod/v4"; -import { remap as remap$ } from "../../lib/primitives.js"; -import * as models from "../index.js"; - export type CreateAudioSpeechGlobals = { /** * The app identifier should be your app's URL and is used as the primary identifier for rankings. @@ -28,58 +24,3 @@ export type CreateAudioSpeechGlobals = { */ appCategories?: string | undefined; }; - -export type CreateAudioSpeechRequest = { - /** - * The app identifier should be your app's URL and is used as the primary identifier for rankings. - * - * @remarks - * This is used to track API usage per application. - */ - httpReferer?: string | undefined; - /** - * The app display name allows you to customize how your app appears in OpenRouter's dashboard. - * - * @remarks - */ - appTitle?: string | undefined; - /** - * Comma-separated list of app categories (e.g. "cli-agent,cloud-agent"). Used for marketplace rankings. - * - * @remarks - */ - appCategories?: string | undefined; - speechRequest: models.SpeechRequest; -}; - -/** @internal */ -export type CreateAudioSpeechRequest$Outbound = { - "HTTP-Referer"?: string | undefined; - appTitle?: string | undefined; - appCategories?: string | undefined; - SpeechRequest: models.SpeechRequest$Outbound; -}; - -/** @internal */ -export const CreateAudioSpeechRequest$outboundSchema: z.ZodType< - CreateAudioSpeechRequest$Outbound, - CreateAudioSpeechRequest -> = z.object({ - httpReferer: z.string().optional(), - appTitle: z.string().optional(), - appCategories: z.string().optional(), - speechRequest: models.SpeechRequest$outboundSchema, -}).transform((v) => { - return remap$(v, { - httpReferer: "HTTP-Referer", - speechRequest: "SpeechRequest", - }); -}); - -export function createAudioSpeechRequestToJSON( - createAudioSpeechRequest: CreateAudioSpeechRequest, -): string { - return JSON.stringify( - CreateAudioSpeechRequest$outboundSchema.parse(createAudioSpeechRequest), - ); -} diff --git a/src/models/operations/createaudiotranscriptions.ts b/src/models/operations/createaudiotranscriptions.ts index 680fccc1..0d69ef17 100644 --- a/src/models/operations/createaudiotranscriptions.ts +++ b/src/models/operations/createaudiotranscriptions.ts @@ -3,10 +3,6 @@ * @generated-id: cfb0e2ed254b */ -import * as z from "zod/v4"; -import { remap as remap$ } from "../../lib/primitives.js"; -import * as models from "../index.js"; - export type CreateAudioTranscriptionsGlobals = { /** * The app identifier should be your app's URL and is used as the primary identifier for rankings. @@ -28,60 +24,3 @@ export type CreateAudioTranscriptionsGlobals = { */ appCategories?: string | undefined; }; - -export type CreateAudioTranscriptionsRequest = { - /** - * The app identifier should be your app's URL and is used as the primary identifier for rankings. - * - * @remarks - * This is used to track API usage per application. - */ - httpReferer?: string | undefined; - /** - * The app display name allows you to customize how your app appears in OpenRouter's dashboard. - * - * @remarks - */ - appTitle?: string | undefined; - /** - * Comma-separated list of app categories (e.g. "cli-agent,cloud-agent"). Used for marketplace rankings. - * - * @remarks - */ - appCategories?: string | undefined; - sttRequest: models.STTRequest; -}; - -/** @internal */ -export type CreateAudioTranscriptionsRequest$Outbound = { - "HTTP-Referer"?: string | undefined; - appTitle?: string | undefined; - appCategories?: string | undefined; - STTRequest: models.STTRequest$Outbound; -}; - -/** @internal */ -export const CreateAudioTranscriptionsRequest$outboundSchema: z.ZodType< - CreateAudioTranscriptionsRequest$Outbound, - CreateAudioTranscriptionsRequest -> = z.object({ - httpReferer: z.string().optional(), - appTitle: z.string().optional(), - appCategories: z.string().optional(), - sttRequest: models.STTRequest$outboundSchema, -}).transform((v) => { - return remap$(v, { - httpReferer: "HTTP-Referer", - sttRequest: "STTRequest", - }); -}); - -export function createAudioTranscriptionsRequestToJSON( - createAudioTranscriptionsRequest: CreateAudioTranscriptionsRequest, -): string { - return JSON.stringify( - CreateAudioTranscriptionsRequest$outboundSchema.parse( - createAudioTranscriptionsRequest, - ), - ); -} diff --git a/src/sdk/stt.ts b/src/sdk/stt.ts index 78ae89ca..40f49a1a 100644 --- a/src/sdk/stt.ts +++ b/src/sdk/stt.ts @@ -6,7 +6,6 @@ import { sttCreateTranscription } from "../funcs/sttCreateTranscription.js"; import { ClientSDK, RequestOptions } from "../lib/sdks.js"; import * as models from "../models/index.js"; -import * as operations from "../models/operations/index.js"; import { unwrapAsync } from "../types/fp.js"; export class Stt extends ClientSDK { @@ -17,7 +16,7 @@ export class Stt extends ClientSDK { * Transcribes audio into text. Accepts base64-encoded audio input and returns the transcribed text. */ async createTranscription( - request: operations.CreateAudioTranscriptionsRequest, + request: models.STTRequest, options?: RequestOptions, ): Promise { return unwrapAsync(sttCreateTranscription( diff --git a/src/sdk/tts.ts b/src/sdk/tts.ts index 99ba633f..71dcfcd6 100644 --- a/src/sdk/tts.ts +++ b/src/sdk/tts.ts @@ -5,7 +5,7 @@ import { ttsCreateSpeech } from "../funcs/ttsCreateSpeech.js"; import { ClientSDK, RequestOptions } from "../lib/sdks.js"; -import * as operations from "../models/operations/index.js"; +import * as models from "../models/index.js"; import { unwrapAsync } from "../types/fp.js"; export class Tts extends ClientSDK { @@ -16,7 +16,7 @@ export class Tts extends ClientSDK { * Synthesizes audio from the input text. Returns a raw audio bytestream in the requested format (e.g. mp3, pcm, wav). */ async createSpeech( - request: operations.CreateAudioSpeechRequest, + request: models.SpeechRequest, options?: RequestOptions, ): Promise> { return unwrapAsync(ttsCreateSpeech( diff --git a/tests/unit/audio-signature-types.test.ts b/tests/unit/audio-signature-types.test.ts new file mode 100644 index 00000000..81c1bfc1 --- /dev/null +++ b/tests/unit/audio-signature-types.test.ts @@ -0,0 +1,29 @@ +import { describe, expect, it } from 'vitest'; +import type * as models from '../../src/models/index.js'; +import type { OpenRouter } from '../../src/sdk/sdk.js'; + +type SttRequestParam = Parameters[0]; +type TtsRequestParam = Parameters[0]; + +type IsEqual = (() => T extends TActual ? 1 : 2) extends + (() => T extends TExpected ? 1 : 2) ? true : false; +type IsAssignable = TActual extends TExpected ? true : false; +type AssertTrue = T; +type AssertFalse = T; + +const signatureAssertions = { + sttParamIsBody: true as AssertTrue>, + ttsParamIsBody: true as AssertTrue>, + sttRejectsNestedWrapper: true as AssertFalse< + IsAssignable<{ sttRequest: models.STTRequest }, SttRequestParam> + >, + ttsRejectsNestedWrapper: true as AssertFalse< + IsAssignable<{ speechRequest: models.SpeechRequest }, TtsRequestParam> + >, +}; + +describe('audio request signatures', () => { + it('typechecks flattened STT/TTS request shapes', () => { + expect(signatureAssertions).toBeDefined(); + }); +});